Refactored things a bit and added help text support
This commit is contained in:
+3
-14
@@ -7,26 +7,13 @@ use serde::{Deserialize, Serialize};
|
||||
use tokio::sync::mpsc::Sender;
|
||||
use tokio::time::Instant;
|
||||
|
||||
use crate::app::models::{HorizontallyScrollableText, TabRoute, TabState};
|
||||
use crate::app::radarr::{ActiveRadarrBlock, RadarrData};
|
||||
use crate::models::{HorizontallyScrollableText, Route, TabRoute, TabState};
|
||||
use crate::network::NetworkEvent;
|
||||
|
||||
pub(crate) mod key_binding;
|
||||
pub mod models;
|
||||
pub mod radarr;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
pub enum Route {
|
||||
Radarr(ActiveRadarrBlock),
|
||||
Sonarr,
|
||||
}
|
||||
|
||||
impl From<ActiveRadarrBlock> for Route {
|
||||
fn from(active_radarr_block: ActiveRadarrBlock) -> Route {
|
||||
Route::Radarr(active_radarr_block)
|
||||
}
|
||||
}
|
||||
|
||||
const DEFAULT_ROUTE: Route = Route::Radarr(ActiveRadarrBlock::Movies);
|
||||
|
||||
pub struct App {
|
||||
@@ -130,10 +117,12 @@ impl Default for App {
|
||||
TabRoute {
|
||||
title: "Radarr".to_owned(),
|
||||
route: ActiveRadarrBlock::Movies.into(),
|
||||
help: "<tab> change servarr | <?> help | <q> quit ".to_owned(),
|
||||
},
|
||||
TabRoute {
|
||||
title: "Sonarr".to_owned(),
|
||||
route: Route::Sonarr,
|
||||
help: "<tab> change servarr | <?> help | <q> quit ".to_owned(),
|
||||
},
|
||||
]),
|
||||
client: Client::new(),
|
||||
|
||||
@@ -1,196 +0,0 @@
|
||||
use std::cell::RefCell;
|
||||
use std::fmt::{Display, Formatter};
|
||||
|
||||
use serde::Deserialize;
|
||||
use tui::widgets::TableState;
|
||||
|
||||
use crate::app::Route;
|
||||
|
||||
pub trait Scrollable {
|
||||
fn scroll_down(&mut self);
|
||||
fn scroll_up(&mut self);
|
||||
}
|
||||
|
||||
pub struct StatefulTable<T> {
|
||||
pub state: TableState,
|
||||
pub items: Vec<T>,
|
||||
}
|
||||
|
||||
impl<T> Default for StatefulTable<T> {
|
||||
fn default() -> StatefulTable<T> {
|
||||
StatefulTable {
|
||||
state: TableState::default(),
|
||||
items: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clone> StatefulTable<T> {
|
||||
pub fn set_items(&mut self, items: Vec<T>) {
|
||||
let items_len = items.len();
|
||||
self.items = items;
|
||||
if !self.items.is_empty() {
|
||||
let selected_row = self.state.selected().map_or(0, |i| {
|
||||
if i > 0 && i < items_len {
|
||||
i
|
||||
} else if i >= items_len {
|
||||
items_len - 1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
});
|
||||
self.state.select(Some(selected_row));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn current_selection(&self) -> &T {
|
||||
&self.items[self.state.selected().unwrap_or(0)]
|
||||
}
|
||||
|
||||
pub fn current_selection_clone(&self) -> T {
|
||||
self.items[self.state.selected().unwrap_or(0)].clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Scrollable for StatefulTable<T> {
|
||||
fn scroll_down(&mut self) {
|
||||
let selected_row = match self.state.selected() {
|
||||
Some(i) => {
|
||||
if i >= self.items.len() - 1 {
|
||||
0
|
||||
} else {
|
||||
i + 1
|
||||
}
|
||||
}
|
||||
None => 0,
|
||||
};
|
||||
|
||||
self.state.select(Some(selected_row));
|
||||
}
|
||||
|
||||
fn scroll_up(&mut self) {
|
||||
let selected_row = match self.state.selected() {
|
||||
Some(i) => {
|
||||
if i == 0 {
|
||||
self.items.len() - 1
|
||||
} else {
|
||||
i - 1
|
||||
}
|
||||
}
|
||||
None => 0,
|
||||
};
|
||||
|
||||
self.state.select(Some(selected_row));
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct ScrollableText {
|
||||
pub items: Vec<String>,
|
||||
pub offset: u16,
|
||||
}
|
||||
|
||||
impl ScrollableText {
|
||||
pub fn with_string(item: String) -> ScrollableText {
|
||||
let items: Vec<&str> = item.split('\n').collect();
|
||||
let items: Vec<String> = items.iter().map(|it| it.to_string()).collect();
|
||||
ScrollableText { items, offset: 0 }
|
||||
}
|
||||
|
||||
pub fn get_text(&self) -> String {
|
||||
self.items.join("\n")
|
||||
}
|
||||
}
|
||||
|
||||
impl Scrollable for ScrollableText {
|
||||
fn scroll_down(&mut self) {
|
||||
if self.offset < self.items.len() as u16 {
|
||||
self.offset += 1;
|
||||
}
|
||||
}
|
||||
|
||||
fn scroll_up(&mut self) {
|
||||
if self.offset > 0 {
|
||||
self.offset -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Deserialize, Debug, Clone, PartialEq, Eq)]
|
||||
#[serde(from = "String")]
|
||||
pub struct HorizontallyScrollableText {
|
||||
pub text: String,
|
||||
pub offset: RefCell<usize>,
|
||||
}
|
||||
|
||||
impl From<String> for HorizontallyScrollableText {
|
||||
fn from(input: String) -> HorizontallyScrollableText {
|
||||
HorizontallyScrollableText::new(input)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for HorizontallyScrollableText {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
if *self.offset.borrow() == 0 {
|
||||
write!(f, "{}", self.text)
|
||||
} else {
|
||||
write!(f, "{}", &self.text[*self.offset.borrow()..])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl HorizontallyScrollableText {
|
||||
pub fn new(input: String) -> HorizontallyScrollableText {
|
||||
HorizontallyScrollableText {
|
||||
text: format!("{} ", input),
|
||||
offset: RefCell::new(0),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn scroll_text(&self) {
|
||||
let new_offset = *self.offset.borrow() + 1;
|
||||
*self.offset.borrow_mut() = new_offset % self.text.len();
|
||||
}
|
||||
|
||||
pub fn reset_offset(&self) {
|
||||
*self.offset.borrow_mut() = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct TabRoute {
|
||||
pub title: String,
|
||||
pub route: Route,
|
||||
}
|
||||
|
||||
pub struct TabState {
|
||||
pub tabs: Vec<TabRoute>,
|
||||
pub index: usize,
|
||||
}
|
||||
|
||||
impl TabState {
|
||||
pub fn new(tabs: Vec<TabRoute>) -> TabState {
|
||||
TabState { tabs, index: 0 }
|
||||
}
|
||||
|
||||
pub fn set_index(&mut self, index: usize) -> &TabRoute {
|
||||
self.index = index;
|
||||
&self.tabs[self.index]
|
||||
}
|
||||
|
||||
pub fn get_active_route(&self) -> &Route {
|
||||
&self.tabs[self.index].route
|
||||
}
|
||||
|
||||
pub fn next(&mut self) {
|
||||
self.index = (self.index + 1) % self.tabs.len();
|
||||
}
|
||||
|
||||
pub fn previous(&mut self) {
|
||||
if self.index > 0 {
|
||||
self.index -= 1;
|
||||
} else {
|
||||
self.index = self.tabs.len() - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
+18
-4
@@ -4,12 +4,12 @@ use std::time::Duration;
|
||||
use chrono::{DateTime, Utc};
|
||||
use strum::EnumIter;
|
||||
|
||||
use crate::app::models::{ScrollableText, StatefulTable, TabRoute, TabState};
|
||||
use crate::app::App;
|
||||
use crate::network::radarr_network::{
|
||||
use crate::app::{App, Route};
|
||||
use crate::models::radarr_models::{
|
||||
Collection, CollectionMovie, Credit, DiskSpace, DownloadRecord, Movie, MovieHistoryItem,
|
||||
RadarrEvent,
|
||||
};
|
||||
use crate::models::{ScrollableText, StatefulTable, TabRoute, TabState};
|
||||
use crate::network::radarr_network::RadarrEvent;
|
||||
|
||||
pub struct RadarrData {
|
||||
pub disk_space_vec: Vec<DiskSpace>,
|
||||
@@ -74,36 +74,44 @@ impl Default for RadarrData {
|
||||
TabRoute {
|
||||
title: "Library".to_owned(),
|
||||
route: ActiveRadarrBlock::Movies.into(),
|
||||
help: "<↑↓> scroll table | <enter> movie details | ←→ change tab ".to_owned(),
|
||||
},
|
||||
TabRoute {
|
||||
title: "Downloads".to_owned(),
|
||||
route: ActiveRadarrBlock::Downloads.into(),
|
||||
help: "<↑↓> scroll table | ←→ change tab ".to_owned(),
|
||||
},
|
||||
TabRoute {
|
||||
title: "Collections".to_owned(),
|
||||
route: ActiveRadarrBlock::Collections.into(),
|
||||
help: "<↑↓> scroll table | <enter> collection details | ←→ change tab ".to_owned(),
|
||||
},
|
||||
]),
|
||||
movie_info_tabs: TabState::new(vec![
|
||||
TabRoute {
|
||||
title: "Details".to_owned(),
|
||||
route: ActiveRadarrBlock::MovieDetails.into(),
|
||||
help: "←→ change tab | <esc> close ".to_owned(),
|
||||
},
|
||||
TabRoute {
|
||||
title: "History".to_owned(),
|
||||
route: ActiveRadarrBlock::MovieHistory.into(),
|
||||
help: "<↑↓> scroll table | ←→ change tab | <esc> close ".to_owned(),
|
||||
},
|
||||
TabRoute {
|
||||
title: "File".to_owned(),
|
||||
route: ActiveRadarrBlock::FileInfo.into(),
|
||||
help: "←→ change tab | <esc> close ".to_owned(),
|
||||
},
|
||||
TabRoute {
|
||||
title: "Cast".to_owned(),
|
||||
route: ActiveRadarrBlock::Cast.into(),
|
||||
help: "<↑↓> scroll table | ←→ change tab | <esc> close ".to_owned(),
|
||||
},
|
||||
TabRoute {
|
||||
title: "Crew".to_owned(),
|
||||
route: ActiveRadarrBlock::Crew.into(),
|
||||
help: "<↑↓> scroll table | ←→ change tab | <esc> close ".to_owned(),
|
||||
},
|
||||
]),
|
||||
}
|
||||
@@ -131,6 +139,12 @@ pub enum ActiveRadarrBlock {
|
||||
ViewMovieOverview,
|
||||
}
|
||||
|
||||
impl From<ActiveRadarrBlock> for Route {
|
||||
fn from(active_radarr_block: ActiveRadarrBlock) -> Route {
|
||||
Route::Radarr(active_radarr_block)
|
||||
}
|
||||
}
|
||||
|
||||
impl App {
|
||||
pub(super) async fn dispatch_by_radarr_block(&mut self, active_radarr_block: &ActiveRadarrBlock) {
|
||||
match active_radarr_block {
|
||||
|
||||
Reference in New Issue
Block a user