Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 27 additions & 2 deletions spotify_player/src/event/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ pub fn handle_action_for_focused_context_page(
let data = state.data.read();
match data.caches.context.get(&id.uri()) {
Some(Context::Artist {
artist,
top_tracks,
albums,
related_artists,
..
}) => {
let PageState::Context {
state: Some(ContextPageUIState::Artist { focus, .. }),
Expand Down Expand Up @@ -58,6 +58,18 @@ pub fn handle_action_for_focused_context_page(
ui,
client_pub,
),
ArtistFocusState::LikedSongs => {
let mut liked: Vec<Track> = data
.user_data
.saved_tracks
.values()
.filter(|t| t.artists.iter().any(|a| a.id == artist.id))
.cloned()
.collect();
liked.sort_by(|a, b| b.added_at.cmp(&a.added_at));
let filtered = ui.search_filtered_items(&liked);
handle_action_for_selected_item(action, &filtered, &data, ui, client_pub)
}
}
}
Some(
Expand Down Expand Up @@ -149,10 +161,10 @@ pub fn handle_command_for_focused_context_window(
match data.caches.context.get(&context_id.uri()) {
Some(context) => match context {
Context::Artist {
artist,
top_tracks,
albums,
related_artists,
..
} => {
let PageState::Context {
state: Some(ContextPageUIState::Artist { focus, .. }),
Expand All @@ -179,6 +191,19 @@ pub fn handle_command_for_focused_context_window(
ArtistFocusState::TopTracks => handle_command_for_track_table_window(
command, client_pub, None, top_tracks, &data, ui, state,
),
ArtistFocusState::LikedSongs => {
let mut liked: Vec<Track> = data
.user_data
.saved_tracks
.values()
.filter(|t| t.artists.iter().any(|a| a.id == artist.id))
.cloned()
.collect();
liked.sort_by(|a, b| b.added_at.cmp(&a.added_at));
handle_command_for_track_table_window(
command, client_pub, None, &liked, &data, ui, state,
)
}
}
}
Context::Album { tracks, .. }
Expand Down
8 changes: 7 additions & 1 deletion spotify_player/src/state/ui/page.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ pub enum ContextPageUIState {
top_track_table: TableState,
album_table: TableState,
related_artist_list: ListState,
liked_track_table: TableState,
focus: ArtistFocusState,
},
Tracks {
Expand All @@ -110,6 +111,7 @@ pub enum ArtistFocusState {
TopTracks,
Albums,
RelatedArtists,
LikedSongs,
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
Expand Down Expand Up @@ -218,13 +220,15 @@ impl PageState {
top_track_table,
album_table,
related_artist_list,
liked_track_table,
focus,
} => match focus {
ArtistFocusState::TopTracks => MutableWindowState::Table(top_track_table),
ArtistFocusState::Albums => MutableWindowState::Table(album_table),
ArtistFocusState::RelatedArtists => {
MutableWindowState::List(related_artist_list)
}
ArtistFocusState::LikedSongs => MutableWindowState::Table(liked_track_table),
},
ContextPageUIState::Show { episode_table } => {
MutableWindowState::Table(episode_table)
Expand Down Expand Up @@ -303,6 +307,7 @@ impl ContextPageUIState {
top_track_table: TableState::default(),
album_table: TableState::default(),
related_artist_list: ListState::default(),
liked_track_table: TableState::default(),
focus: ArtistFocusState::TopTracks,
}
}
Expand Down Expand Up @@ -424,7 +429,8 @@ impl_focusable!(

impl_focusable!(
ArtistFocusState,
[TopTracks, Albums],
[TopTracks, LikedSongs],
[LikedSongs, Albums],
[Albums, RelatedArtists],
[RelatedArtists, TopTracks]
);
Expand Down
67 changes: 54 additions & 13 deletions spotify_player/src/ui/page.rs
Original file line number Diff line number Diff line change
Expand Up @@ -315,10 +315,10 @@ pub fn render_context_page(

match context {
Context::Artist {
artist,
top_tracks,
albums,
related_artists,
..
} => {
render_artist_context_page_windows(
is_active,
Expand All @@ -327,6 +327,7 @@ pub fn render_context_page(
ui,
&data,
rect,
artist,
(top_tracks, albums, related_artists),
);
}
Expand All @@ -351,6 +352,7 @@ pub fn render_context_page(
ui.search_filtered_items(tracks),
ui,
&data,
false,
);
}
Context::Tracks { tracks, .. } | Context::Album { tracks, .. } => {
Expand All @@ -362,6 +364,7 @@ pub fn render_context_page(
ui.search_filtered_items(tracks),
ui,
&data,
false,
);
}
Context::Show { episodes, .. } => {
Expand Down Expand Up @@ -808,6 +811,7 @@ pub fn render_queue_page(

/// Render windows for an artist context page, which includes
/// - A top track table
/// - A liked songs table (tracks liked by the user from this artist)
/// - An album table
/// - A related artist list
fn render_artist_context_page_windows(
Expand All @@ -817,6 +821,7 @@ fn render_artist_context_page_windows(
ui: &mut UIStateGuard,
data: &DataReadGuard,
rect: Rect,
artist: &Artist,
artist_data: (&[Track], &[Album], &[Artist]),
) {
// 1. Get data
Expand All @@ -826,6 +831,17 @@ fn render_artist_context_page_windows(
ui.search_filtered_items(artist_data.2),
);

// Collect liked tracks for this artist, sorted newest first
let mut liked_tracks: Vec<Track> = data
.user_data
.saved_tracks
.values()
.filter(|t| t.artists.iter().any(|a| a.id == artist.id))
.cloned()
.collect();
liked_tracks.sort_by(|a, b| b.added_at.cmp(&a.added_at));
let liked_tracks_filtered = ui.search_filtered_items(&liked_tracks);

let focus_state = match ui.current_page() {
PageState::Context {
state: Some(ContextPageUIState::Artist { focus, .. }),
Expand All @@ -834,26 +850,30 @@ fn render_artist_context_page_windows(
_ => return,
};

// 2. Construct the page's layout
// top tracks window
let chunks = Layout::vertical([Constraint::Fill(1), Constraint::Fill(1)]).split(rect);
let top_tracks_rect = chunks[0];

// albums and related artitsts windows
let chunks = Layout::horizontal([Constraint::Ratio(1, 2); 2]).split(chunks[1]);
// 2. Construct the page's layout: 3-row stack
// row 1: top tracks (full width)
// row 2: liked songs (full width)
// row 3: albums (left half) | related artists (right half)
let rows =
Layout::vertical([Constraint::Fill(1), Constraint::Fill(1), Constraint::Fill(1)])
.split(rect);
let top_tracks_rect = rows[0];
let liked_songs_rect =
construct_and_render_block("Liked Songs", &ui.theme, Borders::TOP, frame, rows[1]);

let bot_chunks = Layout::horizontal([Constraint::Ratio(1, 2); 2]).split(rows[2]);
let albums_rect = construct_and_render_block(
"Albums",
&ui.theme,
Borders::TOP | Borders::RIGHT,
frame,
chunks[0],
bot_chunks[0],
);
let related_artists_rect =
construct_and_render_block("Related Artists", &ui.theme, Borders::TOP, frame, chunks[1]);
construct_and_render_block("Related Artists", &ui.theme, Borders::TOP, frame, bot_chunks[1]);

// 3. Construct the page's widgets
// album table

let is_albums_active = is_active && focus_state == ArtistFocusState::Albums;
let n_albums = albums.len();
let album_rows = albums
Expand Down Expand Up @@ -910,6 +930,18 @@ fn render_artist_context_page_windows(
tracks,
ui,
data,
false,
);

render_track_table(
frame,
liked_songs_rect,
is_active && focus_state == ArtistFocusState::LikedSongs,
state,
liked_tracks_filtered,
ui,
data,
true,
);

let PageState::Context {
Expand Down Expand Up @@ -943,6 +975,7 @@ fn render_track_table(
tracks: Vec<&Track>,
ui: &mut UIStateGuard,
data: &DataReadGuard,
for_liked_songs: bool,
) {
let configs = config::get_config();
// get the current playing track's URI to decorate such track (if exists) in the track table
Expand Down Expand Up @@ -1064,8 +1097,16 @@ fn render_track_table(
{
let playable_table_state = match state {
ContextPageUIState::Artist {
top_track_table, ..
} => top_track_table,
top_track_table,
liked_track_table,
..
} => {
if for_liked_songs {
liked_track_table
} else {
top_track_table
}
}
ContextPageUIState::Playlist { track_table }
| ContextPageUIState::Album { track_table }
| ContextPageUIState::Tracks { track_table } => track_table,
Expand Down