166 lines
3.3 KiB
Go
166 lines
3.3 KiB
Go
package tui
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
"charm.land/bubbles/v2/textinput"
|
|
tea "charm.land/bubbletea/v2"
|
|
)
|
|
|
|
type State int
|
|
|
|
const (
|
|
StateForm State = iota
|
|
StateGenerating
|
|
StateDone
|
|
StateError
|
|
)
|
|
|
|
type genResultMsg struct {
|
|
result GenerateResult
|
|
}
|
|
|
|
type spinnerState struct {
|
|
frame int
|
|
}
|
|
|
|
func (s *spinnerState) View() string {
|
|
frames := []string{"⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"}
|
|
return frames[s.frame%len(frames)]
|
|
}
|
|
|
|
type Model struct {
|
|
state State
|
|
form FormModel
|
|
result GenerateResult
|
|
spinner spinnerState
|
|
width int
|
|
height int
|
|
}
|
|
|
|
func New() Model {
|
|
return Model{
|
|
state: StateForm,
|
|
form: NewForm(),
|
|
}
|
|
}
|
|
|
|
func (m Model) Init() tea.Cmd {
|
|
return textinput.Blink
|
|
}
|
|
|
|
func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|
switch msg := msg.(type) {
|
|
case tea.WindowSizeMsg:
|
|
m.width = msg.Width
|
|
m.height = msg.Height
|
|
m.form.SetSize(msg.Width, msg.Height)
|
|
return m, nil
|
|
|
|
case tea.KeyPressMsg:
|
|
if isQuit(msg) && m.state != StateGenerating {
|
|
return m, tea.Quit
|
|
}
|
|
|
|
switch m.state {
|
|
case StateForm:
|
|
if isSubmit(msg) && m.form.focusIndex == fieldGenerateBtn {
|
|
cfg, err := m.form.ToConfig()
|
|
if err != nil {
|
|
m.form.SetError(err.Error())
|
|
return m, nil
|
|
}
|
|
m.state = StateGenerating
|
|
return m, func() tea.Msg {
|
|
return genResultMsg{result: Generate(cfg)}
|
|
}
|
|
}
|
|
if isSubmit(msg) && m.form.focusIndex == fieldCancelBtn {
|
|
return m, tea.Quit
|
|
}
|
|
var cmd tea.Cmd
|
|
m.form, cmd = m.form.Update(msg)
|
|
return m, cmd
|
|
|
|
case StateDone, StateError:
|
|
return m, tea.Quit
|
|
}
|
|
|
|
case genResultMsg:
|
|
m.result = msg.result
|
|
if m.result.Error != nil {
|
|
m.state = StateError
|
|
} else {
|
|
m.state = StateDone
|
|
}
|
|
return m, nil
|
|
}
|
|
|
|
if m.state == StateForm {
|
|
var cmd tea.Cmd
|
|
m.form, cmd = m.form.Update(msg)
|
|
return m, cmd
|
|
}
|
|
|
|
return m, nil
|
|
}
|
|
|
|
func (m Model) View() tea.View {
|
|
var content string
|
|
|
|
switch m.state {
|
|
case StateForm:
|
|
content = m.form.View()
|
|
case StateGenerating:
|
|
content = m.renderGenerating()
|
|
case StateDone:
|
|
content = m.renderDone()
|
|
case StateError:
|
|
content = m.renderError()
|
|
}
|
|
|
|
v := tea.NewView(content)
|
|
v.AltScreen = true
|
|
return v
|
|
}
|
|
|
|
func (m Model) renderGenerating() string {
|
|
var b strings.Builder
|
|
b.WriteString(titleStyle.Render("dirmd"))
|
|
b.WriteString("\n\n")
|
|
b.WriteString(fmt.Sprintf(" %s Generating...\n", m.spinner.View()))
|
|
b.WriteString("\n")
|
|
b.WriteString(footerStyle.Render("Please wait."))
|
|
return appBorder.Render(b.String())
|
|
}
|
|
|
|
func (m Model) renderDone() string {
|
|
var b strings.Builder
|
|
b.WriteString(titleStyle.Render("dirmd"))
|
|
b.WriteString("\n\n")
|
|
b.WriteString(successStyle.Render("✓ Done"))
|
|
b.WriteString("\n\n")
|
|
for _, f := range m.result.Files {
|
|
b.WriteString(fmt.Sprintf(" %s\n", f))
|
|
}
|
|
if m.result.Uploaded {
|
|
b.WriteString(successStyle.Render("\n Uploaded to Proton Drive"))
|
|
}
|
|
b.WriteString("\n\n")
|
|
b.WriteString(footerStyle.Render("Press any key to exit."))
|
|
return appBorder.Render(b.String())
|
|
}
|
|
|
|
func (m Model) renderError() string {
|
|
var b strings.Builder
|
|
b.WriteString(titleStyle.Render("dirmd"))
|
|
b.WriteString("\n\n")
|
|
b.WriteString(errorStyle.Render("✗ Error"))
|
|
b.WriteString("\n\n")
|
|
b.WriteString(fmt.Sprintf(" %s\n", m.result.Error.Error()))
|
|
b.WriteString("\n")
|
|
b.WriteString(footerStyle.Render("Press any key to exit."))
|
|
return appBorder.Render(b.String())
|
|
}
|