Began the Great Widget Refactor of 2024 and introduced custom widgets for buttons, checkboxes, and input boxes. Up next: loading and table widgets

This commit is contained in:
2024-02-09 16:36:54 -07:00
parent 9b0c272e76
commit 68de986c48
11 changed files with 667 additions and 627 deletions
@@ -8,13 +8,17 @@ use crate::models::servarr_data::radarr::radarr_data::{
ActiveRadarrBlock, COLLECTION_DETAILS_BLOCKS, EDIT_COLLECTION_BLOCKS,
};
use crate::models::Route;
use crate::render_selectable_input_box;
use crate::ui::radarr_ui::collections::collection_details_ui::CollectionDetailsUi;
use crate::ui::radarr_ui::collections::draw_collections;
use crate::ui::styles::ManagarrStyle;
use crate::ui::utils::{layout_paragraph_borderless, title_block_centered};
use crate::ui::widgets::button::Button;
use crate::ui::widgets::checkbox::Checkbox;
use crate::ui::widgets::input_box::InputBox;
use crate::ui::{
draw_button, draw_checkbox_with_label, draw_drop_down_menu_button, draw_drop_down_popup,
draw_large_popup_over_background_fn_with_ui, draw_medium_popup_over, draw_popup,
draw_selectable_list, draw_text_box_with_label, DrawUi, LabeledTextBoxProps,
draw_drop_down_popup, draw_large_popup_over_background_fn_with_ui, draw_medium_popup_over,
draw_popup, draw_selectable_list, DrawUi,
};
#[cfg(test)]
@@ -126,12 +130,9 @@ fn draw_edit_collection_confirmation_prompt(f: &mut Frame<'_>, app: &mut App<'_>
search_on_add,
path,
} = app.data.radarr_data.edit_collection_modal.as_ref().unwrap();
let selected_minimum_availability = minimum_availability_list.current_selection();
let selected_quality_profile = quality_profile_list.current_selection();
f.render_widget(title_block_centered(&title), area);
let [paragraph_area, monitored_area, min_availability_area, quality_profile_area, root_folder_area, search_on_add_area, _, buttons_area] =
Layout::vertical([
Constraint::Length(6),
@@ -145,63 +146,52 @@ fn draw_edit_collection_confirmation_prompt(f: &mut Frame<'_>, app: &mut App<'_>
])
.margin(1)
.areas(area);
let prompt_paragraph = layout_paragraph_borderless(&collection_overview);
f.render_widget(prompt_paragraph, paragraph_area);
let [save_area, cancel_area] =
Layout::horizontal([Constraint::Percentage(50), Constraint::Percentage(50)])
.areas(buttons_area);
draw_checkbox_with_label(
f,
monitored_area,
"Monitored",
monitored.unwrap_or_default(),
selected_block == &ActiveRadarrBlock::EditCollectionToggleMonitored,
);
draw_drop_down_menu_button(
f,
min_availability_area,
"Minimum Availability",
selected_minimum_availability.to_display_str(),
selected_block == &ActiveRadarrBlock::EditCollectionSelectMinimumAvailability,
);
draw_drop_down_menu_button(
f,
quality_profile_area,
"Quality Profile",
selected_quality_profile,
selected_block == &ActiveRadarrBlock::EditCollectionSelectQualityProfile,
);
let prompt_paragraph = layout_paragraph_borderless(&collection_overview);
let monitored_checkbox = Checkbox::new("Monitored")
.highlighted(selected_block == &ActiveRadarrBlock::EditCollectionToggleMonitored)
.checked(monitored.unwrap_or_default());
let min_availability_drop_down_button = Button::new()
.title(selected_minimum_availability.to_display_str())
.label("Minimum Availability")
.icon("")
.selected(selected_block == &ActiveRadarrBlock::EditCollectionSelectMinimumAvailability);
let quality_profile_drop_down_button = Button::new()
.title(selected_quality_profile)
.label("Quality Profile")
.icon("")
.selected(selected_block == &ActiveRadarrBlock::EditCollectionSelectQualityProfile);
if let Route::Radarr(active_radarr_block, _) = *app.get_current_route() {
draw_text_box_with_label(
f,
LabeledTextBoxProps {
area: root_folder_area,
label: "Root Folder",
text: &path.text,
offset: *path.offset.borrow(),
is_selected: selected_block == &ActiveRadarrBlock::EditCollectionRootFolderPathInput,
should_show_cursor: active_radarr_block
== ActiveRadarrBlock::EditCollectionRootFolderPathInput,
cursor_after_string: true,
},
);
let root_folder_input_box = InputBox::new(&path.text)
.offset(*path.offset.borrow())
.label("Root Folder")
.highlighted(selected_block == &ActiveRadarrBlock::EditCollectionRootFolderPathInput)
.selected(active_radarr_block == ActiveRadarrBlock::EditCollectionRootFolderPathInput);
render_selectable_input_box!(root_folder_input_box, f, root_folder_area);
}
draw_checkbox_with_label(
f,
search_on_add_area,
"Search on Add",
search_on_add.unwrap_or_default(),
selected_block == &ActiveRadarrBlock::EditCollectionToggleSearchOnAdd,
);
let search_on_add_checkbox = Checkbox::new("Search on Add")
.highlighted(selected_block == &ActiveRadarrBlock::EditCollectionToggleSearchOnAdd)
.checked(search_on_add.unwrap_or_default());
let save_button = Button::new()
.title("Save")
.selected(yes_no_value && highlight_yes_no);
let cancel_button = Button::new()
.title("Cancel")
.selected(!yes_no_value && highlight_yes_no);
draw_button(f, save_area, "Save", yes_no_value && highlight_yes_no);
draw_button(f, cancel_area, "Cancel", !yes_no_value && highlight_yes_no);
f.render_widget(title_block_centered(&title), area);
f.render_widget(prompt_paragraph, paragraph_area);
f.render_widget(monitored_checkbox, monitored_area);
f.render_widget(min_availability_drop_down_button, min_availability_area);
f.render_widget(quality_profile_drop_down_button, quality_profile_area);
f.render_widget(search_on_add_checkbox, search_on_add_area);
f.render_widget(save_button, save_area);
f.render_widget(cancel_button, cancel_area);
}
fn draw_edit_collection_select_minimum_availability_popup(
+78 -107
View File
@@ -1,12 +1,14 @@
use crate::app::App;
use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, EDIT_INDEXER_BLOCKS};
use crate::models::Route;
use crate::render_selectable_input_box;
use crate::ui::radarr_ui::indexers::draw_indexers;
use crate::ui::styles::ManagarrStyle;
use crate::ui::utils::title_block_centered;
use crate::ui::{
draw_button, draw_checkbox_with_label, draw_popup_over, draw_text_box_with_label, loading,
DrawUi, LabeledTextBoxProps,
};
use crate::ui::widgets::button::Button;
use crate::ui::widgets::checkbox::Checkbox;
use crate::ui::widgets::input_box::InputBox;
use crate::ui::{draw_popup_over, loading, DrawUi};
use ratatui::layout::{Constraint, Flex, Layout, Rect};
use ratatui::Frame;
@@ -48,19 +50,16 @@ fn draw_edit_indexer_prompt(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
if edit_indexer_modal_option.is_some() {
let edit_indexer_modal = edit_indexer_modal_option.as_ref().unwrap();
f.render_widget(block, area);
let [settings_area, buttons_area] =
Layout::vertical([Constraint::Fill(0), Constraint::Length(3)])
.margin(1)
.areas(area);
let [left_side_area, right_side_area] =
Layout::horizontal([Constraint::Ratio(1, 2), Constraint::Ratio(1, 2)])
.margin(1)
.areas(settings_area);
let [name, rss, auto_search, interactive_search, _] = Layout::vertical([
let [name_area, rss_area, auto_search_area, interactive_search_area, _] = Layout::vertical([
Constraint::Length(3),
Constraint::Length(3),
Constraint::Length(3),
@@ -78,115 +77,87 @@ fn draw_edit_indexer_prompt(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
.areas(right_side_area);
if let Route::Radarr(active_radarr_block, _) = *app.get_current_route() {
draw_text_box_with_label(
f,
LabeledTextBoxProps {
area: name,
label: "Name",
text: &edit_indexer_modal.name.text,
offset: *edit_indexer_modal.name.offset.borrow(),
is_selected: selected_block == &ActiveRadarrBlock::EditIndexerNameInput,
should_show_cursor: active_radarr_block == ActiveRadarrBlock::EditIndexerNameInput,
cursor_after_string: true,
},
);
draw_text_box_with_label(
f,
LabeledTextBoxProps {
area: url_area,
label: "URL",
text: &edit_indexer_modal.url.text,
offset: *edit_indexer_modal.url.offset.borrow(),
is_selected: selected_block == &ActiveRadarrBlock::EditIndexerUrlInput,
should_show_cursor: active_radarr_block == ActiveRadarrBlock::EditIndexerUrlInput,
cursor_after_string: true,
},
);
draw_text_box_with_label(
f,
LabeledTextBoxProps {
area: api_key_area,
label: "API Key",
text: &edit_indexer_modal.api_key.text,
offset: *edit_indexer_modal.api_key.offset.borrow(),
is_selected: selected_block == &ActiveRadarrBlock::EditIndexerApiKeyInput,
should_show_cursor: active_radarr_block == ActiveRadarrBlock::EditIndexerApiKeyInput,
cursor_after_string: true,
},
);
let name_input_box = InputBox::new(&edit_indexer_modal.name.text)
.offset(*edit_indexer_modal.name.offset.borrow())
.label("Name")
.highlighted(selected_block == &ActiveRadarrBlock::EditIndexerNameInput)
.selected(active_radarr_block == ActiveRadarrBlock::EditIndexerNameInput);
let url_input_box = InputBox::new(&edit_indexer_modal.url.text)
.offset(*edit_indexer_modal.url.offset.borrow())
.label("URL")
.highlighted(selected_block == &ActiveRadarrBlock::EditIndexerUrlInput)
.selected(active_radarr_block == ActiveRadarrBlock::EditIndexerUrlInput);
let api_key_input_box = InputBox::new(&edit_indexer_modal.api_key.text)
.offset(*edit_indexer_modal.api_key.offset.borrow())
.label("API Key")
.highlighted(selected_block == &ActiveRadarrBlock::EditIndexerApiKeyInput)
.selected(active_radarr_block == ActiveRadarrBlock::EditIndexerApiKeyInput);
let tags_input_box = InputBox::new(&edit_indexer_modal.tags.text)
.offset(*edit_indexer_modal.tags.offset.borrow())
.label("Tags")
.highlighted(selected_block == &ActiveRadarrBlock::EditIndexerTagsInput)
.selected(active_radarr_block == ActiveRadarrBlock::EditIndexerTagsInput);
render_selectable_input_box!(name_input_box, f, name_area);
render_selectable_input_box!(url_input_box, f, url_area);
render_selectable_input_box!(api_key_input_box, f, api_key_area);
if protocol == "torrent" {
draw_text_box_with_label(
f,
LabeledTextBoxProps {
area: seed_ratio_area,
label: "Seed Ratio",
text: &edit_indexer_modal.seed_ratio.text,
offset: *edit_indexer_modal.seed_ratio.offset.borrow(),
is_selected: selected_block == &ActiveRadarrBlock::EditIndexerSeedRatioInput,
should_show_cursor: active_radarr_block == ActiveRadarrBlock::EditIndexerSeedRatioInput,
cursor_after_string: true,
},
);
draw_text_box_with_label(
f,
LabeledTextBoxProps {
area: tags_area,
label: "Tags",
text: &edit_indexer_modal.tags.text,
offset: *edit_indexer_modal.tags.offset.borrow(),
is_selected: selected_block == &ActiveRadarrBlock::EditIndexerTagsInput,
should_show_cursor: active_radarr_block == ActiveRadarrBlock::EditIndexerTagsInput,
cursor_after_string: true,
},
);
let seed_ratio_input_box = InputBox::new(&edit_indexer_modal.seed_ratio.text)
.offset(*edit_indexer_modal.seed_ratio.offset.borrow())
.label("Seed Ratio")
.highlighted(selected_block == &ActiveRadarrBlock::EditIndexerSeedRatioInput)
.selected(active_radarr_block == ActiveRadarrBlock::EditIndexerSeedRatioInput);
let tags_input_box = InputBox::new(&edit_indexer_modal.tags.text)
.offset(*edit_indexer_modal.tags.offset.borrow())
.label("Tags")
.highlighted(selected_block == &ActiveRadarrBlock::EditIndexerTagsInput)
.selected(active_radarr_block == ActiveRadarrBlock::EditIndexerTagsInput);
render_selectable_input_box!(seed_ratio_input_box, f, seed_ratio_area);
render_selectable_input_box!(tags_input_box, f, tags_area);
} else {
draw_text_box_with_label(
f,
LabeledTextBoxProps {
area: seed_ratio_area,
label: "Tags",
text: &edit_indexer_modal.tags.text,
offset: *edit_indexer_modal.tags.offset.borrow(),
is_selected: selected_block == &ActiveRadarrBlock::EditIndexerTagsInput,
should_show_cursor: active_radarr_block == ActiveRadarrBlock::EditIndexerTagsInput,
cursor_after_string: true,
},
);
render_selectable_input_box!(tags_input_box, f, seed_ratio_area);
}
draw_checkbox_with_label(
f,
rss,
"Enable RSS",
edit_indexer_modal.enable_rss.unwrap_or_default(),
selected_block == &ActiveRadarrBlock::EditIndexerToggleEnableRss,
);
draw_checkbox_with_label(
f,
auto_search,
"Enable Automatic Search",
edit_indexer_modal
.enable_automatic_search
.unwrap_or_default(),
selected_block == &ActiveRadarrBlock::EditIndexerToggleEnableAutomaticSearch,
);
draw_checkbox_with_label(
f,
interactive_search,
"Enable Interactive Search",
edit_indexer_modal
.enable_interactive_search
.unwrap_or_default(),
selected_block == &ActiveRadarrBlock::EditIndexerToggleEnableInteractiveSearch,
);
let rss_checkbox = Checkbox::new("Enable RSS")
.checked(edit_indexer_modal.enable_rss.unwrap_or_default())
.highlighted(selected_block == &ActiveRadarrBlock::EditIndexerToggleEnableRss);
let auto_search_checkbox = Checkbox::new("Enable Automatic Search")
.checked(
edit_indexer_modal
.enable_automatic_search
.unwrap_or_default(),
)
.highlighted(selected_block == &ActiveRadarrBlock::EditIndexerToggleEnableAutomaticSearch);
let interactive_search_checkbox = Checkbox::new("Enable Interactive Search")
.checked(
edit_indexer_modal
.enable_interactive_search
.unwrap_or_default(),
)
.highlighted(
selected_block == &ActiveRadarrBlock::EditIndexerToggleEnableInteractiveSearch,
);
let [save_area, cancel_area] =
Layout::horizontal([Constraint::Percentage(25), Constraint::Percentage(25)])
.flex(Flex::Center)
.areas(buttons_area);
draw_button(f, save_area, "Save", yes_no_value && highlight_yes_no);
draw_button(f, cancel_area, "Cancel", !yes_no_value && highlight_yes_no);
let save_button = Button::new()
.title("Save")
.selected(yes_no_value && highlight_yes_no);
let cancel_button = Button::new()
.title("Cancel")
.selected(!yes_no_value && highlight_yes_no);
f.render_widget(block, area);
f.render_widget(rss_checkbox, rss_area);
f.render_widget(auto_search_checkbox, auto_search_area);
f.render_widget(interactive_search_checkbox, interactive_search_area);
f.render_widget(save_button, save_area);
f.render_widget(cancel_button, cancel_area);
}
} else {
loading(f, block, area, app.is_loading);
+72 -103
View File
@@ -6,12 +6,14 @@ use crate::models::servarr_data::radarr::radarr_data::{
ActiveRadarrBlock, INDEXER_SETTINGS_BLOCKS,
};
use crate::models::Route;
use crate::render_selectable_input_box;
use crate::ui::radarr_ui::indexers::draw_indexers;
use crate::ui::styles::ManagarrStyle;
use crate::ui::utils::title_block_centered;
use crate::ui::{
draw_button, draw_checkbox_with_label, draw_popup_over, draw_text_box_with_label, loading,
DrawUi, LabeledTextBoxProps,
};
use crate::ui::widgets::button::Button;
use crate::ui::widgets::checkbox::Checkbox;
use crate::ui::widgets::input_box::InputBox;
use crate::ui::{draw_popup_over, loading, DrawUi};
#[cfg(test)]
#[path = "indexer_settings_ui_tests.rs"]
@@ -50,18 +52,15 @@ fn draw_edit_indexer_settings_prompt(f: &mut Frame<'_>, app: &mut App<'_>, area:
if indexer_settings_option.is_some() {
let indexer_settings = indexer_settings_option.as_ref().unwrap();
f.render_widget(block, area);
let [settings_area, buttons_area] =
Layout::vertical([Constraint::Fill(0), Constraint::Length(3)])
.margin(1)
.areas(area);
let [left_side_area, right_side_area] =
Layout::horizontal([Constraint::Ratio(1, 2), Constraint::Ratio(1, 2)])
.margin(1)
.areas(settings_area);
let [min_age_area, retention_area, max_size_area, prefer_flags_area, _] = Layout::vertical([
Constraint::Length(3),
Constraint::Length(3),
@@ -81,110 +80,80 @@ fn draw_edit_indexer_settings_prompt(f: &mut Frame<'_>, app: &mut App<'_>, area:
.areas(right_side_area);
if let Route::Radarr(active_radarr_block, _) = *app.get_current_route() {
draw_text_box_with_label(
f,
LabeledTextBoxProps {
area: min_age_area,
label: "Minimum Age (minutes) ▴▾",
text: &indexer_settings.minimum_age.to_string(),
offset: 0,
is_selected: selected_block == &ActiveRadarrBlock::IndexerSettingsMinimumAgeInput,
should_show_cursor: active_radarr_block
== ActiveRadarrBlock::IndexerSettingsMinimumAgeInput,
cursor_after_string: false,
},
);
draw_text_box_with_label(
f,
LabeledTextBoxProps {
area: retention_area,
label: "Retention (days) ▴▾",
text: &indexer_settings.retention.to_string(),
offset: 0,
is_selected: selected_block == &ActiveRadarrBlock::IndexerSettingsRetentionInput,
should_show_cursor: active_radarr_block
== ActiveRadarrBlock::IndexerSettingsRetentionInput,
cursor_after_string: false,
},
);
draw_text_box_with_label(
f,
LabeledTextBoxProps {
area: max_size_area,
label: "Maximum Size (MB) ▴▾",
text: &indexer_settings.maximum_size.to_string(),
offset: 0,
is_selected: selected_block == &ActiveRadarrBlock::IndexerSettingsMaximumSizeInput,
should_show_cursor: active_radarr_block
== ActiveRadarrBlock::IndexerSettingsMaximumSizeInput,
cursor_after_string: false,
},
);
draw_text_box_with_label(
f,
LabeledTextBoxProps {
area: availability_delay_area,
label: "Availability Delay (days) ▴▾",
text: &indexer_settings.availability_delay.to_string(),
offset: 0,
is_selected: selected_block == &ActiveRadarrBlock::IndexerSettingsAvailabilityDelayInput,
should_show_cursor: active_radarr_block
== ActiveRadarrBlock::IndexerSettingsAvailabilityDelayInput,
cursor_after_string: false,
},
);
draw_text_box_with_label(
f,
LabeledTextBoxProps {
area: rss_sync_interval_area,
label: "RSS Sync Interval (minutes) ▴▾",
text: &indexer_settings.rss_sync_interval.to_string(),
offset: 0,
is_selected: selected_block == &ActiveRadarrBlock::IndexerSettingsRssSyncIntervalInput,
should_show_cursor: active_radarr_block
== ActiveRadarrBlock::IndexerSettingsRssSyncIntervalInput,
cursor_after_string: false,
},
);
draw_text_box_with_label(
f,
LabeledTextBoxProps {
area: whitelisted_sub_tags_area,
label: "Whitelisted Subtitle Tags",
text: &indexer_settings.whitelisted_hardcoded_subs.text,
offset: *indexer_settings.whitelisted_hardcoded_subs.offset.borrow(),
is_selected: selected_block
== &ActiveRadarrBlock::IndexerSettingsWhitelistedSubtitleTagsInput,
should_show_cursor: active_radarr_block
== ActiveRadarrBlock::IndexerSettingsWhitelistedSubtitleTagsInput,
cursor_after_string: true,
},
);
let min_age = indexer_settings.minimum_age.to_string();
let retention = indexer_settings.retention.to_string();
let max_size = indexer_settings.maximum_size.to_string();
let availability_delay = indexer_settings.availability_delay.to_string();
let rss_sync_interval = indexer_settings.rss_sync_interval.to_string();
let min_age_text_box = InputBox::new(&min_age)
.cursor_after_string(false)
.label("Minimum Age (minutes) ▴▾")
.highlighted(selected_block == &ActiveRadarrBlock::IndexerSettingsMinimumAgeInput)
.selected(active_radarr_block == ActiveRadarrBlock::IndexerSettingsMinimumAgeInput);
let retention_input_box = InputBox::new(&retention)
.cursor_after_string(false)
.label("Retention (days) ▴▾")
.highlighted(selected_block == &ActiveRadarrBlock::IndexerSettingsRetentionInput)
.selected(active_radarr_block == ActiveRadarrBlock::IndexerSettingsRetentionInput);
let max_size_input_box = InputBox::new(&max_size)
.cursor_after_string(false)
.label("Maximum Size (MB) ▴▾")
.highlighted(selected_block == &ActiveRadarrBlock::IndexerSettingsMaximumSizeInput)
.selected(active_radarr_block == ActiveRadarrBlock::IndexerSettingsMaximumSizeInput);
let availability_delay_input_box = InputBox::new(&availability_delay)
.cursor_after_string(false)
.label("Availability Delay (days) ▴▾")
.highlighted(selected_block == &ActiveRadarrBlock::IndexerSettingsAvailabilityDelayInput)
.selected(active_radarr_block == ActiveRadarrBlock::IndexerSettingsAvailabilityDelayInput);
let rss_sync_interval_input_box = InputBox::new(&rss_sync_interval)
.cursor_after_string(false)
.label("RSS Sync Interval (minutes) ▴▾")
.highlighted(selected_block == &ActiveRadarrBlock::IndexerSettingsRssSyncIntervalInput)
.selected(active_radarr_block == ActiveRadarrBlock::IndexerSettingsRssSyncIntervalInput);
let whitelisted_subs_input_box =
InputBox::new(&indexer_settings.whitelisted_hardcoded_subs.text)
.offset(*indexer_settings.whitelisted_hardcoded_subs.offset.borrow())
.label("Whitelisted Subtitle Tags")
.highlighted(
selected_block == &ActiveRadarrBlock::IndexerSettingsWhitelistedSubtitleTagsInput,
)
.selected(
active_radarr_block == ActiveRadarrBlock::IndexerSettingsWhitelistedSubtitleTagsInput,
);
render_selectable_input_box!(min_age_text_box, f, min_age_area);
render_selectable_input_box!(retention_input_box, f, retention_area);
render_selectable_input_box!(max_size_input_box, f, max_size_area);
render_selectable_input_box!(availability_delay_input_box, f, availability_delay_area);
render_selectable_input_box!(rss_sync_interval_input_box, f, rss_sync_interval_area);
render_selectable_input_box!(whitelisted_subs_input_box, f, whitelisted_sub_tags_area);
}
draw_checkbox_with_label(
f,
prefer_flags_area,
"Prefer Indexer Flags",
indexer_settings.prefer_indexer_flags,
selected_block == &ActiveRadarrBlock::IndexerSettingsTogglePreferIndexerFlags,
);
draw_checkbox_with_label(
f,
allow_hardcoded_subs_area,
"Allow Hardcoded Subs",
indexer_settings.allow_hardcoded_subs,
selected_block == &ActiveRadarrBlock::IndexerSettingsToggleAllowHardcodedSubs,
);
let prefer_indexer_flags_checkbox = Checkbox::new("Prefer Indexer Flags")
.highlighted(selected_block == &ActiveRadarrBlock::IndexerSettingsTogglePreferIndexerFlags)
.checked(indexer_settings.prefer_indexer_flags);
let allow_hardcoded_subs_checkbox = Checkbox::new("Allow Hardcoded Subs")
.highlighted(selected_block == &ActiveRadarrBlock::IndexerSettingsToggleAllowHardcodedSubs)
.checked(indexer_settings.allow_hardcoded_subs);
let [save_area, cancel_area] =
Layout::horizontal([Constraint::Percentage(25), Constraint::Percentage(25)])
.flex(Flex::Center)
.areas(buttons_area);
draw_button(f, save_area, "Save", yes_no_value && highlight_yes_no);
draw_button(f, cancel_area, "Cancel", !yes_no_value && highlight_yes_no);
let save_button = Button::new()
.title("Save")
.selected(yes_no_value && highlight_yes_no);
let cancel_button = Button::new()
.title("Cancel")
.selected(!yes_no_value && highlight_yes_no);
f.render_widget(block, area);
f.render_widget(prefer_indexer_flags_checkbox, prefer_flags_area);
f.render_widget(allow_hardcoded_subs_checkbox, allow_hardcoded_subs_area);
f.render_widget(save_button, save_area);
f.render_widget(cancel_button, cancel_area);
} else {
loading(f, block, area, app.is_loading);
}
+56 -73
View File
@@ -16,14 +16,14 @@ use crate::ui::utils::{
borderless_block, get_width_from_percentage, layout_block, layout_paragraph_borderless,
title_block_centered,
};
use crate::ui::widgets::button::Button;
use crate::ui::widgets::input_box::InputBox;
use crate::ui::{
draw_button, draw_drop_down_menu_button, draw_drop_down_popup, draw_error_popup,
draw_error_popup_over, draw_large_popup_over, draw_medium_popup_over, draw_selectable_list,
draw_table, draw_text_box, draw_text_box_with_label, DrawUi, LabeledTextBoxProps, TableProps,
TextBoxProps,
draw_drop_down_popup, draw_error_popup, draw_error_popup_over, draw_large_popup_over,
draw_medium_popup_over, draw_selectable_list, draw_table, DrawUi, TableProps,
};
use crate::utils::convert_runtime;
use crate::App;
use crate::{render_selectable_input_box, App};
#[cfg(test)]
#[path = "add_movie_ui_tests.rs"]
@@ -120,24 +120,17 @@ fn draw_add_movie_search(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
if let Route::Radarr(active_radarr_block, _) = *app.get_current_route() {
match active_radarr_block {
ActiveRadarrBlock::AddMovieSearchInput => {
draw_text_box(
f,
TextBoxProps {
text_box_area: search_box_area,
block_title: Some("Add Movie"),
block_content,
offset,
should_show_cursor: true,
is_selected: false,
cursor_after_string: true,
},
);
f.render_widget(layout_block(), results_area);
let search_box = InputBox::new(block_content)
.offset(offset)
.block(title_block_centered("Add Movie"));
let help_text = Text::from(build_context_clue_string(&BARE_POPUP_CONTEXT_CLUES).help());
let help_paragraph = Paragraph::new(help_text)
.block(borderless_block())
.alignment(Alignment::Center);
search_box.show_cursor(f, search_box_area);
f.render_widget(layout_block(), results_area);
f.render_widget(search_box, search_box_area);
f.render_widget(help_paragraph, help_area);
}
ActiveRadarrBlock::AddMovieEmptySearchResults => {
@@ -252,17 +245,11 @@ fn draw_add_movie_search(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
}
}
draw_text_box(
f,
TextBoxProps {
text_box_area: search_box_area,
block_title: Some("Add Movie"),
block_content,
offset,
should_show_cursor: false,
is_selected: false,
cursor_after_string: true,
},
f.render_widget(
InputBox::new(block_content)
.offset(offset)
.block(title_block_centered("Add Movie")),
search_box_area,
);
}
@@ -395,54 +382,50 @@ fn draw_confirmation_prompt(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
Layout::horizontal([Constraint::Percentage(50), Constraint::Percentage(50)])
.areas(buttons_area);
draw_drop_down_menu_button(
f,
root_folder_area,
"Root Folder",
&selected_root_folder.path,
selected_block == &ActiveRadarrBlock::AddMovieSelectRootFolder,
);
let root_folder_drop_down_button = Button::new()
.title(&selected_root_folder.path)
.label("Root Folder")
.icon("")
.selected(selected_block == &ActiveRadarrBlock::AddMovieSelectRootFolder);
let monitor_drop_down_button = Button::new()
.title(selected_monitor.to_display_str())
.label("Monitor")
.icon("")
.selected(selected_block == &ActiveRadarrBlock::AddMovieSelectMonitor);
let min_availability_drop_down_button = Button::new()
.title(selected_minimum_availability.to_display_str())
.label("Minimum Availability")
.icon("")
.selected(selected_block == &ActiveRadarrBlock::AddMovieSelectMinimumAvailability);
let quality_profile_drop_down_button = Button::new()
.title(selected_quality_profile)
.label("Quality Profile")
.icon("")
.selected(selected_block == &ActiveRadarrBlock::AddMovieSelectQualityProfile);
draw_drop_down_menu_button(
f,
monitor_area,
"Monitor",
selected_monitor.to_display_str(),
selected_block == &ActiveRadarrBlock::AddMovieSelectMonitor,
);
draw_drop_down_menu_button(
f,
min_availability_area,
"Minimum Availability",
selected_minimum_availability.to_display_str(),
selected_block == &ActiveRadarrBlock::AddMovieSelectMinimumAvailability,
);
draw_drop_down_menu_button(
f,
quality_profile_area,
"Quality Profile",
selected_quality_profile,
selected_block == &ActiveRadarrBlock::AddMovieSelectQualityProfile,
);
f.render_widget(root_folder_drop_down_button, root_folder_area);
f.render_widget(monitor_drop_down_button, monitor_area);
f.render_widget(min_availability_drop_down_button, min_availability_area);
f.render_widget(quality_profile_drop_down_button, quality_profile_area);
if let Route::Radarr(active_radarr_block, _) = *app.get_current_route() {
draw_text_box_with_label(
f,
LabeledTextBoxProps {
area: tags_area,
label: "Tags",
text: &tags.text,
offset: *tags.offset.borrow(),
is_selected: selected_block == &ActiveRadarrBlock::AddMovieTagsInput,
should_show_cursor: active_radarr_block == ActiveRadarrBlock::AddMovieTagsInput,
cursor_after_string: true,
},
);
let tags_input_box = InputBox::new(&tags.text)
.offset(*tags.offset.borrow())
.label("Tags")
.highlighted(selected_block == &ActiveRadarrBlock::AddMovieTagsInput)
.selected(active_radarr_block == ActiveRadarrBlock::AddMovieTagsInput);
render_selectable_input_box!(tags_input_box, f, tags_area);
}
draw_button(f, add_area, "Add", yes_no_value && highlight_yes_no);
draw_button(f, cancel_area, "Cancel", !yes_no_value && highlight_yes_no);
let add_button = Button::new()
.title("Add")
.selected(yes_no_value && highlight_yes_no);
let cancel_button = Button::new()
.title("Cancel")
.selected(!yes_no_value && highlight_yes_no);
f.render_widget(add_button, add_area);
f.render_widget(cancel_button, cancel_area);
}
fn draw_add_movie_select_monitor_popup(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
+54 -58
View File
@@ -9,14 +9,18 @@ use crate::models::servarr_data::radarr::radarr_data::{
ActiveRadarrBlock, EDIT_MOVIE_BLOCKS, MOVIE_DETAILS_BLOCKS,
};
use crate::models::Route;
use crate::render_selectable_input_box;
use crate::ui::radarr_ui::library::draw_library;
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::widgets::button::Button;
use crate::ui::widgets::checkbox::Checkbox;
use crate::ui::widgets::input_box::InputBox;
use crate::ui::{
draw_button, draw_checkbox_with_label, draw_drop_down_menu_button, draw_drop_down_popup,
draw_large_popup_over_background_fn_with_ui, draw_medium_popup_over, draw_popup,
draw_selectable_list, draw_text_box_with_label, DrawUi, LabeledTextBoxProps,
draw_drop_down_popup, draw_large_popup_over_background_fn_with_ui,
draw_medium_popup_over, draw_popup, draw_selectable_list, DrawUi,
};
#[cfg(test)]
@@ -123,12 +127,9 @@ fn draw_edit_movie_confirmation_prompt(f: &mut Frame<'_>, app: &mut App<'_>, are
path,
tags,
} = app.data.radarr_data.edit_movie_modal.as_ref().unwrap();
let selected_minimum_availability = minimum_availability_list.current_selection();
let selected_quality_profile = quality_profile_list.current_selection();
f.render_widget(title_block_centered(&title), area);
let [paragraph_area, monitored_area, min_availability_area, quality_profile_area, path_area, tags_area, _, buttons_area] =
Layout::vertical([
Constraint::Length(6),
@@ -142,66 +143,61 @@ fn draw_edit_movie_confirmation_prompt(f: &mut Frame<'_>, app: &mut App<'_>, are
])
.margin(1)
.areas(area);
let prompt_paragraph = layout_paragraph_borderless(&movie_overview);
f.render_widget(prompt_paragraph, paragraph_area);
let [save_area, cancel_area] =
Layout::horizontal([Constraint::Percentage(50), Constraint::Percentage(50)])
.areas(buttons_area);
draw_checkbox_with_label(
f,
monitored_area,
"Monitored",
monitored.unwrap_or_default(),
selected_block == &ActiveRadarrBlock::EditMovieToggleMonitored,
);
draw_drop_down_menu_button(
f,
min_availability_area,
"Minimum Availability",
selected_minimum_availability.to_display_str(),
selected_block == &ActiveRadarrBlock::EditMovieSelectMinimumAvailability,
);
draw_drop_down_menu_button(
f,
quality_profile_area,
"Quality Profile",
selected_quality_profile,
selected_block == &ActiveRadarrBlock::EditMovieSelectQualityProfile,
);
let prompt_paragraph = layout_paragraph_borderless(&movie_overview);
let monitored_checkbox = Checkbox::new("Monitored")
.checked(monitored.unwrap_or_default())
.highlighted(selected_block == &ActiveRadarrBlock::EditMovieToggleMonitored);
let min_availability_drop_down_button = Button::new()
.title(selected_minimum_availability.to_display_str())
.label("Minimum Availability")
.icon("")
.selected(selected_block == &ActiveRadarrBlock::EditMovieSelectMinimumAvailability);
let quality_profile_drop_down_button = Button::new()
.title(selected_quality_profile)
.label("Quality Profile")
.icon("")
.selected(selected_block == &ActiveRadarrBlock::EditMovieSelectQualityProfile);
if let Route::Radarr(active_radarr_block, _) = *app.get_current_route() {
draw_text_box_with_label(
f,
LabeledTextBoxProps {
area: path_area,
label: "Path",
text: &path.text,
offset: *path.offset.borrow(),
is_selected: selected_block == &ActiveRadarrBlock::EditMoviePathInput,
should_show_cursor: active_radarr_block == ActiveRadarrBlock::EditMoviePathInput,
cursor_after_string: true,
},
);
draw_text_box_with_label(
f,
LabeledTextBoxProps {
area: tags_area,
label: "Tags",
text: &tags.text,
offset: *tags.offset.borrow(),
is_selected: selected_block == &ActiveRadarrBlock::EditMovieTagsInput,
should_show_cursor: active_radarr_block == ActiveRadarrBlock::EditMovieTagsInput,
cursor_after_string: true,
},
);
let path_input_box = InputBox::new(&path.text)
.offset(*path.offset.borrow())
.label("Path")
.highlighted(selected_block == &ActiveRadarrBlock::EditMoviePathInput)
.selected(active_radarr_block == ActiveRadarrBlock::EditMoviePathInput);
let tags_input_box = InputBox::new(&tags.text)
.offset(*tags.offset.borrow())
.label("Tags")
.highlighted(selected_block == &ActiveRadarrBlock::EditMovieTagsInput)
.selected(active_radarr_block == ActiveRadarrBlock::EditMovieTagsInput);
match active_radarr_block {
ActiveRadarrBlock::EditMoviePathInput => path_input_box.show_cursor(f, path_area),
ActiveRadarrBlock::EditMovieTagsInput => tags_input_box.show_cursor(f, tags_area),
_ => (),
}
render_selectable_input_box!(path_input_box, f, path_area);
render_selectable_input_box!(tags_input_box, f, tags_area);
}
draw_button(f, save_area, "Save", yes_no_value && highlight_yes_no);
draw_button(f, cancel_area, "Cancel", !yes_no_value && highlight_yes_no);
let save_button = Button::new()
.title("Save")
.selected(yes_no_value && highlight_yes_no);
let cancel_button = Button::new()
.title("Cancel")
.selected(!yes_no_value && highlight_yes_no);
f.render_widget(title_block_centered(&title), area);
f.render_widget(prompt_paragraph, paragraph_area);
f.render_widget(monitored_checkbox, monitored_area);
f.render_widget(min_availability_drop_down_button, min_availability_area);
f.render_widget(quality_profile_drop_down_button, quality_profile_area);
f.render_widget(save_button, save_area);
f.render_widget(cancel_button, cancel_area);
}
fn draw_edit_movie_select_minimum_availability_popup(