diff --git a/mobile/lib/ui/viewer/file/video_widget_native.dart b/mobile/lib/ui/viewer/file/video_widget_native.dart index 217cff7ffd..7b3502a5eb 100644 --- a/mobile/lib/ui/viewer/file/video_widget_native.dart +++ b/mobile/lib/ui/viewer/file/video_widget_native.dart @@ -1,7 +1,6 @@ import "dart:async"; import "dart:io"; -import "package:flutter/cupertino.dart"; import "package:flutter/material.dart"; import "package:logging/logging.dart"; import "package:native_video_player/native_video_player.dart"; @@ -232,111 +231,17 @@ class _VideoWidgetNativeState extends State bottom: widget.isFromMemories ? 32 : 0, ), child: ValueListenableBuilder( + valueListenable: _isPlaybackReady, builder: (BuildContext context, bool value, _) { return value - ? ValueListenableBuilder( - valueListenable: _showControls, - builder: ( - BuildContext context, - bool value, - _, - ) { - return AnimatedOpacity( - duration: const Duration( - milliseconds: 200, - ), - curve: Curves.easeInQuad, - opacity: value ? 1 : 0, - child: IgnorePointer( - ignoring: !value, - child: Padding( - padding: - const EdgeInsets.symmetric( - horizontal: 8, - ), - child: Container( - padding: - const EdgeInsets.fromLTRB( - 16, - 4, - 16, - 4, - ), - decoration: BoxDecoration( - color: Colors.black - .withOpacity(0.3), - borderRadius: - const BorderRadius.all( - Radius.circular(8), - ), - border: Border.all( - color: strokeFaintDark, - width: 1, - ), - ), - child: Row( - children: [ - AnimatedSize( - duration: - const Duration( - seconds: 5, - ), - curve: Curves.easeInOut, - child: - ValueListenableBuilder( - valueListenable: - _controller! - .onPlaybackPositionChanged, - builder: ( - BuildContext - context, - int value, - _, - ) { - return Text( - _secondsToDuration( - value, - ), - style: - getEnteTextTheme( - context, - ).mini.copyWith( - color: - textBaseDark, - ), - ); - }, - ), - ), - Expanded( - child: SeekBar( - _controller!, - _durationToSeconds( - duration, - ), - _isSeeking, - ), - ), - Text( - duration ?? "0:00", - style: getEnteTextTheme( - context, - ).mini.copyWith( - color: - textBaseDark, - ), - ), - ], - ), - ), - ), - ), - ); - }, + ? _SeekBarAndDuration( + controller: _controller, + duration: duration, + showControls: _showControls, + isSeeking: _isSeeking, ) : const SizedBox(); }, - valueListenable: _isPlaybackReady, ), ), ), @@ -349,42 +254,6 @@ class _VideoWidgetNativeState extends State ); } - String _secondsToDuration(int totalSeconds) { - final hours = totalSeconds ~/ 3600; - final minutes = (totalSeconds % 3600) ~/ 60; - final seconds = totalSeconds % 60; - - if (hours > 0) { - return '${hours.toString().padLeft(1, '0')}:${minutes.toString().padLeft(2, '0')}:${seconds.toString().padLeft(2, '0')}'; - } else { - return '${minutes.toString().padLeft(1, '0')}:${seconds.toString().padLeft(2, '0')}'; - } - } - - int? _durationToSeconds(String? duration) { - if (duration == null) { - _logger.warning("Duration is null"); - return null; - } - final parts = duration.split(':'); - int seconds = 0; - - if (parts.length == 3) { - // Format: "h:mm:ss" - seconds += int.parse(parts[0]) * 3600; // Hours to seconds - seconds += int.parse(parts[1]) * 60; // Minutes to seconds - seconds += int.parse(parts[2]); // Seconds - } else if (parts.length == 2) { - // Format: "m:ss" - seconds += int.parse(parts[0]) * 60; // Minutes to seconds - seconds += int.parse(parts[1]); // Seconds - } else { - throw FormatException('Invalid duration format: $duration'); - } - - return seconds; - } - Future _initializeController( NativeVideoPlayerController controller, ) async { @@ -600,3 +469,146 @@ class _VideoWidgetNativeState extends State } } } + +class _SeekBarAndDuration extends StatelessWidget { + final NativeVideoPlayerController? controller; + final String? duration; + final ValueNotifier showControls; + final ValueNotifier isSeeking; + + const _SeekBarAndDuration({ + required this.controller, + required this.duration, + required this.showControls, + required this.isSeeking, + }); + + @override + Widget build(BuildContext context) { + return ValueListenableBuilder( + valueListenable: showControls, + builder: ( + BuildContext context, + bool value, + _, + ) { + return AnimatedOpacity( + duration: const Duration( + milliseconds: 200, + ), + curve: Curves.easeInQuad, + opacity: value ? 1 : 0, + child: IgnorePointer( + ignoring: !value, + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: 8, + ), + child: Container( + padding: const EdgeInsets.fromLTRB( + 16, + 4, + 16, + 4, + ), + decoration: BoxDecoration( + color: Colors.black.withOpacity(0.3), + borderRadius: const BorderRadius.all( + Radius.circular(8), + ), + border: Border.all( + color: strokeFaintDark, + width: 1, + ), + ), + child: Row( + children: [ + AnimatedSize( + duration: const Duration( + seconds: 5, + ), + curve: Curves.easeInOut, + child: ValueListenableBuilder( + valueListenable: controller!.onPlaybackPositionChanged, + builder: ( + BuildContext context, + int value, + _, + ) { + return Text( + _secondsToDuration( + value, + ), + style: getEnteTextTheme( + context, + ).mini.copyWith( + color: textBaseDark, + ), + ); + }, + ), + ), + Expanded( + child: SeekBar( + controller!, + _durationToSeconds( + duration, + ), + isSeeking, + ), + ), + Text( + duration ?? "0:00", + style: getEnteTextTheme( + context, + ).mini.copyWith( + color: textBaseDark, + ), + ), + ], + ), + ), + ), + ), + ); + }, + ); + } + + /// Returns the duration in the format "h:mm:ss" or "m:ss". + String _secondsToDuration(int totalSeconds) { + final hours = totalSeconds ~/ 3600; + final minutes = (totalSeconds % 3600) ~/ 60; + final seconds = totalSeconds % 60; + + if (hours > 0) { + return '${hours.toString().padLeft(1, '0')}:${minutes.toString().padLeft(2, '0')}:${seconds.toString().padLeft(2, '0')}'; + } else { + return '${minutes.toString().padLeft(1, '0')}:${seconds.toString().padLeft(2, '0')}'; + } + } + + /// Returns the duration in seconds from the format "h:mm:ss" or "m:ss". + int? _durationToSeconds(String? duration) { + if (duration == null) { + return null; + } + final parts = duration.split(':'); + int seconds = 0; + + if (parts.length == 3) { + // Format: "h:mm:ss" + seconds += int.parse(parts[0]) * 3600; // Hours to seconds + seconds += int.parse(parts[1]) * 60; // Minutes to seconds + seconds += int.parse(parts[2]); // Seconds + } else if (parts.length == 2) { + // Format: "m:ss" + seconds += int.parse(parts[0]) * 60; // Minutes to seconds + seconds += int.parse(parts[1]); // Seconds + } else { + throw FormatException('Invalid duration format: $duration'); + } + + return seconds; + } +}