nixgreety/src/main.rs

192 lines
5.6 KiB
Rust

use std::{
io,
marker::PhantomData,
time::{Duration, Instant},
};
use crossterm::event::{self, Event, KeyCode, KeyEvent, KeyEventKind};
use ratatui::{
buffer::Buffer,
layout::{Constraint, Direction, Layout, Margin, Rect},
style::{Color, Stylize},
symbols::border,
text::Line,
widgets::{Block, Clear, Widget},
DefaultTerminal, Frame,
};
use tui_rain::Rain;
fn main() -> io::Result<()> {
let mut terminal = ratatui::init();
let app_result = App::default().run(&mut terminal);
ratatui::restore();
app_result
}
#[derive(Debug)]
pub struct App<'a> {
start_time: Instant,
last_draw: Instant,
exit: bool,
focus: Focus,
_marker: PhantomData<&'a ()>,
}
#[derive(Debug)]
enum Focus {
Username,
Password,
}
impl Default for App<'_> {
fn default() -> Self {
let start_time = Instant::now();
let last_draw = Instant::now();
let exit = false;
let focus = Focus::Username;
Self {
start_time,
last_draw,
exit,
focus,
_marker: PhantomData,
}
}
}
impl App<'_> {
pub fn run(&mut self, terminal: &mut DefaultTerminal) -> io::Result<()> {
while !self.exit {
let draw_time = Instant::now();
terminal.draw(|frame| self.draw(frame))?;
self.last_draw = draw_time;
self.handle_events()?;
}
Ok(())
}
fn draw(&mut self, frame: &mut Frame) {
let rain_widget = Rain::new_matrix(self.start_time.elapsed())
.with_character_set(tui_rain::CharacterSet::UnicodeRange {
start: 0x21,
len: 94,
})
.with_bold_dim_effect(false)
.with_rain_density(tui_rain::RainDensity::Relative { sparseness: 60 })
.with_rain_speed(tui_rain::RainSpeed::Absolute { speed: 0.002 })
.with_rain_speed_variance(10000.0)
.with_tail_lifespan(Duration::from_millis(2500))
.with_color(Color::Green)
.with_head_color(Color::White)
.with_noise_interval(Duration::from_millis(2000));
let layout = Layout::default()
.direction(Direction::Horizontal)
.constraints(vec![Constraint::Percentage(40), Constraint::Percentage(20)])
.split(frame.area());
let layout = Layout::default()
.direction(Direction::Vertical)
.constraints(vec![Constraint::Percentage(40), Constraint::Percentage(20)])
.split(layout[1]);
let prompt_area = layout[1];
let inner_area = prompt_area.inner(Margin::new(1, 1));
let prompt_areas = Layout::default()
.direction(Direction::Vertical)
.constraints(vec![Constraint::Length(1), Constraint::Length(1)])
.split(inner_area);
frame.render_widget(rain_widget, frame.area());
frame.render_widget(Clear, prompt_area);
let title = Line::from(" Hewwo! >w< :3 ".bold());
let instructions = Line::from(vec![
" Decrement ".into(),
"<Left>".blue().bold(),
" Increment ".into(),
"<Right>".blue().bold(),
" Quit ".into(),
"<Q> ".blue().bold(),
]);
let prompt_block = Block::bordered()
.title(title.left_aligned())
.title_bottom(instructions.centered())
.border_set(border::PLAIN);
frame.render_widget(prompt_block, prompt_area);
// TextPrompt::from("User").draw(frame, prompt_areas[0], &mut self.username_state);
// TextPrompt::from("Password")
// .with_render_style(TextRenderStyle::Password)
// .draw(frame, prompt_areas[1], &mut self.password_state);
}
fn handle_events(&mut self) -> io::Result<()> {
if event::poll(Duration::from_millis(10))? {
match event::read()? {
Event::Key(key_event) if key_event.kind == KeyEventKind::Press => {
self.handle_key_event(key_event)
}
_ => {}
}
};
Ok(())
}
fn handle_key_event(&mut self, key_event: KeyEvent) {
match key_event.code {
KeyCode::Esc => self.exit(),
KeyCode::Tab => match self.focus {
Focus::Username => self.focus = Focus::Password,
Focus::Password => self.focus = Focus::Username,
},
KeyCode::BackTab => match self.focus {
Focus::Username => self.focus = Focus::Password,
Focus::Password => self.focus = Focus::Username,
},
_ => self.focus_handle_key_event(key_event),
}
}
fn focus_handle_key_event(&mut self, key_event: KeyEvent) {
// let state = match self.focus {
// Focus::Username => &mut self.username_state,
// Focus::Password => &mut self.password_state,
// };
// state.handle_key_event(key_event);
}
fn exit(&mut self) {
self.exit = true;
}
}
impl Widget for &mut App<'_> {
fn render(self, area: Rect, buf: &mut Buffer) {
let title = Line::from(" Hewwo >w< :3 ".bold());
let instructions = Line::from(vec![
" Decrement ".into(),
"<Left>".blue().bold(),
" Increment ".into(),
"<Right>".blue().bold(),
" Quit ".into(),
"<Q> ".blue().bold(),
]);
let block = Block::bordered()
.title(title.left_aligned())
.title_bottom(instructions.centered())
.border_set(border::PLAIN);
block.render(area, buf);
}
}