1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
use crate::error::{TimebarError, TimebarResult};
use crate::helpers::{
  get_current_timestamp, get_percentage, get_time_left, print_bar, string_to_u32,
};
use std::io::stdin;
use std::process;
use std::thread;
use std::time::Duration;
use termion::{clear, color, cursor};

pub fn timer_handler() {
  print_timer_intro();

  let mut args = String::new();
  stdin().read_line(&mut args).expect("Failed to read line");

  let config = TimerConfig::new(args.split(' ').collect()).unwrap_or_else(|err| {
    eprintln!("Problem parsing arguments: {}", err);
    process::exit(1);
  });

  let start = get_current_timestamp();
  let duration = config.seconds + config.minutes * 60 + config.hours * 60 * 60;
  let end = start + duration as u64;

  // Prepare display
  println!("\n{}{}", clear::All, cursor::Goto(1, 1));
  display_timer(start, end);
}

struct TimerConfig {
  hours: u32,
  minutes: u32,
  seconds: u32,
}

impl TimerConfig {
  pub fn new(args: Vec<&str>) -> TimebarResult<TimerConfig> {
    let mut iterator = args.into_iter();
    let timer = match iterator.next() {
      Some(arg) => arg,
      None => return Err(TimebarError::InvalidInput("duration".to_string())),
    };

    let timer_config: Vec<&str> = timer.split(':').collect();

    if timer_config.len() != 3 {
      return Err(TimebarError::InvalidDurationFormat);
    }

    let hours = string_to_u32(timer_config[0].clone().trim()).unwrap_or_else(|err| {
      eprintln!("Problem parsing arguments: {}", err);
      process::exit(1);
    });
    let minutes = string_to_u32(timer_config[1].clone().trim()).unwrap_or_else(|err| {
      eprintln!("Problem parsing arguments: {}", err);
      process::exit(1);
    });
    let seconds = string_to_u32(timer_config[2].clone().trim()).unwrap_or_else(|err| {
      eprintln!("Problem parsing arguments: {}", err);
      process::exit(1);
    });

    Ok(TimerConfig {
      hours,
      minutes,
      seconds,
    })
  }
}

fn print_timer_intro() {
  println!("Enter timer duration in the format of hour:minute:second.");
  println!(
    "For example: {}0:30:0{}",
    color::Fg(color::Green),
    color::Fg(color::White)
  );
}

fn display_timer(start: u64, end: u64) {
  println!("\n{}{}", clear::All, cursor::Goto(1, 1));
  loop {
    draw(start, end, "timer");
    thread::sleep(Duration::from_millis(1000));
    println!("\n{}{}{}", cursor::Show, clear::All, cursor::Goto(1, 1))
  }
}

fn draw(start: u64, end: u64, display_type: &str) {
  let percentage = get_percentage(start, end);
  let info = get_time_left(end, display_type.to_string()).unwrap();

  print!("{}", color::Fg(color::White));
  print_bar(&percentage);
  println!("\nTime is ticking... You have:\n");
  print!("{}", color::Fg(color::Green));
  println!("{} in hours", info.hours);
  println!("{} in minutes", info.minutes);
  println!(
    "{}{}{} in seconds.",
    color::Fg(color::Yellow),
    info.seconds,
    color::Fg(color::Green),
  );
}