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)) }