From ace5c1bf334847bcadfaaa6e32fbe3f3389b8d5b Mon Sep 17 00:00:00 2001 From: Ian Keane Date: Sun, 23 Nov 2025 13:13:14 -0500 Subject: [PATCH] Updated tracking indicator --- src/ui.rs | 67 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 39 insertions(+), 28 deletions(-) diff --git a/src/ui.rs b/src/ui.rs index 04d162c..36c6ad4 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -170,14 +170,35 @@ fn render_new_entry(frame: &mut Frame, app: &App) { } fn render_bottom_bar(frame: &mut Frame, area: Rect, app: &App) { - // Render status message if present + // Split the bottom bar into left (tracking indicator) and right (help/status) + let chunks = Layout::default() + .direction(Direction::Horizontal) + .constraints([Constraint::Percentage(70), Constraint::Percentage(30)]) + .split(area); + + // Left side: Tracking indicator (only when actively tracking) + if let Some((active_item, _)) = &app.state.active_timer { + let tracking_text = if !active_item.tags.is_empty() { + format!("❯❯ Tracking {} [{}] ❯❯", active_item.tags.join(", "), active_item.name) + } else { + format!("❯❯ Tracking {} ❯❯", active_item.name) + }; + + let tracking = Paragraph::new(tracking_text) + .alignment(Alignment::Left) + .style(Style::default().fg(ACTIVE_COLOR).add_modifier(Modifier::BOLD)); + frame.render_widget(tracking, chunks[0]); + } + // No else - show nothing when not tracking + + // Right side: Status message or help hint if let Some((ref message, _)) = app.status_message { let text = Paragraph::new(message.as_str()) .style(Style::default().fg(Color::Yellow)) - .alignment(Alignment::Center); - frame.render_widget(text, area); + .alignment(Alignment::Right); + frame.render_widget(text, chunks[1]); } else if app.config.show_help_hint { - render_help_hint(frame, area); + render_help_hint(frame, chunks[1]); } } @@ -343,7 +364,7 @@ fn render_section( items: &[TimeItem], is_active: bool, selected: usize, - state: &AppState, + _state: &AppState, ) { let border_color = if is_active { ACTIVE_COLOR @@ -360,17 +381,7 @@ fn render_section( .iter() .enumerate() .map(|(i, item)| { - let is_running = state - .active_timer - .as_ref() - .map(|(active, _)| active.name == item.name) - .unwrap_or(false); - - let style = if is_running { - Style::default() - .fg(ACTIVE_COLOR) - .add_modifier(Modifier::BOLD) - } else if i == selected && is_active { + let style = if i == selected && is_active { Style::default() .fg(border_color) .add_modifier(Modifier::REVERSED) @@ -502,28 +513,28 @@ fn render_log_view(frame: &mut Frame, app: &App) { let mut frame_count = 0; let mut selected_line_start = 0; let mut selected_line_end = 0; - + // First pass: find the date/project containing the selected frame let mut current_date = String::new(); let mut current_project = String::new(); - + // Determine what counts as an entry based on grouping mode let is_by_project = matches!(app.log_view_grouping, LogViewGrouping::ByProject); - + for (_idx, line) in app.log_view_content.iter().enumerate() { if !line.starts_with('\t') && !line.is_empty() && !line.starts_with(" ") { current_date = line.clone(); } else if line.starts_with(" ") && !line.starts_with("\t") { current_project = line.clone(); } - + // Only count actual entries (not all tab-indented lines) let is_entry = if is_by_project { line.starts_with("\t\t") // Double tab for ByProject } else { line.starts_with('\t') && !line.starts_with("\t\t") // Single tab for ByDate }; - + if is_entry { if frame_count == app.log_view_selected { selected_date = current_date.clone(); @@ -533,7 +544,7 @@ fn render_log_view(frame: &mut Frame, app: &App) { frame_count += 1; } } - + // Second pass: determine the range of lines to highlight match app.log_view_selection_level { LogViewSelection::Entry => { @@ -545,7 +556,7 @@ fn render_log_view(frame: &mut Frame, app: &App) { } else { line.starts_with('\t') && !line.starts_with("\t\t") }; - + if is_entry { if frame_count == app.log_view_selected { selected_line_start = idx; @@ -560,7 +571,7 @@ fn render_log_view(frame: &mut Frame, app: &App) { // Find the range of the selected project (within the same day) let mut in_target_project = false; current_date = String::new(); - + for (idx, line) in app.log_view_content.iter().enumerate() { if !line.starts_with('\t') && !line.is_empty() && !line.starts_with(" ") { current_date = line.clone(); @@ -582,7 +593,7 @@ fn render_log_view(frame: &mut Frame, app: &App) { LogViewSelection::Day => { // Find the range of the selected day let mut in_target_day = false; - + for (idx, line) in app.log_view_content.iter().enumerate() { if !line.starts_with('\t') && !line.is_empty() && !line.starts_with(" ") { if line == &selected_date { @@ -602,14 +613,14 @@ fn render_log_view(frame: &mut Frame, app: &App) { selected_line_end = app.log_view_content.len().saturating_sub(1); } } - + // Third pass: render with highlighting app.log_view_content .iter() .enumerate() .map(|(idx, line)| { let is_selected = idx >= selected_line_start && idx <= selected_line_end; - + let style = if is_selected { Style::default() .fg(ACTIVE_COLOR) @@ -703,7 +714,7 @@ fn render_log_view_help(frame: &mut Frame, app: &App) { .wrap(ratatui::widgets::Wrap { trim: true }); frame.render_widget(paragraph, area); - + // Render command bar let bar_area = Rect::new( 0,