quick chooser changes

This commit is contained in:
Thibault Deckers 2022-12-03 11:27:28 +01:00
parent 1e7690d5a4
commit 7cd2c3fa8b
7 changed files with 61 additions and 18 deletions

View file

@ -37,7 +37,7 @@ class _MoveButtonState extends ChooserQuickButtonState<MoveButton, String> {
String get tooltip => action.getText(context); String get tooltip => action.getText(context);
@override @override
Widget buildChooser(Animation<double> animation) { Widget buildChooser(Animation<double> animation, PopupMenuPosition chooserPosition) {
final options = settings.recentDestinationAlbums; final options = settings.recentDestinationAlbums;
final takeCount = FilterQuickChooser.maxOptionCount - options.length; final takeCount = FilterQuickChooser.maxOptionCount - options.length;
if (takeCount > 0) { if (takeCount > 0) {
@ -53,9 +53,11 @@ class _MoveButtonState extends ChooserQuickButtonState<MoveButton, String> {
opacity: animation, opacity: animation,
child: ScaleTransition( child: ScaleTransition(
scale: animation, scale: animation,
alignment: chooserPosition == PopupMenuPosition.over ? Alignment.bottomCenter : Alignment.topCenter,
child: AlbumQuickChooser( child: AlbumQuickChooser(
valueNotifier: chooserValueNotifier, valueNotifier: chooserValueNotifier,
options: widget.chooserPosition == PopupMenuPosition.over ? options.reversed.toList() : options, options: options,
chooserPosition: chooserPosition,
pointerGlobalPosition: pointerGlobalPosition, pointerGlobalPosition: pointerGlobalPosition,
), ),
), ),

View file

@ -10,12 +10,14 @@ import 'package:provider/provider.dart';
class AlbumQuickChooser extends StatelessWidget { class AlbumQuickChooser extends StatelessWidget {
final ValueNotifier<String?> valueNotifier; final ValueNotifier<String?> valueNotifier;
final List<String> options; final List<String> options;
final PopupMenuPosition chooserPosition;
final Stream<Offset> pointerGlobalPosition; final Stream<Offset> pointerGlobalPosition;
const AlbumQuickChooser({ const AlbumQuickChooser({
super.key, super.key,
required this.valueNotifier, required this.valueNotifier,
required this.options, required this.options,
required this.chooserPosition,
required this.pointerGlobalPosition, required this.pointerGlobalPosition,
}); });
@ -25,6 +27,7 @@ class AlbumQuickChooser extends StatelessWidget {
return FilterQuickChooser<String>( return FilterQuickChooser<String>(
valueNotifier: valueNotifier, valueNotifier: valueNotifier,
options: options, options: options,
chooserPosition: chooserPosition,
pointerGlobalPosition: pointerGlobalPosition, pointerGlobalPosition: pointerGlobalPosition,
buildFilterChip: (context, album) => AvesFilterChip( buildFilterChip: (context, album) => AvesFilterChip(
filter: AlbumFilter(album, source.getAlbumDisplayName(context, album)), filter: AlbumFilter(album, source.getAlbumDisplayName(context, album)),

View file

@ -35,7 +35,7 @@ abstract class ChooserQuickButtonState<T extends ChooserQuickButton<U>, U> exten
Curve get animationCurve => Curves.easeOutQuad; Curve get animationCurve => Curves.easeOutQuad;
Widget buildChooser(Animation<double> animation); Widget buildChooser(Animation<double> animation, PopupMenuPosition chooserPosition);
ValueNotifier<U?> get chooserValueNotifier => _chooserValueNotifier; ValueNotifier<U?> get chooserValueNotifier => _chooserValueNotifier;
@ -106,7 +106,7 @@ abstract class ChooserQuickButtonState<T extends ChooserQuickButton<U>, U> exten
mediaQuery.padding, mediaQuery.padding,
DisplayFeatureSubScreen.avoidBounds(mediaQuery).toSet(), DisplayFeatureSubScreen.avoidBounds(mediaQuery).toSet(),
), ),
child: buildChooser(_animation!), child: buildChooser(_animation!, chooserPosition),
); );
}, },
); );

View file

@ -1,22 +1,29 @@
import 'dart:async'; import 'dart:async';
import 'dart:ui';
import 'package:aves/theme/durations.dart';
import 'package:aves/widgets/dialogs/aves_dialog.dart'; import 'package:aves/widgets/dialogs/aves_dialog.dart';
import 'package:aves_ui/aves_ui.dart'; import 'package:aves_ui/aves_ui.dart';
import 'package:collection/collection.dart'; import 'package:collection/collection.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter_staggered_animations/flutter_staggered_animations.dart';
import 'package:provider/provider.dart';
class FilterQuickChooser<T> extends StatefulWidget { class FilterQuickChooser<T> extends StatefulWidget {
final ValueNotifier<T?> valueNotifier; final ValueNotifier<T?> valueNotifier;
final List<T> options; final List<T> options;
final PopupMenuPosition chooserPosition;
final Stream<Offset> pointerGlobalPosition; final Stream<Offset> pointerGlobalPosition;
final Widget Function(BuildContext context, T album) buildFilterChip; final Widget Function(BuildContext context, T album) buildFilterChip;
static const int maxOptionCount = 3; static const int maxOptionCount = 5;
FilterQuickChooser({ FilterQuickChooser({
super.key, super.key,
required this.valueNotifier, required this.valueNotifier,
required List<T> options, required List<T> options,
required this.chooserPosition,
required this.pointerGlobalPosition, required this.pointerGlobalPosition,
required this.buildFilterChip, required this.buildFilterChip,
}) : options = options.take(maxOptionCount).toList(); }) : options = options.take(maxOptionCount).toList();
@ -33,13 +40,16 @@ class _FilterQuickChooserState<T> extends State<FilterQuickChooser<T>> {
List<T> get options => widget.options; List<T> get options => widget.options;
bool get reversed => widget.chooserPosition == PopupMenuPosition.over;
static const margin = EdgeInsets.all(8); static const margin = EdgeInsets.all(8);
static const padding = EdgeInsets.all(8); static const padding = EdgeInsets.symmetric(horizontal: 8);
static const double intraPadding = 8; static const double intraPadding = 8;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_selectedRowRect.value = Rect.fromLTWH(0, window.physicalSize.height * (reversed ? 1 : -1), 0, 0);
_registerWidget(widget); _registerWidget(widget);
} }
@ -72,11 +82,38 @@ class _FilterQuickChooserState<T> extends State<FilterQuickChooser<T>> {
padding: margin, padding: margin,
child: Material( child: Material(
shape: AvesDialog.shape(context), shape: AvesDialog.shape(context),
clipBehavior: Clip.antiAlias,
child: Padding( child: Padding(
padding: padding, padding: padding,
child: ValueListenableBuilder<T?>( child: ValueListenableBuilder<T?>(
valueListenable: valueNotifier, valueListenable: valueNotifier,
builder: (context, selectedValue, child) { builder: (context, selectedValue, child) {
final durations = context.watch<DurationsData>();
List<Widget> optionChildren = options.mapIndexed((index, value) {
final isFirst = index == (reversed ? options.length - 1 : 0);
return Padding(
padding: EdgeInsets.only(top: isFirst ? intraPadding : 0, bottom: intraPadding),
child: widget.buildFilterChip(context, value),
);
}).toList();
optionChildren = AnimationConfiguration.toStaggeredList(
duration: durations.staggeredAnimation * .5,
delay: durations.staggeredAnimationDelay * .5 * timeDilation,
childAnimationBuilder: (child) => SlideAnimation(
verticalOffset: 50.0,
child: FadeInAnimation(
child: child,
),
),
children: optionChildren,
);
if (reversed) {
optionChildren = optionChildren.reversed.toList();
}
return Stack( return Stack(
children: [ children: [
ValueListenableBuilder<Rect>( ValueListenableBuilder<Rect>(
@ -104,12 +141,7 @@ class _FilterQuickChooserState<T> extends State<FilterQuickChooser<T>> {
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: options.mapIndexed((index, value) { children: optionChildren,
return Padding(
padding: index == 0 ? EdgeInsets.zero : const EdgeInsets.only(top: intraPadding),
child: widget.buildFilterChip(context, value),
);
}).toList(),
), ),
), ),
], ],
@ -128,7 +160,7 @@ class _FilterQuickChooserState<T> extends State<FilterQuickChooser<T>> {
final contentHeight = chooserSize.height - (margin.vertical + padding.vertical); final contentHeight = chooserSize.height - (margin.vertical + padding.vertical);
final optionCount = options.length; final optionCount = options.length;
final itemHeight = (contentHeight - (optionCount - 1) * intraPadding) / optionCount; final itemHeight = (contentHeight - (optionCount + 1) * intraPadding) / optionCount;
final local = chooserBox.globalToLocal(globalPosition); final local = chooserBox.globalToLocal(globalPosition);
final dx = local.dx; final dx = local.dx;
@ -138,8 +170,8 @@ class _FilterQuickChooserState<T> extends State<FilterQuickChooser<T>> {
if (0 < dx && dx < contentWidth && 0 < dy && dy < contentHeight) { if (0 < dx && dx < contentWidth && 0 < dy && dy < contentHeight) {
final index = (optionCount * dy / contentHeight).floor(); final index = (optionCount * dy / contentHeight).floor();
if (0 <= index && index < optionCount) { if (0 <= index && index < optionCount) {
selectedValue = options[index]; selectedValue = options[reversed ? optionCount - 1 - index : index];
final top = index * (itemHeight + intraPadding); final top = index * (itemHeight + intraPadding) + intraPadding;
_selectedRowRect.value = Rect.fromLTWH(0, top, contentWidth, itemHeight); _selectedRowRect.value = Rect.fromLTWH(0, top, contentWidth, itemHeight);
} }
} }

View file

@ -8,12 +8,14 @@ import 'package:flutter/material.dart';
class TagQuickChooser extends StatelessWidget { class TagQuickChooser extends StatelessWidget {
final ValueNotifier<CollectionFilter?> valueNotifier; final ValueNotifier<CollectionFilter?> valueNotifier;
final List<CollectionFilter> options; final List<CollectionFilter> options;
final PopupMenuPosition chooserPosition;
final Stream<Offset> pointerGlobalPosition; final Stream<Offset> pointerGlobalPosition;
const TagQuickChooser({ const TagQuickChooser({
super.key, super.key,
required this.valueNotifier, required this.valueNotifier,
required this.options, required this.options,
required this.chooserPosition,
required this.pointerGlobalPosition, required this.pointerGlobalPosition,
}); });
@ -22,6 +24,7 @@ class TagQuickChooser extends StatelessWidget {
return FilterQuickChooser<CollectionFilter>( return FilterQuickChooser<CollectionFilter>(
valueNotifier: valueNotifier, valueNotifier: valueNotifier,
options: options, options: options,
chooserPosition: chooserPosition,
pointerGlobalPosition: pointerGlobalPosition, pointerGlobalPosition: pointerGlobalPosition,
buildFilterChip: (context, filter) => AvesFilterChip( buildFilterChip: (context, filter) => AvesFilterChip(
filter: filter, filter: filter,

View file

@ -28,11 +28,12 @@ class _RateButtonState extends ChooserQuickButtonState<RateButton, int> {
int? get defaultValue => 3; int? get defaultValue => 3;
@override @override
Widget buildChooser(Animation<double> animation) { Widget buildChooser(Animation<double> animation, PopupMenuPosition chooserPosition) {
return FadeTransition( return FadeTransition(
opacity: animation, opacity: animation,
child: ScaleTransition( child: ScaleTransition(
scale: animation, scale: animation,
alignment: chooserPosition == PopupMenuPosition.over ? Alignment.bottomCenter : Alignment.topCenter,
child: RateQuickChooser( child: RateQuickChooser(
valueNotifier: chooserValueNotifier, valueNotifier: chooserValueNotifier,
pointerGlobalPosition: pointerGlobalPosition, pointerGlobalPosition: pointerGlobalPosition,

View file

@ -34,7 +34,7 @@ class _TagButtonState extends ChooserQuickButtonState<TagButton, CollectionFilte
String get tooltip => action.getText(context); String get tooltip => action.getText(context);
@override @override
Widget buildChooser(Animation<double> animation) { Widget buildChooser(Animation<double> animation, PopupMenuPosition chooserPosition) {
final options = settings.recentTags; final options = settings.recentTags;
final takeCount = FilterQuickChooser.maxOptionCount - options.length; final takeCount = FilterQuickChooser.maxOptionCount - options.length;
if (takeCount > 0) { if (takeCount > 0) {
@ -50,9 +50,11 @@ class _TagButtonState extends ChooserQuickButtonState<TagButton, CollectionFilte
opacity: animation, opacity: animation,
child: ScaleTransition( child: ScaleTransition(
scale: animation, scale: animation,
alignment: chooserPosition == PopupMenuPosition.over ? Alignment.bottomCenter : Alignment.topCenter,
child: TagQuickChooser( child: TagQuickChooser(
valueNotifier: chooserValueNotifier, valueNotifier: chooserValueNotifier,
options: widget.chooserPosition == PopupMenuPosition.over ? options.reversed.toList() : options, options: options,
chooserPosition: chooserPosition,
pointerGlobalPosition: pointerGlobalPosition, pointerGlobalPosition: pointerGlobalPosition,
), ),
), ),