quick chooser changes
This commit is contained in:
parent
1e7690d5a4
commit
7cd2c3fa8b
7 changed files with 61 additions and 18 deletions
|
@ -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,
|
||||
),
|
||||
),
|
||||
|
|
|
@ -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)),
|
||||
|
|
|
@ -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),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
),
|
||||
),
|
||||
|
|
Loading…
Reference in a new issue