fixed collection page app bar layout
This commit is contained in:
parent
27db528e67
commit
7777bf1550
4 changed files with 71 additions and 50 deletions
|
@ -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),
|
||||
);
|
||||
|
|
|
@ -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))),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue