@@ -47,7 +47,6 @@ class VideoPlayerScreen extends StatefulWidget {
|
||||
final PlexMetadata metadata;
|
||||
final AudioTrack? preferredAudioTrack;
|
||||
final SubtitleTrack? preferredSubtitleTrack;
|
||||
final double? preferredPlaybackRate;
|
||||
final int selectedMediaIndex;
|
||||
final bool isOffline;
|
||||
|
||||
@@ -56,7 +55,6 @@ class VideoPlayerScreen extends StatefulWidget {
|
||||
required this.metadata,
|
||||
this.preferredAudioTrack,
|
||||
this.preferredSubtitleTrack,
|
||||
this.preferredPlaybackRate,
|
||||
this.selectedMediaIndex = 0,
|
||||
this.isOffline = false,
|
||||
});
|
||||
@@ -1216,6 +1214,7 @@ class VideoPlayerScreenState extends State<VideoPlayerScreen> with WidgetsBindin
|
||||
if (!mounted || player == null) return;
|
||||
|
||||
final profileSettings = context.read<UserProfileProvider>().profileSettings;
|
||||
final settingsService = await SettingsService.getInstance();
|
||||
final trackService = TrackSelectionService(
|
||||
player: player!,
|
||||
profileSettings: profileSettings,
|
||||
@@ -1226,7 +1225,7 @@ class VideoPlayerScreenState extends State<VideoPlayerScreen> with WidgetsBindin
|
||||
await trackService.selectAndApplyTracks(
|
||||
preferredAudioTrack: widget.preferredAudioTrack,
|
||||
preferredSubtitleTrack: widget.preferredSubtitleTrack,
|
||||
preferredPlaybackRate: widget.preferredPlaybackRate,
|
||||
defaultPlaybackSpeed: settingsService.getDefaultPlaybackSpeed(),
|
||||
onAudioTrackChanged: _onAudioTrackChanged,
|
||||
onSubtitleTrackChanged: _onSubtitleTrackChanged,
|
||||
);
|
||||
@@ -1462,7 +1461,6 @@ class VideoPlayerScreenState extends State<VideoPlayerScreen> with WidgetsBindin
|
||||
|
||||
final currentAudioTrack = currentPlayer.state.track.audio;
|
||||
final currentSubtitleTrack = currentPlayer.state.track.subtitle;
|
||||
final currentRate = currentPlayer.state.rate;
|
||||
|
||||
// Pause and stop current playback
|
||||
currentPlayer.pause();
|
||||
@@ -1479,7 +1477,6 @@ class VideoPlayerScreenState extends State<VideoPlayerScreen> with WidgetsBindin
|
||||
metadata: episodeMetadata,
|
||||
preferredAudioTrack: currentAudioTrack,
|
||||
preferredSubtitleTrack: currentSubtitleTrack,
|
||||
preferredPlaybackRate: currentRate,
|
||||
usePushReplacement: true,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -97,7 +97,6 @@ class EpisodeNavigationService {
|
||||
metadata: episode,
|
||||
preferredAudioTrack: currentAudioTrack,
|
||||
preferredSubtitleTrack: currentSubtitleTrack,
|
||||
preferredPlaybackRate: currentPlaybackRate,
|
||||
usePushReplacement: usePushReplacement,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -305,15 +305,18 @@ class KeyboardShortcutsService {
|
||||
onPreviousChapter?.call();
|
||||
break;
|
||||
case 'speed_increase':
|
||||
final newRate = (player.state.rate + 0.1).clamp(0.1, 3.0);
|
||||
player.setRate(newRate);
|
||||
final newRateUp = (player.state.rate + 0.1).clamp(0.1, 3.0);
|
||||
player.setRate(newRateUp);
|
||||
_settingsService.setDefaultPlaybackSpeed(newRateUp);
|
||||
break;
|
||||
case 'speed_decrease':
|
||||
final newRate = (player.state.rate - 0.1).clamp(0.1, 3.0);
|
||||
player.setRate(newRate);
|
||||
final newRateDown = (player.state.rate - 0.1).clamp(0.1, 3.0);
|
||||
player.setRate(newRateDown);
|
||||
_settingsService.setDefaultPlaybackSpeed(newRateDown);
|
||||
break;
|
||||
case 'speed_reset':
|
||||
player.setRate(1.0);
|
||||
_settingsService.setDefaultPlaybackSpeed(1.0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,6 +61,7 @@ class SettingsService extends BaseSharedPreferencesService {
|
||||
static const String _keyMaxVolume = 'max_volume';
|
||||
static const String _keyEnableDiscordRPC = 'enable_discord_rpc';
|
||||
static const String _keyMatchContentFrameRate = 'match_content_frame_rate';
|
||||
static const String _keyDefaultPlaybackSpeed = 'default_playback_speed';
|
||||
|
||||
SettingsService._();
|
||||
|
||||
@@ -947,6 +948,15 @@ class SettingsService extends BaseSharedPreferencesService {
|
||||
return prefs.getBool(_keyMatchContentFrameRate) ?? false; // Default disabled
|
||||
}
|
||||
|
||||
// Default Playback Speed (0.5 to 3.0)
|
||||
Future<void> setDefaultPlaybackSpeed(double speed) async {
|
||||
await prefs.setDouble(_keyDefaultPlaybackSpeed, speed.clamp(0.5, 3.0));
|
||||
}
|
||||
|
||||
double getDefaultPlaybackSpeed() {
|
||||
return prefs.getDouble(_keyDefaultPlaybackSpeed) ?? 1.0; // Default: normal speed
|
||||
}
|
||||
|
||||
// Reset all settings to defaults
|
||||
Future<void> resetAllSettings() async {
|
||||
await Future.wait([
|
||||
@@ -989,6 +999,7 @@ class SettingsService extends BaseSharedPreferencesService {
|
||||
prefs.remove(_keyMpvConfigPresets),
|
||||
prefs.remove(_keyEnableDiscordRPC),
|
||||
prefs.remove(_keyMatchContentFrameRate),
|
||||
prefs.remove(_keyDefaultPlaybackSpeed),
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
@@ -446,7 +446,7 @@ class TrackSelectionService {
|
||||
Future<void> selectAndApplyTracks({
|
||||
AudioTrack? preferredAudioTrack,
|
||||
SubtitleTrack? preferredSubtitleTrack,
|
||||
double? preferredPlaybackRate,
|
||||
double? defaultPlaybackSpeed,
|
||||
Function(AudioTrack)? onAudioTrackChanged,
|
||||
Function(SubtitleTrack)? onSubtitleTrackChanged,
|
||||
}) async {
|
||||
@@ -491,9 +491,9 @@ class TrackSelectionService {
|
||||
onSubtitleTrackChanged(selectedSubtitleTrack);
|
||||
}
|
||||
|
||||
// Set playback rate if preferred rate was provided
|
||||
if (preferredPlaybackRate != null) {
|
||||
player.setRate(preferredPlaybackRate);
|
||||
// Apply default playback speed from settings
|
||||
if (defaultPlaybackSpeed != null && defaultPlaybackSpeed != 1.0) {
|
||||
player.setRate(defaultPlaybackSpeed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@ const String kVideoPlayerRouteName = '/video_player';
|
||||
/// - [metadata]: The Plex metadata for the content to play
|
||||
/// - [preferredAudioTrack]: Optional audio track to select on playback start
|
||||
/// - [preferredSubtitleTrack]: Optional subtitle track to select on playback start
|
||||
/// - [preferredPlaybackRate]: Optional playback speed to set on playback start
|
||||
/// - [selectedMediaIndex]: Optional media version index to use; if not provided,
|
||||
/// loads the saved preference for the series/movie. Defaults to 0 if no preference exists.
|
||||
/// - [usePushReplacement]: If true, replaces current route instead of pushing;
|
||||
@@ -33,7 +32,6 @@ Future<bool?> navigateToVideoPlayer(
|
||||
required PlexMetadata metadata,
|
||||
AudioTrack? preferredAudioTrack,
|
||||
SubtitleTrack? preferredSubtitleTrack,
|
||||
double? preferredPlaybackRate,
|
||||
int? selectedMediaIndex,
|
||||
bool usePushReplacement = false,
|
||||
bool isOffline = false,
|
||||
@@ -72,7 +70,6 @@ Future<bool?> navigateToVideoPlayer(
|
||||
metadata: metadata,
|
||||
preferredAudioTrack: preferredAudioTrack,
|
||||
preferredSubtitleTrack: preferredSubtitleTrack,
|
||||
preferredPlaybackRate: preferredPlaybackRate,
|
||||
selectedMediaIndex: mediaIndex,
|
||||
isOffline: isOffline,
|
||||
),
|
||||
@@ -108,7 +105,6 @@ Future<bool?> navigateToVideoPlayerWithRefresh(
|
||||
VoidCallback? onRefresh,
|
||||
AudioTrack? preferredAudioTrack,
|
||||
SubtitleTrack? preferredSubtitleTrack,
|
||||
double? preferredPlaybackRate,
|
||||
int? selectedMediaIndex,
|
||||
bool usePushReplacement = false,
|
||||
}) async {
|
||||
@@ -118,7 +114,6 @@ Future<bool?> navigateToVideoPlayerWithRefresh(
|
||||
isOffline: isOffline,
|
||||
preferredAudioTrack: preferredAudioTrack,
|
||||
preferredSubtitleTrack: preferredSubtitleTrack,
|
||||
preferredPlaybackRate: preferredPlaybackRate,
|
||||
selectedMediaIndex: selectedMediaIndex,
|
||||
usePushReplacement: usePushReplacement,
|
||||
);
|
||||
|
||||
@@ -338,9 +338,14 @@ class _VideoSettingsSheetState extends State<VideoSettingsSheet> {
|
||||
return ListTile(
|
||||
title: Text(label, style: TextStyle(color: isSelected ? Colors.blue : Colors.white)),
|
||||
trailing: isSelected ? const AppIcon(Symbols.check_rounded, fill: 1, color: Colors.blue) : null,
|
||||
onTap: () {
|
||||
onTap: () async {
|
||||
widget.player.setRate(speed);
|
||||
Navigator.pop(context); // Close sheet after selection
|
||||
// Save as default playback speed
|
||||
final settings = await SettingsService.getInstance();
|
||||
await settings.setDefaultPlaybackSpeed(speed);
|
||||
if (context.mounted) {
|
||||
Navigator.pop(context); // Close sheet after selection
|
||||
}
|
||||
},
|
||||
);
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user