Handle idle time between fetch results #212
@ -94,7 +94,6 @@ fn with<Database: IDatabase + 'static, Library: ILibrary + 'static>(
|
||||
let app = App::new(music_hoard, musicbrainz, app_sender);
|
||||
let ui = Ui;
|
||||
|
||||
|
||||
// Run the TUI application.
|
||||
Tui::run(terminal, app, ui, handler, listener).expect("failed to run tui");
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ use crate::tui::{
|
||||
app::{
|
||||
machine::{App, AppInner, AppMachine},
|
||||
selection::{Delta, ListSelection},
|
||||
AppMatchesInfo, AppPublic, AppState, IAppInteractBrowse,
|
||||
AppMatchesInfo, AppPublic, AppState, IAppBase, IAppInteractBrowse,
|
||||
},
|
||||
event::{Event, EventSender},
|
||||
lib::interface::musicbrainz::{self, IMusicBrainz},
|
||||
@ -183,6 +183,10 @@ impl IAppInteractBrowse for AppMachine<AppBrowse> {
|
||||
|
||||
AppMachine::app_fetch_new(self.inner, fetch_rx)
|
||||
}
|
||||
}
|
||||
|
||||
impl IAppBase for AppMachine<AppBrowse> {
|
||||
type APP = App;
|
||||
|
||||
fn no_op(self) -> Self::APP {
|
||||
self.into()
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::tui::app::{
|
||||
machine::{App, AppInner, AppMachine},
|
||||
AppPublic, AppState, IAppInteractCritical,
|
||||
AppPublic, AppState, IAppBase,
|
||||
};
|
||||
|
||||
pub struct AppCritical {
|
||||
@ -33,7 +33,7 @@ impl<'a> From<&'a mut AppMachine<AppCritical>> for AppPublic<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl IAppInteractCritical for AppMachine<AppCritical> {
|
||||
impl IAppBase for AppMachine<AppCritical> {
|
||||
type APP = App;
|
||||
|
||||
fn no_op(self) -> Self::APP {
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::tui::app::{
|
||||
machine::{App, AppInner, AppMachine},
|
||||
AppPublic, AppState, IAppInteractError,
|
||||
AppPublic, AppState, IAppBase, IAppInteractError,
|
||||
};
|
||||
|
||||
pub struct AppError {
|
||||
@ -39,6 +39,10 @@ impl IAppInteractError for AppMachine<AppError> {
|
||||
fn dismiss_error(self) -> Self::APP {
|
||||
AppMachine::browse(self.inner).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl IAppBase for AppMachine<AppError> {
|
||||
type APP = App;
|
||||
|
||||
fn no_op(self) -> Self::APP {
|
||||
self.into()
|
||||
|
@ -3,7 +3,7 @@ use std::sync::mpsc::{self, TryRecvError};
|
||||
use crate::tui::{
|
||||
app::{
|
||||
machine::{App, AppInner, AppMachine},
|
||||
AppMatchesInfo, AppPublic, AppState, IAppEventFetch, IAppInteractFetch,
|
||||
AppMatchesInfo, AppPublic, AppState, IAppBase, IAppEventFetch, IAppInteractFetch,
|
||||
},
|
||||
lib::interface::musicbrainz::Error as MbError,
|
||||
};
|
||||
@ -85,6 +85,10 @@ impl IAppInteractFetch for AppMachine<AppFetch> {
|
||||
fn abort(self) -> Self::APP {
|
||||
AppMachine::browse(self.inner).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl IAppBase for AppMachine<AppFetch> {
|
||||
type APP = App;
|
||||
|
||||
fn no_op(self) -> Self::APP {
|
||||
self.into()
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::tui::app::{
|
||||
machine::{App, AppInner, AppMachine},
|
||||
AppPublic, AppState, IAppInteractInfo,
|
||||
AppPublic, AppState, IAppBase, IAppInteractInfo,
|
||||
};
|
||||
|
||||
pub struct AppInfo;
|
||||
@ -35,6 +35,10 @@ impl IAppInteractInfo for AppMachine<AppInfo> {
|
||||
fn hide_info_overlay(self) -> Self::APP {
|
||||
AppMachine::browse(self.inner).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl IAppBase for AppMachine<AppInfo> {
|
||||
type APP = App;
|
||||
|
||||
fn no_op(self) -> Self::APP {
|
||||
self.into()
|
||||
|
@ -3,7 +3,7 @@ use std::cmp;
|
||||
use crate::tui::app::{
|
||||
machine::{App, AppInner, AppMachine},
|
||||
AppAlbumMatches, AppArtistMatches, AppMatchesInfo, AppPublic, AppPublicMatches, AppState,
|
||||
IAppInteractMatches, MatchOption, WidgetState,
|
||||
IAppBase, IAppInteractMatches, MatchOption, WidgetState,
|
||||
};
|
||||
|
||||
use super::fetch::AppFetch;
|
||||
@ -122,6 +122,10 @@ impl IAppInteractMatches for AppMachine<AppMatches> {
|
||||
fn abort(self) -> Self::APP {
|
||||
AppMachine::browse(self.inner).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl IAppBase for AppMachine<AppMatches> {
|
||||
type APP = App;
|
||||
|
||||
fn no_op(self) -> Self::APP {
|
||||
self.into()
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::tui::app::{
|
||||
machine::{App, AppInner, AppMachine},
|
||||
selection::KeySelection,
|
||||
AppPublic, AppState, IAppInteractReload,
|
||||
AppPublic, AppState, IAppBase, IAppInteractReload,
|
||||
};
|
||||
|
||||
pub struct AppReload;
|
||||
@ -53,6 +53,10 @@ impl IAppInteractReload for AppMachine<AppReload> {
|
||||
fn hide_reload_menu(self) -> Self::APP {
|
||||
AppMachine::browse(self.inner).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl IAppBase for AppMachine<AppReload> {
|
||||
type APP = App;
|
||||
|
||||
fn no_op(self) -> Self::APP {
|
||||
self.into()
|
||||
|
@ -6,7 +6,7 @@ use musichoard::collection::{album::Album, artist::Artist, track::Track};
|
||||
use crate::tui::app::{
|
||||
machine::{App, AppInner, AppMachine},
|
||||
selection::{ListSelection, SelectionState},
|
||||
AppPublic, AppState, Category, IAppInteractSearch,
|
||||
AppPublic, AppState, Category, IAppBase, IAppInteractSearch,
|
||||
};
|
||||
|
||||
// Unlikely that this covers all possible strings, but it should at least cover strings
|
||||
@ -98,6 +98,10 @@ impl IAppInteractSearch for AppMachine<AppSearch> {
|
||||
self.inner.selection.select_by_list(self.state.orig);
|
||||
AppMachine::browse(self.inner).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl IAppBase for AppMachine<AppSearch> {
|
||||
type APP = App;
|
||||
|
||||
fn no_op(self) -> Self::APP {
|
||||
self.into()
|
||||
|
@ -20,14 +20,14 @@ pub enum AppState<BS, IS, RS, SS, FS, MS, ES, CS> {
|
||||
}
|
||||
|
||||
pub trait IAppInteract {
|
||||
type BS: IAppInteractBrowse<APP = Self>;
|
||||
type IS: IAppInteractInfo<APP = Self>;
|
||||
type RS: IAppInteractReload<APP = Self>;
|
||||
type SS: IAppInteractSearch<APP = Self>;
|
||||
type FS: IAppInteractFetch<APP = Self> + IAppEventFetch<APP = Self>;
|
||||
type MS: IAppInteractMatches<APP = Self>;
|
||||
type ES: IAppInteractError<APP = Self>;
|
||||
type CS: IAppInteractCritical<APP = Self>;
|
||||
type BS: IAppBase<APP = Self> + IAppInteractBrowse<APP = Self>;
|
||||
type IS: IAppBase<APP = Self> + IAppInteractInfo<APP = Self>;
|
||||
type RS: IAppBase<APP = Self> + IAppInteractReload<APP = Self>;
|
||||
type SS: IAppBase<APP = Self> + IAppInteractSearch<APP = Self>;
|
||||
type FS: IAppBase<APP = Self> + IAppInteractFetch<APP = Self> + IAppEventFetch<APP = Self>;
|
||||
type MS: IAppBase<APP = Self> + IAppInteractMatches<APP = Self>;
|
||||
type ES: IAppBase<APP = Self> + IAppInteractError<APP = Self>;
|
||||
type CS: IAppBase<APP = Self>;
|
||||
|
||||
fn is_running(&self) -> bool;
|
||||
fn force_quit(self) -> Self;
|
||||
@ -38,6 +38,12 @@ pub trait IAppInteract {
|
||||
) -> AppState<Self::BS, Self::IS, Self::RS, Self::SS, Self::FS, Self::MS, Self::ES, Self::CS>;
|
||||
}
|
||||
|
||||
pub trait IAppBase {
|
||||
type APP: IAppInteract;
|
||||
|
||||
fn no_op(self) -> Self::APP;
|
||||
}
|
||||
|
||||
pub trait IAppInteractBrowse {
|
||||
type APP: IAppInteract;
|
||||
|
||||
@ -55,16 +61,12 @@ pub trait IAppInteractBrowse {
|
||||
fn begin_search(self) -> Self::APP;
|
||||
|
||||
fn fetch_musicbrainz(self) -> Self::APP;
|
||||
|
||||
fn no_op(self) -> Self::APP;
|
||||
}
|
||||
|
||||
pub trait IAppInteractInfo {
|
||||
type APP: IAppInteract;
|
||||
|
||||
fn hide_info_overlay(self) -> Self::APP;
|
||||
|
||||
fn no_op(self) -> Self::APP;
|
||||
}
|
||||
|
||||
pub trait IAppInteractReload {
|
||||
@ -73,8 +75,6 @@ pub trait IAppInteractReload {
|
||||
fn reload_library(self) -> Self::APP;
|
||||
fn reload_database(self) -> Self::APP;
|
||||
fn hide_reload_menu(self) -> Self::APP;
|
||||
|
||||
fn no_op(self) -> Self::APP;
|
||||
}
|
||||
|
||||
pub trait IAppInteractSearch {
|
||||
@ -85,16 +85,12 @@ pub trait IAppInteractSearch {
|
||||
fn step_back(self) -> Self::APP;
|
||||
fn finish_search(self) -> Self::APP;
|
||||
fn cancel_search(self) -> Self::APP;
|
||||
|
||||
fn no_op(self) -> Self::APP;
|
||||
}
|
||||
|
||||
pub trait IAppInteractFetch {
|
||||
type APP: IAppInteract;
|
||||
|
||||
fn abort(self) -> Self::APP;
|
||||
|
||||
fn no_op(self) -> Self::APP;
|
||||
}
|
||||
|
||||
pub trait IAppEventFetch {
|
||||
@ -111,22 +107,12 @@ pub trait IAppInteractMatches {
|
||||
fn select(self) -> Self::APP;
|
||||
|
||||
fn abort(self) -> Self::APP;
|
||||
|
||||
fn no_op(self) -> Self::APP;
|
||||
}
|
||||
|
||||
pub trait IAppInteractError {
|
||||
type APP: IAppInteract;
|
||||
|
||||
fn dismiss_error(self) -> Self::APP;
|
||||
|
||||
fn no_op(self) -> Self::APP;
|
||||
}
|
||||
|
||||
pub trait IAppInteractCritical {
|
||||
type APP: IAppInteract;
|
||||
|
||||
fn no_op(self) -> Self::APP;
|
||||
}
|
||||
|
||||
// It would be preferable to have a getter for each field separately. However, the selection field
|
||||
|
@ -5,14 +5,13 @@ use mockall::automock;
|
||||
|
||||
use crate::tui::{
|
||||
app::{
|
||||
AppState, Delta, IAppInteract, IAppInteractBrowse, IAppInteractCritical, IAppInteractError,
|
||||
IAppInteractFetch, IAppInteractInfo, IAppInteractMatches, IAppInteractReload,
|
||||
IAppInteractSearch,
|
||||
AppState, Delta, IAppInteract, IAppInteractBrowse, IAppInteractError, IAppInteractFetch,
|
||||
IAppInteractInfo, IAppInteractMatches, IAppInteractReload, IAppInteractSearch,
|
||||
},
|
||||
event::{Event, EventError, EventReceiver},
|
||||
};
|
||||
|
||||
use super::app::IAppEventFetch;
|
||||
use super::app::{IAppBase, IAppEventFetch};
|
||||
|
||||
#[cfg_attr(test, automock)]
|
||||
pub trait IEventHandler<APP: IAppInteract> {
|
||||
|
Loading…
Reference in New Issue
Block a user