Editable Countdown (#12)
- Editable `Countdown` - ASCII Symbols for `Clock` states - Update labels
This commit is contained in:
parent
4c38ac368e
commit
64300631c7
17
src/app.rs
17
src/app.rs
@ -48,19 +48,16 @@ impl Default for App {
|
|||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
mode: Mode::Running,
|
mode: Mode::Running,
|
||||||
content: Content::Pomodoro,
|
content: Content::Countdown,
|
||||||
show_menu: false,
|
show_menu: false,
|
||||||
countdown: Countdown::new(
|
countdown: Countdown::new(Clock::<clock::Countdown>::new(
|
||||||
"Countdown".into(),
|
|
||||||
Clock::<clock::Countdown>::new(
|
|
||||||
Duration::from_secs(10 * 60 /* 10min */),
|
Duration::from_secs(10 * 60 /* 10min */),
|
||||||
Duration::from_millis(TICK_VALUE_MS),
|
Duration::from_millis(TICK_VALUE_MS),
|
||||||
),
|
)),
|
||||||
),
|
timer: Timer::new(Clock::<clock::Timer>::new(
|
||||||
timer: Timer::new(
|
Duration::ZERO,
|
||||||
"Timer".into(),
|
Duration::from_millis(TICK_VALUE_MS),
|
||||||
Clock::<clock::Timer>::new(Duration::ZERO, Duration::from_millis(TICK_VALUE_MS)),
|
)),
|
||||||
),
|
|
||||||
pomodoro: Pomodoro::new(),
|
pomodoro: Pomodoro::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,7 +20,7 @@ pub enum Time {
|
|||||||
// Hours,
|
// Hours,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Display, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub enum Mode {
|
pub enum Mode {
|
||||||
Initial,
|
Initial,
|
||||||
Tick,
|
Tick,
|
||||||
@ -32,6 +32,21 @@ pub enum Mode {
|
|||||||
Done,
|
Done,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Mode {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
Mode::Initial => write!(f, "[]"),
|
||||||
|
Mode::Tick => write!(f, ">"),
|
||||||
|
Mode::Pause => write!(f, "||"),
|
||||||
|
Mode::Editable(time, _) => match time {
|
||||||
|
Time::Seconds => write!(f, "[edit seconds]"),
|
||||||
|
Time::Minutes => write!(f, "[edit minutes]"),
|
||||||
|
},
|
||||||
|
Mode::Done => write!(f, "done"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Clock<T> {
|
pub struct Clock<T> {
|
||||||
initial_value: Duration,
|
initial_value: Duration,
|
||||||
|
|||||||
@ -15,13 +15,12 @@ use crate::{
|
|||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Countdown {
|
pub struct Countdown {
|
||||||
headline: String,
|
|
||||||
clock: Clock<clock::Countdown>,
|
clock: Clock<clock::Countdown>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Countdown {
|
impl Countdown {
|
||||||
pub const fn new(headline: String, clock: Clock<clock::Countdown>) -> Self {
|
pub const fn new(clock: Clock<clock::Countdown>) -> Self {
|
||||||
Self { headline, clock }
|
Self { clock }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_edit_mode(&mut self) -> bool {
|
pub fn is_edit_mode(&mut self) -> bool {
|
||||||
@ -35,12 +34,33 @@ impl EventHandler for Countdown {
|
|||||||
Event::Tick => {
|
Event::Tick => {
|
||||||
self.clock.tick();
|
self.clock.tick();
|
||||||
}
|
}
|
||||||
Event::Key(key) if key.code == KeyCode::Char('s') => {
|
|
||||||
self.clock.toggle_pause();
|
|
||||||
}
|
|
||||||
Event::Key(key) if key.code == KeyCode::Char('r') => {
|
Event::Key(key) if key.code == KeyCode::Char('r') => {
|
||||||
self.clock.reset();
|
self.clock.reset();
|
||||||
}
|
}
|
||||||
|
Event::Key(key) => match key.code {
|
||||||
|
KeyCode::Char('r') => {
|
||||||
|
self.clock.reset();
|
||||||
|
}
|
||||||
|
KeyCode::Char('s') => {
|
||||||
|
self.clock.toggle_pause();
|
||||||
|
}
|
||||||
|
KeyCode::Char('e') => {
|
||||||
|
self.clock.toggle_edit();
|
||||||
|
}
|
||||||
|
KeyCode::Left => {
|
||||||
|
self.clock.edit_next();
|
||||||
|
}
|
||||||
|
KeyCode::Right => {
|
||||||
|
self.clock.edit_prev();
|
||||||
|
}
|
||||||
|
KeyCode::Up => {
|
||||||
|
self.clock.edit_up();
|
||||||
|
}
|
||||||
|
KeyCode::Down => {
|
||||||
|
self.clock.edit_down();
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
},
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -52,17 +72,18 @@ impl StatefulWidget for CountdownWidget {
|
|||||||
type State = Countdown;
|
type State = Countdown;
|
||||||
fn render(self, area: Rect, buf: &mut Buffer, state: &mut Self::State) {
|
fn render(self, area: Rect, buf: &mut Buffer, state: &mut Self::State) {
|
||||||
let clock = ClockWidget::new();
|
let clock = ClockWidget::new();
|
||||||
let headline = Line::raw(state.headline.to_uppercase());
|
let headline = "Countdown".to_uppercase();
|
||||||
|
let label = Line::raw((format!("{} {}", headline, state.clock.get_mode())).to_uppercase());
|
||||||
|
|
||||||
let area = center(
|
let area = center(
|
||||||
area,
|
area,
|
||||||
Constraint::Length(max(clock.get_width(), headline.width() as u16)),
|
Constraint::Length(max(clock.get_width(), label.width() as u16)),
|
||||||
Constraint::Length(clock.get_height() + 1 /* height of headline */),
|
Constraint::Length(clock.get_height() + 1 /* height of label */),
|
||||||
);
|
);
|
||||||
let [v1, v2] =
|
let [v1, v2] =
|
||||||
Layout::vertical(Constraint::from_lengths([clock.get_height(), 1])).areas(area);
|
Layout::vertical(Constraint::from_lengths([clock.get_height(), 1])).areas(area);
|
||||||
|
|
||||||
clock.render(v1, buf, &mut state.clock);
|
clock.render(v1, buf, &mut state.clock);
|
||||||
headline.render(v2, buf);
|
label.centered().render(v2, buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,8 +11,8 @@ use ratatui::{
|
|||||||
text::Line,
|
text::Line,
|
||||||
widgets::{StatefulWidget, Widget},
|
widgets::{StatefulWidget, Widget},
|
||||||
};
|
};
|
||||||
use std::cmp::max;
|
use std::{cmp::max, time::Duration};
|
||||||
use std::time::Duration;
|
|
||||||
use strum::Display;
|
use strum::Display;
|
||||||
|
|
||||||
static PAUSE_MS: u64 = 5 * 60 * 1000; /* 5min in milliseconds */
|
static PAUSE_MS: u64 = 5 * 60 * 1000; /* 5min in milliseconds */
|
||||||
@ -107,15 +107,11 @@ impl EventHandler for Pomodoro {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
KeyCode::Up => {
|
KeyCode::Up => {
|
||||||
if self.get_clock().is_edit_mode() {
|
|
||||||
self.get_clock().edit_up();
|
self.get_clock().edit_up();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
KeyCode::Down => {
|
KeyCode::Down => {
|
||||||
if self.get_clock().is_edit_mode() {
|
|
||||||
self.get_clock().edit_down();
|
self.get_clock().edit_down();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
KeyCode::Char('r') => {
|
KeyCode::Char('r') => {
|
||||||
self.get_clock().reset();
|
self.get_clock().reset();
|
||||||
}
|
}
|
||||||
@ -133,18 +129,18 @@ impl StatefulWidget for PomodoroWidget {
|
|||||||
type State = Pomodoro;
|
type State = Pomodoro;
|
||||||
fn render(self, area: Rect, buf: &mut Buffer, state: &mut Self::State) {
|
fn render(self, area: Rect, buf: &mut Buffer, state: &mut Self::State) {
|
||||||
let clock = ClockWidget::new();
|
let clock = ClockWidget::new();
|
||||||
let mode_str = Line::raw(
|
let label = Line::raw(
|
||||||
(if let Some(edit_mode) = state.get_clock().edit_mode() {
|
(format!(
|
||||||
format!("{} > edit {}", state.mode, edit_mode)
|
"Pomodoro {} {}",
|
||||||
} else {
|
state.mode.clone(),
|
||||||
format!("{} > {}", state.mode.clone(), state.get_clock().get_mode())
|
state.get_clock().get_mode()
|
||||||
})
|
))
|
||||||
.to_uppercase(),
|
.to_uppercase(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let area = center(
|
let area = center(
|
||||||
area,
|
area,
|
||||||
Constraint::Length(max(clock.get_width(), mode_str.width() as u16)),
|
Constraint::Length(max(clock.get_width(), label.width() as u16)),
|
||||||
Constraint::Length(clock.get_height() + 1 /* height of mode_str */),
|
Constraint::Length(clock.get_height() + 1 /* height of mode_str */),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -152,6 +148,6 @@ impl StatefulWidget for PomodoroWidget {
|
|||||||
Layout::vertical(Constraint::from_lengths([clock.get_height(), 1])).areas(area);
|
Layout::vertical(Constraint::from_lengths([clock.get_height(), 1])).areas(area);
|
||||||
|
|
||||||
clock.render(v1, buf, state.get_clock());
|
clock.render(v1, buf, state.get_clock());
|
||||||
mode_str.render(v2, buf);
|
label.centered().render(v2, buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,13 +14,12 @@ use std::cmp::max;
|
|||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Timer {
|
pub struct Timer {
|
||||||
headline: String,
|
|
||||||
clock: Clock<clock::Timer>,
|
clock: Clock<clock::Timer>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Timer {
|
impl Timer {
|
||||||
pub const fn new(headline: String, clock: Clock<clock::Timer>) -> Self {
|
pub const fn new(clock: Clock<clock::Timer>) -> Self {
|
||||||
Self { headline, clock }
|
Self { clock }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,17 +46,18 @@ impl StatefulWidget for &TimerWidget {
|
|||||||
type State = Timer;
|
type State = Timer;
|
||||||
fn render(self, area: Rect, buf: &mut Buffer, state: &mut Self::State) {
|
fn render(self, area: Rect, buf: &mut Buffer, state: &mut Self::State) {
|
||||||
let clock = ClockWidget::new();
|
let clock = ClockWidget::new();
|
||||||
let headline = Line::raw(state.headline.to_uppercase());
|
let headline = "Timer".to_uppercase();
|
||||||
|
let label = Line::raw((format!("{} {}", headline, state.clock.get_mode())).to_uppercase());
|
||||||
|
|
||||||
let area = center(
|
let area = center(
|
||||||
area,
|
area,
|
||||||
Constraint::Length(max(clock.get_width(), headline.width() as u16)),
|
Constraint::Length(max(clock.get_width(), label.width() as u16)),
|
||||||
Constraint::Length(clock.get_height() + 1 /* height of headline */),
|
Constraint::Length(clock.get_height() + 1 /* height of label */),
|
||||||
);
|
);
|
||||||
let [v1, v2] =
|
let [v1, v2] =
|
||||||
Layout::vertical(Constraint::from_lengths([clock.get_height(), 1])).areas(area);
|
Layout::vertical(Constraint::from_lengths([clock.get_height(), 1])).areas(area);
|
||||||
|
|
||||||
clock.render(v1, buf, &mut state.clock);
|
clock.render(v1, buf, &mut state.clock);
|
||||||
headline.render(v2, buf);
|
label.centered().render(v2, buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user