From 7cd2c3fa8b4e29381f1413ca346c61da8dc10193 Mon Sep 17 00:00:00 2001 From: Thibault Deckers Date: Sat, 3 Dec 2022 11:27:28 +0100 Subject: [PATCH] quick chooser changes --- lib/widgets/common/app_bar/move_button.dart | 6 ++- .../app_bar/quick_choosers/album_chooser.dart | 3 ++ .../quick_choosers/chooser_button.dart | 4 +- .../quick_choosers/filter_chooser.dart | 54 +++++++++++++++---- .../app_bar/quick_choosers/tag_chooser.dart | 3 ++ lib/widgets/common/app_bar/rate_button.dart | 3 +- lib/widgets/common/app_bar/tag_button.dart | 6 ++- 7 files changed, 61 insertions(+), 18 deletions(-) diff --git a/lib/widgets/common/app_bar/move_button.dart b/lib/widgets/common/app_bar/move_button.dart index edaec5843..2b8561338 100644 --- a/lib/widgets/common/app_bar/move_button.dart +++ b/lib/widgets/common/app_bar/move_button.dart @@ -37,7 +37,7 @@ class _MoveButtonState extends ChooserQuickButtonState { String get tooltip => action.getText(context); @override - Widget buildChooser(Animation animation) { + Widget buildChooser(Animation animation, PopupMenuPosition chooserPosition) { final options = settings.recentDestinationAlbums; final takeCount = FilterQuickChooser.maxOptionCount - options.length; if (takeCount > 0) { @@ -53,9 +53,11 @@ class _MoveButtonState extends ChooserQuickButtonState { opacity: animation, child: ScaleTransition( scale: animation, + alignment: chooserPosition == PopupMenuPosition.over ? Alignment.bottomCenter : Alignment.topCenter, child: AlbumQuickChooser( valueNotifier: chooserValueNotifier, - options: widget.chooserPosition == PopupMenuPosition.over ? options.reversed.toList() : options, + options: options, + chooserPosition: chooserPosition, pointerGlobalPosition: pointerGlobalPosition, ), ), diff --git a/lib/widgets/common/app_bar/quick_choosers/album_chooser.dart b/lib/widgets/common/app_bar/quick_choosers/album_chooser.dart index db09f8044..16b226920 100644 --- a/lib/widgets/common/app_bar/quick_choosers/album_chooser.dart +++ b/lib/widgets/common/app_bar/quick_choosers/album_chooser.dart @@ -10,12 +10,14 @@ import 'package:provider/provider.dart'; class AlbumQuickChooser extends StatelessWidget { final ValueNotifier valueNotifier; final List options; + final PopupMenuPosition chooserPosition; final Stream pointerGlobalPosition; const AlbumQuickChooser({ super.key, required this.valueNotifier, required this.options, + required this.chooserPosition, required this.pointerGlobalPosition, }); @@ -25,6 +27,7 @@ class AlbumQuickChooser extends StatelessWidget { return FilterQuickChooser( valueNotifier: valueNotifier, options: options, + chooserPosition: chooserPosition, pointerGlobalPosition: pointerGlobalPosition, buildFilterChip: (context, album) => AvesFilterChip( filter: AlbumFilter(album, source.getAlbumDisplayName(context, album)), diff --git a/lib/widgets/common/app_bar/quick_choosers/chooser_button.dart b/lib/widgets/common/app_bar/quick_choosers/chooser_button.dart index b3f71c1b7..2d6ce1e00 100644 --- a/lib/widgets/common/app_bar/quick_choosers/chooser_button.dart +++ b/lib/widgets/common/app_bar/quick_choosers/chooser_button.dart @@ -35,7 +35,7 @@ abstract class ChooserQuickButtonState, U> exten Curve get animationCurve => Curves.easeOutQuad; - Widget buildChooser(Animation animation); + Widget buildChooser(Animation animation, PopupMenuPosition chooserPosition); ValueNotifier get chooserValueNotifier => _chooserValueNotifier; @@ -106,7 +106,7 @@ abstract class ChooserQuickButtonState, U> exten mediaQuery.padding, DisplayFeatureSubScreen.avoidBounds(mediaQuery).toSet(), ), - child: buildChooser(_animation!), + child: buildChooser(_animation!, chooserPosition), ); }, ); diff --git a/lib/widgets/common/app_bar/quick_choosers/filter_chooser.dart b/lib/widgets/common/app_bar/quick_choosers/filter_chooser.dart index 1b51b3a4a..c8214ef7b 100644 --- a/lib/widgets/common/app_bar/quick_choosers/filter_chooser.dart +++ b/lib/widgets/common/app_bar/quick_choosers/filter_chooser.dart @@ -1,22 +1,29 @@ import 'dart:async'; +import 'dart:ui'; +import 'package:aves/theme/durations.dart'; import 'package:aves/widgets/dialogs/aves_dialog.dart'; import 'package:aves_ui/aves_ui.dart'; import 'package:collection/collection.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 extends StatefulWidget { final ValueNotifier valueNotifier; final List options; + final PopupMenuPosition chooserPosition; final Stream pointerGlobalPosition; final Widget Function(BuildContext context, T album) buildFilterChip; - static const int maxOptionCount = 3; + static const int maxOptionCount = 5; FilterQuickChooser({ super.key, required this.valueNotifier, required List options, + required this.chooserPosition, required this.pointerGlobalPosition, required this.buildFilterChip, }) : options = options.take(maxOptionCount).toList(); @@ -33,13 +40,16 @@ class _FilterQuickChooserState extends State> { List get options => widget.options; + bool get reversed => widget.chooserPosition == PopupMenuPosition.over; + static const margin = EdgeInsets.all(8); - static const padding = EdgeInsets.all(8); + static const padding = EdgeInsets.symmetric(horizontal: 8); static const double intraPadding = 8; @override void initState() { super.initState(); + _selectedRowRect.value = Rect.fromLTWH(0, window.physicalSize.height * (reversed ? 1 : -1), 0, 0); _registerWidget(widget); } @@ -72,11 +82,38 @@ class _FilterQuickChooserState extends State> { padding: margin, child: Material( shape: AvesDialog.shape(context), + clipBehavior: Clip.antiAlias, child: Padding( padding: padding, child: ValueListenableBuilder( valueListenable: valueNotifier, builder: (context, selectedValue, child) { + final durations = context.watch(); + + List 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( children: [ ValueListenableBuilder( @@ -104,12 +141,7 @@ class _FilterQuickChooserState extends State> { child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, - children: options.mapIndexed((index, value) { - return Padding( - padding: index == 0 ? EdgeInsets.zero : const EdgeInsets.only(top: intraPadding), - child: widget.buildFilterChip(context, value), - ); - }).toList(), + children: optionChildren, ), ), ], @@ -128,7 +160,7 @@ class _FilterQuickChooserState extends State> { final contentHeight = chooserSize.height - (margin.vertical + padding.vertical); final optionCount = options.length; - final itemHeight = (contentHeight - (optionCount - 1) * intraPadding) / optionCount; + final itemHeight = (contentHeight - (optionCount + 1) * intraPadding) / optionCount; final local = chooserBox.globalToLocal(globalPosition); final dx = local.dx; @@ -138,8 +170,8 @@ class _FilterQuickChooserState extends State> { if (0 < dx && dx < contentWidth && 0 < dy && dy < contentHeight) { final index = (optionCount * dy / contentHeight).floor(); if (0 <= index && index < optionCount) { - selectedValue = options[index]; - final top = index * (itemHeight + intraPadding); + selectedValue = options[reversed ? optionCount - 1 - index : index]; + final top = index * (itemHeight + intraPadding) + intraPadding; _selectedRowRect.value = Rect.fromLTWH(0, top, contentWidth, itemHeight); } } diff --git a/lib/widgets/common/app_bar/quick_choosers/tag_chooser.dart b/lib/widgets/common/app_bar/quick_choosers/tag_chooser.dart index c546eb624..354b7266a 100644 --- a/lib/widgets/common/app_bar/quick_choosers/tag_chooser.dart +++ b/lib/widgets/common/app_bar/quick_choosers/tag_chooser.dart @@ -8,12 +8,14 @@ import 'package:flutter/material.dart'; class TagQuickChooser extends StatelessWidget { final ValueNotifier valueNotifier; final List options; + final PopupMenuPosition chooserPosition; final Stream pointerGlobalPosition; const TagQuickChooser({ super.key, required this.valueNotifier, required this.options, + required this.chooserPosition, required this.pointerGlobalPosition, }); @@ -22,6 +24,7 @@ class TagQuickChooser extends StatelessWidget { return FilterQuickChooser( valueNotifier: valueNotifier, options: options, + chooserPosition: chooserPosition, pointerGlobalPosition: pointerGlobalPosition, buildFilterChip: (context, filter) => AvesFilterChip( filter: filter, diff --git a/lib/widgets/common/app_bar/rate_button.dart b/lib/widgets/common/app_bar/rate_button.dart index 2cee25b45..8612e259d 100644 --- a/lib/widgets/common/app_bar/rate_button.dart +++ b/lib/widgets/common/app_bar/rate_button.dart @@ -28,11 +28,12 @@ class _RateButtonState extends ChooserQuickButtonState { int? get defaultValue => 3; @override - Widget buildChooser(Animation animation) { + Widget buildChooser(Animation animation, PopupMenuPosition chooserPosition) { return FadeTransition( opacity: animation, child: ScaleTransition( scale: animation, + alignment: chooserPosition == PopupMenuPosition.over ? Alignment.bottomCenter : Alignment.topCenter, child: RateQuickChooser( valueNotifier: chooserValueNotifier, pointerGlobalPosition: pointerGlobalPosition, diff --git a/lib/widgets/common/app_bar/tag_button.dart b/lib/widgets/common/app_bar/tag_button.dart index eda816098..2920632a4 100644 --- a/lib/widgets/common/app_bar/tag_button.dart +++ b/lib/widgets/common/app_bar/tag_button.dart @@ -34,7 +34,7 @@ class _TagButtonState extends ChooserQuickButtonState action.getText(context); @override - Widget buildChooser(Animation animation) { + Widget buildChooser(Animation animation, PopupMenuPosition chooserPosition) { final options = settings.recentTags; final takeCount = FilterQuickChooser.maxOptionCount - options.length; if (takeCount > 0) { @@ -50,9 +50,11 @@ class _TagButtonState extends ChooserQuickButtonState