pominal/pominal.go

232 lines
6.2 KiB
Go
Raw Normal View History

/*
Pominal
2020-02-11 16:27:47 +00:00
Copyright (C) 2020 Daniel Anglin
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package main
import (
"time"
2020-01-18 19:24:35 +00:00
"github.com/rivo/tview"
)
type Pominal struct {
// 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)
2022-10-08 22:13:41 +01:00
// for the long break sessions.
longBreak float64
// workNotificationMsg is the desktop notification
// message when a work session has started.
workNotificationMsg string
// shortBreakNotificationMsg is the desktop notification
// message when a short break session has started.
shortBreakNotificationMsg string
// longBreakNotificationMsg is the desktop notification
// message when a long break session has started.
longBreakNotificationMsg string
// currentNotificationMsg is used for desktop notifications.
// This will be equal to workNotificationMsg, shortBreakNotificationMsg
// or longBreakNotificationMsg depending on the session in progress.
currentNotificationMsg string
// label labels Pominal based on the session.
label string
2020-01-19 21:26:46 +00:00
// stopChan is a no-data channel used to stop Pominal.
stopChan chan struct{}
}
// NewPominal creates a new pominal instance
func newPominal(config PominalConfig) (Pominal, error) {
initWorkSession := 1
initCycle := 1
maxWorkSessions := setMaxWorkSessions(config.MaxWorkSessions)
work, err := setSessionTime(config.Sessions.Work.Duration, defaultWorkTime)
if err != nil {
return Pominal{}, err
}
shortBreak, err := setSessionTime(config.Sessions.ShortBreak.Duration, defaultShortBreakTime)
if err != nil {
return Pominal{}, err
}
longBreak, err := setSessionTime(config.Sessions.LongBreak.Duration, defaultLongBreakTime)
if err != nil {
return Pominal{}, err
}
p := Pominal{
workSession: initWorkSession,
maxWorkSessions: maxWorkSessions,
cycle: initCycle,
work: work,
shortBreak: shortBreak,
longBreak: longBreak,
workNotificationMsg: config.Sessions.Work.NotificationMessage,
shortBreakNotificationMsg: config.Sessions.ShortBreak.NotificationMessage,
longBreakNotificationMsg: config.Sessions.LongBreak.NotificationMessage,
stopChan: nil,
}
return p, nil
}
// Run Pominal
2020-01-18 19:24:35 +00:00
func (p *Pominal) Run(infoUI, timerUI *tview.TextView) {
p.stopChan = make(chan struct{})
p.UpdateSession()
drawInfo(infoUI, p.cycle, p.workSession, p.maxWorkSessions, p.label)
// notifier is used for desktop notifications
notifier := initNotifier()
t := time.NewTicker(time.Second)
infinite:
for {
select {
2020-01-19 21:26:46 +00:00
case <-p.stopChan:
t.Stop()
break infinite
case <-t.C:
p.countdown--
if p.countdown < 0 {
t.Stop()
p.UpdateSession()
drawInfo(
infoUI,
p.cycle,
p.workSession,
p.maxWorkSessions,
p.label,
)
desktopAlert(p.label, p.currentNotificationMsg, notifier)
time.Sleep(time.Second)
t = time.NewTicker(time.Second)
} else {
2020-01-18 19:24:35 +00:00
drawTimer(timerUI, p.countdown)
}
}
}
}
2020-01-19 21:26:46 +00:00
// Stop sends a signal to the Run method to stop the timer.
// Afterwards the process returns from the Run method.
func (p *Pominal) Stop() {
close(p.stopChan)
}
// 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:
if p.workSession >= p.maxWorkSessions {
p.countdown = p.longBreak
p.label = longBreakTimerLabel
p.currentNotificationMsg = p.longBreakNotificationMsg
} else {
p.countdown = p.shortBreak
p.label = shortBreakTimerLabel
p.currentNotificationMsg = p.shortBreakNotificationMsg
}
case shortBreakTimerLabel:
p.workSession++
p.countdown = p.work
p.label = workTimerLabel
p.currentNotificationMsg = p.workNotificationMsg
case longBreakTimerLabel:
p.cycle++
p.workSession = 1
p.countdown = p.work
p.label = workTimerLabel
p.currentNotificationMsg = p.workNotificationMsg
default:
p.countdown = p.work
p.label = workTimerLabel
p.currentNotificationMsg = p.workNotificationMsg
}
}
2019-09-20 00:55:10 +01:00
// setSessionTime parses the configured session time and
// returns the session time represented in seconds.
// If the session time is unconfigured then the default for
// that particular session is returned.
// If the value is less than the minimum session time
// then the minimum is returned instead.
// An error is returned if the configured session time cannot be parsed.
func setSessionTime(s, defaultSessionTime string) (float64, error) {
if len(s) == 0 {
s = defaultSessionTime
}
sTime, err := time.ParseDuration(s)
if err != nil {
return float64(0), err
}
sTimeInSecs := sTime.Seconds()
if sTimeInSecs < minimumSessionTime {
sTimeInSecs = minimumSessionTime
2019-09-20 00:55:10 +01:00
}
return sTimeInSecs, nil
2019-09-20 00:55:10 +01:00
}
// setMaxWorkSessions checks and returns the configured
// number of work session per Pominal cycle.
// The default value is returned if the argument is 0
// or less.
func setMaxWorkSessions(w int) int {
if w <= 0 {
w = defaultMaxWorkSessions
}
return w
}