diff --git a/lib/model/settings/enums/viewer_transition.dart b/lib/model/settings/enums/viewer_transition.dart index e5fe2032e..739e067c3 100644 --- a/lib/model/settings/enums/viewer_transition.dart +++ b/lib/model/settings/enums/viewer_transition.dart @@ -1,5 +1,5 @@ import 'package:aves/widgets/common/extensions/build_context.dart'; -import 'package:aves/widgets/viewer/controller.dart'; +import 'package:aves/widgets/viewer/controls/controller.dart'; import 'package:flutter/widgets.dart'; import 'enums.dart'; diff --git a/lib/widgets/collection/collection_grid.dart b/lib/widgets/collection/collection_grid.dart index 5909acd79..3b71fc124 100644 --- a/lib/widgets/collection/collection_grid.dart +++ b/lib/widgets/collection/collection_grid.dart @@ -247,7 +247,6 @@ class _CollectionGridContentState extends State<_CollectionGridContent> { final viewerCollection = collection.copyWith( listenToSource: false, ); - assert(viewerCollection.sortedEntries.map((entry) => entry.id).contains(entry.id)); Widget child = EntryViewerPage( collection: viewerCollection, initialEntry: entry, diff --git a/lib/widgets/common/action_mixins/entry_storage.dart b/lib/widgets/common/action_mixins/entry_storage.dart index ef1bcdea9..e3c1e5a12 100644 --- a/lib/widgets/common/action_mixins/entry_storage.dart +++ b/lib/widgets/common/action_mixins/entry_storage.dart @@ -30,7 +30,7 @@ import 'package:aves/widgets/dialogs/aves_confirmation_dialog.dart'; import 'package:aves/widgets/dialogs/aves_selection_dialog.dart'; import 'package:aves/widgets/dialogs/convert_entry_dialog.dart'; import 'package:aves/widgets/dialogs/pick_dialogs/album_pick_page.dart'; -import 'package:aves/widgets/viewer/notifications.dart'; +import 'package:aves/widgets/viewer/controls/notifications.dart'; import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; diff --git a/lib/widgets/common/map/buttons/coordinate_filter.dart b/lib/widgets/common/map/buttons/coordinate_filter.dart index 5c984c4dc..4146ae893 100644 --- a/lib/widgets/common/map/buttons/coordinate_filter.dart +++ b/lib/widgets/common/map/buttons/coordinate_filter.dart @@ -5,7 +5,7 @@ import 'package:aves/theme/themes.dart'; import 'package:aves/utils/debouncer.dart'; import 'package:aves/widgets/common/fx/blurred.dart'; import 'package:aves/widgets/common/identity/aves_filter_chip.dart'; -import 'package:aves/widgets/viewer/notifications.dart'; +import 'package:aves/widgets/viewer/controls/notifications.dart'; import 'package:aves_map/aves_map.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; diff --git a/lib/widgets/map/map_page.dart b/lib/widgets/map/map_page.dart index be56ab1ed..b3629257b 100644 --- a/lib/widgets/map/map_page.dart +++ b/lib/widgets/map/map_page.dart @@ -32,7 +32,7 @@ import 'package:aves/widgets/common/thumbnail/scroller.dart'; import 'package:aves/widgets/filter_grids/common/action_delegates/chip.dart'; import 'package:aves/widgets/map/map_info_row.dart'; import 'package:aves/widgets/viewer/entry_viewer_page.dart'; -import 'package:aves/widgets/viewer/notifications.dart'; +import 'package:aves/widgets/viewer/controls/notifications.dart'; import 'package:aves_map/aves_map.dart'; import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; diff --git a/lib/widgets/viewer/action/entry_action_delegate.dart b/lib/widgets/viewer/action/entry_action_delegate.dart index ca4322671..094035435 100644 --- a/lib/widgets/viewer/action/entry_action_delegate.dart +++ b/lib/widgets/viewer/action/entry_action_delegate.dart @@ -29,9 +29,9 @@ import 'package:aves/widgets/dialogs/entry_editors/rename_entry_dialog.dart'; import 'package:aves/widgets/viewer/action/entry_info_action_delegate.dart'; import 'package:aves/widgets/viewer/action/printer.dart'; import 'package:aves/widgets/viewer/action/single_entry_editor.dart'; +import 'package:aves/widgets/viewer/controls/notifications.dart'; import 'package:aves/widgets/viewer/debug/debug_page.dart'; import 'package:aves/widgets/viewer/multipage/conductor.dart'; -import 'package:aves/widgets/viewer/notifications.dart'; import 'package:aves/widgets/viewer/source_viewer_page.dart'; import 'package:aves/widgets/viewer/video/conductor.dart'; import 'package:flutter/foundation.dart'; diff --git a/lib/widgets/viewer/action/entry_info_action_delegate.dart b/lib/widgets/viewer/action/entry_info_action_delegate.dart index 78dfe9374..469252264 100644 --- a/lib/widgets/viewer/action/entry_info_action_delegate.dart +++ b/lib/widgets/viewer/action/entry_info_action_delegate.dart @@ -21,7 +21,7 @@ import 'package:aves/widgets/dialogs/aves_dialog.dart'; import 'package:aves/widgets/map/map_page.dart'; import 'package:aves/widgets/viewer/action/single_entry_editor.dart'; import 'package:aves/widgets/viewer/debug/debug_page.dart'; -import 'package:aves/widgets/viewer/embedded/notifications.dart'; +import 'package:aves/widgets/viewer/info/embedded/notifications.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; diff --git a/lib/widgets/viewer/video_action_delegate.dart b/lib/widgets/viewer/action/video_action_delegate.dart similarity index 99% rename from lib/widgets/viewer/video_action_delegate.dart rename to lib/widgets/viewer/action/video_action_delegate.dart index e58571471..e9562998a 100644 --- a/lib/widgets/viewer/video_action_delegate.dart +++ b/lib/widgets/viewer/action/video_action_delegate.dart @@ -17,7 +17,7 @@ import 'package:aves/widgets/dialogs/aves_dialog.dart'; import 'package:aves/widgets/dialogs/video_speed_dialog.dart'; import 'package:aves/widgets/dialogs/video_stream_selection_dialog.dart'; import 'package:aves/widgets/settings/video/video_settings_page.dart'; -import 'package:aves/widgets/viewer/notifications.dart'; +import 'package:aves/widgets/viewer/controls/notifications.dart'; import 'package:aves/widgets/viewer/video/controller.dart'; import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; diff --git a/lib/widgets/viewer/controller.dart b/lib/widgets/viewer/controls/controller.dart similarity index 97% rename from lib/widgets/viewer/controller.dart rename to lib/widgets/viewer/controls/controller.dart index 7a5d141d0..3ee3f2a6e 100644 --- a/lib/widgets/viewer/controller.dart +++ b/lib/widgets/viewer/controls/controller.dart @@ -4,6 +4,7 @@ import 'dart:math'; import 'package:aves/model/entry.dart'; import 'package:aves/model/settings/enums/enums.dart'; import 'package:aves/theme/durations.dart'; +import 'package:aves/widgets/viewer/controls/events.dart'; import 'package:aves_magnifier/aves_magnifier.dart'; import 'package:flutter/widgets.dart'; @@ -103,16 +104,6 @@ class ViewerController { } } -@immutable -class ViewerShowNextEvent {} - -@immutable -class ViewerOverlayToggleEvent { - final bool? visible; - - const ViewerOverlayToggleEvent({required this.visible}); -} - class PageTransitionEffects { static TransitionBuilder fade( PageController pageController, diff --git a/lib/widgets/viewer/controls/events.dart b/lib/widgets/viewer/controls/events.dart new file mode 100644 index 000000000..e39c97e1e --- /dev/null +++ b/lib/widgets/viewer/controls/events.dart @@ -0,0 +1,11 @@ +import 'package:flutter/foundation.dart'; + +@immutable +class ViewerShowNextEvent {} + +@immutable +class ViewerOverlayToggleEvent { + final bool? visible; + + const ViewerOverlayToggleEvent({required this.visible}); +} diff --git a/lib/widgets/viewer/controls/intents.dart b/lib/widgets/viewer/controls/intents.dart new file mode 100644 index 000000000..f59918194 --- /dev/null +++ b/lib/widgets/viewer/controls/intents.dart @@ -0,0 +1,50 @@ +import 'package:aves/model/actions/entry_actions.dart'; +import 'package:flutter/widgets.dart'; + +class ShowPreviousIntent extends Intent { + const ShowPreviousIntent(); +} + +class ShowNextIntent extends Intent { + const ShowNextIntent(); +} + +class LeaveIntent extends Intent { + const LeaveIntent(); +} + +class ShowInfoIntent extends Intent { + const ShowInfoIntent(); +} + +class TvShowLessInfoIntent extends Intent { + const TvShowLessInfoIntent(); +} + +class TvShowMoreInfoIntent extends Intent { + const TvShowMoreInfoIntent(); +} + +class PlayPauseIntent extends Intent { + final TvPlayPauseType type; + + const PlayPauseIntent.play() : type = TvPlayPauseType.play; + + const PlayPauseIntent.pause() : type = TvPlayPauseType.pause; + + const PlayPauseIntent.toggle() : type = TvPlayPauseType.toggle; +} + +enum TvPlayPauseType { + play, + pause, + toggle, +} + +class EntryActionIntent extends Intent { + final EntryAction action; + + const EntryActionIntent({ + required this.action, + }); +} diff --git a/lib/widgets/viewer/notifications.dart b/lib/widgets/viewer/controls/notifications.dart similarity index 100% rename from lib/widgets/viewer/notifications.dart rename to lib/widgets/viewer/controls/notifications.dart diff --git a/lib/widgets/viewer/controls/shortcuts.dart b/lib/widgets/viewer/controls/shortcuts.dart new file mode 100644 index 000000000..af2c9b9b8 --- /dev/null +++ b/lib/widgets/viewer/controls/shortcuts.dart @@ -0,0 +1,34 @@ +import 'package:aves/model/actions/entry_actions.dart'; +import 'package:aves/widgets/viewer/controls/intents.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +class ViewerShortcuts { + static const entryActions = { + SingleActivator(LogicalKeyboardKey.delete): EntryActionIntent(action: EntryAction.delete), + }; + +// cf https://developer.android.com/training/tv/start/controllers#media-events + static const media = { + // KEYCODE_MEDIA_PLAY_PAUSE / 85 / play/pause + SingleActivator(LogicalKeyboardKey.mediaPlayPause): PlayPauseIntent.toggle(), + // KEYCODE_MEDIA_STOP / 86 / stop + SingleActivator(LogicalKeyboardKey.mediaStop): PlayPauseIntent.pause(), + // KEYCODE_MEDIA_NEXT / 87 / skip to next + SingleActivator(LogicalKeyboardKey.mediaTrackNext): ShowNextIntent(), + // KEYCODE_MEDIA_PREVIOUS / 88 / skip to previous + SingleActivator(LogicalKeyboardKey.mediaTrackPrevious): ShowPreviousIntent(), + // KEYCODE_MEDIA_PLAY / 126 / play + SingleActivator(LogicalKeyboardKey.mediaPlay): PlayPauseIntent.play(), + // KEYCODE_MEDIA_PAUSE / 127 / pause + SingleActivator(LogicalKeyboardKey.mediaPause): PlayPauseIntent.pause(), + // KEYCODE_BUTTON_L1 / 102 / skip to previous + SingleActivator(LogicalKeyboardKey.gameButtonLeft1): ShowPreviousIntent(), + // KEYCODE_BUTTON_R1 / 103 / skip to next + SingleActivator(LogicalKeyboardKey.gameButtonRight1): ShowNextIntent(), + // KEYCODE_BUTTON_START / 108 / pause + SingleActivator(LogicalKeyboardKey.gameButtonStart): PlayPauseIntent.pause(), + // KEYCODE_BUTTON_SELECT / 109 / play/pause + SingleActivator(LogicalKeyboardKey.gameButtonSelect): PlayPauseIntent.toggle(), + }; +} diff --git a/lib/widgets/viewer/entry_horizontal_pager.dart b/lib/widgets/viewer/entry_horizontal_pager.dart index 099ec2f92..82bad368e 100644 --- a/lib/widgets/viewer/entry_horizontal_pager.dart +++ b/lib/widgets/viewer/entry_horizontal_pager.dart @@ -3,9 +3,9 @@ import 'package:aves/model/settings/enums/accessibility_animations.dart'; import 'package:aves/model/settings/enums/viewer_transition.dart'; import 'package:aves/model/settings/settings.dart'; import 'package:aves/model/source/collection_lens.dart'; -import 'package:aves/widgets/viewer/controller.dart'; +import 'package:aves/widgets/viewer/controls/controller.dart'; +import 'package:aves/widgets/viewer/controls/notifications.dart'; import 'package:aves/widgets/viewer/multipage/conductor.dart'; -import 'package:aves/widgets/viewer/notifications.dart'; import 'package:aves/widgets/viewer/page_entry_builder.dart'; import 'package:aves/widgets/viewer/visual/entry_page_view.dart'; import 'package:aves_magnifier/aves_magnifier.dart'; diff --git a/lib/widgets/viewer/entry_vertical_pager.dart b/lib/widgets/viewer/entry_vertical_pager.dart index 8b73e3be5..3f7c7a0d2 100644 --- a/lib/widgets/viewer/entry_vertical_pager.dart +++ b/lib/widgets/viewer/entry_vertical_pager.dart @@ -8,10 +8,14 @@ import 'package:aves/model/entry.dart'; import 'package:aves/model/settings/settings.dart'; import 'package:aves/model/source/collection_lens.dart'; import 'package:aves/theme/durations.dart'; -import 'package:aves/widgets/viewer/controller.dart'; +import 'package:aves/widgets/viewer/action/entry_action_delegate.dart'; +import 'package:aves/widgets/viewer/controls/controller.dart'; +import 'package:aves/widgets/viewer/controls/intents.dart'; +import 'package:aves/widgets/viewer/controls/notifications.dart'; +import 'package:aves/widgets/viewer/controls/shortcuts.dart'; import 'package:aves/widgets/viewer/entry_horizontal_pager.dart'; import 'package:aves/widgets/viewer/info/info_page.dart'; -import 'package:aves/widgets/viewer/notifications.dart'; +import 'package:aves/widgets/viewer/multipage/conductor.dart'; import 'package:aves/widgets/viewer/video/conductor.dart'; import 'package:aves_magnifier/aves_magnifier.dart'; import 'package:flutter/gestures.dart'; @@ -184,37 +188,18 @@ class _ViewerVerticalPageViewState extends State { Widget _buildImagePage() { final useTvLayout = settings.useTvLayout; - // cf https://developer.android.com/training/tv/start/controllers#media-events Map? shortcuts = { - const SingleActivator(LogicalKeyboardKey.arrowUp): useTvLayout ? const TvShowLessInfoIntent() : const _LeaveIntent(), - const SingleActivator(LogicalKeyboardKey.arrowDown): useTvLayout ? const _TvShowMoreInfoIntent() : const _ShowInfoIntent(), - // KEYCODE_MEDIA_PLAY_PAUSE / 85 / play/pause - const SingleActivator(LogicalKeyboardKey.mediaPlayPause): const _PlayPauseIntent.toggle(), - // KEYCODE_MEDIA_STOP / 86 / stop - const SingleActivator(LogicalKeyboardKey.mediaStop): const _PlayPauseIntent.pause(), - // KEYCODE_MEDIA_NEXT / 87 / skip to next - const SingleActivator(LogicalKeyboardKey.mediaTrackNext): const _ShowNextIntent(), - // KEYCODE_MEDIA_PREVIOUS / 88 / skip to previous - const SingleActivator(LogicalKeyboardKey.mediaTrackPrevious): const _ShowPreviousIntent(), - // KEYCODE_MEDIA_PLAY / 126 / play - const SingleActivator(LogicalKeyboardKey.mediaPlay): const _PlayPauseIntent.play(), - // KEYCODE_MEDIA_PAUSE / 127 / pause - const SingleActivator(LogicalKeyboardKey.mediaPause): const _PlayPauseIntent.pause(), - // KEYCODE_BUTTON_L1 / 102 / skip to previous - const SingleActivator(LogicalKeyboardKey.gameButtonLeft1): const _ShowPreviousIntent(), - // KEYCODE_BUTTON_R1 / 103 / skip to next - const SingleActivator(LogicalKeyboardKey.gameButtonRight1): const _ShowNextIntent(), - // KEYCODE_BUTTON_START / 108 / pause - const SingleActivator(LogicalKeyboardKey.gameButtonStart): const _PlayPauseIntent.pause(), - // KEYCODE_BUTTON_SELECT / 109 / play/pause - const SingleActivator(LogicalKeyboardKey.gameButtonSelect): const _PlayPauseIntent.toggle(), + ...ViewerShortcuts.entryActions, + ...ViewerShortcuts.media, + const SingleActivator(LogicalKeyboardKey.arrowUp): useTvLayout ? const TvShowLessInfoIntent() : const LeaveIntent(), + const SingleActivator(LogicalKeyboardKey.arrowDown): useTvLayout ? const TvShowMoreInfoIntent() : const ShowInfoIntent(), }; Widget? child; if (hasCollection) { shortcuts.addAll(const { - SingleActivator(LogicalKeyboardKey.arrowLeft): _ShowPreviousIntent(), - SingleActivator(LogicalKeyboardKey.arrowRight): _ShowNextIntent(), + SingleActivator(LogicalKeyboardKey.arrowLeft): ShowPreviousIntent(), + SingleActivator(LogicalKeyboardKey.arrowRight): ShowNextIntent(), }); child = MultiEntryScroller( collection: collection!, @@ -249,13 +234,14 @@ class _ViewerVerticalPageViewState extends State { autofocus: true, shortcuts: shortcuts, actions: { - _ShowPreviousIntent: CallbackAction(onInvoke: (intent) => _goToHorizontalPage(-1, animate: false)), - _ShowNextIntent: CallbackAction(onInvoke: (intent) => _goToHorizontalPage(1, animate: false)), - _LeaveIntent: CallbackAction(onInvoke: (intent) => Navigator.maybeOf(context)?.pop()), - _ShowInfoIntent: CallbackAction(onInvoke: (intent) => ShowInfoPageNotification().dispatch(context)), + ShowPreviousIntent: CallbackAction(onInvoke: (intent) => _goToHorizontalPage(-1, animate: false)), + ShowNextIntent: CallbackAction(onInvoke: (intent) => _goToHorizontalPage(1, animate: false)), + LeaveIntent: CallbackAction(onInvoke: (intent) => Navigator.maybeOf(context)?.pop()), + ShowInfoIntent: CallbackAction(onInvoke: (intent) => ShowInfoPageNotification().dispatch(context)), TvShowLessInfoIntent: CallbackAction(onInvoke: (intent) => TvShowLessInfoNotification().dispatch(context)), - _TvShowMoreInfoIntent: CallbackAction(onInvoke: (intent) => TvShowMoreInfoNotification().dispatch(context)), - _PlayPauseIntent: CallbackAction<_PlayPauseIntent>(onInvoke: (intent) => _onPlayPauseIntent(intent, entry)), + TvShowMoreInfoIntent: CallbackAction(onInvoke: (intent) => TvShowMoreInfoNotification().dispatch(context)), + PlayPauseIntent: CallbackAction(onInvoke: (intent) => _onPlayPauseIntent(intent, entry)), + EntryActionIntent: CallbackAction(onInvoke: (intent) => _onEntryActionIntent(intent.action)), ActivateIntent: CallbackAction(onInvoke: (intent) { if (useTvLayout) { final _entry = entry; @@ -279,6 +265,22 @@ class _ViewerVerticalPageViewState extends State { return const SizedBox(); } + void _onEntryActionIntent(EntryAction action) { + final mainEntry = entry; + if (mainEntry != null) { + AvesEntry? pageEntry; + final multiPageController = context.read().getController(mainEntry); + if (multiPageController != null) { + pageEntry = multiPageController.info?.getPageEntryByIndex(multiPageController.page); + } + final appMode = context.read>().value; + final actionDelegate = EntryActionDelegate(mainEntry, pageEntry ?? mainEntry, collection); + if (actionDelegate.isVisible(appMode: appMode, action: action) && actionDelegate.canApply(action)) { + actionDelegate.onActionSelected(context, action); + } + } + } + void _goToHorizontalPage(int delta, {required bool animate}) { final pageController = widget.horizontalPager; final page = pageController.page?.round(); @@ -355,7 +357,7 @@ class _ViewerVerticalPageViewState extends State { } } - void _onPlayPauseIntent(_PlayPauseIntent intent, entry) { + void _onPlayPauseIntent(PlayPauseIntent intent, entry) { // address `TV-PP` requirement from https://developer.android.com/docs/quality-guidelines/tv-app-quality final _entry = entry; if (_entry != null && _entry.isVideo) { @@ -363,13 +365,13 @@ class _ViewerVerticalPageViewState extends State { if (controller != null) { bool toggle; switch (intent.type) { - case _TvPlayPauseType.play: + case TvPlayPauseType.play: toggle = !controller.isPlaying; break; - case _TvPlayPauseType.pause: + case TvPlayPauseType.pause: toggle = controller.isPlaying; break; - case _TvPlayPauseType.toggle: + case TvPlayPauseType.toggle: toggle = true; break; } @@ -380,49 +382,3 @@ class _ViewerVerticalPageViewState extends State { } } } - -// keyboard shortcut intents - -class _ShowPreviousIntent extends Intent { - const _ShowPreviousIntent(); -} - -class _ShowNextIntent extends Intent { - const _ShowNextIntent(); -} - -class _LeaveIntent extends Intent { - const _LeaveIntent(); -} - -class _ShowInfoIntent extends Intent { - const _ShowInfoIntent(); -} - -class TvShowLessInfoIntent extends Intent { - const TvShowLessInfoIntent(); -} - -class _TvShowMoreInfoIntent extends Intent { - const _TvShowMoreInfoIntent(); -} - -class _PlayPauseIntent extends Intent { - const _PlayPauseIntent({ - required this.type, - }); - - const _PlayPauseIntent.play() : type = _TvPlayPauseType.play; - - const _PlayPauseIntent.pause() : type = _TvPlayPauseType.pause; - - const _PlayPauseIntent.toggle() : type = _TvPlayPauseType.toggle; - - final _TvPlayPauseType type; -} - -enum _TvPlayPauseType { - play, - pause, - toggle, -} diff --git a/lib/widgets/viewer/entry_viewer_page.dart b/lib/widgets/viewer/entry_viewer_page.dart index 1efca6ae1..527da25df 100644 --- a/lib/widgets/viewer/entry_viewer_page.dart +++ b/lib/widgets/viewer/entry_viewer_page.dart @@ -1,7 +1,7 @@ import 'package:aves/model/entry.dart'; import 'package:aves/model/source/collection_lens.dart'; import 'package:aves/widgets/common/basic/scaffold.dart'; -import 'package:aves/widgets/viewer/controller.dart'; +import 'package:aves/widgets/viewer/controls/controller.dart'; import 'package:aves/widgets/viewer/entry_viewer_stack.dart'; import 'package:aves/widgets/viewer/overlay/bottom.dart'; import 'package:aves/widgets/viewer/providers.dart'; diff --git a/lib/widgets/viewer/entry_viewer_stack.dart b/lib/widgets/viewer/entry_viewer_stack.dart index d52c28ed6..90dce0479 100644 --- a/lib/widgets/viewer/entry_viewer_stack.dart +++ b/lib/widgets/viewer/entry_viewer_stack.dart @@ -18,11 +18,12 @@ import 'package:aves/widgets/aves_app.dart'; import 'package:aves/widgets/collection/collection_page.dart'; import 'package:aves/widgets/common/action_mixins/feedback.dart'; import 'package:aves/widgets/common/basic/insets.dart'; -import 'package:aves/widgets/viewer/controller.dart'; +import 'package:aves/widgets/viewer/action/video_action_delegate.dart'; +import 'package:aves/widgets/viewer/controls/controller.dart'; +import 'package:aves/widgets/viewer/controls/notifications.dart'; import 'package:aves/widgets/viewer/entry_vertical_pager.dart'; import 'package:aves/widgets/viewer/hero.dart'; import 'package:aves/widgets/viewer/multipage/conductor.dart'; -import 'package:aves/widgets/viewer/notifications.dart'; import 'package:aves/widgets/viewer/overlay/bottom.dart'; import 'package:aves/widgets/viewer/overlay/panorama.dart'; import 'package:aves/widgets/viewer/overlay/slideshow_buttons.dart'; @@ -31,7 +32,6 @@ import 'package:aves/widgets/viewer/overlay/video/video.dart'; import 'package:aves/widgets/viewer/page_entry_builder.dart'; import 'package:aves/widgets/viewer/video/conductor.dart'; import 'package:aves/widgets/viewer/video/controller.dart'; -import 'package:aves/widgets/viewer/video_action_delegate.dart'; import 'package:aves/widgets/viewer/visual/conductor.dart'; import 'package:aves/widgets/viewer/visual/controller_mixin.dart'; import 'package:collection/collection.dart'; @@ -786,6 +786,7 @@ class _EntryViewerStackState extends State with EntryViewContr } Future _onOverlayVisibleChanged({bool animate = true}) async { + if (!mounted) return; if (_overlayVisible.value) { await AvesApp.showSystemUI(); AvesApp.setSystemUIStyle(context); diff --git a/lib/widgets/viewer/embedded/embedded_data_opener.dart b/lib/widgets/viewer/info/embedded/embedded_data_opener.dart similarity index 97% rename from lib/widgets/viewer/embedded/embedded_data_opener.dart rename to lib/widgets/viewer/info/embedded/embedded_data_opener.dart index 40e85db37..d9f33d63d 100644 --- a/lib/widgets/viewer/embedded/embedded_data_opener.dart +++ b/lib/widgets/viewer/info/embedded/embedded_data_opener.dart @@ -7,8 +7,8 @@ import 'package:aves/widgets/common/action_mixins/feedback.dart'; import 'package:aves/widgets/common/behaviour/routes.dart'; import 'package:aves/widgets/common/extensions/build_context.dart'; import 'package:aves/widgets/dialogs/aves_dialog.dart'; -import 'package:aves/widgets/viewer/embedded/notifications.dart'; import 'package:aves/widgets/viewer/entry_viewer_page.dart'; +import 'package:aves/widgets/viewer/info/embedded/notifications.dart'; import 'package:flutter/material.dart'; class EmbeddedDataOpener extends StatelessWidget with FeedbackMixin { diff --git a/lib/widgets/viewer/embedded/notifications.dart b/lib/widgets/viewer/info/embedded/notifications.dart similarity index 100% rename from lib/widgets/viewer/embedded/notifications.dart rename to lib/widgets/viewer/info/embedded/notifications.dart diff --git a/lib/widgets/viewer/info/info_page.dart b/lib/widgets/viewer/info/info_page.dart index 9c9541d6c..26c4dfeb7 100644 --- a/lib/widgets/viewer/info/info_page.dart +++ b/lib/widgets/viewer/info/info_page.dart @@ -12,14 +12,14 @@ import 'package:aves/widgets/common/basic/scaffold.dart'; import 'package:aves/widgets/common/basic/tv_edge_focus.dart'; import 'package:aves/widgets/filter_grids/common/action_delegates/chip.dart'; import 'package:aves/widgets/viewer/action/entry_info_action_delegate.dart'; -import 'package:aves/widgets/viewer/embedded/embedded_data_opener.dart'; +import 'package:aves/widgets/viewer/controls/notifications.dart'; import 'package:aves/widgets/viewer/info/basic_section.dart'; +import 'package:aves/widgets/viewer/info/embedded/embedded_data_opener.dart'; import 'package:aves/widgets/viewer/info/info_app_bar.dart'; import 'package:aves/widgets/viewer/info/location_section.dart'; import 'package:aves/widgets/viewer/info/metadata/metadata_dir.dart'; import 'package:aves/widgets/viewer/info/metadata/metadata_section.dart'; import 'package:aves/widgets/viewer/multipage/conductor.dart'; -import 'package:aves/widgets/viewer/notifications.dart'; import 'package:aves/widgets/viewer/page_entry_builder.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; diff --git a/lib/widgets/viewer/info/info_search.dart b/lib/widgets/viewer/info/info_search.dart index 1ed477589..008fa535e 100644 --- a/lib/widgets/viewer/info/info_search.dart +++ b/lib/widgets/viewer/info/info_search.dart @@ -3,7 +3,7 @@ import 'package:aves/theme/icons.dart'; import 'package:aves/widgets/common/extensions/build_context.dart'; import 'package:aves/widgets/common/identity/empty.dart'; import 'package:aves/widgets/common/providers/media_query_data_provider.dart'; -import 'package:aves/widgets/viewer/embedded/embedded_data_opener.dart'; +import 'package:aves/widgets/viewer/info/embedded/embedded_data_opener.dart'; import 'package:aves/widgets/viewer/info/metadata/metadata_dir.dart'; import 'package:aves/widgets/viewer/info/metadata/metadata_dir_tile.dart'; import 'package:collection/collection.dart'; diff --git a/lib/widgets/viewer/info/metadata/metadata_dir_tile.dart b/lib/widgets/viewer/info/metadata/metadata_dir_tile.dart index def7e8670..dc7a8f6f3 100644 --- a/lib/widgets/viewer/info/metadata/metadata_dir_tile.dart +++ b/lib/widgets/viewer/info/metadata/metadata_dir_tile.dart @@ -7,8 +7,8 @@ import 'package:aves/theme/colors.dart'; import 'package:aves/utils/constants.dart'; import 'package:aves/widgets/common/extensions/build_context.dart'; import 'package:aves/widgets/common/identity/aves_expansion_tile.dart'; -import 'package:aves/widgets/viewer/embedded/notifications.dart'; import 'package:aves/widgets/viewer/info/common.dart'; +import 'package:aves/widgets/viewer/info/embedded/notifications.dart'; import 'package:aves/widgets/viewer/info/metadata/geotiff.dart'; import 'package:aves/widgets/viewer/info/metadata/metadata_dir.dart'; import 'package:aves/widgets/viewer/info/metadata/metadata_thumbnail.dart'; diff --git a/lib/widgets/viewer/info/metadata/xmp_ns/google.dart b/lib/widgets/viewer/info/metadata/xmp_ns/google.dart index e33140105..5b0834a13 100644 --- a/lib/widgets/viewer/info/metadata/xmp_ns/google.dart +++ b/lib/widgets/viewer/info/metadata/xmp_ns/google.dart @@ -1,7 +1,7 @@ import 'package:aves/utils/xmp_utils.dart'; import 'package:aves/widgets/common/extensions/build_context.dart'; -import 'package:aves/widgets/viewer/embedded/notifications.dart'; import 'package:aves/widgets/viewer/info/common.dart'; +import 'package:aves/widgets/viewer/info/embedded/notifications.dart'; import 'package:aves/widgets/viewer/info/metadata/xmp_namespaces.dart'; import 'package:collection/collection.dart'; import 'package:tuple/tuple.dart'; diff --git a/lib/widgets/viewer/info/metadata/xmp_ns/xmp.dart b/lib/widgets/viewer/info/metadata/xmp_ns/xmp.dart index 7d497e1ac..78e874750 100644 --- a/lib/widgets/viewer/info/metadata/xmp_ns/xmp.dart +++ b/lib/widgets/viewer/info/metadata/xmp_ns/xmp.dart @@ -1,8 +1,8 @@ import 'package:aves/ref/mime_types.dart'; import 'package:aves/utils/xmp_utils.dart'; import 'package:aves/widgets/common/extensions/build_context.dart'; -import 'package:aves/widgets/viewer/embedded/notifications.dart'; import 'package:aves/widgets/viewer/info/common.dart'; +import 'package:aves/widgets/viewer/info/embedded/notifications.dart'; import 'package:aves/widgets/viewer/info/metadata/xmp_namespaces.dart'; class XmpBasicNamespace extends XmpNamespace { diff --git a/lib/widgets/viewer/overlay/bottom.dart b/lib/widgets/viewer/overlay/bottom.dart index e23aa29a7..2c3f15efb 100644 --- a/lib/widgets/viewer/overlay/bottom.dart +++ b/lib/widgets/viewer/overlay/bottom.dart @@ -6,9 +6,9 @@ import 'package:aves/model/selection.dart'; import 'package:aves/model/settings/settings.dart'; import 'package:aves/model/source/collection_lens.dart'; import 'package:aves/widgets/common/extensions/media_query.dart'; -import 'package:aves/widgets/viewer/entry_vertical_pager.dart'; +import 'package:aves/widgets/viewer/controls/intents.dart'; +import 'package:aves/widgets/viewer/controls/notifications.dart'; import 'package:aves/widgets/viewer/multipage/controller.dart'; -import 'package:aves/widgets/viewer/notifications.dart'; import 'package:aves/widgets/viewer/overlay/multipage.dart'; import 'package:aves/widgets/viewer/overlay/selection_button.dart'; import 'package:aves/widgets/viewer/overlay/thumbnail_preview.dart'; @@ -193,8 +193,14 @@ class _BottomOverlayContentState extends State<_BottomOverlayContent> { ) : FocusableActionDetector( focusNode: _buttonRowFocusScopeNode, - shortcuts: settings.useTvLayout ? const {SingleActivator(LogicalKeyboardKey.arrowUp): TvShowLessInfoIntent()} : null, - actions: {TvShowLessInfoIntent: CallbackAction(onInvoke: (intent) => TvShowLessInfoNotification().dispatch(context))}, + shortcuts: settings.useTvLayout + ? const { + SingleActivator(LogicalKeyboardKey.arrowUp): TvShowLessInfoIntent(), + } + : null, + actions: { + TvShowLessInfoIntent: CallbackAction(onInvoke: (intent) => TvShowLessInfoNotification().dispatch(context)), + }, child: SafeArea( top: false, bottom: false, diff --git a/lib/widgets/viewer/overlay/slideshow_buttons.dart b/lib/widgets/viewer/overlay/slideshow_buttons.dart index ee630d502..cbfee2a3b 100644 --- a/lib/widgets/viewer/overlay/slideshow_buttons.dart +++ b/lib/widgets/viewer/overlay/slideshow_buttons.dart @@ -2,8 +2,8 @@ import 'package:aves/model/actions/slideshow_actions.dart'; import 'package:aves/model/settings/settings.dart'; import 'package:aves/widgets/common/identity/buttons/captioned_button.dart'; import 'package:aves/widgets/common/identity/buttons/overlay_button.dart'; -import 'package:aves/widgets/viewer/entry_vertical_pager.dart'; -import 'package:aves/widgets/viewer/notifications.dart'; +import 'package:aves/widgets/viewer/controls/intents.dart'; +import 'package:aves/widgets/viewer/controls/notifications.dart'; import 'package:aves/widgets/viewer/overlay/viewer_buttons.dart'; import 'package:aves/widgets/viewer/slideshow_page.dart'; import 'package:collection/collection.dart'; @@ -70,8 +70,14 @@ class _SlideshowButtonsState extends State { Widget build(BuildContext context) { return FocusableActionDetector( focusNode: _buttonRowFocusScopeNode, - shortcuts: settings.useTvLayout ? const {SingleActivator(LogicalKeyboardKey.arrowUp): TvShowLessInfoIntent()} : null, - actions: {TvShowLessInfoIntent: CallbackAction(onInvoke: (intent) => TvShowLessInfoNotification().dispatch(context))}, + shortcuts: settings.useTvLayout + ? const { + SingleActivator(LogicalKeyboardKey.arrowUp): TvShowLessInfoIntent(), + } + : null, + actions: { + TvShowLessInfoIntent: CallbackAction(onInvoke: (intent) => TvShowLessInfoNotification().dispatch(context)), + }, child: settings.useTvLayout ? Row( mainAxisAlignment: MainAxisAlignment.center, diff --git a/lib/widgets/viewer/overlay/thumbnail_preview.dart b/lib/widgets/viewer/overlay/thumbnail_preview.dart index 5a0f27bb9..a7fa1119a 100644 --- a/lib/widgets/viewer/overlay/thumbnail_preview.dart +++ b/lib/widgets/viewer/overlay/thumbnail_preview.dart @@ -2,7 +2,7 @@ import 'package:aves/model/entry.dart'; import 'package:aves/theme/durations.dart'; import 'package:aves/utils/debouncer.dart'; import 'package:aves/widgets/common/thumbnail/scroller.dart'; -import 'package:aves/widgets/viewer/notifications.dart'; +import 'package:aves/widgets/viewer/controls/notifications.dart'; import 'package:flutter/material.dart'; class ViewerThumbnailPreview extends StatefulWidget { diff --git a/lib/widgets/viewer/overlay/video/controls.dart b/lib/widgets/viewer/overlay/video/controls.dart index 1a27b0a8d..71db0d998 100644 --- a/lib/widgets/viewer/overlay/video/controls.dart +++ b/lib/widgets/viewer/overlay/video/controls.dart @@ -1,8 +1,8 @@ import 'package:aves/model/actions/entry_actions.dart'; import 'package:aves/model/settings/enums/enums.dart'; import 'package:aves/model/settings/settings.dart'; -import 'package:aves/widgets/common/identity/buttons/overlay_button.dart'; import 'package:aves/widgets/common/action_controls/togglers/play.dart'; +import 'package:aves/widgets/common/identity/buttons/overlay_button.dart'; import 'package:aves/widgets/viewer/video/controller.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; diff --git a/lib/widgets/viewer/overlay/viewer_buttons.dart b/lib/widgets/viewer/overlay/viewer_buttons.dart index 2ad237638..faf3196da 100644 --- a/lib/widgets/viewer/overlay/viewer_buttons.dart +++ b/lib/widgets/viewer/overlay/viewer_buttons.dart @@ -22,7 +22,7 @@ import 'package:aves/widgets/common/extensions/build_context.dart'; import 'package:aves/widgets/common/identity/buttons/captioned_button.dart'; import 'package:aves/widgets/common/identity/buttons/overlay_button.dart'; import 'package:aves/widgets/viewer/action/entry_action_delegate.dart'; -import 'package:aves/widgets/viewer/notifications.dart'; +import 'package:aves/widgets/viewer/controls/notifications.dart'; import 'package:aves/widgets/viewer/video/conductor.dart'; import 'package:aves/widgets/viewer/video/controller.dart'; import 'package:collection/collection.dart'; @@ -87,7 +87,7 @@ class ViewerButtons extends StatelessWidget { } return ViewerButtonRowContent( - actionDelegate: EntryActionDelegate(mainEntry, pageEntry, collection), + actionDelegate: actionDelegate, quickActions: quickActions, topLevelActions: getMenuActions(EntryActions.topLevel), exportActions: getMenuActions(EntryActions.export), diff --git a/lib/widgets/viewer/screen_saver_page.dart b/lib/widgets/viewer/screen_saver_page.dart index bad726db5..cc370fc39 100644 --- a/lib/widgets/viewer/screen_saver_page.dart +++ b/lib/widgets/viewer/screen_saver_page.dart @@ -7,7 +7,7 @@ import 'package:aves/theme/icons.dart'; import 'package:aves/widgets/common/basic/scaffold.dart'; import 'package:aves/widgets/common/extensions/build_context.dart'; import 'package:aves/widgets/common/identity/empty.dart'; -import 'package:aves/widgets/viewer/controller.dart'; +import 'package:aves/widgets/viewer/controls/controller.dart'; import 'package:aves/widgets/viewer/entry_viewer_stack.dart'; import 'package:aves/widgets/viewer/providers.dart'; import 'package:aves_magnifier/aves_magnifier.dart'; diff --git a/lib/widgets/viewer/slideshow_page.dart b/lib/widgets/viewer/slideshow_page.dart index eccf250bf..c4762de49 100644 --- a/lib/widgets/viewer/slideshow_page.dart +++ b/lib/widgets/viewer/slideshow_page.dart @@ -13,7 +13,7 @@ import 'package:aves/widgets/common/basic/scaffold.dart'; import 'package:aves/widgets/common/extensions/build_context.dart'; import 'package:aves/widgets/common/identity/empty.dart'; import 'package:aves/widgets/settings/viewer/slideshow.dart'; -import 'package:aves/widgets/viewer/controller.dart'; +import 'package:aves/widgets/viewer/controls/controller.dart'; import 'package:aves/widgets/viewer/entry_viewer_stack.dart'; import 'package:aves/widgets/viewer/providers.dart'; import 'package:aves_magnifier/aves_magnifier.dart'; diff --git a/lib/widgets/viewer/visual/conductor.dart b/lib/widgets/viewer/visual/conductor.dart index f9372d62f..d350c34ae 100644 --- a/lib/widgets/viewer/visual/conductor.dart +++ b/lib/widgets/viewer/visual/conductor.dart @@ -1,6 +1,6 @@ import 'package:aves/model/entry.dart'; -import 'package:aves_magnifier/aves_magnifier.dart'; import 'package:aves/widgets/viewer/visual/state.dart'; +import 'package:aves_magnifier/aves_magnifier.dart'; import 'package:collection/collection.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/rendering.dart'; diff --git a/lib/widgets/viewer/visual/entry_page_view.dart b/lib/widgets/viewer/visual/entry_page_view.dart index a62f65d13..91af37de0 100644 --- a/lib/widgets/viewer/visual/entry_page_view.dart +++ b/lib/widgets/viewer/visual/entry_page_view.dart @@ -10,9 +10,9 @@ import 'package:aves/services/media/media_session_service.dart'; import 'package:aves/theme/icons.dart'; import 'package:aves/widgets/common/action_mixins/feedback.dart'; import 'package:aves/widgets/common/basic/insets.dart'; -import 'package:aves/widgets/viewer/controller.dart'; +import 'package:aves/widgets/viewer/controls/controller.dart'; +import 'package:aves/widgets/viewer/controls/notifications.dart'; import 'package:aves/widgets/viewer/hero.dart'; -import 'package:aves/widgets/viewer/notifications.dart'; import 'package:aves/widgets/viewer/video/conductor.dart'; import 'package:aves/widgets/viewer/visual/conductor.dart'; import 'package:aves/widgets/viewer/visual/error.dart'; diff --git a/lib/widgets/wallpaper_page.dart b/lib/widgets/wallpaper_page.dart index 81d347d08..5d6ad023a 100644 --- a/lib/widgets/wallpaper_page.dart +++ b/lib/widgets/wallpaper_page.dart @@ -7,17 +7,17 @@ import 'package:aves/theme/durations.dart'; import 'package:aves/widgets/aves_app.dart'; import 'package:aves/widgets/common/basic/insets.dart'; import 'package:aves/widgets/common/basic/scaffold.dart'; -import 'package:aves/widgets/viewer/controller.dart'; +import 'package:aves/widgets/viewer/action/video_action_delegate.dart'; +import 'package:aves/widgets/viewer/controls/controller.dart'; +import 'package:aves/widgets/viewer/controls/notifications.dart'; import 'package:aves/widgets/viewer/entry_horizontal_pager.dart'; import 'package:aves/widgets/viewer/multipage/conductor.dart'; -import 'package:aves/widgets/viewer/notifications.dart'; import 'package:aves/widgets/viewer/overlay/bottom.dart'; import 'package:aves/widgets/viewer/overlay/video/video.dart'; import 'package:aves/widgets/viewer/page_entry_builder.dart'; import 'package:aves/widgets/viewer/providers.dart'; import 'package:aves/widgets/viewer/video/conductor.dart'; import 'package:aves/widgets/viewer/video/controller.dart'; -import 'package:aves/widgets/viewer/video_action_delegate.dart'; import 'package:aves/widgets/viewer/visual/controller_mixin.dart'; import 'package:aves_magnifier/aves_magnifier.dart'; import 'package:flutter/material.dart';