spotatui 0.36.2

A Spotify client for the terminal written in Rust, powered by Ratatui
use super::{
  super::app::{ActiveBlock, App, DialogContext},
  common_key_events,
};
use crate::event::Key;
use crate::network::IoEvent;

pub fn handler(key: Key, app: &mut App) {
  let dialog_context = match app.get_current_route().active_block {
    ActiveBlock::Dialog(context) => context,
    _ => return,
  };

  match dialog_context {
    DialogContext::AddTrackToPlaylistPicker => handle_add_to_playlist_picker(key, app),
    DialogContext::PlaylistWindow
    | DialogContext::PlaylistSearch
    | DialogContext::RemoveTrackFromPlaylistConfirm => {
      handle_confirmation_dialog(key, app, dialog_context)
    }
  }
}

fn handle_confirmation_dialog(key: Key, app: &mut App, dialog_context: DialogContext) {
  match key {
    Key::Enter => {
      if app.confirm {
        match dialog_context {
          DialogContext::PlaylistWindow => handle_playlist_dialog(app),
          DialogContext::PlaylistSearch => handle_playlist_search_dialog(app),
          DialogContext::RemoveTrackFromPlaylistConfirm => {
            handle_remove_track_from_playlist_confirm(app);
          }
          DialogContext::AddTrackToPlaylistPicker => {}
        }
      }
      close_dialog(app);
    }
    Key::Char('q') => {
      close_dialog(app);
    }
    k if common_key_events::right_event(k) => app.confirm = !app.confirm,
    k if common_key_events::left_event(k) => app.confirm = !app.confirm,
    _ => {}
  }
}

fn handle_add_to_playlist_picker(key: Key, app: &mut App) {
  let playlist_count = app.all_playlists.len();
  match key {
    k if common_key_events::down_event(k) => {
      if playlist_count > 0 {
        let next = common_key_events::on_down_press_handler(
          &app.all_playlists,
          Some(app.playlist_picker_selected_index),
        );
        app.playlist_picker_selected_index = next;
      }
    }
    k if common_key_events::up_event(k) => {
      if playlist_count > 0 {
        let next = common_key_events::on_up_press_handler(
          &app.all_playlists,
          Some(app.playlist_picker_selected_index),
        );
        app.playlist_picker_selected_index = next;
      }
    }
    k if common_key_events::high_event(k) => {
      if playlist_count > 0 {
        app.playlist_picker_selected_index = common_key_events::on_high_press_handler();
      }
    }
    k if common_key_events::middle_event(k) => {
      if playlist_count > 0 {
        app.playlist_picker_selected_index =
          common_key_events::on_middle_press_handler(&app.all_playlists);
      }
    }
    k if common_key_events::low_event(k) => {
      if playlist_count > 0 {
        app.playlist_picker_selected_index =
          common_key_events::on_low_press_handler(&app.all_playlists);
      }
    }
    Key::Enter => {
      if let Some(pending_add) = app.pending_playlist_track_add.clone() {
        if let Some(playlist) = app.all_playlists.get(
          app
            .playlist_picker_selected_index
            .min(playlist_count.saturating_sub(1)),
        ) {
          app.dispatch(IoEvent::AddTrackToPlaylist(
            playlist.id.clone().into_static(),
            pending_add.track_id,
          ));
        }
      }
      close_dialog(app);
    }
    Key::Char('q') => {
      close_dialog(app);
    }
    _ => {}
  }
}

fn handle_playlist_dialog(app: &mut App) {
  app.user_unfollow_playlist()
}

fn handle_playlist_search_dialog(app: &mut App) {
  app.user_unfollow_playlist_search_result()
}

fn handle_remove_track_from_playlist_confirm(app: &mut App) {
  if let Some(pending_remove) = app.pending_playlist_track_removal.clone() {
    app.dispatch(IoEvent::RemoveTrackFromPlaylistAtPosition(
      pending_remove.playlist_id,
      pending_remove.track_id,
      pending_remove.position,
    ));
  }
}

fn close_dialog(app: &mut App) {
  app.pop_navigation_stack();
  app.dialog = None;
  app.confirm = false;
  app.clear_playlist_track_dialog_state();
}

#[cfg(test)]
mod tests {
  use super::*;
  use crate::app::RouteId;

  #[test]
  fn confirmation_dialog_toggles_with_vim_hl() {
    let mut app = App::default();
    app.push_navigation_stack(
      RouteId::Dialog,
      ActiveBlock::Dialog(DialogContext::RemoveTrackFromPlaylistConfirm),
    );
    app.confirm = false;

    handler(Key::Char('l'), &mut app);
    assert!(app.confirm);

    handler(Key::Char('h'), &mut app);
    assert!(!app.confirm);
  }
}