From 3f378fb25ac4777786f6f547bcbd59da77db3dc4 Mon Sep 17 00:00:00 2001 From: Dark-Alex-17 Date: Tue, 8 Aug 2023 10:50:04 -0600 Subject: [PATCH] Refactored things a bit and added help text support --- src/app/mod.rs | 17 +-- src/app/radarr.rs | 22 ++- src/handlers/mod.rs | 4 +- src/handlers/radarr_handler.rs | 2 +- src/main.rs | 2 +- src/{app/models.rs => models/mod.rs} | 15 +- src/models/radarr_models.rs | 201 ++++++++++++++++++++++++++ src/network/radarr_network.rs | 205 +-------------------------- src/network/utils.rs | 2 +- src/ui/mod.rs | 38 ++--- src/ui/radarr_ui.rs | 56 +++++--- 11 files changed, 307 insertions(+), 257 deletions(-) rename src/{app/models.rs => models/mod.rs} (93%) create mode 100644 src/models/radarr_models.rs diff --git a/src/app/mod.rs b/src/app/mod.rs index a102471..25d4414 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -7,26 +7,13 @@ use serde::{Deserialize, Serialize}; use tokio::sync::mpsc::Sender; use tokio::time::Instant; -use crate::app::models::{HorizontallyScrollableText, TabRoute, TabState}; use crate::app::radarr::{ActiveRadarrBlock, RadarrData}; +use crate::models::{HorizontallyScrollableText, Route, TabRoute, TabState}; use crate::network::NetworkEvent; pub(crate) mod key_binding; -pub mod models; pub mod radarr; -#[derive(Clone, PartialEq, Eq, Debug)] -pub enum Route { - Radarr(ActiveRadarrBlock), - Sonarr, -} - -impl From for Route { - fn from(active_radarr_block: ActiveRadarrBlock) -> Route { - Route::Radarr(active_radarr_block) - } -} - const DEFAULT_ROUTE: Route = Route::Radarr(ActiveRadarrBlock::Movies); pub struct App { @@ -130,10 +117,12 @@ impl Default for App { TabRoute { title: "Radarr".to_owned(), route: ActiveRadarrBlock::Movies.into(), + help: " change servarr | help | quit ".to_owned(), }, TabRoute { title: "Sonarr".to_owned(), route: Route::Sonarr, + help: " change servarr | help | quit ".to_owned(), }, ]), client: Client::new(), diff --git a/src/app/radarr.rs b/src/app/radarr.rs index 3b75542..c22ea89 100644 --- a/src/app/radarr.rs +++ b/src/app/radarr.rs @@ -4,12 +4,12 @@ use std::time::Duration; use chrono::{DateTime, Utc}; use strum::EnumIter; -use crate::app::models::{ScrollableText, StatefulTable, TabRoute, TabState}; -use crate::app::App; -use crate::network::radarr_network::{ +use crate::app::{App, Route}; +use crate::models::radarr_models::{ Collection, CollectionMovie, Credit, DiskSpace, DownloadRecord, Movie, MovieHistoryItem, - RadarrEvent, }; +use crate::models::{ScrollableText, StatefulTable, TabRoute, TabState}; +use crate::network::radarr_network::RadarrEvent; pub struct RadarrData { pub disk_space_vec: Vec, @@ -74,36 +74,44 @@ impl Default for RadarrData { TabRoute { title: "Library".to_owned(), route: ActiveRadarrBlock::Movies.into(), + help: "<↑↓> scroll table | movie details | ←→ change tab ".to_owned(), }, TabRoute { title: "Downloads".to_owned(), route: ActiveRadarrBlock::Downloads.into(), + help: "<↑↓> scroll table | ←→ change tab ".to_owned(), }, TabRoute { title: "Collections".to_owned(), route: ActiveRadarrBlock::Collections.into(), + help: "<↑↓> scroll table | collection details | ←→ change tab ".to_owned(), }, ]), movie_info_tabs: TabState::new(vec![ TabRoute { title: "Details".to_owned(), route: ActiveRadarrBlock::MovieDetails.into(), + help: "←→ change tab | close ".to_owned(), }, TabRoute { title: "History".to_owned(), route: ActiveRadarrBlock::MovieHistory.into(), + help: "<↑↓> scroll table | ←→ change tab | close ".to_owned(), }, TabRoute { title: "File".to_owned(), route: ActiveRadarrBlock::FileInfo.into(), + help: "←→ change tab | close ".to_owned(), }, TabRoute { title: "Cast".to_owned(), route: ActiveRadarrBlock::Cast.into(), + help: "<↑↓> scroll table | ←→ change tab | close ".to_owned(), }, TabRoute { title: "Crew".to_owned(), route: ActiveRadarrBlock::Crew.into(), + help: "<↑↓> scroll table | ←→ change tab | close ".to_owned(), }, ]), } @@ -131,6 +139,12 @@ pub enum ActiveRadarrBlock { ViewMovieOverview, } +impl From for Route { + fn from(active_radarr_block: ActiveRadarrBlock) -> Route { + Route::Radarr(active_radarr_block) + } +} + impl App { pub(super) async fn dispatch_by_radarr_block(&mut self, active_radarr_block: &ActiveRadarrBlock) { match active_radarr_block { diff --git a/src/handlers/mod.rs b/src/handlers/mod.rs index 27343fe..9c001c4 100644 --- a/src/handlers/mod.rs +++ b/src/handlers/mod.rs @@ -1,7 +1,7 @@ -use crate::app::models::HorizontallyScrollableText; -use crate::app::{App, Route}; +use crate::app::App; use crate::event::Key; use crate::handlers::radarr_handler::handle_radarr_key_events; +use crate::models::{HorizontallyScrollableText, Route}; mod radarr_handler; diff --git a/src/handlers/radarr_handler.rs b/src/handlers/radarr_handler.rs index f6433ff..65e7bbe 100644 --- a/src/handlers/radarr_handler.rs +++ b/src/handlers/radarr_handler.rs @@ -1,7 +1,7 @@ use crate::app::key_binding::DEFAULT_KEYBINDINGS; -use crate::app::models::Scrollable; use crate::app::radarr::ActiveRadarrBlock; use crate::handlers::handle_clear_errors; +use crate::models::Scrollable; use crate::{App, Key}; pub async fn handle_radarr_key_events( diff --git a/src/main.rs b/src/main.rs index 491f8b3..ffde32e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,7 +7,6 @@ use crossterm::execute; use crossterm::terminal::{ disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen, }; -use log::debug; use tokio::sync::mpsc::Receiver; use tokio::sync::{mpsc, Mutex}; use tui::backend::CrosstermBackend; @@ -23,6 +22,7 @@ mod app; mod event; mod handlers; mod logos; +mod models; mod network; mod ui; mod utils; diff --git a/src/app/models.rs b/src/models/mod.rs similarity index 93% rename from src/app/models.rs rename to src/models/mod.rs index f715134..ed9006a 100644 --- a/src/app/models.rs +++ b/src/models/mod.rs @@ -4,7 +4,15 @@ use std::fmt::{Display, Formatter}; use serde::Deserialize; use tui::widgets::TableState; -use crate::app::Route; +use crate::app::radarr::ActiveRadarrBlock; + +pub mod radarr_models; + +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum Route { + Radarr(ActiveRadarrBlock), + Sonarr, +} pub trait Scrollable { fn scroll_down(&mut self); @@ -161,6 +169,7 @@ impl HorizontallyScrollableText { pub struct TabRoute { pub title: String, pub route: Route, + pub help: String, } pub struct TabState { @@ -182,6 +191,10 @@ impl TabState { &self.tabs[self.index].route } + pub fn get_active_tab_help(&self) -> String { + self.tabs[self.index].help.clone() + } + pub fn next(&mut self) { self.index = (self.index + 1) % self.tabs.len(); } diff --git a/src/models/radarr_models.rs b/src/models/radarr_models.rs new file mode 100644 index 0000000..444bf46 --- /dev/null +++ b/src/models/radarr_models.rs @@ -0,0 +1,201 @@ +use chrono::{DateTime, Utc}; +use derivative::Derivative; +use serde::Deserialize; +use serde_json::Number; + +use crate::models::HorizontallyScrollableText; + +#[derive(Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct DiskSpace { + pub free_space: Number, + pub total_space: Number, +} + +#[derive(Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct SystemStatus { + pub version: String, + pub start_time: DateTime, +} + +#[derive(Derivative, Deserialize, Debug, Clone)] +#[derivative(Default)] +#[serde(rename_all = "camelCase")] +pub struct Movie { + #[derivative(Default(value = "Number::from(0)"))] + pub id: Number, + pub title: String, + pub original_language: Language, + #[derivative(Default(value = "Number::from(0)"))] + pub size_on_disk: Number, + pub status: String, + pub overview: String, + pub path: String, + pub studio: String, + pub genres: Vec, + #[derivative(Default(value = "Number::from(0)"))] + pub year: Number, + pub monitored: bool, + pub has_file: bool, + #[derivative(Default(value = "Number::from(0)"))] + pub runtime: Number, + #[derivative(Default(value = "Number::from(0)"))] + pub quality_profile_id: Number, + pub certification: Option, + pub ratings: RatingsList, + pub movie_file: Option, + pub collection: Option, +} + +#[derive(Derivative, Deserialize, Debug, Clone)] +#[derivative(Default)] +#[serde(rename_all = "camelCase")] +pub struct CollectionMovie { + pub title: String, + pub overview: String, + #[derivative(Default(value = "Number::from(0)"))] + pub year: Number, + #[derivative(Default(value = "Number::from(0)"))] + pub runtime: Number, + pub genres: Vec, + pub ratings: RatingsList, +} + +#[derive(Deserialize, Derivative, Clone, Debug)] +#[derivative(Default)] +#[serde(rename_all = "camelCase")] +pub struct Collection { + pub title: String, + pub root_folder_path: Option, + pub search_on_add: bool, + pub overview: Option, + #[derivative(Default(value = "Number::from(0)"))] + pub quality_profile_id: Number, + pub movies: Option>, +} + +#[derive(Deserialize, Derivative, Debug, Clone)] +#[derivative(Default)] +#[serde(rename_all = "camelCase")] +pub struct MovieFile { + pub relative_path: String, + pub path: String, + pub date_added: DateTime, + pub media_info: MediaInfo, +} + +#[derive(Deserialize, Derivative, Debug, Clone)] +#[derivative(Default)] +#[serde(rename_all = "camelCase")] +pub struct MediaInfo { + #[derivative(Default(value = "Number::from(0)"))] + pub audio_bitrate: Number, + #[derivative(Default(value = "Number::from(0)"))] + pub audio_channels: Number, + pub audio_codec: Option, + pub audio_languages: Option, + #[derivative(Default(value = "Number::from(0)"))] + pub audio_stream_count: Number, + #[derivative(Default(value = "Number::from(0)"))] + pub video_bit_depth: Number, + #[derivative(Default(value = "Number::from(0)"))] + pub video_bitrate: Number, + pub video_codec: String, + #[derivative(Default(value = "Number::from(0)"))] + pub video_fps: Number, + pub resolution: String, + pub run_time: String, + pub scan_type: String, +} + +#[derive(Default, Deserialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct RatingsList { + pub imdb: Option, + pub tmdb: Option, + pub rotten_tomatoes: Option, +} + +#[derive(Derivative, Deserialize, Debug, Clone)] +#[derivative(Default)] +pub struct Rating { + #[derivative(Default(value = "Number::from(0)"))] + pub value: Number, +} + +#[derive(Derivative, Deserialize, Debug)] +#[derivative(Default)] +#[serde(rename_all = "camelCase")] +pub struct DownloadsResponse { + pub records: Vec, +} + +#[derive(Derivative, Deserialize, Debug, Clone, PartialEq, Eq)] +#[derivative(Default)] +#[serde(rename_all = "camelCase")] +pub struct DownloadRecord { + pub title: String, + pub status: String, + #[derivative(Default(value = "Number::from(0)"))] + pub movie_id: Number, + #[derivative(Default(value = "Number::from(0)"))] + pub size: Number, + #[derivative(Default(value = "Number::from(0)"))] + pub sizeleft: Number, + pub output_path: HorizontallyScrollableText, + pub indexer: String, + pub download_client: String, +} + +#[derive(Derivative, Deserialize, Debug)] +#[derivative(Default)] +#[serde(rename_all = "camelCase")] +pub struct QualityProfile { + #[derivative(Default(value = "Number::from(0)"))] + pub id: Number, + pub name: String, +} + +#[derive(Deserialize, Default, Debug, Clone, PartialEq, Eq)] +#[serde(rename_all = "camelCase")] +pub struct MovieHistoryItem { + pub source_title: HorizontallyScrollableText, + pub quality: QualityHistory, + pub languages: Vec, + pub date: DateTime, + pub event_type: String, +} + +#[derive(Deserialize, Default, Debug, Clone, PartialEq, Eq)] +pub struct Language { + pub name: String, +} + +#[derive(Deserialize, Default, Debug, Clone, PartialEq, Eq)] +pub struct QualityHistory { + pub quality: Quality, +} + +#[derive(Deserialize, Default, Debug, Clone, PartialEq, Eq)] +pub struct Quality { + pub name: String, +} + +#[derive(Deserialize, PartialEq, Eq, Clone, Debug)] +#[serde(rename_all = "lowercase")] +pub enum CreditType { + Cast, + Crew, +} + +#[derive(Deserialize, Clone, Debug)] +#[serde(rename_all = "camelCase")] +pub struct Credit { + pub person_name: String, + pub character: Option, + pub department: Option, + pub job: Option, + #[serde(rename(deserialize = "type"))] + pub credit_type: CreditType, +} diff --git a/src/network/radarr_network.rs b/src/network/radarr_network.rs index 22b9682..e2862a5 100644 --- a/src/network/radarr_network.rs +++ b/src/network/radarr_network.rs @@ -1,16 +1,16 @@ use anyhow::anyhow; -use chrono::{DateTime, Utc}; -use derivative::Derivative; use indoc::formatdoc; use log::{debug, error}; use reqwest::RequestBuilder; use serde::de::DeserializeOwned; -use serde::Deserialize; -use serde_json::Number; use tokio::sync::MutexGuard; -use crate::app::models::{HorizontallyScrollableText, ScrollableText}; use crate::app::{App, RadarrConfig}; +use crate::models::radarr_models::{ + Collection, Credit, CreditType, DiskSpace, DownloadsResponse, Movie, MovieHistoryItem, + QualityProfile, SystemStatus, +}; +use crate::models::ScrollableText; use crate::network::utils::get_movie_status; use crate::network::{utils, Network, NetworkEvent}; use crate::utils::{convert_runtime, convert_to_gb}; @@ -51,201 +51,6 @@ impl From for NetworkEvent { } } -#[derive(Deserialize, Debug)] -#[serde(rename_all = "camelCase")] -pub struct DiskSpace { - pub free_space: Number, - pub total_space: Number, -} - -#[derive(Deserialize, Debug)] -#[serde(rename_all = "camelCase")] -struct SystemStatus { - version: String, - start_time: DateTime, -} - -#[derive(Derivative, Deserialize, Debug, Clone)] -#[derivative(Default)] -#[serde(rename_all = "camelCase")] -pub struct Movie { - #[derivative(Default(value = "Number::from(0)"))] - pub id: Number, - pub title: String, - pub original_language: Language, - #[derivative(Default(value = "Number::from(0)"))] - pub size_on_disk: Number, - pub status: String, - pub overview: String, - pub path: String, - pub studio: String, - pub genres: Vec, - #[derivative(Default(value = "Number::from(0)"))] - pub year: Number, - pub monitored: bool, - pub has_file: bool, - #[derivative(Default(value = "Number::from(0)"))] - pub runtime: Number, - #[derivative(Default(value = "Number::from(0)"))] - pub quality_profile_id: Number, - pub certification: Option, - pub ratings: RatingsList, - pub movie_file: Option, - pub collection: Option, -} - -#[derive(Derivative, Deserialize, Debug, Clone)] -#[derivative(Default)] -#[serde(rename_all = "camelCase")] -pub struct CollectionMovie { - pub title: String, - pub overview: String, - #[derivative(Default(value = "Number::from(0)"))] - pub year: Number, - #[derivative(Default(value = "Number::from(0)"))] - pub runtime: Number, - pub genres: Vec, - pub ratings: RatingsList, -} - -#[derive(Deserialize, Derivative, Clone, Debug)] -#[derivative(Default)] -#[serde(rename_all = "camelCase")] -pub struct Collection { - pub title: String, - pub root_folder_path: Option, - pub search_on_add: bool, - pub overview: Option, - #[derivative(Default(value = "Number::from(0)"))] - pub quality_profile_id: Number, - pub movies: Option>, -} - -#[derive(Deserialize, Derivative, Debug, Clone)] -#[derivative(Default)] -#[serde(rename_all = "camelCase")] -pub struct MovieFile { - pub relative_path: String, - pub path: String, - pub date_added: DateTime, - pub media_info: MediaInfo, -} - -#[derive(Deserialize, Derivative, Debug, Clone)] -#[derivative(Default)] -#[serde(rename_all = "camelCase")] -pub struct MediaInfo { - #[derivative(Default(value = "Number::from(0)"))] - pub audio_bitrate: Number, - #[derivative(Default(value = "Number::from(0)"))] - pub audio_channels: Number, - pub audio_codec: Option, - pub audio_languages: Option, - #[derivative(Default(value = "Number::from(0)"))] - pub audio_stream_count: Number, - #[derivative(Default(value = "Number::from(0)"))] - pub video_bit_depth: Number, - #[derivative(Default(value = "Number::from(0)"))] - pub video_bitrate: Number, - pub video_codec: String, - #[derivative(Default(value = "Number::from(0)"))] - pub video_fps: Number, - pub resolution: String, - pub run_time: String, - pub scan_type: String, -} - -#[derive(Default, Deserialize, Debug, Clone)] -#[serde(rename_all = "camelCase")] -pub struct RatingsList { - pub imdb: Option, - pub tmdb: Option, - pub rotten_tomatoes: Option, -} - -#[derive(Derivative, Deserialize, Debug, Clone)] -#[derivative(Default)] -pub struct Rating { - #[derivative(Default(value = "Number::from(0)"))] - pub value: Number, -} - -#[derive(Derivative, Deserialize, Debug)] -#[derivative(Default)] -#[serde(rename_all = "camelCase")] -pub struct DownloadsResponse { - pub records: Vec, -} - -#[derive(Derivative, Deserialize, Debug, Clone, PartialEq, Eq)] -#[derivative(Default)] -#[serde(rename_all = "camelCase")] -pub struct DownloadRecord { - pub title: String, - pub status: String, - #[derivative(Default(value = "Number::from(0)"))] - pub movie_id: Number, - #[derivative(Default(value = "Number::from(0)"))] - pub size: Number, - #[derivative(Default(value = "Number::from(0)"))] - pub sizeleft: Number, - pub output_path: HorizontallyScrollableText, - pub indexer: String, - pub download_client: String, -} - -#[derive(Derivative, Deserialize, Debug)] -#[derivative(Default)] -#[serde(rename_all = "camelCase")] -struct QualityProfile { - #[derivative(Default(value = "Number::from(0)"))] - pub id: Number, - pub name: String, -} - -#[derive(Deserialize, Default, Debug, Clone, PartialEq, Eq)] -#[serde(rename_all = "camelCase")] -pub struct MovieHistoryItem { - pub source_title: HorizontallyScrollableText, - pub quality: QualityHistory, - pub languages: Vec, - pub date: DateTime, - pub event_type: String, -} - -#[derive(Deserialize, Default, Debug, Clone, PartialEq, Eq)] -pub struct Language { - pub name: String, -} - -#[derive(Deserialize, Default, Debug, Clone, PartialEq, Eq)] -pub struct QualityHistory { - pub quality: Quality, -} - -#[derive(Deserialize, Default, Debug, Clone, PartialEq, Eq)] -pub struct Quality { - pub name: String, -} - -#[derive(Deserialize, PartialEq, Eq, Clone, Debug)] -#[serde(rename_all = "lowercase")] -pub enum CreditType { - Cast, - Crew, -} - -#[derive(Deserialize, Clone, Debug)] -#[serde(rename_all = "camelCase")] -pub struct Credit { - pub person_name: String, - pub character: Option, - pub department: Option, - pub job: Option, - #[serde(rename(deserialize = "type"))] - pub credit_type: CreditType, -} - impl<'a> Network<'a> { pub async fn handle_radarr_event(&self, radarr_event: RadarrEvent) { match radarr_event { diff --git a/src/network/utils.rs b/src/network/utils.rs index bf2a917..7e269f7 100644 --- a/src/network/utils.rs +++ b/src/network/utils.rs @@ -2,7 +2,7 @@ use reqwest::Response; use serde::de::DeserializeOwned; use serde_json::Number; -use crate::network::radarr_network::DownloadRecord; +use crate::models::radarr_models::DownloadRecord; pub async fn parse_response(response: Response) -> Result { response.json::().await diff --git a/src/ui/mod.rs b/src/ui/mod.rs index 2411a72..26206ea 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -1,4 +1,3 @@ -use log::debug; use tui::backend::Backend; use tui::layout::{Alignment, Constraint, Rect}; use tui::text::{Span, Spans, Text}; @@ -10,15 +9,12 @@ use tui::widgets::Tabs; use tui::widgets::{Block, Borders, Wrap}; use tui::Frame; -use crate::app::models::{StatefulTable, TabState}; -use crate::app::{App, Route}; -use crate::logos::{ - BAZARR_LOGO, LIDARR_LOGO, PROWLARR_LOGO, RADARR_LOGO, READARR_LOGO, SONARR_LOGO, -}; +use crate::app::App; +use crate::models::{Route, StatefulTable, TabState}; use crate::ui::utils::{ - centered_rect, horizontal_chunks_with_margin, layout_block_top_border, logo_block, - style_default_bold, style_failure, style_help, style_highlight, style_primary, style_secondary, - style_system_function, title_block, vertical_chunks_with_margin, + borderless_block, centered_rect, horizontal_chunks_with_margin, layout_block_top_border, + logo_block, style_default_bold, style_failure, style_help, style_highlight, style_primary, + style_secondary, style_system_function, title_block, vertical_chunks_with_margin, }; mod radarr_ui; @@ -65,6 +61,7 @@ pub fn ui(f: &mut Frame, app: &mut App) { fn draw_header_row(f: &mut Frame<'_, B>, 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()); let titles = app .server_tabs @@ -76,19 +73,17 @@ fn draw_header_row(f: &mut Frame<'_, B>, app: &mut App, area: Rect) .block(logo_block()) .highlight_style(style_secondary()) .select(app.server_tabs.index); - let help = Paragraph::new(Text::from( - "<↑↓> scroll | select | change servarr | help ", - )) - .block(Block::default()) - .style(style_help()) - .alignment(Alignment::Right); + let help = Paragraph::new(help_text) + .block(borderless_block()) + .style(style_help()) + .alignment(Alignment::Right); f.render_widget(tabs, area); f.render_widget(help, chunks[1]); } fn draw_error(f: &mut Frame<'_, B>, app: &mut App, area: Rect) { - let block = Block::default() + let block = borderless_block() .title("Error | to close") .style(style_failure()) .borders(Borders::ALL); @@ -169,7 +164,14 @@ fn draw_tabs<'a, B: Backend>( ) -> (Rect, Block<'a>) { let chunks = vertical_chunks_with_margin(vec![Constraint::Length(2), Constraint::Min(0)], area, 1); + let horizontal_chunks = horizontal_chunks_with_margin( + vec![Constraint::Percentage(10), Constraint::Min(0)], + area, + 1, + ); let block = title_block(title); + let mut help_text = Text::from(tab_state.get_active_tab_help()); + help_text.patch_style(style_help()); let titles = tab_state .tabs @@ -180,8 +182,12 @@ fn draw_tabs<'a, B: Backend>( .block(block) .highlight_style(style_secondary()) .select(tab_state.index); + let help = Paragraph::new(help_text) + .block(borderless_block()) + .alignment(Alignment::Right); f.render_widget(tabs, area); + f.render_widget(help, horizontal_chunks[1]); (chunks[1], layout_block_top_border()) } diff --git a/src/ui/radarr_ui.rs b/src/ui/radarr_ui.rs index bbb79aa..86d5296 100644 --- a/src/ui/radarr_ui.rs +++ b/src/ui/radarr_ui.rs @@ -10,14 +10,15 @@ use tui::widgets::{Block, Cell, Paragraph, Row, Wrap}; use tui::Frame; use crate::app::radarr::{ActiveRadarrBlock, RadarrData}; -use crate::app::{App, Route}; +use crate::app::App; use crate::logos::RADARR_LOGO; -use crate::network::radarr_network::{Credit, DiskSpace, DownloadRecord, Movie, MovieHistoryItem}; +use crate::models::radarr_models::{Credit, DiskSpace, DownloadRecord, Movie, MovieHistoryItem}; +use crate::models::Route; use crate::ui::utils::{ - borderless_block, horizontal_chunks, layout_block_bottom_border, layout_block_top_border, - layout_block_top_border_with_title, layout_block_with_title, line_gauge_with_label, - line_gauge_with_title, spans_info_default, spans_info_primary, spans_info_with_style, style_bold, - style_default, style_default_bold, style_failure, style_primary, style_success, style_warning, + borderless_block, horizontal_chunks, horizontal_chunks_with_margin, layout_block_bottom_border, + layout_block_top_border, layout_block_top_border_with_title, layout_block_with_title, + line_gauge_with_label, line_gauge_with_title, spans_info_default, spans_info_primary, style_bold, + style_default, style_failure, style_help, style_primary, style_success, style_warning, title_block, title_style, vertical_chunks, vertical_chunks_with_margin, }; use crate::ui::{ @@ -250,7 +251,11 @@ fn draw_collections(f: &mut Frame<'_, B>, app: &mut App, area: Rect) fn draw_collection_details(f: &mut Frame<'_, B>, app: &mut App, content_area: Rect) { let chunks = vertical_chunks_with_margin( - vec![Constraint::Length(10), Constraint::Min(0)], + vec![ + Constraint::Percentage(20), + Constraint::Percentage(75), + Constraint::Percentage(5), + ], content_area, 1, ); @@ -262,6 +267,8 @@ fn draw_collection_details(f: &mut Frame<'_, B>, app: &mut App, cont .get(&collection_selection.quality_profile_id.as_u64().unwrap()) .unwrap() .to_owned(); + let mut help_text = Text::from("<↑↓> scroll table | show overview | close"); + help_text.patch_style(style_help()); let collection_description = Text::from(vec![ spans_info_primary( @@ -285,13 +292,14 @@ fn draw_collection_details(f: &mut Frame<'_, B>, app: &mut App, cont let description_paragraph = Paragraph::new(collection_description) .block(borderless_block()) .wrap(Wrap { trim: false }); + let help_paragraph = Paragraph::new(help_text) + .block(borderless_block()) + .alignment(Alignment::Center); - f.render_widget( - layout_block_with_title(title_style(&collection_selection.title)), - content_area, - ); + f.render_widget(title_block(&collection_selection.title), content_area); f.render_widget(description_paragraph, chunks[0]); + f.render_widget(help_paragraph, chunks[2]); draw_table( f, @@ -400,6 +408,14 @@ fn draw_movie_info(f: &mut Frame<'_, B>, app: &mut App, area: Rect) } fn draw_movie_overview(f: &mut Frame<'_, B>, app: &mut App, content_area: Rect) { + let title_block = title_block("Overview"); + f.render_widget(title_block, content_area); + + let chunks = vertical_chunks_with_margin( + vec![Constraint::Percentage(95), Constraint::Percentage(5)], + content_area, + 1, + ); let mut overview = Text::from( app .data @@ -409,12 +425,18 @@ fn draw_movie_overview(f: &mut Frame<'_, B>, app: &mut App, content_ .overview, ); overview.patch_style(style_default()); + let mut help_text = Text::from(" close"); + help_text.patch_style(style_help()); let paragraph = Paragraph::new(overview) - .block(layout_block_with_title(title_style("Overview"))) + .block(borderless_block()) .wrap(Wrap { trim: false }); + let help_paragraph = Paragraph::new(help_text) + .block(borderless_block()) + .alignment(Alignment::Center); - f.render_widget(paragraph, content_area); + f.render_widget(paragraph, chunks[0]); + f.render_widget(help_paragraph, chunks[1]); } fn draw_movie_details( @@ -678,7 +700,7 @@ fn draw_stats_context(f: &mut Frame<'_, B>, app: &App, area: Rect) { "Radarr Version: {}", app.data.radarr_data.version ))) - .block(Block::default()); + .block(borderless_block()); let uptime = Utc::now().sub(start_time.to_owned()); let days = uptime.num_days(); @@ -698,15 +720,15 @@ fn draw_stats_context(f: &mut Frame<'_, B>, app: &App, area: Rect) { seconds, width = 2 ))) - .block(Block::default()); + .block(borderless_block()); let mut logo_text = Text::from(RADARR_LOGO); logo_text.patch_style(Style::default().fg(Color::LightYellow)); let logo = Paragraph::new(logo_text) - .block(Block::default()) + .block(borderless_block()) .alignment(Alignment::Center); let storage = - Paragraph::new(Text::from("Storage:")).block(Block::default().style(style_bold())); + Paragraph::new(Text::from("Storage:")).block(borderless_block().style(style_bold())); f.render_widget(logo, chunks[0]); f.render_widget(version_paragraph, chunks[1]);