pomodoro/main.go
Alexander Kiryukhin a6c52444e9
Added control keys
2021-12-15 01:47:23 +03:00

141 lines
2.3 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package main
import (
"context"
"fmt"
"os"
"os/signal"
"time"
"github.com/eiannone/keyboard"
)
type state int
const (
Working state = iota
Break
LongBreak
Pause
)
var (
currentState = Working
prevState = Working
currentDuration = 25 * 60
pomodoros = 1
)
func main() {
ctx, cancel := signal.NotifyContext(context.Background(), os.Kill, os.Interrupt)
defer cancel()
go timer(ctx)
go keys(cancel)
<-ctx.Done()
}
func keys(cancel func()) {
if err := keyboard.Open(); err != nil {
panic(err)
}
defer func() {
_ = keyboard.Close()
}()
for {
char, _, err := keyboard.GetKey()
if err != nil {
panic(err)
}
switch string(char) {
case "p":
if currentState != Pause {
prevState = currentState
currentState = Pause
} else {
currentState = prevState
}
case "n":
currentDuration = 0
case "q":
cancel()
return
}
}
}
func timer(ctx context.Context) {
needClear := false
for {
if currentState != Pause {
currentDuration--
}
if currentDuration < 0 {
switch currentState {
case Working:
if pomodoros%4 == 0 {
currentState = LongBreak
currentDuration = 15 * 60
} else {
currentState = Break
currentDuration = 5 * 60
}
case Break, LongBreak:
currentState = Working
currentDuration = 25 * 60
pomodoros++
}
bell()
}
if needClear {
clear()
}
needClear = true
displayTimer()
select {
case <-time.After(1 * time.Second):
// Do nothing
case <-ctx.Done():
return
}
}
}
func displayTimer() {
stateText := ""
if currentState == Pause {
stateText = fmt.Sprintf("[Paused] %s", getStateText(prevState))
} else {
stateText = getStateText(currentState)
}
fmt.Printf("%s %s\n(keys: p - pause/resume timer, n - next phase, q - quit)", stateText, secondsToMinutes(currentDuration))
}
func getStateText(state state) string {
switch state {
case Working:
return fmt.Sprintf("🍅 #%d Working", pomodoros)
case Break:
return fmt.Sprintf("☕️ #%d Break", pomodoros)
case LongBreak:
return fmt.Sprintf("☕️ #%d Long break", pomodoros)
}
return ""
}
func bell() {
fmt.Print("\u0007")
}
func clear() {
fmt.Print("\u001B[2K\u001B[F\u001B[2K\r")
}
func secondsToMinutes(inSeconds int) string {
minutes := inSeconds / 60
seconds := inSeconds % 60
str := fmt.Sprintf("%02d:%02d", minutes, seconds)
return str
}