package main import ( "github.com/charmbracelet/bubbles/list" "github.com/charmbracelet/bubbles/progress" "github.com/charmbracelet/bubbles/spinner" "github.com/charmbracelet/bubbles/textinput" tea "github.com/charmbracelet/bubbletea" ) type page int const ( pageVersionSelect page = iota pageMainMenu pageCodeInput pageExecuting ) type model struct { currentPage page exeDir string versionDir string versionName string width int height int versionList list.Model menuList list.Model codeInput textinput.Model spinner spinner.Model progress progress.Model actions []Action actionIdx int logLines []string execErr error execDone bool choosingMirror bool mirrorList list.Model pendingAction *Action backupDir string progressCh chan float64 } func newModel(exeDir string) model { s := spinner.New() s.Spinner = spinner.Dot ti := textinput.New() ti.Placeholder = "0000" ti.CharLimit = 4 ti.Width = 10 ti.Validate = func(s string) error { for _, r := range s { if r < '0' || r > '9' { return errNotDigit } } return nil } delegate := list.NewDefaultDelegate() vl := list.New(nil, delegate, 80, 20) vl.Title = "选择 Minecraft 版本" vl.SetFilteringEnabled(false) vl.SetShowStatusBar(false) ml := list.New(nil, delegate, 80, 20) ml.Title = "主菜单" ml.SetFilteringEnabled(false) ml.SetShowStatusBar(false) return model{ currentPage: pageVersionSelect, exeDir: exeDir, spinner: s, progress: progress.New(progress.WithDefaultGradient()), codeInput: ti, versionList: vl, menuList: ml, } } func (m model) Init() tea.Cmd { return scanVersions(m.exeDir) } func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch msg := msg.(type) { case tea.KeyMsg: if msg.String() == "ctrl+c" { return m, tea.Quit } case tea.WindowSizeMsg: m.width = msg.Width m.height = msg.Height h := msg.Height - 4 if h < 5 { h = 5 } m.versionList.SetSize(msg.Width, h) m.menuList.SetSize(msg.Width, h) m.progress.Width = msg.Width - 8 if m.progress.Width > 80 { m.progress.Width = 80 } } switch m.currentPage { case pageVersionSelect: return updateVersionSelect(m, msg) case pageMainMenu: return updateMainMenu(m, msg) case pageCodeInput: return updateCodeInput(m, msg) case pageExecuting: return updateExecuting(m, msg) } return m, nil } func (m model) View() string { switch m.currentPage { case pageVersionSelect: return viewVersionSelect(m) case pageMainMenu: return viewMainMenu(m) case pageCodeInput: return viewCodeInput(m) case pageExecuting: return viewExecuting(m) } return "" }