diff --git a/src/app/app_tests.rs b/src/app/app_tests.rs index aea2490..ffefe31 100644 --- a/src/app/app_tests.rs +++ b/src/app/app_tests.rs @@ -5,6 +5,7 @@ mod tests { use reqwest::header::{HeaderMap, HeaderName, HeaderValue}; use serde_json::Value; use serial_test::serial; + use std::time::{Duration, Instant}; use tokio::sync::mpsc; use crate::app::{App, AppConfig, Data, ServarrConfig, interpolate_env_vars}; @@ -80,9 +81,9 @@ mod tests { assert_eq!(app.server_tabs.index, 0); assert_eq!(app.server_tabs.tabs, expected_tab_routes); assert_eq!(app.tick_until_poll, 400); - assert_eq!(app.ticks_until_scroll, 64); + assert_eq!(app.scroll_interval, Duration::from_millis(100)); assert_eq!(app.tick_count, 0); - assert_eq!(app.ui_scroll_tick_count, 0); + assert!(!app.should_text_scroll); assert!(!app.is_loading); assert!(!app.is_routing); assert!(!app.should_refresh); @@ -101,7 +102,7 @@ mod tests { assert_eq!(app.error, HorizontallyScrollableText::default()); assert_eq!(app.server_tabs.index, 0); assert_eq!(app.tick_until_poll, 400); - assert_eq!(app.ticks_until_scroll, 64); + assert_eq!(app.scroll_interval, Duration::from_millis(100)); assert_eq!(app.tick_count, 0); assert!(!app.is_loading); assert!(!app.is_routing); @@ -247,22 +248,20 @@ mod tests { #[test] fn test_on_ui_scroll_tick() { let mut app = App { - ticks_until_scroll: 1, + scroll_interval: Duration::ZERO, ..App::default() }; - assert_eq!(app.ui_scroll_tick_count, 0); - assert_eq!(app.tick_count, 0); + app.on_ui_scroll_tick(); + assert!(app.should_text_scroll); app.on_ui_scroll_tick(); + assert!(app.should_text_scroll); - assert_eq!(app.ui_scroll_tick_count, 1); - assert_eq!(app.tick_count, 0); - + app.scroll_interval = Duration::from_secs(60); + app.last_scroll = Instant::now(); app.on_ui_scroll_tick(); - - assert_eq!(app.ui_scroll_tick_count, 0); - assert_eq!(app.tick_count, 0); + assert!(!app.should_text_scroll); } #[tokio::test] diff --git a/src/app/mod.rs b/src/app/mod.rs index fc0b234..a660243 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -7,6 +7,7 @@ use reqwest::header::{HeaderMap, HeaderName, HeaderValue}; use serde::{Deserialize, Serialize}; use std::collections::HashMap; use std::path::PathBuf; +use std::time::{Duration, Instant}; use std::{fs, process}; use tokio::sync::mpsc::Sender; use tokio_util::sync::CancellationToken; @@ -41,9 +42,10 @@ pub struct App<'a> { pub error: HorizontallyScrollableText, pub notification: Option, pub tick_until_poll: u64, - pub ticks_until_scroll: u64, + pub scroll_interval: Duration, + pub last_scroll: Instant, pub tick_count: u64, - pub ui_scroll_tick_count: u64, + pub should_text_scroll: bool, pub is_routing: bool, pub is_loading: bool, pub should_refresh: bool, @@ -171,10 +173,11 @@ impl App<'_> { } pub fn on_ui_scroll_tick(&mut self) { - if self.ui_scroll_tick_count == self.ticks_until_scroll { - self.ui_scroll_tick_count = 0; + if self.last_scroll.elapsed() >= self.scroll_interval { + self.should_text_scroll = true; + self.last_scroll = Instant::now(); } else { - self.ui_scroll_tick_count += 1; + self.should_text_scroll = false; } } @@ -260,9 +263,10 @@ impl Default for App<'_> { is_first_render: true, server_tabs: TabState::new(Vec::new()), tick_until_poll: 400, - ticks_until_scroll: 64, + scroll_interval: Duration::from_millis(100), + last_scroll: Instant::now(), tick_count: 0, - ui_scroll_tick_count: 0, + should_text_scroll: false, is_loading: false, is_routing: false, should_refresh: false, diff --git a/src/event/input_event.rs b/src/event/input_event.rs index 67e5897..1dfa0a3 100644 --- a/src/event/input_event.rs +++ b/src/event/input_event.rs @@ -18,10 +18,12 @@ pub struct Events { rx: Receiver>, } +const DEFAULT_TICK_RATE_MS: u64 = 50; + impl Events { pub fn new() -> Self { let (tx, rx) = mpsc::channel(); - let tick_rate: Duration = Duration::from_millis(50); + let tick_rate: Duration = Duration::from_millis(DEFAULT_TICK_RATE_MS); thread::spawn(move || { let mut last_tick = Instant::now(); @@ -51,9 +53,19 @@ impl Events { } pub fn next(&self) -> Result>> { - match self.rx.try_recv() { + match self.rx.recv() { Ok(event) => Ok(Some(event)), _ => Ok(None), } } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn defaults_to_original_tick_rate() { + assert_eq!(DEFAULT_TICK_RATE_MS, 50); + } +} diff --git a/src/main.rs b/src/main.rs index 033c440..a40173f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -277,12 +277,15 @@ async fn start_ui( let input_events = Events::new(); loop { - let mut app = app.lock().await; - - terminal.draw(|f| ui(f, &mut app))?; + { + let mut app = app.lock().await; + terminal.draw(|f| ui(f, &mut app))?; + } match input_events.next()? { Some(InputEvent::KeyEvent(key)) => { + let mut app = app.lock().await; + if key == Key::Char('q') && !app.ignore_special_keys_for_textbox_input { break; } @@ -290,8 +293,11 @@ async fn start_ui( handlers::handle_events(key, &mut app); } - Some(InputEvent::Tick) => app.on_tick().await, - _ => {} + Some(InputEvent::Tick) => { + let mut app = app.lock().await; + app.on_tick().await; + } + None => break, } } diff --git a/src/network/mod.rs b/src/network/mod.rs index 4be177b..f74ba3b 100644 --- a/src/network/mod.rs +++ b/src/network/mod.rs @@ -1,5 +1,5 @@ use std::fmt::Debug; -use std::sync::Arc; +use std::sync::{Arc, OnceLock}; use anyhow::{Result, anyhow}; use async_trait::async_trait; @@ -9,6 +9,7 @@ use regex::Regex; use reqwest::{Client, RequestBuilder}; use serde::Serialize; use serde::de::DeserializeOwned; +use serde_json::Value; use sonarr_network::SonarrEvent; use strum_macros::Display; use tokio::select; @@ -32,6 +33,8 @@ mod network_tests; #[cfg(test)] pub mod servarr_test_utils; +static WHITESPACE_RE: OnceLock = OnceLock::new(); + #[cfg_attr(test, automock)] #[async_trait] pub trait NetworkTrait { @@ -142,11 +145,8 @@ impl<'a, 'b> Network<'a, 'b> { } } else { let status = response.status(); - let whitespace_regex = Regex::new(r"\s+")?; let response_body = response.text().await.unwrap_or_default(); - let error_body = whitespace_regex - .replace_all(&response_body.replace('\n', " "), " ") - .to_string(); + let error_body = format_error_body(&response_body); error!("Request failed. Received {status} response code with body: {response_body}"); self.app.lock().await.handle_error(anyhow!("Request failed. Received {status} response code with body: {error_body}")); @@ -279,6 +279,23 @@ impl<'a, 'b> Network<'a, 'b> { } } +fn format_error_body(response_body: &str) -> String { + let re = WHITESPACE_RE.get_or_init(|| Regex::new(r"\s+").unwrap()); + let body = serde_json::from_str::(response_body) + .ok() + .and_then(|value| { + value + .get("message") + .or_else(|| value.get("errorMessage")) + .or_else(|| value.get("error")) + .and_then(Value::as_str) + .map(ToOwned::to_owned) + }) + .unwrap_or_else(|| response_body.replace('\n', " ")); + + re.replace_all(&body, " ").to_string() +} + #[derive(Clone, Copy, Debug, Display, PartialEq, Eq)] pub enum RequestMethod { Get, diff --git a/src/network/network_tests.rs b/src/network/network_tests.rs index 7dd4c20..2b14efc 100644 --- a/src/network/network_tests.rs +++ b/src/network/network_tests.rs @@ -353,6 +353,51 @@ mod tests { ); } + #[tokio::test] + async fn test_handle_request_non_success_code_uses_json_message_for_error_body() { + let mut server = Server::new_async().await; + let async_server = server + .mock("GET", "/test") + .match_header("X-Api-Key", "test1234") + .with_status(500) + .with_body( + json!({ + "message": "database is locked\ndatabase is locked", + "description": "at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker" + }) + .to_string(), + ) + .create_async() + .await; + let app_arc = Arc::new(Mutex::new(App::test_default())); + let mut network = test_network(&app_arc); + + let resp = network + .handle_request::<(), Test>( + RequestProps { + uri: format!("{}/test", server.url()), + method: RequestMethod::Get, + body: None, + api_token: "test1234".to_owned(), + ignore_status_code: false, + custom_headers: HeaderMap::new(), + }, + |response, mut app| app.error = HorizontallyScrollableText::from(response.value), + ) + .await; + + async_server.assert_async().await; + assert_str_eq!( + app_arc.lock().await.error.text, + "Request failed. Received 500 Internal Server Error response code with body: database is locked database is locked" + ); + assert!(resp.is_err()); + assert_str_eq!( + resp.unwrap_err().to_string(), + "Request failed. Received 500 Internal Server Error response code with body: database is locked database is locked" + ); + } + #[rstest] #[tokio::test] async fn test_call_api( diff --git a/src/ui/lidarr_ui/downloads/mod.rs b/src/ui/lidarr_ui/downloads/mod.rs index 2e0ed1f..004606d 100644 --- a/src/ui/lidarr_ui/downloads/mod.rs +++ b/src/ui/lidarr_ui/downloads/mod.rs @@ -88,7 +88,7 @@ fn draw_downloads(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { output_path.as_ref().unwrap().scroll_left_or_reset( get_width_from_percentage(area, 18), current_selection == *download_record, - app.ui_scroll_tick_count == 0, + app.should_text_scroll, ); } diff --git a/src/ui/lidarr_ui/history/mod.rs b/src/ui/lidarr_ui/history/mod.rs index fb6b8a8..45c26ca 100644 --- a/src/ui/lidarr_ui/history/mod.rs +++ b/src/ui/lidarr_ui/history/mod.rs @@ -60,7 +60,7 @@ fn draw_history_table(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { source_title.scroll_left_or_reset( get_width_from_percentage(area, 50), current_selection == *history_item, - app.ui_scroll_tick_count == 0, + app.should_text_scroll, ); Row::new(vec![ diff --git a/src/ui/lidarr_ui/indexers/test_all_indexers_ui.rs b/src/ui/lidarr_ui/indexers/test_all_indexers_ui.rs index 6a3b30e..b78a74a 100644 --- a/src/ui/lidarr_ui/indexers/test_all_indexers_ui.rs +++ b/src/ui/lidarr_ui/indexers/test_all_indexers_ui.rs @@ -46,7 +46,7 @@ fn draw_test_all_indexers_test_results(f: &mut Frame<'_>, app: &mut App<'_>, are result.validation_failures.scroll_left_or_reset( get_width_from_percentage(area, 86), *result == current_selection, - app.ui_scroll_tick_count == 0, + app.should_text_scroll, ); let pass_fail = if result.is_valid { "+" } else { "x" }; let row = Row::new(vec![ diff --git a/src/ui/lidarr_ui/library/add_artist_ui.rs b/src/ui/lidarr_ui/library/add_artist_ui.rs index bb9ab21..7867130 100644 --- a/src/ui/lidarr_ui/library/add_artist_ui.rs +++ b/src/ui/lidarr_ui/library/add_artist_ui.rs @@ -112,7 +112,7 @@ fn draw_add_artist_search(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { artist.artist_name.scroll_left_or_reset( get_width_from_percentage(area, 27), *artist == current_selection, - app.ui_scroll_tick_count == 0, + app.should_text_scroll, ); Row::new(vec![ diff --git a/src/ui/lidarr_ui/library/album_details_ui.rs b/src/ui/lidarr_ui/library/album_details_ui.rs index 964ee8c..86e7899 100644 --- a/src/ui/lidarr_ui/library/album_details_ui.rs +++ b/src/ui/lidarr_ui/library/album_details_ui.rs @@ -250,7 +250,7 @@ fn draw_album_history_table(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { source_title.scroll_left_or_reset( get_width_from_percentage(area, 40), current_selection == *history_item, - app.ui_scroll_tick_count == 0, + app.should_text_scroll, ); Row::new(vec![ @@ -345,7 +345,7 @@ fn draw_album_releases(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { get_width_from_percentage(area, 35), current_selection == *release && active_lidarr_block != ActiveLidarrBlock::ManualAlbumSearchConfirmPrompt, - app.ui_scroll_tick_count == 0, + app.should_text_scroll, ); let size = convert_to_gb(*size); let rejected_str = if *rejected { "⛔" } else { "" }; diff --git a/src/ui/lidarr_ui/library/artist_details_ui.rs b/src/ui/lidarr_ui/library/artist_details_ui.rs index 939fea4..952bfc1 100644 --- a/src/ui/lidarr_ui/library/artist_details_ui.rs +++ b/src/ui/lidarr_ui/library/artist_details_ui.rs @@ -271,7 +271,7 @@ fn draw_albums_table(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { album.title.scroll_left_or_reset( get_width_from_percentage(area, 33), *album == current_selection, - app.ui_scroll_tick_count == 0, + app.should_text_scroll, ); let monitored = if album.monitored { "🏷" } else { "" }; let album_type = album.album_type.clone().unwrap_or_default(); @@ -376,7 +376,7 @@ fn draw_artist_history_table(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { source_title.scroll_left_or_reset( get_width_from_percentage(area, 40), current_selection == *history_item, - app.ui_scroll_tick_count == 0, + app.should_text_scroll, ); Row::new(vec![ @@ -490,7 +490,7 @@ fn draw_artist_releases(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { get_width_from_percentage(area, 35), current_selection == *release && active_lidarr_block != ActiveLidarrBlock::ManualArtistSearchConfirmPrompt, - app.ui_scroll_tick_count == 0, + app.should_text_scroll, ); let size = convert_to_gb(*size); let rejected_str = if *rejected { "⛔" } else { "" }; diff --git a/src/ui/lidarr_ui/library/mod.rs b/src/ui/lidarr_ui/library/mod.rs index 449a4f9..4f981aa 100644 --- a/src/ui/lidarr_ui/library/mod.rs +++ b/src/ui/lidarr_ui/library/mod.rs @@ -96,7 +96,7 @@ fn draw_library(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { artist.artist_name.scroll_left_or_reset( get_width_from_percentage(area, 25), *artist == current_selection, - app.ui_scroll_tick_count == 0, + app.should_text_scroll, ); let monitored = if artist.monitored { "🏷" } else { "" }; let artist_type = artist.artist_type.clone().unwrap_or_default(); diff --git a/src/ui/lidarr_ui/library/track_details_ui.rs b/src/ui/lidarr_ui/library/track_details_ui.rs index cf330cc..f9c3d72 100644 --- a/src/ui/lidarr_ui/library/track_details_ui.rs +++ b/src/ui/lidarr_ui/library/track_details_ui.rs @@ -158,7 +158,7 @@ fn draw_track_history_table(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { source_title.scroll_left_or_reset( get_width_from_percentage(area, 40), current_selection == *history_item, - app.ui_scroll_tick_count == 0, + app.should_text_scroll, ); Row::new(vec![ diff --git a/src/ui/mod.rs b/src/ui/mod.rs index 502a7c1..17bc5a7 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -139,7 +139,7 @@ fn draw_error(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { app .error - .scroll_left_or_reset(area.width as usize, true, app.ui_scroll_tick_count == 0); + .scroll_left_or_reset(area.width as usize, true, app.should_text_scroll); let paragraph = Paragraph::new(Text::from(app.error.to_string().failure())) .block(block) diff --git a/src/ui/radarr_ui/blocklist/mod.rs b/src/ui/radarr_ui/blocklist/mod.rs index 3fb243b..1101e45 100644 --- a/src/ui/radarr_ui/blocklist/mod.rs +++ b/src/ui/radarr_ui/blocklist/mod.rs @@ -96,7 +96,7 @@ fn draw_blocklist_table(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { movie.title.scroll_left_or_reset( get_width_from_percentage(area, 20), current_selection == *blocklist_item, - app.ui_scroll_tick_count == 0, + app.should_text_scroll, ); let languages_string = languages diff --git a/src/ui/radarr_ui/collections/collection_details_ui.rs b/src/ui/radarr_ui/collections/collection_details_ui.rs index 3daeaa4..f0bf0d4 100644 --- a/src/ui/radarr_ui/collections/collection_details_ui.rs +++ b/src/ui/radarr_ui/collections/collection_details_ui.rs @@ -90,7 +90,7 @@ pub fn draw_collection_details(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) movie.title.scroll_left_or_reset( get_width_from_percentage(table_area, 20), current_selection == *movie, - app.ui_scroll_tick_count == 0, + app.should_text_scroll, ); let (hours, minutes) = convert_runtime(movie.runtime); let imdb_rating = movie diff --git a/src/ui/radarr_ui/collections/mod.rs b/src/ui/radarr_ui/collections/mod.rs index 63ed8a8..870a123 100644 --- a/src/ui/radarr_ui/collections/mod.rs +++ b/src/ui/radarr_ui/collections/mod.rs @@ -70,7 +70,7 @@ pub(super) fn draw_collections(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) collection.title.scroll_left_or_reset( get_width_from_percentage(area, 25), *collection == current_selection, - app.ui_scroll_tick_count == 0, + app.should_text_scroll, ); let monitored = if collection.monitored { "🏷" } else { "" }; let search_on_add = if collection.search_on_add { diff --git a/src/ui/radarr_ui/downloads/mod.rs b/src/ui/radarr_ui/downloads/mod.rs index 2e52d7b..af14789 100644 --- a/src/ui/radarr_ui/downloads/mod.rs +++ b/src/ui/radarr_ui/downloads/mod.rs @@ -87,7 +87,7 @@ fn draw_downloads(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { output_path.as_ref().unwrap().scroll_left_or_reset( get_width_from_percentage(area, 18), current_selection == *download_record, - app.ui_scroll_tick_count == 0, + app.should_text_scroll, ); } diff --git a/src/ui/radarr_ui/history/mod.rs b/src/ui/radarr_ui/history/mod.rs index 797ee58..5ac566f 100644 --- a/src/ui/radarr_ui/history/mod.rs +++ b/src/ui/radarr_ui/history/mod.rs @@ -61,7 +61,7 @@ fn draw_history_table(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { source_title.scroll_left_or_reset( get_width_from_percentage(area, 40), current_selection == *history_item, - app.ui_scroll_tick_count == 0, + app.should_text_scroll, ); Row::new(vec![ diff --git a/src/ui/radarr_ui/indexers/test_all_indexers_ui.rs b/src/ui/radarr_ui/indexers/test_all_indexers_ui.rs index 3fc509d..12bc402 100644 --- a/src/ui/radarr_ui/indexers/test_all_indexers_ui.rs +++ b/src/ui/radarr_ui/indexers/test_all_indexers_ui.rs @@ -47,7 +47,7 @@ fn draw_test_all_indexers_test_results(f: &mut Frame<'_>, app: &mut App<'_>, are result.validation_failures.scroll_left_or_reset( get_width_from_percentage(area, 86), *result == current_selection, - app.ui_scroll_tick_count == 0, + app.should_text_scroll, ); let pass_fail = if result.is_valid { "✔" } else { "❌" }; let row = Row::new(vec![ diff --git a/src/ui/radarr_ui/library/add_movie_ui.rs b/src/ui/radarr_ui/library/add_movie_ui.rs index f3afa39..fa24913 100644 --- a/src/ui/radarr_ui/library/add_movie_ui.rs +++ b/src/ui/radarr_ui/library/add_movie_ui.rs @@ -141,7 +141,7 @@ fn draw_add_movie_search(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { movie.title.scroll_left_or_reset( get_width_from_percentage(area, 27), *movie == current_selection, - app.ui_scroll_tick_count == 0, + app.should_text_scroll, ); Row::new(vec![ diff --git a/src/ui/radarr_ui/library/mod.rs b/src/ui/radarr_ui/library/mod.rs index 2ba46ae..0b1af8d 100644 --- a/src/ui/radarr_ui/library/mod.rs +++ b/src/ui/radarr_ui/library/mod.rs @@ -90,7 +90,7 @@ fn draw_library(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { movie.title.scroll_left_or_reset( get_width_from_percentage(area, 27), *movie == current_selection, - app.ui_scroll_tick_count == 0, + app.should_text_scroll, ); let monitored = if movie.monitored { "🏷" } else { "" }; let studio = movie.studio.clone().unwrap_or_default(); diff --git a/src/ui/radarr_ui/library/movie_details_ui.rs b/src/ui/radarr_ui/library/movie_details_ui.rs index e36ecad..bd2c41f 100644 --- a/src/ui/radarr_ui/library/movie_details_ui.rs +++ b/src/ui/radarr_ui/library/movie_details_ui.rs @@ -250,7 +250,7 @@ fn draw_movie_history(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { movie_history_item.source_title.scroll_left_or_reset( get_width_from_percentage(area, 34), current_selection == *movie_history_item, - app.ui_scroll_tick_count == 0, + app.should_text_scroll, ); Row::new(vec![ @@ -402,7 +402,7 @@ fn draw_movie_releases(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { get_width_from_percentage(area, 30), current_selection == *release && current_route != ActiveRadarrBlock::ManualSearchConfirmPrompt.into(), - app.ui_scroll_tick_count == 0, + app.should_text_scroll, ); let size = convert_to_gb(*size); let rejected_str = if *rejected { "⛔" } else { "" }; diff --git a/src/ui/sonarr_ui/downloads/mod.rs b/src/ui/sonarr_ui/downloads/mod.rs index 5706bd4..bf46b5b 100644 --- a/src/ui/sonarr_ui/downloads/mod.rs +++ b/src/ui/sonarr_ui/downloads/mod.rs @@ -88,7 +88,7 @@ fn draw_downloads(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { output_path.as_ref().unwrap().scroll_left_or_reset( get_width_from_percentage(area, 18), current_selection == *download_record, - app.ui_scroll_tick_count == 0, + app.should_text_scroll, ); } diff --git a/src/ui/sonarr_ui/history/mod.rs b/src/ui/sonarr_ui/history/mod.rs index b37bf8c..8e6a24a 100644 --- a/src/ui/sonarr_ui/history/mod.rs +++ b/src/ui/sonarr_ui/history/mod.rs @@ -61,7 +61,7 @@ fn draw_history_table(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { source_title.scroll_left_or_reset( get_width_from_percentage(area, 40), current_selection == *history_item, - app.ui_scroll_tick_count == 0, + app.should_text_scroll, ); Row::new(vec![ diff --git a/src/ui/sonarr_ui/indexers/test_all_indexers_ui.rs b/src/ui/sonarr_ui/indexers/test_all_indexers_ui.rs index bc02ed8..6a3c164 100644 --- a/src/ui/sonarr_ui/indexers/test_all_indexers_ui.rs +++ b/src/ui/sonarr_ui/indexers/test_all_indexers_ui.rs @@ -46,7 +46,7 @@ fn draw_test_all_indexers_test_results(f: &mut Frame<'_>, app: &mut App<'_>, are result.validation_failures.scroll_left_or_reset( get_width_from_percentage(area, 86), *result == current_selection, - app.ui_scroll_tick_count == 0, + app.should_text_scroll, ); let pass_fail = if result.is_valid { "✔" } else { "❌" }; let row = Row::new(vec![ diff --git a/src/ui/sonarr_ui/library/add_series_ui.rs b/src/ui/sonarr_ui/library/add_series_ui.rs index 942cb8e..5836f01 100644 --- a/src/ui/sonarr_ui/library/add_series_ui.rs +++ b/src/ui/sonarr_ui/library/add_series_ui.rs @@ -121,7 +121,7 @@ fn draw_add_series_search(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { series.title.scroll_left_or_reset( get_width_from_percentage(area, 27), *series == current_selection, - app.ui_scroll_tick_count == 0, + app.should_text_scroll, ); Row::new(vec![ diff --git a/src/ui/sonarr_ui/library/episode_details_ui.rs b/src/ui/sonarr_ui/library/episode_details_ui.rs index 3d78a26..c1776e1 100644 --- a/src/ui/sonarr_ui/library/episode_details_ui.rs +++ b/src/ui/sonarr_ui/library/episode_details_ui.rs @@ -279,7 +279,7 @@ fn draw_episode_history_table(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) source_title.scroll_left_or_reset( get_width_from_percentage(area, 40), current_selection == *history_item, - app.ui_scroll_tick_count == 0, + app.should_text_scroll, ); Row::new(vec![ @@ -414,7 +414,7 @@ fn draw_episode_releases(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { get_width_from_percentage(area, 30), current_selection == *release && active_sonarr_block != ActiveSonarrBlock::ManualEpisodeSearchConfirmPrompt, - app.ui_scroll_tick_count == 0, + app.should_text_scroll, ); let size = convert_to_gb(*size); let rejected_str = if *rejected { "⛔" } else { "" }; diff --git a/src/ui/sonarr_ui/library/mod.rs b/src/ui/sonarr_ui/library/mod.rs index 19569ef..2cef864 100644 --- a/src/ui/sonarr_ui/library/mod.rs +++ b/src/ui/sonarr_ui/library/mod.rs @@ -95,7 +95,7 @@ fn draw_library(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { series.title.scroll_left_or_reset( get_width_from_percentage(area, 23), *series == current_selection, - app.ui_scroll_tick_count == 0, + app.should_text_scroll, ); let monitored = if series.monitored { "🏷" } else { "" }; let certification = series.certification.clone().unwrap_or_default(); diff --git a/src/ui/sonarr_ui/library/season_details_ui.rs b/src/ui/sonarr_ui/library/season_details_ui.rs index f77caad..92926a3 100644 --- a/src/ui/sonarr_ui/library/season_details_ui.rs +++ b/src/ui/sonarr_ui/library/season_details_ui.rs @@ -266,7 +266,7 @@ fn draw_season_history_table(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { source_title.scroll_left_or_reset( get_width_from_percentage(area, 40), current_selection == *history_item, - app.ui_scroll_tick_count == 0, + app.should_text_scroll, ); Row::new(vec![ @@ -377,7 +377,7 @@ fn draw_season_releases(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { get_width_from_percentage(area, 30), current_selection == *release && active_sonarr_block != ActiveSonarrBlock::ManualSeasonSearchConfirmPrompt, - app.ui_scroll_tick_count == 0, + app.should_text_scroll, ); let size = convert_to_gb(*size); let rejected_str = if *rejected { "⛔" } else { "" }; diff --git a/src/ui/sonarr_ui/library/series_details_ui.rs b/src/ui/sonarr_ui/library/series_details_ui.rs index 37dce9b..3958763 100644 --- a/src/ui/sonarr_ui/library/series_details_ui.rs +++ b/src/ui/sonarr_ui/library/series_details_ui.rs @@ -314,7 +314,7 @@ fn draw_series_history_table(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { source_title.scroll_left_or_reset( get_width_from_percentage(area, 40), current_selection == *history_item, - app.ui_scroll_tick_count == 0, + app.should_text_scroll, ); Row::new(vec![