diff --git a/mobile/lib/events/seekbar_triggered_event.dart b/mobile/lib/events/seekbar_triggered_event.dart new file mode 100644 index 0000000000..33d5aa3014 --- /dev/null +++ b/mobile/lib/events/seekbar_triggered_event.dart @@ -0,0 +1,7 @@ +import "package:photos/events/event.dart"; + +class SeekbarTriggeredEvent extends Event { + final int position; + + SeekbarTriggeredEvent({required this.position}); +} diff --git a/mobile/lib/ui/viewer/file/native_video_player_controls/seek_bar.dart b/mobile/lib/ui/viewer/file/native_video_player_controls/seek_bar.dart index 574bd4f132..c3a9e80f8c 100644 --- a/mobile/lib/ui/viewer/file/native_video_player_controls/seek_bar.dart +++ b/mobile/lib/ui/viewer/file/native_video_player_controls/seek_bar.dart @@ -2,6 +2,8 @@ import "dart:async"; import "package:flutter/material.dart"; import "package:native_video_player/native_video_player.dart"; +import "package:photos/core/event_bus.dart"; +import "package:photos/events/seekbar_triggered_event.dart"; import "package:photos/theme/colors.dart"; import "package:photos/theme/ente_theme.dart"; import "package:photos/utils/debouncer.dart"; @@ -23,6 +25,7 @@ class _SeekBarState extends State with SingleTickerProviderStateMixin { executionInterval: const Duration(milliseconds: 325), ); StreamSubscription? _eventsSubscription; + StreamSubscription? _seekbarSubscription; @override void initState() { @@ -33,6 +36,16 @@ class _SeekBarState extends State with SingleTickerProviderStateMixin { value: 0, ); + Future.microtask(() { + _seekbarSubscription = + Bus.instance.on().listen((event) { + if (!mounted || _animationController.value == event.position) return; + + _animationController.value = event.position.toDouble(); + setState(() {}); + }); + }); + _eventsSubscription = widget.controller.events.listen( _listen, ); @@ -42,6 +55,7 @@ class _SeekBarState extends State with SingleTickerProviderStateMixin { @override void dispose() { + _seekbarSubscription?.cancel(); _eventsSubscription?.cancel(); _animationController.dispose(); _debouncer.cancelDebounceTimer(); @@ -57,6 +71,7 @@ class _SeekBarState extends State with SingleTickerProviderStateMixin { return SliderTheme( data: SliderTheme.of(context).copyWith( trackHeight: 1.0, + tickMarkShape: SliderTickMarkShape.noTickMark, thumbShape: const RoundSliderThumbShape(enabledThumbRadius: 8.0), overlayShape: const RoundSliderOverlayShape(overlayRadius: 14.0), activeTrackColor: colorScheme.primary300, diff --git a/mobile/lib/ui/viewer/file/video_widget_native.dart b/mobile/lib/ui/viewer/file/video_widget_native.dart index a74cba0132..3d4578e549 100644 --- a/mobile/lib/ui/viewer/file/video_widget_native.dart +++ b/mobile/lib/ui/viewer/file/video_widget_native.dart @@ -10,6 +10,7 @@ import "package:photos/core/constants.dart"; import "package:photos/core/event_bus.dart"; import "package:photos/events/guest_view_event.dart"; import "package:photos/events/pause_video_event.dart"; +import "package:photos/events/seekbar_triggered_event.dart"; import "package:photos/events/stream_switched_event.dart"; import "package:photos/events/use_media_kit_for_video.dart"; import "package:photos/generated/l10n.dart"; @@ -108,38 +109,51 @@ class _VideoWidgetNativeState extends State Bus.instance.on().listen((event) { if (event.type != PlayerType.nativeVideoPlayer) return; if (event.selectedPreview) { - loadPreview(); + loadPreview(update: true); } else { - loadOriginal(); + loadOriginal(update: true); } }); } - void loadPreview() { - _setFilePathForNativePlayer(widget.playlistData!.preview.path); + Future setVideoSource() async { + final videoSource = VideoSource( + path: _filePath!, + type: VideoSourceType.file, + ); + await _controller?.loadVideo(videoSource); + await _controller?.play(); + + Bus.instance.fire(SeekbarTriggeredEvent(position: 0)); } - void loadOriginal() { + void loadPreview({bool update = false}) async { + _setFilePathForNativePlayer(widget.playlistData!.preview.path, update); + + await setVideoSource(); + } + + void loadOriginal({bool update = false}) async { if (widget.file.isRemoteFile) { - _loadNetworkVideo(); + _loadNetworkVideo(update); _setFileSizeIfNull(); } else if (widget.file.isSharedMediaToAppSandbox) { final localFile = File(getSharedMediaFilePath(widget.file)); if (localFile.existsSync()) { - _setFilePathForNativePlayer(localFile.path); + _setFilePathForNativePlayer(localFile.path, update); } else if (widget.file.uploadedFileID != null) { - _loadNetworkVideo(); + _loadNetworkVideo(update); } } else { - widget.file.getAsset.then((asset) async { + await widget.file.getAsset.then((asset) async { if (asset == null || !(await asset.exists)) { if (widget.file.uploadedFileID != null) { - _loadNetworkVideo(); + _loadNetworkVideo(update); } } else { // ignore: unawaited_futures getFile(widget.file, isOrigin: true).then((file) { - _setFilePathForNativePlayer(file!.path); + _setFilePathForNativePlayer(file!.path, update); if (Platform.isIOS) { _shouldClearCache = true; } @@ -147,6 +161,9 @@ class _VideoWidgetNativeState extends State } }); } + if (update) { + await setVideoSource(); + } } @override @@ -372,11 +389,7 @@ class _VideoWidgetNativeState extends State _isSeeking.addListener(_seekListener); - final videoSource = VideoSource( - path: _filePath!, - type: VideoSourceType.file, - ); - await controller.loadVideo(videoSource); + await setVideoSource(); } catch (e) { _logger.severe( "Error initializing native video player controller for file gen id: ${widget.file.generatedID}", @@ -478,7 +491,7 @@ class _VideoWidgetNativeState extends State } } - void _loadNetworkVideo() { + void _loadNetworkVideo(bool update) { getFileFromServer( widget.file, progressCallback: (count, total) { @@ -494,7 +507,7 @@ class _VideoWidgetNativeState extends State }, ).then((file) { if (file != null) { - _setFilePathForNativePlayer(file.path); + _setFilePathForNativePlayer(file.path, update); } }).onError((error, stackTrace) { showErrorDialog( @@ -578,14 +591,17 @@ class _VideoWidgetNativeState extends State ); } - void _setFilePathForNativePlayer(String url) { - if (mounted) { - setState(() { - _filePath = url; - }); - _setAspectRatioFromVideoProps().then((_) { - setState(() {}); - }); + void _setFilePathForNativePlayer(String url, bool update) { + if (!mounted) return; + setState(() { + _filePath = url; + }); + _setAspectRatioFromVideoProps().then((_) { + setState(() {}); + }); + + if (update) { + setVideoSource(); } }