build: Upgraded to Ratatui v0.30.0 and fixed a new security vulnerability [#13]

This commit is contained in:
2026-01-07 17:15:54 -07:00
parent 243de47cae
commit f0ed71b436
43 changed files with 1532 additions and 828 deletions
Generated
+1037 -397
View File
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -42,7 +42,7 @@ strum = { version = "0.26.3", features = ["derive"] }
strum_macros = "0.26.4" strum_macros = "0.26.4"
tokio = { version = "1.44.2", features = ["full"] } tokio = { version = "1.44.2", features = ["full"] }
tokio-util = "0.7.8" tokio-util = "0.7.8"
ratatui = { version = "0.29.0", features = [ ratatui = { version = "0.30.0", features = [
"all-widgets", "all-widgets",
"unstable-widget-ref", "unstable-widget-ref",
] } ] }
@@ -59,7 +59,7 @@ ctrlc = "3.4.5"
colored = "3.0.0" colored = "3.0.0"
async-trait = "0.1.83" async-trait = "0.1.83"
dirs-next = "2.0.0" dirs-next = "2.0.0"
managarr-tree-widget = "0.24.0" managarr-tree-widget = "0.25.0"
indicatif = "0.17.9" indicatif = "0.17.9"
derive_setters = "0.1.6" derive_setters = "0.1.6"
deunicode = "1.6.0" deunicode = "1.6.0"
+3 -3
View File
@@ -109,14 +109,14 @@ fn draw_add_artist_search(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
.block(title_block_centered("Add Artist")); .block(title_block_centered("Add Artist"));
search_box.show_cursor(f, search_box_area); search_box.show_cursor(f, search_box_area);
f.render_widget(layout_block().default(), results_area); f.render_widget(layout_block().default_color(), results_area);
f.render_widget(search_box, search_box_area); f.render_widget(search_box, search_box_area);
} }
ActiveLidarrBlock::AddArtistEmptySearchResults => { ActiveLidarrBlock::AddArtistEmptySearchResults => {
let error_message = Message::new("No artists found matching your query!"); let error_message = Message::new("No artists found matching your query!");
let error_message_popup = Popup::new(error_message).size(Size::Message); let error_message_popup = Popup::new(error_message).size(Size::Message);
f.render_widget(layout_block().default(), results_area); f.render_widget(layout_block().default_color(), results_area);
f.render_widget(error_message_popup, f.area()); f.render_widget(error_message_popup, f.area());
} }
ActiveLidarrBlock::AddArtistSearchResults => { ActiveLidarrBlock::AddArtistSearchResults => {
@@ -125,7 +125,7 @@ fn draw_add_artist_search(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
search_results_row_mapping, search_results_row_mapping,
) )
.loading(is_loading) .loading(is_loading)
.block(layout_block().default()) .block(layout_block().default_color())
.headers(["", "Name", "Type", "Status", "Rating", "Genres"]) .headers(["", "Name", "Type", "Status", "Rating", "Genres"])
.constraints([ .constraints([
Constraint::Percentage(3), Constraint::Percentage(3),
+5 -6
View File
@@ -11,7 +11,6 @@ use crate::models::servarr_data::lidarr::lidarr_data::{ActiveLidarrBlock, EDIT_A
use crate::models::servarr_data::lidarr::modals::EditArtistModal; use crate::models::servarr_data::lidarr::modals::EditArtistModal;
use crate::render_selectable_input_box; use crate::render_selectable_input_box;
use crate::ui::styles::ManagarrStyle;
use crate::ui::utils::title_block_centered; use crate::ui::utils::title_block_centered;
use crate::ui::widgets::button::Button; use crate::ui::widgets::button::Button;
use crate::ui::widgets::checkbox::Checkbox; use crate::ui::widgets::checkbox::Checkbox;
@@ -120,17 +119,17 @@ fn draw_edit_artist_confirmation_prompt(f: &mut Frame<'_>, app: &mut App<'_>, ar
let monitored_checkbox = Checkbox::new("Monitored") let monitored_checkbox = Checkbox::new("Monitored")
.checked(monitored.unwrap_or_default()) .checked(monitored.unwrap_or_default())
.highlighted(selected_block == ActiveLidarrBlock::EditArtistToggleMonitored); .highlighted(selected_block == ActiveLidarrBlock::EditArtistToggleMonitored);
let monitor_new_items_drop_down_button = Button::new() let monitor_new_items_drop_down_button = Button::default()
.title(selected_monitor_new_items.to_display_str()) .title(selected_monitor_new_items.to_display_str())
.label("Monitor New Albums") .label("Monitor New Albums")
.icon("") .icon("")
.selected(selected_block == ActiveLidarrBlock::EditArtistSelectMonitorNewItems); .selected(selected_block == ActiveLidarrBlock::EditArtistSelectMonitorNewItems);
let quality_profile_drop_down_button = Button::new() let quality_profile_drop_down_button = Button::default()
.title(selected_quality_profile) .title(selected_quality_profile)
.label("Quality Profile") .label("Quality Profile")
.icon("") .icon("")
.selected(selected_block == ActiveLidarrBlock::EditArtistSelectQualityProfile); .selected(selected_block == ActiveLidarrBlock::EditArtistSelectQualityProfile);
let metadata_profile_drop_down_button = Button::new() let metadata_profile_drop_down_button = Button::default()
.title(selected_metadata_profile) .title(selected_metadata_profile)
.label("Metadata Profile") .label("Metadata Profile")
.icon("") .icon("")
@@ -158,10 +157,10 @@ fn draw_edit_artist_confirmation_prompt(f: &mut Frame<'_>, app: &mut App<'_>, ar
render_selectable_input_box!(tags_input_box, f, tags_area); render_selectable_input_box!(tags_input_box, f, tags_area);
} }
let save_button = Button::new() let save_button = Button::default()
.title("Save") .title("Save")
.selected(yes_no_value && highlight_yes_no); .selected(yes_no_value && highlight_yes_no);
let cancel_button = Button::new() let cancel_button = Button::default()
.title("Cancel") .title("Cancel")
.selected(!yes_no_value && highlight_yes_no); .selected(!yes_no_value && highlight_yes_no);
+2 -2
View File
@@ -154,7 +154,7 @@ fn draw_stats_context(f: &mut Frame<'_>, app: &App<'_>, area: Rect) {
let space: f64 = convert_to_gb(*free_space); let space: f64 = convert_to_gb(*free_space);
let root_folder_space = Paragraph::new(format!("{path}: {space:.2} GB free")) let root_folder_space = Paragraph::new(format!("{path}: {space:.2} GB free"))
.block(borderless_block()) .block(borderless_block())
.default(); .default_color();
f.render_widget( f.render_widget(
root_folder_space, root_folder_space,
@@ -205,7 +205,7 @@ fn draw_lidarr_logo(f: &mut Frame<'_>, area: Rect) {
let logo_text = Text::from(LIDARR_LOGO); let logo_text = Text::from(LIDARR_LOGO);
let logo = Paragraph::new(logo_text) let logo = Paragraph::new(logo_text)
.light_green() .light_green()
.block(layout_block().default()) .block(layout_block().default_color())
.centered(); .centered();
f.render_widget(logo, area); f.render_widget(logo, area);
} }
+5 -5
View File
@@ -4,7 +4,7 @@ use std::sync::atomic::Ordering;
use lidarr_ui::LidarrUi; use lidarr_ui::LidarrUi;
use ratatui::Frame; use ratatui::Frame;
use ratatui::layout::{Constraint, Flex, Layout, Rect}; use ratatui::layout::{Constraint, Flex, Layout, Rect};
use ratatui::style::{Style, Stylize}; use ratatui::style::Stylize;
use ratatui::text::{Line, Text}; use ratatui::text::{Line, Text};
use ratatui::widgets::Paragraph; use ratatui::widgets::Paragraph;
use ratatui::widgets::Tabs; use ratatui::widgets::Tabs;
@@ -17,7 +17,7 @@ use crate::app::App;
use crate::models::servarr_models::KeybindingItem; use crate::models::servarr_models::KeybindingItem;
use crate::models::{HorizontallyScrollableText, Route, TabState}; use crate::models::{HorizontallyScrollableText, Route, TabState};
use crate::ui::radarr_ui::RadarrUi; use crate::ui::radarr_ui::RadarrUi;
use crate::ui::styles::ManagarrStyle; use crate::ui::styles::{ManagarrStyle, secondary_style};
use crate::ui::theme::Theme; use crate::ui::theme::Theme;
use crate::ui::utils::{ use crate::ui::utils::{
background_block, borderless_block, centered_rect, logo_block, title_block, title_block_centered, background_block, borderless_block, centered_rect, logo_block, title_block, title_block_centered,
@@ -116,7 +116,7 @@ fn draw_header_row(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
.map(|tab| Line::from(tab.title.clone().bold())); .map(|tab| Line::from(tab.title.clone().bold()));
let tabs = Tabs::new(titles) let tabs = Tabs::new(titles)
.block(borderless_block()) .block(borderless_block())
.highlight_style(Style::new().secondary()) .highlight_style(secondary_style())
.select(app.server_tabs.index); .select(app.server_tabs.index);
let help = Paragraph::new(help_text) let help = Paragraph::new(help_text)
.block(borderless_block()) .block(borderless_block())
@@ -185,7 +185,7 @@ pub fn draw_help_popup(f: &mut Frame<'_>, app: &mut App<'_>) {
fn draw_tabs(f: &mut Frame<'_>, area: Rect, title: &str, tab_state: &TabState) -> Rect { fn draw_tabs(f: &mut Frame<'_>, area: Rect, title: &str, tab_state: &TabState) -> Rect {
if title.is_empty() { if title.is_empty() {
f.render_widget(layout_block().default(), area); f.render_widget(layout_block().default_color(), area);
} else { } else {
f.render_widget(title_block(title), area); f.render_widget(title_block(title), area);
} }
@@ -200,7 +200,7 @@ fn draw_tabs(f: &mut Frame<'_>, area: Rect, title: &str, tab_state: &TabState) -
.map(|tab_route| Line::from(tab_route.title.clone().bold())); .map(|tab_route| Line::from(tab_route.title.clone().bold()));
let tabs = Tabs::new(titles) let tabs = Tabs::new(titles)
.block(borderless_block()) .block(borderless_block())
.highlight_style(Style::new().secondary()) .highlight_style(secondary_style())
.select(tab_state.index); .select(tab_state.index);
f.render_widget(tabs, header_area); f.render_widget(tabs, header_area);
+3 -3
View File
@@ -3,7 +3,7 @@ use crate::models::Route;
use crate::models::radarr_models::BlocklistItem; use crate::models::radarr_models::BlocklistItem;
use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, BLOCKLIST_BLOCKS}; use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, BLOCKLIST_BLOCKS};
use crate::ui::DrawUi; use crate::ui::DrawUi;
use crate::ui::styles::ManagarrStyle; use crate::ui::styles::{ManagarrStyle, secondary_style};
use crate::ui::utils::{get_width_from_percentage, layout_block_top_border}; use crate::ui::utils::{get_width_from_percentage, layout_block_top_border};
use crate::ui::widgets::confirmation_prompt::ConfirmationPrompt; use crate::ui::widgets::confirmation_prompt::ConfirmationPrompt;
use crate::ui::widgets::managarr_table::ManagarrTable; use crate::ui::widgets::managarr_table::ManagarrTable;
@@ -11,7 +11,7 @@ use crate::ui::widgets::message::Message;
use crate::ui::widgets::popup::{Popup, Size}; use crate::ui::widgets::popup::{Popup, Size};
use ratatui::Frame; use ratatui::Frame;
use ratatui::layout::{Alignment, Constraint, Rect}; use ratatui::layout::{Alignment, Constraint, Rect};
use ratatui::style::{Style, Stylize}; use ratatui::style::Stylize;
use ratatui::text::{Line, Text}; use ratatui::text::{Line, Text};
use ratatui::widgets::{Cell, Row}; use ratatui::widgets::{Cell, Row};
@@ -186,7 +186,7 @@ fn draw_blocklist_item_details_popup(f: &mut Frame<'_>, app: &mut App<'_>) {
let message = Message::new(text) let message = Message::new(text)
.title("Details") .title("Details")
.style(Style::new().secondary()) .style(secondary_style())
.alignment(Alignment::Left); .alignment(Alignment::Left);
f.render_widget(Popup::new(message).size(Size::NarrowMessage), f.area()); f.render_widget(Popup::new(message).size(Size::NarrowMessage), f.area());
@@ -150,7 +150,7 @@ pub fn draw_collection_details(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect)
.overview .overview
.clone() .clone()
.unwrap_or_default() .unwrap_or_default()
.default(), .default_color(),
]), ]),
Line::from(vec![ Line::from(vec![
"Root Folder Path: ".primary().bold(), "Root Folder Path: ".primary().bold(),
@@ -158,20 +158,23 @@ pub fn draw_collection_details(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect)
.root_folder_path .root_folder_path
.clone() .clone()
.unwrap_or_default() .unwrap_or_default()
.default(), .default_color(),
]), ]),
Line::from(vec![ Line::from(vec![
"Quality Profile: ".primary().bold(), "Quality Profile: ".primary().bold(),
quality_profile.default(), quality_profile.default_color(),
]), ]),
Line::from(vec![ Line::from(vec![
"Minimum Availability: ".primary().bold(), "Minimum Availability: ".primary().bold(),
minimum_availability.default(), minimum_availability.default_color(),
]),
Line::from(vec![
"Monitored: ".primary().bold(),
monitored.default_color(),
]), ]),
Line::from(vec!["Monitored: ".primary().bold(), monitored.default()]),
Line::from(vec![ Line::from(vec![
"Search on Add: ".primary().bold(), "Search on Add: ".primary().bold(),
search_on_add.default(), search_on_add.default_color(),
]), ]),
]); ]);
@@ -225,7 +228,7 @@ fn draw_movie_overview(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
.clone() .clone()
.overview, .overview,
) )
.default(); .default_color();
let paragraph = Paragraph::new(overview) let paragraph = Paragraph::new(overview)
.block(borderless_block()) .block(borderless_block())
@@ -11,7 +11,6 @@ use crate::models::servarr_data::radarr::radarr_data::{
}; };
use crate::render_selectable_input_box; use crate::render_selectable_input_box;
use crate::ui::radarr_ui::collections::collection_details_ui::CollectionDetailsUi; use crate::ui::radarr_ui::collections::collection_details_ui::CollectionDetailsUi;
use crate::ui::styles::ManagarrStyle;
use crate::ui::utils::{layout_paragraph_borderless, title_block_centered}; use crate::ui::utils::{layout_paragraph_borderless, title_block_centered};
use crate::ui::widgets::button::Button; use crate::ui::widgets::button::Button;
use crate::ui::widgets::checkbox::Checkbox; use crate::ui::widgets::checkbox::Checkbox;
@@ -129,12 +128,12 @@ fn draw_edit_collection_confirmation_prompt(f: &mut Frame<'_>, app: &mut App<'_>
let monitored_checkbox = Checkbox::new("Monitored") let monitored_checkbox = Checkbox::new("Monitored")
.highlighted(selected_block == ActiveRadarrBlock::EditCollectionToggleMonitored) .highlighted(selected_block == ActiveRadarrBlock::EditCollectionToggleMonitored)
.checked(monitored.unwrap_or_default()); .checked(monitored.unwrap_or_default());
let min_availability_drop_down_button = Button::new() let min_availability_drop_down_button = Button::default()
.title(selected_minimum_availability.to_display_str()) .title(selected_minimum_availability.to_display_str())
.label("Minimum Availability") .label("Minimum Availability")
.icon("") .icon("")
.selected(selected_block == ActiveRadarrBlock::EditCollectionSelectMinimumAvailability); .selected(selected_block == ActiveRadarrBlock::EditCollectionSelectMinimumAvailability);
let quality_profile_drop_down_button = Button::new() let quality_profile_drop_down_button = Button::default()
.title(selected_quality_profile) .title(selected_quality_profile)
.label("Quality Profile") .label("Quality Profile")
.icon("") .icon("")
@@ -152,10 +151,10 @@ fn draw_edit_collection_confirmation_prompt(f: &mut Frame<'_>, app: &mut App<'_>
let search_on_add_checkbox = Checkbox::new("Search on Add") let search_on_add_checkbox = Checkbox::new("Search on Add")
.highlighted(selected_block == ActiveRadarrBlock::EditCollectionToggleSearchOnAdd) .highlighted(selected_block == ActiveRadarrBlock::EditCollectionToggleSearchOnAdd)
.checked(search_on_add.unwrap_or_default()); .checked(search_on_add.unwrap_or_default());
let save_button = Button::new() let save_button = Button::default()
.title("Save") .title("Save")
.selected(yes_no_value && highlight_yes_no); .selected(yes_no_value && highlight_yes_no);
let cancel_button = Button::new() let cancel_button = Button::default()
.title("Cancel") .title("Cancel")
.selected(!yes_no_value && highlight_yes_no); .selected(!yes_no_value && highlight_yes_no);
+2 -3
View File
@@ -4,7 +4,6 @@ use crate::app::App;
use crate::models::Route; use crate::models::Route;
use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, EDIT_INDEXER_BLOCKS}; use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, EDIT_INDEXER_BLOCKS};
use crate::render_selectable_input_box; use crate::render_selectable_input_box;
use crate::ui::styles::ManagarrStyle;
use crate::ui::utils::title_block_centered; use crate::ui::utils::title_block_centered;
use crate::ui::widgets::button::Button; use crate::ui::widgets::button::Button;
use crate::ui::widgets::checkbox::Checkbox; use crate::ui::widgets::checkbox::Checkbox;
@@ -152,10 +151,10 @@ fn draw_edit_indexer_prompt(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
.flex(Flex::Center) .flex(Flex::Center)
.areas(buttons_area); .areas(buttons_area);
let save_button = Button::new() let save_button = Button::default()
.title("Save") .title("Save")
.selected(yes_no_value && highlight_yes_no); .selected(yes_no_value && highlight_yes_no);
let cancel_button = Button::new() let cancel_button = Button::default()
.title("Cancel") .title("Cancel")
.selected(!yes_no_value && highlight_yes_no); .selected(!yes_no_value && highlight_yes_no);
@@ -9,7 +9,6 @@ use crate::models::servarr_data::radarr::radarr_data::{
ActiveRadarrBlock, INDEXER_SETTINGS_BLOCKS, ActiveRadarrBlock, INDEXER_SETTINGS_BLOCKS,
}; };
use crate::render_selectable_input_box; use crate::render_selectable_input_box;
use crate::ui::styles::ManagarrStyle;
use crate::ui::utils::title_block_centered; use crate::ui::utils::title_block_centered;
use crate::ui::widgets::button::Button; use crate::ui::widgets::button::Button;
use crate::ui::widgets::checkbox::Checkbox; use crate::ui::widgets::checkbox::Checkbox;
@@ -154,10 +153,10 @@ fn draw_edit_indexer_settings_prompt(f: &mut Frame<'_>, app: &mut App<'_>, area:
.flex(Flex::Center) .flex(Flex::Center)
.areas(buttons_area); .areas(buttons_area);
let save_button = Button::new() let save_button = Button::default()
.title("Save") .title("Save")
.selected(yes_no_value && highlight_yes_no); .selected(yes_no_value && highlight_yes_no);
let cancel_button = Button::new() let cancel_button = Button::default()
.title("Cancel") .title("Cancel")
.selected(!yes_no_value && highlight_yes_no); .selected(!yes_no_value && highlight_yes_no);
+2 -2
View File
@@ -1,6 +1,6 @@
use crate::ui::styles::success_style;
use ratatui::Frame; use ratatui::Frame;
use ratatui::layout::{Constraint, Rect}; use ratatui::layout::{Constraint, Rect};
use ratatui::style::{Style, Stylize};
use ratatui::text::Text; use ratatui::text::Text;
use ratatui::widgets::{Cell, Row}; use ratatui::widgets::{Cell, Row};
@@ -73,7 +73,7 @@ impl DrawUi for IndexersUi {
} else { } else {
let message = Message::new("Indexer test succeeded!") let message = Message::new("Indexer test succeeded!")
.title("Success") .title("Success")
.style(Style::new().success().bold()); .style(success_style().bold());
Popup::new(message).size(Size::Message) Popup::new(message).size(Size::Message)
} }
}; };
+9 -9
View File
@@ -164,14 +164,14 @@ fn draw_add_movie_search(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
.block(title_block_centered("Add Movie")); .block(title_block_centered("Add Movie"));
search_box.show_cursor(f, search_box_area); search_box.show_cursor(f, search_box_area);
f.render_widget(layout_block().default(), results_area); f.render_widget(layout_block().default_color(), results_area);
f.render_widget(search_box, search_box_area); f.render_widget(search_box, search_box_area);
} }
ActiveRadarrBlock::AddMovieEmptySearchResults => { ActiveRadarrBlock::AddMovieEmptySearchResults => {
let error_message = Message::new("No movies found matching your query!"); let error_message = Message::new("No movies found matching your query!");
let error_message_popup = Popup::new(error_message).size(Size::Message); let error_message_popup = Popup::new(error_message).size(Size::Message);
f.render_widget(layout_block().default(), results_area); f.render_widget(layout_block().default_color(), results_area);
f.render_widget(error_message_popup, f.area()); f.render_widget(error_message_popup, f.area());
} }
ActiveRadarrBlock::AddMovieSearchResults ActiveRadarrBlock::AddMovieSearchResults
@@ -187,7 +187,7 @@ fn draw_add_movie_search(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
search_results_row_mapping, search_results_row_mapping,
) )
.loading(is_loading) .loading(is_loading)
.block(layout_block().default()) .block(layout_block().default_color())
.headers([ .headers([
"", "",
"Title", "Title",
@@ -338,22 +338,22 @@ fn draw_confirmation_prompt(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
Layout::horizontal([Constraint::Percentage(50), Constraint::Percentage(50)]) Layout::horizontal([Constraint::Percentage(50), Constraint::Percentage(50)])
.areas(buttons_area); .areas(buttons_area);
let root_folder_drop_down_button = Button::new() let root_folder_drop_down_button = Button::default()
.title(&selected_root_folder.path) .title(&selected_root_folder.path)
.label("Root Folder") .label("Root Folder")
.icon("") .icon("")
.selected(selected_block == ActiveRadarrBlock::AddMovieSelectRootFolder); .selected(selected_block == ActiveRadarrBlock::AddMovieSelectRootFolder);
let monitor_drop_down_button = Button::new() let monitor_drop_down_button = Button::default()
.title(selected_monitor.to_display_str()) .title(selected_monitor.to_display_str())
.label("Monitor") .label("Monitor")
.icon("") .icon("")
.selected(selected_block == ActiveRadarrBlock::AddMovieSelectMonitor); .selected(selected_block == ActiveRadarrBlock::AddMovieSelectMonitor);
let min_availability_drop_down_button = Button::new() let min_availability_drop_down_button = Button::default()
.title(selected_minimum_availability.to_display_str()) .title(selected_minimum_availability.to_display_str())
.label("Minimum Availability") .label("Minimum Availability")
.icon("") .icon("")
.selected(selected_block == ActiveRadarrBlock::AddMovieSelectMinimumAvailability); .selected(selected_block == ActiveRadarrBlock::AddMovieSelectMinimumAvailability);
let quality_profile_drop_down_button = Button::new() let quality_profile_drop_down_button = Button::default()
.title(selected_quality_profile) .title(selected_quality_profile)
.label("Quality Profile") .label("Quality Profile")
.icon("") .icon("")
@@ -373,10 +373,10 @@ fn draw_confirmation_prompt(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
render_selectable_input_box!(tags_input_box, f, tags_area); render_selectable_input_box!(tags_input_box, f, tags_area);
} }
let add_button = Button::new() let add_button = Button::default()
.title("Add") .title("Add")
.selected(yes_no_value && highlight_yes_no); .selected(yes_no_value && highlight_yes_no);
let cancel_button = Button::new() let cancel_button = Button::default()
.title("Cancel") .title("Cancel")
.selected(!yes_no_value && highlight_yes_no); .selected(!yes_no_value && highlight_yes_no);
+4 -5
View File
@@ -14,7 +14,6 @@ use crate::models::servarr_data::radarr::radarr_data::{
use crate::render_selectable_input_box; use crate::render_selectable_input_box;
use crate::ui::radarr_ui::library::movie_details_ui::MovieDetailsUi; use crate::ui::radarr_ui::library::movie_details_ui::MovieDetailsUi;
use crate::ui::styles::ManagarrStyle;
use crate::ui::utils::{layout_paragraph_borderless, title_block_centered}; use crate::ui::utils::{layout_paragraph_borderless, title_block_centered};
use crate::ui::widgets::button::Button; use crate::ui::widgets::button::Button;
use crate::ui::widgets::checkbox::Checkbox; use crate::ui::widgets::checkbox::Checkbox;
@@ -125,12 +124,12 @@ fn draw_edit_movie_confirmation_prompt(f: &mut Frame<'_>, app: &mut App<'_>, are
let monitored_checkbox = Checkbox::new("Monitored") let monitored_checkbox = Checkbox::new("Monitored")
.checked(monitored.unwrap_or_default()) .checked(monitored.unwrap_or_default())
.highlighted(selected_block == ActiveRadarrBlock::EditMovieToggleMonitored); .highlighted(selected_block == ActiveRadarrBlock::EditMovieToggleMonitored);
let min_availability_drop_down_button = Button::new() let min_availability_drop_down_button = Button::default()
.title(selected_minimum_availability.to_display_str()) .title(selected_minimum_availability.to_display_str())
.label("Minimum Availability") .label("Minimum Availability")
.icon("") .icon("")
.selected(selected_block == ActiveRadarrBlock::EditMovieSelectMinimumAvailability); .selected(selected_block == ActiveRadarrBlock::EditMovieSelectMinimumAvailability);
let quality_profile_drop_down_button = Button::new() let quality_profile_drop_down_button = Button::default()
.title(selected_quality_profile) .title(selected_quality_profile)
.label("Quality Profile") .label("Quality Profile")
.icon("") .icon("")
@@ -158,10 +157,10 @@ fn draw_edit_movie_confirmation_prompt(f: &mut Frame<'_>, app: &mut App<'_>, are
render_selectable_input_box!(tags_input_box, f, tags_area); render_selectable_input_box!(tags_input_box, f, tags_area);
} }
let save_button = Button::new() let save_button = Button::default()
.title("Save") .title("Save")
.selected(yes_no_value && highlight_yes_no); .selected(yes_no_value && highlight_yes_no);
let cancel_button = Button::new() let cancel_button = Button::default()
.title("Cancel") .title("Cancel")
.selected(!yes_no_value && highlight_yes_no); .selected(!yes_no_value && highlight_yes_no);
+11 -7
View File
@@ -1,3 +1,7 @@
use crate::ui::styles::{
awaiting_import_style, downloaded_style, downloading_style, missing_style,
unmonitored_missing_style, unreleased_style,
};
use std::iter; use std::iter;
use ratatui::Frame; use ratatui::Frame;
@@ -529,12 +533,12 @@ fn draw_manual_search_confirm_prompt(f: &mut Frame<'_>, app: &mut App<'_>) {
fn style_from_download_status(download_status: &str, is_monitored: bool, status: String) -> Style { fn style_from_download_status(download_status: &str, is_monitored: bool, status: String) -> Style {
match download_status { match download_status {
"Downloaded" => Style::new().downloaded(), "Downloaded" => downloaded_style(),
"Awaiting Import" => Style::new().awaiting_import(), "Awaiting Import" => awaiting_import_style(),
"Downloading" => Style::new().downloading(), "Downloading" => downloading_style(),
_ if !is_monitored && download_status == "Missing" => Style::new().unmonitored_missing(), _ if !is_monitored && download_status == "Missing" => unmonitored_missing_style(),
_ if status != "released" && download_status == "Missing" => Style::new().unreleased(), _ if status != "released" && download_status == "Missing" => unreleased_style(),
"Missing" => Style::new().missing(), "Missing" => missing_style(),
_ => Style::new().downloaded(), _ => downloaded_style(),
} }
} }
@@ -11,7 +11,10 @@ mod tests {
use crate::ui::radarr_ui::library::movie_details_ui::{ use crate::ui::radarr_ui::library::movie_details_ui::{
MovieDetailsUi, style_from_download_status, MovieDetailsUi, style_from_download_status,
}; };
use crate::ui::styles::ManagarrStyle; use crate::ui::styles::{
awaiting_import_style, downloaded_style, downloading_style, missing_style,
unmonitored_missing_style,
};
use crate::ui::ui_test_utils::test_utils::{TerminalSize, render_to_string_with_app}; use crate::ui::ui_test_utils::test_utils::{TerminalSize, render_to_string_with_app};
#[test] #[test]
@@ -26,13 +29,13 @@ mod tests {
} }
#[rstest] #[rstest]
#[case("Downloading", true, "", Style::new().downloading())] #[case("Downloading", true, "", downloading_style())]
#[case("Downloaded", true, "", Style::new().downloaded())] #[case("Downloaded", true, "", downloaded_style())]
#[case("Awaiting Import", true, "", Style::new().awaiting_import())] #[case("Awaiting Import", true, "", awaiting_import_style())]
#[case("Missing", false, "", Style::new().unmonitored_missing())] #[case("Missing", false, "", unmonitored_missing_style())]
#[case("Missing", false, "", Style::new().unmonitored_missing())] #[case("Missing", false, "", unmonitored_missing_style())]
#[case("Missing", true, "released", Style::new().missing())] #[case("Missing", true, "released", missing_style())]
#[case("", true, "", Style::new().downloaded())] #[case("", true, "", downloaded_style())]
fn test_style_from_download_status( fn test_style_from_download_status(
#[case] download_status: &str, #[case] download_status: &str,
#[case] is_monitored: bool, #[case] is_monitored: bool,
+2 -2
View File
@@ -161,7 +161,7 @@ fn draw_stats_context(f: &mut Frame<'_>, app: &App<'_>, area: Rect) {
let space: f64 = convert_to_gb(*free_space); let space: f64 = convert_to_gb(*free_space);
let root_folder_space = Paragraph::new(format!("{path}: {space:.2} GB free")) let root_folder_space = Paragraph::new(format!("{path}: {space:.2} GB free"))
.block(borderless_block()) .block(borderless_block())
.default(); .default_color();
f.render_widget( f.render_widget(
root_folder_space, root_folder_space,
@@ -249,7 +249,7 @@ fn draw_radarr_logo(f: &mut Frame<'_>, area: Rect) {
let logo_text = Text::from(RADARR_LOGO); let logo_text = Text::from(RADARR_LOGO);
let logo = Paragraph::new(logo_text) let logo = Paragraph::new(logo_text)
.light_yellow() .light_yellow()
.block(layout_block().default()) .block(layout_block().default_color())
.centered(); .centered();
f.render_widget(logo, area); f.render_widget(logo, area);
} }
+2 -2
View File
@@ -1,3 +1,4 @@
use crate::ui::styles::default_style;
use std::ops::Sub; use std::ops::Sub;
#[cfg(test)] #[cfg(test)]
@@ -5,7 +6,6 @@ use crate::ui::ui_test_utils::test_utils::Utc;
#[cfg(not(test))] #[cfg(not(test))]
use chrono::Utc; use chrono::Utc;
use ratatui::layout::Layout; use ratatui::layout::Layout;
use ratatui::style::Style;
use ratatui::text::{Span, Text}; use ratatui::text::{Span, Text};
use ratatui::widgets::{Cell, Row}; use ratatui::widgets::{Cell, Row};
use ratatui::{ use ratatui::{
@@ -178,7 +178,7 @@ fn draw_logs(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
style_log_list_item(ListItem::new(Text::from(Span::raw(log_line))), level) style_log_list_item(ListItem::new(Text::from(Span::raw(log_line))), level)
}) })
.block(block) .block(block)
.highlight_style(Style::new().default()); .highlight_style(default_style());
f.render_widget(logs_box, area); f.render_widget(logs_box, area);
} }
+3 -3
View File
@@ -3,7 +3,7 @@ use crate::models::Route;
use crate::models::servarr_data::sonarr::sonarr_data::{ActiveSonarrBlock, BLOCKLIST_BLOCKS}; use crate::models::servarr_data::sonarr::sonarr_data::{ActiveSonarrBlock, BLOCKLIST_BLOCKS};
use crate::models::sonarr_models::BlocklistItem; use crate::models::sonarr_models::BlocklistItem;
use crate::ui::DrawUi; use crate::ui::DrawUi;
use crate::ui::styles::ManagarrStyle; use crate::ui::styles::{ManagarrStyle, secondary_style};
use crate::ui::utils::layout_block_top_border; use crate::ui::utils::layout_block_top_border;
use crate::ui::widgets::confirmation_prompt::ConfirmationPrompt; use crate::ui::widgets::confirmation_prompt::ConfirmationPrompt;
use crate::ui::widgets::managarr_table::ManagarrTable; use crate::ui::widgets::managarr_table::ManagarrTable;
@@ -11,7 +11,7 @@ use crate::ui::widgets::message::Message;
use crate::ui::widgets::popup::{Popup, Size}; use crate::ui::widgets::popup::{Popup, Size};
use ratatui::Frame; use ratatui::Frame;
use ratatui::layout::{Alignment, Constraint, Rect}; use ratatui::layout::{Alignment, Constraint, Rect};
use ratatui::style::{Style, Stylize}; use ratatui::style::Stylize;
use ratatui::text::{Line, Text}; use ratatui::text::{Line, Text};
use ratatui::widgets::{Cell, Row}; use ratatui::widgets::{Cell, Row};
@@ -163,7 +163,7 @@ fn draw_blocklist_item_details_popup(f: &mut Frame<'_>, app: &mut App<'_>) {
let message = Message::new(text) let message = Message::new(text)
.title("Details") .title("Details")
.style(Style::new().secondary()) .style(secondary_style())
.alignment(Alignment::Left); .alignment(Alignment::Left);
f.render_widget(Popup::new(message).size(Size::NarrowMessage), f.area()); f.render_widget(Popup::new(message).size(Size::NarrowMessage), f.area());
+2 -3
View File
@@ -4,14 +4,13 @@ use crate::models::servarr_data::sonarr::sonarr_data::{ActiveSonarrBlock, HISTOR
use crate::models::servarr_models::Language; use crate::models::servarr_models::Language;
use crate::models::sonarr_models::{SonarrHistoryEventType, SonarrHistoryItem}; use crate::models::sonarr_models::{SonarrHistoryEventType, SonarrHistoryItem};
use crate::ui::DrawUi; use crate::ui::DrawUi;
use crate::ui::styles::ManagarrStyle; use crate::ui::styles::{ManagarrStyle, secondary_style};
use crate::ui::utils::{get_width_from_percentage, layout_block_top_border}; use crate::ui::utils::{get_width_from_percentage, layout_block_top_border};
use crate::ui::widgets::managarr_table::ManagarrTable; use crate::ui::widgets::managarr_table::ManagarrTable;
use crate::ui::widgets::message::Message; use crate::ui::widgets::message::Message;
use crate::ui::widgets::popup::{Popup, Size}; use crate::ui::widgets::popup::{Popup, Size};
use ratatui::Frame; use ratatui::Frame;
use ratatui::layout::{Alignment, Constraint, Rect}; use ratatui::layout::{Alignment, Constraint, Rect};
use ratatui::style::Style;
use ratatui::text::Text; use ratatui::text::Text;
use ratatui::widgets::{Cell, Row}; use ratatui::widgets::{Cell, Row};
@@ -151,7 +150,7 @@ fn draw_history_item_details_popup(f: &mut Frame<'_>, app: &mut App<'_>) {
let message = Message::new(text) let message = Message::new(text)
.title("Details") .title("Details")
.style(Style::new().secondary()) .style(secondary_style())
.alignment(Alignment::Left); .alignment(Alignment::Left);
f.render_widget(Popup::new(message).size(Size::NarrowMessage), f.area()); f.render_widget(Popup::new(message).size(Size::NarrowMessage), f.area());
+2 -3
View File
@@ -4,7 +4,6 @@ use crate::app::App;
use crate::models::Route; use crate::models::Route;
use crate::models::servarr_data::sonarr::sonarr_data::{ActiveSonarrBlock, EDIT_INDEXER_BLOCKS}; use crate::models::servarr_data::sonarr::sonarr_data::{ActiveSonarrBlock, EDIT_INDEXER_BLOCKS};
use crate::render_selectable_input_box; use crate::render_selectable_input_box;
use crate::ui::styles::ManagarrStyle;
use crate::ui::utils::title_block_centered; use crate::ui::utils::title_block_centered;
use crate::ui::widgets::button::Button; use crate::ui::widgets::button::Button;
use crate::ui::widgets::checkbox::Checkbox; use crate::ui::widgets::checkbox::Checkbox;
@@ -151,10 +150,10 @@ fn draw_edit_indexer_prompt(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
.flex(Flex::Center) .flex(Flex::Center)
.areas(buttons_area); .areas(buttons_area);
let save_button = Button::new() let save_button = Button::default()
.title("Save") .title("Save")
.selected(yes_no_value && highlight_yes_no); .selected(yes_no_value && highlight_yes_no);
let cancel_button = Button::new() let cancel_button = Button::default()
.title("Cancel") .title("Cancel")
.selected(!yes_no_value && highlight_yes_no); .selected(!yes_no_value && highlight_yes_no);
@@ -7,7 +7,6 @@ use crate::models::servarr_data::sonarr::sonarr_data::{
ActiveSonarrBlock, INDEXER_SETTINGS_BLOCKS, ActiveSonarrBlock, INDEXER_SETTINGS_BLOCKS,
}; };
use crate::render_selectable_input_box; use crate::render_selectable_input_box;
use crate::ui::styles::ManagarrStyle;
use crate::ui::utils::title_block_centered; use crate::ui::utils::title_block_centered;
use crate::ui::widgets::button::Button; use crate::ui::widgets::button::Button;
use crate::ui::widgets::input_box::InputBox; use crate::ui::widgets::input_box::InputBox;
@@ -103,10 +102,10 @@ fn draw_edit_indexer_settings_prompt(f: &mut Frame<'_>, app: &mut App<'_>, area:
.flex(Flex::Center) .flex(Flex::Center)
.areas(buttons_area); .areas(buttons_area);
let save_button = Button::new() let save_button = Button::default()
.title("Save") .title("Save")
.selected(yes_no_value && highlight_yes_no); .selected(yes_no_value && highlight_yes_no);
let cancel_button = Button::new() let cancel_button = Button::default()
.title("Cancel") .title("Cancel")
.selected(!yes_no_value && highlight_yes_no); .selected(!yes_no_value && highlight_yes_no);
+2 -2
View File
@@ -1,6 +1,6 @@
use crate::ui::styles::success_style;
use ratatui::Frame; use ratatui::Frame;
use ratatui::layout::{Constraint, Rect}; use ratatui::layout::{Constraint, Rect};
use ratatui::style::{Style, Stylize};
use ratatui::text::Text; use ratatui::text::Text;
use ratatui::widgets::{Cell, Row}; use ratatui::widgets::{Cell, Row};
@@ -73,7 +73,7 @@ impl DrawUi for IndexersUi {
} else { } else {
let message = Message::new("Indexer test succeeded!") let message = Message::new("Indexer test succeeded!")
.title("Success") .title("Success")
.style(Style::new().success().bold()); .style(success_style().bold());
Popup::new(message).size(Size::Message) Popup::new(message).size(Size::Message)
} }
}; };
+10 -10
View File
@@ -144,14 +144,14 @@ fn draw_add_series_search(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
.block(title_block_centered("Add Series")); .block(title_block_centered("Add Series"));
search_box.show_cursor(f, search_box_area); search_box.show_cursor(f, search_box_area);
f.render_widget(layout_block().default(), results_area); f.render_widget(layout_block().default_color(), results_area);
f.render_widget(search_box, search_box_area); f.render_widget(search_box, search_box_area);
} }
ActiveSonarrBlock::AddSeriesEmptySearchResults => { ActiveSonarrBlock::AddSeriesEmptySearchResults => {
let error_message = Message::new("No series found matching your query!"); let error_message = Message::new("No series found matching your query!");
let error_message_popup = Popup::new(error_message).size(Size::Message); let error_message_popup = Popup::new(error_message).size(Size::Message);
f.render_widget(layout_block().default(), results_area); f.render_widget(layout_block().default_color(), results_area);
f.render_widget(error_message_popup, f.area()); f.render_widget(error_message_popup, f.area());
} }
ActiveSonarrBlock::AddSeriesSearchResults ActiveSonarrBlock::AddSeriesSearchResults
@@ -168,7 +168,7 @@ fn draw_add_series_search(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
search_results_row_mapping, search_results_row_mapping,
) )
.loading(is_loading) .loading(is_loading)
.block(layout_block().default()) .block(layout_block().default_color())
.headers([ .headers([
"", "Title", "Year", "Network", "Seasons", "Rating", "Genres", "", "Title", "Year", "Network", "Seasons", "Rating", "Genres",
]) ])
@@ -314,27 +314,27 @@ fn draw_confirmation_prompt(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
let use_season_folder_checkbox = Checkbox::new("Season Folder") let use_season_folder_checkbox = Checkbox::new("Season Folder")
.checked(*use_season_folder) .checked(*use_season_folder)
.highlighted(selected_block == ActiveSonarrBlock::AddSeriesToggleUseSeasonFolder); .highlighted(selected_block == ActiveSonarrBlock::AddSeriesToggleUseSeasonFolder);
let root_folder_drop_down_button = Button::new() let root_folder_drop_down_button = Button::default()
.title(&selected_root_folder.path) .title(&selected_root_folder.path)
.label("Root Folder") .label("Root Folder")
.icon("") .icon("")
.selected(selected_block == ActiveSonarrBlock::AddSeriesSelectRootFolder); .selected(selected_block == ActiveSonarrBlock::AddSeriesSelectRootFolder);
let monitor_drop_down_button = Button::new() let monitor_drop_down_button = Button::default()
.title(selected_monitor.to_display_str()) .title(selected_monitor.to_display_str())
.label("Monitor") .label("Monitor")
.icon("") .icon("")
.selected(selected_block == ActiveSonarrBlock::AddSeriesSelectMonitor); .selected(selected_block == ActiveSonarrBlock::AddSeriesSelectMonitor);
let series_type_drop_down_button = Button::new() let series_type_drop_down_button = Button::default()
.title(selected_series_type.to_display_str()) .title(selected_series_type.to_display_str())
.label("Series Type") .label("Series Type")
.icon("") .icon("")
.selected(selected_block == ActiveSonarrBlock::AddSeriesSelectSeriesType); .selected(selected_block == ActiveSonarrBlock::AddSeriesSelectSeriesType);
let quality_profile_drop_down_button = Button::new() let quality_profile_drop_down_button = Button::default()
.title(selected_quality_profile) .title(selected_quality_profile)
.label("Quality Profile") .label("Quality Profile")
.icon("") .icon("")
.selected(selected_block == ActiveSonarrBlock::AddSeriesSelectQualityProfile); .selected(selected_block == ActiveSonarrBlock::AddSeriesSelectQualityProfile);
let language_profile_drop_down_button = Button::new() let language_profile_drop_down_button = Button::default()
.title(selected_language_profile) .title(selected_language_profile)
.label("Language Profile") .label("Language Profile")
.icon("") .icon("")
@@ -356,10 +356,10 @@ fn draw_confirmation_prompt(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
render_selectable_input_box!(tags_input_box, f, tags_area); render_selectable_input_box!(tags_input_box, f, tags_area);
} }
let add_button = Button::new() let add_button = Button::default()
.title("Add") .title("Add")
.selected(yes_no_value && highlight_yes_no); .selected(yes_no_value && highlight_yes_no);
let cancel_button = Button::new() let cancel_button = Button::default()
.title("Cancel") .title("Cancel")
.selected(!yes_no_value && highlight_yes_no); .selected(!yes_no_value && highlight_yes_no);
+5 -6
View File
@@ -13,7 +13,6 @@ use crate::models::servarr_data::sonarr::sonarr_data::{
}; };
use crate::render_selectable_input_box; use crate::render_selectable_input_box;
use crate::ui::styles::ManagarrStyle;
use crate::ui::utils::{layout_paragraph_borderless, title_block_centered}; use crate::ui::utils::{layout_paragraph_borderless, title_block_centered};
use crate::ui::widgets::button::Button; use crate::ui::widgets::button::Button;
use crate::ui::widgets::checkbox::Checkbox; use crate::ui::widgets::checkbox::Checkbox;
@@ -145,17 +144,17 @@ fn draw_edit_series_confirmation_prompt(f: &mut Frame<'_>, app: &mut App<'_>, ar
let season_folder_checkbox = Checkbox::new("Season Folder") let season_folder_checkbox = Checkbox::new("Season Folder")
.checked(use_season_folders.unwrap_or_default()) .checked(use_season_folders.unwrap_or_default())
.highlighted(selected_block == ActiveSonarrBlock::EditSeriesToggleSeasonFolder); .highlighted(selected_block == ActiveSonarrBlock::EditSeriesToggleSeasonFolder);
let series_type_drop_down_button = Button::new() let series_type_drop_down_button = Button::default()
.title(selected_series_type.to_display_str()) .title(selected_series_type.to_display_str())
.label("Series Type") .label("Series Type")
.icon("") .icon("")
.selected(selected_block == ActiveSonarrBlock::EditSeriesSelectSeriesType); .selected(selected_block == ActiveSonarrBlock::EditSeriesSelectSeriesType);
let quality_profile_drop_down_button = Button::new() let quality_profile_drop_down_button = Button::default()
.title(selected_quality_profile) .title(selected_quality_profile)
.label("Quality Profile") .label("Quality Profile")
.icon("") .icon("")
.selected(selected_block == ActiveSonarrBlock::EditSeriesSelectQualityProfile); .selected(selected_block == ActiveSonarrBlock::EditSeriesSelectQualityProfile);
let language_profile_drop_down_button = Button::new() let language_profile_drop_down_button = Button::default()
.title(selected_language_profile) .title(selected_language_profile)
.label("Language Profile") .label("Language Profile")
.icon("") .icon("")
@@ -183,10 +182,10 @@ fn draw_edit_series_confirmation_prompt(f: &mut Frame<'_>, app: &mut App<'_>, ar
render_selectable_input_box!(tags_input_box, f, tags_area); render_selectable_input_box!(tags_input_box, f, tags_area);
} }
let save_button = Button::new() let save_button = Button::default()
.title("Save") .title("Save")
.selected(yes_no_value && highlight_yes_no); .selected(yes_no_value && highlight_yes_no);
let cancel_button = Button::new() let cancel_button = Button::default()
.title("Cancel") .title("Cancel")
.selected(!yes_no_value && highlight_yes_no); .selected(!yes_no_value && highlight_yes_no);
+12 -8
View File
@@ -13,6 +13,10 @@ use crate::ui::sonarr_ui::sonarr_ui_utils::{
create_no_data_history_event_details, create_no_data_history_event_details,
}; };
use crate::ui::styles::ManagarrStyle; use crate::ui::styles::ManagarrStyle;
use crate::ui::styles::{
awaiting_import_style, downloaded_style, downloading_style, missing_style, secondary_style,
unmonitored_missing_style, unmonitored_style, unreleased_style,
};
use crate::ui::utils::{ use crate::ui::utils::{
borderless_block, decorate_peer_style, get_width_from_percentage, layout_block_bottom_border, borderless_block, decorate_peer_style, get_width_from_percentage, layout_block_bottom_border,
layout_block_top_border, layout_block_top_border,
@@ -388,7 +392,7 @@ fn draw_history_item_details_popup(f: &mut Frame<'_>, app: &mut App<'_>, area: R
let message = Message::new(text) let message = Message::new(text)
.title("Details") .title("Details")
.style(Style::new().secondary()) .style(secondary_style())
.alignment(Alignment::Left); .alignment(Alignment::Left);
f.render_widget(Popup::new(message).size(Size::NarrowMessage), area); f.render_widget(Popup::new(message).size(Size::NarrowMessage), area);
@@ -602,29 +606,29 @@ fn style_from_status(download: Option<&DownloadRecord>, episode: &Episode) -> St
if !episode.has_file { if !episode.has_file {
if let Some(download) = download { if let Some(download) = download {
if download.status == DownloadStatus::Downloading { if download.status == DownloadStatus::Downloading {
return Style::new().downloading(); return downloading_style();
} }
if download.status == DownloadStatus::Completed { if download.status == DownloadStatus::Completed {
return Style::new().awaiting_import(); return awaiting_import_style();
} }
} }
if !episode.monitored { if !episode.monitored {
return Style::new().unmonitored_missing(); return unmonitored_missing_style();
} }
if let Some(air_date) = episode.air_date_utc.as_ref() if let Some(air_date) = episode.air_date_utc.as_ref()
&& air_date > &Utc::now() && air_date > &Utc::now()
{ {
return Style::new().unreleased(); return unreleased_style();
} }
return Style::new().missing(); return missing_style();
} }
if !episode.monitored { if !episode.monitored {
Style::new().unmonitored() unmonitored_style()
} else { } else {
Style::new().downloaded() downloaded_style()
} }
} }
@@ -13,6 +13,7 @@ use crate::ui::sonarr_ui::sonarr_ui_utils::{
create_no_data_history_event_details, create_no_data_history_event_details,
}; };
use crate::ui::styles::ManagarrStyle; use crate::ui::styles::ManagarrStyle;
use crate::ui::styles::secondary_style;
use crate::ui::utils::{ use crate::ui::utils::{
borderless_block, decorate_peer_style, get_width_from_percentage, layout_block_top_border, borderless_block, decorate_peer_style, get_width_from_percentage, layout_block_top_border,
}; };
@@ -26,7 +27,7 @@ use crate::utils::convert_to_gb;
use chrono::Utc; use chrono::Utc;
use ratatui::Frame; use ratatui::Frame;
use ratatui::layout::{Alignment, Constraint, Rect}; use ratatui::layout::{Alignment, Constraint, Rect};
use ratatui::prelude::{Line, Style, Stylize, Text}; use ratatui::prelude::{Line, Stylize, Text};
use ratatui::widgets::{Cell, Paragraph, Row, Wrap}; use ratatui::widgets::{Cell, Paragraph, Row, Wrap};
use serde_json::Number; use serde_json::Number;
@@ -567,7 +568,7 @@ fn draw_history_item_details_popup(f: &mut Frame<'_>, app: &mut App<'_>, area: R
let message = Message::new(text) let message = Message::new(text)
.title("Details") .title("Details")
.style(Style::new().secondary()) .style(secondary_style())
.alignment(Alignment::Left); .alignment(Alignment::Left);
f.render_widget(Popup::new(message).size(Size::NarrowMessage), area); f.render_widget(Popup::new(message).size(Size::NarrowMessage), area);
+21 -14
View File
@@ -1,8 +1,9 @@
use crate::ui::styles::secondary_style;
use chrono::Utc; use chrono::Utc;
use deunicode::deunicode; use deunicode::deunicode;
use ratatui::Frame; use ratatui::Frame;
use ratatui::layout::{Alignment, Constraint, Layout, Rect}; use ratatui::layout::{Alignment, Constraint, Layout, Rect};
use ratatui::style::{Style, Stylize}; use ratatui::style::Stylize;
use ratatui::text::{Line, Text}; use ratatui::text::{Line, Text};
use ratatui::widgets::{Cell, Paragraph, Row, Wrap}; use ratatui::widgets::{Cell, Paragraph, Row, Wrap};
use regex::Regex; use regex::Regex;
@@ -157,54 +158,60 @@ fn draw_series_description(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
"Title: ".primary().bold(), "Title: ".primary().bold(),
current_selection.title.text.clone().primary().bold(), current_selection.title.text.clone().primary().bold(),
]), ]),
Line::from(vec!["Overview: ".primary().bold(), overview.default()]), Line::from(vec![
"Overview: ".primary().bold(),
overview.default_color(),
]),
Line::from(vec![ Line::from(vec![
"Network: ".primary().bold(), "Network: ".primary().bold(),
current_selection current_selection
.network .network
.clone() .clone()
.unwrap_or_default() .unwrap_or_default()
.default(), .default_color(),
]), ]),
Line::from(vec![ Line::from(vec![
"Status: ".primary().bold(), "Status: ".primary().bold(),
current_selection.status.to_display_str().default(), current_selection.status.to_display_str().default_color(),
]), ]),
Line::from(vec![ Line::from(vec![
"Genres: ".primary().bold(), "Genres: ".primary().bold(),
current_selection.genres.join(", ").default(), current_selection.genres.join(", ").default_color(),
]), ]),
Line::from(vec![ Line::from(vec![
"Rating: ".primary().bold(), "Rating: ".primary().bold(),
format!("{}%", (current_selection.ratings.value * 10.0) as i32).default(), format!("{}%", (current_selection.ratings.value * 10.0) as i32).default_color(),
]), ]),
Line::from(vec![ Line::from(vec![
"Year: ".primary().bold(), "Year: ".primary().bold(),
current_selection.year.to_string().default(), current_selection.year.to_string().default_color(),
]), ]),
Line::from(vec![ Line::from(vec![
"Runtime: ".primary().bold(), "Runtime: ".primary().bold(),
format!("{} minutes", current_selection.runtime).default(), format!("{} minutes", current_selection.runtime).default_color(),
]), ]),
Line::from(vec![ Line::from(vec![
"Path: ".primary().bold(), "Path: ".primary().bold(),
current_selection.path.clone().default(), current_selection.path.clone().default_color(),
]), ]),
Line::from(vec![ Line::from(vec![
"Quality Profile: ".primary().bold(), "Quality Profile: ".primary().bold(),
quality_profile.default(), quality_profile.default_color(),
]), ]),
Line::from(vec![ Line::from(vec![
"Language Profile: ".primary().bold(), "Language Profile: ".primary().bold(),
language_profile.default(), language_profile.default_color(),
]),
Line::from(vec![
"Monitored: ".primary().bold(),
monitored.default_color(),
]), ]),
Line::from(vec!["Monitored: ".primary().bold(), monitored.default()]),
]; ];
if let Some(stats) = current_selection.statistics.as_ref() { if let Some(stats) = current_selection.statistics.as_ref() {
let size = convert_to_gb(stats.size_on_disk); let size = convert_to_gb(stats.size_on_disk);
series_description.extend(vec![Line::from(vec![ series_description.extend(vec![Line::from(vec![
"Size on Disk: ".primary().bold(), "Size on Disk: ".primary().bold(),
format!("{size:.2} GB").default(), format!("{size:.2} GB").default_color(),
])]); ])]);
} }
@@ -421,7 +428,7 @@ fn draw_history_item_details_popup(f: &mut Frame<'_>, app: &mut App<'_>, area: R
let message = Message::new(text) let message = Message::new(text)
.title("Details") .title("Details")
.style(Style::new().secondary()) .style(secondary_style())
.alignment(Alignment::Left); .alignment(Alignment::Left);
f.render_widget(Popup::new(message).size(Size::NarrowMessage), area); f.render_widget(Popup::new(message).size(Size::NarrowMessage), area);
+2 -2
View File
@@ -173,7 +173,7 @@ fn draw_stats_context(f: &mut Frame<'_>, app: &App<'_>, area: Rect) {
let space: f64 = convert_to_gb(*free_space); let space: f64 = convert_to_gb(*free_space);
let root_folder_space = Paragraph::new(format!("{path}: {space:.2} GB free")) let root_folder_space = Paragraph::new(format!("{path}: {space:.2} GB free"))
.block(borderless_block()) .block(borderless_block())
.default(); .default_color();
f.render_widget( f.render_widget(
root_folder_space, root_folder_space,
@@ -224,7 +224,7 @@ fn draw_sonarr_logo(f: &mut Frame<'_>, area: Rect) {
let logo_text = Text::from(SONARR_LOGO); let logo_text = Text::from(SONARR_LOGO);
let logo = Paragraph::new(logo_text) let logo = Paragraph::new(logo_text)
.light_cyan() .light_cyan()
.block(layout_block().default()) .block(layout_block().default_color())
.centered(); .centered();
f.render_widget(logo, area); f.render_widget(logo, area);
} }
+2 -2
View File
@@ -1,3 +1,4 @@
use crate::ui::styles::default_style;
use std::ops::Sub; use std::ops::Sub;
#[cfg(test)] #[cfg(test)]
@@ -5,7 +6,6 @@ use crate::ui::ui_test_utils::test_utils::Utc;
#[cfg(not(test))] #[cfg(not(test))]
use chrono::Utc; use chrono::Utc;
use ratatui::layout::Layout; use ratatui::layout::Layout;
use ratatui::style::Style;
use ratatui::text::{Span, Text}; use ratatui::text::{Span, Text};
use ratatui::widgets::{Cell, Row}; use ratatui::widgets::{Cell, Row};
use ratatui::{ use ratatui::{
@@ -171,7 +171,7 @@ fn draw_logs(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
style_log_list_item(ListItem::new(Text::from(Span::raw(log_line))), level) style_log_list_item(ListItem::new(Text::from(Span::raw(log_line))), level)
}) })
.block(block) .block(block)
.highlight_style(Style::new().default()); .highlight_style(default_style());
f.render_widget(logs_box, area); f.render_widget(logs_box, area);
} }
+135 -85
View File
@@ -1,47 +1,13 @@
use crate::ui::THEME; use crate::ui::THEME;
use ratatui::style::{Styled, Stylize}; use ratatui::style::{Style, Styled};
#[cfg(test)] #[cfg(test)]
#[path = "styles_tests.rs"] #[path = "styles_tests.rs"]
mod styles_tests; mod styles_tests;
pub trait ManagarrStyle<'a, T>: Stylize<'a, T> pub fn awaiting_import_style() -> Style {
where
T: Default,
{
#[allow(clippy::new_ret_no_self)]
fn new() -> T;
fn awaiting_import(self) -> T;
fn indeterminate(self) -> T;
fn default(self) -> T;
fn downloaded(self) -> T;
fn downloading(self) -> T;
fn failure(self) -> T;
fn help(self) -> T;
fn highlight(self) -> T;
fn missing(self) -> T;
fn primary(self) -> T;
fn secondary(self) -> T;
fn success(self) -> T;
fn system_function(self) -> T;
fn unmonitored(self) -> T;
fn unmonitored_missing(self) -> T;
fn unreleased(self) -> T;
fn warning(self) -> T;
}
impl<T, U> ManagarrStyle<'_, T> for U
where
U: Styled<Item = T>,
T: Default,
{
fn new() -> T {
T::default()
}
fn awaiting_import(self) -> T {
THEME.with(|theme| { THEME.with(|theme| {
self.fg( Style::new().fg(
theme theme
.get() .get()
.awaiting_import .awaiting_import
@@ -50,11 +16,11 @@ where
.expect("awaiting_import color must be defined"), .expect("awaiting_import color must be defined"),
) )
}) })
} }
fn indeterminate(self) -> T { pub fn indeterminate_style() -> Style {
THEME.with(|theme| { THEME.with(|theme| {
self.fg( Style::new().fg(
theme theme
.get() .get()
.indeterminate .indeterminate
@@ -63,11 +29,11 @@ where
.expect("indeterminate color must be defined"), .expect("indeterminate color must be defined"),
) )
}) })
} }
fn default(self) -> T { pub fn default_style() -> Style {
THEME.with(|theme| { THEME.with(|theme| {
self.fg( Style::new().fg(
theme theme
.get() .get()
.default .default
@@ -76,11 +42,11 @@ where
.expect("default color must be defined"), .expect("default color must be defined"),
) )
}) })
} }
fn downloaded(self) -> T { pub fn downloaded_style() -> Style {
THEME.with(|theme| { THEME.with(|theme| {
self.fg( Style::new().fg(
theme theme
.get() .get()
.downloaded .downloaded
@@ -89,11 +55,11 @@ where
.expect("downloaded color must be defined"), .expect("downloaded color must be defined"),
) )
}) })
} }
fn downloading(self) -> T { pub fn downloading_style() -> Style {
THEME.with(|theme| { THEME.with(|theme| {
self.fg( Style::new().fg(
theme theme
.get() .get()
.downloading .downloading
@@ -102,11 +68,11 @@ where
.expect("downloading color must be defined"), .expect("downloading color must be defined"),
) )
}) })
} }
fn failure(self) -> T { pub fn failure_style() -> Style {
THEME.with(|theme| { THEME.with(|theme| {
self.fg( Style::new().fg(
theme theme
.get() .get()
.failure .failure
@@ -115,11 +81,11 @@ where
.expect("failure color must be defined"), .expect("failure color must be defined"),
) )
}) })
} }
fn help(self) -> T { pub fn help_style() -> Style {
THEME.with(|theme| { THEME.with(|theme| {
self.fg( Style::new().fg(
theme theme
.get() .get()
.help .help
@@ -128,15 +94,15 @@ where
.expect("help color must be defined"), .expect("help color must be defined"),
) )
}) })
} }
fn highlight(self) -> T { pub fn highlight_style() -> Style {
self.reversed() Style::new().reversed()
} }
fn missing(self) -> T { pub fn missing_style() -> Style {
THEME.with(|theme| { THEME.with(|theme| {
self.fg( Style::new().fg(
theme theme
.get() .get()
.missing .missing
@@ -145,11 +111,11 @@ where
.expect("missing color must be defined"), .expect("missing color must be defined"),
) )
}) })
} }
fn primary(self) -> T { pub fn primary_style() -> Style {
THEME.with(|theme| { THEME.with(|theme| {
self.fg( Style::new().fg(
theme theme
.get() .get()
.primary .primary
@@ -158,11 +124,11 @@ where
.expect("primary color must be defined"), .expect("primary color must be defined"),
) )
}) })
} }
fn secondary(self) -> T { pub fn secondary_style() -> Style {
THEME.with(|theme| { THEME.with(|theme| {
self.fg( Style::new().fg(
theme theme
.get() .get()
.secondary .secondary
@@ -171,11 +137,11 @@ where
.expect("secondary color must be defined"), .expect("secondary color must be defined"),
) )
}) })
} }
fn success(self) -> T { pub fn success_style() -> Style {
THEME.with(|theme| { THEME.with(|theme| {
self.fg( Style::new().fg(
theme theme
.get() .get()
.success .success
@@ -184,11 +150,11 @@ where
.expect("success color must be defined"), .expect("success color must be defined"),
) )
}) })
} }
fn system_function(self) -> T { pub fn system_function_style() -> Style {
THEME.with(|theme| { THEME.with(|theme| {
self.fg( Style::new().fg(
theme theme
.get() .get()
.system_function .system_function
@@ -197,11 +163,11 @@ where
.expect("system_function color must be defined"), .expect("system_function color must be defined"),
) )
}) })
} }
fn unmonitored(self) -> T { pub fn unmonitored_style() -> Style {
THEME.with(|theme| { THEME.with(|theme| {
self.fg( Style::new().fg(
theme theme
.get() .get()
.unmonitored .unmonitored
@@ -210,11 +176,11 @@ where
.expect("unmonitored color must be defined"), .expect("unmonitored color must be defined"),
) )
}) })
} }
fn unmonitored_missing(self) -> T { pub fn unmonitored_missing_style() -> Style {
THEME.with(|theme| { THEME.with(|theme| {
self.fg( Style::new().fg(
theme theme
.get() .get()
.unmonitored_missing .unmonitored_missing
@@ -223,11 +189,11 @@ where
.expect("unmonitored_missing color must be defined"), .expect("unmonitored_missing color must be defined"),
) )
}) })
} }
fn unreleased(self) -> T { pub fn unreleased_style() -> Style {
THEME.with(|theme| { THEME.with(|theme| {
self.fg( Style::new().fg(
theme theme
.get() .get()
.unreleased .unreleased
@@ -236,11 +202,11 @@ where
.expect("unreleased color must be defined"), .expect("unreleased color must be defined"),
) )
}) })
} }
fn warning(self) -> T { pub fn warning_style() -> Style {
THEME.with(|theme| { THEME.with(|theme| {
self.fg( Style::new().fg(
theme theme
.get() .get()
.warning .warning
@@ -249,5 +215,89 @@ where
.expect("warning color must be defined"), .expect("warning color must be defined"),
) )
}) })
}
pub trait ManagarrStyle: Styled {
fn awaiting_import(self) -> Self::Item;
fn indeterminate(self) -> Self::Item;
fn default_color(self) -> Self::Item;
fn downloaded(self) -> Self::Item;
fn downloading(self) -> Self::Item;
fn failure(self) -> Self::Item;
fn help(self) -> Self::Item;
fn missing(self) -> Self::Item;
fn primary(self) -> Self::Item;
fn secondary(self) -> Self::Item;
fn success(self) -> Self::Item;
fn system_function(self) -> Self::Item;
fn unmonitored(self) -> Self::Item;
fn unmonitored_missing(self) -> Self::Item;
fn unreleased(self) -> Self::Item;
fn warning(self) -> Self::Item;
}
impl<T: Styled> ManagarrStyle for T {
fn awaiting_import(self) -> Self::Item {
self.set_style(awaiting_import_style())
}
fn indeterminate(self) -> Self::Item {
self.set_style(indeterminate_style())
}
fn default_color(self) -> Self::Item {
self.set_style(default_style())
}
fn downloaded(self) -> Self::Item {
self.set_style(downloaded_style())
}
fn downloading(self) -> Self::Item {
self.set_style(downloading_style())
}
fn failure(self) -> Self::Item {
self.set_style(failure_style())
}
fn help(self) -> Self::Item {
self.set_style(help_style())
}
fn missing(self) -> Self::Item {
self.set_style(missing_style())
}
fn primary(self) -> Self::Item {
self.set_style(primary_style())
}
fn secondary(self) -> Self::Item {
self.set_style(secondary_style())
}
fn success(self) -> Self::Item {
self.set_style(success_style())
}
fn system_function(self) -> Self::Item {
self.set_style(system_function_style())
}
fn unmonitored(self) -> Self::Item {
self.set_style(unmonitored_style())
}
fn unmonitored_missing(self) -> Self::Item {
self.set_style(unmonitored_missing_style())
}
fn unreleased(self) -> Self::Item {
self.set_style(unreleased_style())
}
fn warning(self) -> Self::Item {
self.set_style(warning_style())
} }
} }
+24 -24
View File
@@ -1,19 +1,19 @@
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use crate::ui::styles::ManagarrStyle; use crate::ui::styles::{
awaiting_import_style, default_style, downloaded_style, downloading_style, failure_style,
help_style, highlight_style, indeterminate_style, missing_style, primary_style,
secondary_style, success_style, system_function_style, unmonitored_missing_style,
unmonitored_style, unreleased_style, warning_style,
};
use pretty_assertions::assert_eq; use pretty_assertions::assert_eq;
use ratatui::prelude::Modifier; use ratatui::prelude::Modifier;
use ratatui::style::{Color, Style, Stylize}; use ratatui::style::{Color, Style};
#[test]
fn test_new() {
assert_eq!(Style::new(), <Style as Default>::default())
}
#[test] #[test]
fn test_style_awaiting_import() { fn test_style_awaiting_import() {
assert_eq!( assert_eq!(
Style::new().awaiting_import(), awaiting_import_style(),
Style::new().fg(Color::Rgb(255, 170, 66)) Style::new().fg(Color::Rgb(255, 170, 66))
); );
} }
@@ -21,86 +21,86 @@ mod test {
#[test] #[test]
fn test_style_indeterminate() { fn test_style_indeterminate() {
assert_eq!( assert_eq!(
Style::new().indeterminate(), indeterminate_style(),
Style::new().fg(Color::Rgb(255, 170, 66)) Style::new().fg(Color::Rgb(255, 170, 66))
); );
} }
#[test] #[test]
fn test_style_default() { fn test_style_default() {
assert_eq!(Style::new().default(), Style::new().white()); assert_eq!(default_style(), Style::new().white());
} }
#[test] #[test]
fn test_style_downloaded() { fn test_style_downloaded() {
assert_eq!(Style::new().downloaded(), Style::new().green()); assert_eq!(downloaded_style(), Style::new().green());
} }
#[test] #[test]
fn test_style_downloading() { fn test_style_downloading() {
assert_eq!(Style::new().downloading(), Style::new().magenta()); assert_eq!(downloading_style(), Style::new().magenta());
} }
#[test] #[test]
fn test_style_failure() { fn test_style_failure() {
assert_eq!(Style::new().failure(), Style::new().red()); assert_eq!(failure_style(), Style::new().red());
} }
#[test] #[test]
fn test_style_help() { fn test_style_help() {
assert_eq!(Style::new().help(), Style::new().light_blue()); assert_eq!(help_style(), Style::new().light_blue());
} }
#[test] #[test]
fn test_style_highlight() { fn test_style_highlight() {
assert_eq!( assert_eq!(
Style::new().highlight(), highlight_style(),
Style::new().add_modifier(Modifier::REVERSED) Style::new().add_modifier(Modifier::REVERSED)
); );
} }
#[test] #[test]
fn test_style_missing() { fn test_style_missing() {
assert_eq!(Style::new().missing(), Style::new().red()); assert_eq!(missing_style(), Style::new().red());
} }
#[test] #[test]
fn test_style_primary() { fn test_style_primary() {
assert_eq!(Style::new().primary(), Style::new().cyan()); assert_eq!(primary_style(), Style::new().cyan());
} }
#[test] #[test]
fn test_style_secondary() { fn test_style_secondary() {
assert_eq!(Style::new().secondary(), Style::new().yellow()); assert_eq!(secondary_style(), Style::new().yellow());
} }
#[test] #[test]
fn test_style_success() { fn test_style_success() {
assert_eq!(Style::new().success(), Style::new().green()); assert_eq!(success_style(), Style::new().green());
} }
#[test] #[test]
fn test_style_system_function() { fn test_style_system_function() {
assert_eq!(Style::new().system_function(), Style::new().yellow()); assert_eq!(system_function_style(), Style::new().yellow());
} }
#[test] #[test]
fn test_style_unmonitored() { fn test_style_unmonitored() {
assert_eq!(Style::new().unmonitored(), Style::new().gray()); assert_eq!(unmonitored_style(), Style::new().gray());
} }
#[test] #[test]
fn test_style_unmonitored_missing() { fn test_style_unmonitored_missing() {
assert_eq!(Style::new().unmonitored_missing(), Style::new().yellow()); assert_eq!(unmonitored_missing_style(), Style::new().yellow());
} }
#[test] #[test]
fn test_style_unreleased() { fn test_style_unreleased() {
assert_eq!(Style::new().unreleased(), Style::new().light_cyan()); assert_eq!(unreleased_style(), Style::new().light_cyan());
} }
#[test] #[test]
fn test_style_warning() { fn test_style_warning() {
assert_eq!(Style::new().warning(), Style::new().magenta()); assert_eq!(warning_style(), Style::new().magenta());
} }
} }
+22 -20
View File
@@ -1,8 +1,10 @@
use crate::ui::THEME; use crate::ui::THEME;
use crate::ui::styles::ManagarrStyle; use crate::ui::styles::{
ManagarrStyle, default_style, failure_style, primary_style, secondary_style,
system_function_style,
};
use ratatui::layout::{Alignment, Constraint, Layout, Rect}; use ratatui::layout::{Alignment, Constraint, Layout, Rect};
use ratatui::style::{Style, Stylize}; use ratatui::style::{Style, Stylize};
use ratatui::symbols;
use ratatui::text::{Line, Span, Text}; use ratatui::text::{Line, Span, Text};
use ratatui::widgets::{Block, BorderType, Borders, LineGauge, ListItem, Paragraph, Wrap}; use ratatui::widgets::{Block, BorderType, Borders, LineGauge, ListItem, Paragraph, Wrap};
@@ -37,11 +39,11 @@ pub fn layout_block_top_border_with_title(title_span: Span<'_>) -> Block<'_> {
} }
pub fn layout_block_top_border<'a>() -> Block<'a> { pub fn layout_block_top_border<'a>() -> Block<'a> {
Block::new().borders(Borders::TOP).default() Block::new().borders(Borders::TOP).default_color()
} }
pub fn layout_block_bottom_border<'a>() -> Block<'a> { pub fn layout_block_bottom_border<'a>() -> Block<'a> {
Block::new().borders(Borders::BOTTOM).default() Block::new().borders(Borders::BOTTOM).default_color()
} }
pub fn layout_paragraph_borderless(string: &str) -> Paragraph<'_> { pub fn layout_paragraph_borderless(string: &str) -> Paragraph<'_> {
@@ -54,14 +56,14 @@ pub fn layout_paragraph_borderless(string: &str) -> Paragraph<'_> {
} }
pub fn borderless_block<'a>() -> Block<'a> { pub fn borderless_block<'a>() -> Block<'a> {
Block::new().default() Block::new().default_color()
} }
pub fn style_block_highlight(is_selected: bool) -> Style { pub fn style_block_highlight(is_selected: bool) -> Style {
if is_selected { if is_selected {
Style::new().system_function().bold() system_function_style().bold()
} else { } else {
Style::new().default().bold() default_style().bold()
} }
} }
@@ -74,7 +76,7 @@ pub fn unstyled_title_block(title: &str) -> Block<'_> {
} }
pub fn title_block(title: &str) -> Block<'_> { pub fn title_block(title: &str) -> Block<'_> {
unstyled_title_block(title).default() unstyled_title_block(title).default_color()
} }
pub fn title_block_centered(title: &str) -> Block<'_> { pub fn title_block_centered(title: &str) -> Block<'_> {
@@ -82,7 +84,7 @@ pub fn title_block_centered(title: &str) -> Block<'_> {
} }
pub fn logo_block<'a>() -> Block<'a> { pub fn logo_block<'a>() -> Block<'a> {
layout_block().default().title(Span::styled( layout_block().default_color().title(Span::styled(
" Managarr - A Servarr management TUI ", " Managarr - A Servarr management TUI ",
Style::new().magenta().bold().italic(), Style::new().magenta().bold().italic(),
)) ))
@@ -107,19 +109,19 @@ pub fn centered_rect(percent_x: u16, percent_y: u16, area: Rect) -> Rect {
} }
pub fn line_gauge_with_title(title: &str, ratio: f64) -> LineGauge<'_> { pub fn line_gauge_with_title(title: &str, ratio: f64) -> LineGauge<'_> {
LineGauge::new() LineGauge::default()
.block(Block::new().title(title)) .block(Block::new().title(title))
.filled_style(Style::new().primary()) .filled_style(primary_style())
.line_set(symbols::line::THICK) .filled_symbol("")
.ratio(ratio) .ratio(ratio)
.label(Line::from(format!("{:.0}%", ratio * 100.0))) .label(Line::from(format!("{:.0}%", ratio * 100.0)))
} }
pub fn line_gauge_with_label(title: &str, ratio: f64) -> LineGauge<'_> { pub fn line_gauge_with_label(title: &str, ratio: f64) -> LineGauge<'_> {
LineGauge::new() LineGauge::default()
.block(Block::new()) .block(Block::new())
.filled_style(Style::new().primary()) .filled_style(primary_style())
.line_set(symbols::line::THICK) .filled_symbol("")
.ratio(ratio) .ratio(ratio)
.label(Line::from(format!("{title}: {:.0}%", ratio * 100.0))) .label(Line::from(format!("{title}: {:.0}%", ratio * 100.0)))
} }
@@ -132,11 +134,11 @@ pub(super) fn style_log_list_item(list_item: ListItem<'_>, level: String) -> Lis
match level.to_lowercase().as_str() { match level.to_lowercase().as_str() {
"trace" => list_item.gray(), "trace" => list_item.gray(),
"debug" => list_item.blue(), "debug" => list_item.blue(),
"info" => list_item.style(Style::new().default()), "info" => list_item.style(default_style()),
"warn" => list_item.style(Style::new().secondary()), "warn" => list_item.style(secondary_style()),
"error" => list_item.style(Style::new().failure()), "error" => list_item.style(failure_style()),
"fatal" => list_item.style(Style::new().failure().bold()), "fatal" => list_item.style(failure_style().bold()),
_ => list_item.style(Style::new().default()), _ => list_item.style(default_style()),
} }
} }
+13 -14
View File
@@ -1,6 +1,6 @@
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use crate::ui::styles::ManagarrStyle; use crate::ui::styles::{ManagarrStyle, default_style, failure_style, secondary_style};
use crate::ui::utils::{ use crate::ui::utils::{
borderless_block, centered_rect, convert_to_minutes_hours_days, decorate_peer_style, borderless_block, centered_rect, convert_to_minutes_hours_days, decorate_peer_style,
get_width_from_percentage, layout_block, layout_block_bottom_border, layout_block_top_border, get_width_from_percentage, layout_block, layout_block_bottom_border, layout_block_top_border,
@@ -49,7 +49,7 @@ mod test {
.add_modifier(Modifier::BOLD), .add_modifier(Modifier::BOLD),
); );
let expected_block = Block::new() let expected_block = Block::new()
.default() .default_color()
.borders(Borders::TOP) .borders(Borders::TOP)
.title(title_span.clone()); .title(title_span.clone());
@@ -63,7 +63,7 @@ mod test {
fn test_layout_block_top_border() { fn test_layout_block_top_border() {
assert_eq!( assert_eq!(
layout_block_top_border(), layout_block_top_border(),
Block::new().borders(Borders::TOP).default() Block::new().borders(Borders::TOP).default_color()
); );
} }
@@ -71,13 +71,13 @@ mod test {
fn test_layout_block_bottom_border() { fn test_layout_block_bottom_border() {
assert_eq!( assert_eq!(
layout_block_bottom_border(), layout_block_bottom_border(),
Block::new().borders(Borders::BOTTOM).default() Block::new().borders(Borders::BOTTOM).default_color()
); );
} }
#[test] #[test]
fn test_borderless_block() { fn test_borderless_block() {
assert_eq!(borderless_block(), Block::new().default()); assert_eq!(borderless_block(), Block::new().default_color());
} }
#[test] #[test]
@@ -117,7 +117,7 @@ mod test {
#[test] #[test]
fn test_title_block() { fn test_title_block() {
let expected_block = Block::new() let expected_block = Block::new()
.default() .default_color()
.borders(Borders::ALL) .borders(Borders::ALL)
.border_type(BorderType::Rounded) .border_type(BorderType::Rounded)
.title(Span::styled( .title(Span::styled(
@@ -131,7 +131,7 @@ mod test {
#[test] #[test]
fn test_title_block_centered() { fn test_title_block_centered() {
let expected_block = Block::new() let expected_block = Block::new()
.default() .default_color()
.borders(Borders::ALL) .borders(Borders::ALL)
.border_type(BorderType::Rounded) .border_type(BorderType::Rounded)
.title(Span::styled( .title(Span::styled(
@@ -146,7 +146,7 @@ mod test {
#[test] #[test]
fn test_logo_block() { fn test_logo_block() {
let expected_block = Block::new() let expected_block = Block::new()
.default() .default_color()
.borders(Borders::ALL) .borders(Borders::ALL)
.border_type(BorderType::Rounded) .border_type(BorderType::Rounded)
.title(Span::styled( .title(Span::styled(
@@ -190,7 +190,6 @@ mod test {
#[test] #[test]
fn test_determine_log_style_by_level() { fn test_determine_log_style_by_level() {
use crate::ui::styles::ManagarrStyle;
let list_item = ListItem::new(Text::from(Span::raw("test"))); let list_item = ListItem::new(Text::from(Span::raw("test")));
assert_eq!( assert_eq!(
@@ -203,23 +202,23 @@ mod test {
); );
assert_eq!( assert_eq!(
style_log_list_item(list_item.clone(), "info".to_string()), style_log_list_item(list_item.clone(), "info".to_string()),
list_item.clone().style(Style::new().default()) list_item.clone().style(default_style())
); );
assert_eq!( assert_eq!(
style_log_list_item(list_item.clone(), "warn".to_string()), style_log_list_item(list_item.clone(), "warn".to_string()),
list_item.clone().style(Style::new().secondary()) list_item.clone().style(secondary_style())
); );
assert_eq!( assert_eq!(
style_log_list_item(list_item.clone(), "error".to_string()), style_log_list_item(list_item.clone(), "error".to_string()),
list_item.clone().style(Style::new().failure()) list_item.clone().style(failure_style())
); );
assert_eq!( assert_eq!(
style_log_list_item(list_item.clone(), "fatal".to_string()), style_log_list_item(list_item.clone(), "fatal".to_string()),
list_item.clone().style(Style::new().failure().bold()) list_item.clone().style(failure_style().bold())
); );
assert_eq!( assert_eq!(
style_log_list_item(list_item.clone(), "".to_string()), style_log_list_item(list_item.clone(), "".to_string()),
list_item.style(Style::new().default()) list_item.style(default_style())
); );
} }
-1
View File
@@ -4,7 +4,6 @@ use derive_setters::Setters;
use ratatui::buffer::Buffer; use ratatui::buffer::Buffer;
use ratatui::layout::{Constraint, Layout, Rect}; use ratatui::layout::{Constraint, Layout, Rect};
use ratatui::prelude::Text; use ratatui::prelude::Text;
use ratatui::style::Stylize;
use ratatui::widgets::{Paragraph, Widget}; use ratatui::widgets::{Paragraph, Widget};
#[derive(PartialEq, Debug, Copy, Clone, Setters)] #[derive(PartialEq, Debug, Copy, Clone, Setters)]
+4 -5
View File
@@ -1,4 +1,3 @@
use crate::ui::styles::ManagarrStyle;
use crate::ui::utils::{layout_paragraph_borderless, title_block_centered}; use crate::ui::utils::{layout_paragraph_borderless, title_block_centered};
use crate::ui::widgets::button::Button; use crate::ui::widgets::button::Button;
use crate::ui::widgets::checkbox::Checkbox; use crate::ui::widgets::checkbox::Checkbox;
@@ -63,11 +62,11 @@ impl ConfirmationPrompt<'_> {
checkbox.render(chunks[i + 1], buf); checkbox.render(chunks[i + 1], buf);
}); });
Button::new() Button::default()
.title("Yes") .title("Yes")
.selected(self.yes_no_value && self.yes_no_highlighted) .selected(self.yes_no_value && self.yes_no_highlighted)
.render(yes_area, buf); .render(yes_area, buf);
Button::new() Button::default()
.title("No") .title("No")
.selected(!self.yes_no_value && self.yes_no_highlighted) .selected(!self.yes_no_value && self.yes_no_highlighted)
.render(no_area, buf); .render(no_area, buf);
@@ -109,11 +108,11 @@ impl ConfirmationPrompt<'_> {
Layout::horizontal([Constraint::Percentage(50), Constraint::Percentage(50)]) Layout::horizontal([Constraint::Percentage(50), Constraint::Percentage(50)])
.areas(buttons_area); .areas(buttons_area);
Button::new() Button::default()
.title("Yes") .title("Yes")
.selected(self.yes_no_value) .selected(self.yes_no_value)
.render(yes_area, buf); .render(yes_area, buf);
Button::new() Button::default()
.title("No") .title("No")
.selected(!self.yes_no_value) .selected(!self.yes_no_value)
.render(no_area, buf); .render(no_area, buf);
+4 -3
View File
@@ -1,9 +1,10 @@
use crate::ui::styles::{default_style, system_function_style};
use derive_setters::Setters; use derive_setters::Setters;
use ratatui::Frame; use ratatui::Frame;
use ratatui::buffer::Buffer; use ratatui::buffer::Buffer;
use ratatui::layout::{Constraint, Layout, Position, Rect}; use ratatui::layout::{Constraint, Layout, Position, Rect};
use ratatui::prelude::Text; use ratatui::prelude::Text;
use ratatui::style::{Style, Styled, Stylize}; use ratatui::style::{Style, Styled};
use ratatui::widgets::{Block, Paragraph, Widget, WidgetRef}; use ratatui::widgets::{Block, Paragraph, Widget, WidgetRef};
use crate::ui::styles::ManagarrStyle; use crate::ui::styles::ManagarrStyle;
@@ -35,7 +36,7 @@ impl<'a> InputBox<'a> {
InputBox { InputBox {
content, content,
offset: 0, offset: 0,
style: Style::new().default(), style: default_style(),
block: layout_block(), block: layout_block(),
label: None, label: None,
cursor_after_string: true, cursor_after_string: true,
@@ -71,7 +72,7 @@ impl<'a> InputBox<'a> {
fn render_input_box(&self, area: Rect, buf: &mut Buffer) { fn render_input_box(&self, area: Rect, buf: &mut Buffer) {
let style = let style =
if matches!(self.is_highlighted, Some(true)) && matches!(self.is_selected, Some(false)) { if matches!(self.is_highlighted, Some(true)) && matches!(self.is_selected, Some(false)) {
Style::new().system_function().bold() system_function_style().bold()
} else { } else {
self.style self.style
}; };
+2 -3
View File
@@ -1,10 +1,9 @@
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::ui::styles::ManagarrStyle; use crate::ui::styles::default_style;
use crate::ui::utils::layout_block; use crate::ui::utils::layout_block;
use crate::ui::widgets::input_box::InputBox; use crate::ui::widgets::input_box::InputBox;
use pretty_assertions::{assert_eq, assert_str_eq}; use pretty_assertions::{assert_eq, assert_str_eq};
use ratatui::style::Style;
#[test] #[test]
fn test_input_box_new() { fn test_input_box_new() {
@@ -12,7 +11,7 @@ mod tests {
assert_str_eq!(input_box.content, "test"); assert_str_eq!(input_box.content, "test");
assert_eq!(input_box.offset, 0); assert_eq!(input_box.offset, 0);
assert_eq!(input_box.style, Style::new().default()); assert_eq!(input_box.style, default_style());
assert_eq!(input_box.block, layout_block()); assert_eq!(input_box.block, layout_block());
assert_eq!(input_box.label, None); assert_eq!(input_box.label, None);
assert!(input_box.cursor_after_string); assert!(input_box.cursor_after_string);
+7 -4
View File
@@ -3,7 +3,7 @@ use super::message::Message;
use super::popup::Size; use super::popup::Size;
use crate::models::stateful_table::StatefulTable; use crate::models::stateful_table::StatefulTable;
use crate::ui::HIGHLIGHT_SYMBOL; use crate::ui::HIGHLIGHT_SYMBOL;
use crate::ui::styles::ManagarrStyle; use crate::ui::styles::{ManagarrStyle, highlight_style};
use crate::ui::utils::{borderless_block, centered_rect, title_block_centered}; use crate::ui::utils::{borderless_block, centered_rect, title_block_centered};
use crate::ui::widgets::loading_block::LoadingBlock; use crate::ui::widgets::loading_block::LoadingBlock;
use crate::ui::widgets::popup::Popup; use crate::ui::widgets::popup::Popup;
@@ -12,7 +12,7 @@ use derive_setters::Setters;
use ratatui::Frame; use ratatui::Frame;
use ratatui::buffer::Buffer; use ratatui::buffer::Buffer;
use ratatui::layout::{Constraint, Layout, Position, Rect}; use ratatui::layout::{Constraint, Layout, Position, Rect};
use ratatui::prelude::{Style, Stylize, Text}; use ratatui::prelude::{Stylize, Text};
use ratatui::widgets::{Block, ListItem, Row, StatefulWidget, Table, Widget, WidgetRef}; use ratatui::widgets::{Block, ListItem, Row, StatefulWidget, Table, Widget, WidgetRef};
use std::fmt::Debug; use std::fmt::Debug;
use std::sync::atomic::Ordering; use std::sync::atomic::Ordering;
@@ -136,7 +136,10 @@ where
if !table_contents.is_empty() { if !table_contents.is_empty() {
let rows = table_contents.iter().map(&self.row_mapper); let rows = table_contents.iter().map(&self.row_mapper);
let headers = Row::new(table_headers).default().bold().bottom_margin(0); let headers = Row::new(table_headers)
.default_color()
.bold()
.bottom_margin(0);
let mut table = Table::new(rows, &self.constraints) let mut table = Table::new(rows, &self.constraints)
.header(headers) .header(headers)
@@ -144,7 +147,7 @@ where
if self.highlight_rows { if self.highlight_rows {
table = table table = table
.row_highlight_style(Style::new().highlight()) .row_highlight_style(highlight_style())
.highlight_symbol(HIGHLIGHT_SYMBOL); .highlight_symbol(HIGHLIGHT_SYMBOL);
} }
+3 -3
View File
@@ -1,9 +1,9 @@
use crate::ui::styles::ManagarrStyle; use crate::ui::styles::failure_style;
use crate::ui::utils::title_block_centered; use crate::ui::utils::title_block_centered;
use derive_setters::Setters; use derive_setters::Setters;
use ratatui::buffer::Buffer; use ratatui::buffer::Buffer;
use ratatui::layout::{Alignment, Rect}; use ratatui::layout::{Alignment, Rect};
use ratatui::style::{Style, Stylize}; use ratatui::style::Style;
use ratatui::text::Text; use ratatui::text::Text;
use ratatui::widgets::{Paragraph, Widget, Wrap}; use ratatui::widgets::{Paragraph, Widget, Wrap};
@@ -27,7 +27,7 @@ impl<'a> Message<'a> {
Message { Message {
text: message.into(), text: message.into(),
title: "Error", title: "Error",
style: Style::new().failure().bold(), style: failure_style().bold(),
alignment: Alignment::Center, alignment: Alignment::Center,
} }
} }
+2 -3
View File
@@ -1,10 +1,9 @@
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::ui::styles::ManagarrStyle; use crate::ui::styles::failure_style;
use crate::ui::widgets::message::Message; use crate::ui::widgets::message::Message;
use pretty_assertions::{assert_eq, assert_str_eq}; use pretty_assertions::{assert_eq, assert_str_eq};
use ratatui::layout::Alignment; use ratatui::layout::Alignment;
use ratatui::style::{Style, Stylize};
use ratatui::text::Text; use ratatui::text::Text;
#[test] #[test]
@@ -15,7 +14,7 @@ mod tests {
assert_eq!(message.text, Text::from(test_message)); assert_eq!(message.text, Text::from(test_message));
assert_str_eq!(message.title, "Error"); assert_str_eq!(message.title, "Error");
assert_eq!(message.style, Style::new().failure().bold()); assert_eq!(message.style, failure_style().bold());
assert_eq!(message.alignment, Alignment::Center); assert_eq!(message.alignment, Alignment::Center);
} }
} }
+2 -2
View File
@@ -1,5 +1,5 @@
use crate::models::stateful_list::StatefulList; use crate::models::stateful_list::StatefulList;
use crate::ui::styles::ManagarrStyle; use crate::ui::styles::highlight_style;
use crate::ui::utils::layout_block; use crate::ui::utils::layout_block;
use ratatui::buffer::Buffer; use ratatui::buffer::Buffer;
use ratatui::layout::Rect; use ratatui::layout::Rect;
@@ -29,7 +29,7 @@ where
Self { Self {
content, content,
row_mapper, row_mapper,
highlight_style: Style::new().highlight(), highlight_style: highlight_style(),
block: layout_block(), block: layout_block(),
} }
} }
+4 -4
View File
@@ -1,11 +1,11 @@
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::models::stateful_list::StatefulList; use crate::models::stateful_list::StatefulList;
use crate::ui::styles::ManagarrStyle; use crate::ui::styles::highlight_style;
use crate::ui::utils::{layout_block, title_block}; use crate::ui::utils::{layout_block, title_block};
use crate::ui::widgets::selectable_list::SelectableList; use crate::ui::widgets::selectable_list::SelectableList;
use pretty_assertions::assert_eq; use pretty_assertions::assert_eq;
use ratatui::style::{Style, Stylize}; use ratatui::style::Style;
use ratatui::widgets::ListItem; use ratatui::widgets::ListItem;
#[test] #[test]
@@ -20,7 +20,7 @@ mod tests {
let row_mapper = selectable_list.row_mapper; let row_mapper = selectable_list.row_mapper;
assert_eq!(selectable_list.content.items, items); assert_eq!(selectable_list.content.items, items);
assert_eq!(row_mapper(&"test"), ListItem::new("test")); assert_eq!(row_mapper(&"test"), ListItem::new("test"));
assert_eq!(selectable_list.highlight_style, Style::new().highlight()); assert_eq!(selectable_list.highlight_style, highlight_style());
assert_eq!(selectable_list.block, layout_block()); assert_eq!(selectable_list.block, layout_block());
} }
@@ -55,6 +55,6 @@ mod tests {
assert_eq!(selectable_list.block, title_block("test")); assert_eq!(selectable_list.block, title_block("test"));
assert_eq!(selectable_list.content.items, items); assert_eq!(selectable_list.content.items, items);
assert_eq!(row_mapper(&"test"), ListItem::new("test")); assert_eq!(row_mapper(&"test"), ListItem::new("test"));
assert_eq!(selectable_list.highlight_style, Style::new().highlight()); assert_eq!(selectable_list.highlight_style, highlight_style());
} }
} }