Updated UI to have contextual help with tables so the UI doesn't feel so crowded
This commit is contained in:
+3
-12
@@ -72,14 +72,11 @@ impl App {
|
|||||||
|
|
||||||
pub async fn on_tick(&mut self, is_first_render: bool) {
|
pub async fn on_tick(&mut self, is_first_render: bool) {
|
||||||
if self.tick_count % self.tick_until_poll == 0 || self.is_routing || self.should_refresh {
|
if self.tick_count % self.tick_until_poll == 0 || self.is_routing || self.should_refresh {
|
||||||
match self.get_current_route() {
|
if let Route::Radarr(active_radarr_block) = self.get_current_route() {
|
||||||
Route::Radarr(active_radarr_block) => {
|
|
||||||
self
|
self
|
||||||
.radarr_on_tick(active_radarr_block.clone(), is_first_render)
|
.radarr_on_tick(active_radarr_block.clone(), is_first_render)
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
|
|
||||||
self.is_routing = false;
|
self.is_routing = false;
|
||||||
self.should_refresh = false;
|
self.should_refresh = false;
|
||||||
@@ -108,14 +105,6 @@ impl App {
|
|||||||
pub fn get_current_route(&self) -> &Route {
|
pub fn get_current_route(&self) -> &Route {
|
||||||
self.navigation_stack.last().unwrap_or(&DEFAULT_ROUTE)
|
self.navigation_stack.last().unwrap_or(&DEFAULT_ROUTE)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_previous_route(&self) -> &Route {
|
|
||||||
if self.navigation_stack.len() > 1 {
|
|
||||||
&self.navigation_stack[self.navigation_stack.len() - 2]
|
|
||||||
} else {
|
|
||||||
self.get_current_route()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for App {
|
impl Default for App {
|
||||||
@@ -130,11 +119,13 @@ impl Default for App {
|
|||||||
route: ActiveRadarrBlock::Movies.into(),
|
route: ActiveRadarrBlock::Movies.into(),
|
||||||
help: "<↑↓> scroll | ←→ change tab | <tab> change servarr | <?> help | <q> quit "
|
help: "<↑↓> scroll | ←→ change tab | <tab> change servarr | <?> help | <q> quit "
|
||||||
.to_owned(),
|
.to_owned(),
|
||||||
|
contextual_help: None,
|
||||||
},
|
},
|
||||||
TabRoute {
|
TabRoute {
|
||||||
title: "Sonarr".to_owned(),
|
title: "Sonarr".to_owned(),
|
||||||
route: Route::Sonarr,
|
route: Route::Sonarr,
|
||||||
help: "<tab> change servarr | <?> help | <q> quit ".to_owned(),
|
help: "<tab> change servarr | <?> help | <q> quit ".to_owned(),
|
||||||
|
contextual_help: None,
|
||||||
},
|
},
|
||||||
]),
|
]),
|
||||||
client: Client::new(),
|
client: Client::new(),
|
||||||
|
|||||||
+21
-11
@@ -118,51 +118,60 @@ impl Default for RadarrData {
|
|||||||
TabRoute {
|
TabRoute {
|
||||||
title: "Library".to_owned(),
|
title: "Library".to_owned(),
|
||||||
route: ActiveRadarrBlock::Movies.into(),
|
route: ActiveRadarrBlock::Movies.into(),
|
||||||
help: "<a> add | <s> search | <f> filter | <enter> details | <esc> cancel filter | <del> delete "
|
help: String::default(),
|
||||||
.to_owned(),
|
contextual_help: Some("<a> add | <s> search | <f> filter | <enter> details | <esc> cancel filter | <del> delete"
|
||||||
|
.to_owned()),
|
||||||
},
|
},
|
||||||
TabRoute {
|
TabRoute {
|
||||||
title: "Downloads".to_owned(),
|
title: "Downloads".to_owned(),
|
||||||
route: ActiveRadarrBlock::Downloads.into(),
|
route: ActiveRadarrBlock::Downloads.into(),
|
||||||
help: "<del> delete ".to_owned(),
|
help: String::default(),
|
||||||
|
contextual_help: Some("<del> delete".to_owned()),
|
||||||
},
|
},
|
||||||
TabRoute {
|
TabRoute {
|
||||||
title: "Collections".to_owned(),
|
title: "Collections".to_owned(),
|
||||||
route: ActiveRadarrBlock::Collections.into(),
|
route: ActiveRadarrBlock::Collections.into(),
|
||||||
help: "<s> search | <f> filter | <enter> details | <esc> cancel filter "
|
help: String::default(),
|
||||||
.to_owned(),
|
contextual_help: Some("<s> search | <f> filter | <enter> details | <esc> cancel filter"
|
||||||
|
.to_owned()),
|
||||||
},
|
},
|
||||||
]),
|
]),
|
||||||
movie_info_tabs: TabState::new(vec![
|
movie_info_tabs: TabState::new(vec![
|
||||||
TabRoute {
|
TabRoute {
|
||||||
title: "Details".to_owned(),
|
title: "Details".to_owned(),
|
||||||
route: ActiveRadarrBlock::MovieDetails.into(),
|
route: ActiveRadarrBlock::MovieDetails.into(),
|
||||||
help: "<r> refresh | <s> auto search | ←→ change tab | <esc> close ".to_owned(),
|
help: "<r> refresh | <s> auto search | <esc> close".to_owned(),
|
||||||
|
contextual_help: None
|
||||||
},
|
},
|
||||||
TabRoute {
|
TabRoute {
|
||||||
title: "History".to_owned(),
|
title: "History".to_owned(),
|
||||||
route: ActiveRadarrBlock::MovieHistory.into(),
|
route: ActiveRadarrBlock::MovieHistory.into(),
|
||||||
help: "<r> refresh | <s> auto search | <↑↓> scroll | ←→ change tab | <esc> close ".to_owned(),
|
help: "<r> refresh | <s> auto search | <esc> close".to_owned(),
|
||||||
|
contextual_help: None
|
||||||
},
|
},
|
||||||
TabRoute {
|
TabRoute {
|
||||||
title: "File".to_owned(),
|
title: "File".to_owned(),
|
||||||
route: ActiveRadarrBlock::FileInfo.into(),
|
route: ActiveRadarrBlock::FileInfo.into(),
|
||||||
help: "<r> refresh | <s> auto search | ←→ change tab | <esc> close ".to_owned(),
|
help: "<r> refresh | <s> auto search | <esc> close".to_owned(),
|
||||||
|
contextual_help: None,
|
||||||
},
|
},
|
||||||
TabRoute {
|
TabRoute {
|
||||||
title: "Cast".to_owned(),
|
title: "Cast".to_owned(),
|
||||||
route: ActiveRadarrBlock::Cast.into(),
|
route: ActiveRadarrBlock::Cast.into(),
|
||||||
help: "<r> refresh | <s> auto search | <↑↓> scroll | ←→ change tab | <esc> close ".to_owned(),
|
help: "<r> refresh | <s> auto search | <esc> close".to_owned(),
|
||||||
|
contextual_help: None,
|
||||||
},
|
},
|
||||||
TabRoute {
|
TabRoute {
|
||||||
title: "Crew".to_owned(),
|
title: "Crew".to_owned(),
|
||||||
route: ActiveRadarrBlock::Crew.into(),
|
route: ActiveRadarrBlock::Crew.into(),
|
||||||
help: "<r> refresh | <s> auto search | <↑↓> scroll | ←→ change tab | <esc> close ".to_owned(),
|
help: "<r> refresh | <s> auto search | <esc> close".to_owned(),
|
||||||
|
contextual_help: None,
|
||||||
},
|
},
|
||||||
TabRoute {
|
TabRoute {
|
||||||
title: "Manual Search".to_owned(),
|
title: "Manual Search".to_owned(),
|
||||||
route: ActiveRadarrBlock::ManualSearch.into(),
|
route: ActiveRadarrBlock::ManualSearch.into(),
|
||||||
help: "<r> refresh | <s> auto search | <↑↓> scroll | <enter> details | ←→ change tab | <esc> close ".to_owned(),
|
help: "<r> refresh | <s> auto search | <esc> close".to_owned(),
|
||||||
|
contextual_help: Some("<enter> details | <o> sort".to_owned())
|
||||||
}
|
}
|
||||||
]),
|
]),
|
||||||
}
|
}
|
||||||
@@ -189,6 +198,7 @@ pub enum ActiveRadarrBlock {
|
|||||||
FilterCollections,
|
FilterCollections,
|
||||||
FilterMovies,
|
FilterMovies,
|
||||||
ManualSearch,
|
ManualSearch,
|
||||||
|
ManualSearchConfirmPrompt,
|
||||||
Movies,
|
Movies,
|
||||||
MovieDetails,
|
MovieDetails,
|
||||||
MovieHistory,
|
MovieHistory,
|
||||||
|
|||||||
@@ -296,6 +296,7 @@ pub struct TabRoute {
|
|||||||
pub title: String,
|
pub title: String,
|
||||||
pub route: Route,
|
pub route: Route,
|
||||||
pub help: String,
|
pub help: String,
|
||||||
|
pub contextual_help: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct TabState {
|
pub struct TabState {
|
||||||
@@ -321,6 +322,10 @@ impl TabState {
|
|||||||
self.tabs[self.index].help.clone()
|
self.tabs[self.index].help.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_active_tab_contextual_help(&self) -> Option<String> {
|
||||||
|
self.tabs[self.index].contextual_help.clone()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn next(&mut self) {
|
pub fn next(&mut self) {
|
||||||
self.index = (self.index + 1) % self.tabs.len();
|
self.index = (self.index + 1) % self.tabs.len();
|
||||||
}
|
}
|
||||||
|
|||||||
+21
-1
@@ -17,7 +17,7 @@ use crate::ui::utils::{
|
|||||||
layout_block_top_border, layout_button_paragraph, layout_button_paragraph_borderless, logo_block,
|
layout_block_top_border, layout_button_paragraph, layout_button_paragraph_borderless, logo_block,
|
||||||
style_button_highlight, style_default_bold, style_failure, style_help, style_highlight,
|
style_button_highlight, style_default_bold, style_failure, style_help, style_highlight,
|
||||||
style_primary, style_secondary, style_system_function, title_block, title_block_centered,
|
style_primary, style_secondary, style_system_function, title_block, title_block_centered,
|
||||||
vertical_chunks_with_margin,
|
vertical_chunks, vertical_chunks_with_margin,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod radarr_ui;
|
mod radarr_ui;
|
||||||
@@ -217,6 +217,7 @@ pub struct TableProps<'a, T> {
|
|||||||
pub content: &'a mut StatefulTable<T>,
|
pub content: &'a mut StatefulTable<T>,
|
||||||
pub table_headers: Vec<&'a str>,
|
pub table_headers: Vec<&'a str>,
|
||||||
pub constraints: Vec<Constraint>,
|
pub constraints: Vec<Constraint>,
|
||||||
|
pub help: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_table<'a, B, T, F>(
|
fn draw_table<'a, B, T, F>(
|
||||||
@@ -234,8 +235,27 @@ fn draw_table<'a, B, T, F>(
|
|||||||
content,
|
content,
|
||||||
table_headers,
|
table_headers,
|
||||||
constraints,
|
constraints,
|
||||||
|
help,
|
||||||
} = table_props;
|
} = table_props;
|
||||||
|
|
||||||
|
let content_area = if let Some(help_string) = help {
|
||||||
|
let chunks = vertical_chunks(
|
||||||
|
vec![Constraint::Min(0), Constraint::Length(3)],
|
||||||
|
content_area,
|
||||||
|
);
|
||||||
|
let mut help_text = Text::from(format!(" {}", help_string));
|
||||||
|
help_text.patch_style(style_help());
|
||||||
|
let help_paragraph = Paragraph::new(help_text)
|
||||||
|
.block(layout_block_top_border())
|
||||||
|
.alignment(Alignment::Left);
|
||||||
|
|
||||||
|
f.render_widget(help_paragraph, chunks[1]);
|
||||||
|
|
||||||
|
chunks[0]
|
||||||
|
} else {
|
||||||
|
content_area
|
||||||
|
};
|
||||||
|
|
||||||
if !content.items.is_empty() {
|
if !content.items.is_empty() {
|
||||||
let rows = content.items.iter().map(row_mapper);
|
let rows = content.items.iter().map(row_mapper);
|
||||||
|
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ fn draw_add_movie_search<B: Backend>(f: &mut Frame<'_, B>, app: &mut App, area:
|
|||||||
| ActiveRadarrBlock::AddMovieSelectMonitor
|
| ActiveRadarrBlock::AddMovieSelectMonitor
|
||||||
| ActiveRadarrBlock::AddMovieSelectMinimumAvailability
|
| ActiveRadarrBlock::AddMovieSelectMinimumAvailability
|
||||||
| ActiveRadarrBlock::AddMovieSelectQualityProfile => {
|
| ActiveRadarrBlock::AddMovieSelectQualityProfile => {
|
||||||
let mut help_text = Text::from("<esc> edit search");
|
let mut help_text = Text::from("<enter> details | <esc> edit search");
|
||||||
help_text.patch_style(style_help());
|
help_text.patch_style(style_help());
|
||||||
let help_paragraph = Paragraph::new(help_text)
|
let help_paragraph = Paragraph::new(help_text)
|
||||||
.block(borderless_block())
|
.block(borderless_block())
|
||||||
@@ -113,6 +113,7 @@ fn draw_add_movie_search<B: Backend>(f: &mut Frame<'_, B>, app: &mut App, area:
|
|||||||
Constraint::Percentage(14),
|
Constraint::Percentage(14),
|
||||||
Constraint::Percentage(30),
|
Constraint::Percentage(30),
|
||||||
],
|
],
|
||||||
|
help: None,
|
||||||
},
|
},
|
||||||
|movie| {
|
|movie| {
|
||||||
let (hours, minutes) = convert_runtime(movie.runtime.as_u64().unwrap());
|
let (hours, minutes) = convert_runtime(movie.runtime.as_u64().unwrap());
|
||||||
|
|||||||
@@ -118,6 +118,11 @@ fn draw_collection_details<B: Backend>(f: &mut Frame<'_, B>, app: &mut App, cont
|
|||||||
Constraint::Percentage(18),
|
Constraint::Percentage(18),
|
||||||
Constraint::Percentage(30),
|
Constraint::Percentage(30),
|
||||||
],
|
],
|
||||||
|
help: app
|
||||||
|
.data
|
||||||
|
.radarr_data
|
||||||
|
.main_tabs
|
||||||
|
.get_active_tab_contextual_help(),
|
||||||
},
|
},
|
||||||
|movie| {
|
|movie| {
|
||||||
let (hours, minutes) = convert_runtime(movie.runtime.as_u64().unwrap());
|
let (hours, minutes) = convert_runtime(movie.runtime.as_u64().unwrap());
|
||||||
|
|||||||
@@ -143,6 +143,11 @@ fn draw_library<B: Backend>(f: &mut Frame<'_, B>, app: &mut App, area: Rect) {
|
|||||||
Constraint::Percentage(12),
|
Constraint::Percentage(12),
|
||||||
Constraint::Percentage(12),
|
Constraint::Percentage(12),
|
||||||
],
|
],
|
||||||
|
help: app
|
||||||
|
.data
|
||||||
|
.radarr_data
|
||||||
|
.main_tabs
|
||||||
|
.get_active_tab_contextual_help(),
|
||||||
},
|
},
|
||||||
|movie| {
|
|movie| {
|
||||||
let (hours, minutes) = convert_runtime(movie.runtime.as_u64().unwrap());
|
let (hours, minutes) = convert_runtime(movie.runtime.as_u64().unwrap());
|
||||||
@@ -298,6 +303,11 @@ fn draw_downloads<B: Backend>(f: &mut Frame<'_, B>, app: &mut App, area: Rect) {
|
|||||||
Constraint::Percentage(17),
|
Constraint::Percentage(17),
|
||||||
Constraint::Percentage(13),
|
Constraint::Percentage(13),
|
||||||
],
|
],
|
||||||
|
help: app
|
||||||
|
.data
|
||||||
|
.radarr_data
|
||||||
|
.main_tabs
|
||||||
|
.get_active_tab_contextual_help(),
|
||||||
},
|
},
|
||||||
|download_record| {
|
|download_record| {
|
||||||
let DownloadRecord {
|
let DownloadRecord {
|
||||||
@@ -352,6 +362,11 @@ fn draw_collections<B: Backend>(f: &mut Frame<'_, B>, app: &mut App, area: Rect)
|
|||||||
"Quality Profile",
|
"Quality Profile",
|
||||||
],
|
],
|
||||||
constraints: iter::repeat(Constraint::Ratio(1, 5)).take(5).collect(),
|
constraints: iter::repeat(Constraint::Ratio(1, 5)).take(5).collect(),
|
||||||
|
help: app
|
||||||
|
.data
|
||||||
|
.radarr_data
|
||||||
|
.main_tabs
|
||||||
|
.get_active_tab_contextual_help(),
|
||||||
},
|
},
|
||||||
|collection| {
|
|collection| {
|
||||||
let number_of_movies = collection.movies.clone().unwrap_or_default().len();
|
let number_of_movies = collection.movies.clone().unwrap_or_default().len();
|
||||||
|
|||||||
@@ -220,6 +220,11 @@ fn draw_movie_history<B: Backend>(f: &mut Frame<'_, B>, app: &mut App, content_a
|
|||||||
Constraint::Percentage(14),
|
Constraint::Percentage(14),
|
||||||
Constraint::Percentage(21),
|
Constraint::Percentage(21),
|
||||||
],
|
],
|
||||||
|
help: app
|
||||||
|
.data
|
||||||
|
.radarr_data
|
||||||
|
.movie_info_tabs
|
||||||
|
.get_active_tab_contextual_help(),
|
||||||
},
|
},
|
||||||
|movie_history_item| {
|
|movie_history_item| {
|
||||||
let MovieHistoryItem {
|
let MovieHistoryItem {
|
||||||
@@ -268,6 +273,11 @@ fn draw_movie_cast<B: Backend>(f: &mut Frame<'_, B>, app: &mut App, content_area
|
|||||||
content: &mut app.data.radarr_data.movie_cast,
|
content: &mut app.data.radarr_data.movie_cast,
|
||||||
constraints: iter::repeat(Constraint::Ratio(1, 2)).take(2).collect(),
|
constraints: iter::repeat(Constraint::Ratio(1, 2)).take(2).collect(),
|
||||||
table_headers: vec!["Cast Member", "Character"],
|
table_headers: vec!["Cast Member", "Character"],
|
||||||
|
help: app
|
||||||
|
.data
|
||||||
|
.radarr_data
|
||||||
|
.movie_info_tabs
|
||||||
|
.get_active_tab_contextual_help(),
|
||||||
},
|
},
|
||||||
|cast_member| {
|
|cast_member| {
|
||||||
let Credit {
|
let Credit {
|
||||||
@@ -295,6 +305,11 @@ fn draw_movie_crew<B: Backend>(f: &mut Frame<'_, B>, app: &mut App, content_area
|
|||||||
content: &mut app.data.radarr_data.movie_crew,
|
content: &mut app.data.radarr_data.movie_crew,
|
||||||
constraints: iter::repeat(Constraint::Ratio(1, 3)).take(3).collect(),
|
constraints: iter::repeat(Constraint::Ratio(1, 3)).take(3).collect(),
|
||||||
table_headers: vec!["Crew Member", "Job", "Department"],
|
table_headers: vec!["Crew Member", "Job", "Department"],
|
||||||
|
help: app
|
||||||
|
.data
|
||||||
|
.radarr_data
|
||||||
|
.movie_info_tabs
|
||||||
|
.get_active_tab_contextual_help(),
|
||||||
},
|
},
|
||||||
|crew_member| {
|
|crew_member| {
|
||||||
let Credit {
|
let Credit {
|
||||||
@@ -346,6 +361,11 @@ fn draw_movie_releases<B: Backend>(f: &mut Frame<'_, B>, app: &mut App, content_
|
|||||||
table_headers: vec![
|
table_headers: vec![
|
||||||
"Source", "Age", "⛔", "Title", "Indexer", "Size", "Peers", "Language", "Quality",
|
"Source", "Age", "⛔", "Title", "Indexer", "Size", "Peers", "Language", "Quality",
|
||||||
],
|
],
|
||||||
|
help: app
|
||||||
|
.data
|
||||||
|
.radarr_data
|
||||||
|
.movie_info_tabs
|
||||||
|
.get_active_tab_contextual_help(),
|
||||||
},
|
},
|
||||||
|release| {
|
|release| {
|
||||||
let Release {
|
let Release {
|
||||||
|
|||||||
Reference in New Issue
Block a user