207 lines
5.5 KiB
Go
207 lines
5.5 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
|
|
"github.com/gdamore/tcell/v2"
|
|
"github.com/rivo/tview"
|
|
)
|
|
|
|
// --- Data Structures ---
|
|
|
|
type Brew struct {
|
|
Name string
|
|
Hops string
|
|
Progress int
|
|
Notes string
|
|
}
|
|
|
|
type InventoryItem struct {
|
|
Name string
|
|
Type string
|
|
Amount float64
|
|
Unit string
|
|
}
|
|
|
|
func main() {
|
|
app := tview.NewApplication()
|
|
pages := tview.NewPages()
|
|
|
|
// Colors - Using GetColor for maximum compatibility
|
|
cyan := tcell.GetColor("cyan")
|
|
yellow := tcell.GetColor("yellow")
|
|
green := tcell.GetColor("green")
|
|
gray := tcell.GetColor("gray")
|
|
|
|
// --- Mock Data ---
|
|
|
|
brews := []Brew{
|
|
{"Midnight Stout", "Fuggles, Goldings", 75, "Primary fermentation looking good. Smells like coffee."},
|
|
{"Neon IPA", "Citra, Mosaic, Galaxy", 40, "Dry hopping starts in 2 days."},
|
|
{"Summer Wheat", "Saaz, Hallertau", 95, "Ready for bottling/kegging."},
|
|
}
|
|
|
|
inventory := []InventoryItem{
|
|
{"Citra", "Hops", 500, "g"},
|
|
{"Pilsner Malt", "Grain", 25, "kg"},
|
|
{"US-05 SafAle", "Yeast", 4, "packets"},
|
|
}
|
|
|
|
// --- Shared UI Components ---
|
|
|
|
logo := tview.NewTextView().
|
|
SetTextAlign(tview.AlignRight).
|
|
SetDynamicColors(true).
|
|
SetText(`[yellow]
|
|
[##] ___ ___ ___ _ _
|
|
/____\ | _ )| _ \| __| | | |
|
|
| U | | _ \| /| _|| |/\| |
|
|
|______| |___/|_|_\|___||__/\__|
|
|
|'=__='|
|
|
| | __ __ _ ___ _____ ___ ___
|
|
|______| | \/ | /_\ / __|_ _| __| _ \
|
|
| |\/| |/ _ \\__ \ | | | _|| /
|
|
|_| |_/_/ \_\___/ |_| |___|_|_\
|
|
`)
|
|
|
|
viewTitle := tview.NewTextView().SetTextColor(cyan)
|
|
|
|
header := tview.NewFlex().
|
|
AddItem(viewTitle, 0, 1, false).
|
|
AddItem(logo, 0, 2, false)
|
|
|
|
commandBar := tview.NewInputField().
|
|
SetLabelColor(yellow).
|
|
SetFieldBackgroundColor(tcell.ColorBlack).
|
|
SetFieldTextColor(tcell.ColorWhite)
|
|
|
|
footer := tview.NewTextView().
|
|
SetDynamicColors(true).
|
|
SetText(" [black:gray] <:> Command [white:black] [black:gray] <Enter> Describe [white:black] [black:gray] <Ctrl-C> Exit [white:black] ")
|
|
|
|
// --- View Logic Helpers ---
|
|
|
|
// Detail View (The "Describe" screen)
|
|
detailsView := tview.NewTextView().
|
|
SetDynamicColors(true).
|
|
SetRegions(true).
|
|
SetWrap(true)
|
|
|
|
showDetails := func(content string) {
|
|
detailsView.SetText(content)
|
|
pages.SwitchToPage("details")
|
|
}
|
|
|
|
// --- Page 1: Active Brews ---
|
|
brewsTable := tview.NewTable().SetSelectable(true, false)
|
|
for r, b := range brews {
|
|
brewsTable.SetCell(r, 0, tview.NewTableCell(b.Name).SetTextColor(tcell.ColorWhite))
|
|
brewsTable.SetCell(r, 1, tview.NewTableCell(b.Hops).SetTextColor(gray))
|
|
brewsTable.SetCell(r, 2, tview.NewTableCell(fmt.Sprintf("%d%%", b.Progress)).SetTextColor(green))
|
|
}
|
|
brewsTable.SetSelectedFunc(func(row, column int) {
|
|
b := brews[row]
|
|
detailText := fmt.Sprintf("\n [yellow]NAME:[-] %s\n [yellow]HOPS:[-] %s\n [yellow]PROGRESS:[-] %d%%\n\n [yellow]NOTES:[-]\n %s\n\n [gray]Press <ESC> to return", b.Name, b.Hops, b.Progress, b.Notes)
|
|
showDetails(detailText)
|
|
})
|
|
|
|
// --- Page 2: Inventory ---
|
|
invTable := tview.NewTable().SetSelectable(true, false)
|
|
for r, item := range inventory {
|
|
invTable.SetCell(r, 0, tview.NewTableCell(item.Name))
|
|
invTable.SetCell(r, 1, tview.NewTableCell(fmt.Sprintf("%.1f %s", item.Amount, item.Unit)).SetTextColor(green))
|
|
}
|
|
invTable.SetSelectedFunc(func(row, column int) {
|
|
item := inventory[row]
|
|
detailText := fmt.Sprintf("\n [yellow]ITEM:[-] %s\n [yellow]TYPE:[-] %s\n [yellow]STOCK:[-] %.1f %s\n\n [gray]Inventory check passed. Ready for next brew.\n\n [gray]Press <ESC> to return", item.Name, item.Type, item.Amount, item.Unit)
|
|
showDetails(detailText)
|
|
})
|
|
|
|
pages.AddPage("brews", brewsTable, true, true)
|
|
pages.AddPage("inventory", invTable, true, false)
|
|
pages.AddPage("details", detailsView, true, false)
|
|
|
|
// --- Layout Setup ---
|
|
mainLayout := tview.NewFlex().SetDirection(tview.FlexRow).
|
|
AddItem(header, 9, 0, false).
|
|
AddItem(pages, 0, 1, true).
|
|
AddItem(footer, 1, 0, false)
|
|
|
|
root := tview.NewFlex().SetDirection(tview.FlexRow).
|
|
AddItem(mainLayout, 0, 1, true)
|
|
|
|
// --- Global Navigation ---
|
|
|
|
showCommandBar := func(label string) {
|
|
if root.GetItemCount() == 1 {
|
|
commandBar.SetLabel(label)
|
|
root.AddItem(commandBar, 1, 0, false)
|
|
app.SetFocus(commandBar)
|
|
}
|
|
}
|
|
|
|
hideCommandBar := func() {
|
|
if root.GetItemCount() > 1 {
|
|
root.RemoveItem(commandBar)
|
|
commandBar.SetText("")
|
|
_, activePage := pages.GetFrontPage()
|
|
app.SetFocus(activePage)
|
|
}
|
|
}
|
|
|
|
switchTo := func(pageID string, title string) {
|
|
viewTitle.SetText(" BrewMaster v0.1.0 - " + title)
|
|
pages.SwitchToPage(pageID)
|
|
_, active := pages.GetFrontPage()
|
|
app.SetFocus(active)
|
|
}
|
|
switchTo("brews", "Active Brews")
|
|
|
|
// --- Input Handling ---
|
|
|
|
commandBar.SetDoneFunc(func(key tcell.Key) {
|
|
if key == tcell.KeyEscape {
|
|
hideCommandBar()
|
|
return
|
|
}
|
|
if key == tcell.KeyEnter {
|
|
cmd := strings.ToLower(strings.TrimSpace(commandBar.GetText()))
|
|
switch cmd {
|
|
case "q", "quit":
|
|
app.Stop()
|
|
case "i", "inv":
|
|
switchTo("inventory", "Inventory")
|
|
case "b", "brew":
|
|
switchTo("brews", "Active Brews")
|
|
}
|
|
hideCommandBar()
|
|
}
|
|
})
|
|
|
|
app.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
|
|
if app.GetFocus() != commandBar {
|
|
// ESC to go back from Details to whatever was previous
|
|
if event.Key() == tcell.KeyEscape {
|
|
currentPage, _ := pages.GetFrontPage()
|
|
if currentPage == "details" {
|
|
// Default back to brews for now
|
|
switchTo("brews", "Active Brews")
|
|
}
|
|
}
|
|
switch event.Rune() {
|
|
case ':':
|
|
showCommandBar(": ")
|
|
return nil
|
|
}
|
|
}
|
|
return event
|
|
})
|
|
|
|
if err := app.SetRoot(root, true).Run(); err != nil {
|
|
fmt.Printf("Error running app: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
}
|