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