From f0b46ed8b7de6efef7e6e0877d2cb00203e167d3 Mon Sep 17 00:00:00 2001 From: Dan Anglin Date: Wed, 18 Sep 2019 09:08:12 +0100 Subject: [PATCH] refactor: code refactoring to improve stability. This commit removes the need to calculate the time remaining in a session and instead introduces a countdown counter which decrements at each one second 'tick'. This stabilizes the interface where it appeared that he timer was randomly pausing or skipping time. A summary of changes made in this commit includes: - Updated the command line flags so that they are easier to remember. - The work, short break and long break session times are now parsed and converted to type float64. These times represent the total amount of seconds. - Removal of timer and finish from Pominal. - The method that calculates the time remaining is removed. - A countdown counter is added to the Pominal type. - Updated alert message for the desktop notification. - Simplified the Run method by moving the logic to chosse the next session in a separate method. --- Makefile | 6 +-- alert.go | 8 +-- main.go | 41 +++++++-------- pominal.go | 147 +++++++++++++++++++++++++++-------------------------- 4 files changed, 101 insertions(+), 101 deletions(-) diff --git a/Makefile b/Makefile index cab15e3..83da195 100644 --- a/Makefile +++ b/Makefile @@ -7,10 +7,10 @@ BIN_FILE := $(BIN_DIR)/$(NAME) all: test_unit build test_unit: - go test -v -cover ./... + @go test -v -cover ./... build: - go build -a -v -o $(BIN_FILE) + @go build -a -v -o $(BIN_FILE) clean: - go clean + @go clean diff --git a/alert.go b/alert.go index 6ae4176..17013a8 100644 --- a/alert.go +++ b/alert.go @@ -54,9 +54,9 @@ func getIconPath() string { return result } -// alert pushes a desktop notification -func alert(oldLabel, newLabel string) { - title := oldLabel + " timer has stopped" - text := newLabel + " timer has started" +// alert creates a new desktop notification. +func alert(l string) { + title := "Pominal notification." + text := l + " session has started." notifier.Push(title, text, "", notificator.UR_NORMAL) } diff --git a/main.go b/main.go index 838817a..a3e5b94 100644 --- a/main.go +++ b/main.go @@ -21,7 +21,6 @@ package main import ( "flag" "fmt" - "math" "os" "os/exec" "time" @@ -34,18 +33,18 @@ const ( ) var ( - workTimer string - shortBreakTimer string - longBreakTimer string - maxWorkCycles int + workTime string + shortBreakTime string + longBreakTime string + maxWorkSessions int printVersion bool ) func init() { - flag.StringVar(&workTimer, "work-timer", "25m", "sets the timer for your work session.") - flag.StringVar(&shortBreakTimer, "short-break-timer", "5m", "sets the timer for your short break.") - flag.StringVar(&longBreakTimer, "long-break-timer", "20m", "sets the timer for your long break.") - flag.IntVar(&maxWorkCycles, "max-work-cycles", 4, "sets the maximum number of work cycles to complete before taking a long break.") + flag.StringVar(&workTime, "work", "25m", "sets the timer for your work session.") + flag.StringVar(&shortBreakTime, "short-break", "5m", "sets the timer for your short break.") + flag.StringVar(&longBreakTime, "long-break", "20m", "sets the timer for your long break.") + flag.IntVar(&maxWorkSessions, "max-work-sessions", 4, "sets the maximum number of work cycles to complete before taking a long break.") flag.BoolVar(&printVersion, "version", false, "print version and exit.") flag.Parse() } @@ -59,43 +58,41 @@ func main() { initNotifier() - workTimeDuration, err := time.ParseDuration(workTimer) + w, err := time.ParseDuration(workTime) if err != nil { fmt.Printf("ERROR: Unable to set the work timer. %s", err.Error()) os.Exit(1) } - shortBreakTimeDuration, err := time.ParseDuration(shortBreakTimer) + s, err := time.ParseDuration(shortBreakTime) if err != nil { fmt.Printf("ERROR: Unable to set the work timer. %s", err.Error()) os.Exit(1) } - longBreakTimeDuration, err := time.ParseDuration(longBreakTimer) + l, err := time.ParseDuration(longBreakTime) if err != nil { fmt.Printf("ERROR: Unable to set the work timer. %s", err.Error()) os.Exit(1) } pominal := NewPominal( - workTimeDuration, - shortBreakTimeDuration, - longBreakTimeDuration, - maxWorkCycles, + w.Seconds(), + s.Seconds(), + l.Seconds(), + maxWorkSessions, ) pominal.Run() } // printScreen prints the details of the Pominal session on screen including -// the current work cycle number, the timer's current label and the time remaining -// on the timer. +// the current work session number, the timer's current label and the current countdoen. // TODO: To be removed when TUI is implemented. -func printScreen(remaining float64, pominalCount, workCycle, maxWorkCycle int, label string) { +func printScreen(countdown float64, pominalCount, workSessionCount, maxWorkSession int, label string) { clearScreen() - remainingSecs := int(math.Ceil(remaining)) - fmt.Printf("Pominal session: %d\nWork cycle: %d of %d\n\n", pominalCount, workCycle, maxWorkCycle) - fmt.Printf("Timer: %s\nTime remaining: %02d:%02d", label, (remainingSecs/60)%60, remainingSecs%60) + fmt.Printf("Pominal cycle: %d\nWork session: %d of %d\n\n", pominalCount, workSessionCount, maxWorkSession) + fmt.Printf("Session: %s\nTime remaining: %02d:%02d", label, int(countdown)/60, int(countdown)%60) } // clearScreen clears the terminal screen diff --git a/pominal.go b/pominal.go index 49ea736..7f5dc2b 100644 --- a/pominal.go +++ b/pominal.go @@ -27,106 +27,109 @@ import ( ) type Pominal struct { - timer *time.Timer - finish time.Time - work time.Duration - shortBreak time.Duration - longBreak time.Duration - maxWorkCycles int - session int - label string + // workSession is a counter for work sessions. + workSession int + + // maxWorkSessions sets the number of work sessions to complete + // before running the countdown timer for each long break. + maxWorkSessions int + + // cycle represents a Pominal cycle. A Pominal cycle increments after + // every long break. + cycle int + + // countdown is the decrementing counter for Pominal. + countdown float64 + + // work is the time (represented in seconds) for the work sessions. + work float64 + + // shortBreak is the time (represented in seconds) for the short break sessions. + shortBreak float64 + + // longBreak is the time (represented in seconds) for the long break sessions. + longBreak float64 + + // label labels Pominal based on the session. + label string } // NewPominal creates a new pominal instance -func NewPominal(w, s, l time.Duration, m int) Pominal { +func NewPominal(w, s, l float64, m int) Pominal { return Pominal{ - work: w, - shortBreak: s, - longBreak: l, - maxWorkCycles: m, - session: 1, + workSession: 1, + maxWorkSessions: m, + cycle: 1, + work: w, + shortBreak: s, + longBreak: l, } } // Run Pominal func (p *Pominal) Run() { - workCycleCount := 1 - t := time.NewTicker(1 * time.Second) s := make(chan os.Signal, 1) - signal.Notify(s, syscall.SIGINT, syscall.SIGTERM) - p.Start(workTimerLabel, workCycleCount) + + p.UpdateSession() + t := time.NewTicker(1 * time.Second) infinite: for { select { case sig := <-s: fmt.Printf("\n\nReceived signal '%s'. Closing Pominal.\n", sig) - p.timer.Stop() t.Stop() break infinite case <-t.C: - printScreen(p.TimeRemaining(), p.session, workCycleCount, p.maxWorkCycles, p.label) - case <-p.timer.C: - fmt.Printf("\n%s timer has finished\n", p.label) - p.timer.Stop() - t.Stop() - time.Sleep(1 * time.Second) - oldLabel := p.label - switch p.label { - case workTimerLabel: - if workCycleCount >= p.maxWorkCycles { - p.Start(longBreakTimerLabel, workCycleCount) - } else { - p.Start(shortBreakTimerLabel, workCycleCount) - } - case shortBreakTimerLabel: - workCycleCount++ - p.Start(workTimerLabel, workCycleCount) - case longBreakTimerLabel: - workCycleCount = 1 - p.IncrementCount() - p.Start(workTimerLabel, workCycleCount) + p.countdown-- + if p.countdown < 0 { + fmt.Printf("\n%s session has finished.\n", p.label) + t.Stop() + p.UpdateSession() + time.Sleep(1 * time.Second) + t = time.NewTicker(1 * time.Second) + } else { + printScreen(p.countdown, + p.cycle, + p.workSession, + p.maxWorkSessions, + p.label, + ) } - t = time.NewTicker(1 * time.Second) - newLabel := p.label - alert(oldLabel, newLabel) } } } -// Start begins the timer specified by the -// label argument. -func (p *Pominal) Start(label string, workCycleCount int) { - var d time.Duration - - switch label { +// UpdateSession resets Pominal's countdown +// based on the next session. If a 'short break' +// session is over the work session counter is incremented. +// If a 'long break' session is over then the Pominal cycle +// is incremented and the work session counter is reset +// to 1. +func (p *Pominal) UpdateSession() { + switch p.label { case workTimerLabel: - d = p.work + if p.workSession >= p.maxWorkSessions { + p.countdown = p.longBreak + p.label = longBreakTimerLabel + } else { + p.countdown = p.shortBreak + p.label = shortBreakTimerLabel + } case shortBreakTimerLabel: - d = p.shortBreak + p.workSession++ + p.countdown = p.work + p.label = workTimerLabel case longBreakTimerLabel: - d = p.longBreak + p.cycle++ + p.workSession = 1 + p.countdown = p.work + p.label = workTimerLabel + default: + p.countdown = p.work + p.label = workTimerLabel } - - p.label = label - if p.timer == nil { - p.timer = time.NewTimer(d) - } else { - p.timer.Reset(d) - } - - p.finish = time.Now().Add(d) -} - -// TimeRemaining returns the remaining time left -// on the timer -func (p *Pominal) TimeRemaining() float64 { - return p.finish.Sub(time.Now()).Seconds() -} - -// IncrementCount increments the pominal session count -func (p *Pominal) IncrementCount() { - p.session++ + alert(p.label) }