From 730f5a29e29b13ed9d4f9f67acb1722425708524 Mon Sep 17 00:00:00 2001 From: Christian Rocha Date: Tue, 5 Nov 2024 22:03:46 -0500 Subject: [PATCH] fix: debounce stopwatch and timer This keeps them from ticking too fast. Fixes #661. --- stopwatch/stopwatch.go | 21 ++++++++++++++++----- timer/timer.go | 12 +++++++++++- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/stopwatch/stopwatch.go b/stopwatch/stopwatch.go index bf4e39c..e5d5f63 100644 --- a/stopwatch/stopwatch.go +++ b/stopwatch/stopwatch.go @@ -23,7 +23,8 @@ type TickMsg struct { // Note, however, that a stopwatch will reject ticks from other // stopwatches, so it's safe to flow all TickMsgs through all stopwatches // and have them still behave appropriately. - ID int + ID int + tag int } // StartStopMsg is sent when the stopwatch should start or stop. @@ -41,6 +42,7 @@ type ResetMsg struct { type Model struct { d time.Duration id int + tag int running bool // How long to wait before every tick. Defaults to 1 second. @@ -75,7 +77,7 @@ func (m Model) Init() tea.Cmd { func (m Model) Start() tea.Cmd { return tea.Batch(func() tea.Msg { return StartStopMsg{ID: m.id, running: true} - }, tick(m.id, m.Interval)) + }, tick(m.id, m.tag, m.Interval)) } // Stop stops the stopwatch. @@ -122,8 +124,17 @@ func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) { if !m.running || msg.ID != m.id { break } + + // If a tag is set, and it's not the one we expect, reject the message. + // This prevents the stopwatch from receiving too many messages and + // thus ticking too fast. + if msg.tag > 0 && msg.tag != m.tag { + return m, nil + } + m.d += m.Interval - return m, tick(m.id, m.Interval) + m.tag++ + return m, tick(m.id, m.tag, m.Interval) } return m, nil @@ -139,8 +150,8 @@ func (m Model) View() string { return m.d.String() } -func tick(id int, d time.Duration) tea.Cmd { +func tick(id int, tag int, d time.Duration) tea.Cmd { return tea.Tick(d, func(_ time.Time) tea.Msg { - return TickMsg{ID: id} + return TickMsg{ID: id, tag: tag} }) } diff --git a/timer/timer.go b/timer/timer.go index 076ee6f..d0b6da6 100644 --- a/timer/timer.go +++ b/timer/timer.go @@ -61,6 +61,8 @@ type TickMsg struct { // Timeout returns whether or not this tick is a timeout tick. You can // alternatively listen for TimeoutMsg. Timeout bool + + tag int } // TimeoutMsg is a message that is sent once when the timer times out. @@ -80,6 +82,7 @@ type Model struct { Interval time.Duration id int + tag int running bool } @@ -137,6 +140,13 @@ func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) { break } + // If a tag is set, and it's not the one we expect, reject the message. + // This prevents the ticker from receiving too many messages and + // thus ticking too fast. + if msg.tag > 0 && msg.tag != m.tag { + return m, nil + } + m.Timeout -= m.Interval return m, tea.Batch(m.tick(), m.timedout()) } @@ -166,7 +176,7 @@ func (m *Model) Toggle() tea.Cmd { func (m Model) tick() tea.Cmd { return tea.Tick(m.Interval, func(_ time.Time) tea.Msg { - return TickMsg{ID: m.id, Timeout: m.Timedout()} + return TickMsg{ID: m.id, tag: m.tag, Timeout: m.Timedout()} }) }