diff --git a/toki-tui/README.md b/toki-tui/README.md index deaafdc..963364c 100644 --- a/toki-tui/README.md +++ b/toki-tui/README.md @@ -43,6 +43,7 @@ Current variables: TOKI_TUI_API_URL="http://localhost:8080" TOKI_TUI_GIT_DEFAULT_PREFIX="Development" TOKI_TUI_TASK_FILTER="+work project:Toki" +TOKI_TUI_AUTO_RESIZE_TIMER=true ``` Environment variables override values from `config.toml`. @@ -60,6 +61,11 @@ git_default_prefix = "Utveckling" # Leave empty to show all pending tasks. # Example: "+work project:Toki" task_filter = "" + +# Whether to automatically resize the timer widget when the timer starts/stops. +# When true (default), the timer grows large when running and shrinks when stopped. +# Set to false to keep the timer at a fixed (normal) size at all times. +auto_resize_timer = true ``` ### Example: local dev setup diff --git a/toki-tui/src/app/mod.rs b/toki-tui/src/app/mod.rs index 95341bb..4f94075 100644 --- a/toki-tui/src/app/mod.rs +++ b/toki-tui/src/app/mod.rs @@ -112,6 +112,7 @@ pub struct App { // Config values used at runtime pub task_filter: String, pub git_default_prefix: String, + pub auto_resize_timer: bool, } impl App { @@ -175,6 +176,7 @@ impl App { milltime_reauth: None, task_filter: cfg.task_filter.clone(), git_default_prefix: cfg.git_default_prefix.clone(), + auto_resize_timer: cfg.auto_resize_timer, } } @@ -273,24 +275,35 @@ impl App { } /// Start a new timer - pub fn start_timer(&mut self) { + pub fn start_timer(&mut self, auto_resize: bool) { self.timer_state = TimerState::Running; self.absolute_start = Some(OffsetDateTime::now_utc()); self.local_start = Some(Instant::now()); - self.timer_size = TimerSize::Large; + if auto_resize { + self.timer_size = TimerSize::Large; + } // Shift focus: running timer row is inserted at index 0, pushing DB entries up by 1 if let Some(idx) = self.focused_this_week_index { self.focused_this_week_index = Some(idx + 1); } } - /// Stop the timer (without saving) - #[allow(dead_code)] - pub fn stop_timer(&mut self) { + /// Stop the timer (without saving). + pub fn stop_timer(&mut self, auto_resize: bool) { self.timer_state = TimerState::Stopped; - self.timer_size = TimerSize::Normal; + if auto_resize { + self.timer_size = TimerSize::Normal; + } self.absolute_start = None; self.local_start = None; + // Shift focus back: running timer row at index 0 is removed, pushing DB entries down by 1 + if let Some(idx) = self.focused_this_week_index { + self.focused_this_week_index = if idx == 0 { + None + } else { + Some(idx.saturating_sub(1)) + }; + } } pub fn set_status(&mut self, message: String) { diff --git a/toki-tui/src/config.rs b/toki-tui/src/config.rs index c65c555..fa2c995 100644 --- a/toki-tui/src/config.rs +++ b/toki-tui/src/config.rs @@ -15,6 +15,10 @@ pub struct TokiConfig { /// when no conventional commit prefix or ticket number is found. #[serde(default = "default_git_prefix")] pub git_default_prefix: String, + /// Whether to automatically resize the timer to Large when started + /// and back to Normal when stopped. Default: true. + #[serde(default = "default_auto_resize_timer")] + pub auto_resize_timer: bool, } fn default_api_url() -> String { @@ -25,12 +29,17 @@ fn default_git_prefix() -> String { "Utveckling".to_string() } +fn default_auto_resize_timer() -> bool { + true +} + impl Default for TokiConfig { fn default() -> Self { Self { api_url: default_api_url(), task_filter: String::new(), git_default_prefix: default_git_prefix(), + auto_resize_timer: default_auto_resize_timer(), } } } @@ -68,6 +77,7 @@ impl TokiConfig { .set_default("api_url", default_api_url())? .set_default("task_filter", "")? .set_default("git_default_prefix", default_git_prefix())? + .set_default("auto_resize_timer", default_auto_resize_timer())? .add_source(config::File::from(path.clone()).required(false)) .add_source( config::Environment::with_prefix("TOKI_TUI") diff --git a/toki-tui/src/runtime/actions.rs b/toki-tui/src/runtime/actions.rs index 88bc719..f56021f 100644 --- a/toki-tui/src/runtime/actions.rs +++ b/toki-tui/src/runtime/actions.rs @@ -12,7 +12,9 @@ pub(crate) fn restore_active_timer(app: &mut App, timer: crate::types::ActiveTim app.absolute_start = Some(timer.start_time); app.local_start = Some(Instant::now() - Duration::from_secs(elapsed_secs)); app.timer_state = app::TimerState::Running; - app.timer_size = app::TimerSize::Large; + if app.auto_resize_timer { + app.timer_size = app::TimerSize::Large; + } if let (Some(id), Some(name)) = (timer.project_id, timer.project_name) { app.selected_project = Some(crate::types::Project { id, name }); } @@ -149,7 +151,8 @@ pub(super) async fn handle_start_timer(app: &mut App, client: &mut ApiClient) -> } return Ok(()); } - app.start_timer(); + let auto_resize = app.auto_resize_timer; + app.start_timer(auto_resize); app.clear_status(); } app::TimerState::Running => { @@ -388,7 +391,8 @@ async fn resume_entry(entry: types::TimeEntry, app: &mut App, client: &mut ApiCl Ok(()) => { // Only mutate local state after confirmed server success app.copy_entry_fields(&entry); - app.start_timer(); // sets TimerState::Running + TimerSize::Large + local_start + let auto_resize = app.auto_resize_timer; + app.start_timer(auto_resize); // sets TimerState::Running + TimerSize::Large + local_start app.set_status(format!( "Resumed: {}: {}", entry.project_name, entry.activity_name @@ -459,7 +463,8 @@ pub(super) async fn handle_save_timer_with_action( { app.set_status(format!("Saved but could not restart timer: {}", e)); } else { - app.start_timer(); + let auto_resize = app.auto_resize_timer; + app.start_timer(auto_resize); app.set_status(format!( "Saved {} to {} / {}", duration_str, project_display, activity_display @@ -475,7 +480,8 @@ pub(super) async fn handle_save_timer_with_action( if let Err(e) = client.start_timer(None, None, None, None, None).await { app.set_status(format!("Saved but could not restart timer: {}", e)); } else { - app.start_timer(); + let auto_resize = app.auto_resize_timer; + app.start_timer(auto_resize); app.set_status(format!( "Saved {}. Timer started. Press P to select project.", duration_str @@ -483,17 +489,7 @@ pub(super) async fn handle_save_timer_with_action( } } app::SaveAction::SaveAndStop => { - app.timer_state = app::TimerState::Stopped; - app.timer_size = app::TimerSize::Normal; - app.absolute_start = None; - app.local_start = None; - if let Some(idx) = app.focused_this_week_index { - app.focused_this_week_index = if idx == 0 { - None - } else { - Some(idx.saturating_sub(1)) - }; - } + app.stop_timer(app.auto_resize_timer); app.set_status(format!( "Saved {} to {} / {}", duration_str, project_display, activity_display