Improvements

This commit is contained in:
Wojciech Kozlowski 2024-02-17 21:44:22 +01:00
parent c2920aac81
commit e96963f37a
3 changed files with 258 additions and 329 deletions

View File

@ -1,3 +1,4 @@
// FIXME: Split file apart
#![allow(clippy::module_inception)] #![allow(clippy::module_inception)]
use musichoard::collection::Collection; use musichoard::collection::Collection;
@ -7,7 +8,6 @@ use crate::tui::{
lib::IMusicHoard, lib::IMusicHoard,
}; };
#[derive(Copy, Clone)]
pub enum AppState<BS, IS, RS, SS, ES, CS> { pub enum AppState<BS, IS, RS, SS, ES, CS> {
Browse(BS), Browse(BS),
Info(IS), Info(IS),
@ -110,9 +110,13 @@ pub trait IAppAccess {
pub type AppPublicState<'app> = AppState<(), (), (), &'app str, &'app str, &'app str>; pub type AppPublicState<'app> = AppState<(), (), (), &'app str, &'app str, &'app str>;
pub struct AppPublic<'app> { pub struct AppPublic<'app> {
pub inner: AppPublicInner<'app>,
pub state: AppPublicState<'app>,
}
pub struct AppPublicInner<'app> {
pub collection: &'app Collection, pub collection: &'app Collection,
pub selection: &'app mut Selection, pub selection: &'app mut Selection,
pub state: AppPublicState<'app>,
} }
struct AppInner<MH: IMusicHoard> { struct AppInner<MH: IMusicHoard> {
@ -130,11 +134,13 @@ pub type App<MH> = AppState<
AppErrorState<MH>, AppErrorState<MH>,
>; >;
pub struct AppGenericState<MH: IMusicHoard>(AppInner<MH>); pub struct AppGenericState<MH: IMusicHoard> {
inner: AppInner<MH>,
}
pub struct AppSearchState<MH: IMusicHoard> { pub struct AppSearchState<MH: IMusicHoard> {
inner: AppInner<MH>, inner: AppInner<MH>,
search: String, string: String,
orig: ListSelection, orig: ListSelection,
memo: Vec<AppSearchMemo>, memo: Vec<AppSearchMemo>,
} }
@ -146,7 +152,7 @@ struct AppSearchMemo {
pub struct AppErrorState<MH: IMusicHoard> { pub struct AppErrorState<MH: IMusicHoard> {
inner: AppInner<MH>, inner: AppInner<MH>,
msg: String, string: String,
} }
impl<MH: IMusicHoard> App<MH> { impl<MH: IMusicHoard> App<MH> {
@ -159,10 +165,10 @@ impl<MH: IMusicHoard> App<MH> {
selection, selection,
}; };
match init_result { match init_result {
Ok(()) => Self::Browse(AppGenericState(inner)), Ok(()) => Self::Browse(AppGenericState { inner }),
Err(err) => Self::Critical(AppErrorState { Err(err) => Self::Critical(AppErrorState {
inner, inner,
msg: err.to_string(), string: err.to_string(),
}), }),
} }
} }
@ -175,7 +181,9 @@ impl<MH: IMusicHoard> App<MH> {
fn inner_ref(&self) -> &AppInner<MH> { fn inner_ref(&self) -> &AppInner<MH> {
match self { match self {
AppState::Browse(inner) | AppState::Info(inner) | AppState::Reload(inner) => &inner.0, AppState::Browse(generic) | AppState::Info(generic) | AppState::Reload(generic) => {
&generic.inner
}
AppState::Search(search) => &search.inner, AppState::Search(search) => &search.inner,
AppState::Error(error) | AppState::Critical(error) => &error.inner, AppState::Error(error) | AppState::Critical(error) => &error.inner,
} }
@ -183,8 +191,8 @@ impl<MH: IMusicHoard> App<MH> {
fn inner_mut(&mut self) -> &mut AppInner<MH> { fn inner_mut(&mut self) -> &mut AppInner<MH> {
match self { match self {
AppState::Browse(inner) | AppState::Info(inner) | AppState::Reload(inner) => { AppState::Browse(generic) | AppState::Info(generic) | AppState::Reload(generic) => {
&mut inner.0 &mut generic.inner
} }
AppState::Search(search) => &mut search.inner, AppState::Search(search) => &mut search.inner,
AppState::Error(error) | AppState::Critical(error) => &mut error.inner, AppState::Error(error) | AppState::Critical(error) => &mut error.inner,
@ -218,39 +226,39 @@ impl<MH: IMusicHoard> IAppInteractBrowse for AppGenericState<MH> {
type APP = App<MH>; type APP = App<MH>;
fn save_and_quit(mut self) -> Self::APP { fn save_and_quit(mut self) -> Self::APP {
match self.0.music_hoard.save_to_database() { match self.inner.music_hoard.save_to_database() {
Ok(_) => { Ok(_) => {
self.0.running = false; self.inner.running = false;
AppState::Browse(self) AppState::Browse(self)
} }
Err(err) => AppState::Error(AppErrorState { Err(err) => AppState::Error(AppErrorState {
inner: self.0, inner: self.inner,
msg: err.to_string(), string: err.to_string(),
}), }),
} }
} }
fn increment_category(mut self) -> Self::APP { fn increment_category(mut self) -> Self::APP {
self.0.selection.increment_category(); self.inner.selection.increment_category();
AppState::Browse(self) AppState::Browse(self)
} }
fn decrement_category(mut self) -> Self::APP { fn decrement_category(mut self) -> Self::APP {
self.0.selection.decrement_category(); self.inner.selection.decrement_category();
AppState::Browse(self) AppState::Browse(self)
} }
fn increment_selection(mut self, delta: Delta) -> Self::APP { fn increment_selection(mut self, delta: Delta) -> Self::APP {
self.0 self.inner
.selection .selection
.increment_selection(self.0.music_hoard.get_collection(), delta); .increment_selection(self.inner.music_hoard.get_collection(), delta);
AppState::Browse(self) AppState::Browse(self)
} }
fn decrement_selection(mut self, delta: Delta) -> Self::APP { fn decrement_selection(mut self, delta: Delta) -> Self::APP {
self.0 self.inner
.selection .selection
.decrement_selection(self.0.music_hoard.get_collection(), delta); .decrement_selection(self.inner.music_hoard.get_collection(), delta);
AppState::Browse(self) AppState::Browse(self)
} }
@ -263,13 +271,13 @@ impl<MH: IMusicHoard> IAppInteractBrowse for AppGenericState<MH> {
} }
fn begin_search(mut self) -> Self::APP { fn begin_search(mut self) -> Self::APP {
let orig = ListSelection::get(&self.0.selection); let orig = ListSelection::get(&self.inner.selection);
self.0 self.inner
.selection .selection
.reset_artist(self.0.music_hoard.get_collection()); .reset_artist(self.inner.music_hoard.get_collection());
AppState::Search(AppSearchState { AppState::Search(AppSearchState {
inner: self.0, inner: self.inner,
search: String::new(), string: String::new(),
orig, orig,
memo: vec![], memo: vec![],
}) })
@ -284,7 +292,7 @@ impl<MH: IMusicHoard> IAppInteractInfo for AppGenericState<MH> {
type APP = App<MH>; type APP = App<MH>;
fn hide_info_overlay(self) -> Self::APP { fn hide_info_overlay(self) -> Self::APP {
AppState::Browse(AppGenericState(self.0)) AppState::Browse(AppGenericState { inner: self.inner })
} }
fn no_op(self) -> Self::APP { fn no_op(self) -> Self::APP {
@ -296,19 +304,25 @@ impl<MH: IMusicHoard> IAppInteractReload for AppGenericState<MH> {
type APP = App<MH>; type APP = App<MH>;
fn reload_library(mut self) -> Self::APP { fn reload_library(mut self) -> Self::APP {
let previous = IdSelection::get(self.0.music_hoard.get_collection(), &self.0.selection); let previous = IdSelection::get(
let result = self.0.music_hoard.rescan_library(); self.inner.music_hoard.get_collection(),
&self.inner.selection,
);
let result = self.inner.music_hoard.rescan_library();
self.refresh(previous, result) self.refresh(previous, result)
} }
fn reload_database(mut self) -> Self::APP { fn reload_database(mut self) -> Self::APP {
let previous = IdSelection::get(self.0.music_hoard.get_collection(), &self.0.selection); let previous = IdSelection::get(
let result = self.0.music_hoard.load_from_database(); self.inner.music_hoard.get_collection(),
&self.inner.selection,
);
let result = self.inner.music_hoard.load_from_database();
self.refresh(previous, result) self.refresh(previous, result)
} }
fn hide_reload_menu(self) -> Self::APP { fn hide_reload_menu(self) -> Self::APP {
AppState::Browse(AppGenericState(self.0)) AppState::Browse(AppGenericState { inner: self.inner })
} }
fn no_op(self) -> Self::APP { fn no_op(self) -> Self::APP {
@ -324,14 +338,14 @@ impl<MH: IMusicHoard> IAppInteractReloadPrivate<MH> for AppGenericState<MH> {
fn refresh(mut self, previous: IdSelection, result: Result<(), musichoard::Error>) -> App<MH> { fn refresh(mut self, previous: IdSelection, result: Result<(), musichoard::Error>) -> App<MH> {
match result { match result {
Ok(()) => { Ok(()) => {
self.0 self.inner
.selection .selection
.select_by_id(self.0.music_hoard.get_collection(), previous); .select_by_id(self.inner.music_hoard.get_collection(), previous);
AppState::Browse(AppGenericState(self.0)) AppState::Browse(AppGenericState { inner: self.inner })
} }
Err(err) => AppState::Error(AppErrorState { Err(err) => AppState::Error(AppErrorState {
inner: self.0, inner: self.inner,
msg: err.to_string(), string: err.to_string(),
}), }),
} }
} }
@ -342,22 +356,22 @@ impl<MH: IMusicHoard> IAppInteractSearch for AppSearchState<MH> {
fn append_character(mut self, ch: char) -> Self::APP { fn append_character(mut self, ch: char) -> Self::APP {
let collection = self.inner.music_hoard.get_collection(); let collection = self.inner.music_hoard.get_collection();
self.search.push(ch); self.string.push(ch);
let index = self let index = self
.inner .inner
.selection .selection
.incremental_artist_search(collection, &self.search, false); .incremental_artist_search(collection, &self.string, false);
self.memo.push(AppSearchMemo { index, char: true }); self.memo.push(AppSearchMemo { index, char: true });
AppState::Search(self) AppState::Search(self)
} }
fn search_next(mut self) -> Self::APP { fn search_next(mut self) -> Self::APP {
let collection = self.inner.music_hoard.get_collection(); let collection = self.inner.music_hoard.get_collection();
if !self.search.is_empty() { if !self.string.is_empty() {
let index = let index =
self.inner self.inner
.selection .selection
.incremental_artist_search(collection, &self.search, true); .incremental_artist_search(collection, &self.string, true);
self.memo.push(AppSearchMemo { index, char: false }); self.memo.push(AppSearchMemo { index, char: false });
} }
AppState::Search(self) AppState::Search(self)
@ -367,7 +381,7 @@ impl<MH: IMusicHoard> IAppInteractSearch for AppSearchState<MH> {
let collection = self.inner.music_hoard.get_collection(); let collection = self.inner.music_hoard.get_collection();
if let Some(memo) = self.memo.pop() { if let Some(memo) = self.memo.pop() {
if memo.char { if memo.char {
self.search.pop(); self.string.pop();
} }
self.inner.selection.select_artist(collection, memo.index); self.inner.selection.select_artist(collection, memo.index);
} }
@ -375,12 +389,12 @@ impl<MH: IMusicHoard> IAppInteractSearch for AppSearchState<MH> {
} }
fn finish_search(self) -> Self::APP { fn finish_search(self) -> Self::APP {
AppState::Browse(AppGenericState(self.inner)) AppState::Browse(AppGenericState { inner: self.inner })
} }
fn cancel_search(mut self) -> Self::APP { fn cancel_search(mut self) -> Self::APP {
self.inner.selection.select_by_list(self.orig); self.inner.selection.select_by_list(self.orig);
AppState::Browse(AppGenericState(self.inner)) AppState::Browse(AppGenericState { inner: self.inner })
} }
fn no_op(self) -> Self::APP { fn no_op(self) -> Self::APP {
@ -392,7 +406,7 @@ impl<MH: IMusicHoard> IAppInteractError for AppErrorState<MH> {
type APP = App<MH>; type APP = App<MH>;
fn dismiss_error(self) -> Self::APP { fn dismiss_error(self) -> Self::APP {
AppState::Browse(AppGenericState(self.inner)) AppState::Browse(AppGenericState { inner: self.inner })
} }
} }
@ -408,39 +422,42 @@ impl<MH: IMusicHoard> IAppAccess for App<MH> {
fn get(&mut self) -> AppPublic { fn get(&mut self) -> AppPublic {
match self { match self {
AppState::Browse(generic) => AppPublic { AppState::Browse(generic) => AppPublic {
collection: generic.0.music_hoard.get_collection(), inner: (&mut generic.inner).into(),
selection: &mut generic.0.selection,
state: AppState::Browse(()), state: AppState::Browse(()),
}, },
AppState::Info(generic) => AppPublic { AppState::Info(generic) => AppPublic {
collection: generic.0.music_hoard.get_collection(), inner: (&mut generic.inner).into(),
selection: &mut generic.0.selection,
state: AppState::Info(()), state: AppState::Info(()),
}, },
AppState::Reload(generic) => AppPublic { AppState::Reload(generic) => AppPublic {
collection: generic.0.music_hoard.get_collection(), inner: (&mut generic.inner).into(),
selection: &mut generic.0.selection,
state: AppState::Reload(()), state: AppState::Reload(()),
}, },
AppState::Search(search) => AppPublic { AppState::Search(search) => AppPublic {
collection: search.inner.music_hoard.get_collection(), inner: (&mut search.inner).into(),
selection: &mut search.inner.selection, state: AppState::Search(&search.string),
state: AppState::Search(&search.search),
}, },
AppState::Error(error) => AppPublic { AppState::Error(error) => AppPublic {
collection: error.inner.music_hoard.get_collection(), inner: (&mut error.inner).into(),
selection: &mut error.inner.selection, state: AppState::Error(&error.string),
state: AppState::Error(&error.msg),
}, },
AppState::Critical(critical) => AppPublic { AppState::Critical(critical) => AppPublic {
collection: critical.inner.music_hoard.get_collection(), inner: (&mut critical.inner).into(),
selection: &mut critical.inner.selection, state: AppState::Error(&critical.string),
state: AppState::Error(&critical.msg),
}, },
} }
} }
} }
impl<'app, MH: IMusicHoard> From<&'app mut AppInner<MH>> for AppPublicInner<'app> {
fn from(inner: &'app mut AppInner<MH>) -> Self {
AppPublicInner {
collection: inner.music_hoard.get_collection(),
selection: &mut inner.selection,
}
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::tui::{app::selection::Category, lib::MockIMusicHoard, testmod::COLLECTION}; use crate::tui::{app::selection::Category, lib::MockIMusicHoard, testmod::COLLECTION};
@ -544,8 +561,8 @@ mod tests {
assert!(app.is_running()); assert!(app.is_running());
let app = App::Error(AppErrorState { let app = App::Error(AppErrorState {
inner: app.unwrap_browse().0, inner: app.unwrap_browse().inner,
msg: String::from("get rekt"), string: String::from("get rekt"),
}); });
let error = app.unwrap_error(); let error = app.unwrap_error();
@ -571,8 +588,8 @@ mod tests {
assert!(app.is_running()); assert!(app.is_running());
let app = App::Error(AppErrorState { let app = App::Error(AppErrorState {
inner: app.unwrap_browse().0, inner: app.unwrap_browse().inner,
msg: String::from("get rekt"), string: String::from("get rekt"),
}); });
let app = app.force_quit(); let app = app.force_quit();
@ -630,166 +647,101 @@ mod tests {
let browse = app.unwrap_browse(); let browse = app.unwrap_browse();
assert_eq!(browse.0.selection.active, Category::Artist); let selection = &browse.inner.selection;
assert_eq!(browse.0.selection.artist.state.list.selected(), Some(0)); assert_eq!(selection.active, Category::Artist);
assert_eq!( assert_eq!(selection.artist.state.list.selected(), Some(0));
browse.0.selection.artist.album.state.list.selected(), assert_eq!(selection.artist.album.state.list.selected(), Some(0));
Some(0) assert_eq!(selection.artist.album.track.state.list.selected(), Some(0));
);
assert_eq!(
browse.0.selection.artist.album.track.state.list.selected(),
Some(0)
);
let browse = browse.increment_selection(Delta::Line).unwrap_browse(); let browse = browse.increment_selection(Delta::Line).unwrap_browse();
assert_eq!(browse.0.selection.active, Category::Artist); let selection = &browse.inner.selection;
assert_eq!(browse.0.selection.artist.state.list.selected(), Some(1)); assert_eq!(selection.active, Category::Artist);
assert_eq!( assert_eq!(selection.artist.state.list.selected(), Some(1));
browse.0.selection.artist.album.state.list.selected(), assert_eq!(selection.artist.album.state.list.selected(), Some(0));
Some(0) assert_eq!(selection.artist.album.track.state.list.selected(), Some(0));
);
assert_eq!(
browse.0.selection.artist.album.track.state.list.selected(),
Some(0)
);
let browse = browse.increment_category().unwrap_browse(); let browse = browse.increment_category().unwrap_browse();
assert_eq!(browse.0.selection.active, Category::Album); let selection = &browse.inner.selection;
assert_eq!(browse.0.selection.artist.state.list.selected(), Some(1)); assert_eq!(selection.active, Category::Album);
assert_eq!( assert_eq!(selection.artist.state.list.selected(), Some(1));
browse.0.selection.artist.album.state.list.selected(), assert_eq!(selection.artist.album.state.list.selected(), Some(0));
Some(0) assert_eq!(selection.artist.album.track.state.list.selected(), Some(0));
);
assert_eq!(
browse.0.selection.artist.album.track.state.list.selected(),
Some(0)
);
let browse = browse.increment_selection(Delta::Line).unwrap_browse(); let browse = browse.increment_selection(Delta::Line).unwrap_browse();
assert_eq!(browse.0.selection.active, Category::Album); let selection = &browse.inner.selection;
assert_eq!(browse.0.selection.artist.state.list.selected(), Some(1)); assert_eq!(selection.active, Category::Album);
assert_eq!( assert_eq!(selection.artist.state.list.selected(), Some(1));
browse.0.selection.artist.album.state.list.selected(), assert_eq!(selection.artist.album.state.list.selected(), Some(1));
Some(1) assert_eq!(selection.artist.album.track.state.list.selected(), Some(0));
);
assert_eq!(
browse.0.selection.artist.album.track.state.list.selected(),
Some(0)
);
let browse = browse.increment_category().unwrap_browse(); let browse = browse.increment_category().unwrap_browse();
assert_eq!(browse.0.selection.active, Category::Track); let selection = &browse.inner.selection;
assert_eq!(browse.0.selection.artist.state.list.selected(), Some(1)); assert_eq!(selection.active, Category::Track);
assert_eq!( assert_eq!(selection.artist.state.list.selected(), Some(1));
browse.0.selection.artist.album.state.list.selected(), assert_eq!(selection.artist.album.state.list.selected(), Some(1));
Some(1) assert_eq!(selection.artist.album.track.state.list.selected(), Some(0));
);
assert_eq!(
browse.0.selection.artist.album.track.state.list.selected(),
Some(0)
);
let browse = browse.increment_selection(Delta::Line).unwrap_browse(); let browse = browse.increment_selection(Delta::Line).unwrap_browse();
assert_eq!(browse.0.selection.active, Category::Track); let selection = &browse.inner.selection;
assert_eq!(browse.0.selection.artist.state.list.selected(), Some(1)); assert_eq!(selection.active, Category::Track);
assert_eq!( assert_eq!(selection.artist.state.list.selected(), Some(1));
browse.0.selection.artist.album.state.list.selected(), assert_eq!(selection.artist.album.state.list.selected(), Some(1));
Some(1) assert_eq!(selection.artist.album.track.state.list.selected(), Some(1));
);
assert_eq!(
browse.0.selection.artist.album.track.state.list.selected(),
Some(1)
);
let browse = browse.increment_category().unwrap_browse(); let browse = browse.increment_category().unwrap_browse();
assert_eq!(browse.0.selection.active, Category::Track); let selection = &browse.inner.selection;
assert_eq!(browse.0.selection.artist.state.list.selected(), Some(1)); assert_eq!(selection.active, Category::Track);
assert_eq!( assert_eq!(selection.artist.state.list.selected(), Some(1));
browse.0.selection.artist.album.state.list.selected(), assert_eq!(selection.artist.album.state.list.selected(), Some(1));
Some(1) assert_eq!(selection.artist.album.track.state.list.selected(), Some(1));
);
assert_eq!(
browse.0.selection.artist.album.track.state.list.selected(),
Some(1)
);
let browse = browse.decrement_selection(Delta::Line).unwrap_browse(); let browse = browse.decrement_selection(Delta::Line).unwrap_browse();
assert_eq!(browse.0.selection.active, Category::Track); let selection = &browse.inner.selection;
assert_eq!(browse.0.selection.artist.state.list.selected(), Some(1)); assert_eq!(selection.active, Category::Track);
assert_eq!( assert_eq!(selection.artist.state.list.selected(), Some(1));
browse.0.selection.artist.album.state.list.selected(), assert_eq!(selection.artist.album.state.list.selected(), Some(1));
Some(1) assert_eq!(selection.artist.album.track.state.list.selected(), Some(0));
);
assert_eq!(
browse.0.selection.artist.album.track.state.list.selected(),
Some(0)
);
let browse = browse.increment_selection(Delta::Line).unwrap_browse(); let browse = browse.increment_selection(Delta::Line).unwrap_browse();
let browse = browse.decrement_category().unwrap_browse(); let browse = browse.decrement_category().unwrap_browse();
assert_eq!(browse.0.selection.active, Category::Album); let selection = &browse.inner.selection;
assert_eq!(browse.0.selection.artist.state.list.selected(), Some(1)); assert_eq!(selection.active, Category::Album);
assert_eq!( assert_eq!(selection.artist.state.list.selected(), Some(1));
browse.0.selection.artist.album.state.list.selected(), assert_eq!(selection.artist.album.state.list.selected(), Some(1));
Some(1) assert_eq!(selection.artist.album.track.state.list.selected(), Some(1));
);
assert_eq!(
browse.0.selection.artist.album.track.state.list.selected(),
Some(1)
);
let browse = browse.decrement_selection(Delta::Line).unwrap_browse(); let browse = browse.decrement_selection(Delta::Line).unwrap_browse();
assert_eq!(browse.0.selection.active, Category::Album); let selection = &browse.inner.selection;
assert_eq!(browse.0.selection.artist.state.list.selected(), Some(1)); assert_eq!(selection.active, Category::Album);
assert_eq!( assert_eq!(selection.artist.state.list.selected(), Some(1));
browse.0.selection.artist.album.state.list.selected(), assert_eq!(selection.artist.album.state.list.selected(), Some(0));
Some(0) assert_eq!(selection.artist.album.track.state.list.selected(), Some(0));
);
assert_eq!(
browse.0.selection.artist.album.track.state.list.selected(),
Some(0)
);
let browse = browse.increment_selection(Delta::Line).unwrap_browse(); let browse = browse.increment_selection(Delta::Line).unwrap_browse();
let browse = browse.decrement_category().unwrap_browse(); let browse = browse.decrement_category().unwrap_browse();
assert_eq!(browse.0.selection.active, Category::Artist); let selection = &browse.inner.selection;
assert_eq!(browse.0.selection.artist.state.list.selected(), Some(1)); assert_eq!(selection.active, Category::Artist);
assert_eq!( assert_eq!(selection.artist.state.list.selected(), Some(1));
browse.0.selection.artist.album.state.list.selected(), assert_eq!(selection.artist.album.state.list.selected(), Some(1));
Some(1) assert_eq!(selection.artist.album.track.state.list.selected(), Some(0));
);
assert_eq!(
browse.0.selection.artist.album.track.state.list.selected(),
Some(0)
);
let browse = browse.decrement_selection(Delta::Line).unwrap_browse(); let browse = browse.decrement_selection(Delta::Line).unwrap_browse();
assert_eq!(browse.0.selection.active, Category::Artist); let selection = &browse.inner.selection;
assert_eq!(browse.0.selection.artist.state.list.selected(), Some(0)); assert_eq!(selection.active, Category::Artist);
assert_eq!( assert_eq!(selection.artist.state.list.selected(), Some(0));
browse.0.selection.artist.album.state.list.selected(), assert_eq!(selection.artist.album.state.list.selected(), Some(0));
Some(0) assert_eq!(selection.artist.album.track.state.list.selected(), Some(0));
);
assert_eq!(
browse.0.selection.artist.album.track.state.list.selected(),
Some(0)
);
let browse = browse.increment_category().unwrap_browse(); let browse = browse.increment_category().unwrap_browse();
let browse = browse.increment_selection(Delta::Line).unwrap_browse(); let browse = browse.increment_selection(Delta::Line).unwrap_browse();
let browse = browse.decrement_category().unwrap_browse(); let browse = browse.decrement_category().unwrap_browse();
let browse = browse.decrement_selection(Delta::Line).unwrap_browse(); let browse = browse.decrement_selection(Delta::Line).unwrap_browse();
let browse = browse.decrement_category().unwrap_browse(); let browse = browse.decrement_category().unwrap_browse();
assert_eq!(browse.0.selection.active, Category::Artist); let selection = &browse.inner.selection;
assert_eq!(browse.0.selection.artist.state.list.selected(), Some(0)); assert_eq!(selection.active, Category::Artist);
assert_eq!( assert_eq!(selection.artist.state.list.selected(), Some(0));
browse.0.selection.artist.album.state.list.selected(), assert_eq!(selection.artist.album.state.list.selected(), Some(1));
Some(1) assert_eq!(selection.artist.album.track.state.list.selected(), Some(0));
);
assert_eq!(
browse.0.selection.artist.album.track.state.list.selected(),
Some(0)
);
} }
#[test] #[test]
@ -802,43 +754,28 @@ mod tests {
let browse = app.unwrap_browse(); let browse = app.unwrap_browse();
assert_eq!(browse.0.selection.active, Category::Artist); let selection = &browse.inner.selection;
assert_eq!(browse.0.selection.artist.state.list.selected(), Some(0)); assert_eq!(selection.active, Category::Artist);
assert_eq!( assert_eq!(selection.artist.state.list.selected(), Some(0));
browse.0.selection.artist.album.state.list.selected(), assert_eq!(selection.artist.album.state.list.selected(), Some(0));
Some(0) assert_eq!(selection.artist.album.track.state.list.selected(), None);
);
assert_eq!(
browse.0.selection.artist.album.track.state.list.selected(),
None
);
let browse = browse.increment_category().unwrap_browse(); let browse = browse.increment_category().unwrap_browse();
let browse = browse.increment_category().unwrap_browse(); let browse = browse.increment_category().unwrap_browse();
let browse = browse.increment_selection(Delta::Line).unwrap_browse(); let browse = browse.increment_selection(Delta::Line).unwrap_browse();
assert_eq!(browse.0.selection.active, Category::Track); let selection = &browse.inner.selection;
assert_eq!(browse.0.selection.artist.state.list.selected(), Some(0)); assert_eq!(selection.active, Category::Track);
assert_eq!( assert_eq!(selection.artist.state.list.selected(), Some(0));
browse.0.selection.artist.album.state.list.selected(), assert_eq!(selection.artist.album.state.list.selected(), Some(0));
Some(0) assert_eq!(selection.artist.album.track.state.list.selected(), None);
);
assert_eq!(
browse.0.selection.artist.album.track.state.list.selected(),
None
);
let browse = browse.decrement_selection(Delta::Line).unwrap_browse(); let browse = browse.decrement_selection(Delta::Line).unwrap_browse();
assert_eq!(browse.0.selection.active, Category::Track); let selection = &browse.inner.selection;
assert_eq!(browse.0.selection.artist.state.list.selected(), Some(0)); assert_eq!(selection.active, Category::Track);
assert_eq!( assert_eq!(selection.artist.state.list.selected(), Some(0));
browse.0.selection.artist.album.state.list.selected(), assert_eq!(selection.artist.album.state.list.selected(), Some(0));
Some(0) assert_eq!(selection.artist.album.track.state.list.selected(), None);
);
assert_eq!(
browse.0.selection.artist.album.track.state.list.selected(),
None
);
} }
#[test] #[test]
@ -851,53 +788,43 @@ mod tests {
let browse = app.unwrap_browse(); let browse = app.unwrap_browse();
assert_eq!(browse.0.selection.active, Category::Artist); let selection = &browse.inner.selection;
assert_eq!(browse.0.selection.artist.state.list.selected(), Some(0)); assert_eq!(selection.active, Category::Artist);
assert_eq!(browse.0.selection.artist.album.state.list.selected(), None); assert_eq!(selection.artist.state.list.selected(), Some(0));
assert_eq!( assert_eq!(selection.artist.album.state.list.selected(), None);
browse.0.selection.artist.album.track.state.list.selected(), assert_eq!(selection.artist.album.track.state.list.selected(), None);
None
);
let browse = browse.increment_category().unwrap_browse(); let browse = browse.increment_category().unwrap_browse();
let browse = browse.increment_selection(Delta::Line).unwrap_browse(); let browse = browse.increment_selection(Delta::Line).unwrap_browse();
assert_eq!(browse.0.selection.active, Category::Album); let selection = &browse.inner.selection;
assert_eq!(browse.0.selection.artist.state.list.selected(), Some(0)); assert_eq!(selection.active, Category::Album);
assert_eq!(browse.0.selection.artist.album.state.list.selected(), None); assert_eq!(selection.artist.state.list.selected(), Some(0));
assert_eq!( assert_eq!(selection.artist.album.state.list.selected(), None);
browse.0.selection.artist.album.track.state.list.selected(), assert_eq!(selection.artist.album.track.state.list.selected(), None);
None
);
let browse = browse.decrement_selection(Delta::Line).unwrap_browse(); let browse = browse.decrement_selection(Delta::Line).unwrap_browse();
assert_eq!(browse.0.selection.active, Category::Album); let selection = &browse.inner.selection;
assert_eq!(browse.0.selection.artist.state.list.selected(), Some(0)); assert_eq!(selection.active, Category::Album);
assert_eq!(browse.0.selection.artist.album.state.list.selected(), None); assert_eq!(selection.artist.state.list.selected(), Some(0));
assert_eq!( assert_eq!(selection.artist.album.state.list.selected(), None);
browse.0.selection.artist.album.track.state.list.selected(), assert_eq!(selection.artist.album.track.state.list.selected(), None);
None
);
let browse = browse.increment_category().unwrap_browse(); let browse = browse.increment_category().unwrap_browse();
let browse = browse.increment_selection(Delta::Line).unwrap_browse(); let browse = browse.increment_selection(Delta::Line).unwrap_browse();
assert_eq!(browse.0.selection.active, Category::Track); let selection = &browse.inner.selection;
assert_eq!(browse.0.selection.artist.state.list.selected(), Some(0)); assert_eq!(selection.active, Category::Track);
assert_eq!(browse.0.selection.artist.album.state.list.selected(), None); assert_eq!(selection.artist.state.list.selected(), Some(0));
assert_eq!( assert_eq!(selection.artist.album.state.list.selected(), None);
browse.0.selection.artist.album.track.state.list.selected(), assert_eq!(selection.artist.album.track.state.list.selected(), None);
None
);
let browse = browse.decrement_selection(Delta::Line).unwrap_browse(); let browse = browse.decrement_selection(Delta::Line).unwrap_browse();
assert_eq!(browse.0.selection.active, Category::Track); let selection = &browse.inner.selection;
assert_eq!(browse.0.selection.artist.state.list.selected(), Some(0)); assert_eq!(selection.active, Category::Track);
assert_eq!(browse.0.selection.artist.album.state.list.selected(), None); assert_eq!(selection.artist.state.list.selected(), Some(0));
assert_eq!( assert_eq!(selection.artist.album.state.list.selected(), None);
browse.0.selection.artist.album.track.state.list.selected(), assert_eq!(selection.artist.album.track.state.list.selected(), None);
None
);
} }
#[test] #[test]
@ -907,71 +834,57 @@ mod tests {
let browse = app.unwrap_browse(); let browse = app.unwrap_browse();
assert_eq!(browse.0.selection.active, Category::Artist); let selection = &browse.inner.selection;
assert_eq!(browse.0.selection.artist.state.list.selected(), None); assert_eq!(selection.active, Category::Artist);
assert_eq!(browse.0.selection.artist.album.state.list.selected(), None); assert_eq!(selection.artist.state.list.selected(), None);
assert_eq!( assert_eq!(selection.artist.album.state.list.selected(), None);
browse.0.selection.artist.album.track.state.list.selected(), assert_eq!(selection.artist.album.track.state.list.selected(), None);
None
);
let browse = browse.increment_selection(Delta::Line).unwrap_browse(); let browse = browse.increment_selection(Delta::Line).unwrap_browse();
assert_eq!(browse.0.selection.active, Category::Artist); let selection = &browse.inner.selection;
assert_eq!(browse.0.selection.artist.state.list.selected(), None); assert_eq!(selection.active, Category::Artist);
assert_eq!(browse.0.selection.artist.album.state.list.selected(), None); assert_eq!(selection.artist.state.list.selected(), None);
assert_eq!( assert_eq!(selection.artist.album.state.list.selected(), None);
browse.0.selection.artist.album.track.state.list.selected(), assert_eq!(selection.artist.album.track.state.list.selected(), None);
None
);
let browse = browse.decrement_selection(Delta::Line).unwrap_browse(); let browse = browse.decrement_selection(Delta::Line).unwrap_browse();
assert_eq!(browse.0.selection.active, Category::Artist); let selection = &browse.inner.selection;
assert_eq!(browse.0.selection.artist.state.list.selected(), None); assert_eq!(selection.active, Category::Artist);
assert_eq!(browse.0.selection.artist.album.state.list.selected(), None); assert_eq!(selection.artist.state.list.selected(), None);
assert_eq!( assert_eq!(selection.artist.album.state.list.selected(), None);
browse.0.selection.artist.album.track.state.list.selected(), assert_eq!(selection.artist.album.track.state.list.selected(), None);
None
);
let browse = browse.increment_category().unwrap_browse(); let browse = browse.increment_category().unwrap_browse();
let browse = browse.increment_selection(Delta::Line).unwrap_browse(); let browse = browse.increment_selection(Delta::Line).unwrap_browse();
assert_eq!(browse.0.selection.active, Category::Album); let selection = &browse.inner.selection;
assert_eq!(browse.0.selection.artist.state.list.selected(), None); assert_eq!(selection.active, Category::Album);
assert_eq!(browse.0.selection.artist.album.state.list.selected(), None); assert_eq!(selection.artist.state.list.selected(), None);
assert_eq!( assert_eq!(selection.artist.album.state.list.selected(), None);
browse.0.selection.artist.album.track.state.list.selected(), assert_eq!(selection.artist.album.track.state.list.selected(), None);
None
);
let browse = browse.decrement_selection(Delta::Line).unwrap_browse(); let browse = browse.decrement_selection(Delta::Line).unwrap_browse();
assert_eq!(browse.0.selection.active, Category::Album); let selection = &browse.inner.selection;
assert_eq!(browse.0.selection.artist.state.list.selected(), None); assert_eq!(selection.active, Category::Album);
assert_eq!(browse.0.selection.artist.album.state.list.selected(), None); assert_eq!(selection.artist.state.list.selected(), None);
assert_eq!( assert_eq!(selection.artist.album.state.list.selected(), None);
browse.0.selection.artist.album.track.state.list.selected(), assert_eq!(selection.artist.album.track.state.list.selected(), None);
None
);
let browse = browse.increment_category().unwrap_browse(); let browse = browse.increment_category().unwrap_browse();
let browse = browse.increment_selection(Delta::Line).unwrap_browse(); let browse = browse.increment_selection(Delta::Line).unwrap_browse();
assert_eq!(browse.0.selection.active, Category::Track); let selection = &browse.inner.selection;
assert_eq!(browse.0.selection.artist.state.list.selected(), None); assert_eq!(selection.active, Category::Track);
assert_eq!(browse.0.selection.artist.album.state.list.selected(), None); assert_eq!(selection.artist.state.list.selected(), None);
assert_eq!( assert_eq!(selection.artist.album.state.list.selected(), None);
browse.0.selection.artist.album.track.state.list.selected(), assert_eq!(selection.artist.album.track.state.list.selected(), None);
None
);
let browse = browse.decrement_selection(Delta::Line).unwrap_browse(); let browse = browse.decrement_selection(Delta::Line).unwrap_browse();
assert_eq!(browse.0.selection.active, Category::Track); let selection = &browse.inner.selection;
assert_eq!(browse.0.selection.artist.state.list.selected(), None); assert_eq!(selection.active, Category::Track);
assert_eq!(browse.0.selection.artist.album.state.list.selected(), None); assert_eq!(selection.artist.state.list.selected(), None);
assert_eq!( assert_eq!(selection.artist.album.state.list.selected(), None);
browse.0.selection.artist.album.track.state.list.selected(), assert_eq!(selection.artist.album.track.state.list.selected(), None);
None
);
} }
#[test] #[test]
@ -1049,8 +962,8 @@ mod tests {
let browse = browse.increment_selection(Delta::Line).unwrap_browse(); let browse = browse.increment_selection(Delta::Line).unwrap_browse();
let browse = browse.increment_category().unwrap_browse(); let browse = browse.increment_category().unwrap_browse();
assert_eq!(browse.0.selection.active, Category::Album); assert_eq!(browse.inner.selection.active, Category::Album);
assert_eq!(browse.0.selection.artist.state.list.selected(), Some(1)); assert_eq!(browse.inner.selection.artist.state.list.selected(), Some(1));
let search = browse.begin_search().unwrap_search(); let search = browse.begin_search().unwrap_search();
@ -1097,8 +1010,8 @@ mod tests {
let browse = search.finish_search().unwrap_browse(); let browse = search.finish_search().unwrap_browse();
assert_eq!(browse.0.selection.active, Category::Album); assert_eq!(browse.inner.selection.active, Category::Album);
assert_eq!(browse.0.selection.artist.state.list.selected(), Some(1)); assert_eq!(browse.inner.selection.artist.state.list.selected(), Some(1));
} }
#[test] #[test]
@ -1108,8 +1021,8 @@ mod tests {
let browse = browse.increment_selection(Delta::Line).unwrap_browse(); let browse = browse.increment_selection(Delta::Line).unwrap_browse();
let browse = browse.increment_category().unwrap_browse(); let browse = browse.increment_category().unwrap_browse();
assert_eq!(browse.0.selection.active, Category::Album); assert_eq!(browse.inner.selection.active, Category::Album);
assert_eq!(browse.0.selection.artist.state.list.selected(), Some(1)); assert_eq!(browse.inner.selection.artist.state.list.selected(), Some(1));
let search = browse.begin_search().unwrap_search(); let search = browse.begin_search().unwrap_search();
@ -1176,8 +1089,8 @@ mod tests {
let browse = browse.increment_selection(Delta::Line).unwrap_browse(); let browse = browse.increment_selection(Delta::Line).unwrap_browse();
let browse = browse.increment_category().unwrap_browse(); let browse = browse.increment_category().unwrap_browse();
assert_eq!(browse.0.selection.active, Category::Album); assert_eq!(browse.inner.selection.active, Category::Album);
assert_eq!(browse.0.selection.artist.state.list.selected(), Some(1)); assert_eq!(browse.inner.selection.artist.state.list.selected(), Some(1));
let search = browse.begin_search().unwrap_search(); let search = browse.begin_search().unwrap_search();
@ -1206,8 +1119,8 @@ mod tests {
let browse = search.cancel_search().unwrap_browse(); let browse = search.cancel_search().unwrap_browse();
assert_eq!(browse.0.selection.active, Category::Album); assert_eq!(browse.inner.selection.active, Category::Album);
assert_eq!(browse.0.selection.artist.state.list.selected(), Some(1)); assert_eq!(browse.inner.selection.artist.state.list.selected(), Some(1));
} }
#[test] #[test]
@ -1217,8 +1130,8 @@ mod tests {
let browse = browse.increment_selection(Delta::Line).unwrap_browse(); let browse = browse.increment_selection(Delta::Line).unwrap_browse();
let browse = browse.increment_category().unwrap_browse(); let browse = browse.increment_category().unwrap_browse();
assert_eq!(browse.0.selection.active, Category::Album); assert_eq!(browse.inner.selection.active, Category::Album);
assert_eq!(browse.0.selection.artist.state.list.selected(), None); assert_eq!(browse.inner.selection.artist.state.list.selected(), None);
let search = browse.begin_search().unwrap_search(); let search = browse.begin_search().unwrap_search();
@ -1247,7 +1160,7 @@ mod tests {
let browse = search.cancel_search().unwrap_browse(); let browse = search.cancel_search().unwrap_browse();
assert_eq!(browse.0.selection.active, Category::Album); assert_eq!(browse.inner.selection.active, Category::Album);
assert_eq!(browse.0.selection.artist.state.list.selected(), None); assert_eq!(browse.inner.selection.artist.state.list.selected(), None);
} }
} }

View File

@ -48,6 +48,7 @@ pub struct TrackSelection {
pub state: WidgetState, pub state: WidgetState,
} }
// FIXME: should be with browse state (maybe?)
pub enum Delta { pub enum Delta {
Line, Line,
Page, Page,
@ -268,6 +269,7 @@ impl ArtistSelection {
result result
} }
// FIXME: search logic should be with the search state
fn incremental_search( fn incremental_search(
&mut self, &mut self,
artists: &[Artist], artists: &[Artist],

View File

@ -677,8 +677,8 @@ impl IUi for Ui {
fn render<APP: IAppAccess>(app: &mut APP, frame: &mut Frame) { fn render<APP: IAppAccess>(app: &mut APP, frame: &mut Frame) {
let app = app.get(); let app = app.get();
let collection = app.collection; let collection = app.inner.collection;
let selection = app.selection; let selection = app.inner.selection;
let state = app.state; let state = app.state;
Self::render_main_frame(collection, selection, &state, frame); Self::render_main_frame(collection, selection, &state, frame);
@ -695,7 +695,10 @@ impl IUi for Ui {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::tui::{ use crate::tui::{
app::{app::AppPublic, selection::Delta}, app::{
app::{AppPublic, AppPublicInner},
selection::Delta,
},
testmod::COLLECTION, testmod::COLLECTION,
tests::terminal, tests::terminal,
}; };
@ -706,9 +709,18 @@ mod tests {
impl IAppAccess for AppPublic<'_> { impl IAppAccess for AppPublic<'_> {
fn get(&mut self) -> AppPublic { fn get(&mut self) -> AppPublic {
AppPublic { AppPublic {
collection: self.collection, inner: AppPublicInner {
selection: self.selection, collection: self.inner.collection,
state: self.state, selection: self.inner.selection,
},
state: match self.state {
AppState::Browse(()) => AppState::Browse(()),
AppState::Info(()) => AppState::Info(()),
AppState::Reload(()) => AppState::Reload(()),
AppState::Search(s) => AppState::Search(s),
AppState::Error(s) => AppState::Error(s),
AppState::Critical(s) => AppState::Critical(s),
},
} }
} }
} }
@ -717,8 +729,10 @@ mod tests {
let mut terminal = terminal(); let mut terminal = terminal();
let mut app = AppPublic { let mut app = AppPublic {
inner: AppPublicInner {
collection, collection,
selection, selection,
},
state: AppState::Browse(()), state: AppState::Browse(()),
}; };
terminal.draw(|frame| Ui::render(&mut app, frame)).unwrap(); terminal.draw(|frame| Ui::render(&mut app, frame)).unwrap();