use chrono::prelude::*; use chrono::Duration; use std::io::{stdout, Result, StdoutLock, Write}; use std::process::{Command, Output}; use std::thread::sleep; const TIME_FORMAT: &'static str = "%H:%M:%S"; fn main() { run().unwrap(); } /// Runs the application /// /// Default time settings are 25 minutes for a working block and 5 minutes for a break. fn run() -> Result<()> { let work_duration = Duration::seconds(if cfg!(debug_assertions) { 75 } else { 25 * 60 }); let break_duration = Duration::seconds(if cfg!(debug_assertions) { 5 } else { 5 * 60 }); loop { timer( "Work", "The working time is over, have a break now!", &work_duration, )?; timer( "Break", "The break is over, get back to work!", &break_duration, )?; } } /// Handles a timer block /// /// # Arguments /// /// * name - The name for this block, e.g. 'Work' or 'Break' /// * after_msg - The message to be displayed by the Dialog window at the end of the time /// * duration - How long this block shall be fn timer(name: &str, after_msg: &str, duration: &Duration) -> Result<()> { let out = stdout(); let mut out = out.lock(); let start = Local::now(); writeln!(out, "{} start {}", name, start.format(TIME_FORMAT))?; loop { reset_line(&mut out)?; let elapsed: Duration = Local::now().signed_duration_since(start); if elapsed >= *duration { break; } let elapsed_time: NaiveTime = NaiveTime::from_hms( (elapsed.num_hours() % 24) as u32, (elapsed.num_minutes() % 60) as u32, (elapsed.num_seconds() % 60) as u32, ); write!(out, "Time elapsed: {}", elapsed_time.format(TIME_FORMAT))?; out.flush().unwrap(); sleep(Duration::seconds(1).to_std().unwrap()); } let now = Local::now(); writeln!(out, "{} end {}", name, now.format(TIME_FORMAT))?; dialog(after_msg).unwrap(); Ok(()) } /// Shows a dialog /// /// Currently only supports KDE dialogs via command line program `kdialgo`. /// /// # Arguments /// /// * text - The text to be shown in the Dialog fn dialog(text: &str) -> Result { Command::new("sh") .arg("-c") .arg(format!( "kdialog --title 'Pomodoro Timer' --msgbox '{}'", text )) .output() } /// Resets the current line on stdout /// /// Works for meĀ® but is probably unportable as hell. /// /// # Arguments /// /// * w - A reference to the locked stdout handle pub fn reset_line(w: &mut StdoutLock) -> Result<()> { write!(w, "\r[2K") }