Modify queue, playbar, and playstatus to work with Song model struct instead of old SongData

This commit is contained in:
Connor Wittman 2024-04-05 23:48:24 -04:00
parent 082e6b9269
commit 633000062c
3 changed files with 52 additions and 16 deletions

View File

@ -1,4 +1,6 @@
use crate::playstatus::PlayStatus; use crate::playstatus::PlayStatus;
use crate::api::songs::get_artists;
use crate::api::albums::get_album;
use leptos::ev::MouseEvent; use leptos::ev::MouseEvent;
use leptos::html::{Audio, Div}; use leptos::html::{Audio, Div};
use leptos::leptos_dom::*; use leptos::leptos_dom::*;
@ -152,7 +154,7 @@ fn PlayControls(status: RwSignal<PlayStatus>) -> impl IntoView {
if let Some(last_played_song) = last_played_song { if let Some(last_played_song) = last_played_song {
// Push the popped song to the front of the queue, and play it // Push the popped song to the front of the queue, and play it
let next_src = last_played_song.song_path.clone(); let next_src = last_played_song.storage_path.clone();
status.update(|status| status.queue.push_front(last_played_song)); status.update(|status| status.queue.push_front(last_played_song));
set_play_src(status, next_src); set_play_src(status, next_src);
set_playing(status, true); set_playing(status, true);
@ -245,26 +247,39 @@ fn PlayDuration(elapsed_secs: MaybeSignal<i64>, total_secs: MaybeSignal<i64>) ->
fn MediaInfo(status: RwSignal<PlayStatus>) -> impl IntoView { fn MediaInfo(status: RwSignal<PlayStatus>) -> impl IntoView {
let name = Signal::derive(move || { let name = Signal::derive(move || {
status.with(|status| { status.with(|status| {
status.queue.front().map_or("No media playing".into(), |song| song.name.clone()) status.queue.front().map_or("No media playing".into(), |song| song.title.clone())
}) })
}); });
let artist = Signal::derive(move || { let song_id = Signal::derive(move || {
status.with(|status| { status.with(|status| {
status.queue.front().map_or("".into(), |song| song.artist.clone()) status.queue.front().map_or(None, |song| song.id)
}) })
}); });
let album = Signal::derive(move || { let song_artists_resource = create_resource(song_id, move |song_id| async move {
let artists_vec = get_artists(song_id).await.unwrap_or(Vec::new());
// convert the vec of artists to a string of artists separated by commas
let artists_string = artists_vec.iter().map(|artist| artist.name.clone()).collect::<Vec<String>>().join(", ");
artists_string
});
let album_id = Signal::derive(move || {
status.with(|status| { status.with(|status| {
status.queue.front().map_or("".into(), |song| song.album.clone()) status.queue.front().map_or(None, |song| song.album_id)
}) })
}); });
let album_resource = create_resource(album_id, move |album_id| async move {
// get the album name attribute or return "Unknown Album"
let album_name = get_album(album_id).await.map_or("".to_string(), |album| album.title);
album_name
});
let image = Signal::derive(move || { let image = Signal::derive(move || {
status.with(|status| { status.with(|status| {
// TODO Use some default / unknown image? // TODO Use some default / unknown image?
status.queue.front().map_or("".into(), |song| song.image_path.clone()) status.queue.front().map_or("".into(), |song| song.image_path.clone().unwrap_or("".into()))
}) })
}); });
@ -274,7 +289,28 @@ fn MediaInfo(status: RwSignal<PlayStatus>) -> impl IntoView {
<div class="media-info-text"> <div class="media-info-text">
{name} {name}
<br/> <br/>
{artist} - {album} <Suspense
fallback=move || {
view! {"Loading Artists..."}
}
>
{move || {
song_artists_resource.get().map(|artists_string| view! {
<p>{artists_string}</p>
})
}}
</Suspense>
<Suspense
fallback=move || {
view! {"Loading Album..."}
}
>
{move || {
album_resource.get().map(|album_name| view! {
<p>{album_name}</p>
})
}}
</Suspense>
</div> </div>
</div> </div>
} }
@ -402,11 +438,11 @@ pub fn PlayBar(status: RwSignal<PlayStatus>) -> impl IntoView {
status.with_untracked(|status| { status.with_untracked(|status| {
// Start playing the first song in the queue, if available // Start playing the first song in the queue, if available
if let Some(song) = status.queue.front() { if let Some(song) = status.queue.front() {
log!("Starting playing with song: {}", song.name); log!("Starting playing with song: {}", song.title);
// Don't use the set_play_src / set_playing helper function // Don't use the set_play_src / set_playing helper function
// here because we already have access to the audio element // here because we already have access to the audio element
audio.set_src(&song.song_path); audio.set_src(&song.storage_path);
if let Err(e) = audio.play() { if let Err(e) = audio.play() {
error!("Error playing audio on load: {:?}", e); error!("Error playing audio on load: {:?}", e);
@ -455,7 +491,7 @@ pub fn PlayBar(status: RwSignal<PlayStatus>) -> impl IntoView {
let prev_song = status.queue.pop_front(); let prev_song = status.queue.pop_front();
if let Some(prev_song) = prev_song { if let Some(prev_song) = prev_song {
log!("Adding song to history: {}", prev_song.name); log!("Adding song to history: {}", prev_song.title);
status.history.push_back(prev_song); status.history.push_back(prev_song);
} else { } else {
log!("Queue empty, no previous song to add to history"); log!("Queue empty, no previous song to add to history");
@ -464,7 +500,7 @@ pub fn PlayBar(status: RwSignal<PlayStatus>) -> impl IntoView {
// Get the next song to play, if available // Get the next song to play, if available
let next_src = status.with_untracked(|status| { let next_src = status.with_untracked(|status| {
status.queue.front().map(|song| song.song_path.clone()) status.queue.front().map(|song| song.storage_path.clone())
}); });
if let Some(audio) = audio_ref.get() { if let Some(audio) = audio_ref.get() {

View File

@ -3,7 +3,7 @@ use leptos::NodeRef;
use leptos::html::Audio; use leptos::html::Audio;
use std::collections::VecDeque; use std::collections::VecDeque;
use crate::songdata::SongData; use crate::models::Song;
/// Represents the global state of the audio player feature of LibreTunes /// Represents the global state of the audio player feature of LibreTunes
pub struct PlayStatus { pub struct PlayStatus {
@ -14,9 +14,9 @@ pub struct PlayStatus {
/// A reference to the HTML audio element /// A reference to the HTML audio element
pub audio_player: Option<NodeRef<Audio>>, pub audio_player: Option<NodeRef<Audio>>,
/// A queue of songs that have been played, ordered from oldest to newest /// A queue of songs that have been played, ordered from oldest to newest
pub history: VecDeque<SongData>, pub history: VecDeque<Song>,
/// A queue of songs that have yet to be played, ordered from next up to last /// A queue of songs that have yet to be played, ordered from next up to last
pub queue: VecDeque<SongData>, pub queue: VecDeque<Song>,
} }
impl PlayStatus { impl PlayStatus {

View File

@ -99,7 +99,7 @@ pub fn Queue(status: RwSignal<PlayStatus>) -> impl IntoView {
on:dragenter=move |e: DragEvent| on_drag_enter(e, index) on:dragenter=move |e: DragEvent| on_drag_enter(e, index)
on:dragover=on_drag_over on:dragover=on_drag_over
> >
<Song song_image_path=song.image_path.clone() song_title=song.name.clone() song_artist=song.artist.clone() /> <Song song_id_arg=song.id song_image_path=song.image_path.clone().unwrap_or("".to_string()) song_title=song.title.clone() />
<Show <Show
when=move || index != 0 when=move || index != 0
fallback=|| view!{ fallback=|| view!{