109 lines
2.4 KiB
Go
109 lines
2.4 KiB
Go
package tui
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
tea "github.com/charmbracelet/bubbletea"
|
|
"github.com/leonardotrapani/hyprvoice/internal/config"
|
|
)
|
|
|
|
type wizardModel struct {
|
|
state *wizardState
|
|
screen screen
|
|
width int
|
|
height int
|
|
}
|
|
|
|
func newWizardModel(state *wizardState, start screen) wizardModel {
|
|
return wizardModel{state: state, screen: start}
|
|
}
|
|
|
|
func (m wizardModel) Init() tea.Cmd {
|
|
if m.screen == nil {
|
|
return tea.Quit
|
|
}
|
|
return m.screen.Init()
|
|
}
|
|
|
|
func (m wizardModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|
switch msg := msg.(type) {
|
|
case tea.KeyMsg:
|
|
if msg.String() == "ctrl+c" {
|
|
m.state.cancelled = true
|
|
m.state.result = &ConfigureResult{Cancelled: true}
|
|
return m, tea.Quit
|
|
}
|
|
case tea.WindowSizeMsg:
|
|
m.width = msg.Width
|
|
m.height = msg.Height
|
|
}
|
|
|
|
if m.screen == nil {
|
|
return m, tea.Quit
|
|
}
|
|
|
|
next, cmd := m.screen.Update(msg)
|
|
if next == nil {
|
|
if m.state.result == nil {
|
|
m.state.result = &ConfigureResult{Config: m.state.cfg, Cancelled: m.state.cancelled}
|
|
}
|
|
return m, tea.Quit
|
|
}
|
|
if next != m.screen {
|
|
var sizeCmd tea.Cmd
|
|
if m.width > 0 && m.height > 0 {
|
|
updated, scmd := next.Update(tea.WindowSizeMsg{Width: m.width, Height: m.height})
|
|
if updated == nil {
|
|
if m.state.result == nil {
|
|
m.state.result = &ConfigureResult{Config: m.state.cfg, Cancelled: m.state.cancelled}
|
|
}
|
|
return m, tea.Quit
|
|
}
|
|
next = updated
|
|
sizeCmd = scmd
|
|
}
|
|
m.screen = next
|
|
initCmd := m.screen.Init()
|
|
return m, tea.Batch(cmd, sizeCmd, initCmd)
|
|
}
|
|
m.screen = next
|
|
return m, cmd
|
|
}
|
|
|
|
func (m wizardModel) View() string {
|
|
if m.screen == nil {
|
|
return ""
|
|
}
|
|
return m.screen.View()
|
|
}
|
|
|
|
// Run starts the TUI configuration wizard.
|
|
// If onboarding is true, starts the guided onboarding flow.
|
|
func Run(existingConfig *config.Config, onboarding bool) (*ConfigureResult, error) {
|
|
if existingConfig == nil {
|
|
return nil, fmt.Errorf("config is required")
|
|
}
|
|
|
|
state := &wizardState{cfg: existingConfig, onboarding: onboarding}
|
|
|
|
var start screen
|
|
if onboarding {
|
|
start = newWelcomeScreen(state)
|
|
} else {
|
|
start = newMenuScreen(state)
|
|
}
|
|
|
|
model := newWizardModel(state, start)
|
|
if _, err := tea.NewProgram(model, tea.WithAltScreen()).Run(); err != nil {
|
|
return &ConfigureResult{Cancelled: true}, err
|
|
}
|
|
|
|
if state.err != nil {
|
|
return &ConfigureResult{Cancelled: true}, state.err
|
|
}
|
|
if state.result == nil {
|
|
state.result = &ConfigureResult{Config: existingConfig, Cancelled: state.cancelled}
|
|
}
|
|
return state.result, nil
|
|
}
|