diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f1ef91ca..2b62b5c06 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,8 +13,9 @@ All notable changes to this project will be documented in this file. ### Changed -- No default map style for `izzy` and `libre` flavors -- allow setting default editor +- Map: no default map style for `izzy` and `libre` flavors +- Viewer: allow setting default editor +- Viewer: keep manually un/muted state for following autoplayed videos ### Fixed diff --git a/lib/widgets/viewer/entry_viewer_stack.dart b/lib/widgets/viewer/entry_viewer_stack.dart index 8635e5678..8234b638d 100644 --- a/lib/widgets/viewer/entry_viewer_stack.dart +++ b/lib/widgets/viewer/entry_viewer_stack.dart @@ -1,6 +1,7 @@ import 'dart:math'; import 'package:aves/app_mode.dart'; +import 'package:aves/model/actions/entry_actions.dart'; import 'package:aves/model/actions/move_type.dart'; import 'package:aves/model/entry.dart'; import 'package:aves/model/filters/filters.dart'; @@ -255,7 +256,7 @@ class _EntryViewerStackState extends State with EntryViewContr } else if (notification is VideoActionNotification) { final controller = notification.controller; final action = notification.action; - _videoActionDelegate.onActionSelected(context, controller, action); + _onVideoAction(context, controller, action); } else { return false; } @@ -396,7 +397,7 @@ class _EntryViewerStackState extends State with EntryViewContr scale: _overlayVideoControlScale, onActionSelected: (action) { if (videoController != null) { - _videoActionDelegate.onActionSelected(context, videoController, action); + _onVideoAction(context, videoController, action); } }, onActionMenuOpened: () { @@ -482,6 +483,15 @@ class _EntryViewerStackState extends State with EntryViewContr ); } + Future _onVideoAction(BuildContext context, AvesVideoController controller, EntryAction action) async { + await _videoActionDelegate.onActionSelected(context, controller, action); + if (action == EntryAction.videoToggleMute) { + final override = controller.isMuted; + videoMutedOverride = override; + await context.read().muteAll(override); + } + } + void _onVerticalPageControllerChange() { if (!_isEntryTracked && _verticalPager.hasClients && _verticalPager.page?.floor() == transitionPage) { _trackEntry(); diff --git a/lib/widgets/viewer/video/conductor.dart b/lib/widgets/viewer/video/conductor.dart index eac21879b..df1899f1c 100644 --- a/lib/widgets/viewer/video/conductor.dart +++ b/lib/widgets/viewer/video/conductor.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:aves/model/entry.dart'; import 'package:aves/widgets/viewer/video/controller.dart'; import 'package:aves/widgets/viewer/video/fijkplayer.dart'; @@ -34,5 +36,9 @@ class VideoConductor { return _controllers.firstWhereOrNull((c) => c.entry.uri == entry.uri && c.entry.pageId == entry.pageId); } - Future pauseAll() => Future.forEach(_controllers, (controller) => controller.pause()); + Future _applyToAll(FutureOr Function(AvesVideoController controller) action) => Future.forEach(_controllers, action); + + Future pauseAll() => _applyToAll((controller) => controller.pause()); + + Future muteAll(bool muted) => _applyToAll((controller) => controller.mute(muted)); } diff --git a/lib/widgets/viewer/video/controller.dart b/lib/widgets/viewer/video/controller.dart index 280ed42cb..0c534531d 100644 --- a/lib/widgets/viewer/video/controller.dart +++ b/lib/widgets/viewer/video/controller.dart @@ -144,7 +144,7 @@ abstract class AvesVideoController { Future captureFrame(); - Future toggleMute(); + Future mute(bool muted); Widget buildPlayerWidget(BuildContext context); } diff --git a/lib/widgets/viewer/video/fijkplayer.dart b/lib/widgets/viewer/video/fijkplayer.dart index 6377b87be..157a67568 100644 --- a/lib/widgets/viewer/video/fijkplayer.dart +++ b/lib/widgets/viewer/video/fijkplayer.dart @@ -363,8 +363,8 @@ class IjkPlayerAvesVideoController extends AvesVideoController { bool get isMuted => _volume == 0; @override - Future toggleMute() async { - _volume = isMuted ? 1 : 0; + Future mute(bool muted) async { + _volume = muted ? 0 : 1; _volumeStreamController.add(_volume); await _applyVolume(); } diff --git a/lib/widgets/viewer/video_action_delegate.dart b/lib/widgets/viewer/video_action_delegate.dart index 8e87dcb51..5cb382709 100644 --- a/lib/widgets/viewer/video_action_delegate.dart +++ b/lib/widgets/viewer/video_action_delegate.dart @@ -35,39 +35,39 @@ class VideoActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAwareMix stopOverlayHidingTimer(); } - void onActionSelected(BuildContext context, AvesVideoController controller, EntryAction action) { + Future onActionSelected(BuildContext context, AvesVideoController controller, EntryAction action) async { // make sure overlay is not disappearing when selecting an action stopOverlayHidingTimer(); const ToggleOverlayNotification(visible: true).dispatch(context); switch (action) { case EntryAction.videoCaptureFrame: - _captureFrame(context, controller); + await _captureFrame(context, controller); break; case EntryAction.videoToggleMute: - controller.toggleMute(); + await controller.mute(!controller.isMuted); break; case EntryAction.videoSelectStreams: - _showStreamSelectionDialog(context, controller); + await _showStreamSelectionDialog(context, controller); break; case EntryAction.videoSetSpeed: - _showSpeedDialog(context, controller); + await _showSpeedDialog(context, controller); break; case EntryAction.videoSettings: - _showSettings(context, controller); + await _showSettings(context, controller); break; case EntryAction.videoTogglePlay: - _togglePlayPause(context, controller); + await _togglePlayPause(context, controller); break; case EntryAction.videoReplay10: - controller.seekTo(controller.currentPosition - 10000); + await controller.seekTo(controller.currentPosition - 10000); break; case EntryAction.videoSkip10: - controller.seekTo(controller.currentPosition + 10000); + await controller.seekTo(controller.currentPosition + 10000); break; case EntryAction.open: final entry = controller.entry; - androidAppService.open(entry.uri, entry.mimeTypeAnySubtype).then((success) { + await androidAppService.open(entry.uri, entry.mimeTypeAnySubtype).then((success) { if (!success) showNoMatchingAppDialog(context); }); break; diff --git a/lib/widgets/viewer/visual/controller_mixin.dart b/lib/widgets/viewer/visual/controller_mixin.dart index cc64293f8..447a481e4 100644 --- a/lib/widgets/viewer/visual/controller_mixin.dart +++ b/lib/widgets/viewer/visual/controller_mixin.dart @@ -17,6 +17,8 @@ mixin EntryViewControllerMixin on State { final Map _metadataChangeListeners = {}; final Map Function()> _multiPageControllerPageListeners = {}; + bool? videoMutedOverride; + bool get isViewingImage; ValueNotifier get entryNotifier; @@ -89,6 +91,10 @@ mixin EntryViewControllerMixin on State { } bool get shouldAutoPlayVideoMuted { + if (videoMutedOverride != null) { + return videoMutedOverride!; + } + switch (videoPlaybackOverride) { case SlideshowVideoPlayback.skip: case SlideshowVideoPlayback.playWithSound: @@ -189,7 +195,7 @@ mixin EntryViewControllerMixin on State { await Future.delayed(const Duration(milliseconds: 300) * timeDilation); if (!videoController.isMuted && shouldAutoPlayVideoMuted) { - await videoController.toggleMute(); + await videoController.mute(true); } if (resumeTimeMillis != null) {