feat(ui): Support for the Series table

This commit is contained in:
2024-12-01 14:08:06 -07:00
parent c3fb5dcd5f
commit b75a95a708
3 changed files with 86 additions and 16 deletions
@@ -12,7 +12,7 @@ mod tests {
use crate::handlers::sonarr_handlers::library::{series_sorting_options, LibraryHandler};
use crate::handlers::KeyEventHandler;
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::HorizontallyScrollableText;
@@ -1563,8 +1563,13 @@ mod tests {
}
#[test]
fn test_series_sorting_options_runtime() {
let expected_cmp_fn: fn(&Series, &Series) -> Ordering = |a, b| a.runtime.cmp(&b.runtime);
fn test_series_sorting_options_status() {
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();
expected_series_vec.sort_by(expected_cmp_fn);
@@ -1573,7 +1578,7 @@ mod tests {
sorted_series_vec.sort_by(sort_option.cmp_fn.unwrap());
assert_eq!(sorted_series_vec, expected_series_vec);
assert_str_eq!(sort_option.name, "Runtime");
assert_str_eq!(sort_option.name, "Status");
}
#[test]
@@ -1766,7 +1771,7 @@ mod tests {
year: 2024,
monitored: false,
season_folder: false,
runtime: 12.into(),
status: SeriesStatus::Ended,
quality_profile_id: 1,
language_profile_id: 1,
certification: Some("TV-MA".to_owned()),
@@ -1781,7 +1786,7 @@ mod tests {
year: 1998,
monitored: false,
season_folder: false,
runtime: 60.into(),
status: SeriesStatus::Continuing,
quality_profile_id: 2,
language_profile_id: 2,
certification: Some("TV-PG".to_owned()),
@@ -1796,7 +1801,7 @@ mod tests {
year: 1954,
monitored: true,
season_folder: false,
runtime: 120.into(),
status: SeriesStatus::Upcoming,
quality_profile_id: 3,
language_profile_id: 3,
certification: Some("TV-G".to_owned()),
+7 -2
View File
@@ -403,8 +403,13 @@ fn series_sorting_options() -> Vec<SortOption<Series>> {
}),
},
SortOption {
name: "Runtime",
cmp_fn: Some(|a, b| a.runtime.cmp(&b.runtime)),
name: "Status",
cmp_fn: Some(|a, b| {
a.status
.to_string()
.to_lowercase()
.cmp(&b.status.to_string().to_lowercase())
}),
},
SortOption {
name: "Rating",
+67 -7
View File
@@ -4,6 +4,11 @@ use ratatui::{
Frame,
};
use crate::ui::widgets::{
confirmation_prompt::ConfirmationPrompt,
message::Message,
popup::{Popup, Size},
};
use crate::{
app::App,
models::{
@@ -12,12 +17,12 @@ use crate::{
EnumDisplayStyle, Route,
},
ui::{
draw_input_box_popup, draw_popup_over,
styles::ManagarrStyle,
utils::{get_width_from_percentage, layout_block_top_border},
widgets::managarr_table::ManagarrTable,
DrawUi,
},
utils::convert_runtime,
};
#[cfg(test)]
@@ -40,6 +45,44 @@ impl DrawUi for LibraryUi {
let mut series_ui_matchers = |active_sonarr_block: ActiveSonarrBlock| match active_sonarr_block
{
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| {
series.title.scroll_left_or_reset(
get_width_from_percentage(area, 27),
get_width_from_percentage(area, 23),
*series == current_selection,
app.tick_count % app.ticks_until_scroll == 0,
);
let monitored = if series.monitored { "🏷" } else { "" };
let (hours, minutes) = convert_runtime(series.runtime);
let certification = series.certification.clone().unwrap_or_default();
let network = series.network.clone().unwrap_or_default();
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.year.to_string()),
Cell::from(network),
Cell::from(format!("{hours}h {minutes}m")),
Cell::from(series.status.to_display_str()),
Cell::from(certification),
Cell::from(series.series_type.to_display_str()),
Cell::from(quality_profile),
@@ -128,7 +170,7 @@ pub(super) fn draw_series(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
"Title",
"Year",
"Network",
"Runtime",
"Status",
"Rating",
"Type",
"Quality Profile",
@@ -137,9 +179,9 @@ pub(super) fn draw_series(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
"Tags",
])
.constraints([
Constraint::Percentage(27),
Constraint::Percentage(23),
Constraint::Percentage(4),
Constraint::Percentage(10),
Constraint::Percentage(14),
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(),
}
}
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(),
)
}