package ui import ( "fmt" "github.com/charmbracelet/bubbles/textinput" tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/lipgloss" ) type inputScreenState int const ( urlInput inputScreenState = iota usernameInput tokenInput connNameInput ) type InputScreen struct { urlField textinput.Model usernameField textinput.Model tokenField textinput.Model connNameField textinput.Model focusedField inputScreenState err error url string username string token string connName string done bool } func NewInputScreen() *InputScreen { urlField := textinput.New() urlField.Placeholder = "https://gitea.example.com" urlField.Focus() usernameField := textinput.New() usernameField.Placeholder = "your_username" tokenField := textinput.New() tokenField.Placeholder = "your_access_token" tokenField.EchoMode = textinput.EchoPassword connNameField := textinput.New() connNameField.Placeholder = "(optional) Connection name" return &InputScreen{ urlField: urlField, usernameField: usernameField, tokenField: tokenField, connNameField: connNameField, focusedField: urlInput, } } func (is *InputScreen) Init() tea.Cmd { return textinput.Blink } func (is *InputScreen) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch msg := msg.(type) { case tea.KeyMsg: switch msg.Type { case tea.KeyCtrlC: return is, tea.Quit case tea.KeyEnter: switch is.focusedField { case urlInput: is.url = is.urlField.Value() is.focusedField = usernameInput is.usernameField.Focus() return is, nil case usernameInput: is.username = is.usernameField.Value() is.focusedField = tokenInput is.tokenField.Focus() return is, nil case tokenInput: is.token = is.tokenField.Value() is.focusedField = connNameInput is.connNameField.Focus() return is, nil case connNameInput: is.connName = is.connNameField.Value() is.done = true return is, nil } case tea.KeyTab, tea.KeyShiftTab: switch is.focusedField { case urlInput: is.url = is.urlField.Value() case usernameInput: is.username = is.usernameField.Value() case tokenInput: is.token = is.tokenField.Value() case connNameInput: is.connName = is.connNameField.Value() } if msg.Type == tea.KeyTab { is.focusedField = (is.focusedField + 1) % 4 } else { is.focusedField = (is.focusedField - 1 + 4) % 4 } is.urlField.Blur() is.usernameField.Blur() is.tokenField.Blur() is.connNameField.Blur() switch is.focusedField { case urlInput: is.urlField.Focus() case usernameInput: is.usernameField.Focus() case tokenInput: is.tokenField.Focus() case connNameInput: is.connNameField.Focus() } return is, nil } case errMsg: is.err = msg return is, nil } var cmd tea.Cmd switch is.focusedField { case urlInput: is.urlField, cmd = is.urlField.Update(msg) case usernameInput: is.usernameField, cmd = is.usernameField.Update(msg) case tokenInput: is.tokenField, cmd = is.tokenField.Update(msg) case connNameInput: is.connNameField, cmd = is.connNameField.Update(msg) } return is, cmd } func (is *InputScreen) View() string { var s string s += lipgloss.NewStyle(). Foreground(lipgloss.Color("212")). Bold(true). Render("Gitea Wrapped") + "\n\n" s += "Enter your Gitea credentials:\n\n" s += "Gitea URL\n" s += is.urlField.View() + "\n\n" s += "Username\n" s += is.usernameField.View() + "\n\n" s += "Access Token\n" s += is.tokenField.View() + "\n\n" s += "Connection Name (optional - to save for later)\n" s += is.connNameField.View() + "\n\n" if is.err != nil { s += lipgloss.NewStyle(). Foreground(lipgloss.Color("1")). Render(fmt.Sprintf("Error: %v", is.err)) + "\n" } s += lipgloss.NewStyle(). Foreground(lipgloss.Color("8")). Render("(Tab to navigate, Enter to continue, Ctrl+C to quit)") + "\n" return s } func (is *InputScreen) IsDone() bool { return is.done } func (is *InputScreen) GetCredentials() (url, username, token, connName string) { return is.url, is.username, is.token, is.connName } type errMsg error