Make spinners ignore tick messsages send by other spinners

This commit is contained in:
Christian Rocha 2021-12-01 11:33:48 -05:00
parent f09987549a
commit 94b84b6120

View File

@ -2,6 +2,7 @@ package spinner
import (
"strings"
"sync"
"time"
tea "github.com/charmbracelet/bubbletea"
@ -9,6 +10,21 @@ import (
"github.com/muesli/reflow/ansi"
)
// Internal ID management for text inputs. Necessary for blink integrity when
// multiple text inputs are involved.
var (
lastID int
idMtx sync.Mutex
)
// Return the next ID we should use on the Model.
func nextID() int {
idMtx.Lock()
defer idMtx.Unlock()
lastID++
return lastID
}
// Spinner is a set of frames used in animating the spinner.
type Spinner struct {
Frames []string
@ -92,6 +108,7 @@ type Model struct {
frame int
startTime time.Time
id int
tag int
}
@ -173,13 +190,17 @@ func (m Model) Visible() bool {
// NewModel returns a model with default values.
func NewModel() Model {
return Model{Spinner: Line}
return Model{
Spinner: Line,
id: nextID(),
}
}
// TickMsg indicates that the timer has ticked and we should render a frame.
type TickMsg struct {
Time time.Time
tag int
id int
}
// Update is the Tea update function. This will advance the spinner one frame
@ -188,6 +209,12 @@ type TickMsg struct {
func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) {
switch msg := msg.(type) {
case TickMsg:
// If an ID is set, and the ID doesn't belong to this spinner, reject
// the message.
if msg.id > 0 && msg.id != m.id {
return m, nil
}
// If a tag is set, and it's not the one we expect, reject the message.
// This prevents the spinner from receiving too many messages and
// thus spinning too fast.
@ -201,7 +228,7 @@ func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) {
}
m.tag++
return m, m.tick(m.tag)
return m, m.tick(m.id, m.tag)
default:
return m, nil
}
@ -231,10 +258,11 @@ func Tick() tea.Msg {
return TickMsg{Time: time.Now()}
}
func (m Model) tick(tag int) tea.Cmd {
func (m Model) tick(id, tag int) tea.Cmd {
return tea.Tick(m.Spinner.FPS, func(t time.Time) tea.Msg {
return TickMsg{
Time: t,
id: id,
tag: tag,
}
})