diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 5c5263f..2bde541 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -17,7 +17,7 @@ jobs: uses: VeryGoodOpenSource/very_good_workflows/.github/workflows/flutter_package.yml@v1 with: flutter_channel: stable - flutter_version: 3.13.9 + flutter_version: 3.19.5 pana: uses: VeryGoodOpenSource/very_good_workflows/.github/workflows/pana.yml@v1 diff --git a/CHANGELOG.md b/CHANGELOG.md index d4a5f86..952a3dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +# 0.1.0 + +- **BREAKING**: replace deprecated `WillPopScope` with `PopScope` + - refactor: update dart sdk constrant to `>=3.2.0` + - refactor: update flutter constraint to `>=3.16.0` + # 0.0.10 - feat: add optional `clipBehavior` ([#113](https://github.com/felangel/flow_builder/pull/113)) diff --git a/example/lib/main.dart b/example/lib/main.dart index 406b16a..13e093e 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -22,14 +22,9 @@ class MyApp extends StatelessWidget { } } -class Home extends StatefulWidget { +class Home extends StatelessWidget { const Home({super.key}); - @override - State createState() => _HomeState(); -} - -class _HomeState extends State { @override Widget build(BuildContext context) { return Scaffold( @@ -44,7 +39,7 @@ class _HomeState extends State { trailing: const Icon(Icons.chevron_right), onTap: () async { await Navigator.of(context).push(OnboardingFlow.route()); - if (!mounted) return; + if (!context.mounted) return; ScaffoldMessenger.of(context) ..hideCurrentSnackBar() ..showSnackBar( @@ -62,7 +57,7 @@ class _HomeState extends State { final profile = await Navigator.of(context).push( ProfileFlow.route(), ); - if (!mounted) return; + if (!context.mounted) return; ScaffoldMessenger.of(context) ..hideCurrentSnackBar() ..showSnackBar( @@ -80,7 +75,7 @@ class _HomeState extends State { final location = await Navigator.of(context).push( LocationFlow.route(), ); - if (!mounted) return; + if (!context.mounted) return; ScaffoldMessenger.of(context) ..hideCurrentSnackBar() ..showSnackBar( @@ -98,7 +93,7 @@ class _HomeState extends State { await Navigator.of(context).push( AuthenticationFlow.route(), ); - if (!mounted) return; + if (!context.mounted) return; ScaffoldMessenger.of(context) ..hideCurrentSnackBar() ..showSnackBar( diff --git a/example/pubspec.yaml b/example/pubspec.yaml index bd02c28..f19fa1c 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -4,7 +4,8 @@ version: 1.0.0+1 publish_to: none environment: - sdk: ">=2.17.0 <3.0.0" + sdk: ">=3.2.0 <4.0.0" + flutter: ">=3.16.0 <4.0.0" dependencies: equatable: ^2.0.0 diff --git a/lib/flow_builder.dart b/lib/flow_builder.dart index 5d9aeb6..01d1193 100644 --- a/lib/flow_builder.dart +++ b/lib/flow_builder.dart @@ -148,7 +148,7 @@ class _FlowBuilderState extends State> { if (mounted) { final popHandled = await _navigator?.maybePop() ?? false; if (popHandled) return true; - if (mounted && !_canPop) return Navigator.of(context).maybePop(); + if (mounted && !_canPop) _navigator?.pop(); return false; } return false; @@ -176,12 +176,8 @@ class _FlowBuilderState extends State> { Widget build(BuildContext context) { return _InheritedFlowController( controller: _controller, - child: _ConditionalWillPopScope( + child: _ConditionalPopScope( condition: _canPop, - onWillPop: () async { - await _navigator?.maybePop(); - return false; - }, child: Navigator( key: _navigatorKey, pages: _pages, @@ -197,6 +193,7 @@ class _FlowBuilderState extends State> { _pages.removeLast(); } setState(() {}); + route.onPopInvoked(true); return route.didPop(result); }, ), @@ -329,20 +326,18 @@ class FakeFlowController extends FlowController { } } -class _ConditionalWillPopScope extends StatelessWidget { - const _ConditionalWillPopScope({ +class _ConditionalPopScope extends StatelessWidget { + const _ConditionalPopScope({ required this.condition, - required this.onWillPop, required this.child, }); final bool condition; final Widget child; - final Future Function() onWillPop; @override Widget build(BuildContext context) { - return condition ? WillPopScope(onWillPop: onWillPop, child: child) : child; + return condition ? PopScope(canPop: false, child: child) : child; } } diff --git a/pubspec.yaml b/pubspec.yaml index a911066..52ef47d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -4,10 +4,11 @@ repository: https://github.com/felangel/flow_builder homepage: https://github.com/felangel/flow_builder topics: [navigation, routing] -version: 0.0.10 +version: 0.1.0 environment: - sdk: ">=2.17.0 <3.0.0" + sdk: ">=3.2.0 <4.0.0" + flutter: ">=3.16.0 <4.0.0" dependencies: flutter: diff --git a/test/flow_builder_test.dart b/test/flow_builder_test.dart index 093a97b..a63596a 100644 --- a/test/flow_builder_test.dart +++ b/test/flow_builder_test.dart @@ -1063,7 +1063,7 @@ void main() { expect(find.byKey(button2Key), findsOneWidget); }); - testWidgets('onWillPop pops top page when there are multiple', + testWidgets('Navigator.pop pops top page when there are multiple', (tester) async { const button1Key = Key('__button1__'); const button2Key = Key('__button2__'); @@ -1084,10 +1084,14 @@ void main() { ), MaterialPage( child: Scaffold( - body: TextButton( - key: button2Key, - child: const Text('Button'), - onPressed: () {}, + body: Builder( + builder: (context) { + return TextButton( + key: button2Key, + child: const Text('Button'), + onPressed: () => Navigator.of(context).pop(), + ); + }, ), ), ), @@ -1100,19 +1104,14 @@ void main() { expect(find.byKey(button1Key), findsNothing); expect(find.byKey(button2Key), findsOneWidget); - final willPopScope = tester.widget( - find.byType(WillPopScope), - ); - final result = await willPopScope.onWillPop!(); - expect(result, isFalse); - + await tester.tap(find.byKey(button2Key)); await tester.pumpAndSettle(); expect(find.byKey(button1Key), findsOneWidget); expect(find.byKey(button2Key), findsNothing); }); - testWidgets('onWillPop does not exist for only one page', (tester) async { + testWidgets('PopScope does not exist for only one page', (tester) async { const button1Key = Key('__button1__'); await tester.pumpWidget( MaterialApp( @@ -1136,7 +1135,7 @@ void main() { ); expect(find.byKey(button1Key), findsOneWidget); - expect(find.byType(WillPopScope), findsNothing); + expect(find.byType(PopScope), findsNothing); }); testWidgets('controller change triggers a rebuild with correct state', @@ -1389,21 +1388,19 @@ void main() { expect(navigators.last.observers, equals(observers)); }); - testWidgets('SystemNavigator.pop respects when WillPopScope returns false', + testWidgets('SystemNavigator.pop respects PopScope(canPop: false)', (tester) async { const targetKey = Key('__target__'); - var onWillPopCallCount = 0; + var onPopCallCount = 0; final flow = FlowBuilder( state: 0, onGeneratePages: (state, pages) { return >[ MaterialPage( child: Builder( - builder: (context) => WillPopScope( - onWillPop: () async { - onWillPopCallCount++; - return false; - }, + builder: (context) => PopScope( + canPop: false, + onPopInvoked: (_) => onPopCallCount++, child: TextButton( key: targetKey, onPressed: () { @@ -1441,24 +1438,23 @@ void main() { await tester.tap(find.byKey(targetKey)); await tester.pumpAndSettle(); - expect(onWillPopCallCount, equals(1)); + expect(onPopCallCount, equals(1)); expect(find.byKey(targetKey), findsOneWidget); }); - testWidgets('SystemNavigator.pop respects when WillPopScope returns true', + testWidgets('SystemNavigator.pop respects PopScope(canPop: true)', (tester) async { const targetKey = Key('__target__'); - var onWillPopCallCount = 0; + var onPopCallCount = 0; final flow = FlowBuilder( state: 0, onGeneratePages: (state, pages) { return >[ MaterialPage( child: Builder( - builder: (context) => WillPopScope( - onWillPop: () async { - onWillPopCallCount++; - return true; + builder: (context) => PopScope( + onPopInvoked: (_) { + onPopCallCount++; }, child: TextButton( key: targetKey, @@ -1497,7 +1493,7 @@ void main() { await tester.tap(find.byKey(targetKey)); await tester.pumpAndSettle(); - expect(onWillPopCallCount, equals(1)); + expect(onPopCallCount, equals(1)); expect(find.byKey(targetKey), findsNothing); });