Skip to content

Commit d52829d

Browse files
angelosilvestrematthew-carroll
authored andcommitted
[SuperReader][SuperReader][iOS] Fix crash when pushing a route with a delegatedTransition. (Resolves #2794) (#2797)
1 parent bc93fac commit d52829d

File tree

4 files changed

+187
-8
lines changed

4 files changed

+187
-8
lines changed

super_editor/lib/src/default_editor/document_gestures_touch_ios.dart

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1517,9 +1517,10 @@ class SuperEditorIosToolbarOverlayManagerState extends State<SuperEditorIosToolb
15171517

15181518
_controlsController = SuperEditorIosControlsScope.rootOf(context);
15191519

1520-
WidgetsBinding.instance.addPostFrameCallback((_) {
1521-
// There's some stupid Flutter error that happens without this post frame callback
1522-
// where the error is "OverlayPortalController.show() should not be called during build.".
1520+
// It's possible that `didChangeDependencies` is called during build when pushing a route
1521+
// that has a delegated transition. We need to wait until the next frame to show the overlay,
1522+
// otherwise this widget crashes, since we can't call `OverlayPortalController.show()` during build.
1523+
onNextFrame((timeStamp) {
15231524
_overlayPortalController.show();
15241525
});
15251526
}
@@ -1584,9 +1585,10 @@ class SuperEditorIosMagnifierOverlayManagerState extends State<SuperEditorIosMag
15841585
super.didChangeDependencies();
15851586
_controlsController = SuperEditorIosControlsScope.rootOf(context);
15861587

1587-
WidgetsBinding.instance.addPostFrameCallback((_) {
1588-
// There's some stupid Flutter error that happens without this post frame callback
1589-
// where the error is "OverlayPortalController.show() should not be called during build.".
1588+
// It's possible that `didChangeDependencies` is called during build when pushing a route
1589+
// that has a delegated transition. We need to wait until the next frame to show the overlay,
1590+
// otherwise this widget crashes, since we can't call `OverlayPortalController.show` during build.
1591+
onNextFrame((timeStamp) {
15901592
_overlayPortalController.show();
15911593
});
15921594
}

super_editor/lib/src/super_reader/read_only_document_ios_touch_interactor.dart

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1077,7 +1077,13 @@ class SuperReaderIosToolbarOverlayManagerState extends State<SuperReaderIosToolb
10771077
super.didChangeDependencies();
10781078

10791079
_controlsContext = SuperReaderIosControlsScope.rootOf(context);
1080-
_overlayPortalController.show();
1080+
1081+
// It's possible that `didChangeDependencies` is called during build when pushing a route
1082+
// that has a delegated transition. We need to wait until the next frame to show the overlay,
1083+
// otherwise this widget crashes, since we can't call `OverlayPortalController.show` during build.
1084+
onNextFrame((timeStamp) {
1085+
_overlayPortalController.show();
1086+
});
10811087
}
10821088

10831089
@override
@@ -1138,7 +1144,12 @@ class SuperReaderIosMagnifierOverlayManagerState extends State<SuperReaderIosMag
11381144

11391145
_controlsContext = SuperReaderIosControlsScope.rootOf(context);
11401146

1141-
_overlayPortalController.show();
1147+
// It's possible that `didChangeDependencies` is called during build when pushing a route
1148+
// that has a delegated transition. We need to wait until the next frame to show the overlay,
1149+
// otherwise this widget crashes, since we can't call `OverlayPortalController.show` during build.
1150+
onNextFrame((timeStamp) {
1151+
_overlayPortalController.show();
1152+
});
11421153
}
11431154

11441155
@override
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:flutter_test/flutter_test.dart';
3+
import 'package:flutter_test_runners/flutter_test_runners.dart';
4+
5+
import 'supereditor_test_tools.dart';
6+
7+
void main() {
8+
group('SuperEditor > routes >', () {
9+
testWidgetsOnAllPlatforms('can be used with a route with a delegated transition on top', (tester) async {
10+
await tester //
11+
.createDocument()
12+
.withSingleParagraph()
13+
.withCustomWidgetTreeBuilder(
14+
(superEditor) => MaterialApp(
15+
home: Scaffold(
16+
body: Column(
17+
children: [
18+
Expanded(
19+
child: superEditor,
20+
),
21+
Builder(builder: (context) {
22+
return ElevatedButton(
23+
child: const Text('delegatedTransition'),
24+
onPressed: () {
25+
Navigator.of(context).push(_TestRoute());
26+
},
27+
);
28+
}),
29+
],
30+
),
31+
),
32+
),
33+
)
34+
.pump();
35+
36+
await tester.tap(find.byType(ElevatedButton));
37+
await tester.pump();
38+
39+
// Reaching this point means that the editor did not crash when the route with
40+
// a delegated transition was pushed on top of it.
41+
// See https://github.com/Flutter-Bounty-Hunters/super_editor/issues/2794 for details.
42+
});
43+
});
44+
}
45+
46+
/// A [ModalRoute] that uses a delegated transition.
47+
class _TestRoute extends ModalRoute<void> {
48+
_TestRoute();
49+
50+
@override
51+
DelegatedTransitionBuilder? get delegatedTransition =>
52+
(context, animation, secondaryAnimation, allowSnapshotting, child) {
53+
return FadeTransition(
54+
opacity: animation,
55+
child: child,
56+
);
57+
};
58+
59+
@override
60+
Color? get barrierColor => null;
61+
62+
@override
63+
String? get barrierLabel => null;
64+
65+
@override
66+
bool get barrierDismissible => true;
67+
68+
@override
69+
Widget buildPage(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) {
70+
return const Center(
71+
child: Text('Hello'),
72+
);
73+
}
74+
75+
@override
76+
bool get maintainState => true;
77+
78+
@override
79+
bool get opaque => false;
80+
81+
@override
82+
Duration get transitionDuration => const Duration(milliseconds: 300);
83+
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:flutter_test/flutter_test.dart';
3+
import 'package:flutter_test_runners/flutter_test_runners.dart';
4+
5+
import 'reader_test_tools.dart';
6+
7+
void main() {
8+
group('SuperReader > routes >', () {
9+
testWidgetsOnAllPlatforms('can be used with a route with a delegated transition on top', (tester) async {
10+
await tester //
11+
.createDocument()
12+
.withSingleParagraph()
13+
.withCustomWidgetTreeBuilder(
14+
(superReader) => MaterialApp(
15+
home: Scaffold(
16+
body: Column(
17+
children: [
18+
Expanded(
19+
child: superReader,
20+
),
21+
Builder(builder: (context) {
22+
return ElevatedButton(
23+
child: const Text('delegatedTransition'),
24+
onPressed: () {
25+
Navigator.of(context).push(_TestRoute());
26+
},
27+
);
28+
}),
29+
],
30+
),
31+
),
32+
),
33+
)
34+
.pump();
35+
36+
await tester.tap(find.byType(ElevatedButton));
37+
await tester.pump();
38+
39+
// Reaching this point means that the reader did not crash when the route with
40+
// a delegated transition was pushed on top of it.
41+
// See https://github.com/Flutter-Bounty-Hunters/super_editor/issues/2794 for details.
42+
});
43+
});
44+
}
45+
46+
/// A [ModalRoute] that uses a delegated transition.
47+
class _TestRoute extends ModalRoute<void> {
48+
_TestRoute();
49+
50+
@override
51+
DelegatedTransitionBuilder? get delegatedTransition =>
52+
(context, animation, secondaryAnimation, allowSnapshotting, child) {
53+
return FadeTransition(
54+
opacity: animation,
55+
child: child,
56+
);
57+
};
58+
59+
@override
60+
Color? get barrierColor => null;
61+
62+
@override
63+
String? get barrierLabel => null;
64+
65+
@override
66+
bool get barrierDismissible => true;
67+
68+
@override
69+
Widget buildPage(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) {
70+
return const Center(
71+
child: Text('Hello'),
72+
);
73+
}
74+
75+
@override
76+
bool get maintainState => true;
77+
78+
@override
79+
bool get opaque => false;
80+
81+
@override
82+
Duration get transitionDuration => const Duration(milliseconds: 300);
83+
}

0 commit comments

Comments
 (0)