diff --git a/src/components/song_list.rs b/src/components/song_list.rs index 442b9d5..3da379a 100644 --- a/src/components/song_list.rs +++ b/src/components/song_list.rs @@ -1,3 +1,5 @@ +use std::rc::Rc; + use leptos::*; use leptos::logging::*; use leptos_icons::*; @@ -5,59 +7,82 @@ use leptos_icons::*; use crate::api::songs::*; use crate::songdata::SongData; use crate::models::{Album, Artist}; +use crate::util::state::GlobalState; const LIKE_DISLIKE_BTN_SIZE: &str = "2em"; #[component] -pub fn SongList(songs: MaybeSignal>) -> impl IntoView { - view! { - - { - songs.with(|songs| { - let mut first_song = true; - - songs.iter().map(|song| { - let playing = first_song.into(); - first_song = false; - - let extra = Option::<()>::None; - - view! { - - } - }).collect::>() - }) - } -
- } +pub fn SongList(songs: Vec) -> impl IntoView { + __SongListInner(songs.into_iter().map(|song| (song, ())).collect::>(), false) } #[component] -pub fn SongListExtra(songs: MaybeSignal>) -> impl IntoView where +pub fn SongListExtra(songs: Vec<(SongData, T)>) -> impl IntoView where T: Clone + IntoView + 'static { + __SongListInner(songs, true) +} + +#[component] +fn SongListInner(songs: Vec<(SongData, T)>, show_extra: bool) -> impl IntoView where + T: Clone + IntoView + 'static +{ + let songs = Rc::new(songs); + let songs_2 = songs.clone(); + + // Signal that acts as a callback for a song list item to queue songs after it in the list + let (handle_queue_remaining, do_queue_remaining) = create_signal(None); + create_effect(move |_| { + let clicked_index = handle_queue_remaining.get(); + + if let Some(index) = clicked_index { + GlobalState::play_status().update(|status| { + let song: &(SongData, T) = songs.get(index).expect("Invalid song list item index"); + + if status.queue.front().map(|song| song.id) == Some(song.0.id) { + // If the clicked song is already at the front of the queue, just play it + status.playing = true; + } else { + // Otherwise, add the currently playing song to the history, + // clear the queue, and queue the clicked song and other after it + if let Some(last_playing) = status.queue.pop_front() { + status.history.push_back(last_playing); + } + + status.queue.clear(); + status.queue.extend(songs.iter().skip(index).map(|(song, _)| song.clone())); + status.playing = true; + } + }); + } + }); + view! { { - songs.with(|songs| { - let mut first_song = true; + songs_2.iter().enumerate().map(|(list_index, (song, extra))| { + let song_id = song.id; + let playing = create_rw_signal(false); - songs.iter().map(|(song, extra)| { - let playing = first_song.into(); - first_song = false; + create_effect(move |_| { + GlobalState::play_status().with(|status| { + playing.set(status.queue.front().map(|song| song.id) == Some(song_id) && status.playing); + }); + }); - view! { - - } - }).collect::>() - }) + view! { + + } + }).collect::>() }
} } #[component] -pub fn SongListItem(song: SongData, song_playing: MaybeSignal, extra: Option) -> impl IntoView where +pub fn SongListItem(song: SongData, song_playing: MaybeSignal, extra: Option, + list_index: usize, do_queue_remaining: WriteSignal>) -> impl IntoView where T: IntoView + 'static { let liked = create_rw_signal(song.like_dislike.map(|(liked, _)| liked).unwrap_or(false)); @@ -65,7 +90,8 @@ pub fn SongListItem(song: SongData, song_playing: MaybeSignal, extra: O view! { - +

{song.title}

@@ -85,13 +111,27 @@ pub fn SongListItem(song: SongData, song_playing: MaybeSignal, extra: O /// Display the song's image, with an overlay if the song is playing /// When the song list item is hovered, the overlay will show the play button #[component] -fn SongImage(image_path: String, song_playing: MaybeSignal) -> impl IntoView { +fn SongImage(image_path: String, song_playing: MaybeSignal, list_index: usize, + do_queue_remaining: WriteSignal>) -> impl IntoView +{ + let play_song = move |_| { + do_queue_remaining.set(Some(list_index)); + }; + + let pause_song = move |_| { + GlobalState::play_status().update(|status| { + status.playing = false; + }); + }; + view! { - {if song_playing.get() { - view! { }.into_view() + {move || if song_playing.get() { + view! { }.into_view() } else { - view! { }.into_view() + view! { }.into_view() }} } } diff --git a/src/pages/profile.rs b/src/pages/profile.rs index 2367470..b6fd5b9 100644 --- a/src/pages/profile.rs +++ b/src/pages/profile.rs @@ -214,7 +214,7 @@ fn TopSongs(#[prop(into)] user_id: MaybeSignal) -> impl IntoView { top_songs.get().map(|top_songs| { top_songs.map(|top_songs| { view! { - + } }) }) @@ -255,7 +255,7 @@ fn RecentSongs(#[prop(into)] user_id: MaybeSignal) -> impl IntoView { recent_songs.get().map(|recent_songs| { recent_songs.map(|recent_songs| { view! { - + } }) })