Files
laptop-dashboard/src/main.rs
2025-12-31 22:03:32 +00:00

117 lines
3.3 KiB
Rust

use crossterm::event::{Event, EventStream, KeyCode, KeyEvent, KeyEventKind, KeyModifiers};
use futures::{FutureExt, StreamExt};
use ratatui::{
DefaultTerminal, Frame,
prelude::*,
style::Stylize,
text::Line,
widgets::{Block, Paragraph},
};
fn main() {
smol::block_on(async {
color_eyre::install().unwrap();
let terminal = ratatui::init();
let result = App::new().run(terminal).await;
ratatui::restore();
});
}
#[derive(Debug, Default)]
pub struct App {
/// Is the application running?
running: bool,
// Event stream.
event_stream: EventStream,
state: AppState,
}
#[derive(Debug, Default)]
pub enum screen {
#[default]
Dashboard,
Battery,
}
#[derive(Debug, Default)]
pub struct AppState {
active_screen: screen,
}
impl App {
/// Construct a new instance of [`App`].
pub fn new() -> Self {
Self::default()
}
/// Run the application's main loop.
pub async fn run(mut self, mut terminal: DefaultTerminal) -> color_eyre::Result<()> {
self.running = true;
while self.running {
terminal.draw(|frame| self.draw(frame))?;
self.handle_crossterm_events().await?;
}
Ok(())
}
/// Renders the user interface.
///
/// This is where you add new widgets. See the following resources for more information:
/// - <https://docs.rs/ratatui/latest/ratatui/widgets/index.html>
/// - <https://github.com/ratatui/ratatui/tree/master/examples>
fn draw(&mut self, frame: &mut Frame) {
let title = Line::from("Ratatui Simple Template")
.bold()
.blue()
.centered();
let text = "Hello, Ratatui!\n\n\
Created using https://github.com/ratatui/templates\n\
Press `Esc`, `Ctrl-C` or `q` to stop running.";
let layout = Layout::default()
.direction(Direction::Vertical)
.constraints(vec![
Constraint::Percentage(33),
Constraint::Percentage(33),
Constraint::Percentage(33),
])
.split(frame.area());
frame.render_widget(
Paragraph::new(text)
.block(Block::bordered().title(title))
.centered(),
layout[1],
)
}
/// Reads the crossterm events and updates the state of [`App`].
async fn handle_crossterm_events(&mut self) -> color_eyre::Result<()> {
let event = self.event_stream.next().fuse().await;
match event {
Some(Ok(evt)) => match evt {
Event::Key(key) if key.kind == KeyEventKind::Press => self.on_key_event(key),
Event::Mouse(_) => {}
Event::Resize(_, _) => {}
_ => {}
},
_ => {}
}
Ok(())
}
/// Handles the key events and updates the state of [`App`].
fn on_key_event(&mut self, key: KeyEvent) {
match (key.modifiers, key.code) {
(_, KeyCode::Esc | KeyCode::Char('q'))
| (KeyModifiers::CONTROL, KeyCode::Char('c') | KeyCode::Char('C')) => self.quit(),
// Add other key handlers here.
_ => {}
}
}
/// Set running to false to quit the application.
fn quit(&mut self) {
self.running = false;
}
}