Added 'Test All Indexers' table and functionality to the Indexers tab, and upgraded to Ratatui 0.24.0 and cleaned up code for newer Ratatui version
This commit is contained in:
Generated
+61
-3
@@ -17,6 +17,18 @@ version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
"version_check",
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.1.2"
|
||||
@@ -26,6 +38,12 @@ dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "allocator-api2"
|
||||
version = "0.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5"
|
||||
|
||||
[[package]]
|
||||
name = "android-tzdata"
|
||||
version = "0.1.1"
|
||||
@@ -547,6 +565,10 @@ name = "hashbrown"
|
||||
version = "0.14.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7dfda62a12f55daeae5015f81b0baea145391cb4520f86c248fc615d72640d12"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"allocator-api2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
@@ -828,9 +850,18 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lru"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2994eeba8ed550fd9b47a0b38f0242bc3344e496483c6180b69139cc2fa5d1d7"
|
||||
dependencies = [
|
||||
"hashbrown 0.14.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "managarr"
|
||||
version = "0.0.29"
|
||||
version = "0.0.30"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"backtrace",
|
||||
@@ -1162,15 +1193,16 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ratatui"
|
||||
version = "0.23.0"
|
||||
version = "0.24.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2e2e4cd95294a85c3b4446e63ef054eea43e0205b1fd60120c16b74ff7ff96ad"
|
||||
checksum = "0ebc917cfb527a566c37ecb94c7e3fd098353516fb4eb6bea17015ade0182425"
|
||||
dependencies = [
|
||||
"bitflags 2.4.0",
|
||||
"cassowary",
|
||||
"crossterm",
|
||||
"indoc",
|
||||
"itertools",
|
||||
"lru",
|
||||
"paste",
|
||||
"strum",
|
||||
"time",
|
||||
@@ -1909,6 +1941,12 @@ version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
|
||||
[[package]]
|
||||
name = "want"
|
||||
version = "0.3.1"
|
||||
@@ -2130,3 +2168,23 @@ name = "yansi"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec"
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.7.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e97e415490559a91254a2979b4829267a57d2fcd741a98eee8b722fb57289aa0"
|
||||
dependencies = [
|
||||
"zerocopy-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.7.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd7e48ccf166952882ca8bd778a43502c64f33bf94c12ebe2a7f08e5a0f6689f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.38",
|
||||
]
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "managarr"
|
||||
version = "0.0.29"
|
||||
version = "0.0.30"
|
||||
authors = ["Alex Clarke <alex.j.tusa@gmail.com>"]
|
||||
description = "A TUI to manage your Servarrs"
|
||||
keywords = ["managarr", "tui-rs", "dashboard", "servarr", "tui"]
|
||||
@@ -32,7 +32,7 @@ strum = {version = "0.25.0", features = ["derive"] }
|
||||
strum_macros = "0.25.0"
|
||||
tokio = { version = "1.29.0", features = ["full"] }
|
||||
tokio-util = "0.7.8"
|
||||
tui = { version = "0.23.0", package = "ratatui", features = ["all-widgets"] }
|
||||
ratatui = { version = "0.24.0", features = ["all-widgets"] }
|
||||
urlencoding = "2.1.2"
|
||||
|
||||
[dev-dependencies]
|
||||
|
||||
@@ -22,6 +22,7 @@ generate_keybindings! {
|
||||
edit,
|
||||
logs,
|
||||
tasks,
|
||||
test,
|
||||
refresh,
|
||||
update,
|
||||
events,
|
||||
@@ -97,6 +98,10 @@ pub const DEFAULT_KEYBINDINGS: KeyBindings = KeyBindings {
|
||||
key: Key::Char('t'),
|
||||
desc: "tasks",
|
||||
},
|
||||
test: KeyBinding {
|
||||
key: Key::Char('t'),
|
||||
desc: "test",
|
||||
},
|
||||
refresh: KeyBinding {
|
||||
key: Key::Ctrl('r'),
|
||||
desc: "refresh",
|
||||
|
||||
@@ -21,6 +21,7 @@ mod test {
|
||||
#[case(DEFAULT_KEYBINDINGS.events, Key::Char('e'), "events")]
|
||||
#[case(DEFAULT_KEYBINDINGS.logs, Key::Char('l'), "logs")]
|
||||
#[case(DEFAULT_KEYBINDINGS.tasks, Key::Char('t'), "tasks")]
|
||||
#[case(DEFAULT_KEYBINDINGS.test, Key::Char('t'), "test")]
|
||||
#[case(DEFAULT_KEYBINDINGS.refresh, Key::Ctrl('r'), "refresh")]
|
||||
#[case(DEFAULT_KEYBINDINGS.update, Key::Char('u'), "update")]
|
||||
#[case(DEFAULT_KEYBINDINGS.home, Key::Home, "home")]
|
||||
|
||||
@@ -49,6 +49,11 @@ impl<'a> App<'a> {
|
||||
.dispatch_network_event(RadarrEvent::GetIndexerSettings.into())
|
||||
.await;
|
||||
}
|
||||
ActiveRadarrBlock::TestAllIndexers => {
|
||||
self
|
||||
.dispatch_network_event(RadarrEvent::TestAllIndexers.into())
|
||||
.await;
|
||||
}
|
||||
ActiveRadarrBlock::System => {
|
||||
self
|
||||
.dispatch_network_event(RadarrEvent::GetTasks.into())
|
||||
|
||||
@@ -50,7 +50,7 @@ pub static ROOT_FOLDERS_CONTEXT_CLUES: [ContextClue; 3] = [
|
||||
),
|
||||
];
|
||||
|
||||
pub static INDEXERS_CONTEXT_CLUES: [ContextClue; 5] = [
|
||||
pub static INDEXERS_CONTEXT_CLUES: [ContextClue; 6] = [
|
||||
(DEFAULT_KEYBINDINGS.add, DEFAULT_KEYBINDINGS.add.desc),
|
||||
(DEFAULT_KEYBINDINGS.edit, DEFAULT_KEYBINDINGS.edit.desc),
|
||||
(
|
||||
@@ -58,6 +58,7 @@ pub static INDEXERS_CONTEXT_CLUES: [ContextClue; 5] = [
|
||||
DEFAULT_KEYBINDINGS.settings.desc,
|
||||
),
|
||||
(DEFAULT_KEYBINDINGS.delete, DEFAULT_KEYBINDINGS.delete.desc),
|
||||
(DEFAULT_KEYBINDINGS.test, "test all indexers"),
|
||||
(
|
||||
DEFAULT_KEYBINDINGS.refresh,
|
||||
DEFAULT_KEYBINDINGS.refresh.desc,
|
||||
|
||||
@@ -166,6 +166,11 @@ mod tests {
|
||||
|
||||
let (key_binding, description) = indexers_context_clues_iter.next().unwrap();
|
||||
|
||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.test);
|
||||
assert_str_eq!(*description, "test all indexers");
|
||||
|
||||
let (key_binding, description) = indexers_context_clues_iter.next().unwrap();
|
||||
|
||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.refresh);
|
||||
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.refresh.desc);
|
||||
assert_eq!(indexers_context_clues_iter.next(), None);
|
||||
|
||||
@@ -162,6 +162,22 @@ mod tests {
|
||||
assert_eq!(app.tick_count, 0);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_dispatch_by_test_all_indexers_block() {
|
||||
let (mut app, mut sync_network_rx) = construct_app_unit();
|
||||
|
||||
app
|
||||
.dispatch_by_radarr_block(&ActiveRadarrBlock::TestAllIndexers)
|
||||
.await;
|
||||
|
||||
assert!(app.is_loading);
|
||||
assert_eq!(
|
||||
sync_network_rx.recv().await.unwrap(),
|
||||
RadarrEvent::TestAllIndexers.into()
|
||||
);
|
||||
assert_eq!(app.tick_count, 0);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_dispatch_by_system_block() {
|
||||
let (mut app, mut sync_network_rx) = construct_app_unit();
|
||||
|
||||
@@ -9,7 +9,7 @@ use crate::network::radarr_network::RadarrEvent;
|
||||
use crate::{handle_text_box_keys, handle_text_box_left_right_keys};
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "./edit_indexer_settings_handler_tests.rs"]
|
||||
#[path = "edit_indexer_settings_handler_tests.rs"]
|
||||
mod edit_indexer_settings_handler_tests;
|
||||
|
||||
pub(super) struct IndexerSettingsHandler<'a, 'b> {
|
||||
|
||||
@@ -7,7 +7,7 @@ mod tests {
|
||||
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
||||
use crate::app::App;
|
||||
use crate::event::Key;
|
||||
use crate::handlers::radarr_handlers::indexers::IndexersHandler;
|
||||
use crate::handlers::radarr_handlers::indexers::{IndexersHandler, TestAllIndexersHandler};
|
||||
use crate::handlers::KeyEventHandler;
|
||||
use crate::models::servarr_data::radarr::radarr_data::{
|
||||
ActiveRadarrBlock, INDEXERS_BLOCKS, INDEXER_SETTINGS_BLOCKS,
|
||||
@@ -302,6 +302,24 @@ mod tests {
|
||||
&INDEXER_SETTINGS_SELECTION_BLOCKS
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_test_key() {
|
||||
let mut app = App::default();
|
||||
|
||||
IndexersHandler::with(
|
||||
&DEFAULT_KEYBINDINGS.test.key,
|
||||
&mut app,
|
||||
&ActiveRadarrBlock::Indexers,
|
||||
&None,
|
||||
)
|
||||
.handle();
|
||||
|
||||
assert_eq!(
|
||||
app.get_current_route(),
|
||||
&ActiveRadarrBlock::TestAllIndexers.into()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
@@ -327,6 +345,15 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_delegates_test_all_indexers_block_to_test_all_indexers_handler() {
|
||||
test_handler_delegation!(
|
||||
TestAllIndexersHandler,
|
||||
ActiveRadarrBlock::Indexers,
|
||||
ActiveRadarrBlock::TestAllIndexers
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_indexers_handler_accepts() {
|
||||
let mut indexers_blocks = Vec::new();
|
||||
|
||||
@@ -3,6 +3,7 @@ use crate::app::App;
|
||||
use crate::event::Key;
|
||||
use crate::handlers::radarr_handlers::handle_change_tab_left_right_keys;
|
||||
use crate::handlers::radarr_handlers::indexers::edit_indexer_settings_handler::IndexerSettingsHandler;
|
||||
use crate::handlers::radarr_handlers::indexers::test_all_indexers_handler::TestAllIndexersHandler;
|
||||
use crate::handlers::{handle_clear_errors, handle_prompt_toggle, KeyEventHandler};
|
||||
use crate::models::servarr_data::radarr::radarr_data::{
|
||||
ActiveRadarrBlock, INDEXERS_BLOCKS, INDEXER_SETTINGS_SELECTION_BLOCKS,
|
||||
@@ -11,6 +12,7 @@ use crate::models::{BlockSelectionState, Scrollable};
|
||||
use crate::network::radarr_network::RadarrEvent;
|
||||
|
||||
mod edit_indexer_settings_handler;
|
||||
mod test_all_indexers_handler;
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "indexers_handler_tests.rs"]
|
||||
@@ -30,6 +32,10 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for IndexersHandler<'a,
|
||||
IndexerSettingsHandler::with(self.key, self.app, self.active_radarr_block, self.context)
|
||||
.handle()
|
||||
}
|
||||
_ if TestAllIndexersHandler::accepts(self.active_radarr_block) => {
|
||||
TestAllIndexersHandler::with(self.key, self.app, self.active_radarr_block, self.context)
|
||||
.handle()
|
||||
}
|
||||
_ => self.handle_key_event(),
|
||||
}
|
||||
}
|
||||
@@ -137,6 +143,11 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for IndexersHandler<'a,
|
||||
_ if *key == DEFAULT_KEYBINDINGS.refresh.key => {
|
||||
self.app.should_refresh = true;
|
||||
}
|
||||
_ if *key == DEFAULT_KEYBINDINGS.test.key => {
|
||||
self
|
||||
.app
|
||||
.push_navigation_stack(ActiveRadarrBlock::TestAllIndexers.into());
|
||||
}
|
||||
_ if *key == DEFAULT_KEYBINDINGS.settings.key => {
|
||||
self
|
||||
.app
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
use crate::app::App;
|
||||
use crate::event::Key;
|
||||
use crate::handlers::KeyEventHandler;
|
||||
use crate::models::servarr_data::radarr::radarr_data::ActiveRadarrBlock;
|
||||
use crate::models::Scrollable;
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "test_all_indexers_handler_tests.rs"]
|
||||
mod test_all_indexers_handler_tests;
|
||||
|
||||
pub(super) struct TestAllIndexersHandler<'a, 'b> {
|
||||
key: &'a Key,
|
||||
app: &'a mut App<'b>,
|
||||
active_radarr_block: &'a ActiveRadarrBlock,
|
||||
_context: &'a Option<ActiveRadarrBlock>,
|
||||
}
|
||||
|
||||
impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for TestAllIndexersHandler<'a, 'b> {
|
||||
fn accepts(active_block: &'a ActiveRadarrBlock) -> bool {
|
||||
active_block == &ActiveRadarrBlock::TestAllIndexers
|
||||
}
|
||||
|
||||
fn with(
|
||||
key: &'a Key,
|
||||
app: &'a mut App<'b>,
|
||||
active_block: &'a ActiveRadarrBlock,
|
||||
_context: &'a Option<ActiveRadarrBlock>,
|
||||
) -> TestAllIndexersHandler<'a, 'b> {
|
||||
TestAllIndexersHandler {
|
||||
key,
|
||||
app,
|
||||
active_radarr_block: active_block,
|
||||
_context,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_key(&self) -> &Key {
|
||||
self.key
|
||||
}
|
||||
|
||||
fn handle_scroll_up(&mut self) {
|
||||
if self.active_radarr_block == &ActiveRadarrBlock::TestAllIndexers {
|
||||
self
|
||||
.app
|
||||
.data
|
||||
.radarr_data
|
||||
.indexer_test_all_results
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.scroll_up()
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_scroll_down(&mut self) {
|
||||
if self.active_radarr_block == &ActiveRadarrBlock::TestAllIndexers {
|
||||
self
|
||||
.app
|
||||
.data
|
||||
.radarr_data
|
||||
.indexer_test_all_results
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.scroll_down()
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_home(&mut self) {
|
||||
if self.active_radarr_block == &ActiveRadarrBlock::TestAllIndexers {
|
||||
self
|
||||
.app
|
||||
.data
|
||||
.radarr_data
|
||||
.indexer_test_all_results
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.scroll_to_top()
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_end(&mut self) {
|
||||
if self.active_radarr_block == &ActiveRadarrBlock::TestAllIndexers {
|
||||
self
|
||||
.app
|
||||
.data
|
||||
.radarr_data
|
||||
.indexer_test_all_results
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.scroll_to_bottom()
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_delete(&mut self) {}
|
||||
|
||||
fn handle_left_right_action(&mut self) {}
|
||||
|
||||
fn handle_submit(&mut self) {}
|
||||
|
||||
fn handle_esc(&mut self) {
|
||||
if self.active_radarr_block == &ActiveRadarrBlock::TestAllIndexers {
|
||||
self.app.pop_navigation_stack();
|
||||
self.app.data.radarr_data.indexer_test_all_results = None;
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_char_key_event(&mut self) {}
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
||||
use crate::app::App;
|
||||
use crate::event::Key;
|
||||
use crate::handlers::radarr_handlers::indexers::test_all_indexers_handler::TestAllIndexersHandler;
|
||||
use crate::handlers::KeyEventHandler;
|
||||
use crate::models::servarr_data::radarr::radarr_data::ActiveRadarrBlock;
|
||||
use strum::IntoEnumIterator;
|
||||
|
||||
mod test_handle_scroll_up_and_down {
|
||||
use pretty_assertions::assert_str_eq;
|
||||
use rstest::rstest;
|
||||
|
||||
use crate::models::servarr_data::radarr::modals::IndexerTestResultModalItem;
|
||||
use crate::models::StatefulTable;
|
||||
use crate::simple_stateful_iterable_vec;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[rstest]
|
||||
fn test_test_all_indexers_results_scroll(
|
||||
#[values(DEFAULT_KEYBINDINGS.up.key, DEFAULT_KEYBINDINGS.down.key)] key: Key,
|
||||
) {
|
||||
let mut app = App::default();
|
||||
let mut indexer_test_results = StatefulTable::default();
|
||||
indexer_test_results.set_items(simple_stateful_iterable_vec!(
|
||||
IndexerTestResultModalItem,
|
||||
String,
|
||||
name
|
||||
));
|
||||
app.data.radarr_data.indexer_test_all_results = Some(indexer_test_results);
|
||||
|
||||
TestAllIndexersHandler::with(&key, &mut app, &ActiveRadarrBlock::TestAllIndexers, &None)
|
||||
.handle();
|
||||
|
||||
assert_str_eq!(
|
||||
app
|
||||
.data
|
||||
.radarr_data
|
||||
.indexer_test_all_results
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.current_selection()
|
||||
.name,
|
||||
"Test 2"
|
||||
);
|
||||
|
||||
TestAllIndexersHandler::with(&key, &mut app, &ActiveRadarrBlock::TestAllIndexers, &None)
|
||||
.handle();
|
||||
|
||||
assert_str_eq!(
|
||||
app
|
||||
.data
|
||||
.radarr_data
|
||||
.indexer_test_all_results
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.current_selection()
|
||||
.name,
|
||||
"Test 1"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
mod test_handle_home_end {
|
||||
use crate::extended_stateful_iterable_vec;
|
||||
use crate::models::servarr_data::radarr::modals::IndexerTestResultModalItem;
|
||||
use crate::models::StatefulTable;
|
||||
use pretty_assertions::assert_str_eq;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_test_all_indexers_results_home_end() {
|
||||
let mut app = App::default();
|
||||
let mut indexer_test_results = StatefulTable::default();
|
||||
indexer_test_results.set_items(extended_stateful_iterable_vec!(
|
||||
IndexerTestResultModalItem,
|
||||
String,
|
||||
name
|
||||
));
|
||||
app.data.radarr_data.indexer_test_all_results = Some(indexer_test_results);
|
||||
|
||||
TestAllIndexersHandler::with(
|
||||
&DEFAULT_KEYBINDINGS.end.key,
|
||||
&mut app,
|
||||
&ActiveRadarrBlock::TestAllIndexers,
|
||||
&None,
|
||||
)
|
||||
.handle();
|
||||
|
||||
assert_str_eq!(
|
||||
app
|
||||
.data
|
||||
.radarr_data
|
||||
.indexer_test_all_results
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.current_selection()
|
||||
.name,
|
||||
"Test 3"
|
||||
);
|
||||
|
||||
TestAllIndexersHandler::with(
|
||||
&DEFAULT_KEYBINDINGS.home.key,
|
||||
&mut app,
|
||||
&ActiveRadarrBlock::TestAllIndexers,
|
||||
&None,
|
||||
)
|
||||
.handle();
|
||||
|
||||
assert_str_eq!(
|
||||
app
|
||||
.data
|
||||
.radarr_data
|
||||
.indexer_test_all_results
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.current_selection()
|
||||
.name,
|
||||
"Test 1"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
mod test_handle_esc {
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
use crate::models::StatefulTable;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_test_all_indexers_esc() {
|
||||
let mut app = App::default();
|
||||
app.push_navigation_stack(ActiveRadarrBlock::Indexers.into());
|
||||
app.push_navigation_stack(ActiveRadarrBlock::TestAllIndexers.into());
|
||||
app.data.radarr_data.indexer_test_all_results = Some(StatefulTable::default());
|
||||
|
||||
TestAllIndexersHandler::with(
|
||||
&DEFAULT_KEYBINDINGS.esc.key,
|
||||
&mut app,
|
||||
&ActiveRadarrBlock::TestAllIndexers,
|
||||
&None,
|
||||
)
|
||||
.handle();
|
||||
|
||||
assert_eq!(app.get_current_route(), &ActiveRadarrBlock::Indexers.into());
|
||||
assert!(!app.data.radarr_data.prompt_confirm);
|
||||
assert!(app.data.radarr_data.indexer_test_all_results.is_none());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_test_all_indexers_handler_accepts() {
|
||||
ActiveRadarrBlock::iter().for_each(|active_radarr_block| {
|
||||
if active_radarr_block == ActiveRadarrBlock::TestAllIndexers {
|
||||
assert!(TestAllIndexersHandler::accepts(&active_radarr_block));
|
||||
} else {
|
||||
assert!(!TestAllIndexersHandler::accepts(&active_radarr_block));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -9,11 +9,11 @@ use crossterm::execute;
|
||||
use crossterm::terminal::{
|
||||
disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen,
|
||||
};
|
||||
use ratatui::backend::CrosstermBackend;
|
||||
use ratatui::Terminal;
|
||||
use tokio::sync::mpsc::Receiver;
|
||||
use tokio::sync::{mpsc, Mutex};
|
||||
use tokio_util::sync::CancellationToken;
|
||||
use tui::backend::CrosstermBackend;
|
||||
use tui::Terminal;
|
||||
|
||||
use crate::app::App;
|
||||
use crate::event::input_event::{Events, InputEvent};
|
||||
|
||||
+1
-1
@@ -2,9 +2,9 @@ use std::cell::RefCell;
|
||||
use std::fmt::{Debug, Display, Formatter};
|
||||
|
||||
use crate::models::servarr_data::radarr::radarr_data::ActiveRadarrBlock;
|
||||
use ratatui::widgets::{ListState, TableState};
|
||||
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
|
||||
use serde_json::Number;
|
||||
use tui::widgets::{ListState, TableState};
|
||||
|
||||
pub mod radarr_models;
|
||||
pub mod servarr_data;
|
||||
|
||||
@@ -211,6 +211,23 @@ pub struct IndexerSettings {
|
||||
pub whitelisted_hardcoded_subs: HorizontallyScrollableText,
|
||||
}
|
||||
|
||||
#[derive(Default, Deserialize, Debug, Clone, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct IndexerTestResult {
|
||||
#[serde(deserialize_with = "super::from_i64")]
|
||||
pub id: i64,
|
||||
pub is_valid: bool,
|
||||
pub validation_failures: Vec<IndexerValidationFailure>,
|
||||
}
|
||||
|
||||
#[derive(Default, Deserialize, Debug, Clone, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct IndexerValidationFailure {
|
||||
pub property_name: String,
|
||||
pub error_message: String,
|
||||
pub severity: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Default, Debug, Clone, PartialEq, Eq, Ord, PartialOrd)]
|
||||
pub struct Language {
|
||||
pub name: String,
|
||||
|
||||
@@ -208,3 +208,10 @@ impl From<&RadarrData<'_>> for EditCollectionModal {
|
||||
edit_collection_modal
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Clone, Eq, PartialEq, Debug)]
|
||||
pub struct IndexerTestResultModalItem {
|
||||
pub name: String,
|
||||
pub is_valid: bool,
|
||||
pub validation_failures: HorizontallyScrollableText,
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ use crate::models::radarr_models::{
|
||||
IndexerSettings, Movie, QueueEvent, RootFolder, Task,
|
||||
};
|
||||
use crate::models::servarr_data::radarr::modals::{
|
||||
AddMovieModal, EditCollectionModal, EditMovieModal, MovieDetailsModal,
|
||||
AddMovieModal, EditCollectionModal, EditMovieModal, IndexerTestResultModalItem, MovieDetailsModal,
|
||||
};
|
||||
use crate::models::{
|
||||
BlockSelectionState, HorizontallyScrollableText, Route, ScrollableText, StatefulList,
|
||||
@@ -59,6 +59,7 @@ pub struct RadarrData<'a> {
|
||||
pub filtered_collections: Option<StatefulTable<Collection>>,
|
||||
pub filtered_movies: Option<StatefulTable<Movie>>,
|
||||
pub indexer_settings: Option<IndexerSettings>,
|
||||
pub indexer_test_all_results: Option<StatefulTable<IndexerTestResultModalItem>>,
|
||||
pub movie_details_modal: Option<MovieDetailsModal>,
|
||||
pub prompt_confirm: bool,
|
||||
pub prompt_confirm_action: Option<RadarrEvent>,
|
||||
@@ -126,6 +127,7 @@ impl<'a> Default for RadarrData<'a> {
|
||||
filtered_collections: None,
|
||||
filtered_movies: None,
|
||||
indexer_settings: None,
|
||||
indexer_test_all_results: None,
|
||||
movie_details_modal: None,
|
||||
is_searching: false,
|
||||
is_filtering: false,
|
||||
@@ -288,6 +290,7 @@ pub enum ActiveRadarrBlock {
|
||||
SystemTasks,
|
||||
SystemTaskStartConfirmPrompt,
|
||||
SystemUpdates,
|
||||
TestAllIndexers,
|
||||
UpdateAndScanPrompt,
|
||||
UpdateAllCollectionsPrompt,
|
||||
UpdateAllMoviesPrompt,
|
||||
@@ -315,11 +318,12 @@ pub static COLLECTIONS_BLOCKS: [ActiveRadarrBlock; 6] = [
|
||||
ActiveRadarrBlock::FilterCollectionsError,
|
||||
ActiveRadarrBlock::UpdateAllCollectionsPrompt,
|
||||
];
|
||||
pub static INDEXERS_BLOCKS: [ActiveRadarrBlock; 4] = [
|
||||
pub static INDEXERS_BLOCKS: [ActiveRadarrBlock; 5] = [
|
||||
ActiveRadarrBlock::AddIndexer,
|
||||
ActiveRadarrBlock::EditIndexer,
|
||||
ActiveRadarrBlock::DeleteIndexerPrompt,
|
||||
ActiveRadarrBlock::Indexers,
|
||||
ActiveRadarrBlock::TestAllIndexers,
|
||||
];
|
||||
pub static ROOT_FOLDERS_BLOCKS: [ActiveRadarrBlock; 3] = [
|
||||
ActiveRadarrBlock::RootFolders,
|
||||
|
||||
@@ -101,6 +101,7 @@ mod tests {
|
||||
assert!(radarr_data.filtered_collections.is_none());
|
||||
assert!(radarr_data.filtered_movies.is_none());
|
||||
assert!(radarr_data.indexer_settings.is_none());
|
||||
assert!(radarr_data.indexer_test_all_results.is_none());
|
||||
assert!(radarr_data.movie_details_modal.is_none());
|
||||
assert!(!radarr_data.is_searching);
|
||||
assert!(!radarr_data.is_filtering);
|
||||
@@ -298,11 +299,12 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_indexers_blocks_contents() {
|
||||
assert_eq!(INDEXERS_BLOCKS.len(), 4);
|
||||
assert_eq!(INDEXERS_BLOCKS.len(), 5);
|
||||
assert!(INDEXERS_BLOCKS.contains(&ActiveRadarrBlock::AddIndexer));
|
||||
assert!(INDEXERS_BLOCKS.contains(&ActiveRadarrBlock::EditIndexer));
|
||||
assert!(INDEXERS_BLOCKS.contains(&ActiveRadarrBlock::DeleteIndexerPrompt));
|
||||
assert!(INDEXERS_BLOCKS.contains(&ActiveRadarrBlock::Indexers));
|
||||
assert!(INDEXERS_BLOCKS.contains(&ActiveRadarrBlock::TestAllIndexers));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
+4
-1
@@ -59,6 +59,7 @@ impl<'a, 'b> Network<'a, 'b> {
|
||||
B: Serialize + Default + Debug,
|
||||
R: DeserializeOwned,
|
||||
{
|
||||
let ignore_status_code = request_props.ignore_status_code;
|
||||
let method = request_props.method;
|
||||
let request_uri = request_props.uri.clone();
|
||||
select! {
|
||||
@@ -71,7 +72,7 @@ impl<'a, 'b> Network<'a, 'b> {
|
||||
resp = self.call_api(request_props).await.send() => {
|
||||
match resp {
|
||||
Ok(response) => {
|
||||
if response.status().is_success() {
|
||||
if response.status().is_success() || ignore_status_code {
|
||||
match method {
|
||||
RequestMethod::Get | RequestMethod::Post => {
|
||||
match utils::parse_response::<R>(response).await {
|
||||
@@ -125,6 +126,7 @@ impl<'a, 'b> Network<'a, 'b> {
|
||||
method,
|
||||
body,
|
||||
api_token,
|
||||
..
|
||||
} = request_props;
|
||||
debug!("Creating RequestBuilder for resource: {uri:?}");
|
||||
debug!("Sending {method:?} request to {uri} with body {body:?}");
|
||||
@@ -160,4 +162,5 @@ pub struct RequestProps<T: Serialize + Debug> {
|
||||
pub method: RequestMethod,
|
||||
pub body: Option<T>,
|
||||
pub api_token: String,
|
||||
pub ignore_status_code: bool,
|
||||
}
|
||||
|
||||
@@ -74,6 +74,7 @@ mod tests {
|
||||
value: "Test".to_owned(),
|
||||
}),
|
||||
api_token: "test1234".to_owned(),
|
||||
ignore_status_code: false,
|
||||
},
|
||||
|_, _| (),
|
||||
)
|
||||
@@ -97,6 +98,7 @@ mod tests {
|
||||
method: request_method,
|
||||
body: None,
|
||||
api_token: "test1234".to_owned(),
|
||||
ignore_status_code: false,
|
||||
},
|
||||
|response, mut app| app.error = HorizontallyScrollableText::from(response.value),
|
||||
)
|
||||
@@ -106,6 +108,32 @@ mod tests {
|
||||
assert_str_eq!(app_arc.lock().await.error.text, "Test");
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
#[tokio::test]
|
||||
async fn test_handle_request_with_response_body_ignore_error_code(
|
||||
#[values(RequestMethod::Get, RequestMethod::Post)] request_method: RequestMethod,
|
||||
) {
|
||||
let (async_server, app_arc, server) = mock_api(request_method, 400, true).await;
|
||||
let mut network = Network::new(&app_arc, CancellationToken::new());
|
||||
let mut test_result = String::default();
|
||||
|
||||
network
|
||||
.handle_request::<(), Test>(
|
||||
RequestProps {
|
||||
uri: format!("{}/test", server.url()),
|
||||
method: request_method,
|
||||
body: None,
|
||||
api_token: "test1234".to_owned(),
|
||||
ignore_status_code: true,
|
||||
},
|
||||
|response, _app| test_result = response.value,
|
||||
)
|
||||
.await;
|
||||
|
||||
async_server.assert_async().await;
|
||||
assert!(app_arc.lock().await.error.text.is_empty());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_handle_request_request_is_cancelled() {
|
||||
let (async_server, _, server) = mock_api(RequestMethod::Get, 200, true).await;
|
||||
@@ -127,6 +155,7 @@ mod tests {
|
||||
method: RequestMethod::Get,
|
||||
body: None,
|
||||
api_token: "test1234".to_owned(),
|
||||
ignore_status_code: false,
|
||||
},
|
||||
|_, _| (),
|
||||
)
|
||||
@@ -157,6 +186,7 @@ mod tests {
|
||||
method: RequestMethod::Get,
|
||||
body: None,
|
||||
api_token: "test1234".to_owned(),
|
||||
ignore_status_code: false,
|
||||
},
|
||||
|response, mut app| app.error = HorizontallyScrollableText::from(response.value),
|
||||
)
|
||||
@@ -183,6 +213,7 @@ mod tests {
|
||||
method: RequestMethod::Get,
|
||||
body: None,
|
||||
api_token: "test1234".to_owned(),
|
||||
ignore_status_code: false,
|
||||
},
|
||||
|response, mut app| app.error = HorizontallyScrollableText::from(response.value),
|
||||
)
|
||||
@@ -217,6 +248,7 @@ mod tests {
|
||||
method: request_method,
|
||||
body: None,
|
||||
api_token: "test1234".to_owned(),
|
||||
ignore_status_code: false,
|
||||
},
|
||||
|response, mut app| app.error = HorizontallyScrollableText::from(response.value),
|
||||
)
|
||||
@@ -241,6 +273,7 @@ mod tests {
|
||||
method: RequestMethod::Post,
|
||||
body: None,
|
||||
api_token: "test1234".to_owned(),
|
||||
ignore_status_code: false,
|
||||
},
|
||||
|response, mut app| app.error = HorizontallyScrollableText::from(response.value),
|
||||
)
|
||||
@@ -292,6 +325,7 @@ mod tests {
|
||||
method: request_method,
|
||||
body,
|
||||
api_token: "test1234".to_owned(),
|
||||
ignore_status_code: false,
|
||||
})
|
||||
.await
|
||||
.send()
|
||||
|
||||
@@ -11,11 +11,12 @@ use crate::app::RadarrConfig;
|
||||
use crate::models::radarr_models::{
|
||||
AddMovieBody, AddMovieSearchResult, AddOptions, AddRootFolderBody, Collection, CollectionMovie,
|
||||
CommandBody, Credit, CreditType, DiskSpace, DownloadRecord, DownloadsResponse, Indexer,
|
||||
IndexerSettings, LogResponse, Movie, MovieCommandBody, MovieHistoryItem, QualityProfile,
|
||||
QueueEvent, Release, ReleaseDownloadBody, RootFolder, SystemStatus, Tag, Task, Update,
|
||||
IndexerSettings, IndexerTestResult, LogResponse, Movie, MovieCommandBody, MovieHistoryItem,
|
||||
QualityProfile, QueueEvent, Release, ReleaseDownloadBody, RootFolder, SystemStatus, Tag, Task,
|
||||
Update,
|
||||
};
|
||||
use crate::models::servarr_data::radarr::modals::{
|
||||
AddMovieModal, EditCollectionModal, EditMovieModal, MovieDetailsModal,
|
||||
AddMovieModal, EditCollectionModal, EditMovieModal, IndexerTestResultModalItem, MovieDetailsModal,
|
||||
};
|
||||
use crate::models::servarr_data::radarr::radarr_data::ActiveRadarrBlock;
|
||||
use crate::models::{HorizontallyScrollableText, Route, Scrollable, ScrollableText, StatefulTable};
|
||||
@@ -58,6 +59,7 @@ pub enum RadarrEvent {
|
||||
HealthCheck,
|
||||
SearchNewMovie,
|
||||
StartTask,
|
||||
TestAllIndexers,
|
||||
TriggerAutomaticSearch,
|
||||
UpdateAllMovies,
|
||||
UpdateAndScan,
|
||||
@@ -92,6 +94,7 @@ impl RadarrEvent {
|
||||
RadarrEvent::GetTags => "/tag",
|
||||
RadarrEvent::GetTasks => "/system/task",
|
||||
RadarrEvent::GetUpdates => "/update",
|
||||
RadarrEvent::TestAllIndexers => "/indexer/testall",
|
||||
RadarrEvent::StartTask
|
||||
| RadarrEvent::GetQueuedEvents
|
||||
| RadarrEvent::TriggerAutomaticSearch
|
||||
@@ -143,6 +146,7 @@ impl<'a, 'b> Network<'a, 'b> {
|
||||
RadarrEvent::HealthCheck => self.get_healthcheck().await,
|
||||
RadarrEvent::SearchNewMovie => self.search_movie().await,
|
||||
RadarrEvent::StartTask => self.start_task().await,
|
||||
RadarrEvent::TestAllIndexers => self.test_all_indexers().await,
|
||||
RadarrEvent::TriggerAutomaticSearch => self.trigger_automatic_search().await,
|
||||
RadarrEvent::UpdateAllMovies => self.update_all_movies().await,
|
||||
RadarrEvent::UpdateAndScan => self.update_and_scan().await,
|
||||
@@ -1320,6 +1324,56 @@ impl<'a, 'b> Network<'a, 'b> {
|
||||
.await;
|
||||
}
|
||||
|
||||
async fn test_all_indexers(&mut self) {
|
||||
info!("Testing all indexers");
|
||||
|
||||
let mut request_props = self
|
||||
.radarr_request_props_from(
|
||||
RadarrEvent::TestAllIndexers.resource(),
|
||||
RequestMethod::Post,
|
||||
None,
|
||||
)
|
||||
.await;
|
||||
request_props.ignore_status_code = true;
|
||||
|
||||
self
|
||||
.handle_request::<(), Vec<IndexerTestResult>>(request_props, |test_results, mut app| {
|
||||
let mut test_all_indexer_results = StatefulTable::default();
|
||||
let indexers = app.data.radarr_data.indexers.items.clone();
|
||||
let modal_test_results = test_results
|
||||
.iter()
|
||||
.map(|result| {
|
||||
let name = indexers
|
||||
.iter()
|
||||
.filter(|&indexer| indexer.id == result.id)
|
||||
.map(|indexer| indexer.name.clone())
|
||||
.nth(0)
|
||||
.unwrap_or_default();
|
||||
let validation_failures = result
|
||||
.validation_failures
|
||||
.iter()
|
||||
.map(|failure| {
|
||||
format!(
|
||||
"Failure for field '{}': {}",
|
||||
failure.property_name, failure.error_message
|
||||
)
|
||||
})
|
||||
.collect::<Vec<String>>()
|
||||
.join(", ");
|
||||
|
||||
IndexerTestResultModalItem {
|
||||
name: name.unwrap_or_default(),
|
||||
is_valid: result.is_valid,
|
||||
validation_failures: validation_failures.into(),
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
test_all_indexer_results.set_items(modal_test_results);
|
||||
app.data.radarr_data.indexer_test_all_results = Some(test_all_indexer_results);
|
||||
})
|
||||
.await;
|
||||
}
|
||||
|
||||
async fn trigger_automatic_search(&mut self) {
|
||||
let (movie_id, tmdb_id) = self.extract_movie_id().await;
|
||||
info!("Searching indexers for movie with TMDB id {tmdb_id} and with Radarr id: {movie_id}");
|
||||
@@ -1470,6 +1524,7 @@ impl<'a, 'b> Network<'a, 'b> {
|
||||
method,
|
||||
body,
|
||||
api_token: api_token.to_owned(),
|
||||
ignore_status_code: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -110,6 +110,7 @@ mod test {
|
||||
fn test_resource_movie(
|
||||
#[values(
|
||||
RadarrEvent::AddMovie,
|
||||
RadarrEvent::EditMovie,
|
||||
RadarrEvent::GetMovies,
|
||||
RadarrEvent::GetMovieDetails,
|
||||
RadarrEvent::DeleteMovie
|
||||
@@ -119,6 +120,40 @@ mod test {
|
||||
assert_str_eq!(event.resource(), "/movie");
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn test_resource_collection(
|
||||
#[values(RadarrEvent::GetCollections, RadarrEvent::EditCollection)] event: RadarrEvent,
|
||||
) {
|
||||
assert_str_eq!(event.resource(), "/collection");
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn test_resource_indexer(
|
||||
#[values(RadarrEvent::GetIndexers, RadarrEvent::DeleteIndexer)] event: RadarrEvent,
|
||||
) {
|
||||
assert_str_eq!(event.resource(), "/indexer");
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn test_resource_indexer_settings(
|
||||
#[values(RadarrEvent::GetIndexerSettings, RadarrEvent::UpdateIndexerSettings)]
|
||||
event: RadarrEvent,
|
||||
) {
|
||||
assert_str_eq!(event.resource(), "/config/indexer");
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn test_resource_root_folder(
|
||||
#[values(
|
||||
RadarrEvent::AddRootFolder,
|
||||
RadarrEvent::GetRootFolders,
|
||||
RadarrEvent::DeleteRootFolder
|
||||
)]
|
||||
event: RadarrEvent,
|
||||
) {
|
||||
assert_str_eq!(event.resource(), "/rootfolder");
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn test_resource_release(
|
||||
#[values(RadarrEvent::GetReleases, RadarrEvent::DownloadRelease)] event: RadarrEvent,
|
||||
@@ -136,6 +171,8 @@ mod test {
|
||||
#[rstest]
|
||||
fn test_resource_command(
|
||||
#[values(
|
||||
RadarrEvent::StartTask,
|
||||
RadarrEvent::GetQueuedEvents,
|
||||
RadarrEvent::TriggerAutomaticSearch,
|
||||
RadarrEvent::UpdateAndScan,
|
||||
RadarrEvent::UpdateAllMovies,
|
||||
@@ -148,34 +185,20 @@ mod test {
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn test_resource(
|
||||
#[values(
|
||||
RadarrEvent::GetCollections,
|
||||
RadarrEvent::SearchNewMovie,
|
||||
RadarrEvent::GetMovieCredits,
|
||||
RadarrEvent::GetMovieHistory,
|
||||
RadarrEvent::GetOverview,
|
||||
RadarrEvent::GetQualityProfiles,
|
||||
RadarrEvent::GetRootFolders,
|
||||
RadarrEvent::GetStatus,
|
||||
RadarrEvent::HealthCheck
|
||||
)]
|
||||
event: RadarrEvent,
|
||||
) {
|
||||
let expected_resource = match event {
|
||||
RadarrEvent::GetCollections => "/collection",
|
||||
RadarrEvent::SearchNewMovie => "/movie/lookup",
|
||||
RadarrEvent::GetMovieCredits => "/credit",
|
||||
RadarrEvent::GetMovieHistory => "/history/movie",
|
||||
RadarrEvent::GetOverview => "/diskspace",
|
||||
RadarrEvent::GetQualityProfiles => "/qualityprofile",
|
||||
RadarrEvent::GetRootFolders => "/rootfolder",
|
||||
RadarrEvent::GetStatus => "/system/status",
|
||||
RadarrEvent::HealthCheck => "/health",
|
||||
_ => "",
|
||||
};
|
||||
|
||||
assert_str_eq!(event.resource(), expected_resource);
|
||||
#[case(RadarrEvent::GetLogs, "/log")]
|
||||
#[case(RadarrEvent::SearchNewMovie, "/movie/lookup")]
|
||||
#[case(RadarrEvent::GetMovieCredits, "/credit")]
|
||||
#[case(RadarrEvent::GetMovieHistory, "/history/movie")]
|
||||
#[case(RadarrEvent::GetOverview, "/diskspace")]
|
||||
#[case(RadarrEvent::GetQualityProfiles, "/qualityprofile")]
|
||||
#[case(RadarrEvent::GetStatus, "/system/status")]
|
||||
#[case(RadarrEvent::GetTags, "/tag")]
|
||||
#[case(RadarrEvent::GetTasks, "/system/task")]
|
||||
#[case(RadarrEvent::GetUpdates, "/update")]
|
||||
#[case(RadarrEvent::TestAllIndexers, "/indexer/testall")]
|
||||
#[case(RadarrEvent::HealthCheck, "/health")]
|
||||
fn test_resource(#[case] event: RadarrEvent, #[case] expected_uri: String) {
|
||||
assert_str_eq!(event.resource(), expected_uri);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -192,6 +215,7 @@ mod test {
|
||||
RequestMethod::Get,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
RadarrEvent::HealthCheck.resource(),
|
||||
)
|
||||
.await;
|
||||
@@ -217,6 +241,7 @@ mod test {
|
||||
"totalSpace": 4444
|
||||
}
|
||||
])),
|
||||
None,
|
||||
RadarrEvent::GetOverview.resource(),
|
||||
)
|
||||
.await;
|
||||
@@ -249,6 +274,7 @@ mod test {
|
||||
"version": "v1",
|
||||
"startTime": "2023-02-25T20:16:43Z"
|
||||
})),
|
||||
None,
|
||||
RadarrEvent::GetStatus.resource(),
|
||||
)
|
||||
.await;
|
||||
@@ -271,6 +297,7 @@ mod test {
|
||||
RequestMethod::Get,
|
||||
None,
|
||||
Some(serde_json::from_str(format!("[ {MOVIE_JSON} ]").as_str()).unwrap()),
|
||||
None,
|
||||
RadarrEvent::GetMovies.resource(),
|
||||
)
|
||||
.await;
|
||||
@@ -303,8 +330,14 @@ mod test {
|
||||
"quality": { "quality": { "name": "HD - 1080p" }}
|
||||
}]);
|
||||
let resource = format!("{}?movieId=1", RadarrEvent::GetReleases.resource());
|
||||
let (async_server, app_arc, _server) =
|
||||
mock_radarr_api(RequestMethod::Get, None, Some(release_json), &resource).await;
|
||||
let (async_server, app_arc, _server) = mock_radarr_api(
|
||||
RequestMethod::Get,
|
||||
None,
|
||||
Some(release_json),
|
||||
None,
|
||||
&resource,
|
||||
)
|
||||
.await;
|
||||
app_arc
|
||||
.lock()
|
||||
.await
|
||||
@@ -364,6 +397,7 @@ mod test {
|
||||
RequestMethod::Get,
|
||||
None,
|
||||
Some(add_movie_search_result_json),
|
||||
None,
|
||||
&resource,
|
||||
)
|
||||
.await;
|
||||
@@ -404,6 +438,7 @@ mod test {
|
||||
"name": "TestTask"
|
||||
})),
|
||||
None,
|
||||
None,
|
||||
RadarrEvent::StartTask.resource(),
|
||||
)
|
||||
.await;
|
||||
@@ -431,7 +466,7 @@ mod test {
|
||||
RadarrEvent::SearchNewMovie.resource()
|
||||
);
|
||||
let (async_server, app_arc, _server) =
|
||||
mock_radarr_api(RequestMethod::Get, None, Some(json!([])), &resource).await;
|
||||
mock_radarr_api(RequestMethod::Get, None, Some(json!([])), None, &resource).await;
|
||||
app_arc.lock().await.data.radarr_data.search = Some("test term".into());
|
||||
let mut network = Network::new(&app_arc, CancellationToken::new());
|
||||
|
||||
@@ -502,6 +537,97 @@ mod test {
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_handle_test_all_indexers_event() {
|
||||
let indexers = vec![
|
||||
Indexer {
|
||||
id: 1,
|
||||
name: Some("Test 1".to_owned()),
|
||||
..Indexer::default()
|
||||
},
|
||||
Indexer {
|
||||
id: 2,
|
||||
name: Some("Test 2".to_owned()),
|
||||
..Indexer::default()
|
||||
},
|
||||
];
|
||||
let indexer_test_results_modal_items = vec![
|
||||
IndexerTestResultModalItem {
|
||||
name: "Test 1".to_owned(),
|
||||
is_valid: true,
|
||||
validation_failures: HorizontallyScrollableText::default(),
|
||||
},
|
||||
IndexerTestResultModalItem {
|
||||
name: "Test 2".to_owned(),
|
||||
is_valid: false,
|
||||
validation_failures: "Failure for field 'test field 1': test error message, Failure for field 'test field 2': test error message 2".into(),
|
||||
},
|
||||
];
|
||||
let response_json = json!([
|
||||
{
|
||||
"id": 1,
|
||||
"isValid": true,
|
||||
"validationFailures": []
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"isValid": false,
|
||||
"validationFailures": [
|
||||
{
|
||||
"propertyName": "test field 1",
|
||||
"errorMessage": "test error message",
|
||||
"severity": "error"
|
||||
},
|
||||
{
|
||||
"propertyName": "test field 2",
|
||||
"errorMessage": "test error message 2",
|
||||
"severity": "error"
|
||||
},
|
||||
]
|
||||
}]);
|
||||
let (async_server, app_arc, _server) = mock_radarr_api(
|
||||
RequestMethod::Post,
|
||||
None,
|
||||
Some(response_json),
|
||||
Some(400),
|
||||
RadarrEvent::TestAllIndexers.resource(),
|
||||
)
|
||||
.await;
|
||||
app_arc
|
||||
.lock()
|
||||
.await
|
||||
.data
|
||||
.radarr_data
|
||||
.indexers
|
||||
.set_items(indexers);
|
||||
let mut network = Network::new(&app_arc, CancellationToken::new());
|
||||
|
||||
network
|
||||
.handle_radarr_event(RadarrEvent::TestAllIndexers)
|
||||
.await;
|
||||
|
||||
async_server.assert_async().await;
|
||||
assert!(app_arc
|
||||
.lock()
|
||||
.await
|
||||
.data
|
||||
.radarr_data
|
||||
.indexer_test_all_results
|
||||
.is_some());
|
||||
assert_eq!(
|
||||
app_arc
|
||||
.lock()
|
||||
.await
|
||||
.data
|
||||
.radarr_data
|
||||
.indexer_test_all_results
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.items,
|
||||
indexer_test_results_modal_items
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_handle_trigger_automatic_search_event() {
|
||||
let (async_server, app_arc, _server) = mock_radarr_api(
|
||||
@@ -511,6 +637,7 @@ mod test {
|
||||
"movieIds": [ 1 ]
|
||||
})),
|
||||
None,
|
||||
None,
|
||||
RadarrEvent::TriggerAutomaticSearch.resource(),
|
||||
)
|
||||
.await;
|
||||
@@ -539,6 +666,7 @@ mod test {
|
||||
"movieIds": [ 1 ]
|
||||
})),
|
||||
None,
|
||||
None,
|
||||
RadarrEvent::UpdateAndScan.resource(),
|
||||
)
|
||||
.await;
|
||||
@@ -567,6 +695,7 @@ mod test {
|
||||
"movieIds": []
|
||||
})),
|
||||
None,
|
||||
None,
|
||||
RadarrEvent::UpdateAllMovies.resource(),
|
||||
)
|
||||
.await;
|
||||
@@ -587,6 +716,7 @@ mod test {
|
||||
"name": "RefreshMonitoredDownloads"
|
||||
})),
|
||||
None,
|
||||
None,
|
||||
RadarrEvent::UpdateDownloads.resource(),
|
||||
)
|
||||
.await;
|
||||
@@ -616,6 +746,7 @@ mod test {
|
||||
RequestMethod::Put,
|
||||
Some(indexer_settings_json),
|
||||
None,
|
||||
None,
|
||||
RadarrEvent::UpdateIndexerSettings.resource(),
|
||||
)
|
||||
.await;
|
||||
@@ -645,6 +776,7 @@ mod test {
|
||||
"name": "RefreshCollections"
|
||||
})),
|
||||
None,
|
||||
None,
|
||||
RadarrEvent::UpdateCollections.resource(),
|
||||
)
|
||||
.await;
|
||||
@@ -664,6 +796,7 @@ mod test {
|
||||
RequestMethod::Get,
|
||||
None,
|
||||
Some(serde_json::from_str(MOVIE_JSON).unwrap()),
|
||||
None,
|
||||
&resource,
|
||||
)
|
||||
.await;
|
||||
@@ -775,6 +908,7 @@ mod test {
|
||||
RequestMethod::Get,
|
||||
None,
|
||||
Some(movie_json_with_missing_fields),
|
||||
None,
|
||||
&resource,
|
||||
)
|
||||
.await;
|
||||
@@ -843,6 +977,7 @@ mod test {
|
||||
RequestMethod::Get,
|
||||
None,
|
||||
Some(movie_history_item_json),
|
||||
None,
|
||||
&resource,
|
||||
)
|
||||
.await;
|
||||
@@ -890,6 +1025,7 @@ mod test {
|
||||
RequestMethod::Get,
|
||||
None,
|
||||
Some(movie_history_item_json),
|
||||
None,
|
||||
&resource,
|
||||
)
|
||||
.await;
|
||||
@@ -957,6 +1093,7 @@ mod test {
|
||||
RequestMethod::Get,
|
||||
None,
|
||||
Some(collection_json),
|
||||
None,
|
||||
RadarrEvent::GetCollections.resource(),
|
||||
)
|
||||
.await;
|
||||
@@ -992,6 +1129,7 @@ mod test {
|
||||
RequestMethod::Get,
|
||||
None,
|
||||
Some(downloads_response_json),
|
||||
None,
|
||||
RadarrEvent::GetDownloads.resource(),
|
||||
)
|
||||
.await;
|
||||
@@ -1057,6 +1195,7 @@ mod test {
|
||||
RequestMethod::Get,
|
||||
None,
|
||||
Some(indexers_response_json),
|
||||
None,
|
||||
RadarrEvent::GetIndexers.resource(),
|
||||
)
|
||||
.await;
|
||||
@@ -1088,6 +1227,7 @@ mod test {
|
||||
RequestMethod::Get,
|
||||
None,
|
||||
Some(indexer_settings_response_json),
|
||||
None,
|
||||
RadarrEvent::GetIndexerSettings.resource(),
|
||||
)
|
||||
.await;
|
||||
@@ -1121,6 +1261,7 @@ mod test {
|
||||
RequestMethod::Get,
|
||||
None,
|
||||
Some(indexer_settings_response_json),
|
||||
None,
|
||||
RadarrEvent::GetIndexerSettings.resource(),
|
||||
)
|
||||
.await;
|
||||
@@ -1166,6 +1307,7 @@ mod test {
|
||||
RequestMethod::Get,
|
||||
None,
|
||||
Some(queued_events_json),
|
||||
None,
|
||||
RadarrEvent::GetQueuedEvents.resource(),
|
||||
)
|
||||
.await;
|
||||
@@ -1221,6 +1363,7 @@ mod test {
|
||||
}
|
||||
]
|
||||
})),
|
||||
None,
|
||||
&resource,
|
||||
)
|
||||
.await;
|
||||
@@ -1254,6 +1397,7 @@ mod test {
|
||||
RequestMethod::Get,
|
||||
None,
|
||||
Some(quality_profile_json),
|
||||
None,
|
||||
RadarrEvent::GetQualityProfiles.resource(),
|
||||
)
|
||||
.await;
|
||||
@@ -1280,6 +1424,7 @@ mod test {
|
||||
RequestMethod::Get,
|
||||
None,
|
||||
Some(tags_json),
|
||||
None,
|
||||
RadarrEvent::GetTags.resource(),
|
||||
)
|
||||
.await;
|
||||
@@ -1335,6 +1480,7 @@ mod test {
|
||||
RequestMethod::Get,
|
||||
None,
|
||||
Some(tasks_json),
|
||||
None,
|
||||
RadarrEvent::GetTasks.resource(),
|
||||
)
|
||||
.await;
|
||||
@@ -1421,6 +1567,7 @@ mod test {
|
||||
RequestMethod::Get,
|
||||
None,
|
||||
Some(tasks_json),
|
||||
None,
|
||||
RadarrEvent::GetUpdates.resource(),
|
||||
)
|
||||
.await;
|
||||
@@ -1441,6 +1588,7 @@ mod test {
|
||||
RequestMethod::Post,
|
||||
Some(json!({ "label": "testing" })),
|
||||
Some(json!({ "id": 3, "label": "testing" })),
|
||||
None,
|
||||
RadarrEvent::GetTags.resource(),
|
||||
)
|
||||
.await;
|
||||
@@ -1473,6 +1621,7 @@ mod test {
|
||||
RequestMethod::Get,
|
||||
None,
|
||||
Some(root_folder_json),
|
||||
None,
|
||||
RadarrEvent::GetRootFolders.resource(),
|
||||
)
|
||||
.await;
|
||||
@@ -1505,8 +1654,14 @@ mod test {
|
||||
}
|
||||
]);
|
||||
let resource = format!("{}?movieId=1", RadarrEvent::GetMovieCredits.resource());
|
||||
let (async_server, app_arc, _server) =
|
||||
mock_radarr_api(RequestMethod::Get, None, Some(credits_json), &resource).await;
|
||||
let (async_server, app_arc, _server) = mock_radarr_api(
|
||||
RequestMethod::Get,
|
||||
None,
|
||||
Some(credits_json),
|
||||
None,
|
||||
&resource,
|
||||
)
|
||||
.await;
|
||||
app_arc
|
||||
.lock()
|
||||
.await
|
||||
@@ -1536,7 +1691,7 @@ mod test {
|
||||
RadarrEvent::DeleteMovie.resource()
|
||||
);
|
||||
let (async_server, app_arc, _server) =
|
||||
mock_radarr_api(RequestMethod::Delete, None, None, &resource).await;
|
||||
mock_radarr_api(RequestMethod::Delete, None, None, None, &resource).await;
|
||||
{
|
||||
let mut app = app_arc.lock().await;
|
||||
app.data.radarr_data.movies.set_items(vec![movie()]);
|
||||
@@ -1556,7 +1711,7 @@ mod test {
|
||||
async fn test_handle_delete_download_event() {
|
||||
let resource = format!("{}/1", RadarrEvent::DeleteDownload.resource());
|
||||
let (async_server, app_arc, _server) =
|
||||
mock_radarr_api(RequestMethod::Delete, None, None, &resource).await;
|
||||
mock_radarr_api(RequestMethod::Delete, None, None, None, &resource).await;
|
||||
app_arc
|
||||
.lock()
|
||||
.await
|
||||
@@ -1577,7 +1732,7 @@ mod test {
|
||||
async fn test_handle_delete_indexer_event() {
|
||||
let resource = format!("{}/1", RadarrEvent::DeleteIndexer.resource());
|
||||
let (async_server, app_arc, _server) =
|
||||
mock_radarr_api(RequestMethod::Delete, None, None, &resource).await;
|
||||
mock_radarr_api(RequestMethod::Delete, None, None, None, &resource).await;
|
||||
app_arc
|
||||
.lock()
|
||||
.await
|
||||
@@ -1598,7 +1753,7 @@ mod test {
|
||||
async fn test_handle_delete_root_folder_event() {
|
||||
let resource = format!("{}/1", RadarrEvent::DeleteRootFolder.resource());
|
||||
let (async_server, app_arc, _server) =
|
||||
mock_radarr_api(RequestMethod::Delete, None, None, &resource).await;
|
||||
mock_radarr_api(RequestMethod::Delete, None, None, None, &resource).await;
|
||||
app_arc
|
||||
.lock()
|
||||
.await
|
||||
@@ -1634,6 +1789,7 @@ mod test {
|
||||
}
|
||||
})),
|
||||
None,
|
||||
None,
|
||||
RadarrEvent::AddMovie.resource(),
|
||||
)
|
||||
.await;
|
||||
@@ -1720,6 +1876,7 @@ mod test {
|
||||
}
|
||||
})),
|
||||
None,
|
||||
None,
|
||||
RadarrEvent::AddMovie.resource(),
|
||||
)
|
||||
.await;
|
||||
@@ -1805,6 +1962,7 @@ mod test {
|
||||
"path": "/nfs/test"
|
||||
})),
|
||||
None,
|
||||
None,
|
||||
RadarrEvent::AddRootFolder.resource(),
|
||||
)
|
||||
.await;
|
||||
@@ -1840,6 +1998,7 @@ mod test {
|
||||
RequestMethod::Get,
|
||||
None,
|
||||
Some(serde_json::from_str(MOVIE_JSON).unwrap()),
|
||||
None,
|
||||
&resource,
|
||||
)
|
||||
.await;
|
||||
@@ -1933,6 +2092,7 @@ mod test {
|
||||
RequestMethod::Get,
|
||||
None,
|
||||
Some(detailed_collection_body),
|
||||
None,
|
||||
&resource,
|
||||
)
|
||||
.await;
|
||||
@@ -1992,6 +2152,7 @@ mod test {
|
||||
"movieId": 1
|
||||
})),
|
||||
None,
|
||||
None,
|
||||
RadarrEvent::DownloadRelease.resource(),
|
||||
)
|
||||
.await;
|
||||
@@ -2042,6 +2203,7 @@ mod test {
|
||||
RequestMethod::Post,
|
||||
Some(json!({ "label": "testing" })),
|
||||
Some(json!({ "id": 3, "label": "testing" })),
|
||||
None,
|
||||
RadarrEvent::GetTags.resource(),
|
||||
)
|
||||
.await;
|
||||
@@ -2256,15 +2418,22 @@ mod test {
|
||||
method: RequestMethod,
|
||||
request_body: Option<Value>,
|
||||
response_body: Option<Value>,
|
||||
response_status: Option<usize>,
|
||||
resource: &str,
|
||||
) -> (Mock, Arc<Mutex<App<'_>>>, ServerGuard) {
|
||||
let status = if let Some(status) = response_status {
|
||||
status
|
||||
} else {
|
||||
200
|
||||
};
|
||||
let mut server = Server::new_async().await;
|
||||
let mut async_server = server
|
||||
.mock(
|
||||
&method.to_string().to_uppercase(),
|
||||
format!("/api/v3{resource}").as_str(),
|
||||
)
|
||||
.match_header("X-Api-Key", "test1234");
|
||||
.match_header("X-Api-Key", "test1234")
|
||||
.with_status(status);
|
||||
|
||||
if let Some(body) = request_body {
|
||||
async_server = async_server.match_body(Matcher::Json(body));
|
||||
|
||||
+89
-105
@@ -1,17 +1,16 @@
|
||||
use std::iter;
|
||||
use std::rc::Rc;
|
||||
|
||||
use tui::backend::Backend;
|
||||
use tui::layout::{Alignment, Constraint, Rect};
|
||||
use tui::style::Modifier;
|
||||
use tui::text::{Line, Span, Text};
|
||||
use tui::widgets::Paragraph;
|
||||
use tui::widgets::Row;
|
||||
use tui::widgets::Table;
|
||||
use tui::widgets::Tabs;
|
||||
use tui::widgets::{Block, Wrap};
|
||||
use tui::widgets::{Clear, List, ListItem};
|
||||
use tui::Frame;
|
||||
use ratatui::layout::{Alignment, Constraint, Rect};
|
||||
use ratatui::style::Modifier;
|
||||
use ratatui::text::{Line, Span, Text};
|
||||
use ratatui::widgets::Paragraph;
|
||||
use ratatui::widgets::Row;
|
||||
use ratatui::widgets::Table;
|
||||
use ratatui::widgets::Tabs;
|
||||
use ratatui::widgets::{Block, Wrap};
|
||||
use ratatui::widgets::{Clear, List, ListItem};
|
||||
use ratatui::Frame;
|
||||
|
||||
use crate::app::App;
|
||||
use crate::models::{HorizontallyScrollableText, Route, StatefulList, StatefulTable, TabState};
|
||||
@@ -32,11 +31,11 @@ static HIGHLIGHT_SYMBOL: &str = "=> ";
|
||||
|
||||
pub trait DrawUi {
|
||||
fn accepts(route: Route) -> bool;
|
||||
fn draw<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, content_rect: Rect);
|
||||
fn draw_context_row<B: Backend>(_f: &mut Frame<'_, B>, _app: &App<'_>, _area: Rect) {}
|
||||
fn draw(f: &mut Frame<'_>, app: &mut App<'_>, content_rect: Rect);
|
||||
fn draw_context_row(_f: &mut Frame<'_>, _app: &App<'_>, _area: Rect) {}
|
||||
}
|
||||
|
||||
pub fn ui<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>) {
|
||||
pub fn ui(f: &mut Frame<'_>, app: &mut App<'_>) {
|
||||
f.render_widget(background_block(), f.size());
|
||||
let main_chunks = if !app.error.text.is_empty() {
|
||||
let chunks = vertical_chunks_with_margin(
|
||||
@@ -73,7 +72,7 @@ pub fn ui<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>) {
|
||||
}
|
||||
}
|
||||
|
||||
fn draw_header_row<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, area: Rect) {
|
||||
fn draw_header_row(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||
let chunks =
|
||||
horizontal_chunks_with_margin(vec![Constraint::Length(75), Constraint::Min(0)], area, 1);
|
||||
let help_text = Text::from(app.server_tabs.get_active_tab_help());
|
||||
@@ -97,7 +96,7 @@ fn draw_header_row<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, area: Re
|
||||
f.render_widget(help, chunks[1]);
|
||||
}
|
||||
|
||||
fn draw_error<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, area: Rect) {
|
||||
fn draw_error(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||
let block =
|
||||
title_block("Error | <esc> to close").style(style_failure().add_modifier(Modifier::BOLD));
|
||||
|
||||
@@ -118,10 +117,10 @@ fn draw_error<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, area: Rect) {
|
||||
f.render_widget(paragraph, area);
|
||||
}
|
||||
|
||||
pub fn draw_popup<B: Backend>(
|
||||
f: &mut Frame<'_, B>,
|
||||
pub fn draw_popup(
|
||||
f: &mut Frame<'_>,
|
||||
app: &mut App<'_>,
|
||||
popup_fn: impl Fn(&mut Frame<'_, B>, &mut App<'_>, Rect),
|
||||
popup_fn: impl Fn(&mut Frame<'_>, &mut App<'_>, Rect),
|
||||
percent_x: u16,
|
||||
percent_y: u16,
|
||||
) {
|
||||
@@ -131,8 +130,8 @@ pub fn draw_popup<B: Backend>(
|
||||
popup_fn(f, app, popup_area);
|
||||
}
|
||||
|
||||
pub fn draw_popup_ui<B: Backend, T: DrawUi>(
|
||||
f: &mut Frame<'_, B>,
|
||||
pub fn draw_popup_ui<T: DrawUi>(
|
||||
f: &mut Frame<'_>,
|
||||
app: &mut App<'_>,
|
||||
percent_x: u16,
|
||||
percent_y: u16,
|
||||
@@ -143,12 +142,12 @@ pub fn draw_popup_ui<B: Backend, T: DrawUi>(
|
||||
T::draw(f, app, popup_area);
|
||||
}
|
||||
|
||||
pub fn draw_popup_over<B: Backend>(
|
||||
f: &mut Frame<'_, B>,
|
||||
pub fn draw_popup_over(
|
||||
f: &mut Frame<'_>,
|
||||
app: &mut App<'_>,
|
||||
area: Rect,
|
||||
background_fn: impl Fn(&mut Frame<'_, B>, &mut App<'_>, Rect),
|
||||
popup_fn: impl Fn(&mut Frame<'_, B>, &mut App<'_>, Rect),
|
||||
background_fn: impl Fn(&mut Frame<'_>, &mut App<'_>, Rect),
|
||||
popup_fn: impl Fn(&mut Frame<'_>, &mut App<'_>, Rect),
|
||||
percent_x: u16,
|
||||
percent_y: u16,
|
||||
) {
|
||||
@@ -157,90 +156,90 @@ pub fn draw_popup_over<B: Backend>(
|
||||
draw_popup(f, app, popup_fn, percent_x, percent_y);
|
||||
}
|
||||
|
||||
pub fn draw_popup_over_ui<B: Backend, T: DrawUi>(
|
||||
f: &mut Frame<'_, B>,
|
||||
pub fn draw_popup_over_ui<T: DrawUi>(
|
||||
f: &mut Frame<'_>,
|
||||
app: &mut App<'_>,
|
||||
area: Rect,
|
||||
background_fn: impl Fn(&mut Frame<'_, B>, &mut App<'_>, Rect),
|
||||
background_fn: impl Fn(&mut Frame<'_>, &mut App<'_>, Rect),
|
||||
percent_x: u16,
|
||||
percent_y: u16,
|
||||
) {
|
||||
background_fn(f, app, area);
|
||||
|
||||
draw_popup_ui::<B, T>(f, app, percent_x, percent_y);
|
||||
draw_popup_ui::<T>(f, app, percent_x, percent_y);
|
||||
}
|
||||
|
||||
pub fn draw_prompt_popup_over<B: Backend>(
|
||||
f: &mut Frame<'_, B>,
|
||||
pub fn draw_prompt_popup_over(
|
||||
f: &mut Frame<'_>,
|
||||
app: &mut App<'_>,
|
||||
area: Rect,
|
||||
background_fn: impl Fn(&mut Frame<'_, B>, &mut App<'_>, Rect),
|
||||
popup_fn: impl Fn(&mut Frame<'_, B>, &mut App<'_>, Rect),
|
||||
background_fn: impl Fn(&mut Frame<'_>, &mut App<'_>, Rect),
|
||||
popup_fn: impl Fn(&mut Frame<'_>, &mut App<'_>, Rect),
|
||||
) {
|
||||
draw_popup_over(f, app, area, background_fn, popup_fn, 35, 35);
|
||||
}
|
||||
|
||||
pub fn draw_small_popup_over<B: Backend>(
|
||||
f: &mut Frame<'_, B>,
|
||||
pub fn draw_small_popup_over(
|
||||
f: &mut Frame<'_>,
|
||||
app: &mut App<'_>,
|
||||
area: Rect,
|
||||
background_fn: impl Fn(&mut Frame<'_, B>, &mut App<'_>, Rect),
|
||||
popup_fn: impl Fn(&mut Frame<'_, B>, &mut App<'_>, Rect),
|
||||
background_fn: impl Fn(&mut Frame<'_>, &mut App<'_>, Rect),
|
||||
popup_fn: impl Fn(&mut Frame<'_>, &mut App<'_>, Rect),
|
||||
) {
|
||||
draw_popup_over(f, app, area, background_fn, popup_fn, 40, 40);
|
||||
}
|
||||
|
||||
pub fn draw_medium_popup_over<B: Backend>(
|
||||
f: &mut Frame<'_, B>,
|
||||
pub fn draw_medium_popup_over(
|
||||
f: &mut Frame<'_>,
|
||||
app: &mut App<'_>,
|
||||
area: Rect,
|
||||
background_fn: impl Fn(&mut Frame<'_, B>, &mut App<'_>, Rect),
|
||||
popup_fn: impl Fn(&mut Frame<'_, B>, &mut App<'_>, Rect),
|
||||
background_fn: impl Fn(&mut Frame<'_>, &mut App<'_>, Rect),
|
||||
popup_fn: impl Fn(&mut Frame<'_>, &mut App<'_>, Rect),
|
||||
) {
|
||||
draw_popup_over(f, app, area, background_fn, popup_fn, 60, 60);
|
||||
}
|
||||
|
||||
pub fn draw_large_popup_over<B: Backend>(
|
||||
f: &mut Frame<'_, B>,
|
||||
pub fn draw_large_popup_over(
|
||||
f: &mut Frame<'_>,
|
||||
app: &mut App<'_>,
|
||||
area: Rect,
|
||||
background_fn: impl Fn(&mut Frame<'_, B>, &mut App<'_>, Rect),
|
||||
popup_fn: impl Fn(&mut Frame<'_, B>, &mut App<'_>, Rect),
|
||||
background_fn: impl Fn(&mut Frame<'_>, &mut App<'_>, Rect),
|
||||
popup_fn: impl Fn(&mut Frame<'_>, &mut App<'_>, Rect),
|
||||
) {
|
||||
draw_popup_over(f, app, area, background_fn, popup_fn, 75, 75);
|
||||
}
|
||||
|
||||
pub fn draw_large_popup_over_background_fn_with_ui<B: Backend, T: DrawUi>(
|
||||
f: &mut Frame<'_, B>,
|
||||
pub fn draw_large_popup_over_background_fn_with_ui<T: DrawUi>(
|
||||
f: &mut Frame<'_>,
|
||||
app: &mut App<'_>,
|
||||
area: Rect,
|
||||
background_fn: impl Fn(&mut Frame<'_, B>, &mut App<'_>, Rect),
|
||||
background_fn: impl Fn(&mut Frame<'_>, &mut App<'_>, Rect),
|
||||
) {
|
||||
draw_popup_over_ui::<B, T>(f, app, area, background_fn, 75, 75);
|
||||
draw_popup_over_ui::<T>(f, app, area, background_fn, 75, 75);
|
||||
}
|
||||
|
||||
pub fn draw_drop_down_popup<B: Backend>(
|
||||
f: &mut Frame<'_, B>,
|
||||
pub fn draw_drop_down_popup(
|
||||
f: &mut Frame<'_>,
|
||||
app: &mut App<'_>,
|
||||
area: Rect,
|
||||
background_fn: impl Fn(&mut Frame<'_, B>, &mut App<'_>, Rect),
|
||||
drop_down_fn: impl Fn(&mut Frame<'_, B>, &mut App<'_>, Rect),
|
||||
background_fn: impl Fn(&mut Frame<'_>, &mut App<'_>, Rect),
|
||||
drop_down_fn: impl Fn(&mut Frame<'_>, &mut App<'_>, Rect),
|
||||
) {
|
||||
draw_popup_over(f, app, area, background_fn, drop_down_fn, 20, 30);
|
||||
}
|
||||
|
||||
pub fn draw_error_popup_over<B: Backend>(
|
||||
f: &mut Frame<'_, B>,
|
||||
pub fn draw_error_popup_over(
|
||||
f: &mut Frame<'_>,
|
||||
app: &mut App<'_>,
|
||||
area: Rect,
|
||||
message: &str,
|
||||
background_fn: fn(&mut Frame<'_, B>, &mut App<'_>, Rect),
|
||||
background_fn: fn(&mut Frame<'_>, &mut App<'_>, Rect),
|
||||
) {
|
||||
background_fn(f, app, area);
|
||||
draw_error_popup(f, message);
|
||||
}
|
||||
|
||||
pub fn draw_error_popup<B: Backend>(f: &mut Frame<'_, B>, message: &str) {
|
||||
pub fn draw_error_popup(f: &mut Frame<'_>, message: &str) {
|
||||
let prompt_area = centered_rect(25, 8, f.size());
|
||||
f.render_widget(Clear, prompt_area);
|
||||
f.render_widget(background_block(), prompt_area);
|
||||
@@ -254,8 +253,8 @@ pub fn draw_error_popup<B: Backend>(f: &mut Frame<'_, B>, message: &str) {
|
||||
f.render_widget(error_message, prompt_area);
|
||||
}
|
||||
|
||||
fn draw_tabs<'a, B: Backend>(
|
||||
f: &mut Frame<'_, B>,
|
||||
fn draw_tabs<'a>(
|
||||
f: &mut Frame<'_>,
|
||||
area: Rect,
|
||||
title: &str,
|
||||
tab_state: &TabState,
|
||||
@@ -306,8 +305,8 @@ pub struct ListProps<'a, T> {
|
||||
pub help: Option<String>,
|
||||
}
|
||||
|
||||
fn draw_table<'a, B, T, F>(
|
||||
f: &mut Frame<'_, B>,
|
||||
fn draw_table<'a, T, F>(
|
||||
f: &mut Frame<'_>,
|
||||
content_area: Rect,
|
||||
block: Block<'_>,
|
||||
table_props: TableProps<'a, T>,
|
||||
@@ -315,7 +314,6 @@ fn draw_table<'a, B, T, F>(
|
||||
is_loading: bool,
|
||||
highlight: bool,
|
||||
) where
|
||||
B: Backend,
|
||||
F: Fn(&T) -> Row<'a>,
|
||||
{
|
||||
let TableProps {
|
||||
@@ -357,8 +355,8 @@ fn draw_table<'a, B, T, F>(
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn draw_table_contents<'a, B, T, F>(
|
||||
f: &mut Frame<'_, B>,
|
||||
fn draw_table_contents<'a, T, F>(
|
||||
f: &mut Frame<'_>,
|
||||
block: Block<'_>,
|
||||
row_mapper: F,
|
||||
highlight: bool,
|
||||
@@ -367,7 +365,6 @@ fn draw_table_contents<'a, B, T, F>(
|
||||
constraints: Vec<Constraint>,
|
||||
content_area: Rect,
|
||||
) where
|
||||
B: Backend,
|
||||
F: Fn(&T) -> Row<'a>,
|
||||
{
|
||||
let rows = content.items.iter().map(row_mapper);
|
||||
@@ -389,7 +386,7 @@ fn draw_table_contents<'a, B, T, F>(
|
||||
f.render_stateful_widget(table, content_area, &mut content.state);
|
||||
}
|
||||
|
||||
pub fn loading<B: Backend>(f: &mut Frame<'_, B>, block: Block<'_>, area: Rect, is_loading: bool) {
|
||||
pub fn loading(f: &mut Frame<'_>, block: Block<'_>, area: Rect, is_loading: bool) {
|
||||
if is_loading {
|
||||
let text = "\n\n Loading ...\n\n".to_owned();
|
||||
let mut text = Text::from(text);
|
||||
@@ -404,8 +401,8 @@ pub fn loading<B: Backend>(f: &mut Frame<'_, B>, block: Block<'_>, area: Rect, i
|
||||
}
|
||||
}
|
||||
|
||||
pub fn draw_prompt_box<B: Backend>(
|
||||
f: &mut Frame<'_, B>,
|
||||
pub fn draw_prompt_box(
|
||||
f: &mut Frame<'_>,
|
||||
prompt_area: Rect,
|
||||
title: &str,
|
||||
prompt: &str,
|
||||
@@ -414,8 +411,8 @@ pub fn draw_prompt_box<B: Backend>(
|
||||
draw_prompt_box_with_content(f, prompt_area, title, prompt, None, yes_no_value);
|
||||
}
|
||||
|
||||
pub fn draw_prompt_box_with_content<B: Backend>(
|
||||
f: &mut Frame<'_, B>,
|
||||
pub fn draw_prompt_box_with_content(
|
||||
f: &mut Frame<'_>,
|
||||
prompt_area: Rect,
|
||||
title: &str,
|
||||
prompt: &str,
|
||||
@@ -463,8 +460,8 @@ pub fn draw_prompt_box_with_content<B: Backend>(
|
||||
draw_button(f, horizontal_chunks[1], "No", !yes_no_value);
|
||||
}
|
||||
|
||||
pub fn draw_prompt_box_with_checkboxes<B: Backend>(
|
||||
f: &mut Frame<'_, B>,
|
||||
pub fn draw_prompt_box_with_checkboxes(
|
||||
f: &mut Frame<'_>,
|
||||
prompt_area: Rect,
|
||||
title: &str,
|
||||
prompt: &str,
|
||||
@@ -513,12 +510,7 @@ pub fn draw_prompt_box_with_checkboxes<B: Backend>(
|
||||
);
|
||||
}
|
||||
|
||||
pub fn draw_checkbox<B: Backend>(
|
||||
f: &mut Frame<'_, B>,
|
||||
area: Rect,
|
||||
is_checked: bool,
|
||||
is_selected: bool,
|
||||
) {
|
||||
pub fn draw_checkbox(f: &mut Frame<'_>, area: Rect, is_checked: bool, is_selected: bool) {
|
||||
let check = if is_checked { "✔" } else { "" };
|
||||
let label_paragraph = Paragraph::new(Text::from(check))
|
||||
.block(layout_block())
|
||||
@@ -529,8 +521,8 @@ pub fn draw_checkbox<B: Backend>(
|
||||
f.render_widget(label_paragraph, checkbox_area);
|
||||
}
|
||||
|
||||
pub fn draw_checkbox_with_label<B: Backend>(
|
||||
f: &mut Frame<'_, B>,
|
||||
pub fn draw_checkbox_with_label(
|
||||
f: &mut Frame<'_>,
|
||||
area: Rect,
|
||||
label: &str,
|
||||
is_checked: bool,
|
||||
@@ -555,14 +547,14 @@ pub fn draw_checkbox_with_label<B: Backend>(
|
||||
draw_checkbox(f, horizontal_chunks[1], is_checked, is_selected);
|
||||
}
|
||||
|
||||
pub fn draw_button<B: Backend>(f: &mut Frame<'_, B>, area: Rect, label: &str, is_selected: bool) {
|
||||
pub fn draw_button(f: &mut Frame<'_>, area: Rect, label: &str, is_selected: bool) {
|
||||
let label_paragraph = layout_button_paragraph(is_selected, label, Alignment::Center);
|
||||
|
||||
f.render_widget(label_paragraph, area);
|
||||
}
|
||||
|
||||
pub fn draw_button_with_icon<B: Backend>(
|
||||
f: &mut Frame<'_, B>,
|
||||
pub fn draw_button_with_icon(
|
||||
f: &mut Frame<'_>,
|
||||
area: Rect,
|
||||
label: &str,
|
||||
icon: &str,
|
||||
@@ -589,8 +581,8 @@ pub fn draw_button_with_icon<B: Backend>(
|
||||
f.render_widget(icon_paragraph, horizontal_chunks[1]);
|
||||
}
|
||||
|
||||
pub fn draw_drop_down_menu_button<B: Backend>(
|
||||
f: &mut Frame<'_, B>,
|
||||
pub fn draw_drop_down_menu_button(
|
||||
f: &mut Frame<'_>,
|
||||
area: Rect,
|
||||
description: &str,
|
||||
selection: &str,
|
||||
@@ -615,8 +607,8 @@ pub fn draw_drop_down_menu_button<B: Backend>(
|
||||
draw_button_with_icon(f, horizontal_chunks[1], selection, "▼", is_selected);
|
||||
}
|
||||
|
||||
pub fn draw_selectable_list<'a, B: Backend, T>(
|
||||
f: &mut Frame<'_, B>,
|
||||
pub fn draw_selectable_list<'a, T>(
|
||||
f: &mut Frame<'_>,
|
||||
area: Rect,
|
||||
content: &'a mut StatefulList<T>,
|
||||
item_mapper: impl Fn(&T) -> ListItem<'a>,
|
||||
@@ -629,8 +621,8 @@ pub fn draw_selectable_list<'a, B: Backend, T>(
|
||||
f.render_stateful_widget(list, area, &mut content.state);
|
||||
}
|
||||
|
||||
pub fn draw_list_box<'a, B: Backend, T>(
|
||||
f: &mut Frame<'_, B>,
|
||||
pub fn draw_list_box<'a, T>(
|
||||
f: &mut Frame<'_>,
|
||||
area: Rect,
|
||||
item_mapper: impl Fn(&T) -> ListItem<'a>,
|
||||
list_props: ListProps<'a, T>,
|
||||
@@ -667,11 +659,7 @@ pub fn draw_list_box<'a, B: Backend, T>(
|
||||
}
|
||||
}
|
||||
|
||||
fn draw_help_and_get_content_rect<B: Backend>(
|
||||
f: &mut Frame<'_, B>,
|
||||
area: Rect,
|
||||
help: Option<String>,
|
||||
) -> Rect {
|
||||
fn draw_help_and_get_content_rect(f: &mut Frame<'_>, area: Rect, help: Option<String>) -> Rect {
|
||||
if let Some(help_string) = help {
|
||||
let chunks =
|
||||
vertical_chunks_with_margin(vec![Constraint::Min(0), Constraint::Length(2)], area, 1);
|
||||
@@ -690,8 +678,8 @@ fn draw_help_and_get_content_rect<B: Backend>(
|
||||
}
|
||||
}
|
||||
|
||||
pub fn draw_text_box<B: Backend>(
|
||||
f: &mut Frame<'_, B>,
|
||||
pub fn draw_text_box(
|
||||
f: &mut Frame<'_>,
|
||||
text_box_area: Rect,
|
||||
block_title: Option<&str>,
|
||||
block_content: &str,
|
||||
@@ -721,8 +709,8 @@ pub fn draw_text_box<B: Backend>(
|
||||
}
|
||||
}
|
||||
|
||||
pub fn draw_text_box_with_label<B: Backend>(
|
||||
f: &mut Frame<'_, B>,
|
||||
pub fn draw_text_box_with_label(
|
||||
f: &mut Frame<'_>,
|
||||
area: Rect,
|
||||
label: &str,
|
||||
text: &str,
|
||||
@@ -757,8 +745,8 @@ pub fn draw_text_box_with_label<B: Backend>(
|
||||
);
|
||||
}
|
||||
|
||||
pub fn draw_input_box_popup<B: Backend>(
|
||||
f: &mut Frame<'_, B>,
|
||||
pub fn draw_input_box_popup(
|
||||
f: &mut Frame<'_>,
|
||||
input_box_area: Rect,
|
||||
box_title: &str,
|
||||
box_content: &HorizontallyScrollableText,
|
||||
@@ -790,11 +778,7 @@ pub fn draw_input_box_popup<B: Backend>(
|
||||
f.render_widget(help, chunks[1]);
|
||||
}
|
||||
|
||||
pub fn draw_error_message_popup<B: Backend>(
|
||||
f: &mut Frame<'_, B>,
|
||||
error_message_area: Rect,
|
||||
error_msg: &str,
|
||||
) {
|
||||
pub fn draw_error_message_popup(f: &mut Frame<'_>, error_message_area: Rect, error_msg: &str) {
|
||||
let input = Paragraph::new(error_msg)
|
||||
.style(style_failure())
|
||||
.alignment(Alignment::Center)
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
use tui::backend::Backend;
|
||||
use tui::layout::{Alignment, Constraint, Rect};
|
||||
use tui::text::Text;
|
||||
use tui::widgets::{Cell, Paragraph, Row, Wrap};
|
||||
use tui::Frame;
|
||||
use ratatui::layout::{Alignment, Constraint, Rect};
|
||||
use ratatui::text::Text;
|
||||
use ratatui::widgets::{Cell, Paragraph, Row, Wrap};
|
||||
use ratatui::Frame;
|
||||
|
||||
use crate::app::context_clues::{build_context_clue_string, BARE_POPUP_CONTEXT_CLUES};
|
||||
use crate::app::radarr::radarr_context_clues::COLLECTION_DETAILS_CONTEXT_CLUES;
|
||||
@@ -36,10 +35,10 @@ impl DrawUi for CollectionDetailsUi {
|
||||
false
|
||||
}
|
||||
|
||||
fn draw<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, content_rect: Rect) {
|
||||
fn draw(f: &mut Frame<'_>, app: &mut App<'_>, content_rect: Rect) {
|
||||
if let Route::Radarr(active_radarr_block, context_option) = *app.get_current_route() {
|
||||
let draw_collection_details_popup =
|
||||
|f: &mut Frame<'_, B>, app: &mut App<'_>, popup_area: Rect| match context_option
|
||||
|f: &mut Frame<'_>, app: &mut App<'_>, popup_area: Rect| match context_option
|
||||
.unwrap_or(active_radarr_block)
|
||||
{
|
||||
ActiveRadarrBlock::ViewMovieOverview => {
|
||||
@@ -66,11 +65,7 @@ impl DrawUi for CollectionDetailsUi {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn draw_collection_details<B: Backend>(
|
||||
f: &mut Frame<'_, B>,
|
||||
app: &mut App<'_>,
|
||||
content_area: Rect,
|
||||
) {
|
||||
pub fn draw_collection_details(f: &mut Frame<'_>, app: &mut App<'_>, content_area: Rect) {
|
||||
let chunks = vertical_chunks_with_margin(
|
||||
vec![
|
||||
Constraint::Percentage(25),
|
||||
@@ -242,7 +237,7 @@ pub fn draw_collection_details<B: Backend>(
|
||||
);
|
||||
}
|
||||
|
||||
fn draw_movie_overview<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, content_area: Rect) {
|
||||
fn draw_movie_overview(f: &mut Frame<'_>, app: &mut App<'_>, content_area: Rect) {
|
||||
let title_block = title_block("Overview");
|
||||
f.render_widget(title_block, content_area);
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use tui::backend::Backend;
|
||||
use tui::layout::{Constraint, Rect};
|
||||
use tui::widgets::ListItem;
|
||||
use tui::Frame;
|
||||
use ratatui::layout::{Constraint, Rect};
|
||||
use ratatui::widgets::ListItem;
|
||||
use ratatui::Frame;
|
||||
|
||||
use crate::app::App;
|
||||
use crate::models::servarr_data::radarr::modals::EditCollectionModal;
|
||||
@@ -35,10 +34,10 @@ impl DrawUi for EditCollectionUi {
|
||||
false
|
||||
}
|
||||
|
||||
fn draw<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, content_rect: Rect) {
|
||||
fn draw(f: &mut Frame<'_>, app: &mut App<'_>, content_rect: Rect) {
|
||||
if let Route::Radarr(active_radarr_block, context_option) = *app.get_current_route() {
|
||||
let draw_edit_collection_prompt =
|
||||
|f: &mut Frame<'_, B>, app: &mut App<'_>, prompt_area: Rect| match active_radarr_block {
|
||||
|f: &mut Frame<'_>, app: &mut App<'_>, prompt_area: Rect| match active_radarr_block {
|
||||
ActiveRadarrBlock::EditCollectionSelectMinimumAvailability => {
|
||||
draw_drop_down_popup(
|
||||
f,
|
||||
@@ -76,7 +75,7 @@ impl DrawUi for EditCollectionUi {
|
||||
draw_edit_collection_prompt,
|
||||
),
|
||||
_ if COLLECTION_DETAILS_BLOCKS.contains(&context) => {
|
||||
draw_large_popup_over_background_fn_with_ui::<B, CollectionDetailsUi>(
|
||||
draw_large_popup_over_background_fn_with_ui::<CollectionDetailsUi>(
|
||||
f,
|
||||
app,
|
||||
content_rect,
|
||||
@@ -91,8 +90,8 @@ impl DrawUi for EditCollectionUi {
|
||||
}
|
||||
}
|
||||
|
||||
fn draw_edit_collection_confirmation_prompt<B: Backend>(
|
||||
f: &mut Frame<'_, B>,
|
||||
fn draw_edit_collection_confirmation_prompt(
|
||||
f: &mut Frame<'_>,
|
||||
app: &mut App<'_>,
|
||||
prompt_area: Rect,
|
||||
) {
|
||||
@@ -223,8 +222,8 @@ fn draw_edit_collection_confirmation_prompt<B: Backend>(
|
||||
);
|
||||
}
|
||||
|
||||
fn draw_edit_collection_select_minimum_availability_popup<B: Backend>(
|
||||
f: &mut Frame<'_, B>,
|
||||
fn draw_edit_collection_select_minimum_availability_popup(
|
||||
f: &mut Frame<'_>,
|
||||
app: &mut App<'_>,
|
||||
popup_area: Rect,
|
||||
) {
|
||||
@@ -242,8 +241,8 @@ fn draw_edit_collection_select_minimum_availability_popup<B: Backend>(
|
||||
);
|
||||
}
|
||||
|
||||
fn draw_edit_collection_select_quality_profile_popup<B: Backend>(
|
||||
f: &mut Frame<'_, B>,
|
||||
fn draw_edit_collection_select_quality_profile_popup(
|
||||
f: &mut Frame<'_>,
|
||||
app: &mut App<'_>,
|
||||
popup_area: Rect,
|
||||
) {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use tui::backend::Backend;
|
||||
use tui::layout::{Constraint, Rect};
|
||||
use tui::widgets::{Cell, Row};
|
||||
use tui::Frame;
|
||||
use ratatui::layout::{Constraint, Rect};
|
||||
use ratatui::widgets::{Cell, Row};
|
||||
use ratatui::Frame;
|
||||
|
||||
pub(super) use collection_details_ui::draw_collection_details;
|
||||
|
||||
@@ -36,7 +35,7 @@ impl DrawUi for CollectionsUi {
|
||||
false
|
||||
}
|
||||
|
||||
fn draw<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, content_rect: Rect) {
|
||||
fn draw(f: &mut Frame<'_>, app: &mut App<'_>, content_rect: Rect) {
|
||||
let route = *app.get_current_route();
|
||||
let mut collections_ui_matcher = |active_radarr_block| match active_radarr_block {
|
||||
ActiveRadarrBlock::Collections => draw_collections(f, app, content_rect),
|
||||
@@ -99,7 +98,7 @@ impl DrawUi for CollectionsUi {
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn draw_collections<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, area: Rect) {
|
||||
pub(super) fn draw_collections(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||
let current_selection =
|
||||
if let Some(filtered_collections) = app.data.radarr_data.filtered_collections.as_ref() {
|
||||
filtered_collections.current_selection().clone()
|
||||
@@ -176,11 +175,7 @@ pub(super) fn draw_collections<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'
|
||||
);
|
||||
}
|
||||
|
||||
fn draw_update_all_collections_prompt<B: Backend>(
|
||||
f: &mut Frame<'_, B>,
|
||||
app: &mut App<'_>,
|
||||
prompt_area: Rect,
|
||||
) {
|
||||
fn draw_update_all_collections_prompt(f: &mut Frame<'_>, app: &mut App<'_>, prompt_area: Rect) {
|
||||
draw_prompt_box(
|
||||
f,
|
||||
prompt_area,
|
||||
@@ -190,7 +185,7 @@ fn draw_update_all_collections_prompt<B: Backend>(
|
||||
);
|
||||
}
|
||||
|
||||
fn draw_collection_search_box<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, area: Rect) {
|
||||
fn draw_collection_search_box(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||
draw_input_box_popup(
|
||||
f,
|
||||
area,
|
||||
@@ -199,7 +194,7 @@ fn draw_collection_search_box<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_
|
||||
);
|
||||
}
|
||||
|
||||
fn draw_filter_collections_box<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, area: Rect) {
|
||||
fn draw_filter_collections_box(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||
draw_input_box_popup(
|
||||
f,
|
||||
area,
|
||||
@@ -208,14 +203,10 @@ fn draw_filter_collections_box<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'
|
||||
)
|
||||
}
|
||||
|
||||
fn draw_search_collection_error_box<B: Backend>(f: &mut Frame<'_, B>, _: &mut App<'_>, area: Rect) {
|
||||
fn draw_search_collection_error_box(f: &mut Frame<'_>, _: &mut App<'_>, area: Rect) {
|
||||
draw_error_message_popup(f, area, "Collection not found!");
|
||||
}
|
||||
|
||||
fn draw_filter_collections_error_box<B: Backend>(
|
||||
f: &mut Frame<'_, B>,
|
||||
_: &mut App<'_>,
|
||||
area: Rect,
|
||||
) {
|
||||
fn draw_filter_collections_error_box(f: &mut Frame<'_>, _: &mut App<'_>, area: Rect) {
|
||||
draw_error_message_popup(f, area, "No collections found matching the given filter!");
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use tui::backend::Backend;
|
||||
use tui::layout::{Constraint, Rect};
|
||||
use tui::widgets::{Cell, Row};
|
||||
use tui::Frame;
|
||||
use ratatui::layout::{Constraint, Rect};
|
||||
use ratatui::widgets::{Cell, Row};
|
||||
use ratatui::Frame;
|
||||
|
||||
use crate::app::App;
|
||||
use crate::models::radarr_models::DownloadRecord;
|
||||
@@ -26,7 +25,7 @@ impl DrawUi for DownloadsUi {
|
||||
false
|
||||
}
|
||||
|
||||
fn draw<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, content_rect: Rect) {
|
||||
fn draw(f: &mut Frame<'_>, app: &mut App<'_>, content_rect: Rect) {
|
||||
if let Route::Radarr(active_radarr_block, _) = *app.get_current_route() {
|
||||
match active_radarr_block {
|
||||
ActiveRadarrBlock::Downloads => draw_downloads(f, app, content_rect),
|
||||
@@ -50,7 +49,7 @@ impl DrawUi for DownloadsUi {
|
||||
}
|
||||
}
|
||||
|
||||
fn draw_downloads<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, area: Rect) {
|
||||
fn draw_downloads(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||
let current_selection = if app.data.radarr_data.downloads.items.is_empty() {
|
||||
DownloadRecord::default()
|
||||
} else {
|
||||
@@ -128,11 +127,7 @@ fn draw_downloads<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, area: Rec
|
||||
);
|
||||
}
|
||||
|
||||
fn draw_delete_download_prompt<B: Backend>(
|
||||
f: &mut Frame<'_, B>,
|
||||
app: &mut App<'_>,
|
||||
prompt_area: Rect,
|
||||
) {
|
||||
fn draw_delete_download_prompt(f: &mut Frame<'_>, app: &mut App<'_>, prompt_area: Rect) {
|
||||
draw_prompt_box(
|
||||
f,
|
||||
prompt_area,
|
||||
@@ -146,11 +141,7 @@ fn draw_delete_download_prompt<B: Backend>(
|
||||
);
|
||||
}
|
||||
|
||||
fn draw_update_downloads_prompt<B: Backend>(
|
||||
f: &mut Frame<'_, B>,
|
||||
app: &mut App<'_>,
|
||||
prompt_area: Rect,
|
||||
) {
|
||||
fn draw_update_downloads_prompt(f: &mut Frame<'_>, app: &mut App<'_>, prompt_area: Rect) {
|
||||
draw_prompt_box(
|
||||
f,
|
||||
prompt_area,
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use ratatui::layout::{Constraint, Rect};
|
||||
use ratatui::Frame;
|
||||
use std::iter;
|
||||
use tui::backend::Backend;
|
||||
use tui::layout::{Constraint, Rect};
|
||||
use tui::Frame;
|
||||
|
||||
use crate::app::App;
|
||||
use crate::models::servarr_data::radarr::radarr_data::{
|
||||
@@ -32,7 +31,7 @@ impl DrawUi for IndexerSettingsUi {
|
||||
false
|
||||
}
|
||||
|
||||
fn draw<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, content_rect: Rect) {
|
||||
fn draw(f: &mut Frame<'_>, app: &mut App<'_>, content_rect: Rect) {
|
||||
draw_popup_over(
|
||||
f,
|
||||
app,
|
||||
@@ -45,11 +44,7 @@ impl DrawUi for IndexerSettingsUi {
|
||||
}
|
||||
}
|
||||
|
||||
fn draw_edit_indexer_settings_prompt<B: Backend>(
|
||||
f: &mut Frame<'_, B>,
|
||||
app: &mut App<'_>,
|
||||
prompt_area: Rect,
|
||||
) {
|
||||
fn draw_edit_indexer_settings_prompt(f: &mut Frame<'_>, app: &mut App<'_>, prompt_area: Rect) {
|
||||
let block = title_block_centered("Configure All Indexer Settings");
|
||||
let yes_no_value = app.data.radarr_data.prompt_confirm;
|
||||
let selected_block = app.data.radarr_data.selected_block.get_active_block();
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
use tui::backend::Backend;
|
||||
use tui::layout::{Constraint, Rect};
|
||||
use tui::text::Text;
|
||||
use tui::widgets::{Cell, Row};
|
||||
use tui::Frame;
|
||||
use ratatui::layout::{Constraint, Rect};
|
||||
use ratatui::text::Text;
|
||||
use ratatui::widgets::{Cell, Row};
|
||||
use ratatui::Frame;
|
||||
|
||||
use crate::app::App;
|
||||
use crate::models::radarr_models::Indexer;
|
||||
use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, INDEXERS_BLOCKS};
|
||||
use crate::models::Route;
|
||||
use crate::ui::radarr_ui::indexers::indexer_settings_ui::IndexerSettingsUi;
|
||||
use crate::ui::radarr_ui::indexers::test_all_indexers_ui::TestAllIndexersUi;
|
||||
use crate::ui::utils::{layout_block_top_border, style_failure, style_primary, style_success};
|
||||
use crate::ui::{draw_prompt_box, draw_prompt_popup_over, draw_table, DrawUi, TableProps};
|
||||
|
||||
@@ -17,6 +17,7 @@ mod indexer_settings_ui;
|
||||
#[cfg(test)]
|
||||
#[path = "indexers_ui_tests.rs"]
|
||||
mod indexers_ui_tests;
|
||||
mod test_all_indexers_ui;
|
||||
|
||||
pub(super) struct IndexersUi;
|
||||
|
||||
@@ -29,7 +30,7 @@ impl DrawUi for IndexersUi {
|
||||
false
|
||||
}
|
||||
|
||||
fn draw<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, content_rect: Rect) {
|
||||
fn draw(f: &mut Frame<'_>, app: &mut App<'_>, content_rect: Rect) {
|
||||
let route = *app.get_current_route();
|
||||
let mut indexers_matchers = |active_radarr_block| match active_radarr_block {
|
||||
ActiveRadarrBlock::Indexers => draw_indexers(f, app, content_rect),
|
||||
@@ -45,6 +46,7 @@ impl DrawUi for IndexersUi {
|
||||
|
||||
match route {
|
||||
_ if IndexerSettingsUi::accepts(route) => IndexerSettingsUi::draw(f, app, content_rect),
|
||||
_ if TestAllIndexersUi::accepts(route) => TestAllIndexersUi::draw(f, app, content_rect),
|
||||
Route::Radarr(active_radarr_block, _) if INDEXERS_BLOCKS.contains(&active_radarr_block) => {
|
||||
indexers_matchers(active_radarr_block)
|
||||
}
|
||||
@@ -53,7 +55,7 @@ impl DrawUi for IndexersUi {
|
||||
}
|
||||
}
|
||||
|
||||
fn draw_indexers<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, area: Rect) {
|
||||
fn draw_indexers(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||
draw_table(
|
||||
f,
|
||||
area,
|
||||
@@ -125,11 +127,7 @@ fn draw_indexers<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, area: Rect
|
||||
)
|
||||
}
|
||||
|
||||
fn draw_delete_indexer_prompt<B: Backend>(
|
||||
f: &mut Frame<'_, B>,
|
||||
app: &mut App<'_>,
|
||||
prompt_area: Rect,
|
||||
) {
|
||||
fn draw_delete_indexer_prompt(f: &mut Frame<'_>, app: &mut App<'_>, prompt_area: Rect) {
|
||||
draw_prompt_box(
|
||||
f,
|
||||
prompt_area,
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
use crate::app::context_clues::{build_context_clue_string, BARE_POPUP_CONTEXT_CLUES};
|
||||
use crate::app::App;
|
||||
use crate::models::servarr_data::radarr::modals::IndexerTestResultModalItem;
|
||||
use crate::models::servarr_data::radarr::radarr_data::ActiveRadarrBlock;
|
||||
use crate::models::Route;
|
||||
use crate::ui::radarr_ui::indexers::draw_indexers;
|
||||
use crate::ui::utils::{
|
||||
borderless_block, get_width_from_percentage, style_failure, style_success, title_block,
|
||||
};
|
||||
use crate::ui::{
|
||||
draw_help_and_get_content_rect, draw_large_popup_over, draw_table, DrawUi, TableProps,
|
||||
};
|
||||
use ratatui::layout::{Constraint, Rect};
|
||||
use ratatui::widgets::{Cell, Row};
|
||||
use ratatui::Frame;
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "test_all_indexers_ui_tests.rs"]
|
||||
mod test_all_indexers_ui_tests;
|
||||
|
||||
pub(super) struct TestAllIndexersUi;
|
||||
|
||||
impl DrawUi for TestAllIndexersUi {
|
||||
fn accepts(route: Route) -> bool {
|
||||
if let Route::Radarr(active_radarr_block, _) = route {
|
||||
return active_radarr_block == ActiveRadarrBlock::TestAllIndexers;
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
fn draw(f: &mut Frame<'_>, app: &mut App<'_>, content_rect: Rect) {
|
||||
draw_large_popup_over(
|
||||
f,
|
||||
app,
|
||||
content_rect,
|
||||
draw_indexers,
|
||||
draw_test_all_indexers_test_results,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn draw_test_all_indexers_test_results(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||
let current_selection =
|
||||
if let Some(test_all_results) = app.data.radarr_data.indexer_test_all_results.as_ref() {
|
||||
test_all_results.current_selection().clone()
|
||||
} else {
|
||||
IndexerTestResultModalItem::default()
|
||||
};
|
||||
f.render_widget(title_block("Test All Indexers"), area);
|
||||
let help = Some(format!(
|
||||
"<↑↓> scroll | {}",
|
||||
build_context_clue_string(&BARE_POPUP_CONTEXT_CLUES)
|
||||
));
|
||||
let content_area = draw_help_and_get_content_rect(f, area, help);
|
||||
|
||||
draw_table(
|
||||
f,
|
||||
content_area,
|
||||
borderless_block(),
|
||||
TableProps {
|
||||
content: app.data.radarr_data.indexer_test_all_results.as_mut(),
|
||||
wrapped_content: None,
|
||||
table_headers: vec!["Indexer", "Pass/Fail", "Failure Messages"],
|
||||
constraints: vec![
|
||||
Constraint::Percentage(20),
|
||||
Constraint::Percentage(10),
|
||||
Constraint::Percentage(70),
|
||||
],
|
||||
help: None,
|
||||
},
|
||||
|result| {
|
||||
result.validation_failures.scroll_left_or_reset(
|
||||
get_width_from_percentage(area, 86),
|
||||
*result == current_selection,
|
||||
app.tick_count % app.ticks_until_scroll == 0,
|
||||
);
|
||||
let pass_fail = if result.is_valid { "✔" } else { "❌" };
|
||||
let row_style = if result.is_valid {
|
||||
style_success()
|
||||
} else {
|
||||
style_failure()
|
||||
};
|
||||
|
||||
Row::new(vec![
|
||||
Cell::from(result.name.to_owned()),
|
||||
Cell::from(pass_fail.to_owned()),
|
||||
Cell::from(result.validation_failures.to_string()),
|
||||
])
|
||||
.style(row_style)
|
||||
},
|
||||
app.is_loading,
|
||||
true,
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use strum::IntoEnumIterator;
|
||||
|
||||
use crate::models::servarr_data::radarr::radarr_data::ActiveRadarrBlock;
|
||||
use crate::ui::radarr_ui::indexers::test_all_indexers_ui::TestAllIndexersUi;
|
||||
use crate::ui::DrawUi;
|
||||
|
||||
#[test]
|
||||
fn test_test_all_indexers_ui_accepts() {
|
||||
ActiveRadarrBlock::iter().for_each(|active_radarr_block| {
|
||||
if active_radarr_block == ActiveRadarrBlock::TestAllIndexers {
|
||||
assert!(TestAllIndexersUi::accepts(active_radarr_block.into()));
|
||||
} else {
|
||||
assert!(!TestAllIndexersUi::accepts(active_radarr_block.into()));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,7 @@
|
||||
use tui::backend::Backend;
|
||||
use tui::layout::{Alignment, Constraint, Rect};
|
||||
use tui::text::Text;
|
||||
use tui::widgets::{Cell, ListItem, Paragraph, Row};
|
||||
use tui::Frame;
|
||||
use ratatui::layout::{Alignment, Constraint, Rect};
|
||||
use ratatui::text::Text;
|
||||
use ratatui::widgets::{Cell, ListItem, Paragraph, Row};
|
||||
use ratatui::Frame;
|
||||
|
||||
use crate::app::context_clues::{build_context_clue_string, BARE_POPUP_CONTEXT_CLUES};
|
||||
use crate::app::radarr::radarr_context_clues::ADD_MOVIE_SEARCH_RESULTS_CONTEXT_CLUES;
|
||||
@@ -40,10 +39,10 @@ impl DrawUi for AddMovieUi {
|
||||
false
|
||||
}
|
||||
|
||||
fn draw<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, content_rect: Rect) {
|
||||
fn draw(f: &mut Frame<'_>, app: &mut App<'_>, content_rect: Rect) {
|
||||
if let Route::Radarr(active_radarr_block, context_option) = *app.get_current_route() {
|
||||
let draw_add_movie_search_popup =
|
||||
|f: &mut Frame<'_, B>, app: &mut App<'_>, area: Rect| match active_radarr_block {
|
||||
|f: &mut Frame<'_>, app: &mut App<'_>, area: Rect| match active_radarr_block {
|
||||
ActiveRadarrBlock::AddMovieSearchInput
|
||||
| ActiveRadarrBlock::AddMovieSearchResults
|
||||
| ActiveRadarrBlock::AddMovieEmptySearchResults => {
|
||||
@@ -103,7 +102,7 @@ impl DrawUi for AddMovieUi {
|
||||
}
|
||||
}
|
||||
|
||||
fn draw_add_movie_search<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, area: Rect) {
|
||||
fn draw_add_movie_search(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||
let is_loading = app.is_loading || app.data.radarr_data.add_searched_movies.is_none();
|
||||
let current_selection =
|
||||
if let Some(add_searched_movies) = app.data.radarr_data.add_searched_movies.as_ref() {
|
||||
@@ -277,7 +276,7 @@ fn draw_add_movie_search<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, ar
|
||||
);
|
||||
}
|
||||
|
||||
fn draw_confirmation_popup<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, prompt_area: Rect) {
|
||||
fn draw_confirmation_popup(f: &mut Frame<'_>, app: &mut App<'_>, prompt_area: Rect) {
|
||||
if let Route::Radarr(active_radarr_block, _) = *app.get_current_route() {
|
||||
match active_radarr_block {
|
||||
ActiveRadarrBlock::AddMovieSelectMonitor => {
|
||||
@@ -324,11 +323,7 @@ fn draw_confirmation_popup<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>,
|
||||
}
|
||||
}
|
||||
|
||||
fn draw_confirmation_prompt<B: Backend>(
|
||||
f: &mut Frame<'_, B>,
|
||||
app: &mut App<'_>,
|
||||
prompt_area: Rect,
|
||||
) {
|
||||
fn draw_confirmation_prompt(f: &mut Frame<'_>, app: &mut App<'_>, prompt_area: Rect) {
|
||||
let (movie_title, movie_overview) = if let Route::Radarr(_, Some(_)) = app.get_current_route() {
|
||||
(
|
||||
&app
|
||||
@@ -469,11 +464,7 @@ fn draw_confirmation_prompt<B: Backend>(
|
||||
);
|
||||
}
|
||||
|
||||
fn draw_add_movie_select_monitor_popup<B: Backend>(
|
||||
f: &mut Frame<'_, B>,
|
||||
app: &mut App<'_>,
|
||||
popup_area: Rect,
|
||||
) {
|
||||
fn draw_add_movie_select_monitor_popup(f: &mut Frame<'_>, app: &mut App<'_>, popup_area: Rect) {
|
||||
draw_selectable_list(
|
||||
f,
|
||||
popup_area,
|
||||
@@ -488,8 +479,8 @@ fn draw_add_movie_select_monitor_popup<B: Backend>(
|
||||
);
|
||||
}
|
||||
|
||||
fn draw_add_movie_select_minimum_availability_popup<B: Backend>(
|
||||
f: &mut Frame<'_, B>,
|
||||
fn draw_add_movie_select_minimum_availability_popup(
|
||||
f: &mut Frame<'_>,
|
||||
app: &mut App<'_>,
|
||||
popup_area: Rect,
|
||||
) {
|
||||
@@ -507,8 +498,8 @@ fn draw_add_movie_select_minimum_availability_popup<B: Backend>(
|
||||
);
|
||||
}
|
||||
|
||||
fn draw_add_movie_select_quality_profile_popup<B: Backend>(
|
||||
f: &mut Frame<'_, B>,
|
||||
fn draw_add_movie_select_quality_profile_popup(
|
||||
f: &mut Frame<'_>,
|
||||
app: &mut App<'_>,
|
||||
popup_area: Rect,
|
||||
) {
|
||||
@@ -526,11 +517,7 @@ fn draw_add_movie_select_quality_profile_popup<B: Backend>(
|
||||
);
|
||||
}
|
||||
|
||||
fn draw_add_movie_select_root_folder_popup<B: Backend>(
|
||||
f: &mut Frame<'_, B>,
|
||||
app: &mut App<'_>,
|
||||
popup_area: Rect,
|
||||
) {
|
||||
fn draw_add_movie_select_root_folder_popup(f: &mut Frame<'_>, app: &mut App<'_>, popup_area: Rect) {
|
||||
draw_selectable_list(
|
||||
f,
|
||||
popup_area,
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
use tui::backend::Backend;
|
||||
use tui::layout::Rect;
|
||||
use tui::Frame;
|
||||
use ratatui::layout::Rect;
|
||||
use ratatui::Frame;
|
||||
|
||||
use crate::app::App;
|
||||
use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, DELETE_MOVIE_BLOCKS};
|
||||
@@ -23,39 +22,38 @@ impl DrawUi for DeleteMovieUi {
|
||||
false
|
||||
}
|
||||
|
||||
fn draw<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, content_rect: Rect) {
|
||||
fn draw(f: &mut Frame<'_>, app: &mut App<'_>, content_rect: Rect) {
|
||||
if matches!(
|
||||
*app.get_current_route(),
|
||||
Route::Radarr(ActiveRadarrBlock::DeleteMoviePrompt, _)
|
||||
) {
|
||||
let draw_delete_movie_prompt =
|
||||
|f: &mut Frame<'_, B>, app: &mut App<'_>, prompt_area: Rect| {
|
||||
let selected_block = app.data.radarr_data.selected_block.get_active_block();
|
||||
draw_prompt_box_with_checkboxes(
|
||||
f,
|
||||
prompt_area,
|
||||
"Delete Movie",
|
||||
format!(
|
||||
"Do you really want to delete: \n{}?",
|
||||
app.data.radarr_data.movies.current_selection().title.text
|
||||
)
|
||||
.as_str(),
|
||||
vec![
|
||||
(
|
||||
"Delete Movie Files",
|
||||
app.data.radarr_data.delete_movie_files,
|
||||
selected_block == &ActiveRadarrBlock::DeleteMovieToggleDeleteFile,
|
||||
),
|
||||
(
|
||||
"Add List Exclusion",
|
||||
app.data.radarr_data.add_list_exclusion,
|
||||
selected_block == &ActiveRadarrBlock::DeleteMovieToggleAddListExclusion,
|
||||
),
|
||||
],
|
||||
selected_block == &ActiveRadarrBlock::DeleteMovieConfirmPrompt,
|
||||
app.data.radarr_data.prompt_confirm,
|
||||
let draw_delete_movie_prompt = |f: &mut Frame<'_>, app: &mut App<'_>, prompt_area: Rect| {
|
||||
let selected_block = app.data.radarr_data.selected_block.get_active_block();
|
||||
draw_prompt_box_with_checkboxes(
|
||||
f,
|
||||
prompt_area,
|
||||
"Delete Movie",
|
||||
format!(
|
||||
"Do you really want to delete: \n{}?",
|
||||
app.data.radarr_data.movies.current_selection().title.text
|
||||
)
|
||||
};
|
||||
.as_str(),
|
||||
vec![
|
||||
(
|
||||
"Delete Movie Files",
|
||||
app.data.radarr_data.delete_movie_files,
|
||||
selected_block == &ActiveRadarrBlock::DeleteMovieToggleDeleteFile,
|
||||
),
|
||||
(
|
||||
"Add List Exclusion",
|
||||
app.data.radarr_data.add_list_exclusion,
|
||||
selected_block == &ActiveRadarrBlock::DeleteMovieToggleAddListExclusion,
|
||||
),
|
||||
],
|
||||
selected_block == &ActiveRadarrBlock::DeleteMovieConfirmPrompt,
|
||||
app.data.radarr_data.prompt_confirm,
|
||||
)
|
||||
};
|
||||
|
||||
draw_prompt_popup_over(f, app, content_rect, draw_library, draw_delete_movie_prompt);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use tui::backend::Backend;
|
||||
use tui::layout::{Constraint, Rect};
|
||||
use tui::widgets::ListItem;
|
||||
use tui::Frame;
|
||||
use ratatui::layout::{Constraint, Rect};
|
||||
use ratatui::widgets::ListItem;
|
||||
use ratatui::Frame;
|
||||
|
||||
use crate::app::App;
|
||||
use crate::models::servarr_data::radarr::modals::EditMovieModal;
|
||||
@@ -36,10 +35,10 @@ impl DrawUi for EditMovieUi {
|
||||
false
|
||||
}
|
||||
|
||||
fn draw<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, content_rect: Rect) {
|
||||
fn draw(f: &mut Frame<'_>, app: &mut App<'_>, content_rect: Rect) {
|
||||
if let Route::Radarr(active_radarr_block, context_option) = *app.get_current_route() {
|
||||
let draw_edit_movie_prompt =
|
||||
|f: &mut Frame<'_, B>, app: &mut App<'_>, prompt_area: Rect| match active_radarr_block {
|
||||
|f: &mut Frame<'_>, app: &mut App<'_>, prompt_area: Rect| match active_radarr_block {
|
||||
ActiveRadarrBlock::EditMovieSelectMinimumAvailability => {
|
||||
draw_drop_down_popup(
|
||||
f,
|
||||
@@ -73,7 +72,7 @@ impl DrawUi for EditMovieUi {
|
||||
draw_medium_popup_over(f, app, content_rect, draw_library, draw_edit_movie_prompt);
|
||||
}
|
||||
_ if MOVIE_DETAILS_BLOCKS.contains(&context) => {
|
||||
draw_large_popup_over_background_fn_with_ui::<B, MovieDetailsUi>(
|
||||
draw_large_popup_over_background_fn_with_ui::<MovieDetailsUi>(
|
||||
f,
|
||||
app,
|
||||
content_rect,
|
||||
@@ -88,11 +87,7 @@ impl DrawUi for EditMovieUi {
|
||||
}
|
||||
}
|
||||
|
||||
fn draw_edit_movie_confirmation_prompt<B: Backend>(
|
||||
f: &mut Frame<'_, B>,
|
||||
app: &mut App<'_>,
|
||||
prompt_area: Rect,
|
||||
) {
|
||||
fn draw_edit_movie_confirmation_prompt(f: &mut Frame<'_>, app: &mut App<'_>, prompt_area: Rect) {
|
||||
let (movie_title, movie_overview) =
|
||||
if let Some(filtered_movies) = app.data.radarr_data.filtered_movies.as_ref() {
|
||||
(
|
||||
@@ -216,8 +211,8 @@ fn draw_edit_movie_confirmation_prompt<B: Backend>(
|
||||
);
|
||||
}
|
||||
|
||||
fn draw_edit_movie_select_minimum_availability_popup<B: Backend>(
|
||||
f: &mut Frame<'_, B>,
|
||||
fn draw_edit_movie_select_minimum_availability_popup(
|
||||
f: &mut Frame<'_>,
|
||||
app: &mut App<'_>,
|
||||
popup_area: Rect,
|
||||
) {
|
||||
@@ -235,8 +230,8 @@ fn draw_edit_movie_select_minimum_availability_popup<B: Backend>(
|
||||
);
|
||||
}
|
||||
|
||||
fn draw_edit_movie_select_quality_profile_popup<B: Backend>(
|
||||
f: &mut Frame<'_, B>,
|
||||
fn draw_edit_movie_select_quality_profile_popup(
|
||||
f: &mut Frame<'_>,
|
||||
app: &mut App<'_>,
|
||||
popup_area: Rect,
|
||||
) {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use tui::backend::Backend;
|
||||
use tui::layout::{Constraint, Rect};
|
||||
use tui::widgets::{Cell, Row};
|
||||
use tui::Frame;
|
||||
use ratatui::layout::{Constraint, Rect};
|
||||
use ratatui::widgets::{Cell, Row};
|
||||
use ratatui::Frame;
|
||||
|
||||
use crate::app::App;
|
||||
use crate::models::radarr_models::Movie;
|
||||
@@ -43,7 +42,7 @@ impl DrawUi for LibraryUi {
|
||||
false
|
||||
}
|
||||
|
||||
fn draw<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, content_rect: Rect) {
|
||||
fn draw(f: &mut Frame<'_>, app: &mut App<'_>, content_rect: Rect) {
|
||||
let route = *app.get_current_route();
|
||||
let mut library_ui_matchers = |active_radarr_block: ActiveRadarrBlock| match active_radarr_block
|
||||
{
|
||||
@@ -107,7 +106,7 @@ impl DrawUi for LibraryUi {
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn draw_library<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, area: Rect) {
|
||||
pub(super) fn draw_library(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||
let current_selection =
|
||||
if let Some(filtered_movies) = app.data.radarr_data.filtered_movies.as_ref() {
|
||||
filtered_movies.current_selection().clone()
|
||||
@@ -206,11 +205,7 @@ pub(super) fn draw_library<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>,
|
||||
);
|
||||
}
|
||||
|
||||
fn draw_update_all_movies_prompt<B: Backend>(
|
||||
f: &mut Frame<'_, B>,
|
||||
app: &mut App<'_>,
|
||||
prompt_area: Rect,
|
||||
) {
|
||||
fn draw_update_all_movies_prompt(f: &mut Frame<'_>, app: &mut App<'_>, prompt_area: Rect) {
|
||||
draw_prompt_box(
|
||||
f,
|
||||
prompt_area,
|
||||
@@ -220,7 +215,7 @@ fn draw_update_all_movies_prompt<B: Backend>(
|
||||
);
|
||||
}
|
||||
|
||||
fn draw_movie_search_box<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, area: Rect) {
|
||||
fn draw_movie_search_box(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||
draw_input_box_popup(
|
||||
f,
|
||||
area,
|
||||
@@ -229,7 +224,7 @@ fn draw_movie_search_box<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, ar
|
||||
);
|
||||
}
|
||||
|
||||
fn draw_filter_movies_box<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, area: Rect) {
|
||||
fn draw_filter_movies_box(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||
draw_input_box_popup(
|
||||
f,
|
||||
area,
|
||||
@@ -238,10 +233,10 @@ fn draw_filter_movies_box<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, a
|
||||
)
|
||||
}
|
||||
|
||||
fn draw_search_movie_error_box<B: Backend>(f: &mut Frame<'_, B>, _: &mut App<'_>, area: Rect) {
|
||||
fn draw_search_movie_error_box(f: &mut Frame<'_>, _: &mut App<'_>, area: Rect) {
|
||||
draw_error_message_popup(f, area, "Movie not found!");
|
||||
}
|
||||
|
||||
fn draw_filter_movies_error_box<B: Backend>(f: &mut Frame<'_, B>, _: &mut App<'_>, area: Rect) {
|
||||
fn draw_filter_movies_error_box(f: &mut Frame<'_>, _: &mut App<'_>, area: Rect) {
|
||||
draw_error_message_popup(f, area, "No movies found matching the given filter!");
|
||||
}
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
use std::iter;
|
||||
|
||||
use tui::backend::Backend;
|
||||
use tui::layout::{Alignment, Constraint, Rect};
|
||||
use tui::style::{Modifier, Style};
|
||||
use tui::text::{Line, Span, Text};
|
||||
use tui::widgets::{Cell, ListItem, Paragraph, Row, Wrap};
|
||||
use tui::Frame;
|
||||
use ratatui::layout::{Alignment, Constraint, Rect};
|
||||
use ratatui::style::{Modifier, Style};
|
||||
use ratatui::text::{Line, Span, Text};
|
||||
use ratatui::widgets::{Cell, ListItem, Paragraph, Row, Wrap};
|
||||
use ratatui::Frame;
|
||||
|
||||
use crate::app::App;
|
||||
use crate::models::radarr_models::{Credit, MovieHistoryItem, Release, ReleaseField};
|
||||
@@ -39,9 +38,9 @@ impl DrawUi for MovieDetailsUi {
|
||||
false
|
||||
}
|
||||
|
||||
fn draw<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, content_rect: Rect) {
|
||||
fn draw(f: &mut Frame<'_>, app: &mut App<'_>, content_rect: Rect) {
|
||||
if let Route::Radarr(active_radarr_block, context_option) = *app.get_current_route() {
|
||||
let draw_movie_info_popup = |f: &mut Frame<'_, B>, app: &mut App<'_>, popup_area: Rect| {
|
||||
let draw_movie_info_popup = |f: &mut Frame<'_>, app: &mut App<'_>, popup_area: Rect| {
|
||||
let (content_area, _) = draw_tabs(
|
||||
f,
|
||||
popup_area,
|
||||
@@ -100,7 +99,7 @@ impl DrawUi for MovieDetailsUi {
|
||||
}
|
||||
}
|
||||
|
||||
fn draw_movie_info<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, area: Rect) {
|
||||
fn draw_movie_info(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||
if let Route::Radarr(active_radarr_block, _) =
|
||||
app.data.radarr_data.movie_info_tabs.get_active_route()
|
||||
{
|
||||
@@ -116,11 +115,7 @@ fn draw_movie_info<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, area: Re
|
||||
}
|
||||
}
|
||||
|
||||
fn draw_search_movie_prompt<B: Backend>(
|
||||
f: &mut Frame<'_, B>,
|
||||
app: &mut App<'_>,
|
||||
prompt_area: Rect,
|
||||
) {
|
||||
fn draw_search_movie_prompt(f: &mut Frame<'_>, app: &mut App<'_>, prompt_area: Rect) {
|
||||
draw_prompt_box(
|
||||
f,
|
||||
prompt_area,
|
||||
@@ -134,11 +129,7 @@ fn draw_search_movie_prompt<B: Backend>(
|
||||
);
|
||||
}
|
||||
|
||||
fn draw_update_and_scan_prompt<B: Backend>(
|
||||
f: &mut Frame<'_, B>,
|
||||
app: &mut App<'_>,
|
||||
prompt_area: Rect,
|
||||
) {
|
||||
fn draw_update_and_scan_prompt(f: &mut Frame<'_>, app: &mut App<'_>, prompt_area: Rect) {
|
||||
draw_prompt_box(
|
||||
f,
|
||||
prompt_area,
|
||||
@@ -152,7 +143,7 @@ fn draw_update_and_scan_prompt<B: Backend>(
|
||||
);
|
||||
}
|
||||
|
||||
fn draw_file_info<B: Backend>(f: &mut Frame<'_, B>, app: &App<'_>, content_area: Rect) {
|
||||
fn draw_file_info(f: &mut Frame<'_>, app: &App<'_>, content_area: Rect) {
|
||||
match app.data.radarr_data.movie_details_modal.as_ref() {
|
||||
Some(movie_details_modal)
|
||||
if !movie_details_modal.file_details.is_empty() && !app.is_loading =>
|
||||
@@ -210,7 +201,7 @@ fn draw_file_info<B: Backend>(f: &mut Frame<'_, B>, app: &App<'_>, content_area:
|
||||
}
|
||||
}
|
||||
|
||||
fn draw_movie_details<B: Backend>(f: &mut Frame<'_, B>, app: &App<'_>, content_area: Rect) {
|
||||
fn draw_movie_details(f: &mut Frame<'_>, app: &App<'_>, content_area: Rect) {
|
||||
let block = layout_block_top_border();
|
||||
|
||||
match app.data.radarr_data.movie_details_modal.as_ref() {
|
||||
@@ -253,7 +244,7 @@ fn draw_movie_details<B: Backend>(f: &mut Frame<'_, B>, app: &App<'_>, content_a
|
||||
}
|
||||
}
|
||||
|
||||
fn draw_movie_history<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, content_area: Rect) {
|
||||
fn draw_movie_history(f: &mut Frame<'_>, app: &mut App<'_>, content_area: Rect) {
|
||||
if let Some(movie_details_modal) = app.data.radarr_data.movie_details_modal.as_mut() {
|
||||
let current_selection = if movie_details_modal.movie_history.items.is_empty() {
|
||||
MovieHistoryItem::default()
|
||||
@@ -321,7 +312,7 @@ fn draw_movie_history<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, conte
|
||||
}
|
||||
}
|
||||
|
||||
fn draw_movie_cast<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, content_area: Rect) {
|
||||
fn draw_movie_cast(f: &mut Frame<'_>, app: &mut App<'_>, content_area: Rect) {
|
||||
draw_table(
|
||||
f,
|
||||
content_area,
|
||||
@@ -363,7 +354,7 @@ fn draw_movie_cast<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, content_
|
||||
);
|
||||
}
|
||||
|
||||
fn draw_movie_crew<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, content_area: Rect) {
|
||||
fn draw_movie_crew(f: &mut Frame<'_>, app: &mut App<'_>, content_area: Rect) {
|
||||
draw_table(
|
||||
f,
|
||||
content_area,
|
||||
@@ -407,7 +398,7 @@ fn draw_movie_crew<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, content_
|
||||
);
|
||||
}
|
||||
|
||||
fn draw_movie_releases<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, content_area: Rect) {
|
||||
fn draw_movie_releases(f: &mut Frame<'_>, app: &mut App<'_>, content_area: Rect) {
|
||||
let (current_selection, is_empty, sort_ascending) =
|
||||
match app.data.radarr_data.movie_details_modal.as_ref() {
|
||||
Some(movie_details_modal) if !movie_details_modal.movie_releases.items.is_empty() => (
|
||||
@@ -549,11 +540,7 @@ fn draw_movie_releases<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, cont
|
||||
);
|
||||
}
|
||||
|
||||
fn draw_manual_search_confirm_prompt<B: Backend>(
|
||||
f: &mut Frame<'_, B>,
|
||||
app: &mut App<'_>,
|
||||
prompt_area: Rect,
|
||||
) {
|
||||
fn draw_manual_search_confirm_prompt(f: &mut Frame<'_>, app: &mut App<'_>, prompt_area: Rect) {
|
||||
let current_selection = app
|
||||
.data
|
||||
.radarr_data
|
||||
|
||||
+10
-11
@@ -1,12 +1,11 @@
|
||||
use std::iter;
|
||||
|
||||
use chrono::{Duration, Utc};
|
||||
use tui::backend::Backend;
|
||||
use tui::layout::{Alignment, Constraint, Rect};
|
||||
use tui::style::{Color, Style};
|
||||
use tui::text::Text;
|
||||
use tui::widgets::Paragraph;
|
||||
use tui::Frame;
|
||||
use ratatui::layout::{Alignment, Constraint, Rect};
|
||||
use ratatui::style::{Color, Style};
|
||||
use ratatui::text::Text;
|
||||
use ratatui::widgets::Paragraph;
|
||||
use ratatui::Frame;
|
||||
|
||||
use crate::app::App;
|
||||
use crate::logos::RADARR_LOGO;
|
||||
@@ -48,7 +47,7 @@ impl DrawUi for RadarrUi {
|
||||
matches!(route, Route::Radarr(_, _))
|
||||
}
|
||||
|
||||
fn draw<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, area: Rect) {
|
||||
fn draw(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||
let (content_rect, _) = draw_tabs(f, area, "Movies", &app.data.radarr_data.main_tabs);
|
||||
let route = *app.get_current_route();
|
||||
|
||||
@@ -63,7 +62,7 @@ impl DrawUi for RadarrUi {
|
||||
}
|
||||
}
|
||||
|
||||
fn draw_context_row<B: Backend>(f: &mut Frame<'_, B>, app: &App<'_>, area: Rect) {
|
||||
fn draw_context_row(f: &mut Frame<'_>, app: &App<'_>, area: Rect) {
|
||||
let chunks = horizontal_chunks(vec![Constraint::Min(0), Constraint::Length(20)], area);
|
||||
|
||||
let context_chunks = horizontal_chunks(
|
||||
@@ -77,7 +76,7 @@ impl DrawUi for RadarrUi {
|
||||
}
|
||||
}
|
||||
|
||||
fn draw_stats_context<B: Backend>(f: &mut Frame<'_, B>, app: &App<'_>, area: Rect) {
|
||||
fn draw_stats_context(f: &mut Frame<'_>, app: &App<'_>, area: Rect) {
|
||||
let block = title_block("Stats");
|
||||
|
||||
if !app.data.radarr_data.version.is_empty() {
|
||||
@@ -169,7 +168,7 @@ fn draw_stats_context<B: Backend>(f: &mut Frame<'_, B>, app: &App<'_>, area: Rec
|
||||
}
|
||||
}
|
||||
|
||||
fn draw_downloads_context<B: Backend>(f: &mut Frame<'_, B>, app: &App<'_>, area: Rect) {
|
||||
fn draw_downloads_context(f: &mut Frame<'_>, app: &App<'_>, area: Rect) {
|
||||
let block = title_block("Downloads");
|
||||
let downloads_vec = &app.data.radarr_data.downloads.items;
|
||||
|
||||
@@ -224,7 +223,7 @@ fn determine_row_style(downloads_vec: &[DownloadRecord], movie: &Movie) -> Style
|
||||
}
|
||||
}
|
||||
|
||||
fn draw_radarr_logo<B: Backend>(f: &mut Frame<'_, B>, area: Rect) {
|
||||
fn draw_radarr_logo(f: &mut Frame<'_>, area: Rect) {
|
||||
let mut logo_text = Text::from(RADARR_LOGO);
|
||||
logo_text.patch_style(Style::default().fg(Color::LightYellow));
|
||||
let logo = Paragraph::new(logo_text)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::ui::utils::{style_default, style_failure, style_secondary};
|
||||
use tui::style::{Color, Modifier, Style};
|
||||
use ratatui::style::{Color, Modifier, Style};
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "radarr_ui_utils_tests.rs"]
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use tui::backend::Backend;
|
||||
use tui::layout::{Constraint, Rect};
|
||||
use tui::widgets::{Cell, Row};
|
||||
use tui::Frame;
|
||||
use ratatui::layout::{Constraint, Rect};
|
||||
use ratatui::widgets::{Cell, Row};
|
||||
use ratatui::Frame;
|
||||
|
||||
use crate::app::App;
|
||||
use crate::models::radarr_models::RootFolder;
|
||||
@@ -29,7 +28,7 @@ impl DrawUi for RootFoldersUi {
|
||||
false
|
||||
}
|
||||
|
||||
fn draw<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, content_rect: Rect) {
|
||||
fn draw(f: &mut Frame<'_>, app: &mut App<'_>, content_rect: Rect) {
|
||||
if let Route::Radarr(active_radarr_block, _) = *app.get_current_route() {
|
||||
match active_radarr_block {
|
||||
ActiveRadarrBlock::RootFolders => draw_root_folders(f, app, content_rect),
|
||||
@@ -55,7 +54,7 @@ impl DrawUi for RootFoldersUi {
|
||||
}
|
||||
}
|
||||
|
||||
fn draw_root_folders<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, area: Rect) {
|
||||
fn draw_root_folders(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||
draw_table(
|
||||
f,
|
||||
area,
|
||||
@@ -103,11 +102,7 @@ fn draw_root_folders<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, area:
|
||||
);
|
||||
}
|
||||
|
||||
fn draw_add_root_folder_prompt_box<B: Backend>(
|
||||
f: &mut Frame<'_, B>,
|
||||
app: &mut App<'_>,
|
||||
area: Rect,
|
||||
) {
|
||||
fn draw_add_root_folder_prompt_box(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||
draw_input_box_popup(
|
||||
f,
|
||||
area,
|
||||
@@ -116,11 +111,7 @@ fn draw_add_root_folder_prompt_box<B: Backend>(
|
||||
);
|
||||
}
|
||||
|
||||
fn draw_delete_root_folder_prompt<B: Backend>(
|
||||
f: &mut Frame<'_, B>,
|
||||
app: &mut App<'_>,
|
||||
prompt_area: Rect,
|
||||
) {
|
||||
fn draw_delete_root_folder_prompt(f: &mut Frame<'_>, app: &mut App<'_>, prompt_area: Rect) {
|
||||
draw_prompt_box(
|
||||
f,
|
||||
prompt_area,
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
use std::ops::Sub;
|
||||
|
||||
use chrono::Utc;
|
||||
use tui::layout::Alignment;
|
||||
use tui::text::{Span, Text};
|
||||
use tui::widgets::{Cell, Paragraph, Row};
|
||||
use tui::{
|
||||
backend::Backend,
|
||||
use ratatui::layout::Alignment;
|
||||
use ratatui::text::{Span, Text};
|
||||
use ratatui::widgets::{Cell, Paragraph, Row};
|
||||
use ratatui::{
|
||||
layout::{Constraint, Rect},
|
||||
widgets::ListItem,
|
||||
Frame,
|
||||
@@ -62,7 +61,7 @@ impl DrawUi for SystemUi {
|
||||
false
|
||||
}
|
||||
|
||||
fn draw<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, content_rect: Rect) {
|
||||
fn draw(f: &mut Frame<'_>, app: &mut App<'_>, content_rect: Rect) {
|
||||
let route = *app.get_current_route();
|
||||
|
||||
match route {
|
||||
@@ -75,11 +74,7 @@ impl DrawUi for SystemUi {
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn draw_system_ui_layout<B: Backend>(
|
||||
f: &mut Frame<'_, B>,
|
||||
app: &mut App<'_>,
|
||||
area: Rect,
|
||||
) {
|
||||
pub(super) fn draw_system_ui_layout(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||
let vertical_chunks = vertical_chunks(
|
||||
vec![
|
||||
Constraint::Ratio(1, 2),
|
||||
@@ -100,7 +95,7 @@ pub(super) fn draw_system_ui_layout<B: Backend>(
|
||||
draw_help(f, app, vertical_chunks[2]);
|
||||
}
|
||||
|
||||
fn draw_tasks<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, area: Rect) {
|
||||
fn draw_tasks(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||
draw_table(
|
||||
f,
|
||||
area,
|
||||
@@ -129,7 +124,7 @@ fn draw_tasks<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, area: Rect) {
|
||||
);
|
||||
}
|
||||
|
||||
pub(super) fn draw_queued_events<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, area: Rect) {
|
||||
pub(super) fn draw_queued_events(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||
draw_table(
|
||||
f,
|
||||
area,
|
||||
@@ -189,7 +184,7 @@ pub(super) fn draw_queued_events<B: Backend>(f: &mut Frame<'_, B>, app: &mut App
|
||||
);
|
||||
}
|
||||
|
||||
fn draw_logs<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, area: Rect) {
|
||||
fn draw_logs(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||
draw_list_box(
|
||||
f,
|
||||
area,
|
||||
@@ -210,7 +205,7 @@ fn draw_logs<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, area: Rect) {
|
||||
);
|
||||
}
|
||||
|
||||
fn draw_help<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, area: Rect) {
|
||||
fn draw_help(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||
let mut help_text = Text::from(format!(
|
||||
" {}",
|
||||
app
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
use tui::backend::Backend;
|
||||
use tui::layout::Rect;
|
||||
use tui::text::{Span, Text};
|
||||
use tui::widgets::{Cell, ListItem, Paragraph, Row};
|
||||
use tui::Frame;
|
||||
use ratatui::layout::Rect;
|
||||
use ratatui::text::{Span, Text};
|
||||
use ratatui::widgets::{Cell, ListItem, Paragraph, Row};
|
||||
use ratatui::Frame;
|
||||
|
||||
use crate::app::context_clues::{build_context_clue_string, BARE_POPUP_CONTEXT_CLUES};
|
||||
use crate::app::radarr::radarr_context_clues::SYSTEM_TASKS_CONTEXT_CLUES;
|
||||
@@ -35,7 +34,7 @@ impl DrawUi for SystemDetailsUi {
|
||||
false
|
||||
}
|
||||
|
||||
fn draw<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, content_rect: Rect) {
|
||||
fn draw(f: &mut Frame<'_>, app: &mut App<'_>, content_rect: Rect) {
|
||||
if let Route::Radarr(active_radarr_block, _) = *app.get_current_route() {
|
||||
match active_radarr_block {
|
||||
ActiveRadarrBlock::SystemLogs => {
|
||||
@@ -70,7 +69,7 @@ impl DrawUi for SystemDetailsUi {
|
||||
}
|
||||
}
|
||||
|
||||
fn draw_logs_popup<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, area: Rect) {
|
||||
fn draw_logs_popup(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||
draw_list_box(
|
||||
f,
|
||||
area,
|
||||
@@ -94,8 +93,8 @@ fn draw_logs_popup<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, area: Re
|
||||
);
|
||||
}
|
||||
|
||||
fn draw_tasks_popup<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, area: Rect) {
|
||||
let tasks_popup_table = |f: &mut Frame<'_, B>, app: &mut App<'_>, area: Rect| {
|
||||
fn draw_tasks_popup(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||
let tasks_popup_table = |f: &mut Frame<'_>, app: &mut App<'_>, area: Rect| {
|
||||
f.render_widget(title_block("Tasks"), area);
|
||||
|
||||
let context_area = draw_help_and_get_content_rect(
|
||||
@@ -142,7 +141,7 @@ fn draw_tasks_popup<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, area: R
|
||||
}
|
||||
}
|
||||
|
||||
fn draw_start_task_prompt<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, prompt_area: Rect) {
|
||||
fn draw_start_task_prompt(f: &mut Frame<'_>, app: &mut App<'_>, prompt_area: Rect) {
|
||||
draw_prompt_box(
|
||||
f,
|
||||
prompt_area,
|
||||
@@ -156,7 +155,7 @@ 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(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||
f.render_widget(title_block("Updates"), area);
|
||||
|
||||
let content_rect = draw_help_and_get_content_rect(
|
||||
|
||||
+6
-7
@@ -1,10 +1,9 @@
|
||||
use ratatui::layout::{Alignment, Constraint, Direction, Layout, Rect};
|
||||
use ratatui::style::{Color, Modifier, Style};
|
||||
use ratatui::text::{Line, Span, Text};
|
||||
use ratatui::widgets::{Block, BorderType, Borders, LineGauge, Paragraph, Wrap};
|
||||
use ratatui::{symbols, Frame};
|
||||
use std::rc::Rc;
|
||||
use tui::backend::Backend;
|
||||
use tui::layout::{Alignment, Constraint, Direction, Layout, Rect};
|
||||
use tui::style::{Color, Modifier, Style};
|
||||
use tui::text::{Line, Span, Text};
|
||||
use tui::widgets::{Block, BorderType, Borders, LineGauge, Paragraph, Wrap};
|
||||
use tui::{symbols, Frame};
|
||||
|
||||
pub const COLOR_TEAL: Color = Color::Rgb(35, 50, 55);
|
||||
pub const COLOR_CYAN: Color = Color::Cyan;
|
||||
@@ -268,7 +267,7 @@ pub fn line_gauge_with_label(title: &str, ratio: f64) -> LineGauge<'_> {
|
||||
.label(Line::from(format!("{title}: {:.0}%", ratio * 100.0)))
|
||||
}
|
||||
|
||||
pub fn show_cursor<B: Backend>(f: &mut Frame<'_, B>, area: Rect, offset: usize, string: &str) {
|
||||
pub fn show_cursor(f: &mut Frame<'_>, area: Rect, offset: usize, string: &str) {
|
||||
f.set_cursor(area.x + (string.len() - offset) as u16 + 1, area.y + 1);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use pretty_assertions::assert_eq;
|
||||
use tui::layout::{Alignment, Constraint, Direction, Layout, Rect};
|
||||
use tui::style::{Color, Modifier, Style};
|
||||
use tui::text::{Line, Span};
|
||||
use tui::widgets::{Block, BorderType, Borders};
|
||||
use ratatui::layout::{Alignment, Constraint, Direction, Layout, Rect};
|
||||
use ratatui::style::{Color, Modifier, Style};
|
||||
use ratatui::text::{Line, Span};
|
||||
use ratatui::widgets::{Block, BorderType, Borders};
|
||||
|
||||
use crate::ui::utils::{
|
||||
borderless_block, centered_rect, get_width_from_percentage, horizontal_chunks,
|
||||
|
||||
Reference in New Issue
Block a user