timer/main.go

226 lines
4.8 KiB
Go

// Package main has a comment
package main
import (
"flag"
"fmt"
"local/logger"
"time"
"github.com/eiannone/keyboard"
"github.com/everdev/mack"
)
var notified = false
var alertMessage string
var originalStart = time.Now()
func main() {
var duration string
var offset string
var interval string
var repeat bool
var invert bool
var eta bool
flag.BoolVar(&repeat, "repeat", true, "Whether to repeat the timer on complete")
flag.BoolVar(&invert, "stopwatch", false, "Use as a stopwatch")
flag.StringVar(&duration, "duration", "30m", "How long the timer should be")
flag.StringVar(&offset, "offset", "0m", "How much time the initial time should skip")
flag.StringVar(&alertMessage, "msg", "Timer up", "Message to display on timer expiration")
flag.StringVar(&interval, "interval", "500ms", "Interval duration")
flag.BoolVar(&eta, "eta", false, "Whether to display the ending time")
flag.Parse()
tickerInterval, err := time.ParseDuration(interval)
if err != nil {
panic(err)
}
monitor := time.NewTicker(tickerInterval)
defer monitor.Stop()
base, err := time.ParseDuration(duration)
if err != nil {
panic(err)
}
var cur time.Duration
if invert {
cur = time.Duration(0)
} else {
cur = base
}
skip, err := time.ParseDuration(offset)
if err != nil {
panic(err)
}
if invert {
cur += skip
} else {
cur -= skip
}
stop := make(chan bool)
pause := make(chan bool)
confirm := make(chan bool)
paused := false
delim := ':'
logger.Log("Quit with 'q', Pause with 'p', Reset with 'r'")
keych := keyChannel()
go func() {
last := time.Now()
printTime(&cur, base, &delim, invert, repeat, eta)
for {
select {
case <-monitor.C:
difference := time.Duration(time.Now().UnixNano() - last.UnixNano())
last = time.Now()
if difference > time.Hour*2 {
keych <- 'p'
continue
} else if invert {
cur += difference
} else {
cur -= difference
}
case state := <-pause:
if !state {
monitor = time.NewTicker(tickerInterval)
last = time.Now()
} else {
monitor.Stop()
}
case <-stop:
logger.Logf()
confirm <- true
return
}
printTime(&cur, base, &delim, invert, repeat, eta)
}
}()
for {
b := <-keych
switch b {
case 'q':
stop <- true
<-confirm
return
case 'p':
paused = !paused
pause <- paused
case 'r':
skip = time.Duration(0)
originalStart = time.Now()
if invert {
cur = time.Duration(0)
} else {
cur = base
}
notified = false
printTime(&cur, base, &delim, invert, repeat, eta)
case 'z':
logger.Logf()
printTime(&cur, base, &delim, invert, repeat, eta)
}
}
}
func printTime(pRemains *time.Duration, target time.Duration, delim *rune, reverse bool, repeat bool, eta bool) {
var final string
remains := *pRemains
sec := remains.Seconds()
min := int(sec / 60.0)
seconds := int(sec) % 60
hrs := min / 60
min = min % 60
if *delim == ':' {
*delim = ' '
} else {
*delim = ':'
}
if reverse {
remains := target - remains
rMin := int(remains.Seconds() / 60.0)
rSec := int(remains.Seconds()) % 60
rHrs := rMin / 60
rMin = rMin % 60
tdelim := byte(*delim)
if remains < 0 {
rMin = 0
rSec = 0
rHrs = 0
tdelim = ':'
go alertTime(pRemains, target, reverse, repeat)
}
at := fmt.Sprintf("%2d%c%02d%c%02d ", hrs, byte(*delim), min, byte(*delim), seconds)
rem := fmt.Sprintf("%2d%c%02d%c%02d ", rHrs, tdelim, rMin, tdelim, rSec)
rem = fmt.Sprintf("%s \tAt: %s ", rem, at)
if eta {
rem = fmt.Sprintf("%s \tETA: %s", rem, time.Unix(0, (time.Now().UnixNano()+target.Nanoseconds()-pRemains.Nanoseconds())).Format("3:04"))
}
final = rem
} else {
rem := fmt.Sprintf("%2d%c%02d%c%02d ", hrs, byte(*delim), min, byte(*delim), seconds)
final = rem + " "
if eta {
final = fmt.Sprintf("%s \tETA: %s", final, time.Unix(0, time.Now().UnixNano()+pRemains.Nanoseconds()).Format("3:04"))
}
if remains < 0 {
go alertTime(pRemains, target, reverse, repeat)
}
}
logger.Logf("\r%s", final)
}
func alertTime(pRemains *time.Duration, target time.Duration, reverse, repeat bool) {
if !notified {
notified = true
_, err := mack.Alert(fmt.Sprintf("%s\nTimer for %s done", alertMessage, target.String()))
if err != nil {
panic(err)
}
if repeat {
originalStart = time.Now()
if reverse {
for *pRemains > 0 {
*pRemains -= target
}
*pRemains += target
} else {
for *pRemains < 0 {
*pRemains += target
}
}
notified = false
}
}
}
func keyChannel() chan rune {
ch := make(chan rune, 20)
go func() {
if err := keyboard.Open(); err != nil {
panic(err)
}
for {
b, _, err := keyboard.GetKey()
if err != nil {
panic(err)
}
by := rune(b)
if by == 'q' {
keyboard.Close()
ch <- by
return
}
ch <- by
}
}()
return ch
}