diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f0fb9bf..d8cf64c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,18 +16,8 @@ Types of changes: # Festival GUI Unreleased - - ---- - - -# `festivald` Unreleased - - ---- - - -# `festival-cli` Unreleased +## Added +- `QueueRepeat` mode to repeat queue but start paused ([#90](https://github.com/hinto-janai/festival/pull/90)) --- diff --git a/gui/src/data/state.rs b/gui/src/data/state.rs index 803083f7..347d1caa 100644 --- a/gui/src/data/state.rs +++ b/gui/src/data/state.rs @@ -189,16 +189,19 @@ mod test { // Filled. const S2: Lazy = Lazy::new(|| State::from_path("../assets/festival/gui/state/state1_real.bin").unwrap()); - #[test] - // Compares `new()`. - fn cmp() { - assert_eq!(Lazy::force(&S1), &State::new()); - assert_ne!(Lazy::force(&S1), Lazy::force(&S2)); - - let b1 = S1.to_bytes().unwrap(); - let b2 = S2.to_bytes().unwrap(); - assert_ne!(b1, b2); - } + // BREAKING CHANGE: + // 3rd `Repeat` variant `Off` -> `QueueRepeat` + // + // #[test] + // // Compares `new()`. + // fn cmp() { + // assert_eq!(Lazy::force(&S1), &State::new()); + // assert_ne!(Lazy::force(&S1), Lazy::force(&S2)); + // + // let b1 = S1.to_bytes().unwrap(); + // let b2 = S2.to_bytes().unwrap(); + // assert_ne!(b1, b2); + // } #[test] // Attempts to deserialize the non-empty. @@ -208,7 +211,7 @@ mod test { assert_eq!(S2.last_tab, Some(Tab::Playlists)); assert_eq!(S2.search_string, "asdf"); assert_eq!(S2.volume, 25); - assert_eq!(S2.repeat, Repeat::Off); + assert_eq!(S2.repeat, Repeat::QueuePause); assert_eq!(S2.album, Some(AlbumKey::from(1_u8))); assert_eq!(S2.artist, Some(ArtistKey::zero())); assert_eq!(S2.search_result.artists.len(), 3); diff --git a/gui/src/data/state0.rs b/gui/src/data/state0.rs index 76ebd46e..1b293b8b 100644 --- a/gui/src/data/state0.rs +++ b/gui/src/data/state0.rs @@ -135,16 +135,19 @@ mod test { // Filled. const S2: Lazy = Lazy::new(|| State0::from_path("../assets/festival/gui/state/state0_real.bin").unwrap()); - #[test] - // Compares `new()`. - fn cmp() { - assert_eq!(Lazy::force(&S1), &State0::new()); - assert_ne!(Lazy::force(&S1), Lazy::force(&S2)); - - let b1 = S1.to_bytes().unwrap(); - let b2 = S2.to_bytes().unwrap(); - assert_ne!(b1, b2); - } + // BREAKING CHANGE: + // 3rd `Repeat` variant `Off` -> `QueueRepeat` + // + // #[test] + // // Compares `new()`. + // fn cmp() { + // assert_eq!(Lazy::force(&S1), &State0::new()); + // assert_ne!(Lazy::force(&S1), Lazy::force(&S2)); + // + // let b1 = S1.to_bytes().unwrap(); + // let b2 = S2.to_bytes().unwrap(); + // assert_ne!(b1, b2); + // } #[test] // Attempts to deserialize the non-empty. @@ -154,7 +157,7 @@ mod test { assert_eq!(S2.last_tab, Some(Tab::Playlists)); assert_eq!(S2.search_string, "asdf"); assert_eq!(S2.volume, 0); - assert_eq!(S2.repeat, Repeat::Off); + assert_eq!(S2.repeat, Repeat::QueuePause); assert_eq!(S2.album, Some(AlbumKey::from(1_u8))); assert_eq!(S2.artist, Some(ArtistKey::zero())); assert_eq!(S2.search_result.artists.len(), 3); diff --git a/gui/src/text.rs b/gui/src/text.rs index b1e426e0..43ece7e3 100644 --- a/gui/src/text.rs +++ b/gui/src/text.rs @@ -66,6 +66,7 @@ pub const VOLUME_SLIDER: &str = "Increase/decrease audio volume"; pub const SHUFFLE_OFF: &str = "Shuffle is turned off"; pub const REPEAT_SONG: &str = "The current song will be repeated forever"; pub const REPEAT_QUEUE: &str = "The current queue will be repeated forever"; +pub const REPEAT_QUEUE_PAUSE: &str = "The current queue will be repeated forever, but will start paused"; pub const REPEAT_OFF: &str = "Repeat is turned off"; //---------------------------------------------------------------------------------------------------- Bottom Bar diff --git a/gui/src/ui/queue.rs b/gui/src/ui/queue.rs index f5a0dfc2..c5fad81a 100644 --- a/gui/src/ui/queue.rs +++ b/gui/src/ui/queue.rs @@ -1,7 +1,7 @@ //---------------------------------------------------------------------------------------------------- Use use crate::constants::{ BONE,GRAY,YELLOW,GREEN,MEDIUM_GRAY, - QUEUE_ALBUM_ART_SIZE, + QUEUE_ALBUM_ART_SIZE,WHITE, }; use crate::text::{ UI_QUEUE_CLEAR,UI_QUEUE_SHUFFLE,UI_MINUS, @@ -11,6 +11,7 @@ use crate::text::{ UI_QUEUE_SHUFFLE_SONG,QUEUE_SHUFFLE_SONG, QUEUE_LENGTH,QUEUE_RUNTIME, UI_REPEAT_SONG,UI_REPEAT,REPEAT_SONG,REPEAT_QUEUE,REPEAT_OFF, + REPEAT_QUEUE_PAUSE, }; use shukusai::kernel::{ FrontendToKernel, @@ -87,6 +88,7 @@ pub fn show_tab_queue(&mut self, ui: &mut egui::Ui, ctx: &egui::Context, width: let (icon, text, color) = match self.state.repeat { Repeat::Song => (UI_REPEAT_SONG, REPEAT_SONG, YELLOW), Repeat::Queue => (UI_REPEAT, REPEAT_QUEUE, GREEN), + Repeat::QueuePause => (UI_REPEAT, REPEAT_QUEUE_PAUSE, WHITE), Repeat::Off => (UI_REPEAT, REPEAT_OFF, MEDIUM_GRAY), }; let button = Button::new( diff --git a/shukusai/src/audio/audio.rs b/shukusai/src/audio/audio.rs index 8fef6b7e..2e6751ca 100644 --- a/shukusai/src/audio/audio.rs +++ b/shukusai/src/audio/audio.rs @@ -793,7 +793,7 @@ impl Audio { self.set(next, state); }, None => { - if state.repeat == Repeat::Queue { + if matches!(state.repeat, Repeat::Queue | Repeat::QueuePause) { if !state.queue.is_empty() { let key = state.queue[0]; trace!("Audio - repeating queue, setting: {key:?}"); @@ -801,6 +801,10 @@ impl Audio { state.song = Some(key); state.queue_idx = Some(0); } + if state.repeat == Repeat::QueuePause { + state.playing = false; + self.state.playing = false; + } } else { trace!("Audio - no songs left, calling state.finish()"); state.finish(); @@ -817,7 +821,7 @@ impl Audio { let len = state.queue.len(); // Repeat the queue if we're over bounds (and it's enabled). - if state.repeat == Repeat::Queue && new_index >= len { + if matches!(state.repeat, Repeat::Queue | Repeat::QueuePause) && new_index >= len { if !state.queue.is_empty() { let key = state.queue[0]; trace!("Audio - repeating queue, setting: {key:?}"); @@ -825,6 +829,10 @@ impl Audio { state.song = Some(key); state.queue_idx = Some(0); } + if state.repeat == Repeat::QueuePause { + state.playing = false; + self.state.playing = false; + } } else if len > new_index { let key = state.queue[new_index]; self.set(key, state); diff --git a/shukusai/src/audio/repeat.rs b/shukusai/src/audio/repeat.rs index 1d18ef10..23178e00 100644 --- a/shukusai/src/audio/repeat.rs +++ b/shukusai/src/audio/repeat.rs @@ -13,11 +13,13 @@ use strum::{ //---------------------------------------------------------------------------------------------------- Constants /// [`Repeat::Song`] -const REPEAT_SONG: &str = "Repeat a single song after it finishes"; +const REPEAT_SONG: &str = "Repeat a single song after it finishes"; /// [`Repeat::Queue`] const REPEAT_QUEUE: &str = "Repeat the entire queue after it finishes"; +/// [`Repeat::QueuePause`] +const REPEAT_QUEUE_PAUSE: &str = "Repeat the entire queue after it finishes, but do not start immediately"; /// [`Repeat::Off`] -const REPEAT_OFF: &str = "Turn off all repeating"; +const REPEAT_OFF: &str = "Turn off all repeating"; //---------------------------------------------------------------------------------------------------- Repeat #[derive(Copy,Clone,Debug,Hash,Eq,Ord,PartialEq,PartialOrd,Serialize,Deserialize,Encode,Decode)] @@ -31,14 +33,16 @@ pub enum Repeat { Song, /// When finishing the queue, repeat it, forever. Queue, + /// When finishing the queue, repeat it, but paused. + QueuePause, /// Turn off all repeating. Off, } impl Repeat { - /// Returns the default, [`Self::Off`]. + /// Returns the default, [`Self::QueuePause`]. pub const fn new() -> Self { - Self::Off + Self::QueuePause } #[inline] @@ -48,6 +52,7 @@ impl Repeat { match self { Song => REPEAT_SONG, Queue => REPEAT_QUEUE, + QueuePause => REPEAT_QUEUE_PAUSE, Off => REPEAT_OFF, } } @@ -58,7 +63,8 @@ impl Repeat { pub const fn next(&self) -> Self { match self { Self::Song => Self::Queue, - Self::Queue => Self::Off, + Self::Queue => Self::QueuePause, + Self::QueuePause => Self::Off, Self::Off => Self::Song, } } @@ -70,7 +76,8 @@ impl Repeat { match self { Self::Song => Self::Off, Self::Queue => Self::Song, - Self::Off => Self::Queue, + Self::QueuePause => Self::Queue, + Self::Off => Self::QueuePause, } } }