Files
BrewMasterV2/main.go
2026-04-14 19:33:08 +02:00

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