fix: Long press "play" button with dpad navigation

This commit is contained in:
PartyDonut 2025-10-03 22:37:37 +02:00
parent fd35ffb004
commit 3ce0ed6dbc
9 changed files with 188 additions and 121 deletions

View file

@ -7,12 +7,13 @@ import 'package:fladder/models/item_base_model.dart';
import 'package:fladder/screens/shared/animated_fade_size.dart';
import 'package:fladder/theme.dart';
import 'package:fladder/util/adaptive_layout/adaptive_layout.dart';
import 'package:fladder/util/focus_provider.dart';
import 'package:fladder/widgets/shared/ensure_visible.dart';
class MediaPlayButton extends ConsumerWidget {
final ItemBaseModel? item;
final VoidCallback? onPressed;
final VoidCallback? onLongPressed;
final Function(bool restart)? onPressed;
final Function(bool restart)? onLongPressed;
const MediaPlayButton({
required this.item,
@ -26,17 +27,7 @@ class MediaPlayButton extends ConsumerWidget {
final progress = (item?.progress ?? 0) / 100.0;
final padding = 3.0;
final radius = FladderTheme.smallShape.borderRadius.subtract(BorderRadius.circular(padding));
final buttonState = WidgetStateProperty.resolveWith(
(states) {
return BorderSide(
width: 2,
color: Theme.of(context)
.colorScheme
.onPrimaryContainer
.withValues(alpha: states.contains(WidgetState.focused) ? 0.9 : 0.0),
);
},
);
final theme = Theme.of(context);
Widget buttonTitle(Color contentColor) {
return Padding(
@ -50,10 +41,10 @@ class MediaPlayButton extends ConsumerWidget {
item?.playButtonLabel(context) ?? "",
maxLines: 2,
overflow: TextOverflow.clip,
style: Theme.of(context).textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.w700,
color: contentColor,
),
style: theme.textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.w700,
color: contentColor,
),
),
),
const SizedBox(width: 4),
@ -70,54 +61,79 @@ class MediaPlayButton extends ConsumerWidget {
duration: const Duration(milliseconds: 250),
child: onPressed == null
? const SizedBox.shrink(key: ValueKey('empty'))
: TextButton(
onPressed: onPressed,
onLongPress: onLongPressed,
autofocus: AdaptiveLayout.inputDeviceOf(context) == InputDevice.dPad,
style: ButtonStyle(
side: buttonState,
padding: const WidgetStatePropertyAll(EdgeInsets.zero),
),
onFocusChange: (value) {
if (value) {
context.ensureVisible(
alignment: 1.0,
);
}
},
child: Padding(
padding: EdgeInsets.all(padding),
child: Stack(
alignment: Alignment.center,
children: [
// Progress background
Positioned.fill(
child: DecoratedBox(
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.primaryContainer,
borderRadius: radius,
),
),
),
// Button content
buttonTitle(Theme.of(context).colorScheme.onPrimaryContainer),
Positioned.fill(
child: ClipRect(
clipper: _ProgressClipper(
progress,
),
child: DecoratedBox(
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.primary,
borderRadius: radius,
: Row(
spacing: 2,
children: [
FocusButton(
onTap: () => onPressed?.call(false),
onLongPress: () => onLongPressed?.call(false),
autoFocus: AdaptiveLayout.inputDeviceOf(context) == InputDevice.dPad,
darkOverlay: false,
onFocusChanged: (value) {
if (value) {
context.ensureVisible(
alignment: 1.0,
);
}
},
child: Padding(
padding: EdgeInsets.all(padding),
child: Stack(
alignment: Alignment.center,
children: [
// Progress background
Positioned.fill(
child: DecoratedBox(
decoration: BoxDecoration(
color: theme.colorScheme.primaryContainer,
borderRadius: radius,
),
),
child: buttonTitle(Theme.of(context).colorScheme.onPrimary),
),
// Button content
buttonTitle(theme.colorScheme.onPrimaryContainer),
Positioned.fill(
child: ClipRect(
clipper: _ProgressClipper(
progress,
),
child: DecoratedBox(
decoration: BoxDecoration(
color: theme.colorScheme.primary,
borderRadius: radius,
),
child: buttonTitle(theme.colorScheme.onPrimary),
),
),
),
],
),
),
),
if (progress != 0)
FocusButton(
onTap: () => onPressed?.call(true),
onLongPress: () => onLongPressed?.call(true),
onFocusChanged: (value) {
if (value) {
context.ensureVisible(
alignment: 1.0,
);
}
},
child: Card(
color: theme.colorScheme.primaryContainer,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Icon(
IconsaxPlusBold.refresh,
size: 29,
color: theme.colorScheme.onPrimaryContainer,
),
),
),
],
),
),
),
],
),
);
}