Skip to content

Commit

Permalink
Migrated SuperEditor and SuperReader iOS overlays to OverlayPortal - …
Browse files Browse the repository at this point in the history
…all overlays in this package should now use OverlayPortal (Resolves #1526)
  • Loading branch information
matthew-carroll committed Dec 10, 2023
1 parent b19e1ca commit 1cd69d7
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 240 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,100 +23,73 @@ class _ToolbarFollowingContentInLayerState extends State<ToolbarFollowingContent
final _baseContentWidth = 10.0;
final _expansionExtent = ValueNotifier<double>(0);

OverlayState? _ancestorOverlay;
late final OverlayEntry _toolbarEntry;
final OverlayPortalController _overlayPortalController = OverlayPortalController();

@override
void initState() {
super.initState();

_toolbarEntry = OverlayEntry(builder: (_) {
return _buildToolbarOverlay();
});
}

@override
void didChangeDependencies() {
super.didChangeDependencies();

// Any time our dependencies change, our ancestor Overlay may have changed.
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
final newOverlay = Overlay.of(context);
if (newOverlay == _ancestorOverlay) {
// Overlay didn't change. Nothing to do.
return;
}

if (_ancestorOverlay != null) {
_toolbarEntry.remove();
}

_ancestorOverlay = newOverlay;
newOverlay.insert(_toolbarEntry);
});
}

@override
void dispose() {
_toolbarEntry.remove();

super.dispose();
_overlayPortalController.show();
}

@override
Widget build(BuildContext context) {
return SpotCheckScaffold(
content: KeyedSubtree(
key: _viewportKey,
child: ContentLayers(
overlays: [
(_) => LeaderLayoutLayer(
leaderLink: _leaderLink,
leaderBoundsKey: _leaderBoundsKey,
),
],
content: (_) => Center(
child: Column(
children: [
const Spacer(),
ValueListenableBuilder(
valueListenable: _expansionExtent,
builder: (context, expansionExtent, _) {
return Container(
height: 12,
width: _baseContentWidth + (2 * expansionExtent) + 2, // +2 for border
decoration: BoxDecoration(
border: Border.all(color: Colors.white.withOpacity(0.1)),
),
child: Align(
alignment: Alignment.centerLeft,
child: Container(
key: _leaderBoundsKey,
width: _baseContentWidth + expansionExtent,
height: 10,
color: Colors.white.withOpacity(0.2),
return OverlayPortal(
controller: _overlayPortalController,
overlayChildBuilder: _buildToolbarOverlay,
child: SpotCheckScaffold(
content: KeyedSubtree(
key: _viewportKey,
child: ContentLayers(
overlays: [
(_) => LeaderLayoutLayer(
leaderLink: _leaderLink,
leaderBoundsKey: _leaderBoundsKey,
),
],
content: (_) => Center(
child: Column(
children: [
const Spacer(),
ValueListenableBuilder(
valueListenable: _expansionExtent,
builder: (context, expansionExtent, _) {
return Container(
height: 12,
width: _baseContentWidth + (2 * expansionExtent) + 2, // +2 for border
decoration: BoxDecoration(
border: Border.all(color: Colors.white.withOpacity(0.1)),
),
),
);
},
),
const SizedBox(height: 96),
TextButton(
onPressed: () {
_expansionExtent.value = Random().nextDouble() * 200;
},
child: Text("Change Size"),
),
const Spacer(),
],
child: Align(
alignment: Alignment.centerLeft,
child: Container(
key: _leaderBoundsKey,
width: _baseContentWidth + expansionExtent,
height: 10,
color: Colors.white.withOpacity(0.2),
),
),
);
},
),
const SizedBox(height: 96),
TextButton(
onPressed: () {
_expansionExtent.value = Random().nextDouble() * 200;
},
child: Text("Change Size"),
),
const Spacer(),
],
),
),
),
),
),
);
}

Widget _buildToolbarOverlay() {
Widget _buildToolbarOverlay(BuildContext context) {
return FollowerFadeOutBeyondBoundary(
link: _leaderLink,
boundary: WidgetFollowerBoundary(
Expand Down
108 changes: 26 additions & 82 deletions super_editor/lib/src/default_editor/document_gestures_touch_ios.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1376,63 +1376,38 @@ class SuperEditorIosToolbarOverlayManager extends StatefulWidget {

@visibleForTesting
class SuperEditorIosToolbarOverlayManagerState extends State<SuperEditorIosToolbarOverlayManager> {
final OverlayPortalController _overlayPortalController = OverlayPortalController();
SuperEditorIosControlsController? _controlsController;
OverlayEntry? _toolbarOverlayEntry;

@override
void didChangeDependencies() {
super.didChangeDependencies();

_controlsController = SuperEditorIosControlsScope.rootOf(context);

// Add our overlay on the next frame. If we did it immediately, it would
// cause a setState() to be called during didChangeDependencies, which is
// a framework violation.
onNextFrame((timeStamp) {
_addToolbarOverlay();
});
}

@override
void dispose() {
_removeToolbarOverlay();
super.dispose();
_overlayPortalController.show();
}

@visibleForTesting
bool get wantsToDisplayToolbar => _controlsController!.shouldShowToolbar.value;

void _addToolbarOverlay() {
if (_toolbarOverlayEntry != null) {
return;
}

_toolbarOverlayEntry = OverlayEntry(builder: (overlayContext) {
return IosFloatingToolbarOverlay(
shouldShowToolbar: _controlsController!.shouldShowToolbar,
toolbarFocalPoint: _controlsController!.toolbarFocalPoint,
floatingToolbarBuilder:
_controlsController!.toolbarBuilder ?? widget.defaultToolbarBuilder ?? (_, __, ___) => const SizedBox(),
createOverlayControlsClipper: _controlsController!.createOverlayControlsClipper,
showDebugPaint: false,
);
});

Overlay.of(context).insert(_toolbarOverlayEntry!);
}

void _removeToolbarOverlay() {
if (_toolbarOverlayEntry == null) {
return;
}

_toolbarOverlayEntry!.remove();
_toolbarOverlayEntry = null;
}

@override
Widget build(BuildContext context) {
return widget.child ?? const SizedBox();
return OverlayPortal(
controller: _overlayPortalController,
overlayChildBuilder: _buildToolbar,
child: widget.child ?? const SizedBox(),
);
}

Widget _buildToolbar(BuildContext context) {
return IosFloatingToolbarOverlay(
shouldShowToolbar: _controlsController!.shouldShowToolbar,
toolbarFocalPoint: _controlsController!.toolbarFocalPoint,
floatingToolbarBuilder:
_controlsController!.toolbarBuilder ?? widget.defaultToolbarBuilder ?? (_, __, ___) => const SizedBox(),
createOverlayControlsClipper: _controlsController!.createOverlayControlsClipper,
showDebugPaint: false,
);
}
}

Expand All @@ -1452,61 +1427,30 @@ class SuperEditorIosMagnifierOverlayManager extends StatefulWidget {

@visibleForTesting
class SuperEditorIosMagnifierOverlayManagerState extends State<SuperEditorIosMagnifierOverlayManager> {
final OverlayPortalController _overlayPortalController = OverlayPortalController();
SuperEditorIosControlsController? _controlsController;
OverlayEntry? _magnifierOverlayEntry;

@override
void initState() {
super.initState();

// Add our overlay on the next frame. If we did it immediately, it would
// cause a setState() to be called during didChangeDependencies, which is
// a framework violation.
onNextFrame((timeStamp) {
_addMagnifierOverlay();
});
}

@override
void didChangeDependencies() {
super.didChangeDependencies();

_controlsController = SuperEditorIosControlsScope.rootOf(context);
}

@override
void dispose() {
_removeMagnifierOverlay();
super.dispose();
_overlayPortalController.show();
}

@visibleForTesting
bool get wantsToDisplayMagnifier => _controlsController!.shouldShowMagnifier.value;

void _addMagnifierOverlay() {
if (_magnifierOverlayEntry != null) {
return;
}

_magnifierOverlayEntry = OverlayEntry(builder: (_) => _buildMagnifier());
Overlay.of(context).insert(_magnifierOverlayEntry!);
}

void _removeMagnifierOverlay() {
if (_magnifierOverlayEntry == null) {
return;
}

_magnifierOverlayEntry!.remove();
_magnifierOverlayEntry = null;
}

@override
Widget build(BuildContext context) {
return widget.child ?? const SizedBox();
return OverlayPortal(
controller: _overlayPortalController,
overlayChildBuilder: _buildMagnifier,
child: widget.child ?? const SizedBox(),
);
}

Widget _buildMagnifier() {
Widget _buildMagnifier(BuildContext context) {
// Display a magnifier that tracks a focal point.
//
// When the user is dragging an overlay handle, SuperEditor
Expand Down
Loading

0 comments on commit 1cd69d7

Please sign in to comment.