From a6a3244b3c7efb73a067d74ae2522c1c3e6873f5 Mon Sep 17 00:00:00 2001 From: Thibault Deckers Date: Thu, 19 May 2022 16:41:16 +0900 Subject: [PATCH] app/nav bar fixes --- lib/model/selection.dart | 6 +- lib/widgets/collection/app_bar.dart | 23 ++++- lib/widgets/common/identity/aves_app_bar.dart | 86 +++++++++---------- lib/widgets/filter_grids/album_pick.dart | 6 +- .../filter_grids/common/filter_grid_page.dart | 2 +- .../filter_grids/common/filter_nav_page.dart | 2 + lib/widgets/navigation/nav_bar/nav_bar.dart | 29 +++++++ 7 files changed, 102 insertions(+), 52 deletions(-) diff --git a/lib/model/selection.dart b/lib/model/selection.dart index 2d19227ed..f26d0c4d9 100644 --- a/lib/model/selection.dart +++ b/lib/model/selection.dart @@ -11,13 +11,15 @@ class Selection extends ChangeNotifier { void browse() { if (!_isSelecting) return; - clearSelection(); _isSelecting = false; notifyListeners(); } void select() { if (_isSelecting) return; + // clear selection on `select`, not on `browse`, so that + // the selection count is stable when transitioning to browse + clearSelection(); _isSelecting = true; notifyListeners(); } @@ -42,7 +44,7 @@ class Selection extends ChangeNotifier { } void toggleSelection(T item) { - if (_selectedItems.isEmpty) select(); + if (!_isSelecting) select(); if (!_selectedItems.remove(item)) _selectedItems.add(item); notifyListeners(); } diff --git a/lib/widgets/collection/app_bar.dart b/lib/widgets/collection/app_bar.dart index e68e39ee3..ea768701e 100644 --- a/lib/widgets/collection/app_bar.dart +++ b/lib/widgets/collection/app_bar.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import 'dart:ui'; import 'package:aves/app_mode.dart'; import 'package:aves/model/actions/entry_set_actions.dart'; @@ -45,13 +46,14 @@ class CollectionAppBar extends StatefulWidget { State createState() => _CollectionAppBarState(); } -class _CollectionAppBarState extends State with SingleTickerProviderStateMixin { +class _CollectionAppBarState extends State with SingleTickerProviderStateMixin, WidgetsBindingObserver { final List _subscriptions = []; final EntrySetActionDelegate _actionDelegate = EntrySetActionDelegate(); late AnimationController _browseToSelectAnimation; final ValueNotifier _isSelectingNotifier = ValueNotifier(false); final FocusNode _queryBarFocusNode = FocusNode(); late final Listenable _queryFocusRequestNotifier; + double _statusBarHeight = 0; CollectionLens get collection => widget.collection; @@ -76,7 +78,11 @@ class _CollectionAppBarState extends State with SingleTickerPr ); _isSelectingNotifier.addListener(_onActivityChange); _registerWidget(widget); - WidgetsBinding.instance.addPostFrameCallback((_) => _onFilterChanged()); + WidgetsBinding.instance.addObserver(this); + WidgetsBinding.instance.addPostFrameCallback((_) { + _updateStatusBarHeight(); + _onFilterChanged(); + }); } @override @@ -95,6 +101,7 @@ class _CollectionAppBarState extends State with SingleTickerPr _subscriptions ..forEach((sub) => sub.cancel()) ..clear(); + WidgetsBinding.instance.removeObserver(this); super.dispose(); } @@ -106,6 +113,11 @@ class _CollectionAppBarState extends State with SingleTickerPr widget.collection.filterChangeNotifier.removeListener(_onFilterChanged); } + @override + void didChangeMetrics() { + _updateStatusBarHeight(); + } + @override Widget build(BuildContext context) { final appMode = context.watch>().value; @@ -432,8 +444,13 @@ class _CollectionAppBarState extends State with SingleTickerPr void _onQueryFocusRequest() => _queryBarFocusNode.requestFocus(); + void _updateStatusBarHeight() { + _statusBarHeight = EdgeInsets.fromWindowPadding(window.padding, window.devicePixelRatio).top; + _updateAppBarHeight(); + } + void _updateAppBarHeight() { - widget.appBarHeightNotifier.value = AvesAppBar.appBarHeightForContentHeight(appBarContentHeight); + widget.appBarHeightNotifier.value = _statusBarHeight + AvesAppBar.appBarHeightForContentHeight(appBarContentHeight); } Future _onActionSelected(EntrySetAction action) async { diff --git a/lib/widgets/common/identity/aves_app_bar.dart b/lib/widgets/common/identity/aves_app_bar.dart index 9460a1dee..1fba8daf6 100644 --- a/lib/widgets/common/identity/aves_app_bar.dart +++ b/lib/widgets/common/identity/aves_app_bar.dart @@ -1,5 +1,3 @@ -import 'dart:ui'; - import 'package:aves/model/settings/settings.dart'; import 'package:aves/theme/durations.dart'; import 'package:aves/widgets/common/fx/blurred.dart'; @@ -26,56 +24,58 @@ class AvesAppBar extends StatelessWidget { @override Widget build(BuildContext context) { - return SliverPersistentHeader( - floating: true, - pinned: false, - delegate: _SliverAppBarDelegate( - height: appBarHeightForContentHeight(contentHeight), - child: SafeArea( - bottom: false, - child: AvesFloatingBar( - builder: (context, backgroundColor) => Material( - color: backgroundColor, - textStyle: Theme.of(context).appBarTheme.titleTextStyle, - child: Column( - children: [ - SizedBox( - height: kToolbarHeight, - child: Row( - children: [ - Padding( - padding: const EdgeInsets.symmetric(horizontal: 4), - child: leading, - ), - Expanded( - child: AnimatedSwitcher( - duration: context.read().iconAnimation, - child: Row( - key: ValueKey(transitionKey), - children: [ - Expanded(child: title), - ...actions, - ], + return Selector( + selector: (context, mq) => mq.padding.top, + builder: (context, mqPaddingTop, child) { + return SliverPersistentHeader( + floating: true, + pinned: false, + delegate: _SliverAppBarDelegate( + height: mqPaddingTop + appBarHeightForContentHeight(contentHeight), + child: SafeArea( + bottom: false, + child: AvesFloatingBar( + builder: (context, backgroundColor) => Material( + color: backgroundColor, + textStyle: Theme.of(context).appBarTheme.titleTextStyle, + child: Column( + children: [ + SizedBox( + height: kToolbarHeight, + child: Row( + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 4), + child: leading, ), - ), + Expanded( + child: AnimatedSwitcher( + duration: context.read().iconAnimation, + child: Row( + key: ValueKey(transitionKey), + children: [ + Expanded(child: title), + ...actions, + ], + ), + ), + ), + ], ), - ], - ), + ), + if (bottom != null) bottom!, + ], ), - if (bottom != null) bottom!, - ], + ), ), ), ), - ), - ), + ); + }, ); } - static double appBarHeightForContentHeight(double contentHeight) { - final topPadding = window.padding.top / window.devicePixelRatio; - return topPadding + AvesFloatingBar.margin.vertical + contentHeight; - } + static double appBarHeightForContentHeight(double contentHeight) => AvesFloatingBar.margin.vertical + contentHeight; } class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate { diff --git a/lib/widgets/filter_grids/album_pick.dart b/lib/widgets/filter_grids/album_pick.dart index b25e49617..928954be5 100644 --- a/lib/widgets/filter_grids/album_pick.dart +++ b/lib/widgets/filter_grids/album_pick.dart @@ -85,7 +85,7 @@ class _AlbumPickPageState extends State<_AlbumPickPage> { actionDelegate: AlbumChipSetActionDelegate(gridItems), queryNotifier: _queryNotifier, ), - appBarHeight: _AlbumPickAppBar.preferredHeight, + appBarHeight: AvesAppBar.appBarHeightForContentHeight(_AlbumPickAppBar.contentHeight), sections: AlbumListPage.groupToSections(context, source, gridItems), newFilters: source.getNewAlbumFilters(context), sortFactor: settings.albumSortFactor, @@ -118,7 +118,7 @@ class _AlbumPickAppBar extends StatelessWidget { final AlbumChipSetActionDelegate actionDelegate; final ValueNotifier queryNotifier; - static const preferredHeight = kToolbarHeight + _AlbumQueryBar.preferredHeight; + static const contentHeight = kToolbarHeight + _AlbumQueryBar.preferredHeight; const _AlbumPickAppBar({ required this.source, @@ -145,7 +145,7 @@ class _AlbumPickAppBar extends StatelessWidget { } return AvesAppBar( - contentHeight: preferredHeight, + contentHeight: contentHeight, leading: const BackButton(), title: SourceStateAwareAppBarTitle( title: Text(title()), diff --git a/lib/widgets/filter_grids/common/filter_grid_page.dart b/lib/widgets/filter_grids/common/filter_grid_page.dart index bc9c2f95e..08938aec0 100644 --- a/lib/widgets/filter_grids/common/filter_grid_page.dart +++ b/lib/widgets/filter_grids/common/filter_grid_page.dart @@ -58,7 +58,7 @@ class FilterGridPage extends StatelessWidget { super.key, this.settingsRouteKey, required this.appBar, - this.appBarHeight = kToolbarHeight, + required this.appBarHeight, required this.sections, required this.newFilters, required this.sortFactor, diff --git a/lib/widgets/filter_grids/common/filter_nav_page.dart b/lib/widgets/filter_grids/common/filter_nav_page.dart index 4110b19b1..e06f92500 100644 --- a/lib/widgets/filter_grids/common/filter_nav_page.dart +++ b/lib/widgets/filter_grids/common/filter_nav_page.dart @@ -2,6 +2,7 @@ import 'package:aves/model/filters/filters.dart'; import 'package:aves/model/source/collection_source.dart'; import 'package:aves/model/source/enums.dart'; import 'package:aves/utils/time_utils.dart'; +import 'package:aves/widgets/common/identity/aves_app_bar.dart'; import 'package:aves/widgets/common/identity/aves_filter_chip.dart'; import 'package:aves/widgets/common/providers/selection_provider.dart'; import 'package:aves/widgets/filter_grids/common/action_delegates/chip_set.dart'; @@ -43,6 +44,7 @@ class FilterNavigationPage extends StatelessWidget { actionDelegate: actionDelegate, isEmpty: filterSections.isEmpty, ), + appBarHeight: AvesAppBar.appBarHeightForContentHeight(kToolbarHeight), sections: filterSections, newFilters: newFilters ?? {}, sortFactor: sortFactor, diff --git a/lib/widgets/navigation/nav_bar/nav_bar.dart b/lib/widgets/navigation/nav_bar/nav_bar.dart index 904c720ae..669b0d2b5 100644 --- a/lib/widgets/navigation/nav_bar/nav_bar.dart +++ b/lib/widgets/navigation/nav_bar/nav_bar.dart @@ -36,6 +36,33 @@ class AppBottomNavBar extends StatefulWidget { class _AppBottomNavBarState extends State { String? _lastRoute; + @override + void initState() { + super.initState(); + _registerWidget(widget); + } + + @override + void didUpdateWidget(covariant AppBottomNavBar oldWidget) { + super.didUpdateWidget(oldWidget); + _unregisterWidget(oldWidget); + _registerWidget(widget); + } + + @override + void dispose() { + _unregisterWidget(widget); + super.dispose(); + } + + void _registerWidget(AppBottomNavBar widget) { + widget.currentCollection?.filterChangeNotifier.addListener(_onCollectionFilterChange); + } + + void _unregisterWidget(AppBottomNavBar widget) { + widget.currentCollection?.filterChangeNotifier.removeListener(_onCollectionFilterChange); + } + @override Widget build(BuildContext context) { final showVideo = context.select((s) => !s.hiddenFilters.contains(MimeFilter.video)); @@ -84,6 +111,8 @@ class _AppBottomNavBarState extends State { ); } + void _onCollectionFilterChange() => setState(() {}); + int _getCurrentIndex(BuildContext context, List items) { // current route may be null during navigation final currentRoute = context.currentRouteName ?? _lastRoute;