app/nav bar fixes

This commit is contained in:
Thibault Deckers 2022-05-19 16:41:16 +09:00
parent b6cb113720
commit a6a3244b3c
7 changed files with 102 additions and 52 deletions

View file

@ -11,13 +11,15 @@ class Selection<T> 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<T> extends ChangeNotifier {
}
void toggleSelection(T item) {
if (_selectedItems.isEmpty) select();
if (!_isSelecting) select();
if (!_selectedItems.remove(item)) _selectedItems.add(item);
notifyListeners();
}

View file

@ -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<CollectionAppBar> createState() => _CollectionAppBarState();
}
class _CollectionAppBarState extends State<CollectionAppBar> with SingleTickerProviderStateMixin {
class _CollectionAppBarState extends State<CollectionAppBar> with SingleTickerProviderStateMixin, WidgetsBindingObserver {
final List<StreamSubscription> _subscriptions = [];
final EntrySetActionDelegate _actionDelegate = EntrySetActionDelegate();
late AnimationController _browseToSelectAnimation;
final ValueNotifier<bool> _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<CollectionAppBar> 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<CollectionAppBar> with SingleTickerPr
_subscriptions
..forEach((sub) => sub.cancel())
..clear();
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
@ -106,6 +113,11 @@ class _CollectionAppBarState extends State<CollectionAppBar> with SingleTickerPr
widget.collection.filterChangeNotifier.removeListener(_onFilterChanged);
}
@override
void didChangeMetrics() {
_updateStatusBarHeight();
}
@override
Widget build(BuildContext context) {
final appMode = context.watch<ValueNotifier<AppMode>>().value;
@ -432,8 +444,13 @@ class _CollectionAppBarState extends State<CollectionAppBar> 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<void> _onActionSelected(EntrySetAction action) async {

View file

@ -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<DurationsData>().iconAnimation,
child: Row(
key: ValueKey(transitionKey),
children: [
Expanded(child: title),
...actions,
],
return Selector<MediaQueryData, double>(
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<DurationsData>().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 {

View file

@ -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<String> 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()),

View file

@ -58,7 +58,7 @@ class FilterGridPage<T extends CollectionFilter> extends StatelessWidget {
super.key,
this.settingsRouteKey,
required this.appBar,
this.appBarHeight = kToolbarHeight,
required this.appBarHeight,
required this.sections,
required this.newFilters,
required this.sortFactor,

View file

@ -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<T extends CollectionFilter> extends StatelessWidget {
actionDelegate: actionDelegate,
isEmpty: filterSections.isEmpty,
),
appBarHeight: AvesAppBar.appBarHeightForContentHeight(kToolbarHeight),
sections: filterSections,
newFilters: newFilters ?? {},
sortFactor: sortFactor,

View file

@ -36,6 +36,33 @@ class AppBottomNavBar extends StatefulWidget {
class _AppBottomNavBarState extends State<AppBottomNavBar> {
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<Settings, bool>((s) => !s.hiddenFilters.contains(MimeFilter.video));
@ -84,6 +111,8 @@ class _AppBottomNavBarState extends State<AppBottomNavBar> {
);
}
void _onCollectionFilterChange() => setState(() {});
int _getCurrentIndex(BuildContext context, List<AvesBottomNavItem> items) {
// current route may be null during navigation
final currentRoute = context.currentRouteName ?? _lastRoute;