fixed collection page app bar layout

This commit is contained in:
Thibault Deckers 2024-06-30 18:22:07 +02:00
parent 27db528e67
commit 7777bf1550
4 changed files with 71 additions and 50 deletions

View file

@ -1,4 +1,5 @@
import 'dart:async';
import 'dart:math';
import 'package:aves/app_mode.dart';
import 'package:aves/model/entry/entry.dart';
@ -171,7 +172,6 @@ class _CollectionAppBarState extends State<CollectionAppBar> with SingleTickerPr
selector: (context, s) => s.collectionBrowsingQuickActions,
builder: (context, _, child) {
final useTvLayout = settings.useTvLayout;
final actions = _buildActions(context, selection);
final onFilterTap = canRemoveFilters ? collection.removeFilter : null;
return AvesAppBar(
contentHeight: appBarContentHeight,
@ -181,7 +181,7 @@ class _CollectionAppBarState extends State<CollectionAppBar> with SingleTickerPr
isSelecting: isSelecting,
),
title: _buildAppBarTitle(isSelecting),
actions: useTvLayout ? [] : actions,
actions: (context, maxWidth) => useTvLayout ? [] : _buildActions(context, selection, maxWidth),
bottom: Column(
children: [
if (useTvLayout)
@ -190,7 +190,7 @@ class _CollectionAppBarState extends State<CollectionAppBar> with SingleTickerPr
child: ListView(
padding: const EdgeInsets.symmetric(horizontal: 8),
scrollDirection: Axis.horizontal,
children: actions,
children: _buildActions(context, selection, double.infinity),
),
),
if (showFilterBar)
@ -301,7 +301,7 @@ class _CollectionAppBarState extends State<CollectionAppBar> with SingleTickerPr
}
}
List<Widget> _buildActions(BuildContext context, Selection<AvesEntry> selection) {
List<Widget> _buildActions(BuildContext context, Selection<AvesEntry> selection, double maxWidth) {
final appMode = context.watch<ValueNotifier<AppMode>>().value;
final isSelecting = selection.isSelecting;
final selectedItemCount = selection.selectedItems.length;
@ -333,6 +333,7 @@ class _CollectionAppBarState extends State<CollectionAppBar> with SingleTickerPr
context: context,
appMode: appMode,
selection: selection,
maxWidth: maxWidth,
isVisible: isVisible,
canApply: canApply,
);
@ -366,20 +367,29 @@ class _CollectionAppBarState extends State<CollectionAppBar> with SingleTickerPr
}).toList();
}
static double _iconButtonWidth(BuildContext context) {
const defaultPadding = EdgeInsets.all(8);
const defaultIconSize = 24.0;
return defaultPadding.horizontal + MediaQuery.textScalerOf(context).scale(defaultIconSize);
}
List<Widget> _buildMobileActions({
required BuildContext context,
required AppMode appMode,
required Selection<AvesEntry> selection,
required double maxWidth,
required bool Function(EntrySetAction action) isVisible,
required bool Function(EntrySetAction action) canApply,
}) {
final availableCount = (maxWidth / _iconButtonWidth(context)).floor();
final isSelecting = selection.isSelecting;
final selectedItemCount = selection.selectedItems.length;
final hasSelection = selectedItemCount > 0;
final browsingQuickActions = settings.collectionBrowsingQuickActions;
final selectionQuickActions = isTrash ? [EntrySetAction.delete, EntrySetAction.restore] : settings.collectionSelectionQuickActions;
final quickActions = isSelecting ? selectionQuickActions : browsingQuickActions;
final quickActions = (isSelecting ? selectionQuickActions : browsingQuickActions).take(max(0, availableCount - 1)).toList();
final quickActionButtons = quickActions.where(isVisible).map(
(action) => _buildButtonIcon(context, action, enabled: canApply(action), selection: selection),
);

View file

@ -1,3 +1,5 @@
import 'dart:math';
import 'package:aves/model/settings/settings.dart';
import 'package:aves/theme/durations.dart';
import 'package:aves/theme/themes.dart';
@ -13,12 +15,13 @@ class AvesAppBar extends StatelessWidget {
final bool pinned;
final Widget? leading;
final Widget title;
final List<Widget> actions;
final List<Widget> Function(BuildContext context, double maxWidth) actions;
final Widget? bottom;
final Object? transitionKey;
static const leadingHeroTag = 'appbar-leading';
static const titleHeroTag = 'appbar-title';
static const double _titleMinWidth = 96;
const AvesAppBar({
super.key,
@ -90,12 +93,16 @@ class AvesAppBar extends StatelessWidget {
child: AnimatedSwitcher(
duration: context.read<DurationsData>().iconAnimation,
child: FontSizeIconTheme(
child: Row(
child: LayoutBuilder(
builder: (context, constraints) {
return Row(
key: ValueKey(transitionKey),
children: [
Expanded(child: title),
...actions,
...(actions(context, max(0, constraints.maxWidth - _titleMinWidth))),
],
);
},
),
),
),

View file

@ -53,44 +53,12 @@ class _ExplorerAppBarState extends State<ExplorerAppBar> with WidgetsBindingObse
@override
Widget build(BuildContext context) {
final animations = context.select<Settings, AccessibilityAnimations>((s) => s.accessibilityAnimations);
return AvesAppBar(
contentHeight: appBarContentHeight,
pinned: true,
leading: const DrawerButton(),
title: _buildAppBarTitle(context),
actions: [
IconButton(
icon: const Icon(AIcons.search),
onPressed: () => _goToSearch(context),
tooltip: MaterialLocalizations.of(context).searchFieldLabel,
),
if (_volumes.length > 1)
FontSizeIconTheme(
child: PopupMenuButton<StorageVolume>(
itemBuilder: (context) {
return _volumes.map((v) {
final selected = widget.directoryNotifier.value.volumePath == v.path;
final icon = v.isRemovable ? AIcons.storageCard : AIcons.storageMain;
return PopupMenuItem(
value: v,
enabled: !selected,
child: MenuRow(
text: v.getDescription(context),
icon: Icon(icon),
),
);
}).toList();
},
onSelected: (volume) async {
// wait for the popup menu to hide before proceeding with the action
await Future.delayed(animations.popUpAnimationDelay * timeDilation);
widget.goTo(volume.path);
},
popUpAnimationStyle: animations.popUpAnimationStyle,
),
),
],
actions: _buildActions,
bottom: LayoutBuilder(
builder: (context, constraints) {
return SizedBox(
@ -132,6 +100,42 @@ class _ExplorerAppBarState extends State<ExplorerAppBar> with WidgetsBindingObse
);
}
List<Widget> _buildActions(BuildContext context, double maxWidth) {
final animations = context.select<Settings, AccessibilityAnimations>((s) => s.accessibilityAnimations);
return [
IconButton(
icon: const Icon(AIcons.search),
onPressed: () => _goToSearch(context),
tooltip: MaterialLocalizations.of(context).searchFieldLabel,
),
if (_volumes.length > 1)
FontSizeIconTheme(
child: PopupMenuButton<StorageVolume>(
itemBuilder: (context) {
return _volumes.map((v) {
final selected = widget.directoryNotifier.value.volumePath == v.path;
final icon = v.isRemovable ? AIcons.storageCard : AIcons.storageMain;
return PopupMenuItem(
value: v,
enabled: !selected,
child: MenuRow(
text: v.getDescription(context),
icon: Icon(icon),
),
);
}).toList();
},
onSelected: (volume) async {
// wait for the popup menu to hide before proceeding with the action
await Future.delayed(animations.popUpAnimationDelay * timeDilation);
widget.goTo(volume.path);
},
popUpAnimationStyle: animations.popUpAnimationStyle,
),
),
];
}
double get appBarContentHeight {
final textScaler = MediaQuery.textScalerOf(context);
return textScaler.scale(kToolbarHeight) + CrumbLine.getPreferredHeight(textScaler);

View file

@ -141,9 +141,9 @@ class _FilterGridAppBarState<T extends CollectionFilter, CSAD extends ChipSetAct
child: Selector<Query, bool>(
selector: (context, query) => query.enabled,
builder: (context, queryEnabled, child) {
ActionsBuilder<T, CSAD> actionsBuilder = widget.actionsBuilder ?? _buildActions;
final actionDelegate = widget.actionDelegate;
final ActionsBuilder<T, CSAD> actionsBuilder = widget.actionsBuilder ?? _buildActions;
final useTvLayout = settings.useTvLayout;
final actions = actionsBuilder(context, appMode, selection, widget.actionDelegate);
return AvesAppBar(
contentHeight: appBarContentHeight,
pinned: context.select<Selection<FilterGridItem<T>>, bool>((selection) => selection.isSelecting),
@ -152,7 +152,7 @@ class _FilterGridAppBarState<T extends CollectionFilter, CSAD extends ChipSetAct
isSelecting: isSelecting,
),
title: _buildAppBarTitle(isSelecting),
actions: useTvLayout ? [] : actions,
actions: (context, maxWidth) => useTvLayout ? [] : actionsBuilder(context, appMode, selection, actionDelegate),
bottom: Column(
children: [
if (useTvLayout)
@ -161,7 +161,7 @@ class _FilterGridAppBarState<T extends CollectionFilter, CSAD extends ChipSetAct
child: ListView(
padding: const EdgeInsets.symmetric(horizontal: 8),
scrollDirection: Axis.horizontal,
children: actions,
children: actionsBuilder(context, appMode, selection, actionDelegate),
),
),
if (queryEnabled)