Skip to content

Commit 9a23bac

Browse files
committed
Cleanup and documentation
1 parent ef337ae commit 9a23bac

File tree

2 files changed

+54
-46
lines changed

2 files changed

+54
-46
lines changed

decks/main.deck

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -60,19 +60,6 @@
6060
[keys.action_hold]
6161
keycode = "Mute"
6262

63-
[[keys]]
64-
index = 7
65-
[keys.widget]
66-
id = "timer"
67-
[keys.widget.config]
68-
times = "5s;10m;30m;1h5m" # optional
69-
format = "%Hh;%Im;%Ss"
70-
font = "bold;regular;thin" # optional
71-
#color = "#fefefe" # optional
72-
underflow = "false" # optional
73-
underflowColor = "#ff0000;#ff0000;#ff0000" # optional
74-
75-
7663
[[keys]]
7764
index = 8
7865
[keys.widget]

widget_timer.go

Lines changed: 54 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import (
77
"time"
88
)
99

10-
// TimerWidget is a widget displaying a timer
10+
// TimerWidget is a widget displaying a timer.
1111
type TimerWidget struct {
1212
*BaseWidget
1313

@@ -26,29 +26,34 @@ type TimerWidget struct {
2626
data TimerData
2727
}
2828

29+
// TimerData represents the current state of the timer.
2930
type TimerData struct {
3031
startTime time.Time
3132
pausedTime time.Time
3233
}
3334

35+
// IsPaused returns whether the timer is paused.
3436
func (d *TimerData) IsPaused() bool {
3537
return !d.pausedTime.IsZero()
3638
}
3739

40+
// IsRunning returns whether the timer is running.
3841
func (d *TimerData) IsRunning() bool {
3942
return !d.IsPaused() && d.HasDeadline()
4043
}
4144

45+
// HasDeadline returns whether the start time is set.
4246
func (d *TimerData) HasDeadline() bool {
4347
return !d.startTime.IsZero()
4448
}
4549

50+
// Clear resets the state of the timer.
4651
func (d *TimerData) Clear() {
4752
d.startTime = time.Time{}
4853
d.pausedTime = time.Time{}
4954
}
5055

51-
// NewTimerWidget returns a new TimerWidget
56+
// NewTimerWidget returns a new TimerWidget.
5257
func NewTimerWidget(bw *BaseWidget, opts WidgetConfig) *TimerWidget {
5358
bw.setInterval(time.Duration(opts.Interval)*time.Millisecond, time.Second/2)
5459

@@ -73,6 +78,10 @@ func NewTimerWidget(bw *BaseWidget, opts WidgetConfig) *TimerWidget {
7378
times = append(times, defaultDuration)
7479
}
7580

81+
if len(formats) == 0 {
82+
formats = append(formats, "%H:%i:%s")
83+
}
84+
7685
layout := NewLayout(int(bw.dev.Pixels))
7786
frames := layout.FormatLayout(frameReps, len(formats))
7887

@@ -113,26 +122,30 @@ func (w *TimerWidget) Update() error {
113122
}
114123
size := int(w.dev.Pixels)
115124
img := image.NewRGBA(image.Rect(0, 0, size, size))
116-
var str string
117125

118126
for i := 0; i < len(w.formats); i++ {
127+
var timespan Timespan
119128
var fontColor = w.colors[i]
120129

121130
if !w.data.HasDeadline() {
122-
str = Timespan(w.times[w.currIndex]).Format(w.formats[i], w.adaptive)
131+
timespan = Timespan(w.times[w.currIndex])
123132
} else {
124133
remainingDuration := time.Until(w.data.startTime.Add(w.times[w.currIndex]))
125-
if remainingDuration < 0 && !w.underflow {
126-
str = Timespan(w.times[w.currIndex]).Format(w.formats[i], w.adaptive)
134+
if int(w.times[w.currIndex].Seconds()) == 0 {
135+
timespan = Timespan(remainingDuration * -1)
136+
} else if remainingDuration < 0 && !w.underflow {
137+
timespan = Timespan(w.times[w.currIndex])
127138
w.data.Clear()
128139
} else if remainingDuration < 0 && w.underflow {
129140
fontColor = w.underflowColors[i]
130-
str = Timespan(remainingDuration*-1).Format(w.formats[i], w.adaptive)
141+
timespan = Timespan(remainingDuration * -1)
131142
} else {
132-
str = Timespan(remainingDuration).Format(w.formats[i], w.adaptive)
143+
timespan = Timespan(remainingDuration)
133144
}
134145
}
146+
135147
font := fontByName(w.fonts[i])
148+
str := timespan.Format(w.formats[i], w.adaptive)
136149

137150
drawString(img,
138151
w.frames[i],
@@ -147,10 +160,11 @@ func (w *TimerWidget) Update() error {
147160
return w.render(w.dev, img)
148161
}
149162

163+
// Timespan represents the duration between two events.
150164
type Timespan time.Duration
151165

166+
// Format returns the formatted version of the timespan.
152167
func (t Timespan) Format(format string, adaptive bool) string {
153-
formatStr := format
154168
tm := map[string]string{
155169
"%h": "03",
156170
"%H": "15",
@@ -162,44 +176,51 @@ func (t Timespan) Format(format string, adaptive bool) string {
162176

163177
z := time.Unix(0, 0).UTC()
164178
current := z.Add(time.Duration(t))
165-
foundNonZero := false
166-
timeStr := ""
179+
var timeStr string
167180
if adaptive {
168-
for i := 0; i < len(formatStr); i++ {
169-
if formatStr[i:i+1] == "%" && len(formatStr) > i+1 {
170-
format := ReplaceAll(formatStr[i:i+2], tm)
171-
str := strings.TrimLeft(current.Format(format), "0")
172-
timeStr += str
173-
if str != "" {
174-
format = ReplaceAll(formatStr[i+2:], tm)
175-
timeStr += current.Format(format)
176-
break
177-
}
178-
foundNonZero = true
179-
i++
180-
} else {
181-
if !foundNonZero {
182-
timeStr += formatStr[i : i+1]
183-
}
184-
}
185-
}
186-
if timeStr == "" {
187-
timeStr = "0"
188-
}
181+
timeStr = TrimTime(current, format, tm)
189182
} else {
190183
format := ReplaceAll(format, tm)
191184
timeStr = current.Format(format)
192185
}
193186
return timeStr
194187
}
195188

189+
// TrimTime does remove leading zeroes and separator that are not required for the time representation.
190+
func TrimTime(current time.Time, formatStr string, tm map[string]string) string {
191+
foundNonZero := false
192+
timeStr := ""
193+
for i := 0; i < len(formatStr); i++ {
194+
if formatStr[i:i+1] == "%" && len(formatStr) > i+1 {
195+
format := ReplaceAll(formatStr[i:i+2], tm)
196+
str := strings.TrimLeft(current.Format(format), "0")
197+
timeStr += str
198+
if str != "" {
199+
format = ReplaceAll(formatStr[i+2:], tm)
200+
timeStr += current.Format(format)
201+
break
202+
}
203+
foundNonZero = true
204+
i++
205+
} else if !foundNonZero {
206+
timeStr += formatStr[i : i+1]
207+
}
208+
}
209+
if timeStr == "" {
210+
return "0"
211+
}
212+
return timeStr
213+
}
214+
215+
// ReplaceAll does a replacement with all entries of a map.
196216
func ReplaceAll(str string, tm map[string]string) string {
197217
for k, v := range tm {
198218
str = strings.ReplaceAll(str, k, v)
199219
}
200220
return str
201221
}
202222

223+
// TriggerAction updates the timer state.
203224
func (w *TimerWidget) TriggerAction(hold bool) {
204225
if hold {
205226
if w.data.IsPaused() {
@@ -211,7 +232,7 @@ func (w *TimerWidget) TriggerAction(hold bool) {
211232
if w.data.IsRunning() {
212233
w.data.pausedTime = time.Now()
213234
} else if w.data.IsPaused() && w.data.HasDeadline() {
214-
pausedDuration := time.Now().Sub(w.data.pausedTime)
235+
pausedDuration := time.Since(w.data.pausedTime)
215236
w.data.startTime = w.data.startTime.Add(pausedDuration)
216237
w.data.pausedTime = time.Time{}
217238
} else {

0 commit comments

Comments
 (0)