Full popup description functionality
This commit is contained in:
@@ -12,6 +12,7 @@ clap = { version = "4.0.30", features = ["help", "usage", "error-context", "deri
|
|||||||
confy = { version = "0.5.1", default_features = false, features = ["yaml_conf"] }
|
confy = { version = "0.5.1", default_features = false, features = ["yaml_conf"] }
|
||||||
crossterm = "0.25.0"
|
crossterm = "0.25.0"
|
||||||
derivative = "2.2.0"
|
derivative = "2.2.0"
|
||||||
|
indoc = "1.0.8"
|
||||||
log = "0.4.17"
|
log = "0.4.17"
|
||||||
log4rs = { version = "1.2.0", features = ["file_appender"] }
|
log4rs = { version = "1.2.0", features = ["file_appender"] }
|
||||||
reqwest = { version = "0.11.13", features = ["json"] }
|
reqwest = { version = "0.11.13", features = ["json"] }
|
||||||
|
|||||||
+22
-9
@@ -1,7 +1,10 @@
|
|||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
use log::{debug, error};
|
use log::{debug, error};
|
||||||
use reqwest::Client;
|
use reqwest::Client;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tokio::sync::mpsc::Sender;
|
use tokio::sync::mpsc::Sender;
|
||||||
|
use tokio::time::Instant;
|
||||||
|
|
||||||
use crate::app::radarr::{ActiveRadarrBlock, RadarrData};
|
use crate::app::radarr::{ActiveRadarrBlock, RadarrData};
|
||||||
use crate::network::radarr_network::RadarrEvent;
|
use crate::network::radarr_network::RadarrEvent;
|
||||||
@@ -11,7 +14,7 @@ pub(crate) mod key_binding;
|
|||||||
pub mod models;
|
pub mod models;
|
||||||
pub mod radarr;
|
pub mod radarr;
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||||
pub enum Route {
|
pub enum Route {
|
||||||
Radarr(ActiveRadarrBlock),
|
Radarr(ActiveRadarrBlock),
|
||||||
}
|
}
|
||||||
@@ -31,6 +34,8 @@ pub struct App {
|
|||||||
pub title: &'static str,
|
pub title: &'static str,
|
||||||
pub tick_until_poll: u64,
|
pub tick_until_poll: u64,
|
||||||
pub tick_count: u64,
|
pub tick_count: u64,
|
||||||
|
pub last_tick: Instant,
|
||||||
|
pub network_tick_frequency: Duration,
|
||||||
pub is_routing: bool,
|
pub is_routing: bool,
|
||||||
pub is_loading: bool,
|
pub is_loading: bool,
|
||||||
pub config: AppConfig,
|
pub config: AppConfig,
|
||||||
@@ -38,17 +43,15 @@ pub struct App {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl App {
|
impl App {
|
||||||
pub fn new(network_tx: Sender<NetworkEvent>, tick_until_poll: u64, config: AppConfig) -> Self {
|
pub fn new(network_tx: Sender<NetworkEvent>, config: AppConfig) -> Self {
|
||||||
App {
|
App {
|
||||||
network_tx: Some(network_tx),
|
network_tx: Some(network_tx),
|
||||||
tick_until_poll,
|
|
||||||
config,
|
config,
|
||||||
..App::default()
|
..App::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn dispatch(&mut self, action: NetworkEvent) {
|
pub async fn dispatch(&mut self, action: NetworkEvent) {
|
||||||
self.is_loading = true;
|
|
||||||
if let Some(network_tx) = &self.network_tx {
|
if let Some(network_tx) = &self.network_tx {
|
||||||
if let Err(e) = network_tx.send(action).await {
|
if let Err(e) = network_tx.send(action).await {
|
||||||
self.is_loading = false;
|
self.is_loading = false;
|
||||||
@@ -74,12 +77,20 @@ impl App {
|
|||||||
|
|
||||||
if is_first_render {
|
if is_first_render {
|
||||||
self.dispatch(RadarrEvent::GetQualityProfiles.into()).await;
|
self.dispatch(RadarrEvent::GetQualityProfiles.into()).await;
|
||||||
|
self.dispatch(RadarrEvent::GetOverview.into()).await;
|
||||||
|
self.dispatch(RadarrEvent::GetStatus.into()).await;
|
||||||
|
self.dispatch_by_radarr_block(active_block.clone()).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.dispatch(RadarrEvent::GetOverview.into()).await;
|
if self.is_routing
|
||||||
self.dispatch(RadarrEvent::GetStatus.into()).await;
|
|| self
|
||||||
|
.network_tick_frequency
|
||||||
self.dispatch_by_radarr_block(active_block).await;
|
.checked_sub(self.last_tick.elapsed())
|
||||||
|
.unwrap_or_else(|| Duration::from_secs(0))
|
||||||
|
.is_zero()
|
||||||
|
{
|
||||||
|
self.dispatch_by_radarr_block(active_block).await;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,8 +124,10 @@ impl Default for App {
|
|||||||
network_tx: None,
|
network_tx: None,
|
||||||
client: Client::new(),
|
client: Client::new(),
|
||||||
title: "Managarr",
|
title: "Managarr",
|
||||||
tick_until_poll: 0,
|
tick_until_poll: 20,
|
||||||
tick_count: 0,
|
tick_count: 0,
|
||||||
|
network_tick_frequency: Duration::from_secs(5),
|
||||||
|
last_tick: Instant::now(),
|
||||||
is_loading: false,
|
is_loading: false,
|
||||||
is_routing: false,
|
is_routing: false,
|
||||||
config: AppConfig::default(),
|
config: AppConfig::default(),
|
||||||
|
|||||||
+7
-3
@@ -18,7 +18,7 @@ pub struct RadarrData {
|
|||||||
pub movie_details: ScrollableText,
|
pub movie_details: ScrollableText,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||||
pub enum ActiveRadarrBlock {
|
pub enum ActiveRadarrBlock {
|
||||||
AddMovie,
|
AddMovie,
|
||||||
Calendar,
|
Calendar,
|
||||||
@@ -35,15 +35,19 @@ pub enum ActiveRadarrBlock {
|
|||||||
|
|
||||||
impl App {
|
impl App {
|
||||||
pub(super) async fn dispatch_by_radarr_block(&mut self, active_radarr_block: ActiveRadarrBlock) {
|
pub(super) async fn dispatch_by_radarr_block(&mut self, active_radarr_block: ActiveRadarrBlock) {
|
||||||
self.reset_tick_count();
|
|
||||||
match active_radarr_block {
|
match active_radarr_block {
|
||||||
ActiveRadarrBlock::Downloads => self.dispatch(RadarrEvent::GetDownloads.into()).await,
|
ActiveRadarrBlock::Downloads => self.dispatch(RadarrEvent::GetDownloads.into()).await,
|
||||||
ActiveRadarrBlock::Movies => {
|
ActiveRadarrBlock::Movies => {
|
||||||
self.dispatch(RadarrEvent::GetMovies.into()).await;
|
self.dispatch(RadarrEvent::GetMovies.into()).await;
|
||||||
self.dispatch(RadarrEvent::GetDownloads.into()).await;
|
self.dispatch(RadarrEvent::GetDownloads.into()).await;
|
||||||
}
|
}
|
||||||
ActiveRadarrBlock::MovieDetails => self.dispatch(RadarrEvent::GetMovieDetails.into()).await,
|
ActiveRadarrBlock::MovieDetails => {
|
||||||
|
self.is_loading = true;
|
||||||
|
self.dispatch(RadarrEvent::GetMovieDetails.into()).await
|
||||||
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.reset_tick_count();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,7 @@ use crate::handlers::radarr_handler::handle_radarr_key_events;
|
|||||||
mod radarr_handler;
|
mod radarr_handler;
|
||||||
|
|
||||||
pub async fn handle_key_events(key: Key, app: &mut App) {
|
pub async fn handle_key_events(key: Key, app: &mut App) {
|
||||||
match *app.get_current_route() {
|
match app.get_current_route().clone() {
|
||||||
Route::Radarr(active_radarr_block) => {
|
Route::Radarr(active_radarr_block) => {
|
||||||
handle_radarr_key_events(key, app, active_radarr_block).await
|
handle_radarr_key_events(key, app, active_radarr_block).await
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
||||||
use crate::app::models::Scrollable;
|
use crate::app::models::{Scrollable, ScrollableText};
|
||||||
use crate::app::radarr::ActiveRadarrBlock;
|
use crate::app::radarr::ActiveRadarrBlock;
|
||||||
use crate::{App, Key};
|
use crate::{App, Key};
|
||||||
|
|
||||||
@@ -42,7 +42,10 @@ async fn handle_submit(app: &mut App, active_radarr_block: ActiveRadarrBlock) {
|
|||||||
|
|
||||||
async fn handle_esc(app: &mut App, active_radarr_block: ActiveRadarrBlock) {
|
async fn handle_esc(app: &mut App, active_radarr_block: ActiveRadarrBlock) {
|
||||||
match active_radarr_block {
|
match active_radarr_block {
|
||||||
ActiveRadarrBlock::MovieDetails => app.pop_navigation_stack(),
|
ActiveRadarrBlock::MovieDetails => {
|
||||||
|
app.pop_navigation_stack();
|
||||||
|
app.data.radarr_data.movie_details = ScrollableText::default();
|
||||||
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-5
@@ -39,7 +39,7 @@ async fn main() -> Result<()> {
|
|||||||
let config = confy::load("managarr", "config")?;
|
let config = confy::load("managarr", "config")?;
|
||||||
let (sync_network_tx, sync_network_rx) = mpsc::channel(500);
|
let (sync_network_tx, sync_network_rx) = mpsc::channel(500);
|
||||||
|
|
||||||
let app = Arc::new(Mutex::new(App::new(sync_network_tx, 5000 / 250, config)));
|
let app = Arc::new(Mutex::new(App::new(sync_network_tx, config)));
|
||||||
|
|
||||||
let app_nw = Arc::clone(&app);
|
let app_nw = Arc::clone(&app);
|
||||||
|
|
||||||
@@ -55,10 +55,6 @@ async fn start_networking(mut network_rx: Receiver<NetworkEvent>, app: &Arc<Mute
|
|||||||
let network = Network::new(reqwest::Client::new(), app);
|
let network = Network::new(reqwest::Client::new(), app);
|
||||||
|
|
||||||
while let Some(network_event) = network_rx.recv().await {
|
while let Some(network_event) = network_rx.recv().await {
|
||||||
debug!(
|
|
||||||
"**************************************MAIN Received network event: {:?}",
|
|
||||||
network_event
|
|
||||||
);
|
|
||||||
network.handle_network_event(network_event).await;
|
network.handle_network_event(network_event).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -78,6 +74,11 @@ async fn start_ui(app: &Arc<Mutex<App>>) -> Result<()> {
|
|||||||
|
|
||||||
loop {
|
loop {
|
||||||
let mut app = app.lock().await;
|
let mut app = app.lock().await;
|
||||||
|
|
||||||
|
if is_first_render {
|
||||||
|
app.is_loading = true;
|
||||||
|
}
|
||||||
|
|
||||||
terminal.draw(|f| ui(f, &mut app))?;
|
terminal.draw(|f| ui(f, &mut app))?;
|
||||||
|
|
||||||
match input_events.next()? {
|
match input_events.next()? {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use derivative::Derivative;
|
use derivative::Derivative;
|
||||||
|
use indoc::{formatdoc, indoc};
|
||||||
use log::{debug, error};
|
use log::{debug, error};
|
||||||
use reqwest::RequestBuilder;
|
use reqwest::RequestBuilder;
|
||||||
use serde::de::DeserializeOwned;
|
use serde::de::DeserializeOwned;
|
||||||
@@ -148,7 +149,6 @@ impl<'a> Network<'a> {
|
|||||||
RadarrEvent::GetStatus => self.get_status(RadarrEvent::GetStatus.resource()).await,
|
RadarrEvent::GetStatus => self.get_status(RadarrEvent::GetStatus.resource()).await,
|
||||||
RadarrEvent::GetMovies => self.get_movies(RadarrEvent::GetMovies.resource()).await,
|
RadarrEvent::GetMovies => self.get_movies(RadarrEvent::GetMovies.resource()).await,
|
||||||
RadarrEvent::GetMovieDetails => {
|
RadarrEvent::GetMovieDetails => {
|
||||||
debug!("TEST received GetMovieDetails event");
|
|
||||||
self
|
self
|
||||||
.get_movie_details(RadarrEvent::GetMovieDetails.resource())
|
.get_movie_details(RadarrEvent::GetMovieDetails.resource())
|
||||||
.await
|
.await
|
||||||
@@ -164,8 +164,6 @@ impl<'a> Network<'a> {
|
|||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut app = self.app.lock().await;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_healthcheck(&self, resource: &str) {
|
async fn get_healthcheck(&self, resource: &str) {
|
||||||
@@ -207,7 +205,6 @@ impl<'a> Network<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn get_movie_details(&self, resource: &str) {
|
async fn get_movie_details(&self, resource: &str) {
|
||||||
debug!("TEST handling get_movie_details");
|
|
||||||
let movie_id = self
|
let movie_id = self
|
||||||
.app
|
.app
|
||||||
.lock()
|
.lock()
|
||||||
@@ -223,7 +220,6 @@ impl<'a> Network<'a> {
|
|||||||
let mut url = resource.to_owned();
|
let mut url = resource.to_owned();
|
||||||
url.push('/');
|
url.push('/');
|
||||||
url.push_str(movie_id.to_string().as_str());
|
url.push_str(movie_id.to_string().as_str());
|
||||||
debug!("TEST sending request{}", url.as_str());
|
|
||||||
self
|
self
|
||||||
.handle_get_request::<Movie>(url.as_str(), |movie_response, mut app| {
|
.handle_get_request::<Movie>(url.as_str(), |movie_response, mut app| {
|
||||||
let Movie {
|
let Movie {
|
||||||
@@ -251,39 +247,51 @@ impl<'a> Network<'a> {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.to_owned();
|
.to_owned();
|
||||||
let imdb_rating = if let Some(rating) = ratings.imdb {
|
let imdb_rating = if let Some(rating) = ratings.imdb {
|
||||||
rating.value.as_f64().unwrap()
|
if let Some(value) = rating.value.as_f64() {
|
||||||
|
format!("{:.1}", value)
|
||||||
|
} else {
|
||||||
|
"".to_owned()
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
0f64
|
"".to_owned()
|
||||||
};
|
};
|
||||||
|
|
||||||
let tmdb_rating = if let Some(rating) = ratings.tmdb {
|
let tmdb_rating = if let Some(rating) = ratings.tmdb {
|
||||||
rating.value.as_u64().unwrap()
|
if let Some(value) = rating.value.as_f64() {
|
||||||
|
format!("{}%", value * 10f64)
|
||||||
|
} else {
|
||||||
|
"".to_owned()
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
0u64
|
"".to_owned()
|
||||||
};
|
};
|
||||||
|
|
||||||
let rotten_tomatoes_rating = if let Some(rating) = ratings.rotten_tomatoes {
|
let rotten_tomatoes_rating = if let Some(rating) = ratings.rotten_tomatoes {
|
||||||
rating.value.as_u64().unwrap()
|
if let Some(value) = rating.value.as_u64() {
|
||||||
|
format!("{}%", value)
|
||||||
|
} else {
|
||||||
|
"".to_owned()
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
0u64
|
"".to_owned()
|
||||||
};
|
};
|
||||||
|
|
||||||
let status = get_movie_status(has_file, &app.data.radarr_data.downloads.items, id);
|
let status = get_movie_status(has_file, &app.data.radarr_data.downloads.items, id);
|
||||||
|
|
||||||
app.data.radarr_data.movie_details = ScrollableText::with_string(format!(
|
app.data.radarr_data.movie_details = ScrollableText::with_string(formatdoc!(
|
||||||
"Title: {}\n
|
"Title: {}
|
||||||
Year: {}\n
|
Year: {}
|
||||||
Runtime: {}h {}m\n
|
Runtime: {}h {}m
|
||||||
Status: {}\n
|
Status: {}
|
||||||
Description: {}\n
|
Description: {}
|
||||||
TMDB: {}%\n
|
TMDB: {}
|
||||||
IMDB: {:.1}\n
|
IMDB: {}
|
||||||
Rotten Tomatoes: {}%\n
|
Rotten Tomatoes: {}
|
||||||
Quality Profile: {}\n
|
Quality Profile: {}
|
||||||
Size: {:.2} GB\n
|
Size: {:.2} GB
|
||||||
Path: {}\n
|
Path: {}
|
||||||
Studio: {}\n
|
Studio: {}
|
||||||
Genres: {}",
|
Genres: {}",
|
||||||
title,
|
title,
|
||||||
year,
|
year,
|
||||||
hours,
|
hours,
|
||||||
|
|||||||
@@ -10,20 +10,20 @@ pub async fn parse_response<T: DeserializeOwned>(response: Response) -> Result<T
|
|||||||
|
|
||||||
pub fn get_movie_status(
|
pub fn get_movie_status(
|
||||||
has_file: bool,
|
has_file: bool,
|
||||||
downloads_vec: &Vec<DownloadRecord>,
|
downloads_vec: &[DownloadRecord],
|
||||||
movie_id: Number,
|
movie_id: Number,
|
||||||
) -> String {
|
) -> String {
|
||||||
if !has_file {
|
if !has_file {
|
||||||
if let Some(download) = downloads_vec
|
if let Some(download) = downloads_vec
|
||||||
.iter()
|
.iter()
|
||||||
.find(|&download| download.movie_id == movie_id)
|
.find(|&download| download.movie_id.as_u64().unwrap() == movie_id.as_u64().unwrap())
|
||||||
{
|
{
|
||||||
if download.status == "downloading" {
|
if download.status == "downloading" {
|
||||||
return "Downloading".to_owned();
|
return "Downloading".to_owned();
|
||||||
}
|
}
|
||||||
|
|
||||||
return "Missing".to_owned();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return "Missing".to_owned();
|
||||||
}
|
}
|
||||||
|
|
||||||
"Downloaded".to_owned()
|
"Downloaded".to_owned()
|
||||||
|
|||||||
+40
-6
@@ -11,7 +11,7 @@ use crate::logos::{
|
|||||||
};
|
};
|
||||||
use crate::ui::utils::{
|
use crate::ui::utils::{
|
||||||
centered_rect, horizontal_chunks, horizontal_chunks_with_margin, style_secondary,
|
centered_rect, horizontal_chunks, horizontal_chunks_with_margin, style_secondary,
|
||||||
vertical_chunks, vertical_chunks_with_margin,
|
style_system_function, vertical_chunks, vertical_chunks_with_margin,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod radarr_ui;
|
mod radarr_ui;
|
||||||
@@ -27,10 +27,10 @@ pub fn ui<B: Backend>(f: &mut Frame<B>, app: &mut App) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
draw_context_row(f, app, main_chunks[0]);
|
draw_context_row(f, app, main_chunks[0]);
|
||||||
match *app.get_current_route() {
|
match app.get_current_route().clone() {
|
||||||
Route::Radarr(active_radarr_block) => match active_radarr_block {
|
Route::Radarr(active_radarr_block) => match active_radarr_block {
|
||||||
ActiveRadarrBlock::Movies => radarr_ui::draw_radarr_ui(f, app, main_chunks[1]),
|
ActiveRadarrBlock::Movies => radarr_ui::draw_radarr_ui(f, app, main_chunks[1]),
|
||||||
ActiveRadarrBlock::MovieDetails => draw_popup_over(
|
ActiveRadarrBlock::MovieDetails => draw_small_popup_over(
|
||||||
f,
|
f,
|
||||||
app,
|
app,
|
||||||
main_chunks[1],
|
main_chunks[1],
|
||||||
@@ -48,14 +48,46 @@ pub fn draw_popup_over<B: Backend>(
|
|||||||
area: Rect,
|
area: Rect,
|
||||||
background_fn: fn(&mut Frame<'_, B>, &mut App, Rect),
|
background_fn: fn(&mut Frame<'_, B>, &mut App, Rect),
|
||||||
popup_fn: fn(&mut Frame<'_, B>, &App, Rect),
|
popup_fn: fn(&mut Frame<'_, B>, &App, Rect),
|
||||||
|
percent_x: u16,
|
||||||
|
percent_y: u16,
|
||||||
) {
|
) {
|
||||||
background_fn(f, app, area);
|
background_fn(f, app, area);
|
||||||
|
|
||||||
let popup_area = centered_rect(75, 75, f.size());
|
let popup_area = centered_rect(percent_x, percent_y, f.size());
|
||||||
f.render_widget(Clear, popup_area);
|
f.render_widget(Clear, popup_area);
|
||||||
popup_fn(f, app, popup_area);
|
popup_fn(f, app, popup_area);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn draw_small_popup_over<B: Backend>(
|
||||||
|
f: &mut Frame<'_, B>,
|
||||||
|
app: &mut App,
|
||||||
|
area: Rect,
|
||||||
|
background_fn: fn(&mut Frame<'_, B>, &mut App, Rect),
|
||||||
|
popup_fn: fn(&mut Frame<'_, B>, &App, Rect),
|
||||||
|
) {
|
||||||
|
draw_popup_over(f, app, area, background_fn, popup_fn, 40, 40);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn draw_medium_popup_over<B: Backend>(
|
||||||
|
f: &mut Frame<'_, B>,
|
||||||
|
app: &mut App,
|
||||||
|
area: Rect,
|
||||||
|
background_fn: fn(&mut Frame<'_, B>, &mut App, Rect),
|
||||||
|
popup_fn: fn(&mut Frame<'_, B>, &App, Rect),
|
||||||
|
) {
|
||||||
|
draw_popup_over(f, app, area, background_fn, popup_fn, 60, 60);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn draw_large_popup_over<B: Backend>(
|
||||||
|
f: &mut Frame<'_, B>,
|
||||||
|
app: &mut App,
|
||||||
|
area: Rect,
|
||||||
|
background_fn: fn(&mut Frame<'_, B>, &mut App, Rect),
|
||||||
|
popup_fn: fn(&mut Frame<'_, B>, &App, Rect),
|
||||||
|
) {
|
||||||
|
draw_popup_over(f, app, area, background_fn, popup_fn, 75, 75);
|
||||||
|
}
|
||||||
|
|
||||||
fn draw_context_row<B: Backend>(f: &mut Frame<'_, B>, app: &App, area: Rect) {
|
fn draw_context_row<B: Backend>(f: &mut Frame<'_, B>, app: &App, area: Rect) {
|
||||||
let chunks = horizontal_chunks(
|
let chunks = horizontal_chunks(
|
||||||
vec![
|
vec![
|
||||||
@@ -80,9 +112,11 @@ pub fn loading<B: Backend>(f: &mut Frame<'_, B>, block: Block<'_>, area: Rect, i
|
|||||||
if is_loading {
|
if is_loading {
|
||||||
let text = "\n\n Loading ...\n\n".to_owned();
|
let text = "\n\n Loading ...\n\n".to_owned();
|
||||||
let mut text = Text::from(text);
|
let mut text = Text::from(text);
|
||||||
text.patch_style(style_secondary());
|
text.patch_style(style_system_function());
|
||||||
|
|
||||||
let paragraph = Paragraph::new(text).style(style_secondary()).block(block);
|
let paragraph = Paragraph::new(text)
|
||||||
|
.style(style_system_function())
|
||||||
|
.block(block);
|
||||||
f.render_widget(paragraph, area);
|
f.render_widget(paragraph, area);
|
||||||
} else {
|
} else {
|
||||||
f.render_widget(block, area)
|
f.render_widget(block, area)
|
||||||
|
|||||||
+23
-3
@@ -1,6 +1,7 @@
|
|||||||
use std::ops::Sub;
|
use std::ops::Sub;
|
||||||
|
|
||||||
use chrono::{Duration, Utc};
|
use chrono::{Duration, Utc};
|
||||||
|
use log::debug;
|
||||||
use tui::backend::Backend;
|
use tui::backend::Backend;
|
||||||
use tui::layout::{Alignment, Constraint, Rect};
|
use tui::layout::{Alignment, Constraint, Rect};
|
||||||
use tui::style::{Color, Modifier, Style};
|
use tui::style::{Color, Modifier, Style};
|
||||||
@@ -81,11 +82,21 @@ pub(super) fn draw_radarr_ui<B: Backend>(f: &mut Frame<'_, B>, app: &mut App, ar
|
|||||||
|
|
||||||
pub(super) fn draw_movie_details<B: Backend>(f: &mut Frame<'_, B>, app: &App, area: Rect) {
|
pub(super) fn draw_movie_details<B: Backend>(f: &mut Frame<'_, B>, app: &App, area: Rect) {
|
||||||
let block = title_block("Movie Details");
|
let block = title_block("Movie Details");
|
||||||
let movie_details = &app.data.radarr_data.movie_details.get_text();
|
let movie_details = app.data.radarr_data.movie_details.get_text();
|
||||||
|
|
||||||
if !movie_details.is_empty() {
|
if !movie_details.is_empty() {
|
||||||
let mut text = Text::from(movie_details.clone());
|
let download_status = app
|
||||||
text.patch_style(style_primary());
|
.data
|
||||||
|
.radarr_data
|
||||||
|
.movie_details
|
||||||
|
.items
|
||||||
|
.iter()
|
||||||
|
.find(|&line| line.starts_with("Status: "))
|
||||||
|
.unwrap()
|
||||||
|
.split(": ")
|
||||||
|
.collect::<Vec<&str>>()[1];
|
||||||
|
let mut text = Text::from(movie_details);
|
||||||
|
text.patch_style(determine_style_from_download_status(download_status));
|
||||||
|
|
||||||
let paragraph = Paragraph::new(text)
|
let paragraph = Paragraph::new(text)
|
||||||
.block(block)
|
.block(block)
|
||||||
@@ -197,3 +208,12 @@ fn determine_row_style(app: &App, movie: &Movie) -> Style {
|
|||||||
|
|
||||||
style_primary()
|
style_primary()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn determine_style_from_download_status(download_status: &str) -> Style {
|
||||||
|
match download_status {
|
||||||
|
"Downloaded" => style_primary(),
|
||||||
|
"Downloading" => style_secondary(),
|
||||||
|
"Missing" => style_tertiary(),
|
||||||
|
_ => style_primary(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -65,6 +65,10 @@ pub fn style_default() -> Style {
|
|||||||
Style::default().fg(Color::White)
|
Style::default().fg(Color::White)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn style_system_function() -> Style {
|
||||||
|
Style::default().fg(Color::Yellow)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn style_primary() -> Style {
|
pub fn style_primary() -> Style {
|
||||||
Style::default().fg(Color::Green)
|
Style::default().fg(Color::Green)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user