#437 tv: filter app bar

This commit is contained in:
Thibault Deckers 2022-12-13 21:02:58 +01:00
parent 6c71752f18
commit 163056bd84
4 changed files with 97 additions and 22 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.7 KiB

After

Width:  |  Height:  |  Size: 6.9 KiB

View file

@ -174,7 +174,7 @@ class _CollectionAppBarState extends State<CollectionAppBar> with SingleTickerPr
children: [ children: [
if (isTelevision) if (isTelevision)
SizedBox( SizedBox(
height: tvActionButtonHeight, height: ActionButton.getTelevisionButtonHeight(context),
child: ListView( child: ListView(
padding: const EdgeInsets.symmetric(horizontal: 8), padding: const EdgeInsets.symmetric(horizontal: 8),
scrollDirection: Axis.horizontal, scrollDirection: Axis.horizontal,
@ -197,7 +197,7 @@ class _CollectionAppBarState extends State<CollectionAppBar> with SingleTickerPr
EntryQueryBar( EntryQueryBar(
queryNotifier: context.select<Query, ValueNotifier<String>>((query) => query.queryNotifier), queryNotifier: context.select<Query, ValueNotifier<String>>((query) => query.queryNotifier),
focusNode: _queryBarFocusNode, focusNode: _queryBarFocusNode,
) ),
], ],
), ),
transitionKey: isSelecting, transitionKey: isSelecting,
@ -210,19 +210,10 @@ class _CollectionAppBarState extends State<CollectionAppBar> with SingleTickerPr
); );
} }
double get tvActionButtonHeight {
final text = [
...EntrySetActions.general,
...EntrySetActions.pageBrowsing,
...EntrySetActions.pageSelection,
].map((action) => action.getText(context)).fold('', (prev, v) => v.length > prev.length ? v : prev);
return ActionButton.getSize(context, text, showCaption: true).height;
}
double get appBarContentHeight { double get appBarContentHeight {
double height = kToolbarHeight; double height = kToolbarHeight;
if (device.isTelevision) { if (device.isTelevision) {
height += tvActionButtonHeight; height += ActionButton.getTelevisionButtonHeight(context);
} }
if (showFilterBar) { if (showFilterBar) {
height += FilterBar.preferredHeight; height += FilterBar.preferredHeight;
@ -318,12 +309,14 @@ class _CollectionAppBarState extends State<CollectionAppBar> with SingleTickerPr
return device.isTelevision return device.isTelevision
? _buildTelevisionActions( ? _buildTelevisionActions(
context: context,
appMode: appMode, appMode: appMode,
selection: selection, selection: selection,
isVisible: isVisible, isVisible: isVisible,
canApply: canApply, canApply: canApply,
) )
: _buildMobileActions( : _buildMobileActions(
context: context,
appMode: appMode, appMode: appMode,
selection: selection, selection: selection,
isVisible: isVisible, isVisible: isVisible,
@ -332,6 +325,7 @@ class _CollectionAppBarState extends State<CollectionAppBar> with SingleTickerPr
} }
List<Widget> _buildTelevisionActions({ List<Widget> _buildTelevisionActions({
required BuildContext context,
required AppMode appMode, required AppMode appMode,
required Selection<AvesEntry> selection, required Selection<AvesEntry> selection,
required bool Function(EntrySetAction action) isVisible, required bool Function(EntrySetAction action) isVisible,
@ -344,16 +338,18 @@ class _CollectionAppBarState extends State<CollectionAppBar> with SingleTickerPr
...isSelecting ? EntrySetActions.pageSelection : EntrySetActions.pageBrowsing, ...isSelecting ? EntrySetActions.pageSelection : EntrySetActions.pageBrowsing,
].where(isVisible).map((action) { ].where(isVisible).map((action) {
// TODO TLAD [tv] togglers cf `_toIconActionButton` // TODO TLAD [tv] togglers cf `_toIconActionButton`
final enabled = canApply(action);
return ActionButton( return ActionButton(
text: action.getText(context), text: action.getText(context),
icon: action.getIcon(), icon: action.getIcon(),
enabled: canApply(action), enabled: enabled,
onPressed: canApply(action) ? () => _onActionSelected(action) : null, onPressed: enabled ? () => _onActionSelected(action) : null,
); );
}).toList(); }).toList();
} }
List<Widget> _buildMobileActions({ List<Widget> _buildMobileActions({
required BuildContext context,
required AppMode appMode, required AppMode appMode,
required Selection<AvesEntry> selection, required Selection<AvesEntry> selection,
required bool Function(EntrySetAction action) isVisible, required bool Function(EntrySetAction action) isVisible,

View file

@ -2,6 +2,7 @@ import 'dart:async';
import 'package:aves/app_mode.dart'; import 'package:aves/app_mode.dart';
import 'package:aves/model/actions/chip_set_actions.dart'; import 'package:aves/model/actions/chip_set_actions.dart';
import 'package:aves/model/device.dart';
import 'package:aves/model/filters/filters.dart'; import 'package:aves/model/filters/filters.dart';
import 'package:aves/model/query.dart'; import 'package:aves/model/query.dart';
import 'package:aves/model/selection.dart'; import 'package:aves/model/selection.dart';
@ -17,6 +18,7 @@ import 'package:aves/widgets/common/search/route.dart';
import 'package:aves/widgets/filter_grids/common/action_delegates/chip_set.dart'; import 'package:aves/widgets/filter_grids/common/action_delegates/chip_set.dart';
import 'package:aves/widgets/filter_grids/common/query_bar.dart'; import 'package:aves/widgets/filter_grids/common/query_bar.dart';
import 'package:aves/widgets/search/search_delegate.dart'; import 'package:aves/widgets/search/search_delegate.dart';
import 'package:aves/widgets/settings/common/quick_actions/action_button.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart'; import 'package:flutter/scheduler.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
@ -125,6 +127,8 @@ class _FilterGridAppBarState<T extends CollectionFilter, CSAD extends ChipSetAct
selector: (context, query) => query.enabled, selector: (context, query) => query.enabled,
builder: (context, queryEnabled, child) { builder: (context, queryEnabled, child) {
ActionsBuilder<T, CSAD> actionsBuilder = widget.actionsBuilder ?? _buildActions; ActionsBuilder<T, CSAD> actionsBuilder = widget.actionsBuilder ?? _buildActions;
final isTelevision = device.isTelevision;
final actions = actionsBuilder(context, appMode, selection, widget.actionDelegate);
return AvesAppBar( return AvesAppBar(
contentHeight: appBarContentHeight, contentHeight: appBarContentHeight,
leading: _buildAppBarLeading( leading: _buildAppBarLeading(
@ -132,13 +136,25 @@ class _FilterGridAppBarState<T extends CollectionFilter, CSAD extends ChipSetAct
isSelecting: isSelecting, isSelecting: isSelecting,
), ),
title: _buildAppBarTitle(isSelecting), title: _buildAppBarTitle(isSelecting),
actions: actionsBuilder(context, appMode, selection, widget.actionDelegate), actions: isTelevision ? [] : actions,
bottom: queryEnabled bottom: Column(
? FilterQueryBar<T>( children: [
if (isTelevision)
SizedBox(
height: ActionButton.getTelevisionButtonHeight(context),
child: ListView(
padding: const EdgeInsets.symmetric(horizontal: 8),
scrollDirection: Axis.horizontal,
children: actions,
),
),
if (queryEnabled)
FilterQueryBar<T>(
queryNotifier: context.select<Query, ValueNotifier<String>>((query) => query.queryNotifier), queryNotifier: context.select<Query, ValueNotifier<String>>((query) => query.queryNotifier),
focusNode: _queryBarFocusNode, focusNode: _queryBarFocusNode,
) ),
: null, ],
),
transitionKey: isSelecting, transitionKey: isSelecting,
); );
}, },
@ -146,11 +162,19 @@ class _FilterGridAppBarState<T extends CollectionFilter, CSAD extends ChipSetAct
} }
double get appBarContentHeight { double get appBarContentHeight {
final hasQuery = context.read<Query>().enabled; double height = kToolbarHeight;
return kToolbarHeight + (hasQuery ? FilterQueryBar.preferredHeight : .0); if (device.isTelevision) {
height += ActionButton.getTelevisionButtonHeight(context);
}
if (context.read<Query>().enabled) {
height += FilterQueryBar.preferredHeight;
}
return height;
} }
Widget _buildAppBarLeading({required bool hasDrawer, required bool isSelecting}) { Widget? _buildAppBarLeading({required bool hasDrawer, required bool isSelecting}) {
if (device.isTelevision) return null;
if (!hasDrawer) { if (!hasDrawer) {
return const CloseButton(); return const CloseButton();
} }
@ -225,6 +249,56 @@ class _FilterGridAppBarState<T extends CollectionFilter, CSAD extends ChipSetAct
selectedFilters: selectedFilters, selectedFilters: selectedFilters,
); );
return device.isTelevision
? _buildTelevisionActions(
context: context,
selection: selection,
isVisible: isVisible,
canApply: canApply,
actionDelegate: actionDelegate,
)
: _buildMobileActions(
context: context,
selection: selection,
isVisible: isVisible,
canApply: canApply,
actionDelegate: actionDelegate,
);
}
List<Widget> _buildTelevisionActions({
required BuildContext context,
required Selection<FilterGridItem<T>> selection,
required bool Function(ChipSetAction action) isVisible,
required bool Function(ChipSetAction action) canApply,
required CSAD actionDelegate,
}) {
final isSelecting = selection.isSelecting;
return [
...ChipSetActions.general,
...isSelecting ? ChipSetActions.selection : ChipSetActions.browsing,
].where(isVisible).map((action) {
// TODO TLAD [tv] togglers cf `FilterGridAppBar.toMenuItem`
final enabled = canApply(action);
return ActionButton(
text: action.getText(context),
icon: action.getIcon(),
enabled: enabled,
onPressed: enabled ? () => _onActionSelected(context, action, actionDelegate) : null,
);
}).toList();
}
List<Widget> _buildMobileActions({
required BuildContext context,
required Selection<FilterGridItem<T>> selection,
required bool Function(ChipSetAction action) isVisible,
required bool Function(ChipSetAction action) canApply,
required CSAD actionDelegate,
}) {
final isSelecting = selection.isSelecting;
final quickActionButtons = (isSelecting ? selectionQuickActions : browsingQuickActions).where(isVisible).map( final quickActionButtons = (isSelecting ? selectionQuickActions : browsingQuickActions).where(isVisible).map(
(action) => _toActionButton(context, actionDelegate, action, enabled: canApply(action)), (action) => _toActionButton(context, actionDelegate, action, enabled: canApply(action)),
); );

View file

@ -70,4 +70,9 @@ class ActionButton extends StatelessWidget {
} }
return Size(width, height); return Size(width, height);
} }
static double getTelevisionButtonHeight(BuildContext context) {
final text = 'whatever' * 42;
return ActionButton.getSize(context, text, showCaption: true).height;
}
} }