Finish song page
This commit is contained in:
parent
560fe0355d
commit
28b71df7e6
@ -671,7 +671,7 @@ impl Album {
|
|||||||
#[cfg_attr(feature = "ssr", derive(Queryable, Selectable, Insertable))]
|
#[cfg_attr(feature = "ssr", derive(Queryable, Selectable, Insertable))]
|
||||||
#[cfg_attr(feature = "ssr", diesel(table_name = crate::schema::songs))]
|
#[cfg_attr(feature = "ssr", diesel(table_name = crate::schema::songs))]
|
||||||
#[cfg_attr(feature = "ssr", diesel(check_for_backend(diesel::pg::Pg)))]
|
#[cfg_attr(feature = "ssr", diesel(check_for_backend(diesel::pg::Pg)))]
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
pub struct Song {
|
pub struct Song {
|
||||||
/// A unique id for the song
|
/// A unique id for the song
|
||||||
#[cfg_attr(feature = "ssr", diesel(deserialize_as = i32))]
|
#[cfg_attr(feature = "ssr", diesel(deserialize_as = i32))]
|
||||||
|
@ -3,11 +3,18 @@ use leptos_router::use_params_map;
|
|||||||
use leptos_icons::*;
|
use leptos_icons::*;
|
||||||
use server_fn::error::NoCustomError;
|
use server_fn::error::NoCustomError;
|
||||||
|
|
||||||
|
use crate::api::songs;
|
||||||
use crate::components::loading::*;
|
use crate::components::loading::*;
|
||||||
use crate::components::error::*;
|
use crate::components::error::*;
|
||||||
use crate::api::song::*;
|
use crate::components::song_list::*;
|
||||||
use crate::models::Song;
|
use crate::api::songs::*;
|
||||||
use crate::songs::get_song_by_id;
|
use crate::songdata::SongData;
|
||||||
|
use crate::util::state::GlobalState;
|
||||||
|
|
||||||
|
use std::rc::Rc;
|
||||||
|
use std::borrow::Borrow;
|
||||||
|
|
||||||
|
const PLAY_BTN_SIZE: &str = "3rem";
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub fn SongPage() -> impl IntoView {
|
pub fn SongPage() -> impl IntoView {
|
||||||
@ -76,17 +83,120 @@ fn SongDetails(#[prop(into)] id: MaybeSignal<i32>) -> impl IntoView {
|
|||||||
}
|
}
|
||||||
})}
|
})}
|
||||||
</Transition>
|
</Transition>
|
||||||
|
<SongPlays id />
|
||||||
|
<MySongPlays id />
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
fn SongOverview(song: Song) -> impl IntoView {
|
fn SongOverview(song: SongData) -> impl IntoView {
|
||||||
|
let liked = create_rw_signal(song.like_dislike.map(|ld| ld.0).unwrap_or(false));
|
||||||
|
let disliked = create_rw_signal(song.like_dislike.map(|ld| ld.1).unwrap_or(false));
|
||||||
|
|
||||||
|
let playing = create_rw_signal(false);
|
||||||
|
let icon = Signal::derive(move || {
|
||||||
|
if playing.get() {
|
||||||
|
icondata::BsPauseFill
|
||||||
|
} else {
|
||||||
|
icondata::BsPlayFill
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
create_effect(move |_| {
|
||||||
|
GlobalState::play_status().with(|status| {
|
||||||
|
playing.set(status.queue.front().map(|song| song.id) == Some(song.id) && status.playing);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
let song_rc = Rc::new(song.clone());
|
||||||
|
|
||||||
|
let toggle_play_song = move |_| {
|
||||||
|
GlobalState::play_status().update(|status| {
|
||||||
|
if status.queue.front().map(|song| song.id) == Some(song_rc.id) {
|
||||||
|
status.playing = !status.playing;
|
||||||
|
} else {
|
||||||
|
if let Some(last_playing) = status.queue.front() {
|
||||||
|
status.queue.push_front(last_playing.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
status.queue.clear();
|
||||||
|
status.queue.push_front(<Rc<SongData> as Borrow<SongData>>::borrow(&song_rc).clone());
|
||||||
|
status.playing = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
view! {
|
view! {
|
||||||
<div class="song-header">
|
<div class="song-header">
|
||||||
|
<img class="song-image" src=song.image_path />
|
||||||
<h1>{song.title}</h1>
|
<h1>{song.title}</h1>
|
||||||
<p>{format!("Artist: {}", song.artist)}</p>
|
|
||||||
<p>{format!("Album: {}", song.album.unwrap_or_else(|| "Unknown".to_string()))}</p>
|
|
||||||
<p>{format!("Duration: {}", song.duration)}</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div class="song-actions">
|
||||||
|
<button on:click=toggle_play_song>
|
||||||
|
<Icon class="controlbtn" width=PLAY_BTN_SIZE height=PLAY_BTN_SIZE icon />
|
||||||
|
</button>
|
||||||
|
<SongLikeDislike song_id=song.id liked disliked /><br/>
|
||||||
|
</div>
|
||||||
|
<p><SongArtists artists=song.artists /></p>
|
||||||
|
<p><SongAlbum album=song.album /></p>
|
||||||
|
<p>{format!("Duration: {}:{:02}", song.duration / 60, song.duration % 60)}</p>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
fn SongPlays(#[prop(into)] id: MaybeSignal<i32>) -> impl IntoView {
|
||||||
|
let plays = create_resource(move || id.get(), move |id| songs::get_song_plays(id));
|
||||||
|
|
||||||
|
view! {
|
||||||
|
<Transition
|
||||||
|
fallback=move || view! { <Loading /> }
|
||||||
|
>
|
||||||
|
{move || plays.get().map(|plays| {
|
||||||
|
match plays {
|
||||||
|
Ok(plays) => {
|
||||||
|
view! {
|
||||||
|
<p>{format!("Plays: {}", plays)}</p>
|
||||||
|
}.into_view()
|
||||||
|
},
|
||||||
|
Err(error) => {
|
||||||
|
view! {
|
||||||
|
<ServerError<NoCustomError>
|
||||||
|
title="Error fetching song plays"
|
||||||
|
error
|
||||||
|
/>
|
||||||
|
}.into_view()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})}
|
||||||
|
</Transition>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
fn MySongPlays(#[prop(into)] id: MaybeSignal<i32>) -> impl IntoView {
|
||||||
|
let plays = create_resource(move || id.get(), move |id| songs::get_my_song_plays(id));
|
||||||
|
|
||||||
|
view! {
|
||||||
|
<Transition
|
||||||
|
fallback=move || view! { <Loading /> }
|
||||||
|
>
|
||||||
|
{move || plays.get().map(|plays| {
|
||||||
|
match plays {
|
||||||
|
Ok(plays) => {
|
||||||
|
view! {
|
||||||
|
<p>{format!("My Plays: {}", plays)}</p>
|
||||||
|
}.into_view()
|
||||||
|
},
|
||||||
|
Err(error) => {
|
||||||
|
view! {
|
||||||
|
<ServerError<NoCustomError>
|
||||||
|
title="Error fetching my song plays"
|
||||||
|
error
|
||||||
|
/>
|
||||||
|
}.into_view()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})}
|
||||||
|
</Transition>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user