117 lines
3.3 KiB
Rust
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;
|
|
}
|
|
}
|