Sam Fredrickson
1c6d5e9917
All checks were successful
Build & Test / Main (push) Successful in 1m28s
Instead of pre-allocating the grid and using tricky indexing to fill in the cells, just fully regenerate it. But do it columnwise first, and then transpose it.
131 lines
2.6 KiB
Go
131 lines
2.6 KiB
Go
package tui
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
|
|
"code.humancabbage.net/sam/moonmath/config"
|
|
"code.humancabbage.net/sam/moonmath/moon"
|
|
"github.com/charmbracelet/bubbles/table"
|
|
tea "github.com/charmbracelet/bubbletea"
|
|
"github.com/charmbracelet/lipgloss"
|
|
)
|
|
|
|
var baseStyle = lipgloss.NewStyle().
|
|
BorderStyle(lipgloss.NormalBorder()).
|
|
BorderForeground(lipgloss.Color("240"))
|
|
|
|
type Model struct {
|
|
math moon.Math
|
|
|
|
prices table.Model
|
|
projections table.Model
|
|
}
|
|
|
|
func New(cfg config.Data) Model {
|
|
math := moon.NewMath(
|
|
cfg.Asset,
|
|
cfg.Goals,
|
|
config.GetBases(&cfg))
|
|
|
|
tableStyle := table.DefaultStyles()
|
|
tableStyle.Selected = lipgloss.NewStyle()
|
|
prices := table.New(
|
|
table.WithColumns([]table.Column{
|
|
{Title: "Asset", Width: 6},
|
|
{Title: "Price", Width: 9},
|
|
}),
|
|
table.WithHeight(1),
|
|
table.WithStyles(tableStyle),
|
|
)
|
|
|
|
projectionCols := []table.Column{
|
|
{Title: "Labels", Width: 8},
|
|
}
|
|
for i := range math.Columns {
|
|
projectionCols = append(projectionCols, table.Column{
|
|
Title: math.Columns[i].Base.Label(),
|
|
Width: 10,
|
|
})
|
|
}
|
|
projections := table.New(
|
|
table.WithColumns(projectionCols),
|
|
table.WithHeight(len(math.Labels)),
|
|
table.WithStyles(tableStyle),
|
|
)
|
|
|
|
return Model{
|
|
math: math,
|
|
prices: prices,
|
|
projections: projections,
|
|
}
|
|
}
|
|
|
|
func (m Model) Init() tea.Cmd {
|
|
return func() tea.Msg {
|
|
_ = m.math.Refresh(context.TODO())
|
|
return m.math
|
|
}
|
|
}
|
|
|
|
func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|
switch msg := msg.(type) {
|
|
case moon.Math:
|
|
m.math = msg
|
|
refillPrice(&m)
|
|
refillProjections(&m)
|
|
return m, tea.Tick(time.Second*30, func(t time.Time) tea.Msg {
|
|
_ = m.math.Refresh(context.TODO())
|
|
return m.math
|
|
})
|
|
case tea.KeyMsg:
|
|
switch msg.String() {
|
|
case "ctrl+c", "q", "esc":
|
|
return m, tea.Quit
|
|
}
|
|
}
|
|
return m, nil
|
|
}
|
|
|
|
func refillPrice(m *Model) {
|
|
rows := []table.Row{
|
|
[]string{string(m.math.Asset), fmt.Sprintf("$%0.2f", m.math.CurrentPrice)},
|
|
}
|
|
m.prices.SetRows(rows)
|
|
}
|
|
|
|
func refillProjections(m *Model) {
|
|
rows := []table.Row{m.math.Labels}
|
|
for i := range m.math.Columns {
|
|
rows = append(rows, m.math.Columns[i].Column())
|
|
}
|
|
rows = transpose(rows)
|
|
m.projections.SetRows(rows)
|
|
}
|
|
|
|
func transpose(slice []table.Row) []table.Row {
|
|
xl := len(slice[0])
|
|
yl := len(slice)
|
|
result := make([]table.Row, xl)
|
|
for i := range result {
|
|
result[i] = make(table.Row, yl)
|
|
}
|
|
for i := 0; i < xl; i++ {
|
|
for j := 0; j < yl; j++ {
|
|
result[i][j] = slice[j][i]
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
func (m Model) View() string {
|
|
var s string
|
|
s += lipgloss.JoinHorizontal(
|
|
lipgloss.Top,
|
|
baseStyle.Render(m.prices.View()),
|
|
baseStyle.Render(m.projections.View()),
|
|
)
|
|
return s + "\n"
|
|
}
|