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);
@override
Widget buildChooser(Animation<double> animation) {
Widget buildChooser(Animation<double> animation, PopupMenuPosition chooserPosition) {
final options = settings.recentDestinationAlbums;
final takeCount = FilterQuickChooser.maxOptionCount - options.length;
if (takeCount > 0) {
@ -53,9 +53,11 @@ class _MoveButtonState extends ChooserQuickButtonState<MoveButton, String> {
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,
),
),

View file

@ -10,12 +10,14 @@ import 'package:provider/provider.dart';
class AlbumQuickChooser extends StatelessWidget {
final ValueNotifier<String?> valueNotifier;
final List<String> options;
final PopupMenuPosition chooserPosition;
final Stream<Offset> 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<String>(
valueNotifier: valueNotifier,
options: options,
chooserPosition: chooserPosition,
pointerGlobalPosition: pointerGlobalPosition,
buildFilterChip: (context, album) => AvesFilterChip(
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;
Widget buildChooser(Animation<double> animation);
Widget buildChooser(Animation<double> animation, PopupMenuPosition chooserPosition);
ValueNotifier<U?> get chooserValueNotifier => _chooserValueNotifier;
@ -106,7 +106,7 @@ abstract class ChooserQuickButtonState<T extends ChooserQuickButton<U>, U> exten
mediaQuery.padding,
DisplayFeatureSubScreen.avoidBounds(mediaQuery).toSet(),
),
child: buildChooser(_animation!),
child: buildChooser(_animation!, chooserPosition),
);
},
);

View file

@ -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<T> extends StatefulWidget {
final ValueNotifier<T?> valueNotifier;
final List<T> options;
final PopupMenuPosition chooserPosition;
final Stream<Offset> 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<T> options,
required this.chooserPosition,
required this.pointerGlobalPosition,
required this.buildFilterChip,
}) : options = options.take(maxOptionCount).toList();
@ -33,13 +40,16 @@ class _FilterQuickChooserState<T> extends State<FilterQuickChooser<T>> {
List<T> 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<T> extends State<FilterQuickChooser<T>> {
padding: margin,
child: Material(
shape: AvesDialog.shape(context),
clipBehavior: Clip.antiAlias,
child: Padding(
padding: padding,
child: ValueListenableBuilder<T?>(
valueListenable: valueNotifier,
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(
children: [
ValueListenableBuilder<Rect>(
@ -104,12 +141,7 @@ class _FilterQuickChooserState<T> extends State<FilterQuickChooser<T>> {
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<T> extends State<FilterQuickChooser<T>> {
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<T> extends State<FilterQuickChooser<T>> {
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);
}
}

View file

@ -8,12 +8,14 @@ import 'package:flutter/material.dart';
class TagQuickChooser extends StatelessWidget {
final ValueNotifier<CollectionFilter?> valueNotifier;
final List<CollectionFilter> options;
final PopupMenuPosition chooserPosition;
final Stream<Offset> 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<CollectionFilter>(
valueNotifier: valueNotifier,
options: options,
chooserPosition: chooserPosition,
pointerGlobalPosition: pointerGlobalPosition,
buildFilterChip: (context, filter) => AvesFilterChip(
filter: filter,

View file

@ -28,11 +28,12 @@ class _RateButtonState extends ChooserQuickButtonState<RateButton, int> {
int? get defaultValue => 3;
@override
Widget buildChooser(Animation<double> animation) {
Widget buildChooser(Animation<double> 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,

View file

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