Add manual input elements to the app an ui #216
@ -45,8 +45,8 @@ impl IAppInput for AppInputMode {
|
|||||||
|
|
||||||
fn confirm(mut self) -> Self::APP {
|
fn confirm(mut self) -> Self::APP {
|
||||||
if let AppState::Match(state) = &mut self.app {
|
if let AppState::Match(state) = &mut self.app {
|
||||||
state.submit_input(self.input)
|
state.submit_input(self.input);
|
||||||
};
|
}
|
||||||
self.app
|
self.app
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,3 +54,45 @@ impl IAppInput for AppInputMode {
|
|||||||
self.app
|
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::{
|
use crate::tui::{
|
||||||
app::{
|
app::{
|
||||||
machine::tests::{inner, music_hoard},
|
machine::tests::{inner, music_hoard},
|
||||||
IAppAccess,
|
IApp, IAppAccess, IAppInput,
|
||||||
},
|
},
|
||||||
lib::interface::musicbrainz::Match,
|
lib::interface::musicbrainz::Match,
|
||||||
};
|
};
|
||||||
@ -362,4 +362,21 @@ mod tests {
|
|||||||
let matches = AppMachine::match_state(inner(music_hoard(vec![])), match_state(None));
|
let matches = AppMachine::match_state(inner(music_hoard(vec![])), match_state(None));
|
||||||
matches.select().unwrap_browse();
|
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,
|
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 {
|
impl App {
|
||||||
pub fn new<MH: IMusicHoard + 'static, MB: IMusicBrainz + Send + 'static>(
|
pub fn new<MH: IMusicHoard + 'static, MB: IMusicBrainz + Send + 'static>(
|
||||||
mut music_hoard: MH,
|
mut music_hoard: MH,
|
||||||
@ -74,42 +104,20 @@ impl App {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn inner_ref(&self) -> &AppInner {
|
fn inner_ref(&self) -> &AppInner {
|
||||||
match self {
|
app_field_ref!(self, inner)
|
||||||
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,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn inner_mut(&mut self) -> &mut AppInner {
|
fn inner_mut(&mut self) -> &mut AppInner {
|
||||||
match self {
|
app_field_mut!(self, inner)
|
||||||
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,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
fn input_ref(&self) -> &Option<Input> {
|
||||||
|
app_field_ref!(self, input)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn input_mut(&mut self) -> &mut Option<Input> {
|
fn input_mut(&mut self) -> &mut Option<Input> {
|
||||||
match self {
|
app_field_mut!(self, input)
|
||||||
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,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -221,13 +229,29 @@ mod tests {
|
|||||||
use musichoard::collection::Collection;
|
use musichoard::collection::Collection;
|
||||||
|
|
||||||
use crate::tui::{
|
use crate::tui::{
|
||||||
app::{AppState, IApp, IAppInteractBrowse},
|
app::{AppState, IApp, IAppInput, IAppInteractBrowse},
|
||||||
lib::{interface::musicbrainz::MockIMusicBrainz, MockIMusicHoard},
|
lib::{interface::musicbrainz::MockIMusicBrainz, MockIMusicHoard},
|
||||||
EventChannel,
|
EventChannel,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::*;
|
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<
|
impl<
|
||||||
BrowseState,
|
BrowseState,
|
||||||
InfoState,
|
InfoState,
|
||||||
@ -313,7 +337,7 @@ mod tests {
|
|||||||
music_hoard
|
music_hoard
|
||||||
}
|
}
|
||||||
|
|
||||||
fn music_hoard_init(collection: Collection) -> MockIMusicHoard {
|
pub fn music_hoard_init(collection: Collection) -> MockIMusicHoard {
|
||||||
let mut music_hoard = music_hoard(collection);
|
let mut music_hoard = music_hoard(collection);
|
||||||
|
|
||||||
music_hoard
|
music_hoard
|
||||||
@ -324,11 +348,11 @@ mod tests {
|
|||||||
music_hoard
|
music_hoard
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mb_api() -> MockIMusicBrainz {
|
pub fn mb_api() -> MockIMusicBrainz {
|
||||||
MockIMusicBrainz::new()
|
MockIMusicBrainz::new()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn events() -> EventSender {
|
pub fn events() -> EventSender {
|
||||||
EventChannel::new().sender()
|
EventChannel::new().sender()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -340,6 +364,33 @@ mod tests {
|
|||||||
AppInner::new(music_hoard, mb_api, events())
|
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]
|
#[test]
|
||||||
fn state_browse() {
|
fn state_browse() {
|
||||||
let mut app = App::new(music_hoard_init(vec![]), mb_api(), events());
|
let mut app = App::new(music_hoard_init(vec![]), mb_api(), events());
|
||||||
|
Loading…
Reference in New Issue
Block a user