115 lines
3.7 KiB
Rust
115 lines
3.7 KiB
Rust
use ratatui::style::{Modifier, Style};
|
|||
|
|
use ratatui::text::{Line, Span};
|
||
|
|
use ratatui::widgets::{Block, Paragraph};
|
||
|
|
use ratatui::Frame;
|
||
|
|
use crate::view::theme::Theme;
|
||
|
|
|
||
|
|
pub fn render(
|
||
|
|
frame: &mut Frame,
|
||
|
|
area: ratatui::layout::Rect,
|
||
|
|
block: Block<'static>,
|
||
|
|
state: &crate::app::state::rest::AppStateRest,
|
||
|
|
) {
|
||
|
|
let block = block
|
||
|
|
.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 now_ms = chrono::Utc::now().timestamp_millis();
|
||
|
|
let summary = runtime.map(|r| {
|
||
|
|
crate::view::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,
|
||
|
|
)
|
||
|
|
});
|
||
|
|
let mut lines = vec![
|
||
|
|
Line::from(Span::styled(
|
||
|
|
" Token Usage",
|
||
|
|
Style::default()
|
||
|
|
.fg(Theme::INFO)
|
||
|
|
.add_modifier(Modifier::BOLD),
|
||
|
|
)),
|
||
|
|
Line::from(Span::raw("")),
|
||
|
|
];
|
||
|
|
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, area);
|
||
|
|
}
|