Provide search functionality through the TUI #134
@ -1,3 +1,4 @@
|
||||
// FIXME: Split file apart
|
||||
#![allow(clippy::module_inception)]
|
||||
|
||||
use musichoard::collection::Collection;
|
||||
@ -7,7 +8,6 @@ use crate::tui::{
|
||||
lib::IMusicHoard,
|
||||
};
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum AppState<BS, IS, RS, SS, ES, CS> {
|
||||
Browse(BS),
|
||||
Info(IS),
|
||||
@ -110,9 +110,13 @@ pub trait IAppAccess {
|
||||
pub type AppPublicState<'app> = AppState<(), (), (), &'app str, &'app str, &'app str>;
|
||||
|
||||
pub struct AppPublic<'app> {
|
||||
pub inner: AppPublicInner<'app>,
|
||||
pub state: AppPublicState<'app>,
|
||||
}
|
||||
|
||||
pub struct AppPublicInner<'app> {
|
||||
pub collection: &'app Collection,
|
||||
pub selection: &'app mut Selection,
|
||||
pub state: AppPublicState<'app>,
|
||||
}
|
||||
|
||||
struct AppInner<MH: IMusicHoard> {
|
||||
@ -130,11 +134,13 @@ pub type App<MH> = AppState<
|
||||
AppErrorState<MH>,
|
||||
>;
|
||||
|
||||
pub struct AppGenericState<MH: IMusicHoard>(AppInner<MH>);
|
||||
pub struct AppGenericState<MH: IMusicHoard> {
|
||||
inner: AppInner<MH>,
|
||||
}
|
||||
|
||||
pub struct AppSearchState<MH: IMusicHoard> {
|
||||
inner: AppInner<MH>,
|
||||
search: String,
|
||||
string: String,
|
||||
orig: ListSelection,
|
||||
memo: Vec<AppSearchMemo>,
|
||||
}
|
||||
@ -146,7 +152,7 @@ struct AppSearchMemo {
|
||||
|
||||
pub struct AppErrorState<MH: IMusicHoard> {
|
||||
inner: AppInner<MH>,
|
||||
msg: String,
|
||||
string: String,
|
||||
}
|
||||
|
||||
impl<MH: IMusicHoard> App<MH> {
|
||||
@ -159,10 +165,10 @@ impl<MH: IMusicHoard> App<MH> {
|
||||
selection,
|
||||
};
|
||||
match init_result {
|
||||
Ok(()) => Self::Browse(AppGenericState(inner)),
|
||||
Ok(()) => Self::Browse(AppGenericState { inner }),
|
||||
Err(err) => Self::Critical(AppErrorState {
|
||||
inner,
|
||||
msg: err.to_string(),
|
||||
string: err.to_string(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
@ -175,7 +181,9 @@ impl<MH: IMusicHoard> App<MH> {
|
||||
|
||||
fn inner_ref(&self) -> &AppInner<MH> {
|
||||
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::Error(error) | AppState::Critical(error) => &error.inner,
|
||||
}
|
||||
@ -183,8 +191,8 @@ impl<MH: IMusicHoard> App<MH> {
|
||||
|
||||
fn inner_mut(&mut self) -> &mut AppInner<MH> {
|
||||
match self {
|
||||
AppState::Browse(inner) | AppState::Info(inner) | AppState::Reload(inner) => {
|
||||
&mut inner.0
|
||||
AppState::Browse(generic) | AppState::Info(generic) | AppState::Reload(generic) => {
|
||||
&mut generic.inner
|
||||
}
|
||||
AppState::Search(search) => &mut search.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>;
|
||||
|
||||
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(_) => {
|
||||
self.0.running = false;
|
||||
self.inner.running = false;
|
||||
AppState::Browse(self)
|
||||
}
|
||||
Err(err) => AppState::Error(AppErrorState {
|
||||
inner: self.0,
|
||||
msg: err.to_string(),
|
||||
inner: self.inner,
|
||||
string: err.to_string(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
fn increment_category(mut self) -> Self::APP {
|
||||
self.0.selection.increment_category();
|
||||
self.inner.selection.increment_category();
|
||||
AppState::Browse(self)
|
||||
}
|
||||
|
||||
fn decrement_category(mut self) -> Self::APP {
|
||||
self.0.selection.decrement_category();
|
||||
self.inner.selection.decrement_category();
|
||||
AppState::Browse(self)
|
||||
}
|
||||
|
||||
fn increment_selection(mut self, delta: Delta) -> Self::APP {
|
||||
self.0
|
||||
self.inner
|
||||
.selection
|
||||
.increment_selection(self.0.music_hoard.get_collection(), delta);
|
||||
.increment_selection(self.inner.music_hoard.get_collection(), delta);
|
||||
AppState::Browse(self)
|
||||
}
|
||||
|
||||
fn decrement_selection(mut self, delta: Delta) -> Self::APP {
|
||||
self.0
|
||||
self.inner
|
||||
.selection
|
||||
.decrement_selection(self.0.music_hoard.get_collection(), delta);
|
||||
.decrement_selection(self.inner.music_hoard.get_collection(), delta);
|
||||
AppState::Browse(self)
|
||||
}
|
||||
|
||||
@ -263,13 +271,13 @@ impl<MH: IMusicHoard> IAppInteractBrowse for AppGenericState<MH> {
|
||||
}
|
||||
|
||||
fn begin_search(mut self) -> Self::APP {
|
||||
let orig = ListSelection::get(&self.0.selection);
|
||||
self.0
|
||||
let orig = ListSelection::get(&self.inner.selection);
|
||||
self.inner
|
||||
.selection
|
||||
.reset_artist(self.0.music_hoard.get_collection());
|
||||
.reset_artist(self.inner.music_hoard.get_collection());
|
||||
AppState::Search(AppSearchState {
|
||||
inner: self.0,
|
||||
search: String::new(),
|
||||
inner: self.inner,
|
||||
string: String::new(),
|
||||
orig,
|
||||
memo: vec![],
|
||||
})
|
||||
@ -284,7 +292,7 @@ impl<MH: IMusicHoard> IAppInteractInfo for AppGenericState<MH> {
|
||||
type APP = App<MH>;
|
||||
|
||||
fn hide_info_overlay(self) -> Self::APP {
|
||||
AppState::Browse(AppGenericState(self.0))
|
||||
AppState::Browse(AppGenericState { inner: self.inner })
|
||||
}
|
||||
|
||||
fn no_op(self) -> Self::APP {
|
||||
@ -296,19 +304,25 @@ impl<MH: IMusicHoard> IAppInteractReload for AppGenericState<MH> {
|
||||
type APP = App<MH>;
|
||||
|
||||
fn reload_library(mut self) -> Self::APP {
|
||||
let previous = IdSelection::get(self.0.music_hoard.get_collection(), &self.0.selection);
|
||||
let result = self.0.music_hoard.rescan_library();
|
||||
let previous = IdSelection::get(
|
||||
self.inner.music_hoard.get_collection(),
|
||||
&self.inner.selection,
|
||||
);
|
||||
let result = self.inner.music_hoard.rescan_library();
|
||||
self.refresh(previous, result)
|
||||
}
|
||||
|
||||
fn reload_database(mut self) -> Self::APP {
|
||||
let previous = IdSelection::get(self.0.music_hoard.get_collection(), &self.0.selection);
|
||||
let result = self.0.music_hoard.load_from_database();
|
||||
let previous = IdSelection::get(
|
||||
self.inner.music_hoard.get_collection(),
|
||||
&self.inner.selection,
|
||||
);
|
||||
let result = self.inner.music_hoard.load_from_database();
|
||||
self.refresh(previous, result)
|
||||
}
|
||||
|
||||
fn hide_reload_menu(self) -> Self::APP {
|
||||
AppState::Browse(AppGenericState(self.0))
|
||||
AppState::Browse(AppGenericState { inner: self.inner })
|
||||
}
|
||||
|
||||
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> {
|
||||
match result {
|
||||
Ok(()) => {
|
||||
self.0
|
||||
self.inner
|
||||
.selection
|
||||
.select_by_id(self.0.music_hoard.get_collection(), previous);
|
||||
AppState::Browse(AppGenericState(self.0))
|
||||
.select_by_id(self.inner.music_hoard.get_collection(), previous);
|
||||
AppState::Browse(AppGenericState { inner: self.inner })
|
||||
}
|
||||
Err(err) => AppState::Error(AppErrorState {
|
||||
inner: self.0,
|
||||
msg: err.to_string(),
|
||||
inner: self.inner,
|
||||
string: err.to_string(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
@ -342,22 +356,22 @@ impl<MH: IMusicHoard> IAppInteractSearch for AppSearchState<MH> {
|
||||
|
||||
fn append_character(mut self, ch: char) -> Self::APP {
|
||||
let collection = self.inner.music_hoard.get_collection();
|
||||
self.search.push(ch);
|
||||
self.string.push(ch);
|
||||
let index = self
|
||||
.inner
|
||||
.selection
|
||||
.incremental_artist_search(collection, &self.search, false);
|
||||
.incremental_artist_search(collection, &self.string, false);
|
||||
self.memo.push(AppSearchMemo { index, char: true });
|
||||
AppState::Search(self)
|
||||
}
|
||||
|
||||
fn search_next(mut self) -> Self::APP {
|
||||
let collection = self.inner.music_hoard.get_collection();
|
||||
if !self.search.is_empty() {
|
||||
if !self.string.is_empty() {
|
||||
let index =
|
||||
self.inner
|
||||
.selection
|
||||
.incremental_artist_search(collection, &self.search, true);
|
||||
.incremental_artist_search(collection, &self.string, true);
|
||||
self.memo.push(AppSearchMemo { index, char: false });
|
||||
}
|
||||
AppState::Search(self)
|
||||
@ -367,7 +381,7 @@ impl<MH: IMusicHoard> IAppInteractSearch for AppSearchState<MH> {
|
||||
let collection = self.inner.music_hoard.get_collection();
|
||||
if let Some(memo) = self.memo.pop() {
|
||||
if memo.char {
|
||||
self.search.pop();
|
||||
self.string.pop();
|
||||
}
|
||||
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 {
|
||||
AppState::Browse(AppGenericState(self.inner))
|
||||
AppState::Browse(AppGenericState { inner: self.inner })
|
||||
}
|
||||
|
||||
fn cancel_search(mut self) -> Self::APP {
|
||||
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 {
|
||||
@ -392,7 +406,7 @@ impl<MH: IMusicHoard> IAppInteractError for AppErrorState<MH> {
|
||||
type APP = App<MH>;
|
||||
|
||||
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 {
|
||||
match self {
|
||||
AppState::Browse(generic) => AppPublic {
|
||||
collection: generic.0.music_hoard.get_collection(),
|
||||
selection: &mut generic.0.selection,
|
||||
inner: (&mut generic.inner).into(),
|
||||
state: AppState::Browse(()),
|
||||
},
|
||||
AppState::Info(generic) => AppPublic {
|
||||
collection: generic.0.music_hoard.get_collection(),
|
||||
selection: &mut generic.0.selection,
|
||||
inner: (&mut generic.inner).into(),
|
||||
state: AppState::Info(()),
|
||||
},
|
||||
AppState::Reload(generic) => AppPublic {
|
||||
collection: generic.0.music_hoard.get_collection(),
|
||||
selection: &mut generic.0.selection,
|
||||
inner: (&mut generic.inner).into(),
|
||||
state: AppState::Reload(()),
|
||||
},
|
||||
AppState::Search(search) => AppPublic {
|
||||
collection: search.inner.music_hoard.get_collection(),
|
||||
selection: &mut search.inner.selection,
|
||||
state: AppState::Search(&search.search),
|
||||
inner: (&mut search.inner).into(),
|
||||
state: AppState::Search(&search.string),
|
||||
},
|
||||
AppState::Error(error) => AppPublic {
|
||||
collection: error.inner.music_hoard.get_collection(),
|
||||
selection: &mut error.inner.selection,
|
||||
state: AppState::Error(&error.msg),
|
||||
inner: (&mut error.inner).into(),
|
||||
state: AppState::Error(&error.string),
|
||||
},
|
||||
AppState::Critical(critical) => AppPublic {
|
||||
collection: critical.inner.music_hoard.get_collection(),
|
||||
selection: &mut critical.inner.selection,
|
||||
state: AppState::Error(&critical.msg),
|
||||
inner: (&mut critical.inner).into(),
|
||||
state: AppState::Error(&critical.string),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)]
|
||||
mod tests {
|
||||
use crate::tui::{app::selection::Category, lib::MockIMusicHoard, testmod::COLLECTION};
|
||||
@ -544,8 +561,8 @@ mod tests {
|
||||
assert!(app.is_running());
|
||||
|
||||
let app = App::Error(AppErrorState {
|
||||
inner: app.unwrap_browse().0,
|
||||
msg: String::from("get rekt"),
|
||||
inner: app.unwrap_browse().inner,
|
||||
string: String::from("get rekt"),
|
||||
});
|
||||
|
||||
let error = app.unwrap_error();
|
||||
@ -571,8 +588,8 @@ mod tests {
|
||||
assert!(app.is_running());
|
||||
|
||||
let app = App::Error(AppErrorState {
|
||||
inner: app.unwrap_browse().0,
|
||||
msg: String::from("get rekt"),
|
||||
inner: app.unwrap_browse().inner,
|
||||
string: String::from("get rekt"),
|
||||
});
|
||||
|
||||
let app = app.force_quit();
|
||||
@ -630,166 +647,101 @@ mod tests {
|
||||
|
||||
let browse = app.unwrap_browse();
|
||||
|
||||
assert_eq!(browse.0.selection.active, Category::Artist);
|
||||
assert_eq!(browse.0.selection.artist.state.list.selected(), Some(0));
|
||||
assert_eq!(
|
||||
browse.0.selection.artist.album.state.list.selected(),
|
||||
Some(0)
|
||||
);
|
||||
assert_eq!(
|
||||
browse.0.selection.artist.album.track.state.list.selected(),
|
||||
Some(0)
|
||||
);
|
||||
let selection = &browse.inner.selection;
|
||||
assert_eq!(selection.active, Category::Artist);
|
||||
assert_eq!(selection.artist.state.list.selected(), Some(0));
|
||||
assert_eq!(selection.artist.album.state.list.selected(), Some(0));
|
||||
assert_eq!(selection.artist.album.track.state.list.selected(), Some(0));
|
||||
|
||||
let browse = browse.increment_selection(Delta::Line).unwrap_browse();
|
||||
assert_eq!(browse.0.selection.active, Category::Artist);
|
||||
assert_eq!(browse.0.selection.artist.state.list.selected(), Some(1));
|
||||
assert_eq!(
|
||||
browse.0.selection.artist.album.state.list.selected(),
|
||||
Some(0)
|
||||
);
|
||||
assert_eq!(
|
||||
browse.0.selection.artist.album.track.state.list.selected(),
|
||||
Some(0)
|
||||
);
|
||||
let selection = &browse.inner.selection;
|
||||
assert_eq!(selection.active, Category::Artist);
|
||||
assert_eq!(selection.artist.state.list.selected(), Some(1));
|
||||
assert_eq!(selection.artist.album.state.list.selected(), Some(0));
|
||||
assert_eq!(selection.artist.album.track.state.list.selected(), Some(0));
|
||||
|
||||
let browse = browse.increment_category().unwrap_browse();
|
||||
assert_eq!(browse.0.selection.active, Category::Album);
|
||||
assert_eq!(browse.0.selection.artist.state.list.selected(), Some(1));
|
||||
assert_eq!(
|
||||
browse.0.selection.artist.album.state.list.selected(),
|
||||
Some(0)
|
||||
);
|
||||
assert_eq!(
|
||||
browse.0.selection.artist.album.track.state.list.selected(),
|
||||
Some(0)
|
||||
);
|
||||
let selection = &browse.inner.selection;
|
||||
assert_eq!(selection.active, Category::Album);
|
||||
assert_eq!(selection.artist.state.list.selected(), Some(1));
|
||||
assert_eq!(selection.artist.album.state.list.selected(), Some(0));
|
||||
assert_eq!(selection.artist.album.track.state.list.selected(), Some(0));
|
||||
|
||||
let browse = browse.increment_selection(Delta::Line).unwrap_browse();
|
||||
assert_eq!(browse.0.selection.active, Category::Album);
|
||||
assert_eq!(browse.0.selection.artist.state.list.selected(), Some(1));
|
||||
assert_eq!(
|
||||
browse.0.selection.artist.album.state.list.selected(),
|
||||
Some(1)
|
||||
);
|
||||
assert_eq!(
|
||||
browse.0.selection.artist.album.track.state.list.selected(),
|
||||
Some(0)
|
||||
);
|
||||
let selection = &browse.inner.selection;
|
||||
assert_eq!(selection.active, Category::Album);
|
||||
assert_eq!(selection.artist.state.list.selected(), Some(1));
|
||||
assert_eq!(selection.artist.album.state.list.selected(), Some(1));
|
||||
assert_eq!(selection.artist.album.track.state.list.selected(), Some(0));
|
||||
|
||||
let browse = browse.increment_category().unwrap_browse();
|
||||
assert_eq!(browse.0.selection.active, Category::Track);
|
||||
assert_eq!(browse.0.selection.artist.state.list.selected(), Some(1));
|
||||
assert_eq!(
|
||||
browse.0.selection.artist.album.state.list.selected(),
|
||||
Some(1)
|
||||
);
|
||||
assert_eq!(
|
||||
browse.0.selection.artist.album.track.state.list.selected(),
|
||||
Some(0)
|
||||
);
|
||||
let selection = &browse.inner.selection;
|
||||
assert_eq!(selection.active, Category::Track);
|
||||
assert_eq!(selection.artist.state.list.selected(), Some(1));
|
||||
assert_eq!(selection.artist.album.state.list.selected(), Some(1));
|
||||
assert_eq!(selection.artist.album.track.state.list.selected(), Some(0));
|
||||
|
||||
let browse = browse.increment_selection(Delta::Line).unwrap_browse();
|
||||
assert_eq!(browse.0.selection.active, Category::Track);
|
||||
assert_eq!(browse.0.selection.artist.state.list.selected(), Some(1));
|
||||
assert_eq!(
|
||||
browse.0.selection.artist.album.state.list.selected(),
|
||||
Some(1)
|
||||
);
|
||||
assert_eq!(
|
||||
browse.0.selection.artist.album.track.state.list.selected(),
|
||||
Some(1)
|
||||
);
|
||||
let selection = &browse.inner.selection;
|
||||
assert_eq!(selection.active, Category::Track);
|
||||
assert_eq!(selection.artist.state.list.selected(), Some(1));
|
||||
assert_eq!(selection.artist.album.state.list.selected(), Some(1));
|
||||
assert_eq!(selection.artist.album.track.state.list.selected(), Some(1));
|
||||
|
||||
let browse = browse.increment_category().unwrap_browse();
|
||||
assert_eq!(browse.0.selection.active, Category::Track);
|
||||
assert_eq!(browse.0.selection.artist.state.list.selected(), Some(1));
|
||||
assert_eq!(
|
||||
browse.0.selection.artist.album.state.list.selected(),
|
||||
Some(1)
|
||||
);
|
||||
assert_eq!(
|
||||
browse.0.selection.artist.album.track.state.list.selected(),
|
||||
Some(1)
|
||||
);
|
||||
let selection = &browse.inner.selection;
|
||||
assert_eq!(selection.active, Category::Track);
|
||||
assert_eq!(selection.artist.state.list.selected(), Some(1));
|
||||
assert_eq!(selection.artist.album.state.list.selected(), Some(1));
|
||||
assert_eq!(selection.artist.album.track.state.list.selected(), Some(1));
|
||||
|
||||
let browse = browse.decrement_selection(Delta::Line).unwrap_browse();
|
||||
assert_eq!(browse.0.selection.active, Category::Track);
|
||||
assert_eq!(browse.0.selection.artist.state.list.selected(), Some(1));
|
||||
assert_eq!(
|
||||
browse.0.selection.artist.album.state.list.selected(),
|
||||
Some(1)
|
||||
);
|
||||
assert_eq!(
|
||||
browse.0.selection.artist.album.track.state.list.selected(),
|
||||
Some(0)
|
||||
);
|
||||
let selection = &browse.inner.selection;
|
||||
assert_eq!(selection.active, Category::Track);
|
||||
assert_eq!(selection.artist.state.list.selected(), Some(1));
|
||||
assert_eq!(selection.artist.album.state.list.selected(), Some(1));
|
||||
assert_eq!(selection.artist.album.track.state.list.selected(), Some(0));
|
||||
|
||||
let browse = browse.increment_selection(Delta::Line).unwrap_browse();
|
||||
let browse = browse.decrement_category().unwrap_browse();
|
||||
assert_eq!(browse.0.selection.active, Category::Album);
|
||||
assert_eq!(browse.0.selection.artist.state.list.selected(), Some(1));
|
||||
assert_eq!(
|
||||
browse.0.selection.artist.album.state.list.selected(),
|
||||
Some(1)
|
||||
);
|
||||
assert_eq!(
|
||||
browse.0.selection.artist.album.track.state.list.selected(),
|
||||
Some(1)
|
||||
);
|
||||
let selection = &browse.inner.selection;
|
||||
assert_eq!(selection.active, Category::Album);
|
||||
assert_eq!(selection.artist.state.list.selected(), Some(1));
|
||||
assert_eq!(selection.artist.album.state.list.selected(), Some(1));
|
||||
assert_eq!(selection.artist.album.track.state.list.selected(), Some(1));
|
||||
|
||||
let browse = browse.decrement_selection(Delta::Line).unwrap_browse();
|
||||
assert_eq!(browse.0.selection.active, Category::Album);
|
||||
assert_eq!(browse.0.selection.artist.state.list.selected(), Some(1));
|
||||
assert_eq!(
|
||||
browse.0.selection.artist.album.state.list.selected(),
|
||||
Some(0)
|
||||
);
|
||||
assert_eq!(
|
||||
browse.0.selection.artist.album.track.state.list.selected(),
|
||||
Some(0)
|
||||
);
|
||||
let selection = &browse.inner.selection;
|
||||
assert_eq!(selection.active, Category::Album);
|
||||
assert_eq!(selection.artist.state.list.selected(), Some(1));
|
||||
assert_eq!(selection.artist.album.state.list.selected(), Some(0));
|
||||
assert_eq!(selection.artist.album.track.state.list.selected(), Some(0));
|
||||
|
||||
let browse = browse.increment_selection(Delta::Line).unwrap_browse();
|
||||
let browse = browse.decrement_category().unwrap_browse();
|
||||
assert_eq!(browse.0.selection.active, Category::Artist);
|
||||
assert_eq!(browse.0.selection.artist.state.list.selected(), Some(1));
|
||||
assert_eq!(
|
||||
browse.0.selection.artist.album.state.list.selected(),
|
||||
Some(1)
|
||||
);
|
||||
assert_eq!(
|
||||
browse.0.selection.artist.album.track.state.list.selected(),
|
||||
Some(0)
|
||||
);
|
||||
let selection = &browse.inner.selection;
|
||||
assert_eq!(selection.active, Category::Artist);
|
||||
assert_eq!(selection.artist.state.list.selected(), Some(1));
|
||||
assert_eq!(selection.artist.album.state.list.selected(), Some(1));
|
||||
assert_eq!(selection.artist.album.track.state.list.selected(), Some(0));
|
||||
|
||||
let browse = browse.decrement_selection(Delta::Line).unwrap_browse();
|
||||
assert_eq!(browse.0.selection.active, Category::Artist);
|
||||
assert_eq!(browse.0.selection.artist.state.list.selected(), Some(0));
|
||||
assert_eq!(
|
||||
browse.0.selection.artist.album.state.list.selected(),
|
||||
Some(0)
|
||||
);
|
||||
assert_eq!(
|
||||
browse.0.selection.artist.album.track.state.list.selected(),
|
||||
Some(0)
|
||||
);
|
||||
let selection = &browse.inner.selection;
|
||||
assert_eq!(selection.active, Category::Artist);
|
||||
assert_eq!(selection.artist.state.list.selected(), Some(0));
|
||||
assert_eq!(selection.artist.album.state.list.selected(), Some(0));
|
||||
assert_eq!(selection.artist.album.track.state.list.selected(), Some(0));
|
||||
|
||||
let browse = browse.increment_category().unwrap_browse();
|
||||
let browse = browse.increment_selection(Delta::Line).unwrap_browse();
|
||||
let browse = browse.decrement_category().unwrap_browse();
|
||||
let browse = browse.decrement_selection(Delta::Line).unwrap_browse();
|
||||
let browse = browse.decrement_category().unwrap_browse();
|
||||
assert_eq!(browse.0.selection.active, Category::Artist);
|
||||
assert_eq!(browse.0.selection.artist.state.list.selected(), Some(0));
|
||||
assert_eq!(
|
||||
browse.0.selection.artist.album.state.list.selected(),
|
||||
Some(1)
|
||||
);
|
||||
assert_eq!(
|
||||
browse.0.selection.artist.album.track.state.list.selected(),
|
||||
Some(0)
|
||||
);
|
||||
let selection = &browse.inner.selection;
|
||||
assert_eq!(selection.active, Category::Artist);
|
||||
assert_eq!(selection.artist.state.list.selected(), Some(0));
|
||||
assert_eq!(selection.artist.album.state.list.selected(), Some(1));
|
||||
assert_eq!(selection.artist.album.track.state.list.selected(), Some(0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -802,43 +754,28 @@ mod tests {
|
||||
|
||||
let browse = app.unwrap_browse();
|
||||
|
||||
assert_eq!(browse.0.selection.active, Category::Artist);
|
||||
assert_eq!(browse.0.selection.artist.state.list.selected(), Some(0));
|
||||
assert_eq!(
|
||||
browse.0.selection.artist.album.state.list.selected(),
|
||||
Some(0)
|
||||
);
|
||||
assert_eq!(
|
||||
browse.0.selection.artist.album.track.state.list.selected(),
|
||||
None
|
||||
);
|
||||
let selection = &browse.inner.selection;
|
||||
assert_eq!(selection.active, Category::Artist);
|
||||
assert_eq!(selection.artist.state.list.selected(), Some(0));
|
||||
assert_eq!(selection.artist.album.state.list.selected(), Some(0));
|
||||
assert_eq!(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_selection(Delta::Line).unwrap_browse();
|
||||
assert_eq!(browse.0.selection.active, Category::Track);
|
||||
assert_eq!(browse.0.selection.artist.state.list.selected(), Some(0));
|
||||
assert_eq!(
|
||||
browse.0.selection.artist.album.state.list.selected(),
|
||||
Some(0)
|
||||
);
|
||||
assert_eq!(
|
||||
browse.0.selection.artist.album.track.state.list.selected(),
|
||||
None
|
||||
);
|
||||
let selection = &browse.inner.selection;
|
||||
assert_eq!(selection.active, Category::Track);
|
||||
assert_eq!(selection.artist.state.list.selected(), Some(0));
|
||||
assert_eq!(selection.artist.album.state.list.selected(), Some(0));
|
||||
assert_eq!(selection.artist.album.track.state.list.selected(), None);
|
||||
|
||||
let browse = browse.decrement_selection(Delta::Line).unwrap_browse();
|
||||
assert_eq!(browse.0.selection.active, Category::Track);
|
||||
assert_eq!(browse.0.selection.artist.state.list.selected(), Some(0));
|
||||
assert_eq!(
|
||||
browse.0.selection.artist.album.state.list.selected(),
|
||||
Some(0)
|
||||
);
|
||||
assert_eq!(
|
||||
browse.0.selection.artist.album.track.state.list.selected(),
|
||||
None
|
||||
);
|
||||
let selection = &browse.inner.selection;
|
||||
assert_eq!(selection.active, Category::Track);
|
||||
assert_eq!(selection.artist.state.list.selected(), Some(0));
|
||||
assert_eq!(selection.artist.album.state.list.selected(), Some(0));
|
||||
assert_eq!(selection.artist.album.track.state.list.selected(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -851,53 +788,43 @@ mod tests {
|
||||
|
||||
let browse = app.unwrap_browse();
|
||||
|
||||
assert_eq!(browse.0.selection.active, Category::Artist);
|
||||
assert_eq!(browse.0.selection.artist.state.list.selected(), Some(0));
|
||||
assert_eq!(browse.0.selection.artist.album.state.list.selected(), None);
|
||||
assert_eq!(
|
||||
browse.0.selection.artist.album.track.state.list.selected(),
|
||||
None
|
||||
);
|
||||
let selection = &browse.inner.selection;
|
||||
assert_eq!(selection.active, Category::Artist);
|
||||
assert_eq!(selection.artist.state.list.selected(), Some(0));
|
||||
assert_eq!(selection.artist.album.state.list.selected(), None);
|
||||
assert_eq!(selection.artist.album.track.state.list.selected(), None);
|
||||
|
||||
let browse = browse.increment_category().unwrap_browse();
|
||||
|
||||
let browse = browse.increment_selection(Delta::Line).unwrap_browse();
|
||||
assert_eq!(browse.0.selection.active, Category::Album);
|
||||
assert_eq!(browse.0.selection.artist.state.list.selected(), Some(0));
|
||||
assert_eq!(browse.0.selection.artist.album.state.list.selected(), None);
|
||||
assert_eq!(
|
||||
browse.0.selection.artist.album.track.state.list.selected(),
|
||||
None
|
||||
);
|
||||
let selection = &browse.inner.selection;
|
||||
assert_eq!(selection.active, Category::Album);
|
||||
assert_eq!(selection.artist.state.list.selected(), Some(0));
|
||||
assert_eq!(selection.artist.album.state.list.selected(), None);
|
||||
assert_eq!(selection.artist.album.track.state.list.selected(), None);
|
||||
|
||||
let browse = browse.decrement_selection(Delta::Line).unwrap_browse();
|
||||
assert_eq!(browse.0.selection.active, Category::Album);
|
||||
assert_eq!(browse.0.selection.artist.state.list.selected(), Some(0));
|
||||
assert_eq!(browse.0.selection.artist.album.state.list.selected(), None);
|
||||
assert_eq!(
|
||||
browse.0.selection.artist.album.track.state.list.selected(),
|
||||
None
|
||||
);
|
||||
let selection = &browse.inner.selection;
|
||||
assert_eq!(selection.active, Category::Album);
|
||||
assert_eq!(selection.artist.state.list.selected(), Some(0));
|
||||
assert_eq!(selection.artist.album.state.list.selected(), None);
|
||||
assert_eq!(selection.artist.album.track.state.list.selected(), None);
|
||||
|
||||
let browse = browse.increment_category().unwrap_browse();
|
||||
|
||||
let browse = browse.increment_selection(Delta::Line).unwrap_browse();
|
||||
assert_eq!(browse.0.selection.active, Category::Track);
|
||||
assert_eq!(browse.0.selection.artist.state.list.selected(), Some(0));
|
||||
assert_eq!(browse.0.selection.artist.album.state.list.selected(), None);
|
||||
assert_eq!(
|
||||
browse.0.selection.artist.album.track.state.list.selected(),
|
||||
None
|
||||
);
|
||||
let selection = &browse.inner.selection;
|
||||
assert_eq!(selection.active, Category::Track);
|
||||
assert_eq!(selection.artist.state.list.selected(), Some(0));
|
||||
assert_eq!(selection.artist.album.state.list.selected(), None);
|
||||
assert_eq!(selection.artist.album.track.state.list.selected(), None);
|
||||
|
||||
let browse = browse.decrement_selection(Delta::Line).unwrap_browse();
|
||||
assert_eq!(browse.0.selection.active, Category::Track);
|
||||
assert_eq!(browse.0.selection.artist.state.list.selected(), Some(0));
|
||||
assert_eq!(browse.0.selection.artist.album.state.list.selected(), None);
|
||||
assert_eq!(
|
||||
browse.0.selection.artist.album.track.state.list.selected(),
|
||||
None
|
||||
);
|
||||
let selection = &browse.inner.selection;
|
||||
assert_eq!(selection.active, Category::Track);
|
||||
assert_eq!(selection.artist.state.list.selected(), Some(0));
|
||||
assert_eq!(selection.artist.album.state.list.selected(), None);
|
||||
assert_eq!(selection.artist.album.track.state.list.selected(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -907,71 +834,57 @@ mod tests {
|
||||
|
||||
let browse = app.unwrap_browse();
|
||||
|
||||
assert_eq!(browse.0.selection.active, Category::Artist);
|
||||
assert_eq!(browse.0.selection.artist.state.list.selected(), None);
|
||||
assert_eq!(browse.0.selection.artist.album.state.list.selected(), None);
|
||||
assert_eq!(
|
||||
browse.0.selection.artist.album.track.state.list.selected(),
|
||||
None
|
||||
);
|
||||
let selection = &browse.inner.selection;
|
||||
assert_eq!(selection.active, Category::Artist);
|
||||
assert_eq!(selection.artist.state.list.selected(), None);
|
||||
assert_eq!(selection.artist.album.state.list.selected(), None);
|
||||
assert_eq!(selection.artist.album.track.state.list.selected(), None);
|
||||
|
||||
let browse = browse.increment_selection(Delta::Line).unwrap_browse();
|
||||
assert_eq!(browse.0.selection.active, Category::Artist);
|
||||
assert_eq!(browse.0.selection.artist.state.list.selected(), None);
|
||||
assert_eq!(browse.0.selection.artist.album.state.list.selected(), None);
|
||||
assert_eq!(
|
||||
browse.0.selection.artist.album.track.state.list.selected(),
|
||||
None
|
||||
);
|
||||
let selection = &browse.inner.selection;
|
||||
assert_eq!(selection.active, Category::Artist);
|
||||
assert_eq!(selection.artist.state.list.selected(), None);
|
||||
assert_eq!(selection.artist.album.state.list.selected(), None);
|
||||
assert_eq!(selection.artist.album.track.state.list.selected(), None);
|
||||
|
||||
let browse = browse.decrement_selection(Delta::Line).unwrap_browse();
|
||||
assert_eq!(browse.0.selection.active, Category::Artist);
|
||||
assert_eq!(browse.0.selection.artist.state.list.selected(), None);
|
||||
assert_eq!(browse.0.selection.artist.album.state.list.selected(), None);
|
||||
assert_eq!(
|
||||
browse.0.selection.artist.album.track.state.list.selected(),
|
||||
None
|
||||
);
|
||||
let selection = &browse.inner.selection;
|
||||
assert_eq!(selection.active, Category::Artist);
|
||||
assert_eq!(selection.artist.state.list.selected(), None);
|
||||
assert_eq!(selection.artist.album.state.list.selected(), None);
|
||||
assert_eq!(selection.artist.album.track.state.list.selected(), None);
|
||||
|
||||
let browse = browse.increment_category().unwrap_browse();
|
||||
|
||||
let browse = browse.increment_selection(Delta::Line).unwrap_browse();
|
||||
assert_eq!(browse.0.selection.active, Category::Album);
|
||||
assert_eq!(browse.0.selection.artist.state.list.selected(), None);
|
||||
assert_eq!(browse.0.selection.artist.album.state.list.selected(), None);
|
||||
assert_eq!(
|
||||
browse.0.selection.artist.album.track.state.list.selected(),
|
||||
None
|
||||
);
|
||||
let selection = &browse.inner.selection;
|
||||
assert_eq!(selection.active, Category::Album);
|
||||
assert_eq!(selection.artist.state.list.selected(), None);
|
||||
assert_eq!(selection.artist.album.state.list.selected(), None);
|
||||
assert_eq!(selection.artist.album.track.state.list.selected(), None);
|
||||
|
||||
let browse = browse.decrement_selection(Delta::Line).unwrap_browse();
|
||||
assert_eq!(browse.0.selection.active, Category::Album);
|
||||
assert_eq!(browse.0.selection.artist.state.list.selected(), None);
|
||||
assert_eq!(browse.0.selection.artist.album.state.list.selected(), None);
|
||||
assert_eq!(
|
||||
browse.0.selection.artist.album.track.state.list.selected(),
|
||||
None
|
||||
);
|
||||
let selection = &browse.inner.selection;
|
||||
assert_eq!(selection.active, Category::Album);
|
||||
assert_eq!(selection.artist.state.list.selected(), None);
|
||||
assert_eq!(selection.artist.album.state.list.selected(), None);
|
||||
assert_eq!(selection.artist.album.track.state.list.selected(), None);
|
||||
|
||||
let browse = browse.increment_category().unwrap_browse();
|
||||
|
||||
let browse = browse.increment_selection(Delta::Line).unwrap_browse();
|
||||
assert_eq!(browse.0.selection.active, Category::Track);
|
||||
assert_eq!(browse.0.selection.artist.state.list.selected(), None);
|
||||
assert_eq!(browse.0.selection.artist.album.state.list.selected(), None);
|
||||
assert_eq!(
|
||||
browse.0.selection.artist.album.track.state.list.selected(),
|
||||
None
|
||||
);
|
||||
let selection = &browse.inner.selection;
|
||||
assert_eq!(selection.active, Category::Track);
|
||||
assert_eq!(selection.artist.state.list.selected(), None);
|
||||
assert_eq!(selection.artist.album.state.list.selected(), None);
|
||||
assert_eq!(selection.artist.album.track.state.list.selected(), None);
|
||||
|
||||
let browse = browse.decrement_selection(Delta::Line).unwrap_browse();
|
||||
assert_eq!(browse.0.selection.active, Category::Track);
|
||||
assert_eq!(browse.0.selection.artist.state.list.selected(), None);
|
||||
assert_eq!(browse.0.selection.artist.album.state.list.selected(), None);
|
||||
assert_eq!(
|
||||
browse.0.selection.artist.album.track.state.list.selected(),
|
||||
None
|
||||
);
|
||||
let selection = &browse.inner.selection;
|
||||
assert_eq!(selection.active, Category::Track);
|
||||
assert_eq!(selection.artist.state.list.selected(), None);
|
||||
assert_eq!(selection.artist.album.state.list.selected(), None);
|
||||
assert_eq!(selection.artist.album.track.state.list.selected(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -1049,8 +962,8 @@ mod tests {
|
||||
let browse = browse.increment_selection(Delta::Line).unwrap_browse();
|
||||
let browse = browse.increment_category().unwrap_browse();
|
||||
|
||||
assert_eq!(browse.0.selection.active, Category::Album);
|
||||
assert_eq!(browse.0.selection.artist.state.list.selected(), Some(1));
|
||||
assert_eq!(browse.inner.selection.active, Category::Album);
|
||||
assert_eq!(browse.inner.selection.artist.state.list.selected(), Some(1));
|
||||
|
||||
let search = browse.begin_search().unwrap_search();
|
||||
|
||||
@ -1097,8 +1010,8 @@ mod tests {
|
||||
|
||||
let browse = search.finish_search().unwrap_browse();
|
||||
|
||||
assert_eq!(browse.0.selection.active, Category::Album);
|
||||
assert_eq!(browse.0.selection.artist.state.list.selected(), Some(1));
|
||||
assert_eq!(browse.inner.selection.active, Category::Album);
|
||||
assert_eq!(browse.inner.selection.artist.state.list.selected(), Some(1));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -1108,8 +1021,8 @@ mod tests {
|
||||
let browse = browse.increment_selection(Delta::Line).unwrap_browse();
|
||||
let browse = browse.increment_category().unwrap_browse();
|
||||
|
||||
assert_eq!(browse.0.selection.active, Category::Album);
|
||||
assert_eq!(browse.0.selection.artist.state.list.selected(), Some(1));
|
||||
assert_eq!(browse.inner.selection.active, Category::Album);
|
||||
assert_eq!(browse.inner.selection.artist.state.list.selected(), Some(1));
|
||||
|
||||
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_category().unwrap_browse();
|
||||
|
||||
assert_eq!(browse.0.selection.active, Category::Album);
|
||||
assert_eq!(browse.0.selection.artist.state.list.selected(), Some(1));
|
||||
assert_eq!(browse.inner.selection.active, Category::Album);
|
||||
assert_eq!(browse.inner.selection.artist.state.list.selected(), Some(1));
|
||||
|
||||
let search = browse.begin_search().unwrap_search();
|
||||
|
||||
@ -1206,8 +1119,8 @@ mod tests {
|
||||
|
||||
let browse = search.cancel_search().unwrap_browse();
|
||||
|
||||
assert_eq!(browse.0.selection.active, Category::Album);
|
||||
assert_eq!(browse.0.selection.artist.state.list.selected(), Some(1));
|
||||
assert_eq!(browse.inner.selection.active, Category::Album);
|
||||
assert_eq!(browse.inner.selection.artist.state.list.selected(), Some(1));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -1217,8 +1130,8 @@ mod tests {
|
||||
let browse = browse.increment_selection(Delta::Line).unwrap_browse();
|
||||
let browse = browse.increment_category().unwrap_browse();
|
||||
|
||||
assert_eq!(browse.0.selection.active, Category::Album);
|
||||
assert_eq!(browse.0.selection.artist.state.list.selected(), None);
|
||||
assert_eq!(browse.inner.selection.active, Category::Album);
|
||||
assert_eq!(browse.inner.selection.artist.state.list.selected(), None);
|
||||
|
||||
let search = browse.begin_search().unwrap_search();
|
||||
|
||||
@ -1247,7 +1160,7 @@ mod tests {
|
||||
|
||||
let browse = search.cancel_search().unwrap_browse();
|
||||
|
||||
assert_eq!(browse.0.selection.active, Category::Album);
|
||||
assert_eq!(browse.0.selection.artist.state.list.selected(), None);
|
||||
assert_eq!(browse.inner.selection.active, Category::Album);
|
||||
assert_eq!(browse.inner.selection.artist.state.list.selected(), None);
|
||||
}
|
||||
}
|
||||
|
@ -48,6 +48,7 @@ pub struct TrackSelection {
|
||||
pub state: WidgetState,
|
||||
}
|
||||
|
||||
// FIXME: should be with browse state (maybe?)
|
||||
pub enum Delta {
|
||||
Line,
|
||||
Page,
|
||||
@ -268,6 +269,7 @@ impl ArtistSelection {
|
||||
result
|
||||
}
|
||||
|
||||
// FIXME: search logic should be with the search state
|
||||
fn incremental_search(
|
||||
&mut self,
|
||||
artists: &[Artist],
|
||||
|
@ -677,8 +677,8 @@ impl IUi for Ui {
|
||||
fn render<APP: IAppAccess>(app: &mut APP, frame: &mut Frame) {
|
||||
let app = app.get();
|
||||
|
||||
let collection = app.collection;
|
||||
let selection = app.selection;
|
||||
let collection = app.inner.collection;
|
||||
let selection = app.inner.selection;
|
||||
let state = app.state;
|
||||
|
||||
Self::render_main_frame(collection, selection, &state, frame);
|
||||
@ -695,7 +695,10 @@ impl IUi for Ui {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::tui::{
|
||||
app::{app::AppPublic, selection::Delta},
|
||||
app::{
|
||||
app::{AppPublic, AppPublicInner},
|
||||
selection::Delta,
|
||||
},
|
||||
testmod::COLLECTION,
|
||||
tests::terminal,
|
||||
};
|
||||
@ -706,9 +709,18 @@ mod tests {
|
||||
impl IAppAccess for AppPublic<'_> {
|
||||
fn get(&mut self) -> AppPublic {
|
||||
AppPublic {
|
||||
collection: self.collection,
|
||||
selection: self.selection,
|
||||
state: self.state,
|
||||
inner: AppPublicInner {
|
||||
collection: self.inner.collection,
|
||||
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 app = AppPublic {
|
||||
inner: AppPublicInner {
|
||||
collection,
|
||||
selection,
|
||||
},
|
||||
state: AppState::Browse(()),
|
||||
};
|
||||
terminal.draw(|frame| Ui::render(&mut app, frame)).unwrap();
|
||||
|
Loading…
Reference in New Issue
Block a user