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::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()),
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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(),
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user