video: custom playback buttons

This commit is contained in:
Thibault Deckers 2024-10-30 11:40:07 +01:00
parent 9e64da8940
commit e0b3f92b65
12 changed files with 76 additions and 56 deletions

View file

@ -272,10 +272,7 @@
"settingsVideoEnablePip": "Picture-in-picture",
"videoControlsPlay": "Play",
"videoControlsPlaySeek": "Play & seek backward/forward",
"videoControlsPlayOutside": "Open with other player",
"videoControlsNone": "None",
"videoLoopModeNever": "Never",
"videoLoopModeShortOnly": "Short videos only",

View file

@ -133,7 +133,7 @@ class Settings with ChangeNotifier, SettingsAccess, AppSettings, DisplaySettings
viewerGestureSideTapNext = false;
viewerUseCutout = true;
videoBackgroundMode = VideoBackgroundMode.disabled;
videoControls = VideoControls.none;
videoControlActions = [];
videoGestureDoubleTapTogglePlay = false;
videoGestureSideDoubleTapSeek = false;
enableBin = false;
@ -459,7 +459,6 @@ class Settings with ChangeNotifier, SettingsAccess, AppSettings, DisplaySettings
case SettingKeys.videoBackgroundModeKey:
case SettingKeys.videoLoopModeKey:
case SettingKeys.videoResumptionModeKey:
case SettingKeys.videoControlsKey:
case SettingKeys.subtitleTextAlignmentKey:
case SettingKeys.subtitleTextPositionKey:
case SettingKeys.tagEditorExpandedSectionKey:
@ -490,6 +489,7 @@ class Settings with ChangeNotifier, SettingsAccess, AppSettings, DisplaySettings
case SettingKeys.collectionBrowsingQuickActionsKey:
case SettingKeys.collectionSelectionQuickActionsKey:
case SettingKeys.viewerQuickActionsKey:
case SettingKeys.videoControlActionsKey:
case SettingKeys.screenSaverCollectionFiltersKey:
if (newValue is List) {
store.setStringList(key, newValue.cast<String>());

View file

@ -47,7 +47,8 @@ extension ExtraEntryActionView on EntryAction {
EntryAction.videoShowNextFrame => l10n.videoActionShowNextFrame,
// external
EntryAction.edit => l10n.entryActionEdit,
EntryAction.open || EntryAction.openVideo => l10n.entryActionOpen,
EntryAction.open => l10n.entryActionOpen,
EntryAction.openVideo => l10n.videoControlsPlayOutside,
EntryAction.openMap => l10n.entryActionOpenMap,
EntryAction.setAs => l10n.entryActionSetAs,
EntryAction.cast => l10n.entryActionCast,

View file

@ -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 {
String getName(BuildContext context) {
final l10n = context.l10n;

View 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(),
),
),
),
);
}
}

View file

@ -1,9 +1,8 @@
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/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';
class VideoControlsPage extends StatelessWidget {
@ -20,12 +19,10 @@ class VideoControlsPage extends StatelessWidget {
body: SafeArea(
child: ListView(
children: [
SettingsSelectionListTile<VideoControls>(
values: VideoControls.values,
getName: (context, v) => v.getName(context),
selector: (context, s) => s.videoControls,
onSelection: (v) => settings.videoControls = v,
tileTitle: context.l10n.settingsVideoButtonsTile,
SettingsSubPageTile(
title: context.l10n.settingsVideoButtonsTile,
routeName: VideoControlButtonsPage.routeName,
builder: (context) => const VideoControlButtonsPage(),
),
SettingsSwitchListTile(
selector: (context, s) => s.videoGestureDoubleTapTogglePlay,

View file

@ -28,11 +28,9 @@ class VideoControlRow extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Selector<Settings, VideoControls>(
selector: (context, s) => s.videoControls,
builder: (context, videoControls, child) {
final actions = _toActions(videoControls);
return Selector<Settings, List<EntryAction>>(
selector: (context, s) => s.videoControlActions,
builder: (context, actions, child) {
if (actions.isEmpty) {
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(
BuildContext context,
EntryAction action, {

View file

@ -117,8 +117,6 @@ class EntryActions {
EntryAction.videoToggleMute,
EntryAction.videoSetSpeed,
EntryAction.videoABRepeat,
EntryAction.videoShowPreviousFrame,
EntryAction.videoShowNextFrame,
EntryAction.videoSelectStreams,
EntryAction.videoSettings,
EntryAction.lockViewer,
@ -126,7 +124,9 @@ class EntryActions {
static const videoPlayback = [
EntryAction.videoReplay10,
EntryAction.videoShowPreviousFrame,
EntryAction.videoTogglePlay,
EntryAction.videoShowNextFrame,
EntryAction.videoSkip10,
];

View file

@ -36,8 +36,6 @@ enum VideoAutoPlayMode { disabled, playMuted, playWithSound }
enum VideoBackgroundMode { disabled, pip }
enum VideoControls { play, playSeek, playOutside, none }
enum VideoLoopMode { never, shortOnly, always }
enum VideoResumptionMode { never, ask, always }

View file

@ -109,7 +109,7 @@ class SettingKeys {
static const videoAutoPlayModeKey = 'video_auto_play_mode';
static const videoLoopModeKey = 'video_loop';
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 videoGestureSideDoubleTapSeekKey = 'video_gesture_side_double_tap_skip';
static const videoGestureVerticalDragBrightnessVolumeKey = 'video_gesture_vertical_drag_brightness_volume';

View file

@ -11,7 +11,7 @@ class SettingsDefaults {
static const videoLoopMode = VideoLoopMode.shortOnly;
static const videoResumptionMode = VideoResumptionMode.ask;
static const videoShowRawTimedText = false;
static const videoControls = VideoControls.play;
static const videoControlActions = [EntryAction.videoTogglePlay];
static const videoGestureDoubleTapTogglePlay = false;
static const videoGestureSideDoubleTapSeek = true;
static const videoGestureVerticalDragBrightnessVolume = false;

View file

@ -22,9 +22,9 @@ mixin VideoSettings on SettingsAccess {
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;