Jaime Blasco
Committed by GitHub

feat: bring up to date (#391)

* fix: lints

* feat: fix inner not resizing

* fix: expanded
Showing 60 changed files with 561 additions and 323 deletions
1 -  
2 -  
3 -enable-experiment:  
4 - - extension-methods  
  1 +include: package:lints/recommended.yaml
@@ -15,8 +15,8 @@ EXTERNAL SOURCES: @@ -15,8 +15,8 @@ EXTERNAL SOURCES:
15 15
16 SPEC CHECKSUMS: 16 SPEC CHECKSUMS:
17 Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 17 Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
18 - url_launcher_ios: ae1517e5e344f5544fb090b079e11f399dfbe4d2 18 + url_launcher_ios: 68d46cc9766d0c41dbdc884310529557e3cd7a86
19 19
20 PODFILE CHECKSUM: ef19549a9bc3046e7bb7d2fab4d021637c0c58a3 20 PODFILE CHECKSUM: ef19549a9bc3046e7bb7d2fab4d021637c0c58a3
21 21
22 -COCOAPODS: 1.13.0 22 +COCOAPODS: 1.14.3
@@ -93,7 +93,7 @@ class CupertinoSharePage extends StatelessWidget { @@ -93,7 +93,7 @@ class CupertinoSharePage extends StatelessWidget {
93 } 93 }
94 94
95 class PhotoShareBottomSheet extends StatelessWidget { 95 class PhotoShareBottomSheet extends StatelessWidget {
96 - const PhotoShareBottomSheet({Key? key}) : super(key: key); 96 + const PhotoShareBottomSheet({super.key});
97 97
98 @override 98 @override
99 Widget build(BuildContext context) { 99 Widget build(BuildContext context) {
@@ -539,9 +539,9 @@ final actions2 = [ @@ -539,9 +539,9 @@ final actions2 = [
539 ]; 539 ];
540 540
541 extension ListUtils<T> on List<T> { 541 extension ListUtils<T> on List<T> {
542 - List<T> addItemInBetween<A extends T>(A item) => this.length == 0 542 + List<T> addItemInBetween<A extends T>(A item) => isEmpty
543 ? this 543 ? this
544 - : (this.fold([], (r, element) => [...r, element, item])..removeLast()); 544 + : (fold([], (r, element) => [...r, element, item])..removeLast());
545 } 545 }
546 546
547 class SimpleSliverDelegate extends SliverPersistentHeaderDelegate { 547 class SimpleSliverDelegate extends SliverPersistentHeaderDelegate {
@@ -92,12 +92,12 @@ class MyApp extends StatelessWidget { @@ -92,12 +92,12 @@ class MyApp extends StatelessWidget {
92 } 92 }
93 93
94 class MyHomePage extends StatefulWidget { 94 class MyHomePage extends StatefulWidget {
95 - MyHomePage({Key? key, required this.title}) : super(key: key); 95 + MyHomePage({super.key, required this.title});
96 96
97 final String title; 97 final String title;
98 98
99 @override 99 @override
100 - _MyHomePageState createState() => _MyHomePageState(); 100 + State<MyHomePage> createState() => _MyHomePageState();
101 } 101 }
102 102
103 class _MyHomePageState extends State<MyHomePage> { 103 class _MyHomePageState extends State<MyHomePage> {
@@ -11,11 +11,10 @@ class AvatarBottomSheet extends StatelessWidget { @@ -11,11 +11,10 @@ class AvatarBottomSheet extends StatelessWidget {
11 final SystemUiOverlayStyle? overlayStyle; 11 final SystemUiOverlayStyle? overlayStyle;
12 12
13 const AvatarBottomSheet( 13 const AvatarBottomSheet(
14 - {Key? key, 14 + {super.key,
15 required this.child, 15 required this.child,
16 required this.animation, 16 required this.animation,
17 - this.overlayStyle})  
18 - : super(key: key); 17 + this.overlayStyle});
19 18
20 @override 19 @override
21 Widget build(BuildContext context) { 20 Widget build(BuildContext context) {
@@ -5,8 +5,7 @@ class FloatingModal extends StatelessWidget { @@ -5,8 +5,7 @@ class FloatingModal extends StatelessWidget {
5 final Widget child; 5 final Widget child;
6 final Color? backgroundColor; 6 final Color? backgroundColor;
7 7
8 - const FloatingModal({Key? key, required this.child, this.backgroundColor})  
9 - : super(key: key); 8 + const FloatingModal({super.key, required this.child, this.backgroundColor});
10 9
11 @override 10 @override
12 Widget build(BuildContext context) { 11 Widget build(BuildContext context) {
@@ -3,7 +3,7 @@ import 'package:flutter/material.dart'; @@ -3,7 +3,7 @@ import 'package:flutter/material.dart';
3 import 'package:modal_bottom_sheet/modal_bottom_sheet.dart'; 3 import 'package:modal_bottom_sheet/modal_bottom_sheet.dart';
4 4
5 class ComplexModal extends StatelessWidget { 5 class ComplexModal extends StatelessWidget {
6 - const ComplexModal({Key? key}) : super(key: key); 6 + const ComplexModal({super.key});
7 7
8 @override 8 @override
9 Widget build(BuildContext context) { 9 Widget build(BuildContext context) {
1 import 'package:flutter/material.dart'; 1 import 'package:flutter/material.dart';
2 2
3 class ModalFit extends StatelessWidget { 3 class ModalFit extends StatelessWidget {
4 - const ModalFit({Key? key}) : super(key: key); 4 + const ModalFit({super.key});
5 5
6 @override 6 @override
7 Widget build(BuildContext context) { 7 Widget build(BuildContext context) {
@@ -5,7 +5,7 @@ import 'package:modal_bottom_sheet/modal_bottom_sheet.dart'; @@ -5,7 +5,7 @@ import 'package:modal_bottom_sheet/modal_bottom_sheet.dart';
5 class ModalInsideModal extends StatelessWidget { 5 class ModalInsideModal extends StatelessWidget {
6 final bool reverse; 6 final bool reverse;
7 7
8 - const ModalInsideModal({Key? key, this.reverse = false}) : super(key: key); 8 + const ModalInsideModal({super.key, this.reverse = false});
9 9
10 @override 10 @override
11 Widget build(BuildContext context) { 11 Widget build(BuildContext context) {
@@ -2,7 +2,7 @@ import 'package:flutter/cupertino.dart'; @@ -2,7 +2,7 @@ import 'package:flutter/cupertino.dart';
2 import 'package:flutter/material.dart'; 2 import 'package:flutter/material.dart';
3 3
4 class SimpleModal extends StatelessWidget { 4 class SimpleModal extends StatelessWidget {
5 - const SimpleModal({Key? key}) : super(key: key); 5 + const SimpleModal({super.key});
6 6
7 @override 7 @override
8 Widget build(BuildContext context) { 8 Widget build(BuildContext context) {
@@ -2,7 +2,7 @@ import 'package:flutter/cupertino.dart'; @@ -2,7 +2,7 @@ import 'package:flutter/cupertino.dart';
2 import 'package:flutter/material.dart'; 2 import 'package:flutter/material.dart';
3 3
4 class ModalWillScope extends StatelessWidget { 4 class ModalWillScope extends StatelessWidget {
5 - const ModalWillScope({Key? key}) : super(key: key); 5 + const ModalWillScope({super.key});
6 6
7 @override 7 @override
8 Widget build(BuildContext context) { 8 Widget build(BuildContext context) {
@@ -3,30 +3,30 @@ import 'package:flutter/material.dart'; @@ -3,30 +3,30 @@ import 'package:flutter/material.dart';
3 import 'package:modal_bottom_sheet/modal_bottom_sheet.dart'; 3 import 'package:modal_bottom_sheet/modal_bottom_sheet.dart';
4 4
5 class ModalWithNavigator extends StatelessWidget { 5 class ModalWithNavigator extends StatelessWidget {
6 - const ModalWithNavigator({Key? key}) : super(key: key); 6 + const ModalWithNavigator({super.key});
7 7
8 @override 8 @override
9 - Widget build(BuildContext rootContext) { 9 + Widget build(BuildContext context) {
10 return Material( 10 return Material(
11 child: Navigator( 11 child: Navigator(
12 onGenerateRoute: (_) => MaterialPageRoute( 12 onGenerateRoute: (_) => MaterialPageRoute(
13 - builder: (context2) => Builder(  
14 - builder: (context) => CupertinoPageScaffold( 13 + builder: (childContext) => Builder(
  14 + builder: (childContext2) => CupertinoPageScaffold(
15 navigationBar: CupertinoNavigationBar( 15 navigationBar: CupertinoNavigationBar(
16 leading: Container(), middle: Text('Modal Page')), 16 leading: Container(), middle: Text('Modal Page')),
17 child: SafeArea( 17 child: SafeArea(
18 bottom: false, 18 bottom: false,
19 child: ListView( 19 child: ListView(
20 shrinkWrap: true, 20 shrinkWrap: true,
21 - controller: ModalScrollController.of(context), 21 + controller: ModalScrollController.of(childContext2),
22 children: ListTile.divideTiles( 22 children: ListTile.divideTiles(
23 - context: context, 23 + context: childContext2,
24 tiles: List.generate( 24 tiles: List.generate(
25 100, 25 100,
26 (index) => ListTile( 26 (index) => ListTile(
27 title: Text('Item'), 27 title: Text('Item'),
28 onTap: () { 28 onTap: () {
29 - Navigator.of(context).push( 29 + Navigator.of(childContext2).push(
30 MaterialPageRoute( 30 MaterialPageRoute(
31 builder: (context) => CupertinoPageScaffold( 31 builder: (context) => CupertinoPageScaffold(
32 navigationBar: CupertinoNavigationBar( 32 navigationBar: CupertinoNavigationBar(
@@ -37,7 +37,7 @@ class ModalWithNavigator extends StatelessWidget { @@ -37,7 +37,7 @@ class ModalWithNavigator extends StatelessWidget {
37 children: <Widget>[ 37 children: <Widget>[
38 MaterialButton( 38 MaterialButton(
39 onPressed: () => 39 onPressed: () =>
40 - Navigator.of(rootContext).pop(), 40 + Navigator.of(context).pop(),
41 child: Text('touch here'), 41 child: Text('touch here'),
42 ) 42 )
43 ], 43 ],
@@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; @@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
2 import 'package:modal_bottom_sheet/modal_bottom_sheet.dart'; 2 import 'package:modal_bottom_sheet/modal_bottom_sheet.dart';
3 3
4 class NestedScrollModal extends StatelessWidget { 4 class NestedScrollModal extends StatelessWidget {
5 - const NestedScrollModal({Key? key}) : super(key: key); 5 + const NestedScrollModal({super.key});
6 6
7 @override 7 @override
8 Widget build(BuildContext context) { 8 Widget build(BuildContext context) {
@@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; @@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
2 import 'package:modal_bottom_sheet/modal_bottom_sheet.dart'; 2 import 'package:modal_bottom_sheet/modal_bottom_sheet.dart';
3 3
4 class ModalWithPageView extends StatelessWidget { 4 class ModalWithPageView extends StatelessWidget {
5 - const ModalWithPageView({Key? key}) : super(key: key); 5 + const ModalWithPageView({super.key});
6 6
7 @override 7 @override
8 Widget build(BuildContext context) { 8 Widget build(BuildContext context) {
@@ -3,7 +3,7 @@ import 'package:flutter/material.dart'; @@ -3,7 +3,7 @@ import 'package:flutter/material.dart';
3 import 'package:modal_bottom_sheet/modal_bottom_sheet.dart'; 3 import 'package:modal_bottom_sheet/modal_bottom_sheet.dart';
4 4
5 class ModalWithScroll extends StatelessWidget { 5 class ModalWithScroll extends StatelessWidget {
6 - const ModalWithScroll({Key? key}) : super(key: key); 6 + const ModalWithScroll({super.key});
7 7
8 @override 8 @override
9 Widget build(BuildContext context) { 9 Widget build(BuildContext context) {
@@ -6,7 +6,7 @@ import 'package:url_launcher/url_launcher_string.dart'; @@ -6,7 +6,7 @@ import 'package:url_launcher/url_launcher_string.dart';
6 class WebFrame extends StatelessWidget { 6 class WebFrame extends StatelessWidget {
7 final Widget child; 7 final Widget child;
8 8
9 - const WebFrame({Key? key, required this.child}) : super(key: key); 9 + const WebFrame({super.key, required this.child});
10 10
11 @override 11 @override
12 Widget build(BuildContext context) { 12 Widget build(BuildContext context) {
@@ -37,10 +37,10 @@ packages: @@ -37,10 +37,10 @@ packages:
37 dependency: transitive 37 dependency: transitive
38 description: 38 description:
39 name: collection 39 name: collection
40 - sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687 40 + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
41 url: "https://pub.dev" 41 url: "https://pub.dev"
42 source: hosted 42 source: hosted
43 - version: "1.17.2" 43 + version: "1.18.0"
44 cupertino_icons: 44 cupertino_icons:
45 dependency: "direct main" 45 dependency: "direct main"
46 description: 46 description:
@@ -72,6 +72,14 @@ packages: @@ -72,6 +72,14 @@ packages:
72 description: flutter 72 description: flutter
73 source: sdk 73 source: sdk
74 version: "0.0.0" 74 version: "0.0.0"
  75 + lints:
  76 + dependency: "direct dev"
  77 + description:
  78 + name: lints
  79 + sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290
  80 + url: "https://pub.dev"
  81 + source: hosted
  82 + version: "3.0.0"
75 matcher: 83 matcher:
76 dependency: transitive 84 dependency: transitive
77 description: 85 description:
@@ -92,10 +100,10 @@ packages: @@ -92,10 +100,10 @@ packages:
92 dependency: transitive 100 dependency: transitive
93 description: 101 description:
94 name: meta 102 name: meta
95 - sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" 103 + sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e
96 url: "https://pub.dev" 104 url: "https://pub.dev"
97 source: hosted 105 source: hosted
98 - version: "1.9.1" 106 + version: "1.10.0"
99 modal_bottom_sheet: 107 modal_bottom_sheet:
100 dependency: "direct main" 108 dependency: "direct main"
101 description: 109 description:
@@ -136,18 +144,18 @@ packages: @@ -136,18 +144,18 @@ packages:
136 dependency: transitive 144 dependency: transitive
137 description: 145 description:
138 name: stack_trace 146 name: stack_trace
139 - sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 147 + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
140 url: "https://pub.dev" 148 url: "https://pub.dev"
141 source: hosted 149 source: hosted
142 - version: "1.11.0" 150 + version: "1.11.1"
143 stream_channel: 151 stream_channel:
144 dependency: transitive 152 dependency: transitive
145 description: 153 description:
146 name: stream_channel 154 name: stream_channel
147 - sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" 155 + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
148 url: "https://pub.dev" 156 url: "https://pub.dev"
149 source: hosted 157 source: hosted
150 - version: "2.1.1" 158 + version: "2.1.2"
151 string_scanner: 159 string_scanner:
152 dependency: transitive 160 dependency: transitive
153 description: 161 description:
@@ -168,10 +176,10 @@ packages: @@ -168,10 +176,10 @@ packages:
168 dependency: transitive 176 dependency: transitive
169 description: 177 description:
170 name: test_api 178 name: test_api
171 - sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8" 179 + sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b"
172 url: "https://pub.dev" 180 url: "https://pub.dev"
173 source: hosted 181 source: hosted
174 - version: "0.6.0" 182 + version: "0.6.1"
175 url_launcher: 183 url_launcher:
176 dependency: "direct main" 184 dependency: "direct main"
177 description: 185 description:
@@ -248,10 +256,10 @@ packages: @@ -248,10 +256,10 @@ packages:
248 dependency: transitive 256 dependency: transitive
249 description: 257 description:
250 name: web 258 name: web
251 - sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10 259 + sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152
252 url: "https://pub.dev" 260 url: "https://pub.dev"
253 source: hosted 261 source: hosted
254 - version: "0.1.4-beta" 262 + version: "0.3.0"
255 sdks: 263 sdks:
256 - dart: ">=3.1.0 <4.0.0" 264 + dart: ">=3.2.0-194.0.dev <4.0.0"
257 flutter: ">=3.13.0" 265 flutter: ">=3.13.0"
1 name: example 1 name: example
2 description: A new Flutter project. 2 description: A new Flutter project.
3 publish_to: none 3 publish_to: none
4 -# The following defines the version and build number for your application.  
5 -# A version number is three numbers separated by dots, like 1.2.43  
6 -# followed by an optional build number separated by a +.  
7 -# Both the version and the builder number may be overridden in flutter  
8 -# build by specifying --build-name and --build-number, respectively.  
9 -# In Android, build-name is used as versionName while build-number used as versionCode.  
10 -# Read more about Android versioning at https://developer.android.com/studio/publish/versioning  
11 -# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.  
12 -# Read more about iOS versioning at  
13 -# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html  
14 version: 1.0.0+1 4 version: 1.0.0+1
15 5
16 environment: 6 environment:
17 - sdk: '>=2.17.0 <3.0.0'  
18 - flutter: ">=3.7.0"  
19 - 7 + sdk: ">=3.0.0 <4.0.0"
20 8
21 dependencies: 9 dependencies:
22 - cupertino_icons: ^1.0.5 10 + cupertino_icons: ^1.0.6
23 flutter: 11 flutter:
24 sdk: flutter 12 sdk: flutter
25 modal_bottom_sheet: 13 modal_bottom_sheet:
26 path: '../' 14 path: '../'
27 - url_launcher: ^6.1.5 15 + url_launcher: ^6.2.1
28 16
29 dev_dependencies: 17 dev_dependencies:
30 flutter_test: 18 flutter_test:
31 sdk: flutter 19 sdk: flutter
  20 + lints: ^3.0.0
32 21
33 -# For information on the generic Dart part of this file, see the  
34 -# following page: https://dart.dev/tools/pub/pubspec  
35 22
36 -# The following section is specific to Flutter.  
37 flutter: 23 flutter:
38 -  
39 - # The following line ensures that the Material Icons font is  
40 - # included with your application, so that you can use the icons in  
41 - # the material Icons class.  
42 uses-material-design: true 24 uses-material-design: true
43 -  
44 assets: 25 assets:
45 - - assets/  
46 - # To add assets to your application, add an assets section, like this:  
47 - # assets:  
48 - # - images/a_dot_burr.jpeg  
49 - # - images/a_dot_ham.jpeg  
50 -  
51 - # An image asset can refer to one or more resolution-specific "variants", see  
52 - # https://flutter.dev/assets-and-images/#resolution-aware.  
53 -  
54 - # For details regarding adding assets from package dependencies, see  
55 - # https://flutter.dev/assets-and-images/#from-packages  
56 -  
57 - # To add custom fonts to your application, add a fonts section here,  
58 - # in this "flutter" section. Each entry in this list should have a  
59 - # "family" key with the font family name, and a "fonts" key with a  
60 - # list giving the asset and other descriptors for the font. For  
61 - # example:  
62 - # fonts:  
63 - # - family: Schyler  
64 - # fonts:  
65 - # - asset: fonts/Schyler-Regular.ttf  
66 - # - asset: fonts/Schyler-Italic.ttf  
67 - # style: italic  
68 - # - family: Trajan Pro  
69 - # fonts:  
70 - # - asset: fonts/TrajanPro.ttf  
71 - # - asset: fonts/TrajanPro_Bold.ttf  
72 - # weight: 700  
73 - #  
74 - # For details regarding fonts from package dependencies,  
75 - # see https://flutter.dev/custom-fonts/#from-packages 26 + - assets/
@@ -47,7 +47,7 @@ class ModalBottomSheet extends StatefulWidget { @@ -47,7 +47,7 @@ class ModalBottomSheet extends StatefulWidget {
47 this.minFlingVelocity = _minFlingVelocity, 47 this.minFlingVelocity = _minFlingVelocity,
48 double? closeProgressThreshold, 48 double? closeProgressThreshold,
49 this.willPopThreshold = _willPopThreshold, 49 this.willPopThreshold = _willPopThreshold,
50 - }) : closeProgressThreshold = 50 + }) : closeProgressThreshold =
51 closeProgressThreshold ?? _closeProgressThreshold; 51 closeProgressThreshold ?? _closeProgressThreshold;
52 52
53 /// The closeProgressThreshold parameter 53 /// The closeProgressThreshold parameter
@@ -231,7 +231,6 @@ class ModalBottomSheetState extends State<ModalBottomSheet> @@ -231,7 +231,6 @@ class ModalBottomSheetState extends State<ModalBottomSheet>
231 231
232 if (_dismissUnderway || !isDragging) return; 232 if (_dismissUnderway || !isDragging) return;
233 isDragging = false; 233 isDragging = false;
234 - // ignore: unawaited_futures  
235 _bounceDragController.reverse(); 234 _bounceDragController.reverse();
236 235
237 Future<void> tryClose() async { 236 Future<void> tryClose() async {
@@ -251,7 +250,6 @@ class ModalBottomSheetState extends State<ModalBottomSheet> @@ -251,7 +250,6 @@ class ModalBottomSheetState extends State<ModalBottomSheet>
251 tryClose(); 250 tryClose();
252 } else if (hasReachedCloseThreshold) { 251 } else if (hasReachedCloseThreshold) {
253 if (widget.animationController.value > 0.0) { 252 if (widget.animationController.value > 0.0) {
254 - // ignore: unawaited_futures  
255 widget.animationController.fling(velocity: -1.0); 253 widget.animationController.fling(velocity: -1.0);
256 } 254 }
257 tryClose(); 255 tryClose();
@@ -273,13 +271,11 @@ class ModalBottomSheetState extends State<ModalBottomSheet> @@ -273,13 +271,11 @@ class ModalBottomSheetState extends State<ModalBottomSheet>
273 if (!_scrollController.hasClients) return; 271 if (!_scrollController.hasClients) return;
274 272
275 ScrollPosition scrollPosition; 273 ScrollPosition scrollPosition;
276 - // ignore: invalid_use_of_protected_member 274 +
277 if (_scrollController.positions.length > 1) { 275 if (_scrollController.positions.length > 1) {
278 - // ignore: invalid_use_of_protected_member  
279 - scrollPosition = _scrollController.positions  
280 - .firstWhere((p) => p.isScrollingNotifier.value,  
281 - // ignore: invalid_use_of_protected_member  
282 - orElse: () => _scrollController.positions.first); 276 + scrollPosition = _scrollController.positions.firstWhere(
  277 + (p) => p.isScrollingNotifier.value,
  278 + orElse: () => _scrollController.positions.first);
283 } else { 279 } else {
284 scrollPosition = _scrollController.position; 280 scrollPosition = _scrollController.position;
285 } 281 }
@@ -412,9 +408,15 @@ class ModalBottomSheetState extends State<ModalBottomSheet> @@ -412,9 +408,15 @@ class ModalBottomSheetState extends State<ModalBottomSheet>
412 child: RepaintBoundary(child: child), 408 child: RepaintBoundary(child: child),
413 ); 409 );
414 410
415 - return ScrollToTopStatusBarHandler( 411 + return StatusBarGestureDetector(
416 child: child, 412 child: child,
417 - scrollController: _scrollController, 413 + onTap: (context) {
  414 + _scrollController.animateTo(
  415 + 0.0,
  416 + duration: const Duration(milliseconds: 1000),
  417 + curve: Curves.easeOutCirc,
  418 + );
  419 + },
418 ); 420 );
419 } 421 }
420 } 422 }
@@ -395,7 +395,7 @@ class CupertinoScaffoldInheirted extends InheritedWidget { @@ -395,7 +395,7 @@ class CupertinoScaffoldInheirted extends InheritedWidget {
395 required super.child, 395 required super.child,
396 this.topRadius, 396 this.topRadius,
397 required this.transitionBackgroundColor, 397 required this.transitionBackgroundColor,
398 - }) : super(); 398 + });
399 399
400 @override 400 @override
401 bool updateShouldNotify(InheritedWidget oldWidget) { 401 bool updateShouldNotify(InheritedWidget oldWidget) {
1 -import 'package:flutter/widgets.dart'; 1 +import 'package:flutter/material.dart';
2 2
3 -/// Widget that that will scroll to the top the ScrollController 3 +typedef StatusBarGestureDetectorCallback = void Function(BuildContext context);
  4 +
  5 +/// Widget that that will make the [scrollController] to scroll the top
4 /// when tapped on the status bar 6 /// when tapped on the status bar
5 /// 7 ///
6 -/// Extracted from Scaffold and used in modal bottom sheet  
7 -class ScrollToTopStatusBarHandler extends StatefulWidget {  
8 - final Widget child;  
9 - final ScrollController scrollController;  
10 -  
11 - const ScrollToTopStatusBarHandler({ 8 +/// Extracted from [Scaffold] and used in [Sheet]
  9 +class StatusBarGestureDetector extends StatefulWidget {
  10 + const StatusBarGestureDetector({
12 super.key, 11 super.key,
13 required this.child, 12 required this.child,
14 - required this.scrollController, 13 + required this.onTap,
15 }); 14 });
16 15
  16 + final Widget child;
  17 +
  18 + final StatusBarGestureDetectorCallback onTap;
  19 +
17 @override 20 @override
18 - ScrollToTopStatusBarState createState() => ScrollToTopStatusBarState(); 21 + State<StatusBarGestureDetector> createState() =>
  22 + _StatusBarGestureDetectorState();
19 } 23 }
20 24
21 -class ScrollToTopStatusBarState extends State<ScrollToTopStatusBarHandler> { 25 +class _StatusBarGestureDetectorState extends State<StatusBarGestureDetector> {
  26 + final OverlayPortalController controller = OverlayPortalController();
  27 +
22 @override 28 @override
23 void initState() { 29 void initState() {
  30 + controller.show();
24 super.initState(); 31 super.initState();
25 } 32 }
26 33
27 @override 34 @override
28 Widget build(BuildContext context) { 35 Widget build(BuildContext context) {
29 - return Stack(  
30 - fit: StackFit.expand,  
31 - children: [  
32 - widget.child,  
33 - Positioned(  
34 - top: 0,  
35 - left: 0,  
36 - right: 0,  
37 - height: MediaQuery.of(context).padding.top,  
38 - child: Builder(  
39 - builder: (context) => GestureDetector( 36 + final view = View.of(context);
  37 + return OverlayPortal.targetsRootOverlay(
  38 + controller: controller,
  39 + overlayChildBuilder: (context) {
  40 + return Align(
  41 + alignment: Alignment.topCenter,
  42 + child: SizedBox(
  43 + height: view.padding.top / view.devicePixelRatio,
  44 + width: double.infinity,
  45 + child: GestureDetector(
40 behavior: HitTestBehavior.opaque, 46 behavior: HitTestBehavior.opaque,
41 - onTap: () => _handleStatusBarTap(context), 47 + onTap: () => widget.onTap(context),
42 // iOS accessibility automatically adds scroll-to-top to the clock in the status bar 48 // iOS accessibility automatically adds scroll-to-top to the clock in the status bar
43 excludeFromSemantics: true, 49 excludeFromSemantics: true,
44 ), 50 ),
45 ), 51 ),
46 - ),  
47 - ], 52 + );
  53 + },
  54 + child: widget.child,
48 ); 55 );
49 } 56 }
50 -  
51 - void _handleStatusBarTap(BuildContext context) {  
52 - final controller = widget.scrollController;  
53 - if (controller.hasClients) {  
54 - controller.animateTo(  
55 - 0.0,  
56 - duration: const Duration(milliseconds: 300),  
57 - curve: Curves.linear, // TODO(ianh): Use a more appropriate curve.  
58 - );  
59 - }  
60 - }  
61 } 57 }
  1 +include: package:lints/recommended.yaml
@@ -127,7 +127,7 @@ @@ -127,7 +127,7 @@
127 97C146E61CF9000F007C117D /* Project object */ = { 127 97C146E61CF9000F007C117D /* Project object */ = {
128 isa = PBXProject; 128 isa = PBXProject;
129 attributes = { 129 attributes = {
130 - LastUpgradeCheck = 1300; 130 + LastUpgradeCheck = 1430;
131 ORGANIZATIONNAME = ""; 131 ORGANIZATIONNAME = "";
132 TargetAttributes = { 132 TargetAttributes = {
133 97C146ED1CF9000F007C117D = { 133 97C146ED1CF9000F007C117D = {
1 <?xml version="1.0" encoding="UTF-8"?> 1 <?xml version="1.0" encoding="UTF-8"?>
2 <Scheme 2 <Scheme
3 - LastUpgradeVersion = "1300" 3 + LastUpgradeVersion = "1430"
4 version = "1.3"> 4 version = "1.3">
5 <BuildAction 5 <BuildAction
6 parallelizeBuildables = "YES" 6 parallelizeBuildables = "YES"
@@ -3,15 +3,14 @@ import 'package:flutter/material.dart'; @@ -3,15 +3,14 @@ import 'package:flutter/material.dart';
3 3
4 class ExampleTile extends StatelessWidget { 4 class ExampleTile extends StatelessWidget {
5 const ExampleTile({ 5 const ExampleTile({
6 - Key? key, 6 + super.key,
7 required this.title, 7 required this.title,
8 required this.page, 8 required this.page,
9 this.leading, 9 this.leading,
10 - }) : super(key: key); 10 + });
11 11
12 ExampleTile.sheet(this.title, Widget sheet, {this.leading}) 12 ExampleTile.sheet(this.title, Widget sheet, {this.leading})
13 - : page = BaseScaffold(title: Text(title), sheet: sheet),  
14 - super(); 13 + : page = BaseScaffold(title: Text(title), sheet: sheet);
15 14
16 final String title; 15 final String title;
17 final Widget page; 16 final Widget page;
@@ -33,11 +32,11 @@ class ExampleTile extends StatelessWidget { @@ -33,11 +32,11 @@ class ExampleTile extends StatelessWidget {
33 32
34 class BaseScaffold extends StatelessWidget { 33 class BaseScaffold extends StatelessWidget {
35 const BaseScaffold({ 34 const BaseScaffold({
36 - Key? key, 35 + super.key,
37 this.sheet, 36 this.sheet,
38 this.title, 37 this.title,
39 this.appBarTrailingButton, 38 this.appBarTrailingButton,
40 - }) : super(key: key); 39 + });
41 40
42 final Widget? sheet; 41 final Widget? sheet;
43 final Widget? title; 42 final Widget? title;
@@ -142,7 +142,7 @@ class FilterEditor extends StatelessWidget { @@ -142,7 +142,7 @@ class FilterEditor extends StatelessWidget {
142 ), 142 ),
143 ), 143 ),
144 ], 144 ],
145 - ).toList(), 145 + ),
146 const SectionTitle('Appareance'), 146 const SectionTitle('Appareance'),
147 ...ListTile.divideTiles( 147 ...ListTile.divideTiles(
148 context: context, 148 context: context,
@@ -221,7 +221,7 @@ class FilterEditor extends StatelessWidget { @@ -221,7 +221,7 @@ class FilterEditor extends StatelessWidget {
221 }), 221 }),
222 ), 222 ),
223 ], 223 ],
224 - ).toList(), 224 + ),
225 const SectionTitle('Physics'), 225 const SectionTitle('Physics'),
226 ...ListTile.divideTiles( 226 ...ListTile.divideTiles(
227 context: context, 227 context: context,
@@ -251,7 +251,7 @@ class FilterEditor extends StatelessWidget { @@ -251,7 +251,7 @@ class FilterEditor extends StatelessWidget {
251 ), 251 ),
252 ), 252 ),
253 ], 253 ],
254 - ).toList(), 254 + ),
255 ]), 255 ]),
256 ), 256 ),
257 ); 257 );
@@ -259,8 +259,7 @@ class FilterEditor extends StatelessWidget { @@ -259,8 +259,7 @@ class FilterEditor extends StatelessWidget {
259 } 259 }
260 260
261 class NumTextField extends StatelessWidget { 261 class NumTextField extends StatelessWidget {
262 - const NumTextField({Key? key, this.onChanged, this.maxNumber = 999})  
263 - : super(key: key); 262 + const NumTextField({super.key, this.onChanged, this.maxNumber = 999});
264 final ValueChanged<int?>? onChanged; 263 final ValueChanged<int?>? onChanged;
265 final int maxNumber; 264 final int maxNumber;
266 @override 265 @override
@@ -318,8 +317,8 @@ class NumericalRangeFormatter extends TextInputFormatter { @@ -318,8 +317,8 @@ class NumericalRangeFormatter extends TextInputFormatter {
318 class SectionTitle extends StatelessWidget { 317 class SectionTitle extends StatelessWidget {
319 const SectionTitle( 318 const SectionTitle(
320 this.text, { 319 this.text, {
321 - Key? key,  
322 - }) : super(key: key); 320 + super.key,
  321 + });
323 322
324 final String text; 323 final String text;
325 324
@@ -3,7 +3,7 @@ import 'package:flutter/material.dart'; @@ -3,7 +3,7 @@ import 'package:flutter/material.dart';
3 import 'package:sheet/route.dart'; 3 import 'package:sheet/route.dart';
4 4
5 class ModalInsideModal extends StatelessWidget { 5 class ModalInsideModal extends StatelessWidget {
6 - const ModalInsideModal({Key? key, this.reverse = false}) : super(key: key); 6 + const ModalInsideModal({super.key, this.reverse = false});
7 final bool reverse; 7 final bool reverse;
8 8
9 @override 9 @override
@@ -2,8 +2,7 @@ import 'package:flutter/cupertino.dart'; @@ -2,8 +2,7 @@ import 'package:flutter/cupertino.dart';
2 import 'package:flutter/material.dart'; 2 import 'package:flutter/material.dart';
3 3
4 class SimpleModal extends StatelessWidget { 4 class SimpleModal extends StatelessWidget {
5 - const SimpleModal({Key? key, required this.scrollController})  
6 - : super(key: key); 5 + const SimpleModal({super.key, required this.scrollController});
7 final ScrollController scrollController; 6 final ScrollController scrollController;
8 7
9 @override 8 @override
@@ -24,8 +24,7 @@ class AvatarSheetRoute<T> extends SheetRoute<T> { @@ -24,8 +24,7 @@ class AvatarSheetRoute<T> extends SheetRoute<T> {
24 } 24 }
25 25
26 class _AvatarSheet extends StatelessWidget { 26 class _AvatarSheet extends StatelessWidget {
27 - const _AvatarSheet({Key? key, required this.child, required this.animation})  
28 - : super(key: key); 27 + const _AvatarSheet({required this.child, required this.animation});
29 final Widget child; 28 final Widget child;
30 final Animation<double> animation; 29 final Animation<double> animation;
31 30
1 import 'package:flutter/material.dart'; 1 import 'package:flutter/material.dart';
2 import 'package:flutter/services.dart'; 2 import 'package:flutter/services.dart';
3 import 'package:sheet/route.dart'; 3 import 'package:sheet/route.dart';
4 -import 'package:sheet/sheet.dart';  
5 4
6 -const Radius _default_bar_top_radius = Radius.circular(15); 5 +const Radius _defaultBarTopRadius = Radius.circular(15);
7 6
8 class BarBottomSheet extends StatelessWidget { 7 class BarBottomSheet extends StatelessWidget {
9 const BarBottomSheet( 8 const BarBottomSheet(
10 - {Key? key, 9 + {super.key,
11 required this.child, 10 required this.child,
12 this.control, 11 this.control,
13 this.clipBehavior, 12 this.clipBehavior,
14 this.shape, 13 this.shape,
15 - this.elevation})  
16 - : super(key: key); 14 + this.elevation});
17 final Widget child; 15 final Widget child;
18 final Widget? control; 16 final Widget? control;
19 final Clip? clipBehavior; 17 final Clip? clipBehavior;
@@ -49,8 +47,8 @@ class BarBottomSheet extends StatelessWidget { @@ -49,8 +47,8 @@ class BarBottomSheet extends StatelessWidget {
49 const RoundedRectangleBorder( 47 const RoundedRectangleBorder(
50 side: BorderSide(), 48 side: BorderSide(),
51 borderRadius: BorderRadius.only( 49 borderRadius: BorderRadius.only(
52 - topLeft: _default_bar_top_radius,  
53 - topRight: _default_bar_top_radius), 50 + topLeft: _defaultBarTopRadius,
  51 + topRight: _defaultBarTopRadius),
54 ), 52 ),
55 clipBehavior: clipBehavior ?? Clip.hardEdge, 53 clipBehavior: clipBehavior ?? Clip.hardEdge,
56 elevation: elevation ?? 2, 54 elevation: elevation ?? 2,
@@ -72,13 +70,13 @@ class BarSheetRoute<T> extends SheetRoute<T> { @@ -72,13 +70,13 @@ class BarSheetRoute<T> extends SheetRoute<T> {
72 double? elevation, 70 double? elevation,
73 ShapeBorder? shape, 71 ShapeBorder? shape,
74 Clip? clipBehavior, 72 Clip? clipBehavior,
75 - Color barrierColor = Colors.black87,  
76 - SheetFit fit = SheetFit.expand,  
77 - Curve? animationCurve, 73 + Color super.barrierColor = Colors.black87,
  74 + super.fit,
  75 + super.animationCurve,
78 bool isDismissible = true, 76 bool isDismissible = true,
79 bool enableDrag = true, 77 bool enableDrag = true,
80 Widget? topControl, 78 Widget? topControl,
81 - Duration? duration, 79 + super.duration,
82 }) : super( 80 }) : super(
83 builder: (BuildContext context) { 81 builder: (BuildContext context) {
84 return BarBottomSheet( 82 return BarBottomSheet(
@@ -89,11 +87,7 @@ class BarSheetRoute<T> extends SheetRoute<T> { @@ -89,11 +87,7 @@ class BarSheetRoute<T> extends SheetRoute<T> {
89 elevation: elevation, 87 elevation: elevation,
90 ); 88 );
91 }, 89 },
92 - fit: fit,  
93 barrierDismissible: isDismissible, 90 barrierDismissible: isDismissible,
94 - barrierColor: barrierColor,  
95 draggable: enableDrag, 91 draggable: enableDrag,
96 - animationCurve: animationCurve,  
97 - duration: duration,  
98 ); 92 );
99 } 93 }
@@ -3,8 +3,7 @@ import 'package:sheet/route.dart'; @@ -3,8 +3,7 @@ import 'package:sheet/route.dart';
3 import 'package:sheet/sheet.dart'; 3 import 'package:sheet/sheet.dart';
4 4
5 class DialogSheet extends StatelessWidget { 5 class DialogSheet extends StatelessWidget {
6 - const DialogSheet({Key? key, required this.child, this.backgroundColor})  
7 - : super(key: key); 6 + const DialogSheet({super.key, required this.child, this.backgroundColor});
8 final Widget child; 7 final Widget child;
9 final Color? backgroundColor; 8 final Color? backgroundColor;
10 9
@@ -3,8 +3,7 @@ import 'package:sheet/route.dart'; @@ -3,8 +3,7 @@ import 'package:sheet/route.dart';
3 import 'package:sheet/sheet.dart'; 3 import 'package:sheet/sheet.dart';
4 4
5 class FloatingModal extends StatelessWidget { 5 class FloatingModal extends StatelessWidget {
6 - const FloatingModal({Key? key, required this.child, this.backgroundColor})  
7 - : super(key: key); 6 + const FloatingModal({super.key, required this.child, this.backgroundColor});
8 final Widget child; 7 final Widget child;
9 final Color? backgroundColor; 8 final Color? backgroundColor;
10 9
1 import 'package:flutter/material.dart'; 1 import 'package:flutter/material.dart';
2 import 'package:sheet/route.dart'; 2 import 'package:sheet/route.dart';
3 -import 'package:sheet/sheet.dart';  
4 3
5 class MaterialSheetRoute<T> extends SheetRoute<T> { 4 class MaterialSheetRoute<T> extends SheetRoute<T> {
6 MaterialSheetRoute({ 5 MaterialSheetRoute({
@@ -9,14 +8,14 @@ class MaterialSheetRoute<T> extends SheetRoute<T> { @@ -9,14 +8,14 @@ class MaterialSheetRoute<T> extends SheetRoute<T> {
9 double? elevation, 8 double? elevation,
10 ShapeBorder? shape, 9 ShapeBorder? shape,
11 Clip? clipBehavior, 10 Clip? clipBehavior,
12 - Color barrierColor = Colors.black87,  
13 - SheetFit fit = SheetFit.expand,  
14 - Curve? animationCurve,  
15 - bool barrierDismissible = true, 11 + Color super.barrierColor = Colors.black87,
  12 + super.fit,
  13 + super.animationCurve,
  14 + super.barrierDismissible,
16 bool enableDrag = true, 15 bool enableDrag = true,
17 - List<double>? stops, 16 + super.stops,
18 double initialStop = 1, 17 double initialStop = 1,
19 - Duration? duration, 18 + super.duration,
20 }) : super( 19 }) : super(
21 builder: (BuildContext context) => Material( 20 builder: (BuildContext context) => Material(
22 child: Builder( 21 child: Builder(
@@ -27,13 +26,7 @@ class MaterialSheetRoute<T> extends SheetRoute<T> { @@ -27,13 +26,7 @@ class MaterialSheetRoute<T> extends SheetRoute<T> {
27 shape: shape, 26 shape: shape,
28 elevation: elevation ?? 1, 27 elevation: elevation ?? 1,
29 ), 28 ),
30 - stops: stops,  
31 initialExtent: initialStop, 29 initialExtent: initialStop,
32 - fit: fit,  
33 - barrierDismissible: barrierDismissible,  
34 - barrierColor: barrierColor,  
35 draggable: enableDrag, 30 draggable: enableDrag,
36 - animationCurve: animationCurve,  
37 - duration: duration,  
38 ); 31 );
39 } 32 }
  1 +import 'package:collection/collection.dart';
  2 +import 'package:flutter/cupertino.dart';
  3 +import 'package:flutter/material.dart';
  4 +import 'package:go_router/go_router.dart';
  5 +import 'package:sheet/route.dart';
  6 +
  7 +class Book {
  8 + const Book(this.id, this.title, this.author);
  9 + final String id;
  10 + final String title;
  11 + final String author;
  12 +}
  13 +
  14 +class AdvancedGoRouterBooksApp extends StatefulWidget {
  15 + @override
  16 + State<StatefulWidget> createState() => _GoRouterBooksAppState();
  17 +}
  18 +
  19 +class _GoRouterBooksAppState extends State<AdvancedGoRouterBooksApp> {
  20 + List<Book> books = <Book>[
  21 + const Book('1', 'Stranger in a Strange Land', 'Robert A. Heinlein'),
  22 + const Book('2', 'Foundation', 'Isaac Asimov'),
  23 + const Book('3', 'Fahrenheit 451', 'Ray Bradbury'),
  24 + ];
  25 +
  26 + @override
  27 + void initState() {
  28 + super.initState();
  29 + }
  30 +
  31 + Brightness brightness = Brightness.light;
  32 +
  33 + @override
  34 + Widget build(BuildContext context) {
  35 + return MaterialApp.router(
  36 + routeInformationProvider: _router.routeInformationProvider,
  37 + routeInformationParser: _router.routeInformationParser,
  38 + routerDelegate: _router.routerDelegate,
  39 + debugShowCheckedModeBanner: false,
  40 + theme:
  41 + brightness == Brightness.light ? ThemeData.light() : ThemeData.dark(),
  42 + title: 'Books App',
  43 + builder: (BuildContext context, Widget? child) {
  44 + return CupertinoTheme(
  45 + data: CupertinoThemeData(brightness: brightness),
  46 + child: child!,
  47 + );
  48 + },
  49 + );
  50 + }
  51 +
  52 + final rootNavigatorKey = GlobalKey<NavigatorState>();
  53 + final nestedNavigationKey = GlobalKey<NavigatorState>();
  54 + late final GoRouter _router = GoRouter(
  55 + debugLogDiagnostics: true,
  56 + navigatorKey: rootNavigatorKey,
  57 + routes: <GoRoute>[
  58 + GoRoute(
  59 + path: '/',
  60 + pageBuilder: (BuildContext context, GoRouterState state) {
  61 + return MaterialExtendedPage<void>(
  62 + key: state.pageKey,
  63 + child: BooksListScreen(
  64 + books: books,
  65 + onBrigthnessChanged: (Brightness brightness) {
  66 + setState(() {
  67 + this.brightness = brightness;
  68 + });
  69 + },
  70 + ),
  71 + );
  72 + },
  73 + routes: <RouteBase>[
  74 + ShellRoute(
  75 + navigatorKey: nestedNavigationKey,
  76 + parentNavigatorKey: rootNavigatorKey,
  77 + pageBuilder: (context, state, child) {
  78 + return CupertinoSheetPage<void>(child: child);
  79 + },
  80 + routes: [
  81 + GoRoute(
  82 + name: 'book',
  83 + path: 'book/:bid',
  84 + parentNavigatorKey: nestedNavigationKey,
  85 + pageBuilder: (BuildContext context, GoRouterState state) {
  86 + final String id = state.pathParameters['bid']!;
  87 + final Book? book =
  88 + books.firstWhereOrNull((Book b) => b.id == id);
  89 + return MaterialPage<void>(
  90 + key: state.pageKey,
  91 + child: BookDetailsScreen(
  92 + book: book!,
  93 + ),
  94 + );
  95 + },
  96 + redirect: (context, state) {
  97 + final String id = state.pathParameters['bid']!;
  98 + final Book? book =
  99 + books.firstWhereOrNull((Book b) => b.id == id);
  100 + if (book == null) {
  101 + return '/404';
  102 + }
  103 + // no need to redirect at all
  104 + return null;
  105 + },
  106 + routes: [
  107 + GoRoute(
  108 + name: 'Reviews',
  109 + path: 'reviews',
  110 + parentNavigatorKey: nestedNavigationKey,
  111 + pageBuilder: (context, state) {
  112 + return MaterialPage<void>(
  113 + key: state.pageKey,
  114 + child: Scaffold(
  115 + appBar: AppBar(
  116 + title: const Text('Reviews'),
  117 + ),
  118 + ),
  119 + );
  120 + },
  121 + ),
  122 + ]),
  123 + ]),
  124 + GoRoute(
  125 + name: 'new',
  126 + path: 'new',
  127 + parentNavigatorKey: rootNavigatorKey,
  128 + pageBuilder: (BuildContext context, GoRouterState state) {
  129 + return CupertinoSheetPage<void>(
  130 + key: state.pageKey,
  131 + child: Scaffold(
  132 + backgroundColor: Colors.grey[200],
  133 + appBar: AppBar(
  134 + title: const Text('New'),
  135 + ),
  136 + ),
  137 + );
  138 + },
  139 + ),
  140 + ]),
  141 + ],
  142 + );
  143 +}
  144 +
  145 +class BooksListScreen extends StatelessWidget {
  146 + const BooksListScreen({
  147 + required this.books,
  148 + required this.onBrigthnessChanged,
  149 + });
  150 + final List<Book> books;
  151 +
  152 + final void Function(Brightness) onBrigthnessChanged;
  153 +
  154 + @override
  155 + Widget build(BuildContext context) {
  156 + final Brightness brightness = Theme.of(context).brightness;
  157 + return Scaffold(
  158 + appBar: CupertinoNavigationBar(
  159 + leading: BackButton(onPressed: () {
  160 + Navigator.of(context, rootNavigator: true).pop();
  161 + }),
  162 + middle: const Text('Book'),
  163 + trailing: IconButton(
  164 + icon: Icon(brightness == Brightness.light
  165 + ? Icons.nightlight_round
  166 + : Icons.wb_sunny),
  167 + onPressed: () {
  168 + onBrigthnessChanged(
  169 + brightness == Brightness.light
  170 + ? Brightness.dark
  171 + : Brightness.light,
  172 + );
  173 + },
  174 + ),
  175 + ),
  176 + body: SafeArea(
  177 + child: ListView(
  178 + children: <Widget>[
  179 + for (Book book in books)
  180 + ListTile(
  181 + title: Text(book.title),
  182 + subtitle: Text(book.author),
  183 + onTap: () {
  184 + context.go('/book/${book.id}');
  185 + },
  186 + trailing: TextButton(
  187 + onPressed: () {
  188 + context.go('/book/${book.id}');
  189 + context.go('/book/${book.id}/reviews');
  190 + },
  191 + child: const Text('Reviews'),
  192 + ))
  193 + ],
  194 + ),
  195 + ),
  196 + );
  197 + }
  198 +}
  199 +
  200 +class BookDetailsScreen extends StatelessWidget {
  201 + const BookDetailsScreen({
  202 + required this.book,
  203 + });
  204 + final Book book;
  205 +
  206 + @override
  207 + Widget build(BuildContext context) {
  208 + return Scaffold(
  209 + appBar: const CupertinoNavigationBar(
  210 + middle: Text('Book'),
  211 + ),
  212 + body: Padding(
  213 + padding: const EdgeInsets.all(8.0) + const EdgeInsets.only(top: 52.0),
  214 + child: Column(
  215 + crossAxisAlignment: CrossAxisAlignment.stretch,
  216 + children: <Widget>[
  217 + Text(book.title, style: Theme.of(context).textTheme.titleLarge),
  218 + Text(book.author, style: Theme.of(context).textTheme.titleMedium),
  219 + TextButton(
  220 + onPressed: () {
  221 + context.go('/book/${book.id}/reviews');
  222 + },
  223 + child: Text('Reviews'),
  224 + )
  225 + ],
  226 + ),
  227 + ),
  228 + floatingActionButton: FloatingActionButton(
  229 + child: const Icon(Icons.add),
  230 + onPressed: () {
  231 + context.push('/new');
  232 + },
  233 + ),
  234 + );
  235 + }
  236 +}
@@ -20,7 +20,7 @@ class BounceTopSheet extends StatelessWidget { @@ -20,7 +20,7 @@ class BounceTopSheet extends StatelessWidget {
20 20
21 class BouncingSheetPage extends StatefulWidget { 21 class BouncingSheetPage extends StatefulWidget {
22 @override 22 @override
23 - _BouncingSheetPageState createState() => _BouncingSheetPageState(); 23 + State<BouncingSheetPage> createState() => _BouncingSheetPageState();
24 } 24 }
25 25
26 class _BouncingSheetPageState extends State<BouncingSheetPage> { 26 class _BouncingSheetPageState extends State<BouncingSheetPage> {
@@ -6,7 +6,7 @@ import 'package:sheet/sheet.dart'; @@ -6,7 +6,7 @@ import 'package:sheet/sheet.dart';
6 6
7 class ClampedSheet extends StatefulWidget { 7 class ClampedSheet extends StatefulWidget {
8 @override 8 @override
9 - _ClampedSheetState createState() => _ClampedSheetState(); 9 + State<ClampedSheet> createState() => _ClampedSheetState();
10 } 10 }
11 11
12 class _ClampedSheetState extends State<ClampedSheet> { 12 class _ClampedSheetState extends State<ClampedSheet> {
@@ -8,7 +8,7 @@ import 'package:sheet/sheet.dart'; @@ -8,7 +8,7 @@ import 'package:sheet/sheet.dart';
8 8
9 class AdvancedSnapSheetPage extends StatefulWidget { 9 class AdvancedSnapSheetPage extends StatefulWidget {
10 @override 10 @override
11 - _AdvancedSnapSheetPageState createState() => _AdvancedSnapSheetPageState(); 11 + State<AdvancedSnapSheetPage> createState() => _AdvancedSnapSheetPageState();
12 } 12 }
13 13
14 class _AdvancedSnapSheetPageState extends State<AdvancedSnapSheetPage> 14 class _AdvancedSnapSheetPageState extends State<AdvancedSnapSheetPage>
@@ -71,7 +71,7 @@ class _AdvancedSnapSheetPageState extends State<AdvancedSnapSheetPage> @@ -71,7 +71,7 @@ class _AdvancedSnapSheetPageState extends State<AdvancedSnapSheetPage>
71 } 71 }
72 72
73 class MapAppBar extends StatefulWidget implements PreferredSizeWidget { 73 class MapAppBar extends StatefulWidget implements PreferredSizeWidget {
74 - const MapAppBar({Key? key, required this.controller}) : super(key: key); 74 + const MapAppBar({super.key, required this.controller});
75 final SheetController controller; 75 final SheetController controller;
76 @override 76 @override
77 Size get preferredSize => Size.fromHeight(kToolbarHeight); 77 Size get preferredSize => Size.fromHeight(kToolbarHeight);
@@ -174,7 +174,7 @@ class _MapAppBarState extends State<MapAppBar> { @@ -174,7 +174,7 @@ class _MapAppBarState extends State<MapAppBar> {
174 } 174 }
175 175
176 class FloatingButtons extends StatelessWidget { 176 class FloatingButtons extends StatelessWidget {
177 - const FloatingButtons({Key? key, required this.controller}) : super(key: key); 177 + const FloatingButtons({super.key, required this.controller});
178 final SheetController controller; 178 final SheetController controller;
179 @override 179 @override
180 Widget build(BuildContext context) { 180 Widget build(BuildContext context) {
@@ -225,7 +225,7 @@ class FloatingButtons extends StatelessWidget { @@ -225,7 +225,7 @@ class FloatingButtons extends StatelessWidget {
225 } 225 }
226 226
227 class MapSheet extends StatelessWidget { 227 class MapSheet extends StatelessWidget {
228 - const MapSheet({Key? key, required this.controller}) : super(key: key); 228 + const MapSheet({super.key, required this.controller});
229 final SheetController controller; 229 final SheetController controller;
230 @override 230 @override
231 Widget build(BuildContext context) { 231 Widget build(BuildContext context) {
@@ -5,7 +5,7 @@ import 'package:sheet/sheet.dart'; @@ -5,7 +5,7 @@ import 'package:sheet/sheet.dart';
5 5
6 class FitResizableSheet extends StatefulWidget { 6 class FitResizableSheet extends StatefulWidget {
7 @override 7 @override
8 - _FitSheetState createState() => _FitSheetState(); 8 + State<FitResizableSheet> createState() => _FitSheetState();
9 } 9 }
10 10
11 class _FitSheetState extends State<FitResizableSheet> { 11 class _FitSheetState extends State<FitResizableSheet> {
@@ -6,7 +6,7 @@ import 'package:sheet/sheet.dart'; @@ -6,7 +6,7 @@ import 'package:sheet/sheet.dart';
6 6
7 class FitSnapSheet extends StatefulWidget { 7 class FitSnapSheet extends StatefulWidget {
8 @override 8 @override
9 - _FitSheetState createState() => _FitSheetState(); 9 + State<FitSnapSheet> createState() => _FitSheetState();
10 } 10 }
11 11
12 class _FitSheetState extends State<FitSnapSheet> { 12 class _FitSheetState extends State<FitSnapSheet> {
@@ -3,7 +3,7 @@ import 'package:sheet/sheet.dart'; @@ -3,7 +3,7 @@ import 'package:sheet/sheet.dart';
3 3
4 class FloatingSheet extends StatefulWidget { 4 class FloatingSheet extends StatefulWidget {
5 @override 5 @override
6 - _FitSheetState createState() => _FitSheetState(); 6 + State<FloatingSheet> createState() => _FitSheetState();
7 } 7 }
8 8
9 class _FitSheetState extends State<FloatingSheet> { 9 class _FitSheetState extends State<FloatingSheet> {
@@ -3,7 +3,7 @@ import 'package:sheet/sheet.dart'; @@ -3,7 +3,7 @@ import 'package:sheet/sheet.dart';
3 3
4 class FoldableScreenFloatingSheet extends StatefulWidget { 4 class FoldableScreenFloatingSheet extends StatefulWidget {
5 @override 5 @override
6 - _FitSheetState createState() => _FitSheetState(); 6 + State<FoldableScreenFloatingSheet> createState() => _FitSheetState();
7 } 7 }
8 8
9 class _FitSheetState extends State<FoldableScreenFloatingSheet> { 9 class _FitSheetState extends State<FoldableScreenFloatingSheet> {
@@ -6,7 +6,7 @@ import 'package:sheet/sheet.dart'; @@ -6,7 +6,7 @@ import 'package:sheet/sheet.dart';
6 6
7 class NoMomentumSheet extends StatefulWidget { 7 class NoMomentumSheet extends StatefulWidget {
8 @override 8 @override
9 - _NoMomentumSheetState createState() => _NoMomentumSheetState(); 9 + State<NoMomentumSheet> createState() => _NoMomentumSheetState();
10 } 10 }
11 11
12 class _NoMomentumSheetState extends State<NoMomentumSheet> { 12 class _NoMomentumSheetState extends State<NoMomentumSheet> {
@@ -6,7 +6,7 @@ import 'package:sheet/sheet.dart'; @@ -6,7 +6,7 @@ import 'package:sheet/sheet.dart';
6 6
7 class SnapSheet extends StatefulWidget { 7 class SnapSheet extends StatefulWidget {
8 @override 8 @override
9 - _SnapSheetState createState() => _SnapSheetState(); 9 + State<SnapSheet> createState() => _SnapSheetState();
10 } 10 }
11 11
12 class _SnapSheetState extends State<SnapSheet> { 12 class _SnapSheetState extends State<SnapSheet> {
@@ -4,7 +4,7 @@ import 'package:sheet/sheet.dart'; @@ -4,7 +4,7 @@ import 'package:sheet/sheet.dart';
4 4
5 class TextFieldSheet extends StatefulWidget { 5 class TextFieldSheet extends StatefulWidget {
6 @override 6 @override
7 - _TextFieldSheetState createState() => _TextFieldSheetState(); 7 + State<TextFieldSheet> createState() => _TextFieldSheetState();
8 } 8 }
9 9
10 class _TextFieldSheetState extends State<TextFieldSheet> 10 class _TextFieldSheetState extends State<TextFieldSheet>
1 import 'package:example/route_example_page.dart'; 1 import 'package:example/route_example_page.dart';
2 import 'package:example/sheet_example_page.dart'; 2 import 'package:example/sheet_example_page.dart';
3 import 'package:flutter/material.dart'; 3 import 'package:flutter/material.dart';
  4 +import 'package:go_router/go_router.dart';
4 import 'package:sheet/route.dart'; 5 import 'package:sheet/route.dart';
5 6
6 void main() => runApp(MyApp()); 7 void main() => runApp(MyApp());
7 8
  9 +final goRouter = GoRouter(routes: [
  10 + GoRoute(
  11 + path: '/',
  12 + pageBuilder: (context, state) =>
  13 + MaterialExtendedPage<void>(child: const BottomNavigationScaffold()),
  14 + ),
  15 +]);
  16 +
8 class MyApp extends StatelessWidget { 17 class MyApp extends StatelessWidget {
9 @override 18 @override
10 Widget build(BuildContext context) { 19 Widget build(BuildContext context) {
11 - return MaterialApp( 20 + return MaterialApp.router(
12 theme: ThemeData(platform: TargetPlatform.iOS), 21 theme: ThemeData(platform: TargetPlatform.iOS),
13 debugShowCheckedModeBanner: false, 22 debugShowCheckedModeBanner: false,
14 title: 'BottomSheet Modals', 23 title: 'BottomSheet Modals',
15 - onGenerateRoute: (RouteSettings settings) {  
16 - if (settings.name == '/') {  
17 - return MaterialExtendedPageRoute<void>(  
18 - builder: (BuildContext context) {  
19 - return const BottomNavigationScaffold();  
20 - },  
21 - );  
22 - }  
23 - return null;  
24 - }, 24 + routerConfig: goRouter,
25 ); 25 );
26 } 26 }
27 } 27 }
@@ -19,6 +19,7 @@ import 'package:sheet/sheet.dart'; @@ -19,6 +19,7 @@ import 'package:sheet/sheet.dart';
19 19
20 import 'examples/route/examples/modal_with_nested_scroll.dart'; 20 import 'examples/route/examples/modal_with_nested_scroll.dart';
21 import 'examples/route/navigation/go_router.dart'; 21 import 'examples/route/navigation/go_router.dart';
  22 +import 'examples/route/navigation/go_router_advanced.dart';
22 23
23 class RouteExamplePage extends StatelessWidget { 24 class RouteExamplePage extends StatelessWidget {
24 const RouteExamplePage({super.key}); 25 const RouteExamplePage({super.key});
@@ -84,6 +85,16 @@ class RouteExamplePage extends StatelessWidget { @@ -84,6 +85,16 @@ class RouteExamplePage extends StatelessWidget {
84 ), 85 ),
85 ), 86 ),
86 ), 87 ),
  88 + ListTile(
  89 + title: const Text('Go router - ShellRoutes'),
  90 + onTap: () => Navigator.of(context).push(
  91 + MaterialPageRoute<void>(
  92 + fullscreenDialog: true,
  93 + builder: (BuildContext context) =>
  94 + AdvancedGoRouterBooksApp(),
  95 + ),
  96 + ),
  97 + ),
87 const SectionTitle('STYLES'), 98 const SectionTitle('STYLES'),
88 ListTile( 99 ListTile(
89 title: const Text('Material fit'), 100 title: const Text('Material fit'),
@@ -313,11 +324,10 @@ class RouteExamplePage extends StatelessWidget { @@ -313,11 +324,10 @@ class RouteExamplePage extends StatelessWidget {
313 class SectionTitle extends StatelessWidget { 324 class SectionTitle extends StatelessWidget {
314 final String title; 325 final String title;
315 326
316 - // ignore: sort_constructors_first  
317 const SectionTitle( 327 const SectionTitle(
318 this.title, { 328 this.title, {
319 - Key? key,  
320 - }) : super(key: key); 329 + super.key,
  330 + });
321 @override 331 @override
322 Widget build(BuildContext context) { 332 Widget build(BuildContext context) {
323 return Padding( 333 return Padding(
@@ -75,11 +75,10 @@ class SheetExamplesPage extends StatelessWidget { @@ -75,11 +75,10 @@ class SheetExamplesPage extends StatelessWidget {
75 class SectionTitle extends StatelessWidget { 75 class SectionTitle extends StatelessWidget {
76 final String title; 76 final String title;
77 77
78 - // ignore: sort_constructors_first  
79 const SectionTitle( 78 const SectionTitle(
80 this.title, { 79 this.title, {
81 - Key? key,  
82 - }) : super(key: key); 80 + super.key,
  81 + });
83 @override 82 @override
84 Widget build(BuildContext context) { 83 Widget build(BuildContext context) {
85 return Padding( 84 return Padding(
@@ -34,7 +34,7 @@ packages: @@ -34,7 +34,7 @@ packages:
34 source: hosted 34 source: hosted
35 version: "1.1.1" 35 version: "1.1.1"
36 collection: 36 collection:
37 - dependency: transitive 37 + dependency: "direct main"
38 description: 38 description:
39 name: collection 39 name: collection
40 sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687 40 sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687
@@ -84,10 +84,18 @@ packages: @@ -84,10 +84,18 @@ packages:
84 dependency: "direct main" 84 dependency: "direct main"
85 description: 85 description:
86 name: go_router 86 name: go_router
87 - sha256: "2cb236ba3f923043fdbe14a6a3a796b8c250e85658e28caee3e86c0c275847e5" 87 + sha256: "5098760d7478aabfe682a462bf121d61bc5dbe5df5aac8dad733564a0aee33bc"
  88 + url: "https://pub.dev"
  89 + source: hosted
  90 + version: "12.1.0"
  91 + lints:
  92 + dependency: "direct dev"
  93 + description:
  94 + name: lints
  95 + sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290
88 url: "https://pub.dev" 96 url: "https://pub.dev"
89 source: hosted 97 source: hosted
90 - version: "8.2.0" 98 + version: "3.0.0"
91 logging: 99 logging:
92 dependency: transitive 100 dependency: transitive
93 description: 101 description:
@@ -222,4 +230,4 @@ packages: @@ -222,4 +230,4 @@ packages:
222 version: "0.1.4-beta" 230 version: "0.1.4-beta"
223 sdks: 231 sdks:
224 dart: ">=3.1.0-185.0.dev <4.0.0" 232 dart: ">=3.1.0-185.0.dev <4.0.0"
225 - flutter: ">=3.3.0" 233 + flutter: ">=3.7.0"
@@ -10,15 +10,17 @@ dependencies: @@ -10,15 +10,17 @@ dependencies:
10 flutter: 10 flutter:
11 sdk: flutter 11 sdk: flutter
12 equatable: ^2.0.5 12 equatable: ^2.0.5
13 - cupertino_icons: ^1.0.0 13 + collection:
  14 + cupertino_icons: ^1.0.6
14 provider: ^6.0.5 15 provider: ^6.0.5
15 sheet: 16 sheet:
16 path: ../ 17 path: ../
17 - go_router: ^8.0.5 18 + go_router: ^12.1.0
18 19
19 dev_dependencies: 20 dev_dependencies:
20 flutter_test: 21 flutter_test:
21 sdk: flutter 22 sdk: flutter
  23 + lints: ^3.0.0
22 24
23 flutter: 25 flutter:
24 uses-material-design: true 26 uses-material-design: true
@@ -414,6 +414,16 @@ class SnapSheetPhysics extends ScrollPhysics with SheetPhysics { @@ -414,6 +414,16 @@ class SnapSheetPhysics extends ScrollPhysics with SheetPhysics {
414 (old.relative != relative || !listEquals(old.stops, stops)); 414 (old.relative != relative || !listEquals(old.stops, stops));
415 } 415 }
416 416
  417 + @override
  418 + double adjustPositionForNewDimensions(
  419 + {required ScrollMetrics oldPosition,
  420 + required ScrollMetrics newPosition,
  421 + required bool isScrolling,
  422 + required double velocity}) {
  423 + final Tolerance tolerance = toleranceFor(newPosition);
  424 + return _getTargetPixels(newPosition, tolerance, velocity);
  425 + }
  426 +
417 double _getTargetPixels( 427 double _getTargetPixels(
418 ScrollMetrics position, Tolerance tolerance, double velocity) { 428 ScrollMetrics position, Tolerance tolerance, double velocity) {
419 int page = _getPage(position) ?? 0; 429 int page = _getPage(position) ?? 0;
@@ -8,6 +8,7 @@ import 'package:flutter/cupertino.dart'; @@ -8,6 +8,7 @@ import 'package:flutter/cupertino.dart';
8 import 'package:flutter/foundation.dart'; 8 import 'package:flutter/foundation.dart';
9 import 'package:flutter/material.dart'; 9 import 'package:flutter/material.dart';
10 import 'package:flutter/services.dart'; 10 import 'package:flutter/services.dart';
  11 +import 'package:meta/meta.dart';
11 import 'package:sheet/route.dart'; 12 import 'package:sheet/route.dart';
12 import 'package:sheet/sheet.dart'; 13 import 'package:sheet/sheet.dart';
13 14
@@ -219,7 +220,7 @@ class CupertinoSheetRoute<T> extends SheetRoute<T> { @@ -219,7 +220,7 @@ class CupertinoSheetRoute<T> extends SheetRoute<T> {
219 } 220 }
220 221
221 /// Animation for previous route when a [CupertinoSheetRoute] enters/exits 222 /// Animation for previous route when a [CupertinoSheetRoute] enters/exits
222 -@visibleForTesting 223 +@internal
223 class CupertinoSheetBottomRouteTransition extends StatelessWidget { 224 class CupertinoSheetBottomRouteTransition extends StatelessWidget {
224 const CupertinoSheetBottomRouteTransition({ 225 const CupertinoSheetBottomRouteTransition({
225 super.key, 226 super.key,
@@ -349,7 +350,10 @@ class _PageBasedCupertinoSheetRoute<T> extends CupertinoSheetRoute<T> { @@ -349,7 +350,10 @@ class _PageBasedCupertinoSheetRoute<T> extends CupertinoSheetRoute<T> {
349 super.maintainState, 350 super.maintainState,
350 }) : super( 351 }) : super(
351 settings: page, 352 settings: page,
352 - builder: (BuildContext context) => page.child, 353 + builder: (BuildContext context) {
  354 + return (ModalRoute.of(context)!.settings as CupertinoSheetPage<T>)
  355 + .child;
  356 + },
353 ); 357 );
354 358
355 CupertinoSheetPage<T> get _page => settings as CupertinoSheetPage<T>; 359 CupertinoSheetPage<T> get _page => settings as CupertinoSheetPage<T>;
@@ -343,6 +343,9 @@ class _PageBasedSheetRoute<T> extends SheetRoute<T> { @@ -343,6 +343,9 @@ class _PageBasedSheetRoute<T> extends SheetRoute<T> {
343 SheetPage<T> get _page => settings as SheetPage<T>; 343 SheetPage<T> get _page => settings as SheetPage<T>;
344 344
345 @override 345 @override
  346 + WidgetBuilder get builder => (context) => _page.child;
  347 +
  348 + @override
346 bool get maintainState => _page.maintainState; 349 bool get maintainState => _page.maintainState;
347 350
348 @override 351 @override
@@ -4,7 +4,7 @@ import 'dart:math' as math; @@ -4,7 +4,7 @@ import 'dart:math' as math;
4 import 'package:flutter/material.dart'; 4 import 'package:flutter/material.dart';
5 import 'package:flutter/rendering.dart'; 5 import 'package:flutter/rendering.dart';
6 import 'package:sheet/src/widgets/resizable_sheet.dart'; 6 import 'package:sheet/src/widgets/resizable_sheet.dart';
7 -import 'package:sheet/src/widgets/scroll_to_top_status_handler.dart'; 7 +import 'package:sheet/src/widgets/status_bar_gesture_detector.dart';
8 8
9 import '../sheet.dart'; 9 import '../sheet.dart';
10 10
@@ -261,7 +261,7 @@ class Sheet extends StatelessWidget { @@ -261,7 +261,7 @@ class Sheet extends StatelessWidget {
261 scrollBehavior: SheetBehavior(), 261 scrollBehavior: SheetBehavior(),
262 viewportBuilder: (BuildContext context, ViewportOffset offset) { 262 viewportBuilder: (BuildContext context, ViewportOffset offset) {
263 return _DefaultSheetScrollController( 263 return _DefaultSheetScrollController(
264 - child: ScrollToTopStatusBarHandler( 264 + child: StatusBarGestureDetector.scrollToTop(
265 child: SheetViewport( 265 child: SheetViewport(
266 clipBehavior: Clip.antiAlias, 266 clipBehavior: Clip.antiAlias,
267 axisDirection: AxisDirection.down, 267 axisDirection: AxisDirection.down,
@@ -894,8 +894,12 @@ class RenderSheetViewport extends RenderBox @@ -894,8 +894,12 @@ class RenderSheetViewport extends RenderBox
894 } 894 }
895 895
896 @override 896 @override
897 - RevealedOffset getOffsetToReveal(RenderObject target, double alignment,  
898 - {Rect? rect, Axis? axis}) { 897 + RevealedOffset getOffsetToReveal(
  898 + RenderObject target,
  899 + double alignment, {
  900 + Axis? axis,
  901 + Rect? rect,
  902 + }) {
899 rect ??= target.paintBounds; 903 rect ??= target.paintBounds;
900 if (target is! RenderBox) { 904 if (target is! RenderBox) {
901 return RevealedOffset(offset: offset.pixels, rect: rect); 905 return RevealedOffset(offset: offset.pixels, rect: rect);
@@ -14,7 +14,11 @@ typedef SheetControllerCallback = void Function(SheetController controller); @@ -14,7 +14,11 @@ typedef SheetControllerCallback = void Function(SheetController controller);
14 /// 14 ///
15 /// 15 ///
16 class DefaultSheetController extends StatefulWidget { 16 class DefaultSheetController extends StatefulWidget {
17 - const DefaultSheetController({super.key, required this.child, this.onCreated}); 17 + const DefaultSheetController({
  18 + super.key,
  19 + required this.child,
  20 + this.onCreated,
  21 + });
18 22
19 final Widget child; 23 final Widget child;
20 24
@@ -43,7 +47,9 @@ class _DefaultSheetControllerState extends State<DefaultSheetController> { @@ -43,7 +47,9 @@ class _DefaultSheetControllerState extends State<DefaultSheetController> {
43 @override 47 @override
44 Widget build(BuildContext context) { 48 Widget build(BuildContext context) {
45 return _InheritedSheetController( 49 return _InheritedSheetController(
46 - child: widget.child, controller: controller); 50 + child: widget.child,
  51 + controller: controller,
  52 + );
47 } 53 }
48 54
49 @override 55 @override
@@ -54,8 +60,10 @@ class _DefaultSheetControllerState extends State<DefaultSheetController> { @@ -54,8 +60,10 @@ class _DefaultSheetControllerState extends State<DefaultSheetController> {
54 } 60 }
55 61
56 class _InheritedSheetController extends InheritedWidget { 62 class _InheritedSheetController extends InheritedWidget {
57 - const _InheritedSheetController(  
58 - {required super.child, required this.controller}); 63 + const _InheritedSheetController({
  64 + required super.child,
  65 + required this.controller,
  66 + });
59 67
60 final SheetController controller; 68 final SheetController controller;
61 69
1 import 'package:flutter/cupertino.dart'; 1 import 'package:flutter/cupertino.dart';
2 import 'package:flutter/rendering.dart'; 2 import 'package:flutter/rendering.dart';
  3 +import 'package:meta/meta.dart';
3 4
4 /// A widget that add a min interaction zone where hitTestSelf is true 5 /// A widget that add a min interaction zone where hitTestSelf is true
5 /// This is rarely used by its own 6 /// This is rarely used by its own
@@ -8,12 +9,13 @@ import 'package:flutter/rendering.dart'; @@ -8,12 +9,13 @@ import 'package:flutter/rendering.dart';
8 /// 9 ///
9 /// * [Sheet], that uses this widget that enables to drag closed/hidden 10 /// * [Sheet], that uses this widget that enables to drag closed/hidden
10 /// sheets 11 /// sheets
  12 +@internal
11 class MinInteractionZone extends SingleChildRenderObjectWidget { 13 class MinInteractionZone extends SingleChildRenderObjectWidget {
12 const MinInteractionZone({ 14 const MinInteractionZone({
13 required this.direction, 15 required this.direction,
14 required this.extent, 16 required this.extent,
15 - required Widget child,  
16 - }) : super(child: child); 17 + super.child,
  18 + });
17 19
18 final AxisDirection direction; 20 final AxisDirection direction;
19 21
@@ -41,7 +43,6 @@ class MinInteractionPaddingRenderBox extends RenderProxyBox { @@ -41,7 +43,6 @@ class MinInteractionPaddingRenderBox extends RenderProxyBox {
41 AxisDirection _direction; 43 AxisDirection _direction;
42 AxisDirection get direction => _direction; 44 AxisDirection get direction => _direction;
43 set direction(AxisDirection value) { 45 set direction(AxisDirection value) {
44 - // ignore: always_put_control_body_on_new_line  
45 if (value == _direction) return; 46 if (value == _direction) return;
46 _direction = value; 47 _direction = value;
47 } 48 }
@@ -49,7 +50,6 @@ class MinInteractionPaddingRenderBox extends RenderProxyBox { @@ -49,7 +50,6 @@ class MinInteractionPaddingRenderBox extends RenderProxyBox {
49 double _extent; 50 double _extent;
50 double get extent => _extent; 51 double get extent => _extent;
51 set extent(double value) { 52 set extent(double value) {
52 - // ignore: always_put_control_body_on_new_line  
53 if (value == _extent) return; 53 if (value == _extent) return;
54 _extent = value; 54 _extent = value;
55 } 55 }
1 -import 'package:flutter/widgets.dart'; 1 +import 'package:flutter/material.dart';
  2 +
  3 +typedef StatusBarGestureDetectorCallback = void Function(BuildContext context);
2 4
3 /// Widget that that will make the [scrollController] to scroll the top 5 /// Widget that that will make the [scrollController] to scroll the top
4 /// when tapped on the status bar 6 /// when tapped on the status bar
5 /// 7 ///
6 /// Extracted from [Scaffold] and used in [Sheet] 8 /// Extracted from [Scaffold] and used in [Sheet]
7 -class ScrollToTopStatusBarHandler extends StatefulWidget {  
8 - const ScrollToTopStatusBarHandler({ 9 +class StatusBarGestureDetector extends StatefulWidget {
  10 + const StatusBarGestureDetector({
9 super.key, 11 super.key,
10 required this.child, 12 required this.child,
  13 + required this.onTap,
11 }); 14 });
12 15
  16 + const StatusBarGestureDetector.scrollToTop({
  17 + super.key,
  18 + required this.child,
  19 + }) : onTap = _scrollToTopBarTap;
  20 +
  21 + static void _scrollToTopBarTap(BuildContext context) {
  22 + final controller = PrimaryScrollController.maybeOf(context);
  23 + if (controller != null && controller.hasClients) {
  24 + controller.animateTo(
  25 + 0.0,
  26 + duration: const Duration(milliseconds: 1000),
  27 + curve: Curves.easeOutCirc,
  28 + );
  29 + }
  30 + }
  31 +
13 final Widget child; 32 final Widget child;
14 33
  34 + final StatusBarGestureDetectorCallback onTap;
  35 +
15 @override 36 @override
16 - ScrollToTopStatusBarState createState() => ScrollToTopStatusBarState(); 37 + State<StatusBarGestureDetector> createState() =>
  38 + _StatusBarGestureDetectorState();
17 } 39 }
18 40
19 -class ScrollToTopStatusBarState extends State<ScrollToTopStatusBarHandler> { 41 +class _StatusBarGestureDetectorState extends State<StatusBarGestureDetector> {
  42 + final OverlayPortalController controller = OverlayPortalController();
  43 +
20 @override 44 @override
21 void initState() { 45 void initState() {
  46 + controller.show();
22 super.initState(); 47 super.initState();
23 } 48 }
24 49
25 @override 50 @override
26 Widget build(BuildContext context) { 51 Widget build(BuildContext context) {
27 - return Stack(  
28 - fit: StackFit.expand,  
29 - children: <Widget>[  
30 - widget.child,  
31 - Positioned(  
32 - top: 0,  
33 - left: 0,  
34 - right: 0,  
35 - height: MediaQuery.maybeOf(context)?.padding.top ?? 0,  
36 - child: Builder(  
37 - builder: (BuildContext context) {  
38 - return GestureDetector(  
39 - behavior: HitTestBehavior.opaque,  
40 - onTap: () => _handleStatusBarTap(context),  
41 - // iOS accessibility automatically adds scroll-to-top to the clock in the status bar  
42 - excludeFromSemantics: true,  
43 - );  
44 - }, 52 + final view = View.of(context);
  53 + return OverlayPortal.targetsRootOverlay(
  54 + controller: controller,
  55 + overlayChildBuilder: (context) {
  56 + return Align(
  57 + alignment: Alignment.topCenter,
  58 + child: SizedBox(
  59 + height: view.padding.top / view.devicePixelRatio,
  60 + width: double.infinity,
  61 + child: GestureDetector(
  62 + behavior: HitTestBehavior.opaque,
  63 + onTap: () => widget.onTap(context),
  64 + // iOS accessibility automatically adds scroll-to-top to the clock in the status bar
  65 + excludeFromSemantics: true,
  66 + ),
45 ), 67 ),
46 - ),  
47 - ], 68 + );
  69 + },
  70 + child: widget.child,
48 ); 71 );
49 } 72 }
50 -  
51 - void _handleStatusBarTap(BuildContext context) {  
52 - final ScrollController? controller =  
53 - PrimaryScrollController.maybeOf(context);  
54 - if (controller != null && controller.hasClients) {  
55 - controller.animateTo(  
56 - 0.0,  
57 - duration: const Duration(milliseconds: 300),  
58 - curve: Curves.linear, // TODO(ianh): Use a more appropriate curve.  
59 - );  
60 - }  
61 - }  
62 } 73 }
@@ -84,7 +84,7 @@ packages: @@ -84,7 +84,7 @@ packages:
84 source: hosted 84 source: hosted
85 version: "0.5.0" 85 version: "0.5.0"
86 meta: 86 meta:
87 - dependency: transitive 87 + dependency: "direct main"
88 description: 88 description:
89 name: meta 89 name: meta
90 sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" 90 sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3"
@@ -4,12 +4,13 @@ version: 1.0.0-pre @@ -4,12 +4,13 @@ version: 1.0.0-pre
4 homepage: https://github.com/jamesblasco/modal_bottom_sheet 4 homepage: https://github.com/jamesblasco/modal_bottom_sheet
5 5
6 environment: 6 environment:
7 - sdk: ">=2.17.0 <3.0.0" 7 + sdk: ">=3.0.0 <4.0.0"
8 8
9 dependencies: 9 dependencies:
10 flutter: 10 flutter:
11 sdk: flutter 11 sdk: flutter
12 - 12 + meta: ^1.9.1
  13 +
13 dev_dependencies: 14 dev_dependencies:
14 flutter_test: 15 flutter_test:
15 sdk: flutter 16 sdk: flutter
@@ -2,7 +2,7 @@ @@ -2,7 +2,7 @@
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 -import 'package:flutter/widgets.dart'; 5 +import 'package:flutter/material.dart';
6 import 'package:flutter_test/flutter_test.dart'; 6 import 'package:flutter_test/flutter_test.dart';
7 import 'package:sheet/sheet.dart'; 7 import 'package:sheet/sheet.dart';
8 8
@@ -54,9 +54,8 @@ void main() { @@ -54,9 +54,8 @@ void main() {
54 // ScrollController's ScrollPosition to be rebuilt. 54 // ScrollController's ScrollPosition to be rebuilt.
55 55
56 Widget buildFrame(SheetPhysics? physics) { 56 Widget buildFrame(SheetPhysics? physics) {
57 - return Directionality(  
58 - textDirection: TextDirection.ltr,  
59 - child: Sheet( 57 + return MaterialApp(
  58 + home: Sheet(
60 controller: controller, 59 controller: controller,
61 physics: physics, 60 physics: physics,
62 child: ScrollPositionListener( 61 child: ScrollPositionListener(
1 import 'package:flutter/material.dart'; 1 import 'package:flutter/material.dart';
2 import 'package:flutter_test/flutter_test.dart'; 2 import 'package:flutter_test/flutter_test.dart';
3 -import 'package:sheet/src/widgets/scroll_to_top_status_handler.dart'; 3 +import 'package:sheet/src/widgets/status_bar_gesture_detector.dart';
4 4
5 void main() { 5 void main() {
6 - testWidgets('Tap status bar scrolls primary scroll controller',  
7 - (WidgetTester tester) async {  
8 - final ScrollController controller = ScrollController();  
9 - await tester.pumpWidget(MaterialApp(  
10 - builder: (BuildContext context, Widget? child) {  
11 - return MediaQuery(  
12 - data: MediaQuery.of(context).copyWith(  
13 - padding: const EdgeInsets.all(20),  
14 - ),  
15 - child: child!,  
16 - );  
17 - },  
18 - home: PrimaryScrollController(  
19 - controller: controller,  
20 - child: ScrollToTopStatusBarHandler(  
21 - child: Material(  
22 - child: ListView.builder(  
23 - controller: controller,  
24 - itemBuilder: (BuildContext context, int index) {  
25 - return ListTile(title: Text('Text $index'));  
26 - }, 6 + group('StatusBarGestureDetector', () {
  7 + testWidgets('Tap status bar calls onTap callback',
  8 + (WidgetTester tester) async {
  9 + tester.view.padding = FakeViewPadding(top: 20);
  10 + bool called = false;
  11 + await tester.pumpWidget(MaterialApp(
  12 + home: StatusBarGestureDetector(
  13 + onTap: (_) => called = true,
  14 + child: Container(),
  15 + ),
  16 + ));
  17 + await tester.tapAt(Offset.zero);
  18 + await tester.pumpAndSettle();
  19 + expect(called, isTrue);
  20 + });
  21 + testWidgets('Tap status bar scrolls primary scroll controller',
  22 + (WidgetTester tester) async {
  23 + final ScrollController controller = ScrollController();
  24 + tester.view.padding = FakeViewPadding(top: 20);
  25 + await tester.pumpWidget(MaterialApp(
  26 + home: PrimaryScrollController(
  27 + controller: controller,
  28 + child: StatusBarGestureDetector.scrollToTop(
  29 + child: Material(
  30 + child: ListView.builder(
  31 + controller: controller,
  32 + itemBuilder: (BuildContext context, int index) {
  33 + return ListTile(title: Text('Text $index'));
  34 + },
  35 + ),
27 ), 36 ),
28 ), 37 ),
29 ), 38 ),
30 - ),  
31 - ));  
32 - controller.jumpTo(200);  
33 - await tester.pump();  
34 - await tester.tapAt(Offset.zero);  
35 - await tester.pumpAndSettle();  
36 - expect(controller.position.pixels, isZero); 39 + ));
  40 + controller.jumpTo(200);
  41 + await tester.pump();
  42 + await tester.tapAt(Offset.zero);
  43 + await tester.pumpAndSettle();
  44 + expect(controller.position.pixels, isZero);
  45 + });
37 }); 46 });
38 } 47 }