diff --git a/src/clock.rs b/src/clock.rs index 922d2a8..41d5780 100644 --- a/src/clock.rs +++ b/src/clock.rs @@ -6,7 +6,7 @@ #![allow(clippy::cast_possible_wrap)] #![allow(clippy::cast_sign_loss)] // it should only be positive anyway -use chrono::{DateTime, Local, SubsecRound, Timelike}; +use chrono::{Date, DateTime, Local, SubsecRound, Timelike}; use clap::Parser; use libpt::cli::args::HELP_TEMPLATE; use libpt::cli::clap::ArgGroup; @@ -30,7 +30,7 @@ use ui::Data; /// Make your terminal into a big clock #[derive(Parser, Debug, Clone)] #[command(help_template = HELP_TEMPLATE, author, version)] -#[clap(group( ArgGroup::new("timebarlen") .args(&["minute","day", "hour", "custom", "countdown"]),))] +#[clap(group( ArgGroup::new("timebarlen") .args(&["minute","day", "hour", "custom", "countdown", "timer"]),))] #[allow(clippy::struct_excessive_bools)] // the struct is for cli parsing and we already use an // ArgGroup pub struct Clock { @@ -70,6 +70,8 @@ pub struct Clock { pub(crate) last_reset: Option>, #[clap(skip)] pub(crate) did_notify: bool, + #[clap(skip)] + pub(crate) started_at: DateTime, } impl Clock { @@ -82,6 +84,8 @@ impl Clock { Some(TimeBarLength::Day) } else if self.hour { Some(TimeBarLength::Hour) + } else if self.timer { + Some(TimeBarLength::Timer) } else if self.countdown.is_some() { Some(TimeBarLength::Countup( self.countdown.unwrap().as_secs() as i64 @@ -111,7 +115,7 @@ impl Clock { if let Some(len) = self.timebar_len() { let since_last_reset = Local::now().signed_duration_since(self.last_reset.unwrap()); match len { - TimeBarLength::Countup(_) => { + TimeBarLength::Countup(_) | TimeBarLength::Timer => { // the count up should not reset. If the time is over, just keep it at 100% } TimeBarLength::Custom(_) => { @@ -147,7 +151,7 @@ impl Clock { if let Some(len) = self.timebar_len() { trace!("Local Time: {}", Local::now()); match len { - TimeBarLength::Custom(_) | TimeBarLength::Countup(_) => { + TimeBarLength::Custom(_) | TimeBarLength::Countup(_) | TimeBarLength::Timer => { self.last_reset = Some(Local::now()); } TimeBarLength::Minute => { @@ -204,7 +208,7 @@ impl Clock { ) -> anyhow::Result<()> { let tick_rate = std::time::Duration::from_millis(100); let mut last_tick = Instant::now(); - let mut uidata: Data = Data::default(); + let mut uidata: Data = Data::new(self.timebar_len().unwrap()); self.setup()?; loop { let raw_time = chrono::Local::now().round_subsecs(0); diff --git a/src/clock/timebar.rs b/src/clock/timebar.rs index 4be656e..7f04da3 100644 --- a/src/clock/timebar.rs +++ b/src/clock/timebar.rs @@ -4,6 +4,7 @@ use chrono::Duration; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum TimeBarLength { + Timer, Minute, Hour, Custom(i64), @@ -19,6 +20,7 @@ impl TimeBarLength { Self::Minute => 60, Self::Day => 24 * 60 * 60, Self::Hour => 60 * 60, + Self::Timer => 1, Self::Custom(secs) | Self::Countup(secs) => secs, } } @@ -38,6 +40,9 @@ impl Default for TimeBarLength { impl Display for TimeBarLength { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + if *self == Self::Timer { + return write!(f, ""); + } let buf = match self { Self::Minute => humantime::Duration::from( Duration::minutes(1) @@ -59,6 +64,7 @@ impl Display for TimeBarLength { .to_std() .expect("could not convert chrono time to std time"), ), + Self::Timer => unreachable!(), }; write!(f, "{buf}") } diff --git a/src/clock/ui.rs b/src/clock/ui.rs index afa53e9..ebe0b9e 100644 --- a/src/clock/ui.rs +++ b/src/clock/ui.rs @@ -8,18 +8,37 @@ use crate::clock::timebar::TimeBarLength; use super::Clock; +pub const TIME_FORMAT: &str = "%H:%M:%S"; + // TODO: make this a ringbuffer with a custom struct inside? -#[derive(Debug, Clone, PartialEq, Default)] +#[derive(Debug, Clone, PartialEq)] pub struct Data { now: [DateTime; 2], fdate: [String; 2], ftime: [String; 2], timebar_ratio: [Option; 2], + timebar_type: TimeBarLength, + started_at: DateTime, + idx: usize, } impl Data { + pub fn new(timebar_type: TimeBarLength) -> Self { + let mut this = Self { + now: [Default::default(); 2], + fdate: ["".to_string(), "".to_string()], + ftime: ["".to_string(), "".to_string()], + timebar_ratio: [Default::default(); 2], + started_at: Local::now(), + idx: Default::default(), + + timebar_type, + }; + this.started_at = this.started_at.round_subsecs(0); + this + } pub fn update( &mut self, now: DateTime, @@ -71,6 +90,9 @@ impl Data { #[inline] #[allow(clippy::missing_const_for_fn)] // no it's not const pub fn timebar_ratio(&self) -> Option { + if self.timebar_type == TimeBarLength::Timer { + return Some(0.0); + } self.timebar_ratio[self.idx] } } @@ -171,8 +193,21 @@ pub fn timebarw_label<'a>( // example with `-o` #17 .checked_add_signed(len.into()) .expect("could not calculate when the countdown finishes") - .format("%H:%M:%S"); - Paragraph::new(format!("{time_now} / {len} ({until})")) + .format(TIME_FORMAT); + + let text: String = match clock.timebar_len().unwrap() { + TimeBarLength::Timer => format!("{} + {time_now}", data.started_at.format(TIME_FORMAT)), + TimeBarLength::Countup(_) | TimeBarLength::Custom(_) => format!( + "{time_now} / {len} | {} -> {until}", + last_reset.format(TIME_FORMAT) + ), + _ => format!( + "{time_now} / {len} | {} -> {until}", + last_reset.with_second(0).unwrap().format(TIME_FORMAT) + ), + }; + + Paragraph::new(text) .alignment(Alignment::Center) .block( Block::default().padding(Padding::right(if inner_rect.width > 80 { diff --git a/src/main.rs b/src/main.rs index 3b04d7e..679b2c4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -90,7 +90,7 @@ fn mock_tests() { info!("0s=0.0"); } { - let mut data = Data::default(); + let mut data = Data::new(clock::timebar::TimeBarLength::Day); let now = Local::now(); data.update(now, "date".to_owned(), "time".to_owned(), Some(0.1)); assert_eq!(data.timebar_ratio(), Some(0.1));