diff --git a/src/view/mod.rs b/src/view/mod.rs index deaaa23..d760f82 100644 --- a/src/view/mod.rs +++ b/src/view/mod.rs @@ -360,25 +360,16 @@ fn render_overlay( // ── Todo ────────────────────────────────────────────────────── crate::app::state::types::Overlay::Todo => { let block = block - .title(Span::styled(" 📋 Tasks ", Style::default().fg(Theme::ACCENT_PURPLE).add_modifier(Modifier::BOLD))) + .title(Span::styled(" Tasks ", Style::default().fg(Theme::ACCENT_PURPLE).add_modifier(Modifier::BOLD))) .border_style(Style::default().fg(Theme::ACCENT_PURPLE)); - let msg_count = state.transcript_cache.messages.len(); - let lines = vec![ - Line::from(Span::styled( - " Session Activity", - Style::default().fg(Theme::TEXT).add_modifier(Modifier::BOLD), - )), - Line::from(Span::raw("")), - Line::from(Span::styled( - format!(" Messages: {msg_count}"), - Style::default().fg(Theme::INFO), - )), - Line::from(Span::styled( - format!(" Overlay: {:?}", state.misc.overlay), - Style::default().fg(Theme::TEXT_DIM), - )), - ]; - let paragraph = Paragraph::new(lines).block(block); + let content = if state.misc.todo_content.is_empty() { + " No tasks yet." + } else { + &state.misc.todo_content + }; + let paragraph = Paragraph::new(content) + .block(block) + .wrap(Wrap { trim: false }); frame.render_widget(paragraph, overlay_area); } @@ -615,90 +606,75 @@ fn render_overlay( // ── Usage ──────────────────────────────────────────────────── crate::app::state::types::Overlay::Usage => { let block = block - .title(Span::styled(" 📊 Usage ", Style::default().fg(Theme::INFO).add_modifier(Modifier::BOLD))) + .title(Span::styled(" Usage ", Style::default().fg(Theme::INFO).add_modifier(Modifier::BOLD))) .border_style(Style::default().fg(Theme::INFO)); let runtime = state.session_runtime.as_ref(); - let (tokens_in, tokens_out, api_calls, review_tokens, session_start) = runtime - .map_or((0, 0, 0, 0, 0), |r| { - ( - r.usage.tokens_in, - r.usage.tokens_out, - r.usage.api_calls, - r.usage.review_tokens, - r.session_start, - ) - }); + let now_ms = chrono::Utc::now().timestamp_millis(); + let summary = runtime.map(|r| sidebar::compute_usage_summary(&r.usage, r.session_start, now_ms)); let (edit_count, lesson_count, review_count, consec_empty) = runtime .map_or((0, 0, 0, 0), |r| { - ( - r.edit_count, - r.lesson_count, - r.review_count, - r.consecutive_empty_reviews, - ) + (r.edit_count, r.lesson_count, r.review_count, r.consecutive_empty_reviews) }); - let elapsed_ms = chrono::Utc::now().timestamp_millis().saturating_sub(session_start); - let hours = elapsed_ms / 3_600_000; - let minutes = (elapsed_ms % 3_600_000) / 60_000; - let seconds = (elapsed_ms % 60000) / 1000; - let total_tokens = tokens_in.saturating_add(tokens_out); - let self_learning_total = review_tokens; - let main_tokens = total_tokens.saturating_sub(self_learning_total); - let lines = vec![ + let mut lines = vec![ Line::from(Span::styled( " Token Usage", Style::default().fg(Theme::INFO).add_modifier(Modifier::BOLD), )), Line::from(Span::raw("")), - Line::from(Span::styled( - format!(" Main agent: {main_tokens} tokens"), - Style::default().fg(Theme::TEXT), - )), - Line::from(Span::styled( - format!(" Self-learning: {self_learning_total} tokens"), - Style::default().fg(Theme::TEXT_MUTED), - )), - Line::from(Span::styled( - format!(" Total: {total_tokens} tokens"), - Style::default().fg(Theme::TEXT).add_modifier(Modifier::BOLD), - )), - Line::from(Span::styled( - format!(" API calls: {api_calls}"), - Style::default().fg(Theme::TEXT), - )), - Line::from(Span::raw("")), - Line::from(Span::styled( - " Activity", - Style::default().fg(Theme::INFO).add_modifier(Modifier::BOLD), - )), - Line::from(Span::styled( - format!(" Edits: {edit_count}"), - Style::default().fg(Theme::TEXT), - )), - Line::from(Span::styled( - format!(" Reviews: {review_count}"), - Style::default().fg(Theme::TEXT), - )), - Line::from(Span::styled( - format!(" Lessons: {lesson_count}"), - Style::default().fg(Theme::TEXT_MUTED), - )), - Line::from(Span::styled( - format!(" Empty reviews: {}", - if consec_empty > 3 { - format!("{consec_empty} ⚠") - } else { - consec_empty.to_string() - }, - ), - Style::default().fg(if consec_empty > 3 { Theme::WARNING } else { Theme::TEXT_DIM }), - )), - Line::from(Span::raw("")), - Line::from(Span::styled( - format!(" Session: {hours}h {minutes}m {seconds}s"), - Style::default().fg(Theme::TEXT_DIM), - )), ]; + if let Some(s) = &summary { + lines.push(Line::from(Span::styled( + format!(" Main agent: {} tokens", s.main_tokens), + Style::default().fg(Theme::TEXT), + ))); + lines.push(Line::from(Span::styled( + format!(" Self-learning: {} tokens", s.self_learning_tokens), + Style::default().fg(Theme::TEXT_MUTED), + ))); + lines.push(Line::from(Span::styled( + format!(" Total: {} tokens", s.total_tokens), + Style::default().fg(Theme::TEXT).add_modifier(Modifier::BOLD), + ))); + lines.push(Line::from(Span::styled( + format!(" API calls: {}", s.api_calls), + Style::default().fg(Theme::TEXT), + ))); + } else { + lines.push(Line::from(Span::styled( + " No active session.", + Style::default().fg(Theme::TEXT_DIM), + ))); + } + lines.push(Line::from(Span::raw(""))); + lines.push(Line::from(Span::styled( + " Activity", + Style::default().fg(Theme::INFO).add_modifier(Modifier::BOLD), + ))); + lines.push(Line::from(Span::styled( + format!(" Edits: {edit_count}"), + Style::default().fg(Theme::TEXT), + ))); + lines.push(Line::from(Span::styled( + format!(" Reviews: {review_count}"), + Style::default().fg(Theme::TEXT), + ))); + lines.push(Line::from(Span::styled( + format!(" Lessons: {lesson_count}"), + Style::default().fg(Theme::TEXT_MUTED), + ))); + lines.push(Line::from(Span::styled( + format!(" Empty reviews: {}", + if consec_empty > 3 { format!("{consec_empty} ⚠") } else { consec_empty.to_string() }, + ), + Style::default().fg(if consec_empty > 3 { Theme::WARNING } else { Theme::TEXT_DIM }), + ))); + if let Some(s) = &summary { + lines.push(Line::from(Span::raw(""))); + lines.push(Line::from(Span::styled( + format!(" Session: {}h {}m {}s", s.elapsed_hours, s.elapsed_minutes, s.elapsed_seconds), + Style::default().fg(Theme::TEXT_DIM), + ))); + } let paragraph = Paragraph::new(lines).block(block); frame.render_widget(paragraph, overlay_area); }