recator: use timer signals instead of shared.Message.TimeLeft

- remove shared.Message.TimeLeft
- modify Timer struct
  - add TimeLeft signal
  - add End and Abort signals
- add syncronised ticker
- update RunPomodoro to use goroutines for timer starts
  - add waitForTimer function
This commit is contained in:
Sebastian Mark 2024-10-25 23:13:06 +02:00
parent aa5c24f06d
commit 3eae584d6d
2 changed files with 44 additions and 22 deletions

View file

@ -9,6 +9,19 @@ import (
var mu sync.Mutex // to synchronize access to shared state var mu sync.Mutex // to synchronize access to shared state
var timer Timer var timer Timer
func waitForTimer(t Timer) bool {
for {
select {
case <-t.End:
return true
case <-t.Abort:
return false
case shared.Message.TimeLeft = <-t.TimeLeft:
// do nothing, just let the timer update the message
}
}
}
// RunPomodoro iterates the Pomodoro work/break sessions. // RunPomodoro iterates the Pomodoro work/break sessions.
func RunPomodoro() { func RunPomodoro() {
mu.Lock() mu.Lock()
@ -24,18 +37,21 @@ func RunPomodoro() {
shared.Message.Session = session shared.Message.Session = session
shared.Message.Mode = "Work" shared.Message.Mode = "Work"
if !timer.Start(pomodoroConfig.Work) { go timer.Start(pomodoroConfig.Work)
if !waitForTimer(timer) {
break break
} }
if session > pomodoroConfig.Sessions { if session < pomodoroConfig.Sessions {
shared.Message.Mode = "ShortBreak" shared.Message.Mode = "ShortBreak"
if !timer.Start(pomodoroConfig.ShortBreak) { go timer.Start(pomodoroConfig.ShortBreak)
if !waitForTimer(timer) {
break break
} }
} else { // last phase, prepare for finish } else { // last phase, prepare for finish
shared.Message.Mode = "LongBreak" shared.Message.Mode = "LongBreak"
if !timer.Start(pomodoroConfig.LongBreak) { go timer.Start(pomodoroConfig.LongBreak)
if !waitForTimer(timer) {
break break
} }
shared.Message.Mode = "End" shared.Message.Mode = "End"

View file

@ -1,47 +1,53 @@
package pomodoro package pomodoro
import ( import (
"git.smsvc.net/pomodoro/GoTomato/internal/shared"
"time" "time"
) )
type Timer struct { type Timer struct {
abort chan bool TimeLeft chan int // time left
End chan bool // signal on successful end
Abort chan bool // signal on premature end
stop chan bool
wait chan bool wait chan bool
resume chan bool resume chan bool
} }
func (t Timer) Init() Timer { func (t Timer) Init() Timer {
return Timer{ return Timer{
abort: make(chan bool, 1), TimeLeft: make(chan int),
End: make(chan bool, 1),
Abort: make(chan bool, 1),
stop: make(chan bool, 1),
wait: make(chan bool, 1), wait: make(chan bool, 1),
resume: make(chan bool, 1), resume: make(chan bool, 1),
} }
} }
func (t *Timer) Start(duration int) bool { func (t *Timer) Start(duration int) {
tick := time.NewTicker(time.Second)
for timeLeft := duration; timeLeft > 0; { for timeLeft := duration; timeLeft > 0; {
select { select {
case <-t.abort: case <-t.stop:
return false t.Abort <- true
return
case <-t.wait: case <-t.wait:
<-t.resume <-t.resume
default: continue
shared.Message.TimeLeft = timeLeft case <-tick.C:
time.Sleep(time.Second)
timeLeft-- timeLeft--
default:
t.TimeLeft <- timeLeft
} }
} }
t.TimeLeft <- 0
// Final shared.Message when time reaches zero t.End <- true
shared.Message.TimeLeft = 0
return true
} }
func (t *Timer) Stop() { func (t *Timer) Stop() {
t.resume <- true t.resume <- true
t.abort <- true t.stop <- true
} }
func (t *Timer) Pause() { func (t *Timer) Pause() {