From b7ab0129dc8e6d40da79d90e552f2e21491d446f Mon Sep 17 00:00:00 2001 From: LeoRiether Date: Thu, 8 Feb 2024 17:43:21 -0300 Subject: [PATCH] Extract screen-specific actions into their own update() --- tori/src/state/mod.rs | 3 + tori/src/ui/mod.rs | 1 + tori/src/update/browse_screen.rs | 148 ++++++++++++++++++++++++ tori/src/update/mod.rs | 191 ++++++------------------------- 4 files changed, 189 insertions(+), 154 deletions(-) create mode 100644 tori/src/update/browse_screen.rs diff --git a/tori/src/state/mod.rs b/tori/src/state/mod.rs index d758e51..6dd4432 100644 --- a/tori/src/state/mod.rs +++ b/tori/src/state/mod.rs @@ -25,7 +25,10 @@ pub struct State<'n> { pub visualizer: Visualizer, } +#[derive(Default)] pub enum Screen { + #[default] + None, BrowseScreen(BrowseScreen), } diff --git a/tori/src/ui/mod.rs b/tori/src/ui/mod.rs index 02d0a5e..8377b62 100644 --- a/tori/src/ui/mod.rs +++ b/tori/src/ui/mod.rs @@ -28,6 +28,7 @@ pub fn ui(state: &mut State, area: Rect, buf: &mut Buffer) { state.now_playing.render(bottom, buf, &mut l); match &mut state.screen { + Screen::None => unreachable!(), Screen::BrowseScreen(screen) => browse_screen(screen, screen_area, buf, &mut l), } diff --git a/tori/src/update/browse_screen.rs b/tori/src/update/browse_screen.rs new file mode 100644 index 0000000..6eba877 --- /dev/null +++ b/tori/src/update/browse_screen.rs @@ -0,0 +1,148 @@ +use std::mem; + +use crate::{ + error::Result, + events::{channel::Tx, Action, Command}, + input::Input, + player::Player, + state::{ + browse_screen::{BrowseScreen, Focus}, + State, + }, + util::copy_to_clipboard, +}; + +pub fn browse_screen_action( + state: &mut State<'_>, + screen: &mut BrowseScreen, + tx: Tx, + act: Action, +) -> Result> { + use Action::*; + match act { + Action::Command(cmd) => return browse_screen_command(state, screen, tx, cmd), + + ScrollDown => match &screen.focus { + Focus::Playlists => screen.shown_playlists.select_next(), + Focus::Songs => screen.shown_songs.select_next(), + Focus::PlaylistsFilter(_) | Focus::SongsFilter(_) => {} + }, + ScrollUp => match &screen.focus { + Focus::Playlists => screen.shown_playlists.select_prev(), + Focus::Songs => screen.shown_songs.select_prev(), + Focus::PlaylistsFilter(_) | Focus::SongsFilter(_) => {} + }, + + SongAdded { + playlist, + song: _song, + } => { + if screen.selected_playlist() == Some(playlist.as_str()) { + screen.refresh_songs()?; + screen + .shown_songs + .select(Some(screen.shown_songs.items.len() - 1)); + } + } + RefreshSongs => screen.refresh_songs()?, + RefreshPlaylists => screen.refresh_playlists()?, + SelectSong(i) => screen.shown_songs.select(Some(i)), + SelectPlaylist(i) => { + screen.shown_playlists.select(Some(i)); + screen.refresh_songs()?; + } + + _ => {} + } + + Ok(None) +} + +fn browse_screen_command( + state: &mut State<'_>, + screen: &mut BrowseScreen, + _tx: Tx, + cmd: Command, +) -> Result> { + use Command::*; + match cmd { + Esc => { + let focus = mem::take(&mut screen.focus); + screen.focus = match focus { + Focus::PlaylistsFilter(_) => Focus::Playlists, + Focus::SongsFilter(_) => Focus::Songs, + _ => focus, + }; + return Ok(Some(Action::RefreshPlaylists)); + } + + Play => { + if let Some(song) = screen.selected_song() { + state.player.play(&song.path)?; + } + } + QueueSong => { + if let Some(song) = screen.selected_song() { + state.player.queue(&song.path)?; + } + } + QueueShown => { + for &i in screen.shown_songs.iter() { + let path = screen.songs[i].path.as_str(); + state.player.queue(path)?; + } + } + + OpenInBrowser => { + if let Some(song) = screen.selected_song() { + match webbrowser::open(&song.path) { + Ok(_) => state.notify_ok(format!("Opening {} in your browser", song.path)), + Err(e) => state.notify_err(format!("Failed to open song path: {}", e)), + } + } + } + CopyUrl => { + if let Some(song) = screen.selected_song() { + copy_to_clipboard(song.path.clone()); + state.notify_ok(format!("Copied {} to the clipboard", song.path)); + } + } + CopyTitle => { + if let Some(song) = screen.selected_song() { + copy_to_clipboard(song.title.clone()); + state.notify_ok(format!("Copied {} to the clipboard", song.title)); + } + } + + NextSortingMode => screen.next_sorting_mode(), + + SelectNext => screen.select_next()?, + SelectPrev => screen.select_prev()?, + SelectLeft => screen.focus = Focus::Playlists, + SelectRight => screen.focus = Focus::Songs, + + Search => { + let focus = mem::take(&mut screen.focus); + let new_focus = match focus { + Focus::Playlists => Focus::PlaylistsFilter(Input::default()), + Focus::Songs => Focus::SongsFilter(Input::default()), + _ => focus, + }; + screen.focus = new_focus; + } + + GotoStart => match &screen.focus { + Focus::Playlists => screen.shown_playlists.select_first(), + Focus::Songs => screen.shown_songs.select_first(), + Focus::PlaylistsFilter(_) | Focus::SongsFilter(_) => {} + }, + GotoEnd => match &screen.focus { + Focus::Playlists => screen.shown_playlists.select_last(), + Focus::Songs => screen.shown_songs.select_last(), + Focus::PlaylistsFilter(_) | Focus::SongsFilter(_) => {} + }, + _ => {} + } + + Ok(None) +} diff --git a/tori/src/update/mod.rs b/tori/src/update/mod.rs index 15451e4..b6d9378 100644 --- a/tori/src/update/mod.rs +++ b/tori/src/update/mod.rs @@ -1,19 +1,22 @@ +pub mod browse_screen; +use browse_screen::browse_screen_action; + use std::mem; use crate::{ config::Config, error::Result, events::{channel::Tx, Action, Command}, - input::{Input, InputResponse}, + input::InputResponse, player::Player, state::{browse_screen::Focus, Screen, State}, - util::copy_to_clipboard, }; use crossterm::event::{Event as TermEvent, KeyEvent, KeyEventKind, MouseEventKind}; pub fn handle_event(state: &mut State<'_>, ev: TermEvent) -> Result> { Ok(match ev { TermEvent::Key(key) if key.kind != KeyEventKind::Release => match &mut state.screen { + Screen::None => unreachable!(), Screen::BrowseScreen(screen) => match &mut screen.focus { Focus::Playlists | Focus::Songs => transform_normal_mode_key(key), Focus::PlaylistsFilter(filter) | Focus::SongsFilter(filter) => { @@ -51,25 +54,20 @@ fn transform_normal_mode_key(key_event: KeyEvent) -> Option { pub fn update(state: &mut State<'_>, tx: Tx, act: Action) -> Result> { use Action::*; match act { + Command(cmd) => return handle_command(state, tx, cmd), + + ScrollDown + | ScrollUp + | SongAdded { .. } + | RefreshSongs + | RefreshPlaylists + | SelectSong(_) + | SelectPlaylist(_) => return screen_action(state, tx, act), + Rerender => { // just triggered a rerender } - ScrollDown => match &mut state.screen { - Screen::BrowseScreen(screen) => match &screen.focus { - Focus::Playlists => screen.shown_playlists.select_next(), - Focus::Songs => screen.shown_songs.select_next(), - Focus::PlaylistsFilter(_) | Focus::SongsFilter(_) => {} - }, - }, - ScrollUp => match &mut state.screen { - Screen::BrowseScreen(screen) => match &screen.focus { - Focus::Playlists => screen.shown_playlists.select_prev(), - Focus::Songs => screen.shown_songs.select_prev(), - Focus::PlaylistsFilter(_) | Focus::SongsFilter(_) => {} - }, - }, - Tick => { state.now_playing.update(&state.player); state.visualizer.update()?; @@ -82,63 +80,23 @@ pub fn update(state: &mut State<'_>, tx: Tx, act: Action) -> Result { - let Screen::BrowseScreen(screen) = &mut state.screen; - if screen.selected_playlist() == Some(playlist.as_str()) { - screen.refresh_songs()?; - screen - .shown_songs - .select(Some(screen.shown_songs.items.len() - 1)); - } - } - RefreshSongs => { - let Screen::BrowseScreen(screen) = &mut state.screen; - screen.refresh_songs()?; - } - RefreshPlaylists => { - let Screen::BrowseScreen(screen) = &mut state.screen; - screen.refresh_playlists()?; - } - SelectSong(i) => { - let Screen::BrowseScreen(screen) = &mut state.screen; - screen.shown_songs.select(Some(i)); - } - SelectPlaylist(i) => { - let Screen::BrowseScreen(screen) = &mut state.screen; - screen.shown_playlists.select(Some(i)); - screen.refresh_songs()?; - } - - Command(cmd) => return handle_command(state, tx, cmd), } Ok(None) } -fn handle_command(state: &mut State<'_>, _tx: Tx, cmd: Command) -> Result> { +fn handle_command(state: &mut State<'_>, tx: Tx, cmd: Command) -> Result> { use Command::*; match cmd { + Esc | Play | QueueSong | QueueShown | OpenInBrowser | CopyUrl | CopyTitle + | NextSortingMode | SelectLeft | SelectNext | SelectRight | SelectPrev | Search + | GotoStart | GotoEnd => return screen_action(state, tx, Action::Command(cmd)), + Nop => {} Quit => { state.quit(); } - Esc => match &mut state.screen { - Screen::BrowseScreen(screen) => { - let focus = mem::take(&mut screen.focus); - screen.focus = match focus { - Focus::PlaylistsFilter(_) => Focus::Playlists, - Focus::SongsFilter(_) => Focus::Songs, - _ => focus, - }; - return Ok(Some(Action::RefreshPlaylists)); - } - }, - SeekForward => { state.player.seek(10.)?; return Ok(Some(Action::Tick)); @@ -148,28 +106,6 @@ fn handle_command(state: &mut State<'_>, _tx: Tx, cmd: Command) -> Result