Skip to content

Instantly share code, notes, and snippets.

@jrnxf
Last active March 20, 2022 21:47
Show Gist options
  • Save jrnxf/725d435842f7f3508c65a7a23adfed6e to your computer and use it in GitHub Desktop.
Save jrnxf/725d435842f7f3508c65a7a23adfed6e to your computer and use it in GitHub Desktop.
timr
use clap::Parser;
use std::{error::Error, io, sync::mpsc, thread, time::Duration};
use termion::{
event::Key,
input::{MouseTerminal, TermRead},
raw::IntoRawMode,
screen::AlternateScreen,
};
use tui::{
backend::{Backend, TermionBackend},
layout::{Alignment, Constraint, Direction, Layout},
style::Style,
text::Span,
widgets::Paragraph,
Frame, Terminal,
};
#[derive(Parser, Debug, Clone)]
#[clap(version, about, long_about= None)]
pub struct Args {
#[clap(short = 'd', long, default_value_t = 10)]
duration: usize,
}
#[derive(Debug, Clone)]
struct App {
duration: usize,
}
impl App {
fn new(args: Args) -> Self {
Self { duration: args.duration }
}
fn on_tick(&mut self) {
thread::spawn(move || loop {
self.duration -= 1;
thread::sleep(Duration::from_secs(1));
})
}
}
fn main() -> Result<(), Box<dyn Error>> {
let args = Args::parse();
let stdout = io::stdout().into_raw_mode()?;
let stdout = MouseTerminal::from(stdout);
let stdout = AlternateScreen::from(stdout);
let backend = TermionBackend::new(stdout);
let mut terminal = Terminal::new(backend)?;
let mut app = App::new(args);
let result = run_app(&mut terminal, &mut app);
if let Err(err) = result {
println!("{:?}", err)
}
Ok(())
}
fn run_app<B: Backend>(
terminal: &mut Terminal<B>,
mut app: &mut App,
) -> Result<(), Box<dyn Error>> {
let events = key_events();
loop {
terminal.draw(|f| draw(f, &mut app).unwrap())?;
match events.recv()? {
key => match key {
Key::Esc => {
return Ok(());
},
Key::Down => {
app.on_tick();
},
Key
_ => {}
},
}
}
}
fn key_events() -> mpsc::Receiver<Key> {
let (tx, rx) = mpsc::channel();
thread::spawn(move || {
let stdin = io::stdin();
for key in stdin.keys().flatten() {
if let Err(err) = tx.send(key) {
eprintln!("{}", err);
return;
}
}
});
rx
}
fn draw<B: Backend>(f: &mut Frame<B>, app: &mut App) -> Result<(), ()> {
let h = &f.size().height;
let mar = ((*h as f64 - 1 as f64) / 2.0) as u16;
let chunks = Layout::default()
.direction(Direction::Vertical)
.constraints(
[
Constraint::Length(mar as u16),
Constraint::Length(1),
Constraint::Length(mar as u16),
]
.as_ref(),
)
.split(f.size());
f.render_widget(
Paragraph::new(Span::styled(
String::from(format!("{}", app.clone().duration)),
Style::default(),
))
.alignment(Alignment::Center),
chunks[1],
);
Ok(())
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment