refactored managarr table initializer so a mutable app reference can be passed
This commit is contained in:
@@ -103,13 +103,14 @@ fn draw_blocklist_table(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||
])
|
||||
.primary()
|
||||
};
|
||||
let is_sorting = active_sonarr_block == ActiveSonarrBlock::BlocklistSortPrompt;
|
||||
let blocklist_table = ManagarrTable::new(
|
||||
Some(&mut app.data.sonarr_data.blocklist),
|
||||
app,
|
||||
|app| Some(&mut app.data.sonarr_data.blocklist),
|
||||
blocklist_row_mapping,
|
||||
)
|
||||
.block(layout_block_top_border())
|
||||
.loading(app.is_loading)
|
||||
.sorting(active_sonarr_block == ActiveSonarrBlock::BlocklistSortPrompt)
|
||||
.sorting(is_sorting)
|
||||
.headers([
|
||||
"Series Title",
|
||||
"Source Title",
|
||||
|
||||
@@ -72,6 +72,7 @@ fn draw_downloads(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||
} else {
|
||||
app.data.sonarr_data.downloads.current_selection().clone()
|
||||
};
|
||||
let ui_scroll_tick_count = app.ui_scroll_tick_count;
|
||||
|
||||
let downloads_row_mapping = |download_record: &DownloadRecord| {
|
||||
let DownloadRecord {
|
||||
@@ -88,7 +89,7 @@ fn draw_downloads(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||
output_path.as_ref().unwrap().scroll_left_or_reset(
|
||||
get_width_from_percentage(area, 18),
|
||||
current_selection == *download_record,
|
||||
app.ui_scroll_tick_count == 0,
|
||||
ui_scroll_tick_count == 0,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -120,11 +121,11 @@ fn draw_downloads(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||
.primary()
|
||||
};
|
||||
let downloads_table = ManagarrTable::new(
|
||||
Some(&mut app.data.sonarr_data.downloads),
|
||||
app,
|
||||
|app| Some(&mut app.data.sonarr_data.downloads),
|
||||
downloads_row_mapping,
|
||||
)
|
||||
.block(layout_block_top_border())
|
||||
.loading(app.is_loading)
|
||||
.headers([
|
||||
"Title",
|
||||
"Percent Complete",
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
use crate::app::App;
|
||||
use crate::models::Route;
|
||||
use crate::models::servarr_data::sonarr::sonarr_data::{ActiveSonarrBlock, HISTORY_BLOCKS};
|
||||
use crate::models::servarr_models::Language;
|
||||
use crate::models::sonarr_models::{SonarrHistoryEventType, SonarrHistoryItem};
|
||||
use crate::models::Route;
|
||||
use crate::ui::DrawUi;
|
||||
use crate::ui::styles::ManagarrStyle;
|
||||
use crate::ui::utils::{get_width_from_percentage, layout_block_top_border};
|
||||
use crate::ui::widgets::managarr_table::ManagarrTable;
|
||||
use crate::ui::widgets::message::Message;
|
||||
use crate::ui::widgets::popup::{Popup, Size};
|
||||
use crate::ui::DrawUi;
|
||||
use ratatui::Frame;
|
||||
use ratatui::layout::{Alignment, Constraint, Rect};
|
||||
use ratatui::style::Style;
|
||||
use ratatui::text::Text;
|
||||
use ratatui::widgets::{Cell, Row};
|
||||
use ratatui::Frame;
|
||||
|
||||
use super::sonarr_ui_utils::{
|
||||
create_download_failed_history_event_details,
|
||||
@@ -55,6 +55,8 @@ fn draw_history_table(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||
} else {
|
||||
app.data.sonarr_data.history.current_selection().clone()
|
||||
};
|
||||
let ui_scroll_tick_count = app.ui_scroll_tick_count;
|
||||
|
||||
if let Route::Sonarr(active_sonarr_block, _) = app.get_current_route() {
|
||||
let history_row_mapping = |history_item: &SonarrHistoryItem| {
|
||||
let SonarrHistoryItem {
|
||||
@@ -69,7 +71,7 @@ fn draw_history_table(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||
source_title.scroll_left_or_reset(
|
||||
get_width_from_percentage(area, 40),
|
||||
current_selection == *history_item,
|
||||
app.ui_scroll_tick_count == 0,
|
||||
ui_scroll_tick_count == 0,
|
||||
);
|
||||
|
||||
Row::new(vec![
|
||||
@@ -93,23 +95,25 @@ fn draw_history_table(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||
])
|
||||
.primary()
|
||||
};
|
||||
let history_table =
|
||||
ManagarrTable::new(Some(&mut app.data.sonarr_data.history), history_row_mapping)
|
||||
.block(layout_block_top_border())
|
||||
.loading(app.is_loading)
|
||||
.sorting(active_sonarr_block == ActiveSonarrBlock::HistorySortPrompt)
|
||||
.searching(active_sonarr_block == ActiveSonarrBlock::SearchHistory)
|
||||
.search_produced_empty_results(active_sonarr_block == ActiveSonarrBlock::SearchHistoryError)
|
||||
.filtering(active_sonarr_block == ActiveSonarrBlock::FilterHistory)
|
||||
.filter_produced_empty_results(active_sonarr_block == ActiveSonarrBlock::FilterHistoryError)
|
||||
.headers(["Source Title", "Event Type", "Language", "Quality", "Date"])
|
||||
.constraints([
|
||||
Constraint::Percentage(40),
|
||||
Constraint::Percentage(15),
|
||||
Constraint::Percentage(12),
|
||||
Constraint::Percentage(13),
|
||||
Constraint::Percentage(20),
|
||||
]);
|
||||
let history_table = ManagarrTable::new(
|
||||
app,
|
||||
|app| Some(&mut app.data.sonarr_data.history),
|
||||
history_row_mapping,
|
||||
)
|
||||
.block(layout_block_top_border())
|
||||
.sorting(active_sonarr_block == ActiveSonarrBlock::HistorySortPrompt)
|
||||
.searching(active_sonarr_block == ActiveSonarrBlock::SearchHistory)
|
||||
.search_produced_empty_results(active_sonarr_block == ActiveSonarrBlock::SearchHistoryError)
|
||||
.filtering(active_sonarr_block == ActiveSonarrBlock::FilterHistory)
|
||||
.filter_produced_empty_results(active_sonarr_block == ActiveSonarrBlock::FilterHistoryError)
|
||||
.headers(["Source Title", "Event Type", "Language", "Quality", "Date"])
|
||||
.constraints([
|
||||
Constraint::Percentage(40),
|
||||
Constraint::Percentage(15),
|
||||
Constraint::Percentage(12),
|
||||
Constraint::Percentage(13),
|
||||
Constraint::Percentage(20),
|
||||
]);
|
||||
|
||||
if [
|
||||
ActiveSonarrBlock::SearchHistory,
|
||||
|
||||
@@ -111,6 +111,8 @@ impl DrawUi for IndexersUi {
|
||||
}
|
||||
|
||||
fn draw_indexers(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||
let tags_map = app.data.sonarr_data.tags_map.clone();
|
||||
|
||||
let indexers_row_mapping = |indexer: &'_ Indexer| {
|
||||
let Indexer {
|
||||
name,
|
||||
@@ -136,10 +138,7 @@ fn draw_indexers(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||
let tags: String = tags
|
||||
.iter()
|
||||
.map(|tag_id| {
|
||||
app
|
||||
.data
|
||||
.sonarr_data
|
||||
.tags_map
|
||||
tags_map
|
||||
.get_by_left(&tag_id.as_i64().unwrap())
|
||||
.unwrap_or(&empty_tag)
|
||||
.clone()
|
||||
@@ -158,11 +157,11 @@ fn draw_indexers(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||
.primary()
|
||||
};
|
||||
let indexers_table = ManagarrTable::new(
|
||||
Some(&mut app.data.sonarr_data.indexers),
|
||||
app,
|
||||
|app| Some(&mut app.data.sonarr_data.indexers),
|
||||
indexers_row_mapping,
|
||||
)
|
||||
.block(layout_block_top_border())
|
||||
.loading(app.is_loading)
|
||||
.headers([
|
||||
"Indexer",
|
||||
"RSS",
|
||||
|
||||
@@ -39,12 +39,14 @@ fn draw_test_all_indexers_test_results(f: &mut Frame<'_>, app: &mut App<'_>, are
|
||||
} else {
|
||||
IndexerTestResultModalItem::default()
|
||||
};
|
||||
let ui_scroll_tick_count = app.ui_scroll_tick_count;
|
||||
|
||||
f.render_widget(title_block("Test All Indexers"), area);
|
||||
let test_results_row_mapping = |result: &IndexerTestResultModalItem| {
|
||||
result.validation_failures.scroll_left_or_reset(
|
||||
get_width_from_percentage(area, 86),
|
||||
*result == current_selection,
|
||||
app.ui_scroll_tick_count == 0,
|
||||
ui_scroll_tick_count == 0,
|
||||
);
|
||||
let pass_fail = if result.is_valid { "✔" } else { "❌" };
|
||||
let row = Row::new(vec![
|
||||
@@ -61,7 +63,8 @@ fn draw_test_all_indexers_test_results(f: &mut Frame<'_>, app: &mut App<'_>, are
|
||||
};
|
||||
|
||||
let indexers_test_results_table = ManagarrTable::new(
|
||||
app.data.sonarr_data.indexer_test_all_results.as_mut(),
|
||||
app,
|
||||
|app| app.data.sonarr_data.indexer_test_all_results.as_mut(),
|
||||
test_results_row_mapping,
|
||||
)
|
||||
.loading(is_loading)
|
||||
|
||||
@@ -75,13 +75,14 @@ fn draw_add_series_search(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||
Layout::vertical([Constraint::Length(3), Constraint::Fill(0)])
|
||||
.margin(1)
|
||||
.areas(area);
|
||||
let block_content = &app
|
||||
let block_content = app
|
||||
.data
|
||||
.sonarr_data
|
||||
.add_series_search
|
||||
.as_ref()
|
||||
.expect("add_series_search must be populated")
|
||||
.text;
|
||||
.text
|
||||
.clone();
|
||||
let offset = app
|
||||
.data
|
||||
.sonarr_data
|
||||
@@ -90,6 +91,16 @@ fn draw_add_series_search(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||
.expect("add_series_search must be populated")
|
||||
.offset
|
||||
.load(Ordering::SeqCst);
|
||||
let series_tvdb_ids: Vec<_> = app
|
||||
.data
|
||||
.sonarr_data
|
||||
.series
|
||||
.items
|
||||
.iter()
|
||||
.map(|s| s.tvdb_id)
|
||||
.collect();
|
||||
let ui_scroll_tick_count = app.ui_scroll_tick_count;
|
||||
|
||||
let search_results_row_mapping = |series: &AddSeriesSearchResult| {
|
||||
let rating = series.ratings.clone().unwrap_or_default().value;
|
||||
let series_rating = if rating == 0.0 {
|
||||
@@ -97,14 +108,7 @@ fn draw_add_series_search(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||
} else {
|
||||
format!("{rating:.1}")
|
||||
};
|
||||
let in_library = if app
|
||||
.data
|
||||
.sonarr_data
|
||||
.series
|
||||
.items
|
||||
.iter()
|
||||
.any(|mov| mov.tvdb_id == series.tvdb_id)
|
||||
{
|
||||
let in_library = if series_tvdb_ids.contains(&series.tvdb_id) {
|
||||
"✔"
|
||||
} else {
|
||||
""
|
||||
@@ -119,7 +123,7 @@ fn draw_add_series_search(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||
series.title.scroll_left_or_reset(
|
||||
get_width_from_percentage(area, 27),
|
||||
*series == current_selection,
|
||||
app.ui_scroll_tick_count == 0,
|
||||
ui_scroll_tick_count == 0,
|
||||
);
|
||||
|
||||
Row::new(vec![
|
||||
@@ -137,7 +141,7 @@ fn draw_add_series_search(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||
if let Route::Sonarr(active_sonarr_block, _) = app.get_current_route() {
|
||||
match active_sonarr_block {
|
||||
ActiveSonarrBlock::AddSeriesSearchInput => {
|
||||
let search_box = InputBox::new(block_content)
|
||||
let search_box = InputBox::new(&block_content)
|
||||
.offset(offset)
|
||||
.block(title_block_centered("Add Series"));
|
||||
|
||||
@@ -162,7 +166,8 @@ fn draw_add_series_search(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||
| ActiveSonarrBlock::AddSeriesAlreadyInLibrary
|
||||
| ActiveSonarrBlock::AddSeriesTagsInput => {
|
||||
let search_results_table = ManagarrTable::new(
|
||||
app.data.sonarr_data.add_searched_series.as_mut(),
|
||||
app,
|
||||
|app| app.data.sonarr_data.add_searched_series.as_mut(),
|
||||
search_results_row_mapping,
|
||||
)
|
||||
.loading(is_loading)
|
||||
@@ -181,13 +186,20 @@ fn draw_add_series_search(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||
]);
|
||||
|
||||
f.render_widget(search_results_table, results_area);
|
||||
f.render_widget(
|
||||
InputBox::new(&block_content)
|
||||
.offset(offset)
|
||||
.block(title_block_centered("Add Series")),
|
||||
search_box_area,
|
||||
);
|
||||
return;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
f.render_widget(
|
||||
InputBox::new(block_content)
|
||||
InputBox::new(&block_content)
|
||||
.offset(offset)
|
||||
.block(title_block_centered("Add Series")),
|
||||
search_box_area,
|
||||
|
||||
@@ -267,6 +267,7 @@ fn draw_episode_history_table(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect)
|
||||
.current_selection()
|
||||
.clone()
|
||||
};
|
||||
let ui_scroll_tick_count = app.ui_scroll_tick_count;
|
||||
|
||||
let history_row_mapping = |history_item: &SonarrHistoryItem| {
|
||||
let SonarrHistoryItem {
|
||||
@@ -281,7 +282,7 @@ fn draw_episode_history_table(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect)
|
||||
source_title.scroll_left_or_reset(
|
||||
get_width_from_percentage(area, 40),
|
||||
current_selection == *history_item,
|
||||
app.ui_scroll_tick_count == 0,
|
||||
ui_scroll_tick_count == 0,
|
||||
);
|
||||
|
||||
Row::new(vec![
|
||||
@@ -305,28 +306,33 @@ fn draw_episode_history_table(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect)
|
||||
])
|
||||
.primary()
|
||||
};
|
||||
let mut episode_history_table = &mut app
|
||||
.data
|
||||
.sonarr_data
|
||||
.season_details_modal
|
||||
.as_mut()
|
||||
.expect("season_details_modal must exist in this context")
|
||||
.episode_details_modal
|
||||
.as_mut()
|
||||
.expect("episode_details_modal must exist in this context")
|
||||
.episode_history;
|
||||
let history_table =
|
||||
ManagarrTable::new(Some(&mut episode_history_table), history_row_mapping)
|
||||
.block(layout_block_top_border())
|
||||
.loading(app.is_loading)
|
||||
.headers(["Source Title", "Event Type", "Language", "Quality", "Date"])
|
||||
.constraints([
|
||||
Constraint::Percentage(40),
|
||||
Constraint::Percentage(15),
|
||||
Constraint::Percentage(12),
|
||||
Constraint::Percentage(13),
|
||||
Constraint::Percentage(20),
|
||||
]);
|
||||
let history_table = ManagarrTable::new(
|
||||
app,
|
||||
|app| {
|
||||
Some(
|
||||
&mut app
|
||||
.data
|
||||
.sonarr_data
|
||||
.season_details_modal
|
||||
.as_mut()
|
||||
.expect("season_details_modal must exist in this context")
|
||||
.episode_details_modal
|
||||
.as_mut()
|
||||
.expect("episode_details_modal must exist in this context")
|
||||
.episode_history,
|
||||
)
|
||||
},
|
||||
history_row_mapping,
|
||||
)
|
||||
.block(layout_block_top_border())
|
||||
.headers(["Source Title", "Event Type", "Language", "Quality", "Date"])
|
||||
.constraints([
|
||||
Constraint::Percentage(40),
|
||||
Constraint::Percentage(15),
|
||||
Constraint::Percentage(12),
|
||||
Constraint::Percentage(13),
|
||||
Constraint::Percentage(20),
|
||||
]);
|
||||
|
||||
f.render_widget(history_table, area);
|
||||
}
|
||||
@@ -409,6 +415,7 @@ fn draw_episode_releases(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||
episode_details_modal.episode_releases.is_empty(),
|
||||
)
|
||||
};
|
||||
let ui_scroll_tick_count = app.ui_scroll_tick_count;
|
||||
|
||||
if let Route::Sonarr(active_sonarr_block, _) = app.get_current_route() {
|
||||
let episode_release_row_mapping = |release: &SonarrRelease| {
|
||||
@@ -431,7 +438,7 @@ fn draw_episode_releases(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||
get_width_from_percentage(area, 30),
|
||||
current_selection == *release
|
||||
&& active_sonarr_block != ActiveSonarrBlock::ManualEpisodeSearchConfirmPrompt,
|
||||
app.ui_scroll_tick_count == 0,
|
||||
ui_scroll_tick_count == 0,
|
||||
);
|
||||
let size = convert_to_gb(*size);
|
||||
let rejected_str = if *rejected { "⛔" } else { "" };
|
||||
@@ -480,22 +487,26 @@ fn draw_episode_releases(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||
])
|
||||
.primary()
|
||||
};
|
||||
let mut episode_release_table = &mut app
|
||||
.data
|
||||
.sonarr_data
|
||||
.season_details_modal
|
||||
.as_mut()
|
||||
.expect("season_details_modal must exist in this context")
|
||||
.episode_details_modal
|
||||
.as_mut()
|
||||
.expect("episode_details_modal must exist in this context")
|
||||
.episode_releases;
|
||||
let release_table = ManagarrTable::new(
|
||||
Some(&mut episode_release_table),
|
||||
app,
|
||||
|app| {
|
||||
Some(
|
||||
&mut app
|
||||
.data
|
||||
.sonarr_data
|
||||
.season_details_modal
|
||||
.as_mut()
|
||||
.expect("season_details_modal must exist in this context")
|
||||
.episode_details_modal
|
||||
.as_mut()
|
||||
.expect("episode_details_modal must exist in this context")
|
||||
.episode_releases,
|
||||
)
|
||||
},
|
||||
episode_release_row_mapping,
|
||||
)
|
||||
.block(layout_block_top_border())
|
||||
.loading(app.is_loading || is_empty)
|
||||
.loading(is_empty)
|
||||
.sorting(active_sonarr_block == ActiveSonarrBlock::ManualEpisodeSearchSortPrompt)
|
||||
.headers([
|
||||
"Source", "Age", "⛔", "Title", "Indexer", "Size", "Peers", "Language", "Quality",
|
||||
|
||||
@@ -2,9 +2,9 @@ use add_series_ui::AddSeriesUi;
|
||||
use delete_series_ui::DeleteSeriesUi;
|
||||
use edit_series_ui::EditSeriesUi;
|
||||
use ratatui::{
|
||||
Frame,
|
||||
layout::{Constraint, Rect},
|
||||
widgets::{Cell, Row},
|
||||
Frame,
|
||||
};
|
||||
use series_details_ui::SeriesDetailsUi;
|
||||
|
||||
@@ -16,15 +16,15 @@ use crate::utils::convert_to_gb;
|
||||
use crate::{
|
||||
app::App,
|
||||
models::{
|
||||
Route,
|
||||
servarr_data::sonarr::sonarr_data::{ActiveSonarrBlock, LIBRARY_BLOCKS},
|
||||
sonarr_models::{Series, SeriesStatus},
|
||||
Route,
|
||||
},
|
||||
ui::{
|
||||
DrawUi,
|
||||
styles::ManagarrStyle,
|
||||
utils::{get_width_from_percentage, layout_block_top_border},
|
||||
widgets::managarr_table::ManagarrTable,
|
||||
DrawUi,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -86,16 +86,16 @@ fn draw_library(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||
} else {
|
||||
Series::default()
|
||||
};
|
||||
let quality_profile_map = &app.data.sonarr_data.quality_profile_map;
|
||||
let language_profile_map = &app.data.sonarr_data.language_profiles_map;
|
||||
let tags_map = &app.data.sonarr_data.tags_map;
|
||||
let content = Some(&mut app.data.sonarr_data.series);
|
||||
let quality_profile_map = app.data.sonarr_data.quality_profile_map.clone();
|
||||
let language_profile_map = app.data.sonarr_data.language_profiles_map.clone();
|
||||
let tags_map = app.data.sonarr_data.tags_map.clone();
|
||||
let ui_scroll_tick_count = app.ui_scroll_tick_count;
|
||||
|
||||
let series_table_row_mapping = |series: &Series| {
|
||||
series.title.scroll_left_or_reset(
|
||||
get_width_from_percentage(area, 23),
|
||||
*series == current_selection,
|
||||
app.ui_scroll_tick_count == 0,
|
||||
ui_scroll_tick_count == 0,
|
||||
);
|
||||
let monitored = if series.monitored { "🏷" } else { "" };
|
||||
let certification = series.certification.clone().unwrap_or_default();
|
||||
@@ -139,40 +139,43 @@ fn draw_library(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||
]),
|
||||
)
|
||||
};
|
||||
let series_table = ManagarrTable::new(content, series_table_row_mapping)
|
||||
.block(layout_block_top_border())
|
||||
.loading(app.is_loading)
|
||||
.sorting(active_sonarr_block == ActiveSonarrBlock::SeriesSortPrompt)
|
||||
.searching(active_sonarr_block == ActiveSonarrBlock::SearchSeries)
|
||||
.filtering(active_sonarr_block == ActiveSonarrBlock::FilterSeries)
|
||||
.search_produced_empty_results(active_sonarr_block == ActiveSonarrBlock::SearchSeriesError)
|
||||
.filter_produced_empty_results(active_sonarr_block == ActiveSonarrBlock::FilterSeriesError)
|
||||
.headers([
|
||||
"Title",
|
||||
"Year",
|
||||
"Network",
|
||||
"Status",
|
||||
"Rating",
|
||||
"Type",
|
||||
"Quality Profile",
|
||||
"Language",
|
||||
"Size",
|
||||
"Monitored",
|
||||
"Tags",
|
||||
])
|
||||
.constraints([
|
||||
Constraint::Percentage(20),
|
||||
Constraint::Percentage(4),
|
||||
Constraint::Percentage(14),
|
||||
Constraint::Percentage(6),
|
||||
Constraint::Percentage(6),
|
||||
Constraint::Percentage(6),
|
||||
Constraint::Percentage(11),
|
||||
Constraint::Percentage(8),
|
||||
Constraint::Percentage(7),
|
||||
Constraint::Percentage(6),
|
||||
Constraint::Percentage(12),
|
||||
]);
|
||||
let series_table = ManagarrTable::new(
|
||||
app,
|
||||
|app| Some(&mut app.data.sonarr_data.series),
|
||||
series_table_row_mapping,
|
||||
)
|
||||
.block(layout_block_top_border())
|
||||
.sorting(active_sonarr_block == ActiveSonarrBlock::SeriesSortPrompt)
|
||||
.searching(active_sonarr_block == ActiveSonarrBlock::SearchSeries)
|
||||
.filtering(active_sonarr_block == ActiveSonarrBlock::FilterSeries)
|
||||
.search_produced_empty_results(active_sonarr_block == ActiveSonarrBlock::SearchSeriesError)
|
||||
.filter_produced_empty_results(active_sonarr_block == ActiveSonarrBlock::FilterSeriesError)
|
||||
.headers([
|
||||
"Title",
|
||||
"Year",
|
||||
"Network",
|
||||
"Status",
|
||||
"Rating",
|
||||
"Type",
|
||||
"Quality Profile",
|
||||
"Language",
|
||||
"Size",
|
||||
"Monitored",
|
||||
"Tags",
|
||||
])
|
||||
.constraints([
|
||||
Constraint::Percentage(20),
|
||||
Constraint::Percentage(4),
|
||||
Constraint::Percentage(14),
|
||||
Constraint::Percentage(6),
|
||||
Constraint::Percentage(6),
|
||||
Constraint::Percentage(6),
|
||||
Constraint::Percentage(11),
|
||||
Constraint::Percentage(8),
|
||||
Constraint::Percentage(7),
|
||||
Constraint::Percentage(6),
|
||||
Constraint::Percentage(12),
|
||||
]);
|
||||
|
||||
if [
|
||||
ActiveSonarrBlock::SearchSeries,
|
||||
|
||||
@@ -162,16 +162,7 @@ fn draw_episodes_table(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||
.episode_files
|
||||
.items
|
||||
.clone();
|
||||
let content = Some(
|
||||
&mut app
|
||||
.data
|
||||
.sonarr_data
|
||||
.season_details_modal
|
||||
.as_mut()
|
||||
.expect("Season details modal is unpopulated")
|
||||
.episodes,
|
||||
);
|
||||
let downloads_vec = &app.data.sonarr_data.downloads.items;
|
||||
let downloads_vec = app.data.sonarr_data.downloads.items.clone();
|
||||
|
||||
let episode_row_mapping = |episode: &Episode| {
|
||||
let Episode {
|
||||
@@ -202,7 +193,7 @@ fn draw_episodes_table(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||
};
|
||||
|
||||
decorate_with_row_style(
|
||||
downloads_vec,
|
||||
&downloads_vec,
|
||||
episode,
|
||||
Row::new(vec![
|
||||
Cell::from(episode_monitored.to_owned()),
|
||||
@@ -215,27 +206,40 @@ fn draw_episodes_table(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||
)
|
||||
};
|
||||
let is_searching = active_sonarr_block == ActiveSonarrBlock::SearchEpisodes;
|
||||
let season_table = ManagarrTable::new(content, episode_row_mapping)
|
||||
.block(layout_block_top_border())
|
||||
.loading(app.is_loading)
|
||||
.searching(is_searching)
|
||||
.search_produced_empty_results(active_sonarr_block == ActiveSonarrBlock::SearchEpisodesError)
|
||||
.headers([
|
||||
"🏷",
|
||||
"#",
|
||||
"Title",
|
||||
"Air Date",
|
||||
"Size on Disk",
|
||||
"Quality Profile",
|
||||
])
|
||||
.constraints([
|
||||
Constraint::Percentage(4),
|
||||
Constraint::Percentage(4),
|
||||
Constraint::Percentage(50),
|
||||
Constraint::Percentage(19),
|
||||
Constraint::Percentage(10),
|
||||
Constraint::Percentage(12),
|
||||
]);
|
||||
let season_table = ManagarrTable::new(
|
||||
app,
|
||||
|app| {
|
||||
Some(
|
||||
&mut app
|
||||
.data
|
||||
.sonarr_data
|
||||
.season_details_modal
|
||||
.as_mut()
|
||||
.expect("Season details modal is unpopulated")
|
||||
.episodes,
|
||||
)
|
||||
},
|
||||
episode_row_mapping,
|
||||
)
|
||||
.block(layout_block_top_border())
|
||||
.searching(is_searching)
|
||||
.search_produced_empty_results(active_sonarr_block == ActiveSonarrBlock::SearchEpisodesError)
|
||||
.headers([
|
||||
"🏷",
|
||||
"#",
|
||||
"Title",
|
||||
"Air Date",
|
||||
"Size on Disk",
|
||||
"Quality Profile",
|
||||
])
|
||||
.constraints([
|
||||
Constraint::Percentage(4),
|
||||
Constraint::Percentage(4),
|
||||
Constraint::Percentage(50),
|
||||
Constraint::Percentage(19),
|
||||
Constraint::Percentage(10),
|
||||
Constraint::Percentage(12),
|
||||
]);
|
||||
|
||||
if is_searching {
|
||||
season_table.show_cursor(f, area);
|
||||
@@ -256,6 +260,7 @@ fn draw_season_history_table(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||
.current_selection()
|
||||
.clone()
|
||||
};
|
||||
let ui_scroll_tick_count = app.ui_scroll_tick_count;
|
||||
|
||||
if let Route::Sonarr(active_sonarr_block, _) = app.get_current_route() {
|
||||
let history_row_mapping = |history_item: &SonarrHistoryItem| {
|
||||
@@ -271,7 +276,7 @@ fn draw_season_history_table(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||
source_title.scroll_left_or_reset(
|
||||
get_width_from_percentage(area, 40),
|
||||
current_selection == *history_item,
|
||||
app.ui_scroll_tick_count == 0,
|
||||
ui_scroll_tick_count == 0,
|
||||
);
|
||||
|
||||
Row::new(vec![
|
||||
@@ -295,34 +300,39 @@ fn draw_season_history_table(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||
])
|
||||
.primary()
|
||||
};
|
||||
let mut season_history_table = &mut app
|
||||
.data
|
||||
.sonarr_data
|
||||
.season_details_modal
|
||||
.as_mut()
|
||||
.expect("season_details_modal must exist in this context")
|
||||
.season_history;
|
||||
let history_table =
|
||||
ManagarrTable::new(Some(&mut season_history_table), history_row_mapping)
|
||||
.block(layout_block_top_border())
|
||||
.loading(app.is_loading)
|
||||
.sorting(active_sonarr_block == ActiveSonarrBlock::SeasonHistorySortPrompt)
|
||||
.searching(active_sonarr_block == ActiveSonarrBlock::SearchSeasonHistory)
|
||||
.search_produced_empty_results(
|
||||
active_sonarr_block == ActiveSonarrBlock::SearchSeasonHistoryError,
|
||||
let history_table = ManagarrTable::new(
|
||||
app,
|
||||
|app| {
|
||||
Some(
|
||||
&mut app
|
||||
.data
|
||||
.sonarr_data
|
||||
.season_details_modal
|
||||
.as_mut()
|
||||
.expect("season_details_modal must exist in this context")
|
||||
.season_history,
|
||||
)
|
||||
.filtering(active_sonarr_block == ActiveSonarrBlock::FilterSeasonHistory)
|
||||
.filter_produced_empty_results(
|
||||
active_sonarr_block == ActiveSonarrBlock::FilterSeasonHistoryError,
|
||||
)
|
||||
.headers(["Source Title", "Event Type", "Language", "Quality", "Date"])
|
||||
.constraints([
|
||||
Constraint::Percentage(40),
|
||||
Constraint::Percentage(15),
|
||||
Constraint::Percentage(12),
|
||||
Constraint::Percentage(13),
|
||||
Constraint::Percentage(20),
|
||||
]);
|
||||
},
|
||||
history_row_mapping,
|
||||
)
|
||||
.block(layout_block_top_border())
|
||||
.sorting(active_sonarr_block == ActiveSonarrBlock::SeasonHistorySortPrompt)
|
||||
.searching(active_sonarr_block == ActiveSonarrBlock::SearchSeasonHistory)
|
||||
.search_produced_empty_results(
|
||||
active_sonarr_block == ActiveSonarrBlock::SearchSeasonHistoryError,
|
||||
)
|
||||
.filtering(active_sonarr_block == ActiveSonarrBlock::FilterSeasonHistory)
|
||||
.filter_produced_empty_results(
|
||||
active_sonarr_block == ActiveSonarrBlock::FilterSeasonHistoryError,
|
||||
)
|
||||
.headers(["Source Title", "Event Type", "Language", "Quality", "Date"])
|
||||
.constraints([
|
||||
Constraint::Percentage(40),
|
||||
Constraint::Percentage(15),
|
||||
Constraint::Percentage(12),
|
||||
Constraint::Percentage(13),
|
||||
Constraint::Percentage(20),
|
||||
]);
|
||||
|
||||
if [
|
||||
ActiveSonarrBlock::SearchSeriesHistory,
|
||||
@@ -360,6 +370,7 @@ fn draw_season_releases(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||
season_details_modal.season_releases.is_empty(),
|
||||
)
|
||||
};
|
||||
let ui_scroll_tick_count = app.ui_scroll_tick_count;
|
||||
|
||||
if let Route::Sonarr(active_sonarr_block, _) = app.get_current_route() {
|
||||
let season_release_row_mapping = |release: &SonarrRelease| {
|
||||
@@ -382,7 +393,7 @@ fn draw_season_releases(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||
get_width_from_percentage(area, 30),
|
||||
current_selection == *release
|
||||
&& active_sonarr_block != ActiveSonarrBlock::ManualSeasonSearchConfirmPrompt,
|
||||
app.ui_scroll_tick_count == 0,
|
||||
ui_scroll_tick_count == 0,
|
||||
);
|
||||
let size = convert_to_gb(*size);
|
||||
let rejected_str = if *rejected { "⛔" } else { "" };
|
||||
@@ -431,32 +442,38 @@ fn draw_season_releases(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||
])
|
||||
.primary()
|
||||
};
|
||||
let mut season_release_table = &mut app
|
||||
.data
|
||||
.sonarr_data
|
||||
.season_details_modal
|
||||
.as_mut()
|
||||
.expect("season_details_modal must exist in this context")
|
||||
.season_releases;
|
||||
let release_table =
|
||||
ManagarrTable::new(Some(&mut season_release_table), season_release_row_mapping)
|
||||
.block(layout_block_top_border())
|
||||
.loading(app.is_loading || is_empty)
|
||||
.sorting(active_sonarr_block == ActiveSonarrBlock::ManualSeasonSearchSortPrompt)
|
||||
.headers([
|
||||
"Source", "Age", "⛔", "Title", "Indexer", "Size", "Peers", "Language", "Quality",
|
||||
])
|
||||
.constraints([
|
||||
Constraint::Length(9),
|
||||
Constraint::Length(10),
|
||||
Constraint::Length(5),
|
||||
Constraint::Percentage(30),
|
||||
Constraint::Percentage(18),
|
||||
Constraint::Length(12),
|
||||
Constraint::Length(12),
|
||||
Constraint::Percentage(7),
|
||||
Constraint::Percentage(10),
|
||||
]);
|
||||
let release_table = ManagarrTable::new(
|
||||
app,
|
||||
|app| {
|
||||
Some(
|
||||
&mut app
|
||||
.data
|
||||
.sonarr_data
|
||||
.season_details_modal
|
||||
.as_mut()
|
||||
.expect("season_details_modal must exist in this context")
|
||||
.season_releases,
|
||||
)
|
||||
},
|
||||
season_release_row_mapping,
|
||||
)
|
||||
.block(layout_block_top_border())
|
||||
.loading(is_empty)
|
||||
.sorting(active_sonarr_block == ActiveSonarrBlock::ManualSeasonSearchSortPrompt)
|
||||
.headers([
|
||||
"Source", "Age", "⛔", "Title", "Indexer", "Size", "Peers", "Language", "Quality",
|
||||
])
|
||||
.constraints([
|
||||
Constraint::Length(9),
|
||||
Constraint::Length(10),
|
||||
Constraint::Length(5),
|
||||
Constraint::Percentage(30),
|
||||
Constraint::Percentage(18),
|
||||
Constraint::Length(12),
|
||||
Constraint::Length(12),
|
||||
Constraint::Percentage(7),
|
||||
Constraint::Percentage(10),
|
||||
]);
|
||||
|
||||
f.render_widget(release_table, area);
|
||||
}
|
||||
|
||||
@@ -228,7 +228,6 @@ pub fn draw_series_details(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||
|
||||
fn draw_seasons_table(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||
if let Route::Sonarr(active_sonarr_block, _) = app.get_current_route() {
|
||||
let content = Some(&mut app.data.sonarr_data.seasons);
|
||||
let season_row_mapping = |season: &Season| {
|
||||
let Season {
|
||||
title,
|
||||
@@ -271,18 +270,21 @@ fn draw_seasons_table(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||
}
|
||||
};
|
||||
let is_searching = active_sonarr_block == ActiveSonarrBlock::SearchSeason;
|
||||
let season_table = ManagarrTable::new(content, season_row_mapping)
|
||||
.block(layout_block_top_border())
|
||||
.loading(app.is_loading)
|
||||
.searching(is_searching)
|
||||
.search_produced_empty_results(active_sonarr_block == ActiveSonarrBlock::SearchSeasonError)
|
||||
.headers(["Monitored", "Season", "Episode Count", "Size on Disk"])
|
||||
.constraints([
|
||||
Constraint::Percentage(6),
|
||||
Constraint::Ratio(1, 3),
|
||||
Constraint::Ratio(1, 3),
|
||||
Constraint::Ratio(1, 3),
|
||||
]);
|
||||
let season_table = ManagarrTable::new(
|
||||
app,
|
||||
|app| Some(&mut app.data.sonarr_data.seasons),
|
||||
season_row_mapping,
|
||||
)
|
||||
.block(layout_block_top_border())
|
||||
.searching(is_searching)
|
||||
.search_produced_empty_results(active_sonarr_block == ActiveSonarrBlock::SearchSeasonError)
|
||||
.headers(["Monitored", "Season", "Episode Count", "Size on Disk"])
|
||||
.constraints([
|
||||
Constraint::Percentage(6),
|
||||
Constraint::Ratio(1, 3),
|
||||
Constraint::Ratio(1, 3),
|
||||
Constraint::Ratio(1, 3),
|
||||
]);
|
||||
|
||||
if is_searching {
|
||||
season_table.show_cursor(f, area);
|
||||
@@ -300,6 +302,7 @@ fn draw_series_history_table(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||
} else {
|
||||
series_history.current_selection().clone()
|
||||
};
|
||||
let ui_scroll_tick_count = app.ui_scroll_tick_count;
|
||||
|
||||
if let Route::Sonarr(active_sonarr_block, _) = app.get_current_route() {
|
||||
let history_row_mapping = |history_item: &SonarrHistoryItem| {
|
||||
@@ -315,7 +318,7 @@ fn draw_series_history_table(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||
source_title.scroll_left_or_reset(
|
||||
get_width_from_percentage(area, 40),
|
||||
current_selection == *history_item,
|
||||
app.ui_scroll_tick_count == 0,
|
||||
ui_scroll_tick_count == 0,
|
||||
);
|
||||
|
||||
Row::new(vec![
|
||||
@@ -339,33 +342,29 @@ fn draw_series_history_table(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||
])
|
||||
.primary()
|
||||
};
|
||||
let mut series_history_table = app
|
||||
.data
|
||||
.sonarr_data
|
||||
.series_history
|
||||
.as_mut()
|
||||
.expect("series_history must be populated");
|
||||
let history_table =
|
||||
ManagarrTable::new(Some(&mut series_history_table), history_row_mapping)
|
||||
.block(layout_block_top_border())
|
||||
.loading(app.is_loading)
|
||||
.sorting(active_sonarr_block == ActiveSonarrBlock::SeriesHistorySortPrompt)
|
||||
.searching(active_sonarr_block == ActiveSonarrBlock::SearchSeriesHistory)
|
||||
.search_produced_empty_results(
|
||||
active_sonarr_block == ActiveSonarrBlock::SearchSeriesHistoryError,
|
||||
)
|
||||
.filtering(active_sonarr_block == ActiveSonarrBlock::FilterSeriesHistory)
|
||||
.filter_produced_empty_results(
|
||||
active_sonarr_block == ActiveSonarrBlock::FilterSeriesHistoryError,
|
||||
)
|
||||
.headers(["Source Title", "Event Type", "Language", "Quality", "Date"])
|
||||
.constraints([
|
||||
Constraint::Percentage(40),
|
||||
Constraint::Percentage(15),
|
||||
Constraint::Percentage(12),
|
||||
Constraint::Percentage(13),
|
||||
Constraint::Percentage(20),
|
||||
]);
|
||||
let history_table = ManagarrTable::new(
|
||||
app,
|
||||
|app| app.data.sonarr_data.series_history.as_mut(),
|
||||
history_row_mapping,
|
||||
)
|
||||
.block(layout_block_top_border())
|
||||
.sorting(active_sonarr_block == ActiveSonarrBlock::SeriesHistorySortPrompt)
|
||||
.searching(active_sonarr_block == ActiveSonarrBlock::SearchSeriesHistory)
|
||||
.search_produced_empty_results(
|
||||
active_sonarr_block == ActiveSonarrBlock::SearchSeriesHistoryError,
|
||||
)
|
||||
.filtering(active_sonarr_block == ActiveSonarrBlock::FilterSeriesHistory)
|
||||
.filter_produced_empty_results(
|
||||
active_sonarr_block == ActiveSonarrBlock::FilterSeriesHistoryError,
|
||||
)
|
||||
.headers(["Source Title", "Event Type", "Language", "Quality", "Date"])
|
||||
.constraints([
|
||||
Constraint::Percentage(40),
|
||||
Constraint::Percentage(15),
|
||||
Constraint::Percentage(12),
|
||||
Constraint::Percentage(13),
|
||||
Constraint::Percentage(20),
|
||||
]);
|
||||
|
||||
if [
|
||||
ActiveSonarrBlock::SearchSeriesHistory,
|
||||
|
||||
@@ -84,11 +84,11 @@ fn draw_root_folders(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||
};
|
||||
|
||||
let root_folders_table = ManagarrTable::new(
|
||||
Some(&mut app.data.sonarr_data.root_folders),
|
||||
app,
|
||||
|app| Some(&mut app.data.sonarr_data.root_folders),
|
||||
root_folders_row_mapping,
|
||||
)
|
||||
.block(layout_block_top_border())
|
||||
.loading(app.is_loading)
|
||||
.headers(["Path", "Free Space", "Unmapped Folders"])
|
||||
.constraints([
|
||||
Constraint::Ratio(3, 5),
|
||||
|
||||
@@ -89,12 +89,15 @@ fn draw_tasks(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||
])
|
||||
.primary()
|
||||
};
|
||||
let tasks_table = ManagarrTable::new(Some(&mut app.data.sonarr_data.tasks), tasks_row_mapping)
|
||||
.block(title_block("Tasks"))
|
||||
.loading(app.is_loading)
|
||||
.highlight_rows(false)
|
||||
.headers(TASK_TABLE_HEADERS)
|
||||
.constraints(TASK_TABLE_CONSTRAINTS);
|
||||
let tasks_table = ManagarrTable::new(
|
||||
app,
|
||||
|app| Some(&mut app.data.sonarr_data.tasks),
|
||||
tasks_row_mapping,
|
||||
)
|
||||
.block(title_block("Tasks"))
|
||||
.highlight_rows(false)
|
||||
.headers(TASK_TABLE_HEADERS)
|
||||
.constraints(TASK_TABLE_CONSTRAINTS);
|
||||
|
||||
f.render_widget(tasks_table, area);
|
||||
}
|
||||
@@ -137,11 +140,11 @@ pub(super) fn draw_queued_events(f: &mut Frame<'_>, app: &mut App<'_>, area: Rec
|
||||
.primary()
|
||||
};
|
||||
let events_table = ManagarrTable::new(
|
||||
Some(&mut app.data.sonarr_data.queued_events),
|
||||
app,
|
||||
|app| Some(&mut app.data.sonarr_data.queued_events),
|
||||
events_row_mapping,
|
||||
)
|
||||
.block(title_block("Queued Events"))
|
||||
.loading(app.is_loading)
|
||||
.highlight_rows(false)
|
||||
.headers(["Trigger", "Status", "Name", "Queued", "Started", "Duration"])
|
||||
.constraints([
|
||||
|
||||
@@ -92,27 +92,35 @@ fn draw_tasks_popup(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||
])
|
||||
.primary()
|
||||
};
|
||||
let tasks_table = ManagarrTable::new(Some(&mut app.data.sonarr_data.tasks), tasks_row_mapping)
|
||||
.loading(app.is_loading)
|
||||
.margin(1)
|
||||
.headers(TASK_TABLE_HEADERS)
|
||||
.constraints(TASK_TABLE_CONSTRAINTS);
|
||||
let current_route = app.get_current_route();
|
||||
let prompt_confirm = app.data.sonarr_data.prompt_confirm;
|
||||
let task_name = if app.data.sonarr_data.tasks.items.is_empty() {
|
||||
String::new()
|
||||
} else {
|
||||
app.data.sonarr_data.tasks.current_selection().name.clone()
|
||||
};
|
||||
|
||||
let tasks_table = ManagarrTable::new(
|
||||
app,
|
||||
|app| Some(&mut app.data.sonarr_data.tasks),
|
||||
tasks_row_mapping,
|
||||
)
|
||||
.margin(1)
|
||||
.headers(TASK_TABLE_HEADERS)
|
||||
.constraints(TASK_TABLE_CONSTRAINTS);
|
||||
|
||||
f.render_widget(title_block("Tasks"), area);
|
||||
f.render_widget(tasks_table, area);
|
||||
|
||||
if matches!(
|
||||
app.get_current_route(),
|
||||
current_route,
|
||||
Route::Sonarr(ActiveSonarrBlock::SystemTaskStartConfirmPrompt, _)
|
||||
) {
|
||||
let prompt = format!(
|
||||
"Do you want to manually start this task: {}?",
|
||||
app.data.sonarr_data.tasks.current_selection().name
|
||||
);
|
||||
let prompt = format!("Do you want to manually start this task: {}?", task_name);
|
||||
let confirmation_prompt = ConfirmationPrompt::new()
|
||||
.title("Start Task")
|
||||
.prompt(&prompt)
|
||||
.yes_no_value(app.data.sonarr_data.prompt_confirm);
|
||||
.yes_no_value(prompt_confirm);
|
||||
|
||||
f.render_widget(
|
||||
Popup::new(confirmation_prompt).size(Size::MediumPrompt),
|
||||
|
||||
Reference in New Issue
Block a user