From adefa1e4cda00a24b878c2ffcadef754bc105e21 Mon Sep 17 00:00:00 2001 From: Trizotto Date: Sun, 7 Sep 2025 15:03:41 +0200 Subject: [PATCH] feat: create video player speed indicator --- lib/l10n/app_en.arb | 8 ++ .../video_player_speed_indicator.dart | 87 +++++++++++++++++++ .../video_player/video_player_controls.dart | 2 + 3 files changed, 97 insertions(+) create mode 100644 lib/screens/video_player/components/video_player_speed_indicator.dart diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index da95307..60779ac 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -1327,5 +1327,13 @@ "type": "int" } } + }, + "speedIndicator": "Playback rate: {speed}", + "@speedIndicator": { + "placeholders": { + "speed": { + "type": "double" + } + } } } \ No newline at end of file diff --git a/lib/screens/video_player/components/video_player_speed_indicator.dart b/lib/screens/video_player/components/video_player_speed_indicator.dart new file mode 100644 index 0000000..7a4c779 --- /dev/null +++ b/lib/screens/video_player/components/video_player_speed_indicator.dart @@ -0,0 +1,87 @@ +import 'dart:math'; + +import 'package:flutter/material.dart'; + +import 'package:async/async.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:iconsax_plus/iconsax_plus.dart'; + +import 'package:fladder/providers/settings/video_player_settings_provider.dart'; +import 'package:fladder/util/localization_helper.dart'; + +class VideoPlayerSpeedIndicator extends ConsumerStatefulWidget { + const VideoPlayerSpeedIndicator({super.key}); + + @override + ConsumerState createState() => _VideoPlayerSpeedIndicatorState(); +} + +class _VideoPlayerSpeedIndicatorState extends ConsumerState { + late double currentSpeed = ref.read(playbackRateProvider); + + bool showIndicator = false; + late final timer = RestartableTimer(const Duration(seconds: 1), () { + setState(() { + showIndicator = false; + }); + }); + + @override + void dispose() { + showIndicator = false; + timer.cancel(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + ref.listen( + playbackRateProvider, + (previous, next) { + setState(() { + showIndicator = true; + currentSpeed = next; + }); + timer.reset(); + }, + ); + return IgnorePointer( + child: AnimatedOpacity( + duration: const Duration(milliseconds: 250), + opacity: showIndicator ? 1 : 0, + child: Center( + child: Container( + decoration: BoxDecoration( + color: Colors.black.withValues(alpha: 0.85), + borderRadius: BorderRadius.circular(16), + ), + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Row( + mainAxisSize: MainAxisSize.min, + spacing: 12, + children: [ + Transform.rotate( + angle: currentSpeed < 1 ? pi : 0, + child: Icon(speedIcon(currentSpeed)), + ), + Text(context.localized.speedIndicator(currentSpeed)), + ], + ), + ), + ), + ), + ), + ); + } +} + +IconData speedIcon(double value) { + if (value < 1) { + return IconsaxPlusBroken.flash; + } + if (value == 1) { + return IconsaxPlusLinear.flash_slash; + } + return IconsaxPlusLinear.flash; +} diff --git a/lib/screens/video_player/video_player_controls.dart b/lib/screens/video_player/video_player_controls.dart index a7a1e3e..62523a5 100644 --- a/lib/screens/video_player/video_player_controls.dart +++ b/lib/screens/video_player/video_player_controls.dart @@ -26,6 +26,7 @@ import 'package:fladder/screens/video_player/components/video_player_controls_ex import 'package:fladder/screens/video_player/components/video_player_options_sheet.dart'; import 'package:fladder/screens/video_player/components/video_player_quality_controls.dart'; import 'package:fladder/screens/video_player/components/video_player_seek_indicator.dart'; +import 'package:fladder/screens/video_player/components/video_player_speed_indicator.dart'; import 'package:fladder/screens/video_player/components/video_player_volume_indicator.dart'; import 'package:fladder/screens/video_player/components/video_progress_bar.dart'; import 'package:fladder/screens/video_player/components/video_volume_slider.dart'; @@ -125,6 +126,7 @@ class _DesktopControlsState extends ConsumerState { ), const VideoPlayerSeekIndicator(), const VideoPlayerVolumeIndicator(), + const VideoPlayerSpeedIndicator(), Consumer( builder: (context, ref, child) { final position = ref.watch(mediaPlaybackProvider.select((value) => value.position));