Initial commit
This commit is contained in:
@@ -0,0 +1,241 @@
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
import '../core/contracts/player_gestures.dart';
|
||||
import 'shared/settings_persistence.dart';
|
||||
|
||||
class PlayerSettingsState {
|
||||
final String hwdecMode;
|
||||
final double volume;
|
||||
final int seekForwardSeconds;
|
||||
final int seekBackwardSeconds;
|
||||
|
||||
final double keyboardHoldLeftSpeed;
|
||||
final double keyboardHoldRightSpeed;
|
||||
|
||||
final GestureAction mouseLeftClickAction;
|
||||
final GestureAction mouseLeftDoubleClickAction;
|
||||
final GestureAction mouseRightClickAction;
|
||||
final GestureAction mouseRightDoubleClickAction;
|
||||
final bool autoPip;
|
||||
final bool pipShowEpisodeActions;
|
||||
final double? androidBrightness;
|
||||
|
||||
const PlayerSettingsState({
|
||||
this.hwdecMode = 'auto-copy',
|
||||
this.volume = 100.0,
|
||||
this.seekForwardSeconds = 15,
|
||||
this.seekBackwardSeconds = 15,
|
||||
this.keyboardHoldLeftSpeed = 0.5,
|
||||
this.keyboardHoldRightSpeed = 3.0,
|
||||
this.mouseLeftClickAction = GestureAction.playPause,
|
||||
this.mouseLeftDoubleClickAction = GestureAction.fullscreen,
|
||||
this.mouseRightClickAction = GestureAction.toggleControls,
|
||||
this.mouseRightDoubleClickAction = GestureAction.none,
|
||||
this.autoPip = true,
|
||||
this.pipShowEpisodeActions = true,
|
||||
this.androidBrightness,
|
||||
});
|
||||
|
||||
PlayerSettingsState copyWith({
|
||||
String? hwdecMode,
|
||||
double? volume,
|
||||
int? seekForwardSeconds,
|
||||
int? seekBackwardSeconds,
|
||||
double? keyboardHoldLeftSpeed,
|
||||
double? keyboardHoldRightSpeed,
|
||||
GestureAction? mouseLeftClickAction,
|
||||
GestureAction? mouseLeftDoubleClickAction,
|
||||
GestureAction? mouseRightClickAction,
|
||||
GestureAction? mouseRightDoubleClickAction,
|
||||
bool? autoPip,
|
||||
bool? pipShowEpisodeActions,
|
||||
double? androidBrightness,
|
||||
}) => PlayerSettingsState(
|
||||
hwdecMode: hwdecMode ?? this.hwdecMode,
|
||||
volume: volume ?? this.volume,
|
||||
seekForwardSeconds: seekForwardSeconds ?? this.seekForwardSeconds,
|
||||
seekBackwardSeconds: seekBackwardSeconds ?? this.seekBackwardSeconds,
|
||||
keyboardHoldLeftSpeed: keyboardHoldLeftSpeed ?? this.keyboardHoldLeftSpeed,
|
||||
keyboardHoldRightSpeed:
|
||||
keyboardHoldRightSpeed ?? this.keyboardHoldRightSpeed,
|
||||
mouseLeftClickAction: mouseLeftClickAction ?? this.mouseLeftClickAction,
|
||||
mouseLeftDoubleClickAction:
|
||||
mouseLeftDoubleClickAction ?? this.mouseLeftDoubleClickAction,
|
||||
mouseRightClickAction: mouseRightClickAction ?? this.mouseRightClickAction,
|
||||
mouseRightDoubleClickAction:
|
||||
mouseRightDoubleClickAction ?? this.mouseRightDoubleClickAction,
|
||||
autoPip: autoPip ?? this.autoPip,
|
||||
pipShowEpisodeActions: pipShowEpisodeActions ?? this.pipShowEpisodeActions,
|
||||
androidBrightness: androidBrightness ?? this.androidBrightness,
|
||||
);
|
||||
}
|
||||
|
||||
class PlayerSettingsNotifier extends AsyncNotifier<PlayerSettingsState>
|
||||
with SettingsPersistence {
|
||||
static const _keyHwdec = 'smplayer.player_hwdec';
|
||||
static const _legacyKeyEnginePreference = 'smplayer.player_engine_preference';
|
||||
static const _keyVolume = 'smplayer.player_volume';
|
||||
static const _keySeekForward = 'smplayer.player_seek_forward';
|
||||
static const _keySeekBackward = 'smplayer.player_seek_backward';
|
||||
static const _keyKbdHoldLeft = 'smplayer.gesture_kbd_hold_left_speed';
|
||||
static const _keyKbdHoldRight = 'smplayer.gesture_kbd_hold_right_speed';
|
||||
static const _keyMouseLeftClick = 'smplayer.gesture_mouse_left_click';
|
||||
static const _keyMouseLeftDblClick = 'smplayer.gesture_mouse_left_dbl_click';
|
||||
static const _keyMouseRightClick = 'smplayer.gesture_mouse_right_click';
|
||||
static const _keyMouseRightDblClick =
|
||||
'smplayer.gesture_mouse_right_dbl_click';
|
||||
static const _keyAutoPip = 'smplayer.player_auto_pip';
|
||||
static const _keyPipEpisodeActions = 'smplayer.player_pip_episode_actions';
|
||||
static const _keyAndroidBrightness = 'smplayer.player_android_brightness';
|
||||
|
||||
static const _speedAllowed = <double>[
|
||||
0.5,
|
||||
0.75,
|
||||
1.0,
|
||||
1.25,
|
||||
1.5,
|
||||
1.75,
|
||||
2.0,
|
||||
2.5,
|
||||
3.0,
|
||||
4.0,
|
||||
8.0,
|
||||
];
|
||||
|
||||
static double _normalizeSpeed(double v, double fallback) {
|
||||
for (final s in _speedAllowed) {
|
||||
if ((s - v).abs() < 0.001) return s;
|
||||
}
|
||||
return fallback;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<PlayerSettingsState> build() async {
|
||||
final prefs = await getPrefs();
|
||||
if (prefs.containsKey(_keyHwdec)) {
|
||||
await prefs.remove(_keyHwdec);
|
||||
}
|
||||
const hwdec = 'auto-copy';
|
||||
final volume = prefs.getDouble(_keyVolume) ?? 100.0;
|
||||
final seekFwd = prefs.getInt(_keySeekForward) ?? 15;
|
||||
final seekBwd = prefs.getInt(_keySeekBackward) ?? 15;
|
||||
if (prefs.containsKey(_legacyKeyEnginePreference)) {
|
||||
await prefs.remove(_legacyKeyEnginePreference);
|
||||
}
|
||||
final holdLeft = _normalizeSpeed(
|
||||
prefs.getDouble(_keyKbdHoldLeft) ?? 0.5,
|
||||
0.5,
|
||||
);
|
||||
final holdRight = _normalizeSpeed(
|
||||
prefs.getDouble(_keyKbdHoldRight) ?? 3.0,
|
||||
3.0,
|
||||
);
|
||||
final autoPip = prefs.getBool(_keyAutoPip) ?? true;
|
||||
final pipEpisodeActions = prefs.getBool(_keyPipEpisodeActions) ?? true;
|
||||
final androidBrightness = prefs
|
||||
.getDouble(_keyAndroidBrightness)
|
||||
?.clamp(0.0, 1.0);
|
||||
return PlayerSettingsState(
|
||||
hwdecMode: hwdec,
|
||||
volume: volume.clamp(0.0, 200.0),
|
||||
seekForwardSeconds: seekFwd.clamp(5, 120),
|
||||
seekBackwardSeconds: seekBwd.clamp(5, 120),
|
||||
keyboardHoldLeftSpeed: holdLeft,
|
||||
keyboardHoldRightSpeed: holdRight,
|
||||
mouseLeftClickAction: gestureActionFromName(
|
||||
prefs.getString(_keyMouseLeftClick),
|
||||
GestureAction.playPause,
|
||||
),
|
||||
mouseLeftDoubleClickAction: gestureActionFromName(
|
||||
prefs.getString(_keyMouseLeftDblClick),
|
||||
GestureAction.fullscreen,
|
||||
),
|
||||
mouseRightClickAction: gestureActionFromName(
|
||||
prefs.getString(_keyMouseRightClick),
|
||||
GestureAction.toggleControls,
|
||||
),
|
||||
mouseRightDoubleClickAction: gestureActionFromName(
|
||||
prefs.getString(_keyMouseRightDblClick),
|
||||
GestureAction.none,
|
||||
),
|
||||
autoPip: autoPip,
|
||||
pipShowEpisodeActions: pipEpisodeActions,
|
||||
androidBrightness: androidBrightness,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> setVolume(double volume) async {
|
||||
final clamped = volume.clamp(0.0, 200.0);
|
||||
final current = state.value ?? const PlayerSettingsState();
|
||||
state = AsyncValue.data(current.copyWith(volume: clamped));
|
||||
await persistField(_keyVolume, clamped);
|
||||
}
|
||||
|
||||
Future<void> setSeekForwardSeconds(int seconds) async {
|
||||
final clamped = seconds.clamp(5, 120);
|
||||
final current = state.value ?? const PlayerSettingsState();
|
||||
state = AsyncValue.data(current.copyWith(seekForwardSeconds: clamped));
|
||||
await persistField(_keySeekForward, clamped);
|
||||
}
|
||||
|
||||
Future<void> setSeekBackwardSeconds(int seconds) async {
|
||||
final clamped = seconds.clamp(5, 120);
|
||||
final current = state.value ?? const PlayerSettingsState();
|
||||
state = AsyncValue.data(current.copyWith(seekBackwardSeconds: clamped));
|
||||
await persistField(_keySeekBackward, clamped);
|
||||
}
|
||||
|
||||
Future<void> setKeyboardHoldLeftSpeed(double v) async {
|
||||
final normalized = _normalizeSpeed(v, 0.5);
|
||||
final current = state.value ?? const PlayerSettingsState();
|
||||
state = AsyncValue.data(
|
||||
current.copyWith(keyboardHoldLeftSpeed: normalized),
|
||||
);
|
||||
await persistField(_keyKbdHoldLeft, normalized);
|
||||
}
|
||||
|
||||
Future<void> setKeyboardHoldRightSpeed(double v) async {
|
||||
final normalized = _normalizeSpeed(v, 3.0);
|
||||
final current = state.value ?? const PlayerSettingsState();
|
||||
state = AsyncValue.data(
|
||||
current.copyWith(keyboardHoldRightSpeed: normalized),
|
||||
);
|
||||
await persistField(_keyKbdHoldRight, normalized);
|
||||
}
|
||||
|
||||
Future<void> setMouseLeftClickAction(GestureAction a) async {
|
||||
final current = state.value ?? const PlayerSettingsState();
|
||||
state = AsyncValue.data(current.copyWith(mouseLeftClickAction: a));
|
||||
await persistField(_keyMouseLeftClick, a.name);
|
||||
}
|
||||
|
||||
Future<void> setMouseLeftDoubleClickAction(GestureAction a) async {
|
||||
final current = state.value ?? const PlayerSettingsState();
|
||||
state = AsyncValue.data(current.copyWith(mouseLeftDoubleClickAction: a));
|
||||
await persistField(_keyMouseLeftDblClick, a.name);
|
||||
}
|
||||
|
||||
Future<void> setMouseRightClickAction(GestureAction a) async {
|
||||
final current = state.value ?? const PlayerSettingsState();
|
||||
state = AsyncValue.data(current.copyWith(mouseRightClickAction: a));
|
||||
await persistField(_keyMouseRightClick, a.name);
|
||||
}
|
||||
|
||||
Future<void> setMouseRightDoubleClickAction(GestureAction a) async {
|
||||
final current = state.value ?? const PlayerSettingsState();
|
||||
state = AsyncValue.data(current.copyWith(mouseRightDoubleClickAction: a));
|
||||
await persistField(_keyMouseRightDblClick, a.name);
|
||||
}
|
||||
|
||||
Future<void> setAndroidBrightness(double brightness) async {
|
||||
final clamped = brightness.clamp(0.0, 1.0);
|
||||
final current = state.value ?? const PlayerSettingsState();
|
||||
state = AsyncValue.data(current.copyWith(androidBrightness: clamped));
|
||||
await persistField(_keyAndroidBrightness, clamped);
|
||||
}
|
||||
}
|
||||
|
||||
final playerSettingsProvider =
|
||||
AsyncNotifierProvider<PlayerSettingsNotifier, PlayerSettingsState>(
|
||||
PlayerSettingsNotifier.new,
|
||||
);
|
||||
Reference in New Issue
Block a user