diff --git a/example/lib/main.dart b/example/lib/main.dart index 2c821116..e48886a0 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -29,7 +29,8 @@ class _MainAppState extends State { @override Widget build(BuildContext context) { - SliverWoltModalSheetPage page1(BuildContext modalSheetContext, TextTheme textTheme) { + SliverWoltModalSheetPage page1( + BuildContext modalSheetContext, TextTheme textTheme) { return WoltModalSheetPage( hasSabGradient: false, stickyActionBar: Padding( @@ -78,13 +79,15 @@ Pagination involves a sequence of screens the user navigates sequentially. We ch ); } - SliverWoltModalSheetPage page2(BuildContext modalSheetContext, TextTheme textTheme) { + SliverWoltModalSheetPage page2( + BuildContext modalSheetContext, TextTheme textTheme) { return SliverWoltModalSheetPage( pageTitle: Padding( padding: const EdgeInsets.all(_pagePadding), child: Text( 'Material Colors', - style: textTheme.headlineMedium!.copyWith(fontWeight: FontWeight.bold), + style: + textTheme.headlineMedium!.copyWith(fontWeight: FontWeight.bold), ), ), heroImage: Image( @@ -164,7 +167,8 @@ Pagination involves a sequence of screens the user navigates sequentially. We ch padding: const EdgeInsets.all(_pagePadding), child: Switch( value: !_isLightTheme, - onChanged: (_) => setState(() => _isLightTheme = !_isLightTheme), + onChanged: (_) => + setState(() => _isLightTheme = !_isLightTheme), ), ), const Text('Dark Theme'), diff --git a/lib/src/content/wolt_modal_sheet_animated_switcher.dart b/lib/src/content/wolt_modal_sheet_animated_switcher.dart index f9a0d8e6..8bdb5b5b 100644 --- a/lib/src/content/wolt_modal_sheet_animated_switcher.dart +++ b/lib/src/content/wolt_modal_sheet_animated_switcher.dart @@ -30,15 +30,16 @@ class WoltModalSheetAnimatedSwitcher extends StatefulWidget { required this.sheetWidth, required this.showDragHandle, Key? key, - }) - : assert(pageIndex >= 0 && pageIndex < pages.length), + }) : assert(pageIndex >= 0 && pageIndex < pages.length), super(key: key); @override - State createState() => _WoltModalSheetAnimatedSwitcherState(); + State createState() => + _WoltModalSheetAnimatedSwitcherState(); } -class _WoltModalSheetAnimatedSwitcherState extends State +class _WoltModalSheetAnimatedSwitcherState + extends State with TickerProviderStateMixin { PaginatingWidgetsGroup? _incomingPageWidgets; PaginatingWidgetsGroup? _outgoingPageWidgets; @@ -52,7 +53,9 @@ class _WoltModalSheetAnimatedSwitcherState extends State(); final defaultThemeData = WoltModalSheetDefaultThemeData(context); - return _page.hasTopBarLayer ?? themeData?.hasTopBarLayer ?? defaultThemeData.hasTopBarLayer; + return _page.hasTopBarLayer ?? + themeData?.hasTopBarLayer ?? + defaultThemeData.hasTopBarLayer; } late List _titleKeys; @@ -67,7 +70,8 @@ class _WoltModalSheetAnimatedSwitcherState extends State _scrollControllers = []; /// The [ScrollController] of the current [WoltModalSheetPage] main content. - ScrollController get _currentPageScrollController => _scrollControllers[_pageIndex]; + ScrollController get _currentPageScrollController => + _scrollControllers[_pageIndex]; /// List of [ValueNotifier] objects, each one for the listening of the scroll position updates /// in each [WoltModalSheetPage] main content. @@ -75,7 +79,8 @@ class _WoltModalSheetAnimatedSwitcherState extends State get _currentPageScrollPosition => _scrollPositions[_pageIndex]; + ValueNotifier get _currentPageScrollPosition => + _scrollPositions[_pageIndex]; /// Subscription for discovering the state of the soft-keyboard visibility late StreamSubscription _softKeyboardVisibilitySubscription; @@ -93,7 +98,8 @@ class _WoltModalSheetAnimatedSwitcherState extends State _softKeyboardClosedNotifier = ValueNotifier( + final ValueNotifier _softKeyboardClosedNotifier = + ValueNotifier( const SoftKeyboardClosedEvent(eventId: 0), ); @@ -123,14 +129,17 @@ class _WoltModalSheetAnimatedSwitcherState extends State(); final defaultThemeData = WoltModalSheetDefaultThemeData(context); final hasTopBarLayer = _hasTopBarLayer; final isTopBarLayerAlwaysVisible = _page.isTopBarLayerAlwaysVisible ?? themeData?.isTopBarLayerAlwaysVisible ?? defaultThemeData.isTopBarLayerAlwaysVisible; - final topBarTitle = WoltModalSheetTopBarTitle(page: _page, pageTitleKey: _pageTitleKey); - final navBarHeight = - _page.navBarHeight ?? themeData?.navBarHeight ?? defaultThemeData.navBarHeight; + final topBarTitle = + WoltModalSheetTopBarTitle(page: _page, pageTitleKey: _pageTitleKey); + final navBarHeight = _page.navBarHeight ?? + themeData?.navBarHeight ?? + defaultThemeData.navBarHeight; final WoltModalSheetAnimationStyle animationStyle = themeData?.animationStyle ?? defaultThemeData.animationStyle; - const animatedBuilderKey = ValueKey(WoltModalSheetPageTransitionState.incoming); + const animatedBuilderKey = + ValueKey(WoltModalSheetPageTransitionState.incoming); // If the page uses the default top bar, we should show the top bar title to be represented in // the middle of the navigation toolbar. final shouldShowTopBarTitle = hasTopBarLayer && _page.topBar == null; Widget? navigationToolbarMiddle; if (shouldShowTopBarTitle) { navigationToolbarMiddle = - isTopBarLayerAlwaysVisible || _page is NonScrollingWoltModalSheetPage - ? Center(child: topBarTitle) - : WoltModalSheetTopBarTitleFlow( - scrollAnimationStyle: animationStyle.scrollAnimationStyle, - page: _page, - scrollController: _currentPageScrollController, - titleKey: _pageTitleKey, - topBarTitle: topBarTitle, - softKeyboardClosedListenable: _softKeyboardClosedNotifier, - ); + isTopBarLayerAlwaysVisible || _page is NonScrollingWoltModalSheetPage + ? Center(child: topBarTitle) + : WoltModalSheetTopBarTitleFlow( + scrollAnimationStyle: animationStyle.scrollAnimationStyle, + page: _page, + scrollController: _currentPageScrollController, + titleKey: _pageTitleKey, + topBarTitle: topBarTitle, + softKeyboardClosedListenable: _softKeyboardClosedNotifier, + ); } return PaginatingWidgetsGroup( mainContentAnimatedBuilder: MainContentAnimatedBuilder( @@ -340,8 +359,10 @@ class _WoltModalSheetAnimatedSwitcherState extends State(); final defaultThemeData = WoltModalSheetDefaultThemeData(context); final WoltModalSheetAnimationStyle animationStyle = @@ -410,8 +435,10 @@ class _WoltModalSheetAnimatedSwitcherState extends State extends StatefulWidget { /// - A `Future` that resolves to the value returned static Future showWithDynamicPath({ required BuildContext context, - required ValueNotifier pageListBuilderNotifier, + required ValueNotifier + pageListBuilderNotifier, WoltModalTypeBuilder? modalTypeBuilder, ValueNotifier? pageIndexNotifier, Widget Function(Widget)? decorator, @@ -253,7 +254,8 @@ class WoltModalSheet extends StatefulWidget { double? maxPageHeight, Color? modalBarrierColor, }) { - final NavigatorState navigator = Navigator.of(context, rootNavigator: useRootNavigator); + final NavigatorState navigator = + Navigator.of(context, rootNavigator: useRootNavigator); final themeData = Theme.of(context).extension(); return navigator.push( WoltModalSheetRoute( @@ -300,7 +302,8 @@ class WoltModalSheet extends StatefulWidget { if (context is StatefulElement && context.state is WoltModalSheetState) { woltModalSheetState = context.state as WoltModalSheetState; } - woltModalSheetState ??= context.findAncestorStateOfType(); + woltModalSheetState ??= + context.findAncestorStateOfType(); assert(() { if (woltModalSheetState == null) { @@ -326,7 +329,8 @@ class WoltModalSheet extends StatefulWidget { /// /// Returns: /// None. - static void replaceCurrentPage(BuildContext context, SliverWoltModalSheetPage newPage) { + static void replaceCurrentPage( + BuildContext context, SliverWoltModalSheetPage newPage) { WoltModalSheet.of(context).replaceCurrentPage(newPage); } @@ -356,7 +360,8 @@ class WoltModalSheet extends StatefulWidget { List newPages, { int? selectedPageIndex, }) { - WoltModalSheet.of(context).replaceAllPages(newPages, selectedPageIndex: selectedPageIndex); + WoltModalSheet.of(context) + .replaceAllPages(newPages, selectedPageIndex: selectedPageIndex); } /// Adds one or more new pages to the modal sheet stack without making them the current view. @@ -367,7 +372,8 @@ class WoltModalSheet extends StatefulWidget { /// /// Parameters: /// - [pages]: The List of [SliverWoltModalSheetPage] to be added to the stack. Can also be a single page. - static void addPages(BuildContext context, List pages) { + static void addPages( + BuildContext context, List pages) { WoltModalSheet.of(context).addPages(pages); } @@ -396,7 +402,8 @@ class WoltModalSheet extends StatefulWidget { /// /// Returns: /// None. - static void addOrReplacePages(BuildContext context, List pages) { + static void addOrReplacePages( + BuildContext context, List pages) { return WoltModalSheet.of(context).addOrReplacePages(pages); } @@ -407,7 +414,8 @@ class WoltModalSheet extends StatefulWidget { /// /// Returns: /// None. - static void addOrReplacePage(BuildContext context, SliverWoltModalSheetPage page) { + static void addOrReplacePage( + BuildContext context, SliverWoltModalSheetPage page) { return addOrReplacePages(context, [page]); } @@ -426,7 +434,8 @@ class WoltModalSheet extends StatefulWidget { /// /// Returns: /// None. - static void pushPages(BuildContext context, List pages) { + static void pushPages( + BuildContext context, List pages) { return WoltModalSheet.of(context).pushPages(pages); } @@ -516,7 +525,8 @@ class WoltModalSheet extends StatefulWidget { /// Returns: /// - [bool]: Returns `true` if replacing page was successful, `false` if no page with the /// specified [id] is found. - static bool replacePage(BuildContext context, Object id, SliverWoltModalSheetPage page) { + static bool replacePage( + BuildContext context, Object id, SliverWoltModalSheetPage page) { return WoltModalSheet.of(context).replacePage(id, page); } @@ -586,12 +596,14 @@ class WoltModalSheetState extends State { Widget Function(Widget) get _decorator => widget.decorator ?? (widget) => Builder(builder: (_) => widget); - bool get _dismissUnderway => widget.animationController!.status == AnimationStatus.reverse; + bool get _dismissUnderway => + widget.animationController!.status == AnimationStatus.reverse; final GlobalKey _childKey = GlobalKey(debugLabel: 'BottomSheet child'); double get _childHeight { - final RenderBox renderBox = _childKey.currentContext!.findRenderObject()! as RenderBox; + final RenderBox renderBox = + _childKey.currentContext!.findRenderObject()! as RenderBox; return renderBox.size.height; } @@ -613,7 +625,8 @@ class WoltModalSheetState extends State { // set in a declarative way using the WoltModalSheetRoute. setState(() { final pages = widget.pageListBuilderNotifier.value(context); - assert(pages.isNotEmpty, 'pageListBuilder must return a non-empty list.'); + assert( + pages.isNotEmpty, 'pageListBuilder must return a non-empty list.'); _pages ..clear() ..addAll(pages); @@ -628,7 +641,8 @@ class WoltModalSheetState extends State { if (_pages.isEmpty) { // Get the initial page list from the initially provided pageListBuilder. final initialPages = widget.pageListBuilderNotifier.value(context); - assert(initialPages.isNotEmpty, 'pageListBuilder must return a non-empty list.'); + assert(initialPages.isNotEmpty, + 'pageListBuilder must return a non-empty list.'); _pages = initialPages; } } @@ -649,7 +663,8 @@ class WoltModalSheetState extends State { late ShapeBorder shape; switch (_modalType) { case WoltModalType.bottomSheet: - shape = themeData?.bottomSheetShape ?? defaultThemeData.bottomSheetShape; + shape = themeData?.bottomSheetShape ?? + defaultThemeData.bottomSheetShape; break; case WoltModalType.dialog: shape = themeData?.dialogShape ?? defaultThemeData.dialogShape; @@ -661,24 +676,33 @@ class WoltModalSheetState extends State { themeData?.enableDrag ?? defaultThemeData.enableDrag); final showDragHandle = widget.showDragHandle ?? - (enableDrag && (themeData?.showDragHandle ?? defaultThemeData.showDragHandle)); + (enableDrag && + (themeData?.showDragHandle ?? + defaultThemeData.showDragHandle)); final pageBackgroundColor = page.backgroundColor ?? themeData?.backgroundColor ?? defaultThemeData.backgroundColor; - final minPageHeight = - widget.minPageHeight ?? themeData?.minPageHeight ?? defaultThemeData.minPageHeight; - final maxPageHeight = - widget.maxPageHeight ?? themeData?.maxPageHeight ?? defaultThemeData.maxPageHeight; - final minDialogWidth = - widget.minDialogWidth ?? themeData?.minDialogWidth ?? defaultThemeData.minDialogWidth; - final maxDialogWidth = - widget.maxDialogWidth ?? themeData?.maxDialogWidth ?? defaultThemeData.maxDialogWidth; - final shadowColor = themeData?.shadowColor ?? defaultThemeData.shadowColor; + final minPageHeight = widget.minPageHeight ?? + themeData?.minPageHeight ?? + defaultThemeData.minPageHeight; + final maxPageHeight = widget.maxPageHeight ?? + themeData?.maxPageHeight ?? + defaultThemeData.maxPageHeight; + final minDialogWidth = widget.minDialogWidth ?? + themeData?.minDialogWidth ?? + defaultThemeData.minDialogWidth; + final maxDialogWidth = widget.maxDialogWidth ?? + themeData?.maxDialogWidth ?? + defaultThemeData.maxDialogWidth; + final shadowColor = + themeData?.shadowColor ?? defaultThemeData.shadowColor; final surfaceTintColor = page.surfaceTintColor ?? themeData?.surfaceTintColor ?? defaultThemeData.surfaceTintColor; - final modalElevation = themeData?.modalElevation ?? defaultThemeData.modalElevation; - final clipBehavior = themeData?.clipBehavior ?? defaultThemeData.clipBehavior; + final modalElevation = + themeData?.modalElevation ?? defaultThemeData.modalElevation; + final clipBehavior = + themeData?.clipBehavior ?? defaultThemeData.clipBehavior; final resizeToAvoidBottomInset = page.resizeToAvoidBottomInset ?? themeData?.resizeToAvoidBottomInset ?? defaultThemeData.resizeToAvoidBottomInset; @@ -701,7 +725,8 @@ class WoltModalSheetState extends State { behavior: HitTestBehavior.opaque, onTap: () { if (widget.route.barrierDismissible) { - final onModalDismissedWithBarrierTap = widget.onModalDismissedWithBarrierTap; + final onModalDismissedWithBarrierTap = + widget.onModalDismissedWithBarrierTap; if (onModalDismissedWithBarrierTap != null) { onModalDismissedWithBarrierTap(); } else { @@ -721,7 +746,8 @@ class WoltModalSheetState extends State { child: GestureDetector( excludeFromSemantics: true, onVerticalDragStart: enableDrag ? _handleDragStart : null, - onVerticalDragUpdate: enableDrag ? _handleDragUpdate : null, + onVerticalDragUpdate: + enableDrag ? _handleDragUpdate : null, onVerticalDragEnd: enableDrag ? _handleDragEnd : null, child: Material( color: pageBackgroundColor, @@ -795,7 +821,8 @@ class WoltModalSheetState extends State { } bool isClosing = false; if (details.velocity.pixelsPerSecond.dy > _minFlingVelocity) { - final double flingVelocity = -details.velocity.pixelsPerSecond.dy / _childHeight; + final double flingVelocity = + -details.velocity.pixelsPerSecond.dy / _childHeight; if (widget.animationController!.value > 0.0) { widget.animationController!.fling(velocity: flingVelocity); } @@ -870,7 +897,8 @@ class WoltModalSheetState extends State { _pages = List.from(_pages)..addAll(pages); } else { // Replace all pages beyond the current one with new pages. - _pages = List.from(_pages.take(_currentPageIndex + 1)) + _pages = List.from( + _pages.take(_currentPageIndex + 1)) ..addAll(pages); } } @@ -1039,7 +1067,8 @@ class WoltModalSheetState extends State { if (indexToStopRemoving == -1 || indexToStopRemoving == _currentPageIndex) { return false; } - final sublist = List.from(_pages).sublist(0, indexToStopRemoving + 1); + final sublist = List.from(_pages) + .sublist(0, indexToStopRemoving + 1); _pages = sublist; // Update the indexToStopRemoving if the removed page is before the current page. if (indexToStopRemoving < _currentPageIndex) { @@ -1118,7 +1147,8 @@ class WoltModalSheetState extends State { /// /// Returns: /// This method does not return a value. - void replaceAllPages(List newPages, {int? selectedPageIndex}) { + void replaceAllPages(List newPages, + {int? selectedPageIndex}) { if (newPages.isEmpty) { throw ArgumentError('newPages must not be empty.'); } @@ -1126,7 +1156,8 @@ class WoltModalSheetState extends State { // Make sure selectedPageIndex is within the bounds of the new list. if (selectedPageIndex != null && (selectedPageIndex >= newPages.length || selectedPageIndex < 0)) { - throw ArgumentError('selectedPageIndex must be within the bounds of the newPages list.'); + throw ArgumentError( + 'selectedPageIndex must be within the bounds of the newPages list.'); } setState(() {