generated from PlexSheep/rs-base
accept a command to run when the timer ends
This commit is contained in:
parent
684384c3ee
commit
254b6c84cf
2 changed files with 52 additions and 4 deletions
14
src/app.rs
14
src/app.rs
|
@ -27,12 +27,17 @@ pub(crate) enum Mode {
|
||||||
},
|
},
|
||||||
/// The timer mode displays the remaining time until the timer is finished.
|
/// The timer mode displays the remaining time until the timer is finished.
|
||||||
Timer {
|
Timer {
|
||||||
|
/// Initial duration for timer, value can be 10s for 10 seconds, 1m for 1 minute, etc.
|
||||||
#[clap(short, long, value_parser = parse_duration, default_value = "5m")]
|
#[clap(short, long, value_parser = parse_duration, default_value = "5m")]
|
||||||
duration: Duration,
|
duration: Duration,
|
||||||
|
|
||||||
/// Hide milliseconds
|
/// Hide milliseconds
|
||||||
#[clap(long = "no-millis", short = 'M', takes_value = false)]
|
#[clap(long = "no-millis", short = 'M', takes_value = false)]
|
||||||
no_millis: bool,
|
no_millis: bool,
|
||||||
|
|
||||||
|
/// Command to run when the timer ends
|
||||||
|
#[clap(long, short, multiple = true, allow_hyphen_values = true)]
|
||||||
|
execute: Vec<String>,
|
||||||
},
|
},
|
||||||
/// The stopwatch mode displays the elapsed time since it was started.
|
/// The stopwatch mode displays the elapsed time since it was started.
|
||||||
Stopwatch,
|
Stopwatch,
|
||||||
|
@ -79,13 +84,20 @@ impl App {
|
||||||
Mode::Timer {
|
Mode::Timer {
|
||||||
duration,
|
duration,
|
||||||
no_millis,
|
no_millis,
|
||||||
|
execute,
|
||||||
} => {
|
} => {
|
||||||
let format = if *no_millis {
|
let format = if *no_millis {
|
||||||
DurationFormat::HourMinSec
|
DurationFormat::HourMinSec
|
||||||
} else {
|
} else {
|
||||||
DurationFormat::HourMinSecDeci
|
DurationFormat::HourMinSecDeci
|
||||||
};
|
};
|
||||||
self.timer = Some(Timer::new(duration.to_owned(), self.size, style, format));
|
self.timer = Some(Timer::new(
|
||||||
|
duration.to_owned(),
|
||||||
|
self.size,
|
||||||
|
style,
|
||||||
|
format,
|
||||||
|
execute.to_owned(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
Mode::Stopwatch => {
|
Mode::Stopwatch => {
|
||||||
self.stopwatch = Some(Stopwatch::new(self.size, style));
|
self.stopwatch = Some(Stopwatch::new(self.size, style));
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use std::{cell::RefCell, process::Command};
|
||||||
|
|
||||||
use chrono::{DateTime, Duration, Local};
|
use chrono::{DateTime, Duration, Local};
|
||||||
use clock_tui::bricks_text::BricksText;
|
use clock_tui::bricks_text::BricksText;
|
||||||
use tui::{buffer::Buffer, layout::Rect, style::Style, widgets::Widget};
|
use tui::{buffer::Buffer, layout::Rect, style::Style, widgets::Widget};
|
||||||
|
@ -7,19 +9,29 @@ use super::{format_duration, render_centered, DurationFormat};
|
||||||
pub struct Timer {
|
pub struct Timer {
|
||||||
pub size: u16,
|
pub size: u16,
|
||||||
pub style: Style,
|
pub style: Style,
|
||||||
|
pub execute: Vec<String>,
|
||||||
format: DurationFormat,
|
format: DurationFormat,
|
||||||
duration: Duration,
|
duration: Duration,
|
||||||
ended_at: Option<DateTime<Local>>,
|
ended_at: Option<DateTime<Local>>,
|
||||||
|
execute_result: RefCell<Option<String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Timer {
|
impl Timer {
|
||||||
pub(crate) fn new(duration: Duration, size: u16, style: Style, format: DurationFormat) -> Self {
|
pub(crate) fn new(
|
||||||
|
duration: Duration,
|
||||||
|
size: u16,
|
||||||
|
style: Style,
|
||||||
|
format: DurationFormat,
|
||||||
|
execute: Vec<String>,
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
duration,
|
duration,
|
||||||
size,
|
size,
|
||||||
|
execute,
|
||||||
style,
|
style,
|
||||||
format,
|
format,
|
||||||
ended_at: Some(Local::now() + duration),
|
ended_at: Some(Local::now() + duration),
|
||||||
|
execute_result: RefCell::new(None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,10 +45,10 @@ impl Timer {
|
||||||
self.duration = Duration::zero();
|
self.duration = Duration::zero();
|
||||||
} else {
|
} else {
|
||||||
self.duration = end_at - Local::now();
|
self.duration = end_at - Local::now();
|
||||||
}
|
|
||||||
self.ended_at = None;
|
self.ended_at = None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn resume(&mut self) {
|
pub(crate) fn resume(&mut self) {
|
||||||
if self.ended_at.is_none() {
|
if self.ended_at.is_none() {
|
||||||
|
@ -54,10 +66,34 @@ impl Timer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn execute(execute: &Vec<String>) -> String {
|
||||||
|
let mut cmd = Command::new("sh");
|
||||||
|
cmd.arg("-c");
|
||||||
|
let cmd_str = execute.join(" ");
|
||||||
|
cmd.arg(cmd_str);
|
||||||
|
let output = cmd.output();
|
||||||
|
match output {
|
||||||
|
Ok(output) => {
|
||||||
|
if !output.status.success() {
|
||||||
|
format!("[ERROR] {}", String::from_utf8_lossy(&output.stderr))
|
||||||
|
} else {
|
||||||
|
format!("[SUCCEED] {}", String::from_utf8_lossy(&output.stdout))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
format!("[FAILED] {}", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Widget for &Timer {
|
impl Widget for &Timer {
|
||||||
fn render(self, area: Rect, buf: &mut Buffer) {
|
fn render(self, area: Rect, buf: &mut Buffer) {
|
||||||
let remaining_time = self.remaining_time();
|
let remaining_time = self.remaining_time();
|
||||||
let time_str = if remaining_time < Duration::zero() {
|
let time_str = if remaining_time < Duration::zero() {
|
||||||
|
if self.execute.len() > 0 && self.execute_result.borrow().is_none() {
|
||||||
|
let result = execute(&self.execute);
|
||||||
|
*self.execute_result.borrow_mut() = Some(result);
|
||||||
|
}
|
||||||
if remaining_time.num_seconds() % 2 == 0 {
|
if remaining_time.num_seconds() % 2 == 0 {
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
|
@ -71,7 +107,7 @@ impl Widget for &Timer {
|
||||||
let footer = if self.is_paused() {
|
let footer = if self.is_paused() {
|
||||||
Some("PAUSED (press <SPACE> to resume)".to_string())
|
Some("PAUSED (press <SPACE> to resume)".to_string())
|
||||||
} else {
|
} else {
|
||||||
None
|
self.execute_result.borrow().clone()
|
||||||
};
|
};
|
||||||
render_centered(area, buf, &text, None, footer);
|
render_centered(area, buf, &text, None, footer);
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue