Aurora-Print/Core/console_ui/mod.rs

137 lines
5.3 KiB
Rust

use std::time::{Duration, Instant};
use crossterm::{
event::{self, Event, KeyCode},
execute,
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
};
use ratatui::{
backend::CrosstermBackend,
Terminal,
layout::{Constraint, Direction, Layout},
style::{Color, Style},
text::{Line, Span},
widgets::{Block, Borders, List, ListItem, Paragraph},
};
use crate::state::{SharedState, ChromiumPhase, HeadlessPhase};
pub fn start_ui(state: SharedState) -> std::io::Result<()> {
enable_raw_mode()?;
let mut stdout = std::io::stdout();
execute!(stdout, EnterAlternateScreen)?;
let backend = CrosstermBackend::new(stdout);
let mut terminal = Terminal::new(backend)?;
let mut last_tick = Instant::now();
let tick_rate = Duration::from_millis(250);
loop {
let snapshot = {
let s = state.lock().unwrap();
s.clone()
};
terminal.draw(|f| {
let chunks = Layout::default()
.direction(Direction::Vertical)
.margin(1)
.constraints([
Constraint::Length(4),
Constraint::Min(6),
Constraint::Min(6),
])
.split(f.size());
let header = Block::default()
.title(" Aurora Core — Engines ")
.borders(Borders::ALL);
let web_dot = Span::styled(
"",
Style::default().fg(if snapshot.web_server_active { Color::Green } else { Color::Red })
);
let plug_dot = Span::styled(
"",
Style::default().fg(if snapshot.plugin_engine_active { Color::Green } else { Color::Red })
);
// Chromium Punkt + optionaler Text
let (chrom_dot_color, chrom_text) = match &snapshot.chromium {
ChromiumPhase::Ready => (Color::Green, "".to_string()),
ChromiumPhase::Downloading => (Color::Yellow, "downloading…".to_string()),
ChromiumPhase::Checking => (Color::Yellow, "checking…".to_string()),
ChromiumPhase::Idle => (Color::Red, "".to_string()),
ChromiumPhase::Error(msg) => (Color::Red, format!("error: {}", msg)),
};
let chrom_dot = Span::styled("", Style::default().fg(chrom_dot_color));
// Headless Engine Punkt + optionaler Text
let (head_dot_color, head_text) = match &snapshot.headless {
HeadlessPhase::Ready => (Color::Green, "".to_string()),
HeadlessPhase::Starting => (Color::Yellow, "starting…".to_string()),
HeadlessPhase::Idle => (Color::Red, "".to_string()),
HeadlessPhase::Error(msg) => (Color::Red, format!("error: {}", msg)),
};
let head_dot = Span::styled("", Style::default().fg(head_dot_color));
let mut spans = vec![
Span::raw("Web Server "), web_dot, Span::raw(" "),
Span::raw("Plugin Engine "), plug_dot, Span::raw(" "),
Span::raw("Chromium "), chrom_dot,
];
if !chrom_text.is_empty() {
spans.push(Span::raw(" "));
spans.push(Span::styled(format!("({})", chrom_text), Style::default().fg(Color::Gray)));
}
spans.push(Span::raw(" "));
spans.push(Span::raw("Headless Engine "));
spans.push(head_dot);
if !head_text.is_empty() {
spans.push(Span::raw(" "));
spans.push(Span::styled(format!("({})", head_text), Style::default().fg(Color::Gray)));
}
let header_para = Paragraph::new(Line::from(spans)).block(header);
f.render_widget(header_para, chunks[0]);
// Loaded plugins
let plugin_block = Block::default().title(" Loaded Plugins ").borders(Borders::ALL);
let items: Vec<ListItem> = if snapshot.loaded_plugins.is_empty() {
vec![ListItem::new("— none —")]
} else {
snapshot.loaded_plugins.iter().map(|p| ListItem::new(p.clone())).collect()
};
f.render_widget(List::new(items).block(plugin_block), chunks[1]);
// Running jobs
let jobs_block = Block::default().title(" Active Setups ").borders(Borders::ALL);
let jobs_items: Vec<ListItem> = if snapshot.running_jobs.is_empty() {
vec![ListItem::new("— idle —")]
} else {
snapshot.running_jobs.iter().map(|j| ListItem::new(j.clone())).collect()
};
f.render_widget(List::new(jobs_items).block(jobs_block), chunks[2]);
})?;
let timeout = tick_rate.checked_sub(last_tick.elapsed()).unwrap_or(Duration::from_secs(0));
if crossterm::event::poll(timeout)? {
if let Event::Key(key) = event::read()? {
match key.code {
KeyCode::Char('q') | KeyCode::Esc => break,
_ => {}
}
}
}
if last_tick.elapsed() >= tick_rate {
last_tick = Instant::now();
}
}
disable_raw_mode()?;
let mut stdout = std::io::stdout();
execute!(stdout, LeaveAlternateScreen)?;
Ok(())
}