quick chooser changes
This commit is contained in:
parent
7cd2c3fa8b
commit
3726b7334a
12 changed files with 173 additions and 129 deletions
|
@ -18,7 +18,7 @@ class MoveButton extends ChooserQuickButton<String> {
|
||||||
const MoveButton({
|
const MoveButton({
|
||||||
super.key,
|
super.key,
|
||||||
required this.copy,
|
required this.copy,
|
||||||
super.chooserPosition,
|
required super.blurred,
|
||||||
super.onChooserValue,
|
super.onChooserValue,
|
||||||
required super.onPressed,
|
required super.onPressed,
|
||||||
});
|
});
|
||||||
|
@ -57,6 +57,7 @@ class _MoveButtonState extends ChooserQuickButtonState<MoveButton, String> {
|
||||||
child: AlbumQuickChooser(
|
child: AlbumQuickChooser(
|
||||||
valueNotifier: chooserValueNotifier,
|
valueNotifier: chooserValueNotifier,
|
||||||
options: options,
|
options: options,
|
||||||
|
blurred: widget.blurred,
|
||||||
chooserPosition: chooserPosition,
|
chooserPosition: chooserPosition,
|
||||||
pointerGlobalPosition: pointerGlobalPosition,
|
pointerGlobalPosition: pointerGlobalPosition,
|
||||||
),
|
),
|
||||||
|
|
|
@ -10,6 +10,7 @@ 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 bool blurred;
|
||||||
final PopupMenuPosition chooserPosition;
|
final PopupMenuPosition chooserPosition;
|
||||||
final Stream<Offset> pointerGlobalPosition;
|
final Stream<Offset> pointerGlobalPosition;
|
||||||
|
|
||||||
|
@ -17,6 +18,7 @@ class AlbumQuickChooser extends StatelessWidget {
|
||||||
super.key,
|
super.key,
|
||||||
required this.valueNotifier,
|
required this.valueNotifier,
|
||||||
required this.options,
|
required this.options,
|
||||||
|
required this.blurred,
|
||||||
required this.chooserPosition,
|
required this.chooserPosition,
|
||||||
required this.pointerGlobalPosition,
|
required this.pointerGlobalPosition,
|
||||||
});
|
});
|
||||||
|
@ -27,6 +29,7 @@ class AlbumQuickChooser extends StatelessWidget {
|
||||||
return FilterQuickChooser<String>(
|
return FilterQuickChooser<String>(
|
||||||
valueNotifier: valueNotifier,
|
valueNotifier: valueNotifier,
|
||||||
options: options,
|
options: options,
|
||||||
|
blurred: blurred,
|
||||||
chooserPosition: chooserPosition,
|
chooserPosition: chooserPosition,
|
||||||
pointerGlobalPosition: pointerGlobalPosition,
|
pointerGlobalPosition: pointerGlobalPosition,
|
||||||
buildFilterChip: (context, album) => AvesFilterChip(
|
buildFilterChip: (context, album) => AvesFilterChip(
|
||||||
|
|
|
@ -6,16 +6,16 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
abstract class ChooserQuickButton<T> extends StatefulWidget {
|
abstract class ChooserQuickButton<T> extends StatefulWidget {
|
||||||
final PopupMenuPosition? chooserPosition;
|
final bool blurred;
|
||||||
final ValueSetter<T>? onChooserValue;
|
final ValueSetter<T>? onChooserValue;
|
||||||
final VoidCallback? onPressed;
|
final VoidCallback? onPressed;
|
||||||
|
|
||||||
const ChooserQuickButton({
|
const ChooserQuickButton({
|
||||||
super.key,
|
super.key,
|
||||||
this.chooserPosition,
|
required this.blurred,
|
||||||
this.onChooserValue,
|
this.onChooserValue,
|
||||||
required this.onPressed,
|
required this.onPressed,
|
||||||
}) : assert((chooserPosition == null) == (onChooserValue == null));
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class ChooserQuickButtonState<T extends ChooserQuickButton<U>, U> extends State<T> with SingleTickerProviderStateMixin {
|
abstract class ChooserQuickButtonState<T extends ChooserQuickButton<U>, U> extends State<T> with SingleTickerProviderStateMixin {
|
||||||
|
@ -50,13 +50,12 @@ abstract class ChooserQuickButtonState<T extends ChooserQuickButton<U>, U> exten
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final chooserPosition = widget.chooserPosition;
|
|
||||||
final onChooserValue = widget.onChooserValue;
|
final onChooserValue = widget.onChooserValue;
|
||||||
final isChooserEnabled = chooserPosition != null && onChooserValue != null;
|
final isChooserEnabled = onChooserValue != null;
|
||||||
|
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
behavior: HitTestBehavior.opaque,
|
behavior: HitTestBehavior.opaque,
|
||||||
onLongPressStart: isChooserEnabled ? (details) => _showChooser() : null,
|
onLongPressStart: isChooserEnabled ? _showChooser : null,
|
||||||
onLongPressMoveUpdate: isChooserEnabled ? _moveUpdateStreamController.add : null,
|
onLongPressMoveUpdate: isChooserEnabled ? _moveUpdateStreamController.add : null,
|
||||||
onLongPressEnd: isChooserEnabled
|
onLongPressEnd: isChooserEnabled
|
||||||
? (details) {
|
? (details) {
|
||||||
|
@ -83,10 +82,7 @@ abstract class ChooserQuickButtonState<T extends ChooserQuickButton<U>, U> exten
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _showChooser() {
|
void _showChooser(LongPressStartDetails details) {
|
||||||
final chooserPosition = widget.chooserPosition;
|
|
||||||
if (chooserPosition == null) return;
|
|
||||||
|
|
||||||
final overlay = Overlay.of(context)!;
|
final overlay = Overlay.of(context)!;
|
||||||
final triggerBox = context.findRenderObject() as RenderBox;
|
final triggerBox = context.findRenderObject() as RenderBox;
|
||||||
final overlayBox = overlay.context.findRenderObject() as RenderBox;
|
final overlayBox = overlay.context.findRenderObject() as RenderBox;
|
||||||
|
@ -98,13 +94,14 @@ abstract class ChooserQuickButtonState<T extends ChooserQuickButton<U>, U> exten
|
||||||
_chooserValueNotifier.value = defaultValue;
|
_chooserValueNotifier.value = defaultValue;
|
||||||
_chooserOverlayEntry = OverlayEntry(
|
_chooserOverlayEntry = OverlayEntry(
|
||||||
builder: (context) {
|
builder: (context) {
|
||||||
final mediaQuery = MediaQuery.of(context);
|
final mq = MediaQuery.of(context);
|
||||||
|
final chooserPosition = (details.globalPosition.dy > mq.size.height / 2) ? PopupMenuPosition.over : PopupMenuPosition.under;
|
||||||
return CustomSingleChildLayout(
|
return CustomSingleChildLayout(
|
||||||
delegate: QuickChooserRouteLayout(
|
delegate: QuickChooserRouteLayout(
|
||||||
triggerRect,
|
triggerRect,
|
||||||
chooserPosition,
|
chooserPosition,
|
||||||
mediaQuery.padding,
|
mq.padding,
|
||||||
DisplayFeatureSubScreen.avoidBounds(mediaQuery).toSet(),
|
DisplayFeatureSubScreen.avoidBounds(mq).toSet(),
|
||||||
),
|
),
|
||||||
child: buildChooser(_animation!, chooserPosition),
|
child: buildChooser(_animation!, chooserPosition),
|
||||||
);
|
);
|
||||||
|
|
|
@ -2,7 +2,7 @@ import 'dart:async';
|
||||||
import 'dart:ui';
|
import 'dart:ui';
|
||||||
|
|
||||||
import 'package:aves/theme/durations.dart';
|
import 'package:aves/theme/durations.dart';
|
||||||
import 'package:aves/widgets/dialogs/aves_dialog.dart';
|
import 'package:aves/widgets/common/app_bar/quick_choosers/quick_chooser.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';
|
||||||
|
@ -13,6 +13,7 @@ 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 bool blurred;
|
||||||
final PopupMenuPosition chooserPosition;
|
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;
|
||||||
|
@ -23,6 +24,7 @@ class FilterQuickChooser<T> extends StatefulWidget {
|
||||||
super.key,
|
super.key,
|
||||||
required this.valueNotifier,
|
required this.valueNotifier,
|
||||||
required List<T> options,
|
required List<T> options,
|
||||||
|
required this.blurred,
|
||||||
required this.chooserPosition,
|
required this.chooserPosition,
|
||||||
required this.pointerGlobalPosition,
|
required this.pointerGlobalPosition,
|
||||||
required this.buildFilterChip,
|
required this.buildFilterChip,
|
||||||
|
@ -42,8 +44,6 @@ class _FilterQuickChooserState<T> extends State<FilterQuickChooser<T>> {
|
||||||
|
|
||||||
bool get reversed => widget.chooserPosition == PopupMenuPosition.over;
|
bool get reversed => widget.chooserPosition == PopupMenuPosition.over;
|
||||||
|
|
||||||
static const margin = EdgeInsets.all(8);
|
|
||||||
static const padding = EdgeInsets.symmetric(horizontal: 8);
|
|
||||||
static const double intraPadding = 8;
|
static const double intraPadding = 8;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -78,93 +78,88 @@ class _FilterQuickChooserState<T> extends State<FilterQuickChooser<T>> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Padding(
|
return QuickChooser(
|
||||||
padding: margin,
|
blurred: widget.blurred,
|
||||||
child: Material(
|
child: ValueListenableBuilder<T?>(
|
||||||
shape: AvesDialog.shape(context),
|
valueListenable: valueNotifier,
|
||||||
clipBehavior: Clip.antiAlias,
|
builder: (context, selectedValue, child) {
|
||||||
child: Padding(
|
final durations = context.watch<DurationsData>();
|
||||||
padding: padding,
|
|
||||||
child: ValueListenableBuilder<T?>(
|
|
||||||
valueListenable: valueNotifier,
|
|
||||||
builder: (context, selectedValue, child) {
|
|
||||||
final durations = context.watch<DurationsData>();
|
|
||||||
|
|
||||||
List<Widget> optionChildren = options.mapIndexed((index, value) {
|
List<Widget> optionChildren = options.mapIndexed((index, value) {
|
||||||
final isFirst = index == (reversed ? options.length - 1 : 0);
|
final isFirst = index == (reversed ? options.length - 1 : 0);
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: EdgeInsets.only(top: isFirst ? intraPadding : 0, bottom: intraPadding),
|
padding: EdgeInsets.only(top: isFirst ? intraPadding : 0, bottom: intraPadding),
|
||||||
child: widget.buildFilterChip(context, value),
|
child: widget.buildFilterChip(context, value),
|
||||||
);
|
);
|
||||||
}).toList();
|
}).toList();
|
||||||
|
|
||||||
optionChildren = AnimationConfiguration.toStaggeredList(
|
optionChildren = AnimationConfiguration.toStaggeredList(
|
||||||
duration: durations.staggeredAnimation * .5,
|
duration: durations.staggeredAnimation * .5,
|
||||||
delay: durations.staggeredAnimationDelay * .5 * timeDilation,
|
delay: durations.staggeredAnimationDelay * .5 * timeDilation,
|
||||||
childAnimationBuilder: (child) => SlideAnimation(
|
childAnimationBuilder: (child) => SlideAnimation(
|
||||||
verticalOffset: 50.0,
|
verticalOffset: 50.0 * (widget.chooserPosition == PopupMenuPosition.over ? 1 : -1),
|
||||||
child: FadeInAnimation(
|
child: FadeInAnimation(
|
||||||
|
child: child,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
children: optionChildren,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (reversed) {
|
||||||
|
optionChildren = optionChildren.reversed.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Stack(
|
||||||
|
children: [
|
||||||
|
ValueListenableBuilder<Rect>(
|
||||||
|
valueListenable: _selectedRowRect,
|
||||||
|
builder: (context, selectedRowRect, child) {
|
||||||
|
Widget child = const Center(child: AvesDot());
|
||||||
|
child = AnimatedOpacity(
|
||||||
|
opacity: selectedValue != null ? 1 : 0,
|
||||||
|
curve: Curves.easeInOutCubic,
|
||||||
|
duration: const Duration(milliseconds: 200),
|
||||||
child: child,
|
child: child,
|
||||||
),
|
);
|
||||||
|
child = AnimatedPositioned(
|
||||||
|
top: selectedRowRect.top,
|
||||||
|
height: selectedRowRect.height,
|
||||||
|
curve: Curves.easeInOutCubic,
|
||||||
|
duration: const Duration(milliseconds: 200),
|
||||||
|
child: child,
|
||||||
|
);
|
||||||
|
return child;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsetsDirectional.only(start: 24),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: optionChildren,
|
||||||
),
|
),
|
||||||
children: optionChildren,
|
),
|
||||||
);
|
],
|
||||||
|
);
|
||||||
if (reversed) {
|
},
|
||||||
optionChildren = optionChildren.reversed.toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
return Stack(
|
|
||||||
children: [
|
|
||||||
ValueListenableBuilder<Rect>(
|
|
||||||
valueListenable: _selectedRowRect,
|
|
||||||
builder: (context, selectedRowRect, child) {
|
|
||||||
Widget child = const Center(child: AvesDot());
|
|
||||||
child = AnimatedOpacity(
|
|
||||||
opacity: selectedValue != null ? 1 : 0,
|
|
||||||
curve: Curves.easeInOutCubic,
|
|
||||||
duration: const Duration(milliseconds: 200),
|
|
||||||
child: child,
|
|
||||||
);
|
|
||||||
child = AnimatedPositioned(
|
|
||||||
top: selectedRowRect.top,
|
|
||||||
height: selectedRowRect.height,
|
|
||||||
curve: Curves.easeInOutCubic,
|
|
||||||
duration: const Duration(milliseconds: 200),
|
|
||||||
child: child,
|
|
||||||
);
|
|
||||||
return child;
|
|
||||||
},
|
|
||||||
),
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsetsDirectional.only(start: 24),
|
|
||||||
child: Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: optionChildren,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onPointerMove(Offset globalPosition) {
|
void _onPointerMove(Offset globalPosition) {
|
||||||
|
final padding = QuickChooser.margin.vertical + QuickChooser.padding.vertical;
|
||||||
|
|
||||||
final chooserBox = context.findRenderObject() as RenderBox;
|
final chooserBox = context.findRenderObject() as RenderBox;
|
||||||
final chooserSize = chooserBox.size;
|
final chooserSize = chooserBox.size;
|
||||||
final contentWidth = chooserSize.width;
|
final contentWidth = chooserSize.width;
|
||||||
final contentHeight = chooserSize.height - (margin.vertical + padding.vertical);
|
final contentHeight = chooserSize.height - padding;
|
||||||
|
|
||||||
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;
|
||||||
final dy = local.dy - (margin.vertical + padding.vertical) / 2;
|
final dy = local.dy - padding / 2;
|
||||||
|
|
||||||
T? selectedValue;
|
T? selectedValue;
|
||||||
if (0 < dx && dx < contentWidth && 0 < dy && dy < contentHeight) {
|
if (0 < dx && dx < contentWidth && 0 < dy && dy < contentHeight) {
|
||||||
|
|
47
lib/widgets/common/app_bar/quick_choosers/quick_chooser.dart
Normal file
47
lib/widgets/common/app_bar/quick_choosers/quick_chooser.dart
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
import 'package:aves/theme/themes.dart';
|
||||||
|
import 'package:aves/widgets/common/fx/blurred.dart';
|
||||||
|
import 'package:aves/widgets/common/fx/borders.dart';
|
||||||
|
import 'package:aves/widgets/dialogs/aves_dialog.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class QuickChooser extends StatelessWidget {
|
||||||
|
final bool blurred;
|
||||||
|
final Widget child;
|
||||||
|
|
||||||
|
static const margin = EdgeInsets.all(8);
|
||||||
|
static const padding = EdgeInsets.symmetric(horizontal: 8);
|
||||||
|
|
||||||
|
const QuickChooser({
|
||||||
|
super.key,
|
||||||
|
required this.blurred,
|
||||||
|
required this.child,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final brightness = Theme.of(context).brightness;
|
||||||
|
final backgroundColor = blurred ? Themes.overlayBackgroundColor(brightness: brightness, blurred: blurred) : null;
|
||||||
|
const borderRadius = BorderRadius.all(AvesDialog.cornerRadius);
|
||||||
|
return Padding(
|
||||||
|
padding: margin,
|
||||||
|
child: BlurredRRect(
|
||||||
|
enabled: blurred,
|
||||||
|
borderRadius: borderRadius,
|
||||||
|
child: Material(
|
||||||
|
borderRadius: borderRadius,
|
||||||
|
color: backgroundColor,
|
||||||
|
child: Ink(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
border: AvesBorder.border(context),
|
||||||
|
borderRadius: borderRadius,
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: padding,
|
||||||
|
child: child,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,15 +1,17 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:aves/theme/icons.dart';
|
import 'package:aves/theme/icons.dart';
|
||||||
import 'package:aves/widgets/dialogs/aves_dialog.dart';
|
import 'package:aves/widgets/common/app_bar/quick_choosers/quick_chooser.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class RateQuickChooser extends StatefulWidget {
|
class RateQuickChooser extends StatefulWidget {
|
||||||
|
final bool blurred;
|
||||||
final ValueNotifier<int?> valueNotifier;
|
final ValueNotifier<int?> valueNotifier;
|
||||||
final Stream<Offset> pointerGlobalPosition;
|
final Stream<Offset> pointerGlobalPosition;
|
||||||
|
|
||||||
const RateQuickChooser({
|
const RateQuickChooser({
|
||||||
super.key,
|
super.key,
|
||||||
|
required this.blurred,
|
||||||
required this.valueNotifier,
|
required this.valueNotifier,
|
||||||
required this.pointerGlobalPosition,
|
required this.pointerGlobalPosition,
|
||||||
});
|
});
|
||||||
|
@ -23,9 +25,6 @@ class _RateQuickChooserState extends State<RateQuickChooser> {
|
||||||
|
|
||||||
ValueNotifier<int?> get valueNotifier => widget.valueNotifier;
|
ValueNotifier<int?> get valueNotifier => widget.valueNotifier;
|
||||||
|
|
||||||
static const margin = EdgeInsets.all(8);
|
|
||||||
static const padding = EdgeInsets.all(8);
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
@ -57,43 +56,42 @@ class _RateQuickChooserState extends State<RateQuickChooser> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Padding(
|
return QuickChooser(
|
||||||
padding: margin,
|
blurred: widget.blurred,
|
||||||
child: Material(
|
child: Padding(
|
||||||
shape: AvesDialog.shape(context),
|
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||||
child: Padding(
|
child: ValueListenableBuilder<int?>(
|
||||||
padding: padding,
|
valueListenable: valueNotifier,
|
||||||
child: ValueListenableBuilder<int?>(
|
builder: (context, selectedValue, child) {
|
||||||
valueListenable: valueNotifier,
|
final _rating = selectedValue ?? 0;
|
||||||
builder: (context, selectedValue, child) {
|
return Row(
|
||||||
final _rating = selectedValue ?? 0;
|
mainAxisSize: MainAxisSize.min,
|
||||||
return Row(
|
children: List.generate(5, (i) {
|
||||||
mainAxisSize: MainAxisSize.min,
|
final thisRating = i + 1;
|
||||||
children: List.generate(5, (i) {
|
return Padding(
|
||||||
final thisRating = i + 1;
|
padding: const EdgeInsets.all(4),
|
||||||
return Padding(
|
child: Icon(
|
||||||
padding: const EdgeInsets.all(4),
|
_rating < thisRating ? AIcons.rating : AIcons.ratingFull,
|
||||||
child: Icon(
|
color: _rating < thisRating ? Colors.grey : Colors.amber,
|
||||||
_rating < thisRating ? AIcons.rating : AIcons.ratingFull,
|
),
|
||||||
color: _rating < thisRating ? Colors.grey : Colors.amber,
|
);
|
||||||
),
|
}).toList(),
|
||||||
);
|
);
|
||||||
}).toList(),
|
},
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onPointerMove(Offset globalPosition) {
|
void _onPointerMove(Offset globalPosition) {
|
||||||
|
final padding = QuickChooser.margin.horizontal + QuickChooser.padding.horizontal;
|
||||||
|
|
||||||
final chooserBox = context.findRenderObject() as RenderBox;
|
final chooserBox = context.findRenderObject() as RenderBox;
|
||||||
final chooserSize = chooserBox.size;
|
final chooserSize = chooserBox.size;
|
||||||
final contentWidth = chooserSize.width - (margin.horizontal + padding.horizontal);
|
final contentWidth = chooserSize.width - padding;
|
||||||
|
|
||||||
final local = chooserBox.globalToLocal(globalPosition);
|
final local = chooserBox.globalToLocal(globalPosition);
|
||||||
final dx = local.dx - (margin.horizontal + padding.horizontal) / 2;
|
final dx = local.dx - padding / 2;
|
||||||
|
|
||||||
valueNotifier.value = (5 * dx / contentWidth).ceil().clamp(0, 5);
|
valueNotifier.value = (5 * dx / contentWidth).ceil().clamp(0, 5);
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@ class QuickChooserRouteLayout extends SingleChildLayoutDelegate {
|
||||||
y = triggerRect.top - childSize.height;
|
y = triggerRect.top - childSize.height;
|
||||||
break;
|
break;
|
||||||
case PopupMenuPosition.under:
|
case PopupMenuPosition.under:
|
||||||
y = triggerRect.bottom;
|
y = size.height - triggerRect.bottom;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
double x = (triggerRect.left + (size.width - triggerRect.right) - childSize.width) / 2;
|
double x = (triggerRect.left + (size.width - triggerRect.right) - childSize.width) / 2;
|
||||||
|
|
|
@ -8,6 +8,7 @@ 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 bool blurred;
|
||||||
final PopupMenuPosition chooserPosition;
|
final PopupMenuPosition chooserPosition;
|
||||||
final Stream<Offset> pointerGlobalPosition;
|
final Stream<Offset> pointerGlobalPosition;
|
||||||
|
|
||||||
|
@ -15,6 +16,7 @@ class TagQuickChooser extends StatelessWidget {
|
||||||
super.key,
|
super.key,
|
||||||
required this.valueNotifier,
|
required this.valueNotifier,
|
||||||
required this.options,
|
required this.options,
|
||||||
|
required this.blurred,
|
||||||
required this.chooserPosition,
|
required this.chooserPosition,
|
||||||
required this.pointerGlobalPosition,
|
required this.pointerGlobalPosition,
|
||||||
});
|
});
|
||||||
|
@ -24,6 +26,7 @@ class TagQuickChooser extends StatelessWidget {
|
||||||
return FilterQuickChooser<CollectionFilter>(
|
return FilterQuickChooser<CollectionFilter>(
|
||||||
valueNotifier: valueNotifier,
|
valueNotifier: valueNotifier,
|
||||||
options: options,
|
options: options,
|
||||||
|
blurred: blurred,
|
||||||
chooserPosition: chooserPosition,
|
chooserPosition: chooserPosition,
|
||||||
pointerGlobalPosition: pointerGlobalPosition,
|
pointerGlobalPosition: pointerGlobalPosition,
|
||||||
buildFilterChip: (context, filter) => AvesFilterChip(
|
buildFilterChip: (context, filter) => AvesFilterChip(
|
||||||
|
|
|
@ -6,7 +6,7 @@ import 'package:flutter/material.dart';
|
||||||
class RateButton extends ChooserQuickButton<int> {
|
class RateButton extends ChooserQuickButton<int> {
|
||||||
const RateButton({
|
const RateButton({
|
||||||
super.key,
|
super.key,
|
||||||
super.chooserPosition,
|
required super.blurred,
|
||||||
super.onChooserValue,
|
super.onChooserValue,
|
||||||
required super.onPressed,
|
required super.onPressed,
|
||||||
});
|
});
|
||||||
|
@ -35,6 +35,7 @@ class _RateButtonState extends ChooserQuickButtonState<RateButton, int> {
|
||||||
scale: animation,
|
scale: animation,
|
||||||
alignment: chooserPosition == PopupMenuPosition.over ? Alignment.bottomCenter : Alignment.topCenter,
|
alignment: chooserPosition == PopupMenuPosition.over ? Alignment.bottomCenter : Alignment.topCenter,
|
||||||
child: RateQuickChooser(
|
child: RateQuickChooser(
|
||||||
|
blurred: widget.blurred,
|
||||||
valueNotifier: chooserValueNotifier,
|
valueNotifier: chooserValueNotifier,
|
||||||
pointerGlobalPosition: pointerGlobalPosition,
|
pointerGlobalPosition: pointerGlobalPosition,
|
||||||
),
|
),
|
||||||
|
|
|
@ -15,7 +15,7 @@ import 'package:provider/provider.dart';
|
||||||
class TagButton extends ChooserQuickButton<CollectionFilter> {
|
class TagButton extends ChooserQuickButton<CollectionFilter> {
|
||||||
const TagButton({
|
const TagButton({
|
||||||
super.key,
|
super.key,
|
||||||
super.chooserPosition,
|
required super.blurred,
|
||||||
super.onChooserValue,
|
super.onChooserValue,
|
||||||
required super.onPressed,
|
required super.onPressed,
|
||||||
});
|
});
|
||||||
|
@ -54,6 +54,7 @@ class _TagButtonState extends ChooserQuickButtonState<TagButton, CollectionFilte
|
||||||
child: TagQuickChooser(
|
child: TagQuickChooser(
|
||||||
valueNotifier: chooserValueNotifier,
|
valueNotifier: chooserValueNotifier,
|
||||||
options: options,
|
options: options,
|
||||||
|
blurred: widget.blurred,
|
||||||
chooserPosition: chooserPosition,
|
chooserPosition: chooserPosition,
|
||||||
pointerGlobalPosition: pointerGlobalPosition,
|
pointerGlobalPosition: pointerGlobalPosition,
|
||||||
),
|
),
|
||||||
|
|
|
@ -34,8 +34,6 @@ class BasicSection extends StatelessWidget {
|
||||||
final ValueNotifier<EntryAction?> isEditingMetadataNotifier;
|
final ValueNotifier<EntryAction?> isEditingMetadataNotifier;
|
||||||
final FilterCallback onFilter;
|
final FilterCallback onFilter;
|
||||||
|
|
||||||
static const quickChooserPosition = PopupMenuPosition.over;
|
|
||||||
|
|
||||||
const BasicSection({
|
const BasicSection({
|
||||||
super.key,
|
super.key,
|
||||||
required this.entry,
|
required this.entry,
|
||||||
|
@ -135,14 +133,14 @@ class BasicSection extends StatelessWidget {
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case EntryAction.editRating:
|
case EntryAction.editRating:
|
||||||
button = RateButton(
|
button = RateButton(
|
||||||
chooserPosition: quickChooserPosition,
|
blurred: false,
|
||||||
onChooserValue: (rating) => actionDelegate.quickRate(context, entry, rating),
|
onChooserValue: (rating) => actionDelegate.quickRate(context, entry, rating),
|
||||||
onPressed: onPressed,
|
onPressed: onPressed,
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case EntryAction.editTags:
|
case EntryAction.editTags:
|
||||||
button = TagButton(
|
button = TagButton(
|
||||||
chooserPosition: quickChooserPosition,
|
blurred: false,
|
||||||
onChooserValue: (filter) => actionDelegate.quickTag(context, entry, filter),
|
onChooserValue: (filter) => actionDelegate.quickTag(context, entry, filter),
|
||||||
onPressed: onPressed,
|
onPressed: onPressed,
|
||||||
);
|
);
|
||||||
|
|
|
@ -91,7 +91,6 @@ class ViewerButtonRowContent extends StatelessWidget {
|
||||||
AvesEntry get favouriteTargetEntry => mainEntry.isBurst ? pageEntry : mainEntry;
|
AvesEntry get favouriteTargetEntry => mainEntry.isBurst ? pageEntry : mainEntry;
|
||||||
|
|
||||||
static const double padding = 8;
|
static const double padding = 8;
|
||||||
static const quickChooserPosition = PopupMenuPosition.over;
|
|
||||||
|
|
||||||
ViewerButtonRowContent({
|
ViewerButtonRowContent({
|
||||||
super.key,
|
super.key,
|
||||||
|
@ -206,11 +205,12 @@ class ViewerButtonRowContent extends StatelessWidget {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final blurred = settings.enableBlurEffect;
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case EntryAction.copy:
|
case EntryAction.copy:
|
||||||
child = MoveButton(
|
child = MoveButton(
|
||||||
copy: true,
|
copy: true,
|
||||||
chooserPosition: quickChooserPosition,
|
blurred: blurred,
|
||||||
onChooserValue: (album) => _entryActionDelegate.quickMove(context, album, copy: true),
|
onChooserValue: (album) => _entryActionDelegate.quickMove(context, album, copy: true),
|
||||||
onPressed: onPressed,
|
onPressed: onPressed,
|
||||||
);
|
);
|
||||||
|
@ -218,7 +218,7 @@ class ViewerButtonRowContent extends StatelessWidget {
|
||||||
case EntryAction.move:
|
case EntryAction.move:
|
||||||
child = MoveButton(
|
child = MoveButton(
|
||||||
copy: false,
|
copy: false,
|
||||||
chooserPosition: quickChooserPosition,
|
blurred: blurred,
|
||||||
onChooserValue: (album) => _entryActionDelegate.quickMove(context, album, copy: false),
|
onChooserValue: (album) => _entryActionDelegate.quickMove(context, album, copy: false),
|
||||||
onPressed: onPressed,
|
onPressed: onPressed,
|
||||||
);
|
);
|
||||||
|
@ -252,14 +252,14 @@ class ViewerButtonRowContent extends StatelessWidget {
|
||||||
break;
|
break;
|
||||||
case EntryAction.editRating:
|
case EntryAction.editRating:
|
||||||
child = RateButton(
|
child = RateButton(
|
||||||
chooserPosition: quickChooserPosition,
|
blurred: blurred,
|
||||||
onChooserValue: (rating) => _entryActionDelegate.quickRate(context, rating),
|
onChooserValue: (rating) => _entryActionDelegate.quickRate(context, rating),
|
||||||
onPressed: onPressed,
|
onPressed: onPressed,
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case EntryAction.editTags:
|
case EntryAction.editTags:
|
||||||
child = TagButton(
|
child = TagButton(
|
||||||
chooserPosition: quickChooserPosition,
|
blurred: blurred,
|
||||||
onChooserValue: (filter) => _entryActionDelegate.quickTag(context, filter),
|
onChooserValue: (filter) => _entryActionDelegate.quickTag(context, filter),
|
||||||
onPressed: onPressed,
|
onPressed: onPressed,
|
||||||
);
|
);
|
||||||
|
|
Loading…
Reference in a new issue