moonmath/tui/tui.go

101 lines
2.2 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"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
)
type Model struct {
assets []asset.Model
}
func New(assets []coindesk.Asset, cfg config.All) (p *tea.Program) {
model := newModel(assets, cfg)
p = tea.NewProgram(
model,
tea.WithAltScreen(),
tea.WithFPS(30),
)
return
}
func newModel(assets []coindesk.Asset, cfg config.All) (m Model) {
// construct models for each asset, but don't filter out dupes
seen := map[coindesk.Asset]struct{}{}
for _, a := range assets {
_, ok := seen[a]
if ok {
continue
}
assetCfg := cfg.GetData(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) {
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 {
var ss []string
for i := range m.assets {
s := m.assets[i].View()
ss = append(ss, s)
}
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))
}