diff --git a/psst-gui/src/controller/playback.rs b/psst-gui/src/controller/playback.rs index d6268a23..8577bf14 100644 --- a/psst-gui/src/controller/playback.rs +++ b/psst-gui/src/controller/playback.rs @@ -274,6 +274,22 @@ impl PlaybackController { self.send(PlayerEvent::Command(PlayerCommand::Seek { position })); } + fn seek_relative(&mut self, data: &AppState, forward: bool) { + if let Some(now_playing) = &data.playback.now_playing { + let seek_duration = Duration::from_secs(data.config.step_duration as u64); + + // Calculate new position, ensuring it does not exceed duration for forward seeks. + let seek_position = if forward { + now_playing.progress + seek_duration + } else { + now_playing.progress.saturating_sub(seek_duration) + } + .min(now_playing.item.duration()); // Safeguard to not exceed the track duration. + + self.seek(seek_position); + } + } + fn set_volume(&mut self, volume: f64) { self.send(PlayerEvent::Command(PlayerCommand::SetVolume { volume })); } @@ -414,22 +430,16 @@ where Event::KeyDown(key) if key.code == Code::ArrowRight => { if key.mods.shift() { self.next(); - } else if let Some(now_playing) = &data.playback.now_playing { - let current_position = now_playing.progress; - let max_position = now_playing.item.duration(); - let seek_position = - (current_position + Duration::from_secs(10)).min(max_position); - self.seek(seek_position); + } else { + self.seek_relative(data, true); } ctx.set_handled(); } Event::KeyDown(key) if key.code == Code::ArrowLeft => { if key.mods.shift() { self.previous(); - } else if let Some(now_playing) = &data.playback.now_playing { - let current_position = now_playing.progress; - let seek_position = current_position.saturating_sub(Duration::from_secs(10)); - self.seek(seek_position); + } else { + self.seek_relative(data, false); } ctx.set_handled(); } diff --git a/psst-gui/src/data/config.rs b/psst-gui/src/data/config.rs index 093cbf32..96adbb67 100644 --- a/psst-gui/src/data/config.rs +++ b/psst-gui/src/data/config.rs @@ -94,6 +94,7 @@ pub struct Config { pub sort_order: SortOrder, pub sort_criteria: SortCriteria, pub paginated_limit: usize, + pub step_duration: usize, } impl Default for Config { @@ -111,6 +112,7 @@ impl Default for Config { sort_order: Default::default(), sort_criteria: Default::default(), paginated_limit: 500, + step_duration: 10, } } } diff --git a/psst-gui/src/ui/preferences.rs b/psst-gui/src/ui/preferences.rs index 73159b35..0866bf06 100644 --- a/psst-gui/src/ui/preferences.rs +++ b/psst-gui/src/ui/preferences.rs @@ -212,6 +212,22 @@ fn general_tab_widget() -> impl Widget { col = col.with_spacer(theme::grid(3.0)); + col = col + .with_child(Label::new("Step Duration").with_font(theme::UI_FONT_MEDIUM)) + .with_spacer(theme::grid(2.0)) + .with_child( + Flex::row() + .with_child( + TextBox::new().with_formatter(ParseFormatter::with_format_fn( + |usize: &usize| usize.to_string(), + )), + ) + .padding((theme::grid(1.5), 0.0)) + .lens(AppState::config.then(Config::step_duration)), + ); + + col = col.with_spacer(theme::grid(3.0)); + col = col .with_child( Label::new("Max Loaded Tracks (requires restart)").with_font(theme::UI_FONT_MEDIUM), diff --git a/psst-gui/src/widget/mod.rs b/psst-gui/src/widget/mod.rs index 5cb3a437..c6407d2f 100644 --- a/psst-gui/src/widget/mod.rs +++ b/psst-gui/src/widget/mod.rs @@ -23,7 +23,7 @@ use druid_shell::Cursor; pub use empty::Empty; pub use link::Link; pub use maybe::Maybe; -pub use overlay::{Overlay}; +pub use overlay::Overlay; pub use promise::Async; pub use remote_image::RemoteImage; pub use theme::ThemeScope;