pomodoro/main.go

141 lines
2.3 KiB
Go
Raw Permalink Normal View History

2021-12-13 15:39:41 +03:00
package main
import (
2021-12-15 01:47:23 +03:00
"context"
2021-12-13 15:39:41 +03:00
"fmt"
2021-12-15 01:47:23 +03:00
"os"
"os/signal"
2021-12-13 15:39:41 +03:00
"time"
2021-12-15 01:47:23 +03:00
"github.com/eiannone/keyboard"
2021-12-13 15:39:41 +03:00
)
type state int
const (
Working state = iota
Break
LongBreak
2021-12-15 01:47:23 +03:00
Pause
2021-12-13 15:39:41 +03:00
)
var (
currentState = Working
2021-12-15 01:47:23 +03:00
prevState = Working
2021-12-13 15:39:41 +03:00
currentDuration = 25 * 60
pomodoros = 1
)
func main() {
2021-12-15 01:47:23 +03:00
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()
}()
2021-12-13 15:39:41 +03:00
for {
2021-12-15 01:47:23 +03:00
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--
2021-12-13 15:39:41 +03:00
}
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()
}
2021-12-15 01:47:23 +03:00
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)
2021-12-13 15:39:41 +03:00
}
2021-12-15 01:47:23 +03:00
return ""
2021-12-13 15:39:41 +03:00
}
func bell() {
2021-12-15 01:47:23 +03:00
fmt.Print("\u0007")
2021-12-13 15:39:41 +03:00
}
2021-12-15 01:47:23 +03:00
func clear() {
fmt.Print("\u001B[2K\u001B[F\u001B[2K\r")
2021-12-13 15:39:41 +03:00
}
func secondsToMinutes(inSeconds int) string {
minutes := inSeconds / 60
seconds := inSeconds % 60
str := fmt.Sprintf("%02d:%02d", minutes, seconds)
return str
}