Updated tracking indicator

This commit is contained in:
Ian Keane 2025-11-23 13:13:14 -05:00
parent f9459edf09
commit ace5c1bf33

View file

@ -170,14 +170,35 @@ fn render_new_entry(frame: &mut Frame, app: &App) {
} }
fn render_bottom_bar(frame: &mut Frame, area: Rect, 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 { if let Some((ref message, _)) = app.status_message {
let text = Paragraph::new(message.as_str()) let text = Paragraph::new(message.as_str())
.style(Style::default().fg(Color::Yellow)) .style(Style::default().fg(Color::Yellow))
.alignment(Alignment::Center); .alignment(Alignment::Right);
frame.render_widget(text, area); frame.render_widget(text, chunks[1]);
} else if app.config.show_help_hint { } 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], items: &[TimeItem],
is_active: bool, is_active: bool,
selected: usize, selected: usize,
state: &AppState, _state: &AppState,
) { ) {
let border_color = if is_active { let border_color = if is_active {
ACTIVE_COLOR ACTIVE_COLOR
@ -360,17 +381,7 @@ fn render_section(
.iter() .iter()
.enumerate() .enumerate()
.map(|(i, item)| { .map(|(i, item)| {
let is_running = state let style = if i == selected && is_active {
.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 {
Style::default() Style::default()
.fg(border_color) .fg(border_color)
.add_modifier(Modifier::REVERSED) .add_modifier(Modifier::REVERSED)
@ -502,28 +513,28 @@ fn render_log_view(frame: &mut Frame, app: &App) {
let mut frame_count = 0; let mut frame_count = 0;
let mut selected_line_start = 0; let mut selected_line_start = 0;
let mut selected_line_end = 0; let mut selected_line_end = 0;
// First pass: find the date/project containing the selected frame // First pass: find the date/project containing the selected frame
let mut current_date = String::new(); let mut current_date = String::new();
let mut current_project = String::new(); let mut current_project = String::new();
// Determine what counts as an entry based on grouping mode // Determine what counts as an entry based on grouping mode
let is_by_project = matches!(app.log_view_grouping, LogViewGrouping::ByProject); let is_by_project = matches!(app.log_view_grouping, LogViewGrouping::ByProject);
for (_idx, line) in app.log_view_content.iter().enumerate() { for (_idx, line) in app.log_view_content.iter().enumerate() {
if !line.starts_with('\t') && !line.is_empty() && !line.starts_with(" ") { if !line.starts_with('\t') && !line.is_empty() && !line.starts_with(" ") {
current_date = line.clone(); current_date = line.clone();
} else if line.starts_with(" ") && !line.starts_with("\t") { } else if line.starts_with(" ") && !line.starts_with("\t") {
current_project = line.clone(); current_project = line.clone();
} }
// Only count actual entries (not all tab-indented lines) // Only count actual entries (not all tab-indented lines)
let is_entry = if is_by_project { let is_entry = if is_by_project {
line.starts_with("\t\t") // Double tab for ByProject line.starts_with("\t\t") // Double tab for ByProject
} else { } else {
line.starts_with('\t') && !line.starts_with("\t\t") // Single tab for ByDate line.starts_with('\t') && !line.starts_with("\t\t") // Single tab for ByDate
}; };
if is_entry { if is_entry {
if frame_count == app.log_view_selected { if frame_count == app.log_view_selected {
selected_date = current_date.clone(); selected_date = current_date.clone();
@ -533,7 +544,7 @@ fn render_log_view(frame: &mut Frame, app: &App) {
frame_count += 1; frame_count += 1;
} }
} }
// Second pass: determine the range of lines to highlight // Second pass: determine the range of lines to highlight
match app.log_view_selection_level { match app.log_view_selection_level {
LogViewSelection::Entry => { LogViewSelection::Entry => {
@ -545,7 +556,7 @@ fn render_log_view(frame: &mut Frame, app: &App) {
} else { } else {
line.starts_with('\t') && !line.starts_with("\t\t") line.starts_with('\t') && !line.starts_with("\t\t")
}; };
if is_entry { if is_entry {
if frame_count == app.log_view_selected { if frame_count == app.log_view_selected {
selected_line_start = idx; 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) // Find the range of the selected project (within the same day)
let mut in_target_project = false; let mut in_target_project = false;
current_date = String::new(); current_date = String::new();
for (idx, line) in app.log_view_content.iter().enumerate() { for (idx, line) in app.log_view_content.iter().enumerate() {
if !line.starts_with('\t') && !line.is_empty() && !line.starts_with(" ") { if !line.starts_with('\t') && !line.is_empty() && !line.starts_with(" ") {
current_date = line.clone(); current_date = line.clone();
@ -582,7 +593,7 @@ fn render_log_view(frame: &mut Frame, app: &App) {
LogViewSelection::Day => { LogViewSelection::Day => {
// Find the range of the selected day // Find the range of the selected day
let mut in_target_day = false; let mut in_target_day = false;
for (idx, line) in app.log_view_content.iter().enumerate() { for (idx, line) in app.log_view_content.iter().enumerate() {
if !line.starts_with('\t') && !line.is_empty() && !line.starts_with(" ") { if !line.starts_with('\t') && !line.is_empty() && !line.starts_with(" ") {
if line == &selected_date { 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); selected_line_end = app.log_view_content.len().saturating_sub(1);
} }
} }
// Third pass: render with highlighting // Third pass: render with highlighting
app.log_view_content app.log_view_content
.iter() .iter()
.enumerate() .enumerate()
.map(|(idx, line)| { .map(|(idx, line)| {
let is_selected = idx >= selected_line_start && idx <= selected_line_end; let is_selected = idx >= selected_line_start && idx <= selected_line_end;
let style = if is_selected { let style = if is_selected {
Style::default() Style::default()
.fg(ACTIVE_COLOR) .fg(ACTIVE_COLOR)
@ -703,7 +714,7 @@ fn render_log_view_help(frame: &mut Frame, app: &App) {
.wrap(ratatui::widgets::Wrap { trim: true }); .wrap(ratatui::widgets::Wrap { trim: true });
frame.render_widget(paragraph, area); frame.render_widget(paragraph, area);
// Render command bar // Render command bar
let bar_area = Rect::new( let bar_area = Rect::new(
0, 0,