app/nav bar fixes
This commit is contained in:
parent
b6cb113720
commit
a6a3244b3c
7 changed files with 102 additions and 52 deletions
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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()),
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue