diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 20b2fe23e..8fbfd2bc9 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -107,6 +107,8 @@ "@videoActionSelectStreams": {}, "videoActionSetSpeed": "Playback speed", "@videoActionSetSpeed": {}, + "videoActionSettings": "Settings", + "@videoActionSettings": {}, "filterFavouriteLabel": "Favourite", "@filterFavouriteLabel": {}, @@ -582,6 +584,8 @@ "settingsViewerQuickActionEmpty": "No buttons", "@settingsViewerQuickActionEmpty": {}, + "settingsVideoPageTitle": "Video Settings", + "@settingsVideoPageTitle": {}, "settingsSectionVideo": "Video", "@settingsSectionVideo": {}, "settingsVideoShowVideos": "Show videos", diff --git a/lib/l10n/app_ko.arb b/lib/l10n/app_ko.arb index d4c55aa85..f80a4c13a 100644 --- a/lib/l10n/app_ko.arb +++ b/lib/l10n/app_ko.arb @@ -54,6 +54,7 @@ "videoActionSkip10": "10초 앞으로 탐색", "videoActionSelectStreams": "트랙 선택", "videoActionSetSpeed": "재생 배속", + "videoActionSettings": "설정", "filterFavouriteLabel": "즐겨찾기", "filterLocationEmptyLabel": "장소 없음", @@ -274,6 +275,7 @@ "settingsViewerQuickActionEditorAvailableButtons": "추가 가능한 버튼", "settingsViewerQuickActionEmpty": "버튼이 없습니다", + "settingsVideoPageTitle": "동영상 설정", "settingsSectionVideo": "동영상", "settingsVideoShowVideos": "미디어에 동영상 표시", "settingsVideoEnableHardwareAcceleration": "하드웨어 가속", diff --git a/lib/model/actions/video_actions.dart b/lib/model/actions/video_actions.dart index 96b6bce53..d4de71750 100644 --- a/lib/model/actions/video_actions.dart +++ b/lib/model/actions/video_actions.dart @@ -8,6 +8,7 @@ enum VideoAction { skip10, selectStreams, setSpeed, + settings, togglePlay, // TODO TLAD [video] toggle mute } @@ -20,6 +21,7 @@ class VideoActions { VideoAction.selectStreams, VideoAction.replay10, VideoAction.skip10, + VideoAction.settings, ]; } @@ -36,6 +38,8 @@ extension ExtraVideoAction on VideoAction { return context.l10n.videoActionSelectStreams; case VideoAction.setSpeed: return context.l10n.videoActionSetSpeed; + case VideoAction.settings: + return context.l10n.videoActionSettings; case VideoAction.togglePlay: // different data depending on toggle state return context.l10n.videoActionPlay; @@ -54,6 +58,8 @@ extension ExtraVideoAction on VideoAction { return AIcons.streams; case VideoAction.setSpeed: return AIcons.speed; + case VideoAction.settings: + return AIcons.videoSettings; case VideoAction.togglePlay: // different data depending on toggle state return AIcons.play; diff --git a/lib/theme/icons.dart b/lib/theme/icons.dart index 21f96e78b..b914ce5f5 100644 --- a/lib/theme/icons.dart +++ b/lib/theme/icons.dart @@ -68,6 +68,7 @@ class AIcons { static const IconData streamVideo = Icons.movie_outlined; static const IconData streamAudio = Icons.audiotrack_outlined; static const IconData streamText = Icons.closed_caption_outlined; + static const IconData videoSettings = Icons.video_settings_outlined; static const IconData zoomIn = Icons.add_outlined; static const IconData zoomOut = Icons.remove_outlined; static const IconData collapse = Icons.expand_less_outlined; diff --git a/lib/widgets/settings/video/video.dart b/lib/widgets/settings/video/video.dart index e33e3cd35..eb81d51a8 100644 --- a/lib/widgets/settings/video/video.dart +++ b/lib/widgets/settings/video/video.dart @@ -7,6 +7,7 @@ import 'package:aves/theme/icons.dart'; import 'package:aves/utils/color_utils.dart'; import 'package:aves/widgets/common/extensions/build_context.dart'; import 'package:aves/widgets/common/identity/aves_expansion_tile.dart'; +import 'package:aves/widgets/common/providers/media_query_data_provider.dart'; import 'package:aves/widgets/dialogs/aves_selection_dialog.dart'; import 'package:aves/widgets/settings/common/tile_leading.dart'; import 'package:aves/widgets/settings/video/subtitle_theme.dart'; @@ -15,11 +16,13 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; class VideoSection extends StatelessWidget { - final ValueNotifier expandedNotifier; + final ValueNotifier? expandedNotifier; + final bool standalonePage; const VideoSection({ Key? key, - required this.expandedNotifier, + this.expandedNotifier, + this.standalonePage = false, }) : super(key: key); @override @@ -29,50 +32,88 @@ class VideoSection extends StatelessWidget { final currentEnableVideoAutoPlay = context.select((s) => s.enableVideoAutoPlay); final currentVideoLoopMode = context.select((s) => s.videoLoopMode); - return AvesExpansionTile( - leading: SettingsTileLeading( - icon: AIcons.video, - color: stringToColor('Video'), - ), - title: context.l10n.settingsSectionVideo, - expandedNotifier: expandedNotifier, - showHighlight: false, - children: [ + final children = [ + if (!standalonePage) SwitchListTile( value: currentShowVideos, onChanged: (v) => context.read().changeFilterVisibility(MimeFilter.video, v), title: Text(context.l10n.settingsVideoShowVideos), ), - VideoActionsTile(), - SwitchListTile( - value: currentEnableVideoHardwareAcceleration, - onChanged: (v) => settings.enableVideoHardwareAcceleration = v, - title: Text(context.l10n.settingsVideoEnableHardwareAcceleration), + VideoActionsTile(), + SwitchListTile( + value: currentEnableVideoHardwareAcceleration, + onChanged: (v) => settings.enableVideoHardwareAcceleration = v, + title: Text(context.l10n.settingsVideoEnableHardwareAcceleration), + ), + SwitchListTile( + value: currentEnableVideoAutoPlay, + onChanged: (v) => settings.enableVideoAutoPlay = v, + title: Text(context.l10n.settingsVideoEnableAutoPlay), + ), + ListTile( + title: Text(context.l10n.settingsVideoLoopModeTile), + subtitle: Text(currentVideoLoopMode.getName(context)), + onTap: () async { + final value = await showDialog( + context: context, + builder: (context) => AvesSelectionDialog( + initialValue: currentVideoLoopMode, + options: Map.fromEntries(VideoLoopMode.values.map((v) => MapEntry(v, v.getName(context)))), + title: context.l10n.settingsVideoLoopModeTitle, + ), + ); + if (value != null) { + settings.videoLoopMode = value; + } + }, + ), + SubtitleThemeTile(), + ]; + + return standalonePage + ? ListView( + children: children, + ) + : AvesExpansionTile( + leading: SettingsTileLeading( + icon: AIcons.video, + color: stringToColor('Video'), + ), + title: context.l10n.settingsSectionVideo, + expandedNotifier: expandedNotifier, + showHighlight: false, + children: children, + ); + } +} + +class VideoSettingsPage extends StatelessWidget { + static const routeName = '/settings/video'; + + const VideoSettingsPage({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + return MediaQueryDataProvider( + child: Scaffold( + appBar: AppBar( + title: Text(context.l10n.settingsVideoPageTitle), ), - SwitchListTile( - value: currentEnableVideoAutoPlay, - onChanged: (v) => settings.enableVideoAutoPlay = v, - title: Text(context.l10n.settingsVideoEnableAutoPlay), + body: Theme( + data: theme.copyWith( + textTheme: theme.textTheme.copyWith( + // dense style font for tile subtitles, without modifying title font + bodyText2: const TextStyle(fontSize: 12), + ), + ), + child: const SafeArea( + child: VideoSection( + standalonePage: true, + ), + ), ), - ListTile( - title: Text(context.l10n.settingsVideoLoopModeTile), - subtitle: Text(currentVideoLoopMode.getName(context)), - onTap: () async { - final value = await showDialog( - context: context, - builder: (context) => AvesSelectionDialog( - initialValue: currentVideoLoopMode, - options: Map.fromEntries(VideoLoopMode.values.map((v) => MapEntry(v, v.getName(context)))), - title: context.l10n.settingsVideoLoopModeTitle, - ), - ); - if (value != null) { - settings.videoLoopMode = value; - } - }, - ), - SubtitleThemeTile(), - ], + ), ); } } diff --git a/lib/widgets/viewer/overlay/bottom/video.dart b/lib/widgets/viewer/overlay/bottom/video.dart index 2b878f7da..6478e2e11 100644 --- a/lib/widgets/viewer/overlay/bottom/video.dart +++ b/lib/widgets/viewer/overlay/bottom/video.dart @@ -269,6 +269,7 @@ class _ButtonRow extends StatelessWidget { break; case VideoAction.replay10: case VideoAction.skip10: + case VideoAction.settings: child = IconButton( icon: Icon(action.getIcon()), onPressed: onPressed, @@ -299,6 +300,7 @@ class _ButtonRow extends StatelessWidget { break; case VideoAction.replay10: case VideoAction.skip10: + case VideoAction.settings: case VideoAction.togglePlay: enabled = true; break; @@ -317,6 +319,7 @@ class _ButtonRow extends StatelessWidget { case VideoAction.skip10: case VideoAction.selectStreams: case VideoAction.setSpeed: + case VideoAction.settings: child = MenuRow(text: action.getText(context), icon: action.getIcon()); break; } diff --git a/lib/widgets/viewer/video_action_delegate.dart b/lib/widgets/viewer/video_action_delegate.dart index 6828200ed..b892cf1d9 100644 --- a/lib/widgets/viewer/video_action_delegate.dart +++ b/lib/widgets/viewer/video_action_delegate.dart @@ -14,6 +14,7 @@ import 'package:aves/widgets/common/action_mixins/size_aware.dart'; import 'package:aves/widgets/common/extensions/build_context.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.dart'; import 'package:aves/widgets/viewer/video/controller.dart'; import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; @@ -44,6 +45,9 @@ class VideoActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAwareMix case VideoAction.setSpeed: _showSpeedDialog(context, controller); break; + case VideoAction.settings: + _showSettings(context); + break; case VideoAction.togglePlay: _togglePlayPause(context, controller); break; @@ -155,6 +159,16 @@ class VideoActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAwareMix controller.speed = newSpeed; } + void _showSettings(BuildContext context) { + Navigator.push( + context, + MaterialPageRoute( + settings: const RouteSettings(name: VideoSettingsPage.routeName), + builder: (context) => const VideoSettingsPage(), + ), + ); + } + Future _togglePlayPause(BuildContext context, AvesVideoController controller) async { if (controller.isPlaying) { await controller.pause();