feat: add basic ratatui event loop and print time to screen
This commit is contained in:
+104
-9
@@ -1,6 +1,26 @@
|
|||||||
|
use std::{
|
||||||
|
io::{self, stdout},
|
||||||
|
sync::mpsc,
|
||||||
|
thread,
|
||||||
|
time::Duration,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crossterm::{
|
||||||
|
ExecutableCommand,
|
||||||
|
event::{self, Event, KeyCode, KeyModifiers},
|
||||||
|
terminal::{EnterAlternateScreen, LeaveAlternateScreen, disable_raw_mode, enable_raw_mode},
|
||||||
|
};
|
||||||
|
use ratatui::{
|
||||||
|
Terminal,
|
||||||
|
backend::CrosstermBackend,
|
||||||
|
layout::Alignment,
|
||||||
|
style::{Color, Style},
|
||||||
|
widgets::Paragraph,
|
||||||
|
};
|
||||||
|
|
||||||
const SECONDS_PER_MIN: i64 = 60;
|
const SECONDS_PER_MIN: i64 = 60;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
enum TimerState {
|
enum TimerState {
|
||||||
Work,
|
Work,
|
||||||
Break,
|
Break,
|
||||||
@@ -30,6 +50,17 @@ impl Termato {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn toggle_running(&mut self) {
|
||||||
|
if self.is_running {
|
||||||
|
self.prior_state = self.state.clone();
|
||||||
|
self.state = TimerState::Paused;
|
||||||
|
self.is_running = false;
|
||||||
|
} else {
|
||||||
|
self.state = self.prior_state.clone();
|
||||||
|
self.is_running = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn toggle_mode(&mut self) {
|
fn toggle_mode(&mut self) {
|
||||||
let is_on_break = self.state == TimerState::Break
|
let is_on_break = self.state == TimerState::Break
|
||||||
|| (self.state == TimerState::Paused && self.prior_state == TimerState::Break);
|
|| (self.state == TimerState::Paused && self.prior_state == TimerState::Break);
|
||||||
@@ -58,17 +89,58 @@ impl Termato {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() -> Result<(), io::Error> {
|
||||||
let mut termato = Termato::new(1, 1);
|
enable_raw_mode()?;
|
||||||
|
stdout().execute(EnterAlternateScreen)?;
|
||||||
|
let backend = CrosstermBackend::new(stdout());
|
||||||
|
let mut terminal = Terminal::new(backend)?;
|
||||||
|
|
||||||
|
let mut termato = Termato::new(1, 1);
|
||||||
|
|
||||||
|
let (tx, rx) = mpsc::channel();
|
||||||
|
thread::spawn(move || {
|
||||||
loop {
|
loop {
|
||||||
termato.is_running = true;
|
thread::sleep(Duration::from_secs(1));
|
||||||
|
if tx.send(()).is_err() {
|
||||||
termato.tick();
|
break;
|
||||||
|
}
|
||||||
println!("Time remaining: {}", termato.time_remaining_in_sec);
|
|
||||||
println!("State: {:?}", termato.state);
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
loop {
|
||||||
|
terminal.draw(|f| {
|
||||||
|
let size = f.area();
|
||||||
|
let minutes = termato.time_remaining_in_sec / SECONDS_PER_MIN;
|
||||||
|
let seconds = termato.time_remaining_in_sec % SECONDS_PER_MIN;
|
||||||
|
let time_str = format!("{:02}:{:02}", minutes, seconds);
|
||||||
|
|
||||||
|
let paragraph = Paragraph::new(time_str)
|
||||||
|
.style(Style::default().fg(Color::White))
|
||||||
|
.alignment(Alignment::Center);
|
||||||
|
|
||||||
|
f.render_widget(paragraph, size);
|
||||||
|
})?;
|
||||||
|
|
||||||
|
if event::poll(Duration::from_millis(100))?
|
||||||
|
&& let Event::Key(key) = event::read()?
|
||||||
|
&& key.kind == event::KeyEventKind::Press
|
||||||
|
{
|
||||||
|
match key.code {
|
||||||
|
KeyCode::Char('q') | KeyCode::Char('Q') => break,
|
||||||
|
KeyCode::Char('c') if key.modifiers.contains(KeyModifiers::CONTROL) => break,
|
||||||
|
KeyCode::Char(' ') => termato.toggle_running(),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if rx.try_recv().is_ok() {
|
||||||
|
termato.tick();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
disable_raw_mode()?;
|
||||||
|
stdout().execute(LeaveAlternateScreen)?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@@ -160,4 +232,27 @@ mod tests {
|
|||||||
assert_eq!(termato.duration_in_secs, 120);
|
assert_eq!(termato.duration_in_secs, 120);
|
||||||
assert_eq!(termato.time_remaining_in_sec, 120);
|
assert_eq!(termato.time_remaining_in_sec, 120);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn termato_toggle_running_when_called_and_already_running_it_should_pause() {
|
||||||
|
let mut termato = Termato::new(1, 1);
|
||||||
|
termato.is_running = true;
|
||||||
|
|
||||||
|
termato.toggle_running();
|
||||||
|
|
||||||
|
assert_eq!(termato.state, TimerState::Paused);
|
||||||
|
assert_eq!(termato.prior_state, TimerState::Work);
|
||||||
|
assert!(!termato.is_running)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn termato_toggle_running_when_called_and_already_paused_it_should_run() {
|
||||||
|
let mut termato = Termato::new(1, 1);
|
||||||
|
|
||||||
|
termato.toggle_running();
|
||||||
|
|
||||||
|
assert_eq!(termato.state, TimerState::Work);
|
||||||
|
assert_eq!(termato.prior_state, TimerState::Work);
|
||||||
|
assert!(termato.is_running)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user