es_fluent_cli/
ui.rs

1use crate::app_state::AppState;
2use crate::core::{self as fluent_core, BuildOutcome};
3use ratatui::{
4    Frame,
5    layout::{Constraint, Direction, Layout},
6    style::{Color, Modifier, Style},
7    text::{Line, Span},
8    widgets::{Block, Borders, List, ListItem},
9};
10
11fn build_list_items(app: &'_ AppState) -> Vec<ListItem<'_>> {
12    let mut items: Vec<ListItem> = Vec::new();
13    let build_statuses_locked = app.build_statuses.lock().unwrap();
14    let active_builds_locked = app.active_builds.lock().unwrap();
15
16    for krate in &app.crates {
17        let crate_name_str = krate.name().as_str();
18        let status_span: Span;
19
20        if active_builds_locked.contains(crate_name_str) {
21            status_span = Span::styled("Building...", Style::default().fg(Color::Yellow));
22        } else {
23            match build_statuses_locked.get(crate_name_str) {
24                Some(BuildOutcome::Success { duration }) => {
25                    status_span = Span::styled(
26                        format!("Built in {}", fluent_core::format_duration(*duration)),
27                        Style::default().fg(Color::Green),
28                    );
29                },
30                Some(BuildOutcome::Failure {
31                    error_message,
32                    duration,
33                }) => {
34                    status_span = Span::styled(
35                        format!(
36                            "Failed: {} (took {})",
37                            error_message,
38                            fluent_core::format_duration(*duration)
39                        ),
40                        Style::default().fg(Color::Red),
41                    );
42                },
43                None => {
44                    status_span =
45                        Span::styled("Status Unknown", Style::default().fg(Color::DarkGray));
46                },
47            }
48        }
49
50        let line_content = Line::from(vec![
51            Span::raw("• "),
52            Span::styled(
53                crate_name_str.to_string(),
54                Style::default()
55                    .fg(Color::White)
56                    .add_modifier(Modifier::BOLD),
57            ),
58            Span::raw(": "),
59            status_span,
60        ]);
61        items.push(ListItem::new(line_content));
62    }
63
64    items
65}
66
67/// Renders the UI for the application.
68pub fn ui(f: &mut Frame, app: &AppState) {
69    let main_chunks = Layout::default()
70        .direction(Direction::Vertical)
71        .constraints([Constraint::Min(0)].as_ref())
72        .split(f.area());
73
74    let list_items = build_list_items(app);
75
76    let crate_list_widget = List::new(list_items)
77        .block(Block::default().borders(Borders::ALL).title("Crates"))
78        .highlight_style(Style::default().add_modifier(Modifier::ITALIC))
79        .highlight_symbol("❯ ");
80    f.render_widget(crate_list_widget, main_chunks[0]);
81}