Skip to content

Commit

Permalink
Highlight track from link & fix link resolution nav loop (#574)
Browse files Browse the repository at this point in the history
  • Loading branch information
jacksongoode authored Dec 28, 2024
1 parent da32333 commit 64690b9
Show file tree
Hide file tree
Showing 8 changed files with 63 additions and 39 deletions.
2 changes: 1 addition & 1 deletion psst-gui/src/controller/nav.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ impl NavController {
ctx.submit_command(search::LOAD_RESULTS.with(query.to_owned()));
}
}
Nav::AlbumDetail(link) => {
Nav::AlbumDetail(link, _) => {
if !data.album_detail.album.contains(link) {
ctx.submit_command(album::LOAD_DETAIL.with(link.to_owned()));
}
Expand Down
20 changes: 17 additions & 3 deletions psst-gui/src/data/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ impl AppState {
now_playing: None,
library: Arc::clone(&library),
show_track_cover: config.show_track_cover,
nav: Nav::Home,
});
let playback = Playback {
state: PlaybackState::Stopped,
Expand Down Expand Up @@ -179,16 +180,28 @@ impl AppState {
impl AppState {
pub fn navigate(&mut self, nav: &Nav) {
if &self.nav != nav {
let previous: Nav = mem::replace(&mut self.nav, nav.to_owned());
let previous = mem::replace(&mut self.nav, nav.to_owned());
self.history.push_back(previous);
self.config.last_route.replace(nav.to_owned());
Arc::make_mut(&mut self.common_ctx).nav = nav.to_owned();
}
}

pub fn navigate_back(&mut self) {
if let Some(nav) = self.history.pop_back() {
self.config.last_route.replace(nav.clone());
if let Some(mut nav) = self.history.pop_back() {
if let Nav::SearchResults(query) = &nav {
if SpotifyUrl::parse(query).is_some() {
nav = self.history.pop_back().unwrap_or(Nav::Home);
}
}

if let Nav::AlbumDetail(album, _) = nav {
nav = Nav::AlbumDetail(album, None);
}

self.nav = nav;
self.config.last_route.replace(self.nav.to_owned());
Arc::make_mut(&mut self.common_ctx).nav = self.nav.clone();
}
}

Expand Down Expand Up @@ -518,6 +531,7 @@ pub struct CommonCtx {
pub now_playing: Option<Playable>,
pub library: Arc<Library>,
pub show_track_cover: bool,
pub nav: Nav,
}

impl CommonCtx {
Expand Down
22 changes: 11 additions & 11 deletions psst-gui/src/data/nav.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use druid::Data;
use serde::{Deserialize, Serialize};
use url::Url;

use crate::data::track::TrackId;
use crate::data::{AlbumLink, ArtistLink, PlaylistLink, ShowLink};

use super::RecommendationsRequest;
Expand All @@ -23,7 +24,7 @@ pub enum Route {
Recommendations,
}

#[derive(Default, Clone, Debug, Data, PartialEq, Eq, Deserialize, Serialize)]
#[derive(Clone, Debug, Data, PartialEq, Eq, Default, Serialize, Deserialize)]
pub enum Nav {
#[default]
Home,
Expand All @@ -32,10 +33,10 @@ pub enum Nav {
SavedAlbums,
SavedShows,
SearchResults(Arc<str>),
AlbumDetail(AlbumLink, Option<TrackId>),
ArtistDetail(ArtistLink),
AlbumDetail(AlbumLink),
ShowDetail(ShowLink),
PlaylistDetail(PlaylistLink),
ShowDetail(ShowLink),
Recommendations(Arc<RecommendationsRequest>),
}

Expand All @@ -48,8 +49,8 @@ impl Nav {
Nav::SavedAlbums => Route::SavedAlbums,
Nav::SavedShows => Route::SavedShows,
Nav::SearchResults(_) => Route::SearchResults,
Nav::AlbumDetail(_, _) => Route::AlbumDetail,
Nav::ArtistDetail(_) => Route::ArtistDetail,
Nav::AlbumDetail(_) => Route::AlbumDetail,
Nav::PlaylistDetail(_) => Route::PlaylistDetail,
Nav::ShowDetail(_) => Route::ShowDetail,
Nav::Recommendations(_) => Route::Recommendations,
Expand All @@ -64,7 +65,7 @@ impl Nav {
Nav::SavedAlbums => "Saved Albums".to_string(),
Nav::SavedShows => "Saved Podcasts".to_string(),
Nav::SearchResults(query) => query.to_string(),
Nav::AlbumDetail(link) => link.name.to_string(),
Nav::AlbumDetail(link, _) => link.name.to_string(),
Nav::ArtistDetail(link) => link.name.to_string(),
Nav::PlaylistDetail(link) => link.name.to_string(),
Nav::ShowDetail(link) => link.name.to_string(),
Expand All @@ -79,11 +80,11 @@ impl Nav {
Nav::SavedTracks => "Saved Tracks".to_string(),
Nav::SavedAlbums => "Saved Albums".to_string(),
Nav::SavedShows => "Saved Shows".to_string(),
Nav::SearchResults(query) => format!("Search “{}”", query),
Nav::AlbumDetail(link) => format!("Album “{}”", link.name),
Nav::ArtistDetail(link) => format!("Artist “{}”", link.name),
Nav::PlaylistDetail(link) => format!("Playlist “{}”", link.name),
Nav::ShowDetail(link) => format!("Show “{}”", link.name),
Nav::SearchResults(query) => format!("Search \"{}\"", query),
Nav::AlbumDetail(link, _) => format!("Album \"{}\"", link.name),
Nav::ArtistDetail(link) => format!("Artist \"{}\"", link.name),
Nav::PlaylistDetail(link) => format!("Playlist \"{}\"", link.name),
Nav::ShowDetail(link) => format!("Show \"{}\"", link.name),
Nav::Recommendations(_) => "Recommended".to_string(),
}
}
Expand All @@ -104,7 +105,6 @@ impl SpotifyUrl {
let mut segments = url.path_segments()?;
let entity = segments.next()?;
let id = segments.next()?;
log::info!("url: {:?}", url);
match entity {
"playlist" => Some(Self::Playlist(id.into())),
"artist" => Some(Self::Artist(id.into())),
Expand Down
2 changes: 1 addition & 1 deletion psst-gui/src/data/playback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ impl PlaybackOrigin {
match &self {
PlaybackOrigin::Home => Nav::Home,
PlaybackOrigin::Library => Nav::SavedTracks,
PlaybackOrigin::Album(link) => Nav::AlbumDetail(link.clone()),
PlaybackOrigin::Album(link) => Nav::AlbumDetail(link.clone(), None),
PlaybackOrigin::Artist(link) => Nav::ArtistDetail(link.clone()),
PlaybackOrigin::Playlist(link) => Nav::PlaylistDetail(link.clone()),
PlaybackOrigin::Show(link) => Nav::ShowDetail(link.clone()),
Expand Down
2 changes: 1 addition & 1 deletion psst-gui/src/ui/album.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ pub fn album_widget(horizontal: bool) -> impl Widget<WithCtx<Arc<Album>>> {
.link()
.rounded(theme::BUTTON_BORDER_RADIUS)
.on_left_click(|ctx, _, album, _| {
ctx.submit_command(cmd::NAVIGATE.with(Nav::AlbumDetail(album.data.link())));
ctx.submit_command(cmd::NAVIGATE.with(Nav::AlbumDetail(album.data.link(), None)));
})
.context_menu(album_ctx_menu)
}
Expand Down
2 changes: 1 addition & 1 deletion psst-gui/src/ui/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -555,7 +555,7 @@ fn route_icon_widget() -> impl Widget<Nav> {
Empty.boxed()
}
Nav::SearchResults(_) | Nav::Recommendations(_) => icon(&icons::SEARCH).boxed(),
Nav::AlbumDetail(_) => icon(&icons::ALBUM).boxed(),
Nav::AlbumDetail(_, _) => icon(&icons::ALBUM).boxed(),
Nav::ArtistDetail(_) => icon(&icons::ARTIST).boxed(),
Nav::PlaylistDetail(_) => icon(&icons::PLAYLIST).boxed(),
Nav::ShowDetail(_) => icon(&icons::PODCAST).boxed(),
Expand Down
19 changes: 14 additions & 5 deletions psst-gui/src/ui/track.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::sync::Arc;

use druid::{
widget::{CrossAxisAlignment, Either, Flex, Label, ViewSwitcher},
LensExt, LocalizedString, Menu, MenuItem, Size, TextAlignment, Widget, WidgetExt,
Env, LensExt, LocalizedString, Menu, MenuItem, Size, TextAlignment, Widget, WidgetExt,
};
use psst_core::{
audio::normalize::NormalizationLevel,
Expand All @@ -13,8 +13,8 @@ use psst_core::{
use crate::{
cmd,
data::{
AppState, Library, Nav, PlaybackOrigin, PlaylistAddTrack, PlaylistRemoveTrack, QueueEntry,
RecommendationsRequest, Track,
AppState, Library, Nav, Playable, PlaybackOrigin, PlaylistAddTrack, PlaylistRemoveTrack,
QueueEntry, RecommendationsRequest, Track,
},
ui::playlist,
widget::{icons, Empty, MyWidgetExt, RemoteImage},
Expand Down Expand Up @@ -178,7 +178,16 @@ pub fn playable_widget(track: &Track, display: Display) -> impl Widget<PlayRow<A
.with_child(saved)
.padding(theme::grid(1.0))
.link()
.active(|row, _| row.is_playing)
.active(|row: &PlayRow<Arc<Track>>, _env: &Env| {
// Check if this track is the target of album detail navigation
if let Nav::AlbumDetail(_, Some(target_id)) = &row.ctx.nav {
return *target_id == row.item.id;
}
// Otherwise check if it's playing or is the current track
row.is_playing || row.ctx.now_playing.as_ref().map_or(false, |playable| {
matches!(playable, Playable::Track(track) if track.id == row.item.id)
})
})
.rounded(theme::BUTTON_BORDER_RADIUS)
.context_menu(track_row_menu)
}
Expand Down Expand Up @@ -245,7 +254,7 @@ pub fn track_menu(
MenuItem::new(
LocalizedString::new("menu-item-show-album").with_placeholder("Go to Album"),
)
.command(cmd::NAVIGATE.with(Nav::AlbumDetail(album_link.to_owned()))),
.command(cmd::NAVIGATE.with(Nav::AlbumDetail(album_link.to_owned(), None))),
);
}

Expand Down
33 changes: 17 additions & 16 deletions psst-gui/src/webapi/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,7 @@ impl WebApi {
/// Send a request with a empty JSON object, throw away the response body.
/// Use for POST/PUT/DELETE requests.
fn send_empty_json(&self, request: Request) -> Result<(), Error> {
Self::with_retry(|| Ok(request.clone().send_string("{}")?))
.map(|_| ())
Self::with_retry(|| Ok(request.clone().send_string("{}")?)).map(|_| ())
}

/// Send a request and return the deserialized JSON body. Use for GET
Expand Down Expand Up @@ -513,13 +512,14 @@ impl WebApi {
),
owner: PublicUser {
id: Arc::from(""),
display_name: Arc::from(item
.content
.data
.owner_v2
.as_ref()
.map(|owner| owner.data.name.as_str())
.unwrap_or_default())
display_name: Arc::from(
item.content
.data
.owner_v2
.as_ref()
.map(|owner| owner.data.name.as_str())
.unwrap_or_default(),
),
},
collaborative: false,
});
Expand Down Expand Up @@ -1334,14 +1334,15 @@ impl WebApi {
let nav = match link {
SpotifyUrl::Playlist(id) => Nav::PlaylistDetail(self.get_playlist(id)?.link()),
SpotifyUrl::Artist(id) => Nav::ArtistDetail(self.get_artist(id)?.link()),
SpotifyUrl::Album(id) => Nav::AlbumDetail(self.get_album(id)?.data.link()),
SpotifyUrl::Show(id) => Nav::AlbumDetail(self.get_album(id)?.data.link()),
SpotifyUrl::Track(id) => Nav::AlbumDetail(
// TODO: We should highlight the exact track in the album.
self.get_track(id)?.album.clone().ok_or_else(|| {
SpotifyUrl::Album(id) => Nav::AlbumDetail(self.get_album(id)?.data.link(), None),
SpotifyUrl::Show(id) => Nav::AlbumDetail(self.get_album(id)?.data.link(), None),
SpotifyUrl::Track(id) => {
let track = self.get_track(id)?;
let album = track.album.clone().ok_or_else(|| {
Error::WebApiError("Track was found but has no album".to_string())
})?,
),
})?;
Nav::AlbumDetail(album, Some(track.id))
}
};
Ok(nav)
}
Expand Down

0 comments on commit 64690b9

Please sign in to comment.