Refactored things a bit and added help text support

This commit is contained in:
2023-08-08 10:50:04 -06:00
parent ff6e392af1
commit 3f378fb25a
11 changed files with 307 additions and 257 deletions
+209
View File
@@ -0,0 +1,209 @@
use std::cell::RefCell;
use std::fmt::{Display, Formatter};
use serde::Deserialize;
use tui::widgets::TableState;
use crate::app::radarr::ActiveRadarrBlock;
pub mod radarr_models;
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum Route {
Radarr(ActiveRadarrBlock),
Sonarr,
}
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 help: String,
}
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 get_active_tab_help(&self) -> String {
self.tabs[self.index].help.clone()
}
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;
}
}
}
+201
View File
@@ -0,0 +1,201 @@
use chrono::{DateTime, Utc};
use derivative::Derivative;
use serde::Deserialize;
use serde_json::Number;
use crate::models::HorizontallyScrollableText;
#[derive(Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct DiskSpace {
pub free_space: Number,
pub total_space: Number,
}
#[derive(Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct SystemStatus {
pub version: String,
pub start_time: DateTime<Utc>,
}
#[derive(Derivative, Deserialize, Debug, Clone)]
#[derivative(Default)]
#[serde(rename_all = "camelCase")]
pub struct Movie {
#[derivative(Default(value = "Number::from(0)"))]
pub id: Number,
pub title: String,
pub original_language: Language,
#[derivative(Default(value = "Number::from(0)"))]
pub size_on_disk: Number,
pub status: String,
pub overview: String,
pub path: String,
pub studio: String,
pub genres: Vec<String>,
#[derivative(Default(value = "Number::from(0)"))]
pub year: Number,
pub monitored: bool,
pub has_file: bool,
#[derivative(Default(value = "Number::from(0)"))]
pub runtime: Number,
#[derivative(Default(value = "Number::from(0)"))]
pub quality_profile_id: Number,
pub certification: Option<String>,
pub ratings: RatingsList,
pub movie_file: Option<MovieFile>,
pub collection: Option<Collection>,
}
#[derive(Derivative, Deserialize, Debug, Clone)]
#[derivative(Default)]
#[serde(rename_all = "camelCase")]
pub struct CollectionMovie {
pub title: String,
pub overview: String,
#[derivative(Default(value = "Number::from(0)"))]
pub year: Number,
#[derivative(Default(value = "Number::from(0)"))]
pub runtime: Number,
pub genres: Vec<String>,
pub ratings: RatingsList,
}
#[derive(Deserialize, Derivative, Clone, Debug)]
#[derivative(Default)]
#[serde(rename_all = "camelCase")]
pub struct Collection {
pub title: String,
pub root_folder_path: Option<String>,
pub search_on_add: bool,
pub overview: Option<String>,
#[derivative(Default(value = "Number::from(0)"))]
pub quality_profile_id: Number,
pub movies: Option<Vec<CollectionMovie>>,
}
#[derive(Deserialize, Derivative, Debug, Clone)]
#[derivative(Default)]
#[serde(rename_all = "camelCase")]
pub struct MovieFile {
pub relative_path: String,
pub path: String,
pub date_added: DateTime<Utc>,
pub media_info: MediaInfo,
}
#[derive(Deserialize, Derivative, Debug, Clone)]
#[derivative(Default)]
#[serde(rename_all = "camelCase")]
pub struct MediaInfo {
#[derivative(Default(value = "Number::from(0)"))]
pub audio_bitrate: Number,
#[derivative(Default(value = "Number::from(0)"))]
pub audio_channels: Number,
pub audio_codec: Option<String>,
pub audio_languages: Option<String>,
#[derivative(Default(value = "Number::from(0)"))]
pub audio_stream_count: Number,
#[derivative(Default(value = "Number::from(0)"))]
pub video_bit_depth: Number,
#[derivative(Default(value = "Number::from(0)"))]
pub video_bitrate: Number,
pub video_codec: String,
#[derivative(Default(value = "Number::from(0)"))]
pub video_fps: Number,
pub resolution: String,
pub run_time: String,
pub scan_type: String,
}
#[derive(Default, Deserialize, Debug, Clone)]
#[serde(rename_all = "camelCase")]
pub struct RatingsList {
pub imdb: Option<Rating>,
pub tmdb: Option<Rating>,
pub rotten_tomatoes: Option<Rating>,
}
#[derive(Derivative, Deserialize, Debug, Clone)]
#[derivative(Default)]
pub struct Rating {
#[derivative(Default(value = "Number::from(0)"))]
pub value: Number,
}
#[derive(Derivative, Deserialize, Debug)]
#[derivative(Default)]
#[serde(rename_all = "camelCase")]
pub struct DownloadsResponse {
pub records: Vec<DownloadRecord>,
}
#[derive(Derivative, Deserialize, Debug, Clone, PartialEq, Eq)]
#[derivative(Default)]
#[serde(rename_all = "camelCase")]
pub struct DownloadRecord {
pub title: String,
pub status: String,
#[derivative(Default(value = "Number::from(0)"))]
pub movie_id: Number,
#[derivative(Default(value = "Number::from(0)"))]
pub size: Number,
#[derivative(Default(value = "Number::from(0)"))]
pub sizeleft: Number,
pub output_path: HorizontallyScrollableText,
pub indexer: String,
pub download_client: String,
}
#[derive(Derivative, Deserialize, Debug)]
#[derivative(Default)]
#[serde(rename_all = "camelCase")]
pub struct QualityProfile {
#[derivative(Default(value = "Number::from(0)"))]
pub id: Number,
pub name: String,
}
#[derive(Deserialize, Default, Debug, Clone, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct MovieHistoryItem {
pub source_title: HorizontallyScrollableText,
pub quality: QualityHistory,
pub languages: Vec<Language>,
pub date: DateTime<Utc>,
pub event_type: String,
}
#[derive(Deserialize, Default, Debug, Clone, PartialEq, Eq)]
pub struct Language {
pub name: String,
}
#[derive(Deserialize, Default, Debug, Clone, PartialEq, Eq)]
pub struct QualityHistory {
pub quality: Quality,
}
#[derive(Deserialize, Default, Debug, Clone, PartialEq, Eq)]
pub struct Quality {
pub name: String,
}
#[derive(Deserialize, PartialEq, Eq, Clone, Debug)]
#[serde(rename_all = "lowercase")]
pub enum CreditType {
Cast,
Crew,
}
#[derive(Deserialize, Clone, Debug)]
#[serde(rename_all = "camelCase")]
pub struct Credit {
pub person_name: String,
pub character: Option<String>,
pub department: Option<String>,
pub job: Option<String>,
#[serde(rename(deserialize = "type"))]
pub credit_type: CreditType,
}