Sam Fredrickson
9e6abb1112
All checks were successful
Build & Test / Main (push) Successful in 2m26s
100 lines
2.3 KiB
Go
100 lines
2.3 KiB
Go
package tui
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"code.humancabbage.net/sam/moonmath/coindesk"
|
|
"code.humancabbage.net/sam/moonmath/config"
|
|
"code.humancabbage.net/sam/moonmath/tui/asset"
|
|
"code.humancabbage.net/sam/moonmath/tui/perf"
|
|
tea "github.com/charmbracelet/bubbletea"
|
|
"github.com/charmbracelet/lipgloss"
|
|
)
|
|
|
|
type Model struct {
|
|
assets []asset.Model
|
|
stats perf.Model
|
|
displayStats bool
|
|
}
|
|
|
|
func New(assets []coindesk.Asset, cfg config.Root, displayStats bool) (m Model) {
|
|
m.stats = perf.New()
|
|
m.displayStats = displayStats
|
|
// construct models for each asset, but remove dupes
|
|
seen := map[coindesk.Asset]struct{}{}
|
|
for _, a := range assets {
|
|
if _, ok := seen[a]; ok {
|
|
continue
|
|
}
|
|
assetCfg := cfg.ForAsset(a)
|
|
assetModel := asset.New(assetCfg)
|
|
m.assets = append(m.assets, assetModel)
|
|
seen[a] = struct{}{}
|
|
}
|
|
return
|
|
}
|
|
|
|
func (m Model) Init() tea.Cmd {
|
|
// initialize child models, collecting their commands,
|
|
// then return them all in a batch
|
|
var inits []tea.Cmd
|
|
for i := range m.assets {
|
|
cmd := m.assets[i].Init()
|
|
inits = append(inits, cmd)
|
|
}
|
|
return tea.Batch(inits...)
|
|
}
|
|
|
|
func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|
m.stats.AddUpdate()
|
|
switch msg := msg.(type) {
|
|
// handle keys for quitting
|
|
case tea.KeyMsg:
|
|
switch msg.String() {
|
|
case "ctrl+c", "q", "esc":
|
|
return m, tea.Quit
|
|
}
|
|
// forward asset messages to the appropriate model
|
|
case asset.Msg:
|
|
cmd := m.forward(msg.Asset, msg)
|
|
return m, cmd
|
|
// forward any other message to each child model.
|
|
// typically, this is for animation.
|
|
default:
|
|
var commands []tea.Cmd
|
|
for i := range m.assets {
|
|
var cmd tea.Cmd
|
|
m.assets[i], cmd = m.assets[i].Update(msg)
|
|
commands = append(commands, cmd)
|
|
}
|
|
return m, tea.Batch(commands...)
|
|
}
|
|
return m, nil
|
|
}
|
|
|
|
func (m Model) View() string {
|
|
m.stats.AddView()
|
|
var ss []string
|
|
for i := range m.assets {
|
|
s := m.assets[i].View()
|
|
ss = append(ss, s)
|
|
}
|
|
if m.displayStats {
|
|
ss = append(ss, m.stats.View())
|
|
}
|
|
r := lipgloss.JoinVertical(lipgloss.Center, ss...)
|
|
return r
|
|
}
|
|
|
|
func (m Model) forward(a coindesk.Asset, msg tea.Msg) (cmd tea.Cmd) {
|
|
// O(n) is fine when n is small
|
|
for i := range m.assets {
|
|
if !m.assets[i].Handles(a) {
|
|
continue
|
|
}
|
|
m.assets[i], cmd = m.assets[i].Update(msg)
|
|
return
|
|
}
|
|
panic(fmt.Errorf("rogue message: %v", msg))
|
|
}
|