video: custom playback buttons
This commit is contained in:
parent
9e64da8940
commit
e0b3f92b65
12 changed files with 76 additions and 56 deletions
|
@ -272,10 +272,7 @@
|
||||||
|
|
||||||
"settingsVideoEnablePip": "Picture-in-picture",
|
"settingsVideoEnablePip": "Picture-in-picture",
|
||||||
|
|
||||||
"videoControlsPlay": "Play",
|
|
||||||
"videoControlsPlaySeek": "Play & seek backward/forward",
|
|
||||||
"videoControlsPlayOutside": "Open with other player",
|
"videoControlsPlayOutside": "Open with other player",
|
||||||
"videoControlsNone": "None",
|
|
||||||
|
|
||||||
"videoLoopModeNever": "Never",
|
"videoLoopModeNever": "Never",
|
||||||
"videoLoopModeShortOnly": "Short videos only",
|
"videoLoopModeShortOnly": "Short videos only",
|
||||||
|
|
|
@ -133,7 +133,7 @@ class Settings with ChangeNotifier, SettingsAccess, AppSettings, DisplaySettings
|
||||||
viewerGestureSideTapNext = false;
|
viewerGestureSideTapNext = false;
|
||||||
viewerUseCutout = true;
|
viewerUseCutout = true;
|
||||||
videoBackgroundMode = VideoBackgroundMode.disabled;
|
videoBackgroundMode = VideoBackgroundMode.disabled;
|
||||||
videoControls = VideoControls.none;
|
videoControlActions = [];
|
||||||
videoGestureDoubleTapTogglePlay = false;
|
videoGestureDoubleTapTogglePlay = false;
|
||||||
videoGestureSideDoubleTapSeek = false;
|
videoGestureSideDoubleTapSeek = false;
|
||||||
enableBin = false;
|
enableBin = false;
|
||||||
|
@ -459,7 +459,6 @@ class Settings with ChangeNotifier, SettingsAccess, AppSettings, DisplaySettings
|
||||||
case SettingKeys.videoBackgroundModeKey:
|
case SettingKeys.videoBackgroundModeKey:
|
||||||
case SettingKeys.videoLoopModeKey:
|
case SettingKeys.videoLoopModeKey:
|
||||||
case SettingKeys.videoResumptionModeKey:
|
case SettingKeys.videoResumptionModeKey:
|
||||||
case SettingKeys.videoControlsKey:
|
|
||||||
case SettingKeys.subtitleTextAlignmentKey:
|
case SettingKeys.subtitleTextAlignmentKey:
|
||||||
case SettingKeys.subtitleTextPositionKey:
|
case SettingKeys.subtitleTextPositionKey:
|
||||||
case SettingKeys.tagEditorExpandedSectionKey:
|
case SettingKeys.tagEditorExpandedSectionKey:
|
||||||
|
@ -490,6 +489,7 @@ class Settings with ChangeNotifier, SettingsAccess, AppSettings, DisplaySettings
|
||||||
case SettingKeys.collectionBrowsingQuickActionsKey:
|
case SettingKeys.collectionBrowsingQuickActionsKey:
|
||||||
case SettingKeys.collectionSelectionQuickActionsKey:
|
case SettingKeys.collectionSelectionQuickActionsKey:
|
||||||
case SettingKeys.viewerQuickActionsKey:
|
case SettingKeys.viewerQuickActionsKey:
|
||||||
|
case SettingKeys.videoControlActionsKey:
|
||||||
case SettingKeys.screenSaverCollectionFiltersKey:
|
case SettingKeys.screenSaverCollectionFiltersKey:
|
||||||
if (newValue is List) {
|
if (newValue is List) {
|
||||||
store.setStringList(key, newValue.cast<String>());
|
store.setStringList(key, newValue.cast<String>());
|
||||||
|
|
|
@ -47,7 +47,8 @@ extension ExtraEntryActionView on EntryAction {
|
||||||
EntryAction.videoShowNextFrame => l10n.videoActionShowNextFrame,
|
EntryAction.videoShowNextFrame => l10n.videoActionShowNextFrame,
|
||||||
// external
|
// external
|
||||||
EntryAction.edit => l10n.entryActionEdit,
|
EntryAction.edit => l10n.entryActionEdit,
|
||||||
EntryAction.open || EntryAction.openVideo => l10n.entryActionOpen,
|
EntryAction.open => l10n.entryActionOpen,
|
||||||
|
EntryAction.openVideo => l10n.videoControlsPlayOutside,
|
||||||
EntryAction.openMap => l10n.entryActionOpenMap,
|
EntryAction.openMap => l10n.entryActionOpenMap,
|
||||||
EntryAction.setAs => l10n.entryActionSetAs,
|
EntryAction.setAs => l10n.entryActionSetAs,
|
||||||
EntryAction.cast => l10n.entryActionCast,
|
EntryAction.cast => l10n.entryActionCast,
|
||||||
|
|
|
@ -174,18 +174,6 @@ extension ExtraVideoBackgroundModeView on VideoBackgroundMode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension ExtraVideoControlsView on VideoControls {
|
|
||||||
String getName(BuildContext context) {
|
|
||||||
final l10n = context.l10n;
|
|
||||||
return switch (this) {
|
|
||||||
VideoControls.play => l10n.videoControlsPlay,
|
|
||||||
VideoControls.playSeek => l10n.videoControlsPlaySeek,
|
|
||||||
VideoControls.playOutside => l10n.videoControlsPlayOutside,
|
|
||||||
VideoControls.none => l10n.videoControlsNone,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension ExtraVideoLoopModeView on VideoLoopMode {
|
extension ExtraVideoLoopModeView on VideoLoopMode {
|
||||||
String getName(BuildContext context) {
|
String getName(BuildContext context) {
|
||||||
final l10n = context.l10n;
|
final l10n = context.l10n;
|
||||||
|
|
58
lib/widgets/settings/video/control_actions.dart
Normal file
58
lib/widgets/settings/video/control_actions.dart
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
import 'package:aves/model/settings/settings.dart';
|
||||||
|
import 'package:aves/view/view.dart';
|
||||||
|
import 'package:aves/widgets/common/basic/scaffold.dart';
|
||||||
|
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
|
import 'package:aves_model/aves_model.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class VideoControlButtonsPage extends StatefulWidget {
|
||||||
|
static const routeName = '/settings/video/control_buttons';
|
||||||
|
|
||||||
|
const VideoControlButtonsPage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<VideoControlButtonsPage> createState() => _VideoControlButtonsPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _VideoControlButtonsPageState extends State<VideoControlButtonsPage> {
|
||||||
|
late final Set<EntryAction> _selectedActions;
|
||||||
|
|
||||||
|
static const _availableActions = [...EntryActions.videoPlayback, EntryAction.openVideo];
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_selectedActions = settings.videoControlActions.toSet();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return AvesScaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
automaticallyImplyLeading: !settings.useTvLayout,
|
||||||
|
title: Text(context.l10n.settingsViewerOverlayPageTitle),
|
||||||
|
),
|
||||||
|
body: SafeArea(
|
||||||
|
child: PopScope(
|
||||||
|
canPop: true,
|
||||||
|
onPopInvokedWithResult: (didPop, result) => settings.videoControlActions = _availableActions.where(_selectedActions.contains).toList(),
|
||||||
|
child: ListView(
|
||||||
|
children: _availableActions.map((action) {
|
||||||
|
return SwitchListTile(
|
||||||
|
value: _selectedActions.contains(action),
|
||||||
|
onChanged: (v) => setState(() {
|
||||||
|
if (v) {
|
||||||
|
_selectedActions.add(action);
|
||||||
|
} else {
|
||||||
|
_selectedActions.remove(action);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
title: Text(action.getText(context)),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,9 +1,8 @@
|
||||||
import 'package:aves/model/settings/settings.dart';
|
import 'package:aves/model/settings/settings.dart';
|
||||||
import 'package:aves/view/view.dart';
|
|
||||||
import 'package:aves/widgets/common/basic/scaffold.dart';
|
import 'package:aves/widgets/common/basic/scaffold.dart';
|
||||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
import 'package:aves/widgets/settings/common/tiles.dart';
|
import 'package:aves/widgets/settings/common/tiles.dart';
|
||||||
import 'package:aves_model/aves_model.dart';
|
import 'package:aves/widgets/settings/video/control_actions.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class VideoControlsPage extends StatelessWidget {
|
class VideoControlsPage extends StatelessWidget {
|
||||||
|
@ -20,12 +19,10 @@ class VideoControlsPage extends StatelessWidget {
|
||||||
body: SafeArea(
|
body: SafeArea(
|
||||||
child: ListView(
|
child: ListView(
|
||||||
children: [
|
children: [
|
||||||
SettingsSelectionListTile<VideoControls>(
|
SettingsSubPageTile(
|
||||||
values: VideoControls.values,
|
title: context.l10n.settingsVideoButtonsTile,
|
||||||
getName: (context, v) => v.getName(context),
|
routeName: VideoControlButtonsPage.routeName,
|
||||||
selector: (context, s) => s.videoControls,
|
builder: (context) => const VideoControlButtonsPage(),
|
||||||
onSelection: (v) => settings.videoControls = v,
|
|
||||||
tileTitle: context.l10n.settingsVideoButtonsTile,
|
|
||||||
),
|
),
|
||||||
SettingsSwitchListTile(
|
SettingsSwitchListTile(
|
||||||
selector: (context, s) => s.videoGestureDoubleTapTogglePlay,
|
selector: (context, s) => s.videoGestureDoubleTapTogglePlay,
|
||||||
|
|
|
@ -28,11 +28,9 @@ class VideoControlRow extends StatelessWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Selector<Settings, VideoControls>(
|
return Selector<Settings, List<EntryAction>>(
|
||||||
selector: (context, s) => s.videoControls,
|
selector: (context, s) => s.videoControlActions,
|
||||||
builder: (context, videoControls, child) {
|
builder: (context, actions, child) {
|
||||||
final actions = _toActions(videoControls);
|
|
||||||
|
|
||||||
if (actions.isEmpty) {
|
if (actions.isEmpty) {
|
||||||
return const SizedBox();
|
return const SizedBox();
|
||||||
}
|
}
|
||||||
|
@ -65,23 +63,6 @@ class VideoControlRow extends StatelessWidget {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<EntryAction> _toActions(VideoControls videoControls) {
|
|
||||||
switch (videoControls) {
|
|
||||||
case VideoControls.play:
|
|
||||||
return [EntryAction.videoTogglePlay];
|
|
||||||
case VideoControls.playSeek:
|
|
||||||
return [
|
|
||||||
EntryAction.videoReplay10,
|
|
||||||
EntryAction.videoTogglePlay,
|
|
||||||
EntryAction.videoSkip10,
|
|
||||||
];
|
|
||||||
case VideoControls.playOutside:
|
|
||||||
return [EntryAction.openVideo];
|
|
||||||
case VideoControls.none:
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildOverlayButton(
|
Widget _buildOverlayButton(
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
EntryAction action, {
|
EntryAction action, {
|
||||||
|
|
|
@ -117,8 +117,6 @@ class EntryActions {
|
||||||
EntryAction.videoToggleMute,
|
EntryAction.videoToggleMute,
|
||||||
EntryAction.videoSetSpeed,
|
EntryAction.videoSetSpeed,
|
||||||
EntryAction.videoABRepeat,
|
EntryAction.videoABRepeat,
|
||||||
EntryAction.videoShowPreviousFrame,
|
|
||||||
EntryAction.videoShowNextFrame,
|
|
||||||
EntryAction.videoSelectStreams,
|
EntryAction.videoSelectStreams,
|
||||||
EntryAction.videoSettings,
|
EntryAction.videoSettings,
|
||||||
EntryAction.lockViewer,
|
EntryAction.lockViewer,
|
||||||
|
@ -126,7 +124,9 @@ class EntryActions {
|
||||||
|
|
||||||
static const videoPlayback = [
|
static const videoPlayback = [
|
||||||
EntryAction.videoReplay10,
|
EntryAction.videoReplay10,
|
||||||
|
EntryAction.videoShowPreviousFrame,
|
||||||
EntryAction.videoTogglePlay,
|
EntryAction.videoTogglePlay,
|
||||||
|
EntryAction.videoShowNextFrame,
|
||||||
EntryAction.videoSkip10,
|
EntryAction.videoSkip10,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
@ -36,8 +36,6 @@ enum VideoAutoPlayMode { disabled, playMuted, playWithSound }
|
||||||
|
|
||||||
enum VideoBackgroundMode { disabled, pip }
|
enum VideoBackgroundMode { disabled, pip }
|
||||||
|
|
||||||
enum VideoControls { play, playSeek, playOutside, none }
|
|
||||||
|
|
||||||
enum VideoLoopMode { never, shortOnly, always }
|
enum VideoLoopMode { never, shortOnly, always }
|
||||||
|
|
||||||
enum VideoResumptionMode { never, ask, always }
|
enum VideoResumptionMode { never, ask, always }
|
||||||
|
|
|
@ -109,7 +109,7 @@ class SettingKeys {
|
||||||
static const videoAutoPlayModeKey = 'video_auto_play_mode';
|
static const videoAutoPlayModeKey = 'video_auto_play_mode';
|
||||||
static const videoLoopModeKey = 'video_loop';
|
static const videoLoopModeKey = 'video_loop';
|
||||||
static const videoResumptionModeKey = 'video_resumption_mode';
|
static const videoResumptionModeKey = 'video_resumption_mode';
|
||||||
static const videoControlsKey = 'video_controls';
|
static const videoControlActionsKey = 'video_control_actions';
|
||||||
static const videoGestureDoubleTapTogglePlayKey = 'video_gesture_double_tap_toggle_play';
|
static const videoGestureDoubleTapTogglePlayKey = 'video_gesture_double_tap_toggle_play';
|
||||||
static const videoGestureSideDoubleTapSeekKey = 'video_gesture_side_double_tap_skip';
|
static const videoGestureSideDoubleTapSeekKey = 'video_gesture_side_double_tap_skip';
|
||||||
static const videoGestureVerticalDragBrightnessVolumeKey = 'video_gesture_vertical_drag_brightness_volume';
|
static const videoGestureVerticalDragBrightnessVolumeKey = 'video_gesture_vertical_drag_brightness_volume';
|
||||||
|
|
|
@ -11,7 +11,7 @@ class SettingsDefaults {
|
||||||
static const videoLoopMode = VideoLoopMode.shortOnly;
|
static const videoLoopMode = VideoLoopMode.shortOnly;
|
||||||
static const videoResumptionMode = VideoResumptionMode.ask;
|
static const videoResumptionMode = VideoResumptionMode.ask;
|
||||||
static const videoShowRawTimedText = false;
|
static const videoShowRawTimedText = false;
|
||||||
static const videoControls = VideoControls.play;
|
static const videoControlActions = [EntryAction.videoTogglePlay];
|
||||||
static const videoGestureDoubleTapTogglePlay = false;
|
static const videoGestureDoubleTapTogglePlay = false;
|
||||||
static const videoGestureSideDoubleTapSeek = true;
|
static const videoGestureSideDoubleTapSeek = true;
|
||||||
static const videoGestureVerticalDragBrightnessVolume = false;
|
static const videoGestureVerticalDragBrightnessVolume = false;
|
||||||
|
|
|
@ -22,9 +22,9 @@ mixin VideoSettings on SettingsAccess {
|
||||||
|
|
||||||
set videoResumptionMode(VideoResumptionMode newValue) => set(SettingKeys.videoResumptionModeKey, newValue.toString());
|
set videoResumptionMode(VideoResumptionMode newValue) => set(SettingKeys.videoResumptionModeKey, newValue.toString());
|
||||||
|
|
||||||
VideoControls get videoControls => getEnumOrDefault(SettingKeys.videoControlsKey, SettingsDefaults.videoControls, VideoControls.values);
|
List<EntryAction> get videoControlActions => getEnumListOrDefault(SettingKeys.videoControlActionsKey, SettingsDefaults.videoControlActions, EntryAction.values);
|
||||||
|
|
||||||
set videoControls(VideoControls newValue) => set(SettingKeys.videoControlsKey, newValue.toString());
|
set videoControlActions(List<EntryAction> newValue) => set(SettingKeys.videoControlActionsKey, newValue.map((v) => v.toString()).toList());
|
||||||
|
|
||||||
bool get videoGestureDoubleTapTogglePlay => getBool(SettingKeys.videoGestureDoubleTapTogglePlayKey) ?? SettingsDefaults.videoGestureDoubleTapTogglePlay;
|
bool get videoGestureDoubleTapTogglePlay => getBool(SettingKeys.videoGestureDoubleTapTogglePlayKey) ?? SettingsDefaults.videoGestureDoubleTapTogglePlay;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue