From 9552311d026bc02696190c989d84d09cce8f3c9a Mon Sep 17 00:00:00 2001 From: Wojciech Kozlowski Date: Sun, 1 Sep 2024 22:14:45 +0200 Subject: [PATCH] Add fetch state --- src/tui/app/machine/fetch.rs | 46 ++++++++++++++++++++++++++++++++++++ src/tui/app/machine/mod.rs | 25 ++++++++++++++++---- src/tui/app/mod.rs | 19 +++++++++++---- src/tui/handler.rs | 16 ++++++++++++- src/tui/ui/minibuffer.rs | 18 +++++++++----- src/tui/ui/mod.rs | 1 + 6 files changed, 109 insertions(+), 16 deletions(-) create mode 100644 src/tui/app/machine/fetch.rs diff --git a/src/tui/app/machine/fetch.rs b/src/tui/app/machine/fetch.rs new file mode 100644 index 0000000..72d7199 --- /dev/null +++ b/src/tui/app/machine/fetch.rs @@ -0,0 +1,46 @@ +use crate::tui::app::{ + machine::{App, AppInner, AppMachine}, + AppPublic, AppState, IAppInteractFetch, +}; + +pub struct AppFetch; + +impl AppMachine { + pub fn fetch(inner: AppInner) -> Self { + AppMachine { + inner, + state: AppFetch, + } + } +} + +impl From> for App { + fn from(machine: AppMachine) -> Self { + AppState::Fetch(machine) + } +} + +impl<'a> From<&'a mut AppMachine> for AppPublic<'a> { + fn from(machine: &'a mut AppMachine) -> Self { + AppPublic { + inner: (&mut machine.inner).into(), + state: AppState::Fetch(()), + } + } +} + +impl IAppInteractFetch for AppMachine { + type APP = App; + + fn proceed(self) -> Self::APP { + self.into() + } + + fn abort(self) -> Self::APP { + AppMachine::browse(self.inner).into() + } + + fn no_op(self) -> Self::APP { + self.into() + } +} diff --git a/src/tui/app/machine/mod.rs b/src/tui/app/machine/mod.rs index 6aa186f..124b72e 100644 --- a/src/tui/app/machine/mod.rs +++ b/src/tui/app/machine/mod.rs @@ -1,6 +1,7 @@ mod browse; mod critical; mod error; +mod fetch; mod info; mod matches; mod reload; @@ -16,6 +17,7 @@ use crate::tui::{ use browse::AppBrowse; use critical::AppCritical; use error::AppError; +use fetch::AppFetch; use info::AppInfo; use matches::AppMatches; use reload::AppReload; @@ -26,6 +28,7 @@ pub type App = AppState< AppMachine, AppMachine, AppMachine, + AppMachine, AppMachine, AppMachine, AppMachine, @@ -65,9 +68,10 @@ impl App { match self { AppState::Browse(browse) => &browse.inner, AppState::Info(info) => &info.inner, - AppState::Matches(matches) => &matches.inner, AppState::Reload(reload) => &reload.inner, AppState::Search(search) => &search.inner, + AppState::Fetch(fetch) => &fetch.inner, + AppState::Matches(matches) => &matches.inner, AppState::Error(error) => &error.inner, AppState::Critical(critical) => &critical.inner, } @@ -77,9 +81,10 @@ impl App { match self { AppState::Browse(browse) => &mut browse.inner, AppState::Info(info) => &mut info.inner, - AppState::Matches(matches) => &mut matches.inner, AppState::Reload(reload) => &mut reload.inner, AppState::Search(search) => &mut search.inner, + AppState::Fetch(fetch) => &mut fetch.inner, + AppState::Matches(matches) => &mut matches.inner, AppState::Error(error) => &mut error.inner, AppState::Critical(critical) => &mut critical.inner, } @@ -91,6 +96,7 @@ impl IAppInteract for App { type IS = AppMachine; type RS = AppMachine; type SS = AppMachine; + type FS = AppMachine; type MS = AppMachine; type ES = AppMachine; type CS = AppMachine; @@ -106,7 +112,8 @@ impl IAppInteract for App { fn state( self, - ) -> AppState { + ) -> AppState + { self } } @@ -116,9 +123,10 @@ impl IAppAccess for App { match self { AppState::Browse(browse) => browse.into(), AppState::Info(info) => info.into(), - AppState::Matches(matches) => matches.into(), AppState::Reload(reload) => reload.into(), AppState::Search(search) => search.into(), + AppState::Fetch(fetch) => fetch.into(), + AppState::Matches(matches) => matches.into(), AppState::Error(error) => error.into(), AppState::Critical(critical) => critical.into(), } @@ -162,7 +170,7 @@ mod tests { use super::*; - impl AppState { + impl AppState { pub fn unwrap_browse(self) -> BS { match self { AppState::Browse(browse) => browse, @@ -191,6 +199,13 @@ mod tests { } } + pub fn unwrap_fetch(self) -> FS { + match self { + AppState::Fetch(fetch) => fetch, + _ => panic!(), + } + } + pub fn unwrap_matches(self) -> MS { match self { AppState::Matches(matches) => matches, diff --git a/src/tui/app/mod.rs b/src/tui/app/mod.rs index 4d14aef..4c14370 100644 --- a/src/tui/app/mod.rs +++ b/src/tui/app/mod.rs @@ -8,11 +8,12 @@ use musichoard::collection::{album::AlbumMeta, artist::ArtistMeta, Collection}; use crate::tui::lib::interface::musicbrainz::Match; -pub enum AppState { +pub enum AppState { Browse(BS), Info(IS), Reload(RS), Search(SS), + Fetch(FS), Matches(MS), Error(ES), Critical(CS), @@ -23,6 +24,7 @@ pub trait IAppInteract { type IS: IAppInteractInfo; type RS: IAppInteractReload; type SS: IAppInteractSearch; + type FS: IAppInteractFetch; type MS: IAppInteractMatches; type ES: IAppInteractError; type CS: IAppInteractCritical; @@ -33,7 +35,7 @@ pub trait IAppInteract { #[allow(clippy::type_complexity)] fn state( self, - ) -> AppState; + ) -> AppState; } pub trait IAppInteractBrowse { @@ -87,6 +89,15 @@ pub trait IAppInteractSearch { fn no_op(self) -> Self::APP; } +pub trait IAppInteractFetch { + type APP: IAppInteract; + + fn proceed(self) -> Self::APP; + fn abort(self) -> Self::APP; + + fn no_op(self) -> Self::APP; +} + pub trait IAppInteractMatches { type APP: IAppInteract; @@ -177,9 +188,9 @@ pub struct AppPublicMatches<'app> { } pub type AppPublicState<'app> = - AppState<(), (), (), &'app str, AppPublicMatches<'app>, &'app str, &'app str>; + AppState<(), (), (), &'app str, (), AppPublicMatches<'app>, &'app str, &'app str>; -impl AppState { +impl AppState { pub fn is_search(&self) -> bool { matches!(self, AppState::Search(_)) } diff --git a/src/tui/handler.rs b/src/tui/handler.rs index 13f4ec1..bb2e09c 100644 --- a/src/tui/handler.rs +++ b/src/tui/handler.rs @@ -6,7 +6,8 @@ use mockall::automock; use crate::tui::{ app::{ AppState, Delta, IAppInteract, IAppInteractBrowse, IAppInteractCritical, IAppInteractError, - IAppInteractInfo, IAppInteractMatches, IAppInteractReload, IAppInteractSearch, + IAppInteractFetch, IAppInteractInfo, IAppInteractMatches, IAppInteractReload, + IAppInteractSearch, }, event::{Event, EventError, EventReceiver}, }; @@ -22,6 +23,7 @@ trait IEventHandlerPrivate { fn handle_info_key_event(app: ::IS, key_event: KeyEvent) -> APP; fn handle_reload_key_event(app: ::RS, key_event: KeyEvent) -> APP; fn handle_search_key_event(app: ::SS, key_event: KeyEvent) -> APP; + fn handle_fetch_key_event(app: ::FS, key_event: KeyEvent) -> APP; fn handle_matches_key_event(app: ::MS, key_event: KeyEvent) -> APP; fn handle_error_key_event(app: ::ES, key_event: KeyEvent) -> APP; fn handle_critical_key_event(app: ::CS, key_event: KeyEvent) -> APP; @@ -70,6 +72,9 @@ impl IEventHandlerPrivate for EventHandler { AppState::Search(search) => { >::handle_search_key_event(search, key_event) } + AppState::Fetch(fetch) => { + >::handle_fetch_key_event(fetch, key_event) + } AppState::Matches(matches) => { >::handle_matches_key_event(matches, key_event) } @@ -161,6 +166,15 @@ impl IEventHandlerPrivate for EventHandler { } } + fn handle_fetch_key_event(app: ::FS, key_event: KeyEvent) -> APP { + match key_event.code { + // Abort. + KeyCode::Esc | KeyCode::Char('q') | KeyCode::Char('Q') => app.abort(), + // Othey keys. + _ => app.no_op(), + } + } + fn handle_matches_key_event(app: ::MS, key_event: KeyEvent) -> APP { match key_event.code { // Abort. diff --git a/src/tui/ui/minibuffer.rs b/src/tui/ui/minibuffer.rs index 3e6e0f1..2e482a8 100644 --- a/src/tui/ui/minibuffer.rs +++ b/src/tui/ui/minibuffer.rs @@ -27,7 +27,7 @@ impl Minibuffer<'_> { pub fn new(state: &AppPublicState) -> Self { let columns = 3; let mut mb = match state { - AppState::Browse(_) => Minibuffer { + AppState::Browse(()) => Minibuffer { paragraphs: vec![ Paragraph::new("m: show info overlay"), Paragraph::new("g: show reload menu"), @@ -36,11 +36,11 @@ impl Minibuffer<'_> { ], columns, }, - AppState::Info(_) => Minibuffer { + AppState::Info(()) => Minibuffer { paragraphs: vec![Paragraph::new("m: hide info overlay")], columns, }, - AppState::Reload(_) => Minibuffer { + AppState::Reload(()) => Minibuffer { paragraphs: vec![ Paragraph::new("g: hide reload menu"), Paragraph::new("d: reload database"), @@ -51,12 +51,18 @@ impl Minibuffer<'_> { AppState::Search(ref s) => Minibuffer { paragraphs: vec![ Paragraph::new(format!("I-search: {s}")), - Paragraph::new("ctrl+s: search next".to_string()).alignment(Alignment::Center), - Paragraph::new("ctrl+g: cancel search".to_string()) - .alignment(Alignment::Center), + Paragraph::new("ctrl+s: search next").alignment(Alignment::Center), + Paragraph::new("ctrl+g: cancel search").alignment(Alignment::Center), ], columns, }, + AppState::Fetch(()) => Minibuffer { + paragraphs: vec![ + Paragraph::new(format!("fetching...")), + Paragraph::new(format!("q: abort")), + ], + columns: 2, + }, AppState::Matches(public) => Minibuffer { paragraphs: vec![ Paragraph::new(UiDisplay::display_matching_info(public.matches)), diff --git a/src/tui/ui/mod.rs b/src/tui/ui/mod.rs index 3855b7b..02f6d1e 100644 --- a/src/tui/ui/mod.rs +++ b/src/tui/ui/mod.rs @@ -203,6 +203,7 @@ mod tests { AppState::Info(()) => AppState::Info(()), AppState::Reload(()) => AppState::Reload(()), AppState::Search(s) => AppState::Search(s), + AppState::Fetch(()) => AppState::Fetch(()), AppState::Matches(ref mut m) => AppState::Matches(AppPublicMatches { matches: m.matches, state: m.state,