feat(ui): Support for the Series table
This commit is contained in:
@@ -12,7 +12,7 @@ mod tests {
|
|||||||
use crate::handlers::sonarr_handlers::library::{series_sorting_options, LibraryHandler};
|
use crate::handlers::sonarr_handlers::library::{series_sorting_options, LibraryHandler};
|
||||||
use crate::handlers::KeyEventHandler;
|
use crate::handlers::KeyEventHandler;
|
||||||
use crate::models::servarr_data::sonarr::sonarr_data::{ActiveSonarrBlock, SERIES_BLOCKS};
|
use crate::models::servarr_data::sonarr::sonarr_data::{ActiveSonarrBlock, SERIES_BLOCKS};
|
||||||
use crate::models::sonarr_models::{Series, SeriesType};
|
use crate::models::sonarr_models::{Series, SeriesStatus, SeriesType};
|
||||||
use crate::models::stateful_table::SortOption;
|
use crate::models::stateful_table::SortOption;
|
||||||
use crate::models::HorizontallyScrollableText;
|
use crate::models::HorizontallyScrollableText;
|
||||||
|
|
||||||
@@ -1563,8 +1563,13 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_series_sorting_options_runtime() {
|
fn test_series_sorting_options_status() {
|
||||||
let expected_cmp_fn: fn(&Series, &Series) -> Ordering = |a, b| a.runtime.cmp(&b.runtime);
|
let expected_cmp_fn: fn(&Series, &Series) -> Ordering = |a, b| {
|
||||||
|
a.status
|
||||||
|
.to_string()
|
||||||
|
.to_lowercase()
|
||||||
|
.cmp(&b.status.to_string().to_lowercase())
|
||||||
|
};
|
||||||
let mut expected_series_vec = series_vec();
|
let mut expected_series_vec = series_vec();
|
||||||
expected_series_vec.sort_by(expected_cmp_fn);
|
expected_series_vec.sort_by(expected_cmp_fn);
|
||||||
|
|
||||||
@@ -1573,7 +1578,7 @@ mod tests {
|
|||||||
sorted_series_vec.sort_by(sort_option.cmp_fn.unwrap());
|
sorted_series_vec.sort_by(sort_option.cmp_fn.unwrap());
|
||||||
|
|
||||||
assert_eq!(sorted_series_vec, expected_series_vec);
|
assert_eq!(sorted_series_vec, expected_series_vec);
|
||||||
assert_str_eq!(sort_option.name, "Runtime");
|
assert_str_eq!(sort_option.name, "Status");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -1766,7 +1771,7 @@ mod tests {
|
|||||||
year: 2024,
|
year: 2024,
|
||||||
monitored: false,
|
monitored: false,
|
||||||
season_folder: false,
|
season_folder: false,
|
||||||
runtime: 12.into(),
|
status: SeriesStatus::Ended,
|
||||||
quality_profile_id: 1,
|
quality_profile_id: 1,
|
||||||
language_profile_id: 1,
|
language_profile_id: 1,
|
||||||
certification: Some("TV-MA".to_owned()),
|
certification: Some("TV-MA".to_owned()),
|
||||||
@@ -1781,7 +1786,7 @@ mod tests {
|
|||||||
year: 1998,
|
year: 1998,
|
||||||
monitored: false,
|
monitored: false,
|
||||||
season_folder: false,
|
season_folder: false,
|
||||||
runtime: 60.into(),
|
status: SeriesStatus::Continuing,
|
||||||
quality_profile_id: 2,
|
quality_profile_id: 2,
|
||||||
language_profile_id: 2,
|
language_profile_id: 2,
|
||||||
certification: Some("TV-PG".to_owned()),
|
certification: Some("TV-PG".to_owned()),
|
||||||
@@ -1796,7 +1801,7 @@ mod tests {
|
|||||||
year: 1954,
|
year: 1954,
|
||||||
monitored: true,
|
monitored: true,
|
||||||
season_folder: false,
|
season_folder: false,
|
||||||
runtime: 120.into(),
|
status: SeriesStatus::Upcoming,
|
||||||
quality_profile_id: 3,
|
quality_profile_id: 3,
|
||||||
language_profile_id: 3,
|
language_profile_id: 3,
|
||||||
certification: Some("TV-G".to_owned()),
|
certification: Some("TV-G".to_owned()),
|
||||||
|
|||||||
@@ -403,8 +403,13 @@ fn series_sorting_options() -> Vec<SortOption<Series>> {
|
|||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
SortOption {
|
SortOption {
|
||||||
name: "Runtime",
|
name: "Status",
|
||||||
cmp_fn: Some(|a, b| a.runtime.cmp(&b.runtime)),
|
cmp_fn: Some(|a, b| {
|
||||||
|
a.status
|
||||||
|
.to_string()
|
||||||
|
.to_lowercase()
|
||||||
|
.cmp(&b.status.to_string().to_lowercase())
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
SortOption {
|
SortOption {
|
||||||
name: "Rating",
|
name: "Rating",
|
||||||
|
|||||||
@@ -4,6 +4,11 @@ use ratatui::{
|
|||||||
Frame,
|
Frame,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use crate::ui::widgets::{
|
||||||
|
confirmation_prompt::ConfirmationPrompt,
|
||||||
|
message::Message,
|
||||||
|
popup::{Popup, Size},
|
||||||
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
app::App,
|
app::App,
|
||||||
models::{
|
models::{
|
||||||
@@ -12,12 +17,12 @@ use crate::{
|
|||||||
EnumDisplayStyle, Route,
|
EnumDisplayStyle, Route,
|
||||||
},
|
},
|
||||||
ui::{
|
ui::{
|
||||||
|
draw_input_box_popup, draw_popup_over,
|
||||||
styles::ManagarrStyle,
|
styles::ManagarrStyle,
|
||||||
utils::{get_width_from_percentage, layout_block_top_border},
|
utils::{get_width_from_percentage, layout_block_top_border},
|
||||||
widgets::managarr_table::ManagarrTable,
|
widgets::managarr_table::ManagarrTable,
|
||||||
DrawUi,
|
DrawUi,
|
||||||
},
|
},
|
||||||
utils::convert_runtime,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@@ -40,6 +45,44 @@ impl DrawUi for LibraryUi {
|
|||||||
let mut series_ui_matchers = |active_sonarr_block: ActiveSonarrBlock| match active_sonarr_block
|
let mut series_ui_matchers = |active_sonarr_block: ActiveSonarrBlock| match active_sonarr_block
|
||||||
{
|
{
|
||||||
ActiveSonarrBlock::Series | ActiveSonarrBlock::SeriesSortPrompt => draw_series(f, app, area),
|
ActiveSonarrBlock::Series | ActiveSonarrBlock::SeriesSortPrompt => draw_series(f, app, area),
|
||||||
|
ActiveSonarrBlock::SearchSeries => draw_popup_over(
|
||||||
|
f,
|
||||||
|
app,
|
||||||
|
area,
|
||||||
|
draw_series,
|
||||||
|
draw_series_search_box,
|
||||||
|
Size::InputBox,
|
||||||
|
),
|
||||||
|
ActiveSonarrBlock::SearchSeriesError => {
|
||||||
|
let popup = Popup::new(Message::new("Series not found!")).size(Size::Message);
|
||||||
|
|
||||||
|
draw_series(f, app, area);
|
||||||
|
f.render_widget(popup, f.area());
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::FilterSeries => draw_popup_over(
|
||||||
|
f,
|
||||||
|
app,
|
||||||
|
area,
|
||||||
|
draw_series,
|
||||||
|
draw_filter_series_box,
|
||||||
|
Size::InputBox,
|
||||||
|
),
|
||||||
|
ActiveSonarrBlock::FilterSeriesError => {
|
||||||
|
let popup = Popup::new(Message::new("No series found matching the given filter!"))
|
||||||
|
.size(Size::Message);
|
||||||
|
|
||||||
|
draw_series(f, app, area);
|
||||||
|
f.render_widget(popup, f.area());
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::UpdateAllSeriesPrompt => {
|
||||||
|
let confirmation_prompt = ConfirmationPrompt::new()
|
||||||
|
.title("Update All Series")
|
||||||
|
.prompt("Do you want to update info and scan your disks for all of your series?")
|
||||||
|
.yes_no_value(app.data.sonarr_data.prompt_confirm);
|
||||||
|
|
||||||
|
draw_series(f, app, area);
|
||||||
|
f.render_widget(Popup::new(confirmation_prompt).size(Size::Prompt), f.area());
|
||||||
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -71,12 +114,11 @@ pub(super) fn draw_series(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
|||||||
|
|
||||||
let series_table_row_mapping = |series: &Series| {
|
let series_table_row_mapping = |series: &Series| {
|
||||||
series.title.scroll_left_or_reset(
|
series.title.scroll_left_or_reset(
|
||||||
get_width_from_percentage(area, 27),
|
get_width_from_percentage(area, 23),
|
||||||
*series == current_selection,
|
*series == current_selection,
|
||||||
app.tick_count % app.ticks_until_scroll == 0,
|
app.tick_count % app.ticks_until_scroll == 0,
|
||||||
);
|
);
|
||||||
let monitored = if series.monitored { "🏷" } else { "" };
|
let monitored = if series.monitored { "🏷" } else { "" };
|
||||||
let (hours, minutes) = convert_runtime(series.runtime);
|
|
||||||
let certification = series.certification.clone().unwrap_or_default();
|
let certification = series.certification.clone().unwrap_or_default();
|
||||||
let network = series.network.clone().unwrap_or_default();
|
let network = series.network.clone().unwrap_or_default();
|
||||||
let quality_profile = quality_profile_map
|
let quality_profile = quality_profile_map
|
||||||
@@ -109,7 +151,7 @@ pub(super) fn draw_series(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
|||||||
Cell::from(series.title.to_string()),
|
Cell::from(series.title.to_string()),
|
||||||
Cell::from(series.year.to_string()),
|
Cell::from(series.year.to_string()),
|
||||||
Cell::from(network),
|
Cell::from(network),
|
||||||
Cell::from(format!("{hours}h {minutes}m")),
|
Cell::from(series.status.to_display_str()),
|
||||||
Cell::from(certification),
|
Cell::from(certification),
|
||||||
Cell::from(series.series_type.to_display_str()),
|
Cell::from(series.series_type.to_display_str()),
|
||||||
Cell::from(quality_profile),
|
Cell::from(quality_profile),
|
||||||
@@ -128,7 +170,7 @@ pub(super) fn draw_series(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
|||||||
"Title",
|
"Title",
|
||||||
"Year",
|
"Year",
|
||||||
"Network",
|
"Network",
|
||||||
"Runtime",
|
"Status",
|
||||||
"Rating",
|
"Rating",
|
||||||
"Type",
|
"Type",
|
||||||
"Quality Profile",
|
"Quality Profile",
|
||||||
@@ -137,9 +179,9 @@ pub(super) fn draw_series(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
|||||||
"Tags",
|
"Tags",
|
||||||
])
|
])
|
||||||
.constraints([
|
.constraints([
|
||||||
Constraint::Percentage(27),
|
Constraint::Percentage(23),
|
||||||
Constraint::Percentage(4),
|
Constraint::Percentage(4),
|
||||||
Constraint::Percentage(10),
|
Constraint::Percentage(14),
|
||||||
Constraint::Percentage(6),
|
Constraint::Percentage(6),
|
||||||
Constraint::Percentage(6),
|
Constraint::Percentage(6),
|
||||||
Constraint::Percentage(6),
|
Constraint::Percentage(6),
|
||||||
@@ -177,3 +219,21 @@ fn decorate_series_row_with_style<'a>(series: &Series, row: Row<'a>) -> Row<'a>
|
|||||||
_ => row.missing(),
|
_ => row.missing(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn draw_series_search_box(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||||
|
draw_input_box_popup(
|
||||||
|
f,
|
||||||
|
area,
|
||||||
|
"Search",
|
||||||
|
app.data.sonarr_data.series.search.as_ref().unwrap(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_filter_series_box(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||||
|
draw_input_box_popup(
|
||||||
|
f,
|
||||||
|
area,
|
||||||
|
"Filter",
|
||||||
|
app.data.sonarr_data.series.filter.as_ref().unwrap(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user