Tweaked the key mappings so that it is now easier to change key mappings and update the corresponding UI elements as well
This commit is contained in:
@@ -4,6 +4,7 @@ mod tests {
|
|||||||
use pretty_assertions::{assert_eq, assert_str_eq};
|
use pretty_assertions::{assert_eq, assert_str_eq};
|
||||||
use tokio::sync::mpsc;
|
use tokio::sync::mpsc;
|
||||||
|
|
||||||
|
use crate::app::key_binding::{build_keymapping_string, SERVARR_KEYMAPPINGS};
|
||||||
use crate::app::radarr::{ActiveRadarrBlock, RadarrData};
|
use crate::app::radarr::{ActiveRadarrBlock, RadarrData};
|
||||||
use crate::app::{App, Data, RadarrConfig, DEFAULT_ROUTE};
|
use crate::app::{App, Data, RadarrConfig, DEFAULT_ROUTE};
|
||||||
use crate::models::{HorizontallyScrollableText, Route, TabRoute};
|
use crate::models::{HorizontallyScrollableText, Route, TabRoute};
|
||||||
@@ -26,13 +27,16 @@ mod tests {
|
|||||||
TabRoute {
|
TabRoute {
|
||||||
title: "Radarr",
|
title: "Radarr",
|
||||||
route: ActiveRadarrBlock::Movies.into(),
|
route: ActiveRadarrBlock::Movies.into(),
|
||||||
help: "<↑↓> scroll | ←→ change tab | <tab> change servarr | <q> quit ",
|
help: format!(
|
||||||
|
"<↑↓> scroll | ←→ change tab | {} ",
|
||||||
|
build_keymapping_string(&SERVARR_KEYMAPPINGS)
|
||||||
|
),
|
||||||
contextual_help: None,
|
contextual_help: None,
|
||||||
},
|
},
|
||||||
TabRoute {
|
TabRoute {
|
||||||
title: "Sonarr",
|
title: "Sonarr",
|
||||||
route: Route::Sonarr,
|
route: Route::Sonarr,
|
||||||
help: "<tab> change servarr | <q> quit ",
|
help: format!("{} ", build_keymapping_string(&SERVARR_KEYMAPPINGS)),
|
||||||
contextual_help: None,
|
contextual_help: None,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|||||||
+49
-25
@@ -1,5 +1,15 @@
|
|||||||
use crate::event::Key;
|
use crate::event::Key;
|
||||||
|
|
||||||
|
pub(in crate::app) type KeyMapping = (KeyBinding, &'static str);
|
||||||
|
|
||||||
|
pub fn build_keymapping_string(key_mappings: &[(KeyBinding, &str)]) -> String {
|
||||||
|
key_mappings
|
||||||
|
.iter()
|
||||||
|
.map(|(key_binding, desc)| format!("{} {}", key_binding.key, desc))
|
||||||
|
.collect::<Vec<String>>()
|
||||||
|
.join(" | ")
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! generate_keybindings {
|
macro_rules! generate_keybindings {
|
||||||
($($field:ident),+) => {
|
($($field:ident),+) => {
|
||||||
pub struct KeyBindings {
|
pub struct KeyBindings {
|
||||||
@@ -28,12 +38,14 @@ generate_keybindings! {
|
|||||||
events,
|
events,
|
||||||
home,
|
home,
|
||||||
end,
|
end,
|
||||||
|
tab,
|
||||||
delete,
|
delete,
|
||||||
submit,
|
submit,
|
||||||
quit,
|
quit,
|
||||||
esc
|
esc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
pub struct KeyBinding {
|
pub struct KeyBinding {
|
||||||
pub key: Key,
|
pub key: Key,
|
||||||
pub desc: &'static str,
|
pub desc: &'static str,
|
||||||
@@ -42,94 +54,106 @@ pub struct KeyBinding {
|
|||||||
pub const DEFAULT_KEYBINDINGS: KeyBindings = KeyBindings {
|
pub const DEFAULT_KEYBINDINGS: KeyBindings = KeyBindings {
|
||||||
add: KeyBinding {
|
add: KeyBinding {
|
||||||
key: Key::Char('a'),
|
key: Key::Char('a'),
|
||||||
desc: "Add",
|
desc: "add",
|
||||||
},
|
},
|
||||||
up: KeyBinding {
|
up: KeyBinding {
|
||||||
key: Key::Up,
|
key: Key::Up,
|
||||||
desc: "Scroll up",
|
desc: "up",
|
||||||
},
|
},
|
||||||
down: KeyBinding {
|
down: KeyBinding {
|
||||||
key: Key::Down,
|
key: Key::Down,
|
||||||
desc: "Scroll down",
|
desc: "down",
|
||||||
},
|
},
|
||||||
left: KeyBinding {
|
left: KeyBinding {
|
||||||
key: Key::Left,
|
key: Key::Left,
|
||||||
desc: "Move left",
|
desc: "left",
|
||||||
},
|
},
|
||||||
right: KeyBinding {
|
right: KeyBinding {
|
||||||
key: Key::Right,
|
key: Key::Right,
|
||||||
desc: "Move right",
|
desc: "right",
|
||||||
},
|
},
|
||||||
backspace: KeyBinding {
|
backspace: KeyBinding {
|
||||||
key: Key::Backspace,
|
key: Key::Backspace,
|
||||||
desc: "Backspace",
|
desc: "backspace",
|
||||||
},
|
},
|
||||||
search: KeyBinding {
|
search: KeyBinding {
|
||||||
key: Key::Char('s'),
|
key: Key::Char('s'),
|
||||||
desc: "Search",
|
desc: "search",
|
||||||
},
|
},
|
||||||
settings: KeyBinding {
|
settings: KeyBinding {
|
||||||
key: Key::Char('s'),
|
key: Key::Char('s'),
|
||||||
desc: "Settings",
|
desc: "settings",
|
||||||
},
|
},
|
||||||
filter: KeyBinding {
|
filter: KeyBinding {
|
||||||
key: Key::Char('f'),
|
key: Key::Char('f'),
|
||||||
desc: "Filter",
|
desc: "filter",
|
||||||
},
|
},
|
||||||
sort: KeyBinding {
|
sort: KeyBinding {
|
||||||
key: Key::Char('o'),
|
key: Key::Char('o'),
|
||||||
desc: "Sort",
|
desc: "sort",
|
||||||
},
|
},
|
||||||
edit: KeyBinding {
|
edit: KeyBinding {
|
||||||
key: Key::Char('e'),
|
key: Key::Char('e'),
|
||||||
desc: "Edit",
|
desc: "edit",
|
||||||
},
|
},
|
||||||
events: KeyBinding {
|
events: KeyBinding {
|
||||||
key: Key::Char('e'),
|
key: Key::Char('e'),
|
||||||
desc: "Events",
|
desc: "events",
|
||||||
},
|
},
|
||||||
logs: KeyBinding {
|
logs: KeyBinding {
|
||||||
key: Key::Char('l'),
|
key: Key::Char('l'),
|
||||||
desc: "Logs",
|
desc: "logs",
|
||||||
},
|
},
|
||||||
tasks: KeyBinding {
|
tasks: KeyBinding {
|
||||||
key: Key::Char('t'),
|
key: Key::Char('t'),
|
||||||
desc: "Tasks",
|
desc: "tasks",
|
||||||
},
|
},
|
||||||
restrictions: KeyBinding {
|
restrictions: KeyBinding {
|
||||||
key: Key::Char('t'),
|
key: Key::Char('R'),
|
||||||
desc: "Restrictions",
|
desc: "restrictions",
|
||||||
},
|
},
|
||||||
refresh: KeyBinding {
|
refresh: KeyBinding {
|
||||||
key: Key::Char('r'),
|
key: Key::Ctrl('r'),
|
||||||
desc: "Refresh",
|
desc: "refresh",
|
||||||
},
|
},
|
||||||
update: KeyBinding {
|
update: KeyBinding {
|
||||||
key: Key::Char('u'),
|
key: Key::Char('u'),
|
||||||
desc: "Update",
|
desc: "update",
|
||||||
},
|
},
|
||||||
home: KeyBinding {
|
home: KeyBinding {
|
||||||
key: Key::Home,
|
key: Key::Home,
|
||||||
desc: "Home",
|
desc: "home",
|
||||||
},
|
},
|
||||||
end: KeyBinding {
|
end: KeyBinding {
|
||||||
key: Key::End,
|
key: Key::End,
|
||||||
desc: "End",
|
desc: "end",
|
||||||
|
},
|
||||||
|
tab: KeyBinding {
|
||||||
|
key: Key::Tab,
|
||||||
|
desc: "tab",
|
||||||
},
|
},
|
||||||
delete: KeyBinding {
|
delete: KeyBinding {
|
||||||
key: Key::Delete,
|
key: Key::Delete,
|
||||||
desc: "Delete selected item",
|
desc: "delete",
|
||||||
},
|
},
|
||||||
submit: KeyBinding {
|
submit: KeyBinding {
|
||||||
key: Key::Enter,
|
key: Key::Enter,
|
||||||
desc: "Select",
|
desc: "submit",
|
||||||
},
|
},
|
||||||
quit: KeyBinding {
|
quit: KeyBinding {
|
||||||
key: Key::Char('q'),
|
key: Key::Char('q'),
|
||||||
desc: "Quit",
|
desc: "quit",
|
||||||
},
|
},
|
||||||
esc: KeyBinding {
|
esc: KeyBinding {
|
||||||
key: Key::Esc,
|
key: Key::Esc,
|
||||||
desc: "Exit current menu",
|
desc: "close",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub static SERVARR_KEYMAPPINGS: [KeyMapping; 2] = [
|
||||||
|
(DEFAULT_KEYBINDINGS.tab, "change servarr"),
|
||||||
|
(DEFAULT_KEYBINDINGS.quit, DEFAULT_KEYBINDINGS.quit.desc),
|
||||||
|
];
|
||||||
|
|
||||||
|
pub static BARE_POPUP_KEY_MAPPINGS: [KeyMapping; 1] =
|
||||||
|
[(DEFAULT_KEYBINDINGS.esc, DEFAULT_KEYBINDINGS.esc.desc)];
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use crate::app::key_binding::{build_keymapping_string, DEFAULT_KEYBINDINGS};
|
||||||
|
use pretty_assertions::assert_str_eq;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_build_keymapping_string() {
|
||||||
|
let test_keys_array = [
|
||||||
|
(DEFAULT_KEYBINDINGS.add, "add"),
|
||||||
|
(DEFAULT_KEYBINDINGS.delete, "delete"),
|
||||||
|
];
|
||||||
|
|
||||||
|
assert_str_eq!(
|
||||||
|
build_keymapping_string(&test_keys_array),
|
||||||
|
"<a> add | <del> delete"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
+8
-2
@@ -9,10 +9,13 @@ use crate::app::radarr::{ActiveRadarrBlock, RadarrData};
|
|||||||
use crate::models::{HorizontallyScrollableText, Route, TabRoute, TabState};
|
use crate::models::{HorizontallyScrollableText, Route, TabRoute, TabState};
|
||||||
use crate::network::NetworkEvent;
|
use crate::network::NetworkEvent;
|
||||||
|
|
||||||
|
use self::key_binding::{build_keymapping_string, SERVARR_KEYMAPPINGS};
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[path = "app_tests.rs"]
|
#[path = "app_tests.rs"]
|
||||||
mod app_tests;
|
mod app_tests;
|
||||||
pub mod key_binding;
|
pub mod key_binding;
|
||||||
|
mod key_binding_tests;
|
||||||
pub mod radarr;
|
pub mod radarr;
|
||||||
|
|
||||||
const DEFAULT_ROUTE: Route = Route::Radarr(ActiveRadarrBlock::Movies, None);
|
const DEFAULT_ROUTE: Route = Route::Radarr(ActiveRadarrBlock::Movies, None);
|
||||||
@@ -137,13 +140,16 @@ impl<'a> Default for App<'a> {
|
|||||||
TabRoute {
|
TabRoute {
|
||||||
title: "Radarr",
|
title: "Radarr",
|
||||||
route: ActiveRadarrBlock::Movies.into(),
|
route: ActiveRadarrBlock::Movies.into(),
|
||||||
help: "<↑↓> scroll | ←→ change tab | <tab> change servarr | <q> quit ",
|
help: format!(
|
||||||
|
"<↑↓> scroll | ←→ change tab | {} ",
|
||||||
|
build_keymapping_string(&SERVARR_KEYMAPPINGS)
|
||||||
|
),
|
||||||
contextual_help: None,
|
contextual_help: None,
|
||||||
},
|
},
|
||||||
TabRoute {
|
TabRoute {
|
||||||
title: "Sonarr",
|
title: "Sonarr",
|
||||||
route: Route::Sonarr,
|
route: Route::Sonarr,
|
||||||
help: "<tab> change servarr | <q> quit ",
|
help: format!("{} ", build_keymapping_string(&SERVARR_KEYMAPPINGS)),
|
||||||
contextual_help: None,
|
contextual_help: None,
|
||||||
},
|
},
|
||||||
]),
|
]),
|
||||||
|
|||||||
@@ -15,6 +15,16 @@ use crate::models::{
|
|||||||
};
|
};
|
||||||
use crate::network::radarr_network::RadarrEvent;
|
use crate::network::radarr_network::RadarrEvent;
|
||||||
|
|
||||||
|
use self::radarr_key_mappings::{
|
||||||
|
COLLECTIONS_KEY_MAPPINGS, DOWNLOADS_KEY_MAPPINGS, INDEXERS_KEY_MAPPINGS, LIBRARY_KEY_MAPPINGS,
|
||||||
|
MANUAL_MOVIE_SEARCH_CONTEXTUAL_KEY_MAPPINGS, MANUAL_MOVIE_SEARCH_KEY_MAPPINGS,
|
||||||
|
MOVIE_DETAILS_KEY_MAPPINGS, ROOT_FOLDERS_KEY_MAPPINGS, SYSTEM_KEY_MAPPINGS,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::key_binding::build_keymapping_string;
|
||||||
|
|
||||||
|
pub mod radarr_key_mappings;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[path = "radarr_tests.rs"]
|
#[path = "radarr_tests.rs"]
|
||||||
mod radarr_tests;
|
mod radarr_tests;
|
||||||
@@ -302,76 +312,78 @@ impl<'a> Default for RadarrData<'a> {
|
|||||||
TabRoute {
|
TabRoute {
|
||||||
title: "Library",
|
title: "Library",
|
||||||
route: ActiveRadarrBlock::Movies.into(),
|
route: ActiveRadarrBlock::Movies.into(),
|
||||||
help: "",
|
help: String::new(),
|
||||||
contextual_help: Some("<a> add | <e> edit | <del> delete | <s> search | <f> filter | <r> refresh | <u> update all | <enter> details | <esc> cancel filter"),
|
contextual_help: Some(build_keymapping_string(&LIBRARY_KEY_MAPPINGS)),
|
||||||
},
|
},
|
||||||
TabRoute {
|
TabRoute {
|
||||||
title: "Downloads",
|
title: "Downloads",
|
||||||
route: ActiveRadarrBlock::Downloads.into(),
|
route: ActiveRadarrBlock::Downloads.into(),
|
||||||
help: "",
|
help: String::new(),
|
||||||
contextual_help: Some("<r> refresh | <del> delete"),
|
contextual_help: Some(build_keymapping_string(&DOWNLOADS_KEY_MAPPINGS)),
|
||||||
},
|
},
|
||||||
TabRoute {
|
TabRoute {
|
||||||
title: "Collections",
|
title: "Collections",
|
||||||
route: ActiveRadarrBlock::Collections.into(),
|
route: ActiveRadarrBlock::Collections.into(),
|
||||||
help: "",
|
help: String::new(),
|
||||||
contextual_help: Some("<s> search | <e> edit | <f> filter | <r> refresh | <u> update all | <enter> details | <esc> cancel filter"),
|
contextual_help: Some(build_keymapping_string(&COLLECTIONS_KEY_MAPPINGS)),
|
||||||
},
|
},
|
||||||
TabRoute {
|
TabRoute {
|
||||||
title: "Root Folders",
|
title: "Root Folders",
|
||||||
route: ActiveRadarrBlock::RootFolders.into(),
|
route: ActiveRadarrBlock::RootFolders.into(),
|
||||||
help: "",
|
help: String::new(),
|
||||||
contextual_help: Some("<a> add | <del> delete | <r> refresh"),
|
contextual_help: Some(build_keymapping_string(&ROOT_FOLDERS_KEY_MAPPINGS)),
|
||||||
},
|
},
|
||||||
TabRoute {
|
TabRoute {
|
||||||
title: "Indexers",
|
title: "Indexers",
|
||||||
route: ActiveRadarrBlock::Indexers.into(),
|
route: ActiveRadarrBlock::Indexers.into(),
|
||||||
help: "",
|
help: String::new(),
|
||||||
contextual_help: Some("<a> add | <enter> edit | <s> settings | <t> restrictions | <del> delete | <r> refresh"),
|
contextual_help: Some(build_keymapping_string(&INDEXERS_KEY_MAPPINGS)),
|
||||||
},
|
},
|
||||||
TabRoute {
|
TabRoute {
|
||||||
title: "System",
|
title: "System",
|
||||||
route: ActiveRadarrBlock::System.into(),
|
route: ActiveRadarrBlock::System.into(),
|
||||||
help: "",
|
help: String::new(),
|
||||||
contextual_help: Some("<t> open tasks | <e> open events | <l> open logs | <u> open updates | <r> refresh"),
|
contextual_help: Some(build_keymapping_string(&SYSTEM_KEY_MAPPINGS)),
|
||||||
},
|
},
|
||||||
]),
|
]),
|
||||||
movie_info_tabs: TabState::new(vec![
|
movie_info_tabs: TabState::new(vec![
|
||||||
TabRoute {
|
TabRoute {
|
||||||
title: "Details",
|
title: "Details",
|
||||||
route: ActiveRadarrBlock::MovieDetails.into(),
|
route: ActiveRadarrBlock::MovieDetails.into(),
|
||||||
help: "<r> refresh | <u> update | <e> edit | <s> auto search | <esc> close",
|
help: build_keymapping_string(&MOVIE_DETAILS_KEY_MAPPINGS),
|
||||||
contextual_help: None,
|
contextual_help: None,
|
||||||
},
|
},
|
||||||
TabRoute {
|
TabRoute {
|
||||||
title: "History",
|
title: "History",
|
||||||
route: ActiveRadarrBlock::MovieHistory.into(),
|
route: ActiveRadarrBlock::MovieHistory.into(),
|
||||||
help: "<r> refresh | <u> update | <e> edit | <s> auto search | <esc> close",
|
help: build_keymapping_string(&MOVIE_DETAILS_KEY_MAPPINGS),
|
||||||
contextual_help: None,
|
contextual_help: None,
|
||||||
},
|
},
|
||||||
TabRoute {
|
TabRoute {
|
||||||
title: "File",
|
title: "File",
|
||||||
route: ActiveRadarrBlock::FileInfo.into(),
|
route: ActiveRadarrBlock::FileInfo.into(),
|
||||||
help: "<r> refresh | <u> update | <e> edit | <s> auto search | <esc> close",
|
help: build_keymapping_string(&MOVIE_DETAILS_KEY_MAPPINGS),
|
||||||
contextual_help: None,
|
contextual_help: None,
|
||||||
},
|
},
|
||||||
TabRoute {
|
TabRoute {
|
||||||
title: "Cast",
|
title: "Cast",
|
||||||
route: ActiveRadarrBlock::Cast.into(),
|
route: ActiveRadarrBlock::Cast.into(),
|
||||||
help: "<r> refresh | <u> update | <e> edit | <s> auto search | <esc> close",
|
help: build_keymapping_string(&MOVIE_DETAILS_KEY_MAPPINGS),
|
||||||
contextual_help: None,
|
contextual_help: None,
|
||||||
},
|
},
|
||||||
TabRoute {
|
TabRoute {
|
||||||
title: "Crew",
|
title: "Crew",
|
||||||
route: ActiveRadarrBlock::Crew.into(),
|
route: ActiveRadarrBlock::Crew.into(),
|
||||||
help: "<r> refresh | <u> update | <e> edit | <s> auto search | <esc> close",
|
help: build_keymapping_string(&MOVIE_DETAILS_KEY_MAPPINGS),
|
||||||
contextual_help: None,
|
contextual_help: None,
|
||||||
},
|
},
|
||||||
TabRoute {
|
TabRoute {
|
||||||
title: "Manual Search",
|
title: "Manual Search",
|
||||||
route: ActiveRadarrBlock::ManualSearch.into(),
|
route: ActiveRadarrBlock::ManualSearch.into(),
|
||||||
help: "<r> refresh | <u> update | <e> edit | <o> sort | <s> auto search | <esc> close",
|
help: build_keymapping_string(&MANUAL_MOVIE_SEARCH_KEY_MAPPINGS),
|
||||||
contextual_help: Some("<enter> details"),
|
contextual_help: Some(build_keymapping_string(
|
||||||
|
&MANUAL_MOVIE_SEARCH_CONTEXTUAL_KEY_MAPPINGS,
|
||||||
|
)),
|
||||||
},
|
},
|
||||||
]),
|
]),
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,116 @@
|
|||||||
|
use crate::app::key_binding::{KeyMapping, DEFAULT_KEYBINDINGS};
|
||||||
|
|
||||||
|
pub static LIBRARY_KEY_MAPPINGS: [KeyMapping; 9] = [
|
||||||
|
(DEFAULT_KEYBINDINGS.add, DEFAULT_KEYBINDINGS.add.desc),
|
||||||
|
(DEFAULT_KEYBINDINGS.edit, DEFAULT_KEYBINDINGS.edit.desc),
|
||||||
|
(DEFAULT_KEYBINDINGS.delete, DEFAULT_KEYBINDINGS.delete.desc),
|
||||||
|
(DEFAULT_KEYBINDINGS.search, DEFAULT_KEYBINDINGS.search.desc),
|
||||||
|
(DEFAULT_KEYBINDINGS.filter, DEFAULT_KEYBINDINGS.filter.desc),
|
||||||
|
(
|
||||||
|
DEFAULT_KEYBINDINGS.refresh,
|
||||||
|
DEFAULT_KEYBINDINGS.refresh.desc,
|
||||||
|
),
|
||||||
|
(DEFAULT_KEYBINDINGS.update, "update all"),
|
||||||
|
(DEFAULT_KEYBINDINGS.submit, "details"),
|
||||||
|
(DEFAULT_KEYBINDINGS.esc, "cancel filter"),
|
||||||
|
];
|
||||||
|
|
||||||
|
pub static DOWNLOADS_KEY_MAPPINGS: [KeyMapping; 2] = [
|
||||||
|
(
|
||||||
|
DEFAULT_KEYBINDINGS.refresh,
|
||||||
|
DEFAULT_KEYBINDINGS.refresh.desc,
|
||||||
|
),
|
||||||
|
(DEFAULT_KEYBINDINGS.delete, DEFAULT_KEYBINDINGS.delete.desc),
|
||||||
|
];
|
||||||
|
|
||||||
|
pub static COLLECTIONS_KEY_MAPPINGS: [KeyMapping; 7] = [
|
||||||
|
(DEFAULT_KEYBINDINGS.search, DEFAULT_KEYBINDINGS.search.desc),
|
||||||
|
(DEFAULT_KEYBINDINGS.edit, DEFAULT_KEYBINDINGS.edit.desc),
|
||||||
|
(DEFAULT_KEYBINDINGS.filter, DEFAULT_KEYBINDINGS.filter.desc),
|
||||||
|
(
|
||||||
|
DEFAULT_KEYBINDINGS.refresh,
|
||||||
|
DEFAULT_KEYBINDINGS.refresh.desc,
|
||||||
|
),
|
||||||
|
(DEFAULT_KEYBINDINGS.update, "update all"),
|
||||||
|
(DEFAULT_KEYBINDINGS.submit, "details"),
|
||||||
|
(DEFAULT_KEYBINDINGS.esc, "cancel filter"),
|
||||||
|
];
|
||||||
|
|
||||||
|
pub static ROOT_FOLDERS_KEY_MAPPINGS: [KeyMapping; 3] = [
|
||||||
|
(DEFAULT_KEYBINDINGS.add, DEFAULT_KEYBINDINGS.add.desc),
|
||||||
|
(DEFAULT_KEYBINDINGS.delete, DEFAULT_KEYBINDINGS.delete.desc),
|
||||||
|
(
|
||||||
|
DEFAULT_KEYBINDINGS.refresh,
|
||||||
|
DEFAULT_KEYBINDINGS.refresh.desc,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
pub static INDEXERS_KEY_MAPPINGS: [KeyMapping; 6] = [
|
||||||
|
(DEFAULT_KEYBINDINGS.add, DEFAULT_KEYBINDINGS.add.desc),
|
||||||
|
(DEFAULT_KEYBINDINGS.edit, DEFAULT_KEYBINDINGS.edit.desc),
|
||||||
|
(
|
||||||
|
DEFAULT_KEYBINDINGS.settings,
|
||||||
|
DEFAULT_KEYBINDINGS.settings.desc,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
DEFAULT_KEYBINDINGS.restrictions,
|
||||||
|
DEFAULT_KEYBINDINGS.restrictions.desc,
|
||||||
|
),
|
||||||
|
(DEFAULT_KEYBINDINGS.delete, DEFAULT_KEYBINDINGS.delete.desc),
|
||||||
|
(
|
||||||
|
DEFAULT_KEYBINDINGS.refresh,
|
||||||
|
DEFAULT_KEYBINDINGS.refresh.desc,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
pub static SYSTEM_KEY_MAPPINGS: [KeyMapping; 5] = [
|
||||||
|
(DEFAULT_KEYBINDINGS.tasks, "open tasks"),
|
||||||
|
(DEFAULT_KEYBINDINGS.events, "open events"),
|
||||||
|
(DEFAULT_KEYBINDINGS.logs, "open logs"),
|
||||||
|
(DEFAULT_KEYBINDINGS.update, "open updates"),
|
||||||
|
(
|
||||||
|
DEFAULT_KEYBINDINGS.refresh,
|
||||||
|
DEFAULT_KEYBINDINGS.refresh.desc,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
pub static MOVIE_DETAILS_KEY_MAPPINGS: [KeyMapping; 5] = [
|
||||||
|
(
|
||||||
|
DEFAULT_KEYBINDINGS.refresh,
|
||||||
|
DEFAULT_KEYBINDINGS.refresh.desc,
|
||||||
|
),
|
||||||
|
(DEFAULT_KEYBINDINGS.update, DEFAULT_KEYBINDINGS.update.desc),
|
||||||
|
(DEFAULT_KEYBINDINGS.edit, DEFAULT_KEYBINDINGS.edit.desc),
|
||||||
|
(DEFAULT_KEYBINDINGS.search, "auto search"),
|
||||||
|
(DEFAULT_KEYBINDINGS.esc, DEFAULT_KEYBINDINGS.esc.desc),
|
||||||
|
];
|
||||||
|
|
||||||
|
pub static MANUAL_MOVIE_SEARCH_KEY_MAPPINGS: [KeyMapping; 6] = [
|
||||||
|
(
|
||||||
|
DEFAULT_KEYBINDINGS.refresh,
|
||||||
|
DEFAULT_KEYBINDINGS.refresh.desc,
|
||||||
|
),
|
||||||
|
(DEFAULT_KEYBINDINGS.update, DEFAULT_KEYBINDINGS.update.desc),
|
||||||
|
(DEFAULT_KEYBINDINGS.edit, DEFAULT_KEYBINDINGS.edit.desc),
|
||||||
|
(DEFAULT_KEYBINDINGS.sort, DEFAULT_KEYBINDINGS.sort.desc),
|
||||||
|
(DEFAULT_KEYBINDINGS.search, "auto search"),
|
||||||
|
(DEFAULT_KEYBINDINGS.esc, DEFAULT_KEYBINDINGS.esc.desc),
|
||||||
|
];
|
||||||
|
|
||||||
|
pub static MANUAL_MOVIE_SEARCH_CONTEXTUAL_KEY_MAPPINGS: [KeyMapping; 1] =
|
||||||
|
[(DEFAULT_KEYBINDINGS.submit, "details")];
|
||||||
|
|
||||||
|
pub static ADD_MOVIE_SEARCH_RESULTS_KEY_MAPPINGS: [KeyMapping; 2] = [
|
||||||
|
(DEFAULT_KEYBINDINGS.submit, "details"),
|
||||||
|
(DEFAULT_KEYBINDINGS.esc, "edit search"),
|
||||||
|
];
|
||||||
|
|
||||||
|
pub static SYSTEM_TASKS_KEY_MAPPINGS: [KeyMapping; 2] = [
|
||||||
|
(DEFAULT_KEYBINDINGS.submit, "start task"),
|
||||||
|
(DEFAULT_KEYBINDINGS.esc, DEFAULT_KEYBINDINGS.esc.desc),
|
||||||
|
];
|
||||||
|
|
||||||
|
pub static COLLECTION_DETAILS_KEY_MAPPINGS: [KeyMapping; 2] = [
|
||||||
|
(DEFAULT_KEYBINDINGS.submit, "show overview/add movie"),
|
||||||
|
(DEFAULT_KEYBINDINGS.esc, DEFAULT_KEYBINDINGS.esc.desc),
|
||||||
|
];
|
||||||
@@ -8,6 +8,13 @@ mod tests {
|
|||||||
use serde_json::Number;
|
use serde_json::Number;
|
||||||
use strum::IntoEnumIterator;
|
use strum::IntoEnumIterator;
|
||||||
|
|
||||||
|
use crate::app::key_binding::build_keymapping_string;
|
||||||
|
use crate::app::radarr::radarr_key_mappings::{
|
||||||
|
COLLECTIONS_KEY_MAPPINGS, DOWNLOADS_KEY_MAPPINGS, INDEXERS_KEY_MAPPINGS,
|
||||||
|
LIBRARY_KEY_MAPPINGS, MANUAL_MOVIE_SEARCH_CONTEXTUAL_KEY_MAPPINGS,
|
||||||
|
MANUAL_MOVIE_SEARCH_KEY_MAPPINGS, MOVIE_DETAILS_KEY_MAPPINGS, ROOT_FOLDERS_KEY_MAPPINGS,
|
||||||
|
SYSTEM_KEY_MAPPINGS,
|
||||||
|
};
|
||||||
use crate::app::radarr::radarr_test_utils::utils::create_test_radarr_data;
|
use crate::app::radarr::radarr_test_utils::utils::create_test_radarr_data;
|
||||||
use crate::app::radarr::{ActiveRadarrBlock, RadarrData};
|
use crate::app::radarr::{ActiveRadarrBlock, RadarrData};
|
||||||
use crate::models::radarr_models::{
|
use crate::models::radarr_models::{
|
||||||
@@ -316,8 +323,10 @@ mod tests {
|
|||||||
ActiveRadarrBlock::Movies.into()
|
ActiveRadarrBlock::Movies.into()
|
||||||
);
|
);
|
||||||
assert!(radarr_data.main_tabs.tabs[0].help.is_empty());
|
assert!(radarr_data.main_tabs.tabs[0].help.is_empty());
|
||||||
assert_eq!(radarr_data.main_tabs.tabs[0].contextual_help,
|
assert_eq!(
|
||||||
Some("<a> add | <e> edit | <del> delete | <s> search | <f> filter | <r> refresh | <u> update all | <enter> details | <esc> cancel filter"));
|
radarr_data.main_tabs.tabs[0].contextual_help,
|
||||||
|
Some(build_keymapping_string(&LIBRARY_KEY_MAPPINGS))
|
||||||
|
);
|
||||||
|
|
||||||
assert_str_eq!(radarr_data.main_tabs.tabs[1].title, "Downloads");
|
assert_str_eq!(radarr_data.main_tabs.tabs[1].title, "Downloads");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@@ -327,7 +336,7 @@ mod tests {
|
|||||||
assert!(radarr_data.main_tabs.tabs[1].help.is_empty());
|
assert!(radarr_data.main_tabs.tabs[1].help.is_empty());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
radarr_data.main_tabs.tabs[1].contextual_help,
|
radarr_data.main_tabs.tabs[1].contextual_help,
|
||||||
Some("<r> refresh | <del> delete")
|
Some(build_keymapping_string(&DOWNLOADS_KEY_MAPPINGS))
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_str_eq!(radarr_data.main_tabs.tabs[2].title, "Collections");
|
assert_str_eq!(radarr_data.main_tabs.tabs[2].title, "Collections");
|
||||||
@@ -336,8 +345,10 @@ mod tests {
|
|||||||
ActiveRadarrBlock::Collections.into()
|
ActiveRadarrBlock::Collections.into()
|
||||||
);
|
);
|
||||||
assert!(radarr_data.main_tabs.tabs[2].help.is_empty());
|
assert!(radarr_data.main_tabs.tabs[2].help.is_empty());
|
||||||
assert_eq!(radarr_data.main_tabs.tabs[2].contextual_help,
|
assert_eq!(
|
||||||
Some("<s> search | <e> edit | <f> filter | <r> refresh | <u> update all | <enter> details | <esc> cancel filter"));
|
radarr_data.main_tabs.tabs[2].contextual_help,
|
||||||
|
Some(build_keymapping_string(&COLLECTIONS_KEY_MAPPINGS))
|
||||||
|
);
|
||||||
|
|
||||||
assert_str_eq!(radarr_data.main_tabs.tabs[3].title, "Root Folders");
|
assert_str_eq!(radarr_data.main_tabs.tabs[3].title, "Root Folders");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@@ -347,7 +358,7 @@ mod tests {
|
|||||||
assert!(radarr_data.main_tabs.tabs[3].help.is_empty());
|
assert!(radarr_data.main_tabs.tabs[3].help.is_empty());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
radarr_data.main_tabs.tabs[3].contextual_help,
|
radarr_data.main_tabs.tabs[3].contextual_help,
|
||||||
Some("<a> add | <del> delete | <r> refresh")
|
Some(build_keymapping_string(&ROOT_FOLDERS_KEY_MAPPINGS))
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_str_eq!(radarr_data.main_tabs.tabs[4].title, "Indexers");
|
assert_str_eq!(radarr_data.main_tabs.tabs[4].title, "Indexers");
|
||||||
@@ -358,9 +369,7 @@ mod tests {
|
|||||||
assert!(radarr_data.main_tabs.tabs[4].help.is_empty());
|
assert!(radarr_data.main_tabs.tabs[4].help.is_empty());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
radarr_data.main_tabs.tabs[4].contextual_help,
|
radarr_data.main_tabs.tabs[4].contextual_help,
|
||||||
Some(
|
Some(build_keymapping_string(&INDEXERS_KEY_MAPPINGS))
|
||||||
"<a> add | <enter> edit | <s> settings | <t> restrictions | <del> delete | <r> refresh"
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_str_eq!(radarr_data.main_tabs.tabs[5].title, "System");
|
assert_str_eq!(radarr_data.main_tabs.tabs[5].title, "System");
|
||||||
@@ -371,7 +380,7 @@ mod tests {
|
|||||||
assert!(radarr_data.main_tabs.tabs[5].help.is_empty());
|
assert!(radarr_data.main_tabs.tabs[5].help.is_empty());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
radarr_data.main_tabs.tabs[5].contextual_help,
|
radarr_data.main_tabs.tabs[5].contextual_help,
|
||||||
Some("<t> open tasks | <e> open events | <l> open logs | <u> open updates | <r> refresh")
|
Some(build_keymapping_string(&SYSTEM_KEY_MAPPINGS))
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(radarr_data.movie_info_tabs.tabs.len(), 6);
|
assert_eq!(radarr_data.movie_info_tabs.tabs.len(), 6);
|
||||||
@@ -383,7 +392,7 @@ mod tests {
|
|||||||
);
|
);
|
||||||
assert_str_eq!(
|
assert_str_eq!(
|
||||||
radarr_data.movie_info_tabs.tabs[0].help,
|
radarr_data.movie_info_tabs.tabs[0].help,
|
||||||
"<r> refresh | <u> update | <e> edit | <s> auto search | <esc> close"
|
build_keymapping_string(&MOVIE_DETAILS_KEY_MAPPINGS)
|
||||||
);
|
);
|
||||||
assert!(radarr_data.movie_info_tabs.tabs[0]
|
assert!(radarr_data.movie_info_tabs.tabs[0]
|
||||||
.contextual_help
|
.contextual_help
|
||||||
@@ -396,7 +405,7 @@ mod tests {
|
|||||||
);
|
);
|
||||||
assert_str_eq!(
|
assert_str_eq!(
|
||||||
radarr_data.movie_info_tabs.tabs[1].help,
|
radarr_data.movie_info_tabs.tabs[1].help,
|
||||||
"<r> refresh | <u> update | <e> edit | <s> auto search | <esc> close"
|
build_keymapping_string(&MOVIE_DETAILS_KEY_MAPPINGS)
|
||||||
);
|
);
|
||||||
assert!(radarr_data.movie_info_tabs.tabs[1]
|
assert!(radarr_data.movie_info_tabs.tabs[1]
|
||||||
.contextual_help
|
.contextual_help
|
||||||
@@ -409,7 +418,7 @@ mod tests {
|
|||||||
);
|
);
|
||||||
assert_str_eq!(
|
assert_str_eq!(
|
||||||
radarr_data.movie_info_tabs.tabs[2].help,
|
radarr_data.movie_info_tabs.tabs[2].help,
|
||||||
"<r> refresh | <u> update | <e> edit | <s> auto search | <esc> close"
|
build_keymapping_string(&MOVIE_DETAILS_KEY_MAPPINGS)
|
||||||
);
|
);
|
||||||
assert!(radarr_data.movie_info_tabs.tabs[2]
|
assert!(radarr_data.movie_info_tabs.tabs[2]
|
||||||
.contextual_help
|
.contextual_help
|
||||||
@@ -422,7 +431,7 @@ mod tests {
|
|||||||
);
|
);
|
||||||
assert_str_eq!(
|
assert_str_eq!(
|
||||||
radarr_data.movie_info_tabs.tabs[3].help,
|
radarr_data.movie_info_tabs.tabs[3].help,
|
||||||
"<r> refresh | <u> update | <e> edit | <s> auto search | <esc> close"
|
build_keymapping_string(&MOVIE_DETAILS_KEY_MAPPINGS)
|
||||||
);
|
);
|
||||||
assert!(radarr_data.movie_info_tabs.tabs[3]
|
assert!(radarr_data.movie_info_tabs.tabs[3]
|
||||||
.contextual_help
|
.contextual_help
|
||||||
@@ -435,7 +444,7 @@ mod tests {
|
|||||||
);
|
);
|
||||||
assert_str_eq!(
|
assert_str_eq!(
|
||||||
radarr_data.movie_info_tabs.tabs[4].help,
|
radarr_data.movie_info_tabs.tabs[4].help,
|
||||||
"<r> refresh | <u> update | <e> edit | <s> auto search | <esc> close"
|
build_keymapping_string(&MOVIE_DETAILS_KEY_MAPPINGS)
|
||||||
);
|
);
|
||||||
assert!(radarr_data.movie_info_tabs.tabs[4]
|
assert!(radarr_data.movie_info_tabs.tabs[4]
|
||||||
.contextual_help
|
.contextual_help
|
||||||
@@ -448,11 +457,13 @@ mod tests {
|
|||||||
);
|
);
|
||||||
assert_str_eq!(
|
assert_str_eq!(
|
||||||
radarr_data.movie_info_tabs.tabs[5].help,
|
radarr_data.movie_info_tabs.tabs[5].help,
|
||||||
"<r> refresh | <u> update | <e> edit | <o> sort | <s> auto search | <esc> close"
|
build_keymapping_string(&MANUAL_MOVIE_SEARCH_KEY_MAPPINGS)
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
radarr_data.movie_info_tabs.tabs[5].contextual_help,
|
radarr_data.movie_info_tabs.tabs[5].contextual_help,
|
||||||
Some("<enter> details")
|
Some(build_keymapping_string(
|
||||||
|
&MANUAL_MOVIE_SEARCH_CONTEXTUAL_KEY_MAPPINGS
|
||||||
|
))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+24
-2
@@ -1,13 +1,13 @@
|
|||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::fmt::{Display, Formatter};
|
use std::fmt::{Display, Formatter};
|
||||||
|
|
||||||
use crossterm::event::{KeyCode, KeyEvent};
|
use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[path = "key_tests.rs"]
|
#[path = "key_tests.rs"]
|
||||||
mod key_tests;
|
mod key_tests;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||||
pub enum Key {
|
pub enum Key {
|
||||||
Up,
|
Up,
|
||||||
Down,
|
Down,
|
||||||
@@ -18,7 +18,9 @@ pub enum Key {
|
|||||||
Backspace,
|
Backspace,
|
||||||
Home,
|
Home,
|
||||||
End,
|
End,
|
||||||
|
Tab,
|
||||||
Delete,
|
Delete,
|
||||||
|
Ctrl(char),
|
||||||
Char(char),
|
Char(char),
|
||||||
Unknown,
|
Unknown,
|
||||||
}
|
}
|
||||||
@@ -27,6 +29,18 @@ impl Display for Key {
|
|||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
match *self {
|
match *self {
|
||||||
Key::Char(c) => write!(f, "<{}>", c),
|
Key::Char(c) => write!(f, "<{}>", c),
|
||||||
|
Key::Ctrl(c) => write!(f, "<Ctrl-{}>", c),
|
||||||
|
Key::Up => write!(f, "<↑>"),
|
||||||
|
Key::Down => write!(f, "<↓>"),
|
||||||
|
Key::Left => write!(f, "<←>"),
|
||||||
|
Key::Right => write!(f, "<→>"),
|
||||||
|
Key::Enter => write!(f, "<enter>"),
|
||||||
|
Key::Esc => write!(f, "<esc>"),
|
||||||
|
Key::Backspace => write!(f, "<backspace>"),
|
||||||
|
Key::Home => write!(f, "<home>"),
|
||||||
|
Key::End => write!(f, "<end>"),
|
||||||
|
Key::Tab => write!(f, "<tab>"),
|
||||||
|
Key::Delete => write!(f, "<del>"),
|
||||||
_ => write!(f, "<{:?}>", self),
|
_ => write!(f, "<{:?}>", self),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -61,6 +75,9 @@ impl From<KeyEvent> for Key {
|
|||||||
KeyEvent {
|
KeyEvent {
|
||||||
code: KeyCode::End, ..
|
code: KeyCode::End, ..
|
||||||
} => Key::End,
|
} => Key::End,
|
||||||
|
KeyEvent {
|
||||||
|
code: KeyCode::Tab, ..
|
||||||
|
} => Key::Tab,
|
||||||
KeyEvent {
|
KeyEvent {
|
||||||
code: KeyCode::Delete,
|
code: KeyCode::Delete,
|
||||||
..
|
..
|
||||||
@@ -72,6 +89,11 @@ impl From<KeyEvent> for Key {
|
|||||||
KeyEvent {
|
KeyEvent {
|
||||||
code: KeyCode::Esc, ..
|
code: KeyCode::Esc, ..
|
||||||
} => Key::Esc,
|
} => Key::Esc,
|
||||||
|
KeyEvent {
|
||||||
|
code: KeyCode::Char(c),
|
||||||
|
modifiers: KeyModifiers::CONTROL,
|
||||||
|
..
|
||||||
|
} => Key::Ctrl(c),
|
||||||
KeyEvent {
|
KeyEvent {
|
||||||
code: KeyCode::Char(c),
|
code: KeyCode::Char(c),
|
||||||
..
|
..
|
||||||
|
|||||||
+36
-9
@@ -1,18 +1,27 @@
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crossterm::event::{KeyCode, KeyEvent};
|
use crossterm::event::{KeyCode, KeyEvent, KeyEventKind, KeyEventState, KeyModifiers};
|
||||||
use pretty_assertions::{assert_eq, assert_str_eq};
|
use pretty_assertions::{assert_eq, assert_str_eq};
|
||||||
|
use rstest::rstest;
|
||||||
|
|
||||||
use crate::event::key::Key;
|
use crate::event::key::Key;
|
||||||
|
|
||||||
#[test]
|
#[rstest]
|
||||||
fn test_key_formatter() {
|
#[case(Key::Up, "↑")]
|
||||||
assert_str_eq!(format!("{}", Key::Esc), "<Esc>");
|
#[case(Key::Down, "↓")]
|
||||||
}
|
#[case(Key::Left, "←")]
|
||||||
|
#[case(Key::Right, "→")]
|
||||||
#[test]
|
#[case(Key::Enter, "enter")]
|
||||||
fn test_key_formatter_char() {
|
#[case(Key::Esc, "esc")]
|
||||||
assert_str_eq!(format!("{}", Key::Char('q')), "<q>");
|
#[case(Key::Backspace, "backspace")]
|
||||||
|
#[case(Key::Home, "home")]
|
||||||
|
#[case(Key::End, "end")]
|
||||||
|
#[case(Key::Tab, "tab")]
|
||||||
|
#[case(Key::Delete, "del")]
|
||||||
|
#[case(Key::Char('q'), "q")]
|
||||||
|
#[case(Key::Ctrl('q'), "Ctrl-q")]
|
||||||
|
fn test_key_formatter(#[case] key: Key, #[case] expected_str: &str) {
|
||||||
|
assert_str_eq!(format!("{}", key), format!("<{}>", expected_str));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -53,6 +62,11 @@ mod tests {
|
|||||||
assert_eq!(Key::from(KeyEvent::from(KeyCode::End)), Key::End);
|
assert_eq!(Key::from(KeyEvent::from(KeyCode::End)), Key::End);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_key_from_tab() {
|
||||||
|
assert_eq!(Key::from(KeyEvent::from(KeyCode::Tab)), Key::Tab);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_key_from_delete() {
|
fn test_key_from_delete() {
|
||||||
assert_eq!(Key::from(KeyEvent::from(KeyCode::Delete)), Key::Delete);
|
assert_eq!(Key::from(KeyEvent::from(KeyCode::Delete)), Key::Delete);
|
||||||
@@ -76,6 +90,19 @@ mod tests {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_key_from_ctrl() {
|
||||||
|
assert_eq!(
|
||||||
|
Key::from(KeyEvent {
|
||||||
|
code: KeyCode::Char('c'),
|
||||||
|
modifiers: KeyModifiers::CONTROL,
|
||||||
|
kind: KeyEventKind::Press,
|
||||||
|
state: KeyEventState::NONE
|
||||||
|
}),
|
||||||
|
Key::Ctrl('c')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_key_from_unknown() {
|
fn test_key_from_unknown() {
|
||||||
assert_eq!(Key::from(KeyEvent::from(KeyCode::Pause)), Key::Unknown);
|
assert_eq!(Key::from(KeyEvent::from(KeyCode::Pause)), Key::Unknown);
|
||||||
|
|||||||
+7
-7
@@ -284,12 +284,12 @@ impl HorizontallyScrollableText {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||||
pub struct TabRoute {
|
pub struct TabRoute {
|
||||||
pub title: &'static str,
|
pub title: &'static str,
|
||||||
pub route: Route,
|
pub route: Route,
|
||||||
pub help: &'static str,
|
pub help: String,
|
||||||
pub contextual_help: Option<&'static str>,
|
pub contextual_help: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct TabState {
|
pub struct TabState {
|
||||||
@@ -313,12 +313,12 @@ impl TabState {
|
|||||||
&self.tabs[self.index].route
|
&self.tabs[self.index].route
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_active_tab_help(&self) -> &'static str {
|
pub fn get_active_tab_help(&self) -> &str {
|
||||||
self.tabs[self.index].help
|
&self.tabs[self.index].help
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_active_tab_contextual_help(&self) -> Option<&'static str> {
|
pub fn get_active_tab_contextual_help(&self) -> Option<String> {
|
||||||
self.tabs[self.index].contextual_help
|
self.tabs[self.index].contextual_help.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn next(&mut self) {
|
pub fn next(&mut self) {
|
||||||
|
|||||||
@@ -533,7 +533,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_tab_state_get_active_tab_help() {
|
fn test_tab_state_get_active_tab_help() {
|
||||||
let tabs = create_test_tab_routes();
|
let tabs = create_test_tab_routes();
|
||||||
let second_tab_help = tabs[1].help;
|
let second_tab_help = tabs[1].help.clone();
|
||||||
let tab_state = TabState { tabs, index: 1 };
|
let tab_state = TabState { tabs, index: 1 };
|
||||||
|
|
||||||
let tab_help = tab_state.get_active_tab_help();
|
let tab_help = tab_state.get_active_tab_help();
|
||||||
@@ -544,7 +544,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_tab_state_get_active_tab_contextual_help() {
|
fn test_tab_state_get_active_tab_contextual_help() {
|
||||||
let tabs = create_test_tab_routes();
|
let tabs = create_test_tab_routes();
|
||||||
let second_tab_contextual_help = tabs[1].contextual_help.unwrap();
|
let second_tab_contextual_help = tabs[1].contextual_help.clone().unwrap();
|
||||||
let tab_state = TabState { tabs, index: 1 };
|
let tab_state = TabState { tabs, index: 1 };
|
||||||
|
|
||||||
let tab_contextual_help = tab_state.get_active_tab_contextual_help();
|
let tab_contextual_help = tab_state.get_active_tab_contextual_help();
|
||||||
@@ -648,14 +648,14 @@ mod tests {
|
|||||||
TabRoute {
|
TabRoute {
|
||||||
title: "Test 1",
|
title: "Test 1",
|
||||||
route: ActiveRadarrBlock::Movies.into(),
|
route: ActiveRadarrBlock::Movies.into(),
|
||||||
help: "Help for Test 1",
|
help: "Help for Test 1".to_owned(),
|
||||||
contextual_help: Some("Contextual Help for Test 1"),
|
contextual_help: Some("Contextual Help for Test 1".to_owned()),
|
||||||
},
|
},
|
||||||
TabRoute {
|
TabRoute {
|
||||||
title: "Test 2",
|
title: "Test 2",
|
||||||
route: ActiveRadarrBlock::Collections.into(),
|
route: ActiveRadarrBlock::Collections.into(),
|
||||||
help: "Help for Test 2",
|
help: "Help for Test 2".to_owned(),
|
||||||
contextual_help: Some("Contextual Help for Test 2"),
|
contextual_help: Some("Contextual Help for Test 2".to_owned()),
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -294,7 +294,7 @@ pub struct TableProps<'a, T> {
|
|||||||
pub content: &'a mut StatefulTable<T>,
|
pub content: &'a mut StatefulTable<T>,
|
||||||
pub table_headers: Vec<&'a str>,
|
pub table_headers: Vec<&'a str>,
|
||||||
pub constraints: Vec<Constraint>,
|
pub constraints: Vec<Constraint>,
|
||||||
pub help: Option<&'static str>,
|
pub help: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ListProps<'a, T> {
|
pub struct ListProps<'a, T> {
|
||||||
@@ -302,7 +302,7 @@ pub struct ListProps<'a, T> {
|
|||||||
pub title: &'static str,
|
pub title: &'static str,
|
||||||
pub is_loading: bool,
|
pub is_loading: bool,
|
||||||
pub is_popup: bool,
|
pub is_popup: bool,
|
||||||
pub help: Option<&'static str>,
|
pub help: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_table<'a, B, T, F>(
|
fn draw_table<'a, B, T, F>(
|
||||||
@@ -618,7 +618,7 @@ pub fn draw_list_box<'a, B: Backend, T>(
|
|||||||
fn draw_help_and_get_content_rect<B: Backend>(
|
fn draw_help_and_get_content_rect<B: Backend>(
|
||||||
f: &mut Frame<'_, B>,
|
f: &mut Frame<'_, B>,
|
||||||
area: Rect,
|
area: Rect,
|
||||||
help: Option<&str>,
|
help: Option<String>,
|
||||||
) -> Rect {
|
) -> Rect {
|
||||||
if let Some(help_string) = help {
|
if let Some(help_string) = help {
|
||||||
let chunks =
|
let chunks =
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ use tui::text::Text;
|
|||||||
use tui::widgets::{Cell, Paragraph, Row, Wrap};
|
use tui::widgets::{Cell, Paragraph, Row, Wrap};
|
||||||
use tui::Frame;
|
use tui::Frame;
|
||||||
|
|
||||||
|
use crate::app::key_binding::{build_keymapping_string, BARE_POPUP_KEY_MAPPINGS};
|
||||||
|
use crate::app::radarr::radarr_key_mappings::COLLECTION_DETAILS_KEY_MAPPINGS;
|
||||||
use crate::app::radarr::{ActiveRadarrBlock, COLLECTION_DETAILS_BLOCKS};
|
use crate::app::radarr::{ActiveRadarrBlock, COLLECTION_DETAILS_BLOCKS};
|
||||||
use crate::app::App;
|
use crate::app::App;
|
||||||
use crate::models::radarr_models::CollectionMovie;
|
use crate::models::radarr_models::CollectionMovie;
|
||||||
@@ -102,8 +104,10 @@ pub fn draw_collection_details<B: Backend>(
|
|||||||
.current_selection()
|
.current_selection()
|
||||||
.clone()
|
.clone()
|
||||||
};
|
};
|
||||||
let mut help_text =
|
let mut help_text = Text::from(format!(
|
||||||
Text::from("<↑↓> scroll table | <enter> show overview/add movie | <esc> close");
|
"<↑↓> scroll table | {}",
|
||||||
|
build_keymapping_string(&COLLECTION_DETAILS_KEY_MAPPINGS)
|
||||||
|
));
|
||||||
help_text.patch_style(style_help());
|
help_text.patch_style(style_help());
|
||||||
let monitored = if collection_selection.monitored {
|
let monitored = if collection_selection.monitored {
|
||||||
"Yes"
|
"Yes"
|
||||||
@@ -257,7 +261,7 @@ fn draw_movie_overview<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, cont
|
|||||||
.overview,
|
.overview,
|
||||||
);
|
);
|
||||||
overview.patch_style(style_default());
|
overview.patch_style(style_default());
|
||||||
let mut help_text = Text::from("<esc> close");
|
let mut help_text = Text::from(build_keymapping_string(&BARE_POPUP_KEY_MAPPINGS));
|
||||||
help_text.patch_style(style_help());
|
help_text.patch_style(style_help());
|
||||||
|
|
||||||
let paragraph = Paragraph::new(overview)
|
let paragraph = Paragraph::new(overview)
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ use tui::text::Text;
|
|||||||
use tui::widgets::{Cell, ListItem, Paragraph, Row};
|
use tui::widgets::{Cell, ListItem, Paragraph, Row};
|
||||||
use tui::Frame;
|
use tui::Frame;
|
||||||
|
|
||||||
|
use crate::app::key_binding::{build_keymapping_string, BARE_POPUP_KEY_MAPPINGS};
|
||||||
|
use crate::app::radarr::radarr_key_mappings::ADD_MOVIE_SEARCH_RESULTS_KEY_MAPPINGS;
|
||||||
use crate::app::radarr::{ActiveRadarrBlock, ADD_MOVIE_BLOCKS};
|
use crate::app::radarr::{ActiveRadarrBlock, ADD_MOVIE_BLOCKS};
|
||||||
use crate::models::radarr_models::AddMovieSearchResult;
|
use crate::models::radarr_models::AddMovieSearchResult;
|
||||||
use crate::models::Route;
|
use crate::models::Route;
|
||||||
@@ -142,7 +144,7 @@ fn draw_add_movie_search<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, ar
|
|||||||
);
|
);
|
||||||
f.render_widget(layout_block(), chunks[1]);
|
f.render_widget(layout_block(), chunks[1]);
|
||||||
|
|
||||||
let mut help_text = Text::from("<esc> close");
|
let mut help_text = Text::from(build_keymapping_string(&BARE_POPUP_KEY_MAPPINGS));
|
||||||
help_text.patch_style(style_help());
|
help_text.patch_style(style_help());
|
||||||
let help_paragraph = Paragraph::new(help_text)
|
let help_paragraph = Paragraph::new(help_text)
|
||||||
.block(borderless_block())
|
.block(borderless_block())
|
||||||
@@ -161,7 +163,9 @@ fn draw_add_movie_search<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, ar
|
|||||||
| ActiveRadarrBlock::AddMovieSelectRootFolder
|
| ActiveRadarrBlock::AddMovieSelectRootFolder
|
||||||
| ActiveRadarrBlock::AddMovieAlreadyInLibrary
|
| ActiveRadarrBlock::AddMovieAlreadyInLibrary
|
||||||
| ActiveRadarrBlock::AddMovieTagsInput => {
|
| ActiveRadarrBlock::AddMovieTagsInput => {
|
||||||
let mut help_text = Text::from("<enter> details | <esc> edit search");
|
let mut help_text = Text::from(build_keymapping_string(
|
||||||
|
&ADD_MOVIE_SEARCH_RESULTS_KEY_MAPPINGS,
|
||||||
|
));
|
||||||
help_text.patch_style(style_help());
|
help_text.patch_style(style_help());
|
||||||
let help_paragraph = Paragraph::new(help_text)
|
let help_paragraph = Paragraph::new(help_text)
|
||||||
.block(borderless_block())
|
.block(borderless_block())
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ use tui::text::{Span, Text};
|
|||||||
use tui::widgets::{Cell, ListItem, Paragraph, Row};
|
use tui::widgets::{Cell, ListItem, Paragraph, Row};
|
||||||
use tui::Frame;
|
use tui::Frame;
|
||||||
|
|
||||||
|
use crate::app::key_binding::{build_keymapping_string, BARE_POPUP_KEY_MAPPINGS};
|
||||||
|
use crate::app::radarr::radarr_key_mappings::SYSTEM_TASKS_KEY_MAPPINGS;
|
||||||
use crate::app::radarr::{ActiveRadarrBlock, SYSTEM_DETAILS_BLOCKS};
|
use crate::app::radarr::{ActiveRadarrBlock, SYSTEM_DETAILS_BLOCKS};
|
||||||
use crate::app::App;
|
use crate::app::App;
|
||||||
use crate::models::Route;
|
use crate::models::Route;
|
||||||
@@ -84,7 +86,10 @@ fn draw_logs_popup<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, area: Re
|
|||||||
title: "Log Details",
|
title: "Log Details",
|
||||||
is_loading: app.is_loading,
|
is_loading: app.is_loading,
|
||||||
is_popup: true,
|
is_popup: true,
|
||||||
help: Some("<↑↓←→> scroll | <esc> close"),
|
help: Some(format!(
|
||||||
|
"<↑↓←→> scroll | {}",
|
||||||
|
build_keymapping_string(&BARE_POPUP_KEY_MAPPINGS)
|
||||||
|
)),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -93,8 +98,11 @@ fn draw_tasks_popup<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, area: R
|
|||||||
let tasks_popup_table = |f: &mut Frame<'_, B>, app: &mut App<'_>, area: Rect| {
|
let tasks_popup_table = |f: &mut Frame<'_, B>, app: &mut App<'_>, area: Rect| {
|
||||||
f.render_widget(title_block("Tasks"), area);
|
f.render_widget(title_block("Tasks"), area);
|
||||||
|
|
||||||
let context_area =
|
let context_area = draw_help_and_get_content_rect(
|
||||||
draw_help_and_get_content_rect(f, area, Some("<enter> start task | <esc> close"));
|
f,
|
||||||
|
area,
|
||||||
|
Some(build_keymapping_string(&SYSTEM_TASKS_KEY_MAPPINGS)),
|
||||||
|
);
|
||||||
|
|
||||||
draw_table(
|
draw_table(
|
||||||
f,
|
f,
|
||||||
@@ -150,7 +158,14 @@ fn draw_start_task_prompt<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, p
|
|||||||
fn draw_updates_popup<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, area: Rect) {
|
fn draw_updates_popup<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, area: Rect) {
|
||||||
f.render_widget(title_block("Updates"), area);
|
f.render_widget(title_block("Updates"), area);
|
||||||
|
|
||||||
let content_rect = draw_help_and_get_content_rect(f, area, Some("<↑↓> scroll | <esc> close"));
|
let content_rect = draw_help_and_get_content_rect(
|
||||||
|
f,
|
||||||
|
area,
|
||||||
|
Some(format!(
|
||||||
|
"<↑↓> scroll | {}",
|
||||||
|
build_keymapping_string(&BARE_POPUP_KEY_MAPPINGS)
|
||||||
|
)),
|
||||||
|
);
|
||||||
let updates = app.data.radarr_data.updates.get_text();
|
let updates = app.data.radarr_data.updates.get_text();
|
||||||
let block = borderless_block();
|
let block = borderless_block();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user