Move TUI code into separate package.
Build & Test / Main (push) Successful in 51s Details

This commit is contained in:
Sam Fredrickson 2024-03-19 18:38:46 -07:00
parent 15a7052389
commit bf50ba4539
2 changed files with 140 additions and 132 deletions

View File

@ -1,145 +1,15 @@
package main
import (
"context"
"fmt"
"os"
"time"
"code.humancabbage.net/sam/moonmath/moon"
"github.com/charmbracelet/bubbles/table"
"code.humancabbage.net/sam/moonmath/tui"
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 (m model) Init() tea.Cmd {
return func() tea.Msg {
_ = m.math.Refresh(context.TODO())
return m.math
}
}
func initialModel() model {
math := moon.NewMath(nil, nil)
tableStyle := table.DefaultStyles()
tableStyle.Selected = lipgloss.NewStyle()
prices := table.New(
table.WithColumns([]table.Column{
{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.Name(),
Width: 10,
})
}
projectionRows := make([]table.Row, len(math.Goals)+2)
for i := range projectionRows {
projectionRows[i] = make(table.Row, len(projectionCols))
}
projectionRows[0][0] = "Starting"
projectionRows[1][0] = "CDPR"
for i := range math.Goals {
projectionRows[i+2][0] = fmt.Sprintf("$%.0f", math.Goals[i])
}
projections := table.New(
table.WithColumns(projectionCols),
table.WithRows(projectionRows),
table.WithHeight(len(math.Goals)+2),
table.WithStyles(tableStyle),
)
return model{
math: math,
prices: prices,
projections: projections,
}
}
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{fmt.Sprintf("$%0.2f", m.math.CurrentPrice)},
}
m.prices.SetRows(rows)
}
func refillProjections(m *model) {
rows := m.projections.Rows()
for col := range m.math.Columns {
_ = col
never := false
if m.math.Columns[col].CDPR <= 1 {
never = true
}
rows[0][col+1] = fmt.Sprintf("$%.2f", m.math.Columns[col].StartingPrice)
rows[1][col+1] = fmt.Sprintf("%.2f%%", (m.math.Columns[col].CDPR-1)*100)
for row := 0; row < len(m.math.Goals); row++ {
var cell string
if never {
cell = "NEVER!!!!!"
} else {
cell = m.math.Columns[col].
Projections.Dates[row].
Format("2006-01-02")
}
rows[row+2][col+1] = cell
}
}
m.projections.SetRows(rows)
}
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"
}
func main() {
p := tea.NewProgram(initialModel())
p := tea.NewProgram(tui.New())
if _, err := p.Run(); err != nil {
fmt.Printf("program error: %v\n", err)
os.Exit(1)

138
tui/tui.go Normal file
View File

@ -0,0 +1,138 @@
package tui
import (
"context"
"fmt"
"time"
"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() Model {
math := moon.NewMath(nil, nil)
tableStyle := table.DefaultStyles()
tableStyle.Selected = lipgloss.NewStyle()
prices := table.New(
table.WithColumns([]table.Column{
{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.Name(),
Width: 10,
})
}
projectionRows := make([]table.Row, len(math.Goals)+2)
for i := range projectionRows {
projectionRows[i] = make(table.Row, len(projectionCols))
}
projectionRows[0][0] = "Starting"
projectionRows[1][0] = "CDPR"
for i := range math.Goals {
projectionRows[i+2][0] = fmt.Sprintf("$%.0f", math.Goals[i])
}
projections := table.New(
table.WithColumns(projectionCols),
table.WithRows(projectionRows),
table.WithHeight(len(math.Goals)+2),
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{fmt.Sprintf("$%0.2f", m.math.CurrentPrice)},
}
m.prices.SetRows(rows)
}
func refillProjections(m *Model) {
rows := m.projections.Rows()
for col := range m.math.Columns {
_ = col
never := false
if m.math.Columns[col].CDPR <= 1 {
never = true
}
rows[0][col+1] = fmt.Sprintf("$%.2f", m.math.Columns[col].StartingPrice)
rows[1][col+1] = fmt.Sprintf("%.2f%%", (m.math.Columns[col].CDPR-1)*100)
for row := 0; row < len(m.math.Goals); row++ {
var cell string
if never {
cell = "NEVER!!!!!"
} else {
cell = m.math.Columns[col].
Projections.Dates[row].
Format("2006-01-02")
}
rows[row+2][col+1] = cell
}
}
m.projections.SetRows(rows)
}
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"
}