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
|
|
|
|
|
}
|