diff --git a/psst-gui/src/ui/library.rs b/psst-gui/src/ui/library.rs index 9730ec0b..83bbe54b 100644 --- a/psst-gui/src/ui/library.rs +++ b/psst-gui/src/ui/library.rs @@ -1,7 +1,7 @@ use std::sync::Arc; use druid::{ - widget::{Flex, List}, + widget::{Flex, List, Label}, LensExt, Selector, Widget, WidgetExt, }; @@ -14,6 +14,8 @@ use crate::{ ui::home::{shows_that_you_might_like, your_shows}, webapi::WebApi, widget::{Async, MyWidgetExt}, + widget::icons, + ui::theme, }; use super::{album, playable, track, utils}; @@ -31,78 +33,123 @@ pub const UNSAVE_ALBUM: Selector = Selector::new("app.library.unsave- pub const SAVE_SHOW: Selector> = Selector::new("app.library.save-show"); pub const UNSAVE_SHOW: Selector = Selector::new("app.library.unsave-show"); +fn saved_tracks_header() -> impl Widget { + use druid::widget::CrossAxisAlignment; + + let size = theme::grid(10.0); + let heart_cover = icons::HEART.scale((size, size)); + + let title_label = Label::new("Saved Tracks") + .with_text_size(theme::TEXT_SIZE_LARGE) + .with_font(theme::UI_FONT_MEDIUM); + + let track_count_label = Label::dynamic(|data: &AppState, _| { + let count = data + .library + .saved_tracks + .resolved() + .map(|tracks| tracks.tracks.len()) + .unwrap_or(0); + if count == 1 { + "1 track".to_string() + } else { + format!("{} tracks", count) + } + }) + .with_text_size(theme::TEXT_SIZE_SMALL) + .with_text_color(theme::PLACEHOLDER_COLOR); + + let info = Flex::column() + .cross_axis_alignment(CrossAxisAlignment::Start) + .with_child(title_label) + .with_spacer(theme::grid(0.2)) + .with_child(track_count_label); + + Flex::row() + .cross_axis_alignment(CrossAxisAlignment::Center) + .with_child(heart_cover) + .with_default_spacer() + .with_child(info.padding(theme::grid(1.0))) + .align_left() +} + pub fn saved_tracks_widget() -> impl Widget { - Async::new( - utils::spinner_widget, - || { - playable::list_widget_with_find( - playable::Display { - track: track::Display { - title: true, - artist: true, - album: true, - cover: true, - ..track::Display::empty() - }, + Flex::column() + .with_child(saved_tracks_header()) + .with_flex_child( + Async::new( + utils::spinner_widget, + || { + playable::list_widget_with_find( + playable::Display { + track: track::Display { + title: true, + artist: true, + album: true, + cover: true, + ..track::Display::empty() + }, + }, + cmd::FIND_IN_SAVED_TRACKS, + ) }, - cmd::FIND_IN_SAVED_TRACKS, + utils::error_widget, ) - }, - utils::error_widget, - ) - .lens( - Ctx::make( - AppState::common_ctx, - AppState::library.then(Library::saved_tracks.in_arc()), + .lens( + Ctx::make( + AppState::common_ctx, + AppState::library.then(Library::saved_tracks.in_arc()), + ) + .then(Ctx::in_promise()), + ) + .on_command_async( + LOAD_TRACKS, + |_| WebApi::global().get_saved_tracks().map(SavedTracks::new), + |_, data, _| { + data.with_library_mut(|library| { + library.saved_tracks.defer_default(); + }); + }, + |_, data, r| { + data.with_library_mut(|library| { + library.saved_tracks.update(r); + }); + }, + ) + .on_command_async( + SAVE_TRACK, + |t| WebApi::global().save_track(&t.id.0.to_base62()), + |_, data, t| { + data.with_library_mut(|library| { + library.add_track(t); + }); + }, + |_, data, (_, r)| { + if let Err(err) = r { + data.error_alert(err); + } else { + data.info_alert("Track added to library.") + } + }, + ) + .on_command_async( + UNSAVE_TRACK, + |i| WebApi::global().unsave_track(&i.0.to_base62()), + |_, data, i| { + data.with_library_mut(|library| { + library.remove_track(&i); + }); + }, + |_, data, (_, r)| { + if let Err(err) = r { + data.error_alert(err); + } else { + data.info_alert("Track removed from library.") + } + }, + ), + 1.0 ) - .then(Ctx::in_promise()), - ) - .on_command_async( - LOAD_TRACKS, - |_| WebApi::global().get_saved_tracks().map(SavedTracks::new), - |_, data, _| { - data.with_library_mut(|library| { - library.saved_tracks.defer_default(); - }); - }, - |_, data, r| { - data.with_library_mut(|library| { - library.saved_tracks.update(r); - }); - }, - ) - .on_command_async( - SAVE_TRACK, - |t| WebApi::global().save_track(&t.id.0.to_base62()), - |_, data, t| { - data.with_library_mut(|library| { - library.add_track(t); - }); - }, - |_, data, (_, r)| { - if let Err(err) = r { - data.error_alert(err); - } else { - data.info_alert("Track added to library.") - } - }, - ) - .on_command_async( - UNSAVE_TRACK, - |i| WebApi::global().unsave_track(&i.0.to_base62()), - |_, data, i| { - data.with_library_mut(|library| { - library.remove_track(&i); - }); - }, - |_, data, (_, r)| { - if let Err(err) = r { - data.error_alert(err); - } else { - data.info_alert("Track removed from library.") - } - }, - ) } pub fn saved_albums_widget() -> impl Widget {