Add manual input elements to the app an ui #216
@ -45,8 +45,8 @@ impl IAppInput for AppInputMode {
|
||||
|
||||
fn confirm(mut self) -> Self::APP {
|
||||
if let AppState::Match(state) = &mut self.app {
|
||||
state.submit_input(self.input)
|
||||
};
|
||||
state.submit_input(self.input);
|
||||
}
|
||||
self.app
|
||||
}
|
||||
|
||||
@ -54,3 +54,45 @@ impl IAppInput for AppInputMode {
|
||||
self.app
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::tui::app::{
|
||||
machine::tests::{events, mb_api, music_hoard_init},
|
||||
IApp,
|
||||
};
|
||||
|
||||
use super::*;
|
||||
|
||||
fn input_event(c: char) -> InputEvent {
|
||||
InputEvent::new(
|
||||
crossterm::event::KeyCode::Char(c),
|
||||
crossterm::event::KeyModifiers::empty(),
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn handle_input() {
|
||||
let mut app = App::new(music_hoard_init(vec![]), mb_api(), events());
|
||||
app.input_mut().replace(Input::default());
|
||||
|
||||
let input = app.mode().unwrap_input();
|
||||
let app = input.input(input_event('H'));
|
||||
|
||||
let input = app.mode().unwrap_input();
|
||||
let app = input.input(input_event('e'));
|
||||
|
||||
let input = app.mode().unwrap_input();
|
||||
let app = input.input(input_event('l'));
|
||||
|
||||
let input = app.mode().unwrap_input();
|
||||
let app = input.input(input_event('l'));
|
||||
|
||||
let input = app.mode().unwrap_input();
|
||||
let app = input.input(input_event('o'));
|
||||
|
||||
assert_eq!(app.input_ref().as_ref().unwrap().0.value(), "Hello");
|
||||
|
||||
app.mode().unwrap_input().confirm().unwrap_browse();
|
||||
}
|
||||
}
|
||||
|
@ -177,7 +177,7 @@ mod tests {
|
||||
use crate::tui::{
|
||||
app::{
|
||||
machine::tests::{inner, music_hoard},
|
||||
IAppAccess,
|
||||
IApp, IAppAccess, IAppInput,
|
||||
},
|
||||
lib::interface::musicbrainz::Match,
|
||||
};
|
||||
@ -362,4 +362,21 @@ mod tests {
|
||||
let matches = AppMachine::match_state(inner(music_hoard(vec![])), match_state(None));
|
||||
matches.select().unwrap_browse();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn select_manual_input() {
|
||||
let matches =
|
||||
AppMachine::match_state(inner(music_hoard(vec![])), match_state(Some(album_match())));
|
||||
|
||||
// album_match has two matches which means that the fourth option should be manual input.
|
||||
let matches = matches.next_match().unwrap_match();
|
||||
let matches = matches.next_match().unwrap_match();
|
||||
let matches = matches.next_match().unwrap_match();
|
||||
let matches = matches.next_match().unwrap_match();
|
||||
|
||||
let app = matches.select();
|
||||
|
||||
let input = app.mode().unwrap_input();
|
||||
input.confirm().unwrap_match();
|
||||
}
|
||||
}
|
||||
|
@ -54,6 +54,36 @@ pub struct AppInner {
|
||||
events: EventSender,
|
||||
}
|
||||
|
||||
macro_rules! app_field_ref {
|
||||
($app:ident, $field:ident) => {
|
||||
match $app {
|
||||
AppState::Browse(state) => &state.$field,
|
||||
AppState::Info(state) => &state.$field,
|
||||
AppState::Reload(state) => &state.$field,
|
||||
AppState::Search(state) => &state.$field,
|
||||
AppState::Fetch(state) => &state.$field,
|
||||
AppState::Match(state) => &state.$field,
|
||||
AppState::Error(state) => &state.$field,
|
||||
AppState::Critical(state) => &state.$field,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! app_field_mut {
|
||||
($app:ident, $field:ident) => {
|
||||
match $app {
|
||||
AppState::Browse(state) => &mut state.$field,
|
||||
AppState::Info(state) => &mut state.$field,
|
||||
AppState::Reload(state) => &mut state.$field,
|
||||
AppState::Search(state) => &mut state.$field,
|
||||
AppState::Fetch(state) => &mut state.$field,
|
||||
AppState::Match(state) => &mut state.$field,
|
||||
AppState::Error(state) => &mut state.$field,
|
||||
AppState::Critical(state) => &mut state.$field,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl App {
|
||||
pub fn new<MH: IMusicHoard + 'static, MB: IMusicBrainz + Send + 'static>(
|
||||
mut music_hoard: MH,
|
||||
@ -74,42 +104,20 @@ impl App {
|
||||
}
|
||||
|
||||
fn inner_ref(&self) -> &AppInner {
|
||||
match self {
|
||||
AppState::Browse(browse_state) => &browse_state.inner,
|
||||
AppState::Info(info_state) => &info_state.inner,
|
||||
AppState::Reload(reload_state) => &reload_state.inner,
|
||||
AppState::Search(search_state) => &search_state.inner,
|
||||
AppState::Fetch(fetch_state) => &fetch_state.inner,
|
||||
AppState::Match(match_state) => &match_state.inner,
|
||||
AppState::Error(error_state) => &error_state.inner,
|
||||
AppState::Critical(critical_state) => &critical_state.inner,
|
||||
}
|
||||
app_field_ref!(self, inner)
|
||||
}
|
||||
|
||||
fn inner_mut(&mut self) -> &mut AppInner {
|
||||
match self {
|
||||
AppState::Browse(browse_state) => &mut browse_state.inner,
|
||||
AppState::Info(info_state) => &mut info_state.inner,
|
||||
AppState::Reload(reload_state) => &mut reload_state.inner,
|
||||
AppState::Search(search_state) => &mut search_state.inner,
|
||||
AppState::Fetch(fetch_state) => &mut fetch_state.inner,
|
||||
AppState::Match(match_state) => &mut match_state.inner,
|
||||
AppState::Error(error_state) => &mut error_state.inner,
|
||||
AppState::Critical(critical_state) => &mut critical_state.inner,
|
||||
app_field_mut!(self, inner)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
fn input_ref(&self) -> &Option<Input> {
|
||||
app_field_ref!(self, input)
|
||||
}
|
||||
|
||||
fn input_mut(&mut self) -> &mut Option<Input> {
|
||||
match self {
|
||||
AppState::Browse(state) => &mut state.input,
|
||||
AppState::Info(state) => &mut state.input,
|
||||
AppState::Reload(state) => &mut state.input,
|
||||
AppState::Search(state) => &mut state.input,
|
||||
AppState::Fetch(state) => &mut state.input,
|
||||
AppState::Match(state) => &mut state.input,
|
||||
AppState::Error(state) => &mut state.input,
|
||||
AppState::Critical(state) => &mut state.input,
|
||||
}
|
||||
app_field_mut!(self, input)
|
||||
}
|
||||
}
|
||||
|
||||
@ -221,13 +229,29 @@ mod tests {
|
||||
use musichoard::collection::Collection;
|
||||
|
||||
use crate::tui::{
|
||||
app::{AppState, IApp, IAppInteractBrowse},
|
||||
app::{AppState, IApp, IAppInput, IAppInteractBrowse},
|
||||
lib::{interface::musicbrainz::MockIMusicBrainz, MockIMusicHoard},
|
||||
EventChannel,
|
||||
};
|
||||
|
||||
use super::*;
|
||||
|
||||
impl<StateMode, InputMode> AppMode<StateMode, InputMode> {
|
||||
fn unwrap_state(self) -> StateMode {
|
||||
match self {
|
||||
AppMode::State(state) => state,
|
||||
_ => panic!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unwrap_input(self) -> InputMode {
|
||||
match self {
|
||||
AppMode::Input(input) => input,
|
||||
_ => panic!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<
|
||||
BrowseState,
|
||||
InfoState,
|
||||
@ -313,7 +337,7 @@ mod tests {
|
||||
music_hoard
|
||||
}
|
||||
|
||||
fn music_hoard_init(collection: Collection) -> MockIMusicHoard {
|
||||
pub fn music_hoard_init(collection: Collection) -> MockIMusicHoard {
|
||||
let mut music_hoard = music_hoard(collection);
|
||||
|
||||
music_hoard
|
||||
@ -324,11 +348,11 @@ mod tests {
|
||||
music_hoard
|
||||
}
|
||||
|
||||
fn mb_api() -> MockIMusicBrainz {
|
||||
pub fn mb_api() -> MockIMusicBrainz {
|
||||
MockIMusicBrainz::new()
|
||||
}
|
||||
|
||||
fn events() -> EventSender {
|
||||
pub fn events() -> EventSender {
|
||||
EventChannel::new().sender()
|
||||
}
|
||||
|
||||
@ -340,6 +364,33 @@ mod tests {
|
||||
AppInner::new(music_hoard, mb_api, events())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn input_mode() {
|
||||
let app = App::new(music_hoard_init(vec![]), mb_api(), events());
|
||||
assert!(app.is_running());
|
||||
|
||||
let mode = app.mode();
|
||||
assert!(matches!(mode, AppMode::State(_)));
|
||||
|
||||
let state = mode.unwrap_state();
|
||||
assert!(matches!(state, AppState::Browse(_)));
|
||||
|
||||
let mut app = state;
|
||||
app.input_mut().replace(Input::default());
|
||||
|
||||
let public = app.get();
|
||||
assert!(public.input.is_some());
|
||||
|
||||
let mode = app.mode();
|
||||
assert!(matches!(mode, AppMode::Input(_)));
|
||||
|
||||
let mut app = mode.unwrap_input().cancel();
|
||||
assert!(matches!(app, AppState::Browse(_)));
|
||||
|
||||
let public = app.get();
|
||||
assert!(public.input.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn state_browse() {
|
||||
let mut app = App::new(music_hoard_init(vec![]), mb_api(), events());
|
||||
|
Loading…
Reference in New Issue
Block a user