use super::{
super::app::{App, PendingTrackSelection, RecommendationsContext, TrackTable, TrackTableContext},
common_key_events,
};
use crate::event::Key;
use crate::network::IoEvent;
use rand::{thread_rng, Rng};
use rspotify::model::{
idtypes::{PlayContextId, PlaylistId, TrackId},
PlayableId,
};
pub fn handler(key: Key, app: &mut App) {
match key {
k if common_key_events::left_event(k) => common_key_events::handle_left_event(app),
k if common_key_events::down_event(k) => {
let current_index = app.track_table.selected_index;
let tracks_len = app.track_table.tracks.len();
if current_index == tracks_len - 1 {
match &app.track_table.context {
Some(TrackTableContext::MyPlaylists) => {
if let Some(playlist_id) = active_playlist_id_static(app) {
if let Some(playlist_tracks) = &app.playlist_tracks {
if app.playlist_offset + app.large_search_limit < playlist_tracks.total {
app.playlist_offset += app.large_search_limit;
app.dispatch(IoEvent::GetPlaylistItems(playlist_id, app.playlist_offset));
app.pending_track_table_selection = Some(PendingTrackSelection::First);
return;
}
}
}
}
Some(TrackTableContext::DiscoverPlaylist) => {
}
Some(TrackTableContext::SavedTracks) => {
if let Some(saved_tracks) = app.library.saved_tracks.get_results(None) {
let current_offset = saved_tracks.offset;
let limit = saved_tracks.limit;
if current_offset + limit < saved_tracks.total {
app.get_current_user_saved_tracks_next();
app.pending_track_table_selection = Some(PendingTrackSelection::First);
return;
}
}
}
_ => {}
}
}
let next_index = common_key_events::on_down_press_handler(
&app.track_table.tracks,
Some(app.track_table.selected_index),
);
app.track_table.selected_index = next_index;
}
k if common_key_events::up_event(k) => {
let current_index = app.track_table.selected_index;
if current_index == 0 {
match &app.track_table.context {
Some(TrackTableContext::MyPlaylists) => {
if app.playlist_offset > 0 {
if let Some(playlist_id) = active_playlist_id_static(app) {
app.playlist_offset = app.playlist_offset.saturating_sub(app.large_search_limit);
app.dispatch(IoEvent::GetPlaylistItems(playlist_id, app.playlist_offset));
app.pending_track_table_selection = Some(PendingTrackSelection::Last);
return;
}
}
}
Some(TrackTableContext::DiscoverPlaylist) => {
}
Some(TrackTableContext::SavedTracks) => {
if app.library.saved_tracks.index > 0 {
app.get_current_user_saved_tracks_previous();
app.pending_track_table_selection = Some(PendingTrackSelection::Last);
return;
}
}
_ => {}
}
}
let next_index = common_key_events::on_up_press_handler(
&app.track_table.tracks,
Some(app.track_table.selected_index),
);
app.track_table.selected_index = next_index;
}
k if common_key_events::high_event(k) => {
let next_index = common_key_events::on_high_press_handler();
app.track_table.selected_index = next_index;
}
k if common_key_events::middle_event(k) => {
let next_index = common_key_events::on_middle_press_handler(&app.track_table.tracks);
app.track_table.selected_index = next_index;
}
k if common_key_events::low_event(k) => {
let next_index = common_key_events::on_low_press_handler(&app.track_table.tracks);
app.track_table.selected_index = next_index;
}
Key::Enter => {
on_enter(app);
}
k if k == app.user_config.keys.next_page => {
if let Some(context) = &app.track_table.context {
match context {
TrackTableContext::MyPlaylists => {
if let Some(playlist_id) = active_playlist_id_static(app) {
if let Some(playlist_tracks) = &app.playlist_tracks {
if app.playlist_offset + app.large_search_limit < playlist_tracks.total {
app.playlist_offset += app.large_search_limit;
app.dispatch(IoEvent::GetPlaylistItems(playlist_id, app.playlist_offset));
}
}
}
}
TrackTableContext::RecommendedTracks => {}
TrackTableContext::SavedTracks => {
app.get_current_user_saved_tracks_next();
}
TrackTableContext::AlbumSearch => {}
TrackTableContext::PlaylistSearch => {}
TrackTableContext::DiscoverPlaylist => {}
}
};
}
k if k == app.user_config.keys.previous_page => {
if let Some(context) = &app.track_table.context {
match context {
TrackTableContext::MyPlaylists => {
if let Some(playlist_id) = active_playlist_id_static(app) {
if app.playlist_offset >= app.large_search_limit {
app.playlist_offset -= app.large_search_limit;
}
app.dispatch(IoEvent::GetPlaylistItems(playlist_id, app.playlist_offset));
}
}
TrackTableContext::RecommendedTracks => {}
TrackTableContext::SavedTracks => {
app.get_current_user_saved_tracks_previous();
}
TrackTableContext::AlbumSearch => {}
TrackTableContext::PlaylistSearch => {}
TrackTableContext::DiscoverPlaylist => {}
}
};
}
Key::Char('s') => handle_save_track_event(app),
Key::Char('S') => play_random_song(app),
k if k == app.user_config.keys.jump_to_end => jump_to_end(app),
k if k == app.user_config.keys.jump_to_start => jump_to_start(app),
Key::Char('r') => {
handle_recommended_tracks(app);
}
_ if key == app.user_config.keys.add_item_to_queue => on_queue(app),
Key::Char(',') => {
super::sort_menu::open_sort_menu(app, crate::sort::SortContext::PlaylistTracks);
}
_ => {}
}
}
fn play_random_song(app: &mut App) {
if let Some(context) = &app.track_table.context {
match context {
TrackTableContext::MyPlaylists => {
let context_id = active_playlist_context_id(app);
let track_json = active_playlist_total_tracks(app);
if let Some(val) = track_json {
app.dispatch(IoEvent::StartPlayback(
context_id,
None,
Some(thread_rng().gen_range(0..val as usize)),
));
}
}
TrackTableContext::RecommendedTracks => {}
TrackTableContext::SavedTracks => {
if let Some(saved_tracks) = &app.library.saved_tracks.get_results(None) {
let playable_ids: Vec<PlayableId<'static>> = saved_tracks
.items
.iter()
.filter_map(|item| track_playable_id(item.track.id.clone()))
.collect();
if !playable_ids.is_empty() {
let rand_idx = thread_rng().gen_range(0..playable_ids.len());
app.dispatch(IoEvent::StartPlayback(
None,
Some(playable_ids),
Some(rand_idx),
))
}
}
}
TrackTableContext::AlbumSearch => {}
TrackTableContext::PlaylistSearch => {
let (context_id, playlist_track_json) = match (
&app.search_results.selected_playlists_index,
&app.search_results.playlists,
) {
(Some(selected_playlist_index), Some(playlist_result)) => {
if let Some(selected_playlist) = playlist_result
.items
.get(selected_playlist_index.to_owned())
{
(
Some(playlist_context_id_from_ref(&selected_playlist.id)),
Some(selected_playlist.tracks.total),
)
} else {
(None, None)
}
}
_ => (None, None),
};
if let Some(val) = playlist_track_json {
app.dispatch(IoEvent::StartPlayback(
context_id,
None,
Some(thread_rng().gen_range(0..val as usize)),
))
}
}
TrackTableContext::DiscoverPlaylist => {
let mut playable_ids: Vec<PlayableId<'static>> = Vec::new();
for track in &app.track_table.tracks {
if let Some(playable_id) = track_playable_id(track.id.clone()) {
playable_ids.push(playable_id);
}
}
if !playable_ids.is_empty() {
let rand_idx = thread_rng().gen_range(0..playable_ids.len());
app.dispatch(IoEvent::StartPlayback(
None,
Some(playable_ids),
Some(rand_idx),
));
}
}
}
};
}
fn handle_save_track_event(app: &mut App) {
let (selected_index, tracks) = (&app.track_table.selected_index, &app.track_table.tracks);
if let Some(track) = tracks.get(*selected_index) {
if let Some(playable_id) = track_playable_id(track.id.clone()) {
app.dispatch(IoEvent::ToggleSaveTrack(playable_id));
}
};
}
fn handle_recommended_tracks(app: &mut App) {
let (selected_index, tracks) = (&app.track_table.selected_index, &app.track_table.tracks);
if let Some(track) = tracks.get(*selected_index) {
let first_track = track.clone();
let track_id_list = track.id.as_ref().map(|id| vec![id.to_string()]);
app.recommendations_context = Some(RecommendationsContext::Song);
app.recommendations_seed = first_track.name.clone();
app.get_recommendations_for_seed(None, track_id_list, Some(first_track));
};
}
fn jump_to_end(app: &mut App) {
if let Some(context) = &app.track_table.context {
match context {
TrackTableContext::MyPlaylists => {
if let (Some(total_tracks), Some(playlist_id)) = (
active_playlist_total_tracks(app),
active_playlist_id_static(app),
) {
if app.large_search_limit < total_tracks {
app.playlist_offset = total_tracks - (total_tracks % app.large_search_limit);
app.dispatch(IoEvent::GetPlaylistItems(playlist_id, app.playlist_offset));
}
}
}
TrackTableContext::RecommendedTracks => {}
TrackTableContext::SavedTracks => {}
TrackTableContext::AlbumSearch => {}
TrackTableContext::PlaylistSearch => {}
TrackTableContext::DiscoverPlaylist => {}
}
}
}
fn on_enter(app: &mut App) {
let TrackTable {
context,
selected_index,
tracks,
} = &app.track_table;
if let Some(context) = &context {
match context {
TrackTableContext::MyPlaylists => {
if let Some(track) = tracks.get(*selected_index) {
let track_playable_id = track_playable_id(track.id.clone());
let context_id = match &app.active_playlist_index {
Some(active_playlist_index) => app
.all_playlists
.get(active_playlist_index.to_owned())
.map(|selected_playlist| playlist_context_id_from_ref(&selected_playlist.id)),
_ => None,
};
if let Some(playable_id) = track_playable_id {
app.dispatch(IoEvent::StartPlayback(
context_id,
Some(vec![playable_id]),
Some(0), ));
} else {
app.dispatch(IoEvent::StartPlayback(
context_id,
None,
Some(app.track_table.selected_index + app.playlist_offset as usize),
));
}
};
}
TrackTableContext::RecommendedTracks => {
let playable_ids: Vec<PlayableId<'static>> = app
.recommended_tracks
.iter()
.filter_map(|track| track_playable_id(track.id.clone()))
.collect();
if !playable_ids.is_empty() {
app.dispatch(IoEvent::StartPlayback(
None,
Some(playable_ids),
Some(app.track_table.selected_index),
));
}
}
TrackTableContext::SavedTracks => {
let mut all_playable_ids: Vec<PlayableId<'static>> = Vec::new();
let current_page_index = app.library.saved_tracks.index;
for (page_idx, page) in app.library.saved_tracks.pages.iter().enumerate() {
for item in &page.items {
if let Some(id) = track_playable_id(item.track.id.clone()) {
all_playable_ids.push(id);
}
}
if page_idx == current_page_index {
}
}
if !all_playable_ids.is_empty() {
let mut absolute_offset = 0;
for page_idx in 0..current_page_index {
if let Some(page) = app.library.saved_tracks.pages.get(page_idx) {
absolute_offset += page.items.len();
}
}
absolute_offset += app.track_table.selected_index;
app.dispatch(IoEvent::StartPlayback(
None,
Some(all_playable_ids),
Some(absolute_offset),
));
}
}
TrackTableContext::AlbumSearch => {}
TrackTableContext::PlaylistSearch => {
let TrackTable {
selected_index,
tracks,
..
} = &app.track_table;
if let Some(_track) = tracks.get(*selected_index) {
let context_id = match (
&app.search_results.selected_playlists_index,
&app.search_results.playlists,
) {
(Some(selected_playlist_index), Some(playlist_result)) => playlist_result
.items
.get(selected_playlist_index.to_owned())
.map(|selected_playlist| playlist_context_id_from_ref(&selected_playlist.id)),
_ => None,
};
app.dispatch(IoEvent::StartPlayback(
context_id,
None,
Some(app.track_table.selected_index),
));
};
}
TrackTableContext::DiscoverPlaylist => {
let mut playable_ids: Vec<PlayableId<'static>> = Vec::new();
let mut selected_offset: Option<usize> = None;
for (idx, track) in tracks.iter().enumerate() {
if let Some(playable_id) = track_playable_id(track.id.clone()) {
if idx == *selected_index {
selected_offset = Some(playable_ids.len());
}
playable_ids.push(playable_id);
}
}
if !playable_ids.is_empty() {
app.dispatch(IoEvent::StartPlayback(
None,
Some(playable_ids),
Some(selected_offset.unwrap_or(0)),
));
}
}
}
};
}
fn on_queue(app: &mut App) {
let TrackTable {
context,
selected_index,
tracks,
} = &app.track_table;
if let Some(context) = &context {
match context {
TrackTableContext::MyPlaylists => {
if let Some(track) = tracks.get(*selected_index) {
if let Some(playable_id) = track_playable_id(track.id.clone()) {
app.dispatch(IoEvent::AddItemToQueue(playable_id));
}
};
}
TrackTableContext::RecommendedTracks => {
if let Some(full_track) = app.recommended_tracks.get(app.track_table.selected_index) {
if let Some(playable_id) = track_playable_id(full_track.id.clone()) {
app.dispatch(IoEvent::AddItemToQueue(playable_id));
}
}
}
TrackTableContext::SavedTracks => {
if let Some(page) = app.library.saved_tracks.get_results(None) {
if let Some(saved_track) = page.items.get(app.track_table.selected_index) {
if let Some(playable_id) = track_playable_id(saved_track.track.id.clone()) {
app.dispatch(IoEvent::AddItemToQueue(playable_id));
}
}
}
}
TrackTableContext::AlbumSearch => {}
TrackTableContext::PlaylistSearch => {
let TrackTable {
selected_index,
tracks,
..
} = &app.track_table;
if let Some(track) = tracks.get(*selected_index) {
if let Some(playable_id) = track_playable_id(track.id.clone()) {
app.dispatch(IoEvent::AddItemToQueue(playable_id));
}
};
}
TrackTableContext::DiscoverPlaylist => {
if let Some(track) = tracks.get(*selected_index) {
if let Some(playable_id) = track_playable_id(track.id.clone()) {
app.dispatch(IoEvent::AddItemToQueue(playable_id));
}
}
}
}
};
}
fn jump_to_start(app: &mut App) {
if let Some(context) = &app.track_table.context {
match context {
TrackTableContext::MyPlaylists => {
if let Some(playlist_id) = active_playlist_id_static(app) {
app.playlist_offset = 0;
app.dispatch(IoEvent::GetPlaylistItems(playlist_id, app.playlist_offset));
}
}
TrackTableContext::RecommendedTracks => {}
TrackTableContext::SavedTracks => {}
TrackTableContext::AlbumSearch => {}
TrackTableContext::PlaylistSearch => {}
TrackTableContext::DiscoverPlaylist => {}
}
}
}
fn active_playlist_id_static(app: &App) -> Option<PlaylistId<'static>> {
app
.active_playlist_index
.and_then(|idx| app.all_playlists.get(idx))
.map(|playlist| playlist.id.clone().into_static())
}
fn active_playlist_context_id(app: &App) -> Option<PlayContextId<'static>> {
app
.active_playlist_index
.and_then(|idx| app.all_playlists.get(idx))
.map(|playlist| playlist_context_id_from_ref(&playlist.id))
}
fn active_playlist_total_tracks(app: &App) -> Option<u32> {
app
.active_playlist_index
.and_then(|idx| app.all_playlists.get(idx))
.map(|playlist| playlist.tracks.total)
}
fn playlist_context_id_from_ref(id: &PlaylistId<'_>) -> PlayContextId<'static> {
PlayContextId::Playlist(id.clone().into_static())
}
fn track_playable_id(id: Option<TrackId<'_>>) -> Option<PlayableId<'static>> {
id.map(|track_id| PlayableId::Track(track_id.into_static()))
}