1use super::*;
2
3pub(crate) fn draw_zen_dashboard(f: &mut Frame, app: &App, area: Rect) {
4 let theme = &app.theme;
5 let icons = app.icons;
6 let t = &app.timer;
7 let on_break = is_break_mode(t.mode);
8 let mc = mode_color(theme, t.mode);
9
10 let chunks = Layout::default()
11 .constraints([
12 Constraint::Min(1),
13 Constraint::Length(1),
14 Constraint::Length(if on_break { 3 } else { 0 }),
15 Constraint::Length(2),
16 ])
17 .split(area);
18
19 let cycle = t.config.long_break_every.max(1);
20 let style = theme.scene_style(mc);
21 let options = ZenSceneOptions {
22 task_progress: app.active_task_progress(),
23 sessions_done: t.completed_focus_sessions % cycle,
24 sessions_total: cycle,
25 pending_tasks: app.pending_task_count(),
26 active_task_index: app.active_task_pending_index(),
27 layout: crate::canvas_timer::SceneLayout::Zen,
28 };
29 draw_zen_canvas(f, chunks[0], t, &style, &options);
30
31 let (main_time, tenths, _) = format_time_stack(t);
32 let session_label = t.cycle_label();
33 let mut overlay_lines = vec![
34 Line::from(vec![
35 Span::styled(
36 main_time,
37 Style::default().fg(theme.text).add_modifier(Modifier::BOLD),
38 ),
39 Span::styled(tenths, Style::default().fg(theme.dim)),
40 ]),
41 Line::from(Span::styled(session_label, Style::default().fg(theme.dim))),
42 ];
43 if let Some(id) = app.active_task {
44 if let Some(task) = app.data.tasks.iter().find(|t| t.id == id) {
45 overlay_lines.push(Line::from(Span::styled(
46 format!("{} {}", icons.task_active, truncate(&task.title, 36)),
47 Style::default()
48 .fg(theme.accent)
49 .add_modifier(Modifier::BOLD),
50 )));
51 }
52 }
53 let time_area = Rect {
54 x: chunks[0].x,
55 y: chunks[0].y + chunks[0].height / 2 - 2,
56 width: chunks[0].width,
57 height: overlay_lines.len() as u16,
58 };
59 f.render_widget(
60 Paragraph::new(overlay_lines).alignment(Alignment::Center),
61 time_area,
62 );
63
64 let task_line = if let Some(id) = app.active_task {
65 app.data.tasks.iter().find(|t| t.id == id).map(|task| {
66 Line::from(vec![
67 Span::styled(
68 format!("{} ", icons.task_active),
69 Style::default().fg(theme.accent),
70 ),
71 Span::styled(
72 truncate(&task.title, 48),
73 Style::default().fg(theme.text).add_modifier(Modifier::BOLD),
74 ),
75 Span::styled(
76 format!(
77 " {} {}",
78 task_status_icon(icons, task.status),
79 task.status.short_label()
80 ),
81 Style::default().fg(task_status_color(theme, task.status)),
82 ),
83 ])
84 })
85 } else {
86 None
87 };
88 f.render_widget(
89 Paragraph::new(task_line.unwrap_or_else(|| {
90 Line::from(Span::styled(
91 if app.queue_empty() {
92 format!("{} All tasks done — free focus", icons.check)
93 } else {
94 format!("{} No active task — [f] on dashboard", icons.dot)
95 },
96 Style::default().fg(theme.dim),
97 ))
98 }))
99 .alignment(Alignment::Center),
100 chunks[1],
101 );
102
103 if on_break {
104 draw_break_tip(f, chunks[2], t, mc, theme.text, theme.dim, icons.heart);
105 }
106
107 chrome::draw_footer(f, app, chunks[3]);
108}