gostations/internal/ui/ui.go
Greg Gauthier b378fec3b2
Some checks failed
gobuild / build (push) Failing after 4s
refactor: reorganize into internal packages, fix critical panics and error handling
Move browser, config, player, and radio logic into internal/{config,radio,player,ui,version}.
Add cached API host resolution, context-aware HTTP client, and nil/length guards to eliminate
RandomIP, nslookup, reverseLookup, and GetStations panics. Replace subExecute with clean
legacyPlayer using Run-only execution. Fix inverted -short test guards, unformatted config
error messages, and "Erorr" typo. Remove obsolete vendor/GOPATH logic from build scripts.
Update callers in stations.go and radiomenu.go to new paths; retain shims for transition.
2026-06-05 21:10:54 +01:00

70 lines
1.6 KiB
Go

package ui
import (
"fmt"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
"github.com/gmgauthier/gostations/internal/radio"
)
// App is the root Bubble Tea model for the two-stage UI (selection then playback).
type App struct {
stations []radio.Station
// current view state etc.
width, height int
quitting bool
}
func NewApp(initial []radio.Station) *App {
return &App{stations: initial}
}
func (a *App) Init() tea.Cmd {
return nil
}
func (a *App) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.KeyMsg:
switch msg.String() {
case "q", "ctrl+c":
a.quitting = true
return a, tea.Quit
case "enter":
// TODO Phase2: switch to playback view, start player etc.
return a, nil
}
case tea.WindowSizeMsg:
a.width = msg.Width
a.height = msg.Height
}
return a, nil
}
var (
titleStyle = lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color("63"))
)
func (a *App) View() string {
if a.quitting {
return "Thanks for using GoStations!\n"
}
s := titleStyle.Render("GoStations - Radio Browser") + "\n\n"
s += "Selection view (placeholder). Press enter for playback stub, q to quit.\n"
if len(a.stations) > 0 {
s += fmt.Sprintf("%d stations available (favorites would be pinned here).\n", len(a.stations))
s += "First: " + a.stations[0].Name + "\n"
}
s += "\n(Full two-stage TUI with bubbles/list + playback controls coming in Phase 2.)\n"
return s
}
// Run starts the TUI program (alt screen).
func Run(initial []radio.Station) error {
p := tea.NewProgram(NewApp(initial), tea.WithAltScreen())
_, err := p.Run()
return err
}