mirror of
https://github.com/immich-app/immich.git
synced 2026-07-28 14:47:30 -07:00
feat: button longpress handler (#30200)
* feat: button longpress handler * review suggestion --------- Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
This commit is contained in:
co-authored by
shenlong-tanwen
parent
4a5f13d0e5
commit
829b4e748e
@@ -1,4 +1,5 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
import 'dart:core';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:immich_ui/src/constants.dart';
|
import 'package:immich_ui/src/constants.dart';
|
||||||
@@ -8,6 +9,7 @@ class ImmichColumnButton extends StatefulWidget {
|
|||||||
final IconData icon;
|
final IconData icon;
|
||||||
final String label;
|
final String label;
|
||||||
final FutureOr<void> Function() onPressed;
|
final FutureOr<void> Function() onPressed;
|
||||||
|
final FutureOr<void> Function()? onLongPress;
|
||||||
final bool disabled;
|
final bool disabled;
|
||||||
final bool? loading;
|
final bool? loading;
|
||||||
|
|
||||||
@@ -16,6 +18,7 @@ class ImmichColumnButton extends StatefulWidget {
|
|||||||
required this.icon,
|
required this.icon,
|
||||||
required this.label,
|
required this.label,
|
||||||
required this.onPressed,
|
required this.onPressed,
|
||||||
|
this.onLongPress,
|
||||||
this.disabled = false,
|
this.disabled = false,
|
||||||
this.loading,
|
this.loading,
|
||||||
});
|
});
|
||||||
@@ -25,26 +28,44 @@ class ImmichColumnButton extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _ImmichColumnButtonState extends State<ImmichColumnButton> {
|
class _ImmichColumnButtonState extends State<ImmichColumnButton> {
|
||||||
bool _loading = false;
|
bool _running = false;
|
||||||
bool get _isLoading => widget.loading ?? _loading;
|
bool get _isLoading => widget.loading ?? _running;
|
||||||
|
bool get _isDisabled => widget.disabled || _isLoading;
|
||||||
|
|
||||||
Future<void> _onPressed() async {
|
Future<void> _runAction(FutureOr<void> Function() action) async {
|
||||||
setState(() => _loading = true);
|
setState(() => _running = true);
|
||||||
try {
|
try {
|
||||||
await widget.onPressed();
|
await action();
|
||||||
} finally {
|
} finally {
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
setState(() => _loading = false);
|
setState(() => _running = false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void>? _onPressed() {
|
||||||
|
if (_isDisabled) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _runAction(widget.onPressed);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void>? _onLongPress() {
|
||||||
|
if (_isDisabled || widget.onLongPress == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _runAction(widget.onLongPress!);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final foreground = context.colorOverride ?? Theme.of(context).colorScheme.onSurface;
|
final foreground = context.colorOverride ?? Theme.of(context).colorScheme.onSurface;
|
||||||
|
|
||||||
return TextButton(
|
return TextButton(
|
||||||
onPressed: widget.disabled || _isLoading ? null : _onPressed,
|
onPressed: _onPressed,
|
||||||
|
onLongPress: _onLongPress,
|
||||||
style: TextButton.styleFrom(
|
style: TextButton.styleFrom(
|
||||||
foregroundColor: foreground,
|
foregroundColor: foreground,
|
||||||
padding: const .symmetric(horizontal: ImmichSpacing.sm, vertical: ImmichSpacing.md),
|
padding: const .symmetric(horizontal: ImmichSpacing.sm, vertical: ImmichSpacing.md),
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import 'package:immich_ui/src/internal.dart';
|
|||||||
class ImmichIconButton extends StatefulWidget {
|
class ImmichIconButton extends StatefulWidget {
|
||||||
final IconData icon;
|
final IconData icon;
|
||||||
final FutureOr<void> Function() onPressed;
|
final FutureOr<void> Function() onPressed;
|
||||||
|
final FutureOr<void> Function()? onLongPress;
|
||||||
final ImmichVariant variant;
|
final ImmichVariant variant;
|
||||||
final ImmichColor color;
|
final ImmichColor color;
|
||||||
final bool disabled;
|
final bool disabled;
|
||||||
@@ -16,6 +17,7 @@ class ImmichIconButton extends StatefulWidget {
|
|||||||
super.key,
|
super.key,
|
||||||
required this.icon,
|
required this.icon,
|
||||||
required this.onPressed,
|
required this.onPressed,
|
||||||
|
this.onLongPress,
|
||||||
this.color = .primary,
|
this.color = .primary,
|
||||||
this.variant = .filled,
|
this.variant = .filled,
|
||||||
this.disabled = false,
|
this.disabled = false,
|
||||||
@@ -27,20 +29,37 @@ class ImmichIconButton extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _ImmichIconButtonState extends State<ImmichIconButton> {
|
class _ImmichIconButtonState extends State<ImmichIconButton> {
|
||||||
bool _loading = false;
|
bool _running = false;
|
||||||
bool get _isLoading => widget.loading ?? _loading;
|
bool get _isLoading => widget.loading ?? _running;
|
||||||
|
bool get _isDisabled => widget.disabled || _isLoading;
|
||||||
|
|
||||||
Future<void> _onPressed() async {
|
Future<void> _runAction(FutureOr<void> Function() action) async {
|
||||||
setState(() => _loading = true);
|
setState(() => _running = true);
|
||||||
try {
|
try {
|
||||||
await widget.onPressed();
|
await action();
|
||||||
} finally {
|
} finally {
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
setState(() => _loading = false);
|
setState(() => _running = false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void>? _onPressed() {
|
||||||
|
if (_isDisabled) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _runAction(widget.onPressed);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void>? _onLongPress() {
|
||||||
|
if (_isDisabled || widget.onLongPress == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _runAction(widget.onLongPress!);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final colorScheme = Theme.of(context).colorScheme;
|
final colorScheme = Theme.of(context).colorScheme;
|
||||||
@@ -73,7 +92,8 @@ class _ImmichIconButtonState extends State<ImmichIconButton> {
|
|||||||
child: CircularProgressIndicator(strokeWidth: ImmichBorderWidth.md),
|
child: CircularProgressIndicator(strokeWidth: ImmichBorderWidth.md),
|
||||||
)
|
)
|
||||||
: Icon(widget.icon),
|
: Icon(widget.icon),
|
||||||
onPressed: widget.disabled || _isLoading ? null : _onPressed,
|
onPressed: _onPressed,
|
||||||
|
onLongPress: _onLongPress,
|
||||||
style: IconButton.styleFrom(backgroundColor: background, foregroundColor: foreground),
|
style: IconButton.styleFrom(backgroundColor: background, foregroundColor: foreground),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ class ImmichTextButton extends StatefulWidget {
|
|||||||
final String labelText;
|
final String labelText;
|
||||||
final IconData? icon;
|
final IconData? icon;
|
||||||
final FutureOr<void> Function() onPressed;
|
final FutureOr<void> Function() onPressed;
|
||||||
|
final FutureOr<void> Function()? onLongPress;
|
||||||
final ImmichVariant variant;
|
final ImmichVariant variant;
|
||||||
final bool expanded;
|
final bool expanded;
|
||||||
final bool disabled;
|
final bool disabled;
|
||||||
@@ -17,6 +18,7 @@ class ImmichTextButton extends StatefulWidget {
|
|||||||
required this.labelText,
|
required this.labelText,
|
||||||
this.icon,
|
this.icon,
|
||||||
required this.onPressed,
|
required this.onPressed,
|
||||||
|
this.onLongPress,
|
||||||
this.variant = .filled,
|
this.variant = .filled,
|
||||||
this.expanded = true,
|
this.expanded = true,
|
||||||
|
|
||||||
@@ -29,20 +31,37 @@ class ImmichTextButton extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _ImmichTextButtonState extends State<ImmichTextButton> {
|
class _ImmichTextButtonState extends State<ImmichTextButton> {
|
||||||
bool _loading = false;
|
bool _running = false;
|
||||||
bool get _isLoading => widget.loading ?? _loading;
|
bool get _isLoading => widget.loading ?? _running;
|
||||||
|
bool get _isDisabled => widget.disabled || _isLoading;
|
||||||
|
|
||||||
Future<void> _onPressed() async {
|
Future<void> _runAction(FutureOr<void> Function() action) async {
|
||||||
setState(() => _loading = true);
|
setState(() => _running = true);
|
||||||
try {
|
try {
|
||||||
await widget.onPressed();
|
await action();
|
||||||
} finally {
|
} finally {
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
setState(() => _loading = false);
|
setState(() => _running = false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void>? _onPressed() {
|
||||||
|
if (_isDisabled) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _runAction(widget.onPressed);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void>? _onLongPress() {
|
||||||
|
if (_isDisabled || widget.onLongPress == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _runAction(widget.onLongPress!);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final Widget? icon = _isLoading
|
final Widget? icon = _isLoading
|
||||||
@@ -59,11 +78,22 @@ class _ImmichTextButtonState extends State<ImmichTextButton> {
|
|||||||
style: const .new(fontSize: ImmichTextSize.body, fontWeight: .bold),
|
style: const .new(fontSize: ImmichTextSize.body, fontWeight: .bold),
|
||||||
);
|
);
|
||||||
final style = ElevatedButton.styleFrom(padding: const .symmetric(vertical: ImmichSpacing.md));
|
final style = ElevatedButton.styleFrom(padding: const .symmetric(vertical: ImmichSpacing.md));
|
||||||
final onPressed = widget.disabled || _isLoading ? null : _onPressed;
|
|
||||||
|
|
||||||
final button = switch (widget.variant) {
|
final button = switch (widget.variant) {
|
||||||
ImmichVariant.filled => ElevatedButton.icon(style: style, onPressed: onPressed, icon: icon, label: label),
|
ImmichVariant.filled => ElevatedButton.icon(
|
||||||
ImmichVariant.ghost => TextButton.icon(style: style, onPressed: onPressed, icon: icon, label: label),
|
style: style,
|
||||||
|
onPressed: _onPressed,
|
||||||
|
onLongPress: _onLongPress,
|
||||||
|
icon: icon,
|
||||||
|
label: label,
|
||||||
|
),
|
||||||
|
ImmichVariant.ghost => TextButton.icon(
|
||||||
|
style: style,
|
||||||
|
onPressed: _onPressed,
|
||||||
|
onLongPress: _onLongPress,
|
||||||
|
icon: icon,
|
||||||
|
label: label,
|
||||||
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
if (widget.expanded) {
|
if (widget.expanded) {
|
||||||
|
|||||||
Reference in New Issue
Block a user