Files
inp2025/stages/landing.go

242 lines
5.4 KiB
Go

package stages
import (
"fmt"
"net/http"
"strings"
"gitea.konchin.com/ytshih/inp2025/models"
"github.com/charmbracelet/bubbles/textinput"
tea "github.com/charmbracelet/bubbletea"
)
type landingOperationType int
const (
landingOperationChoose landingOperationType = iota
landingOperationLoginCred
landingOperationRegistCred
)
type focusTargetType int
const (
focusTargetUsername focusTargetType = iota
focusTargetPassword
)
type LandingModel struct {
*BaseModel
op landingOperationType
focus focusTargetType
username textinput.Model
password textinput.Model
info string
err error
}
func NewLandingModel(base *BaseModel) *LandingModel {
username := textinput.New()
username.Placeholder = "Username"
username.CharLimit = 32
username.Width = 32
username.Blur()
password := textinput.New()
password.Placeholder = "Password"
password.CharLimit = 32
password.Width = 32
password.Blur()
password.EchoMode = textinput.EchoPassword
password.EchoCharacter = '•'
return &LandingModel{
BaseModel: base,
op: landingOperationChoose,
username: username,
password: password,
}
}
func (m *LandingModel) reset() {
m.op = landingOperationChoose
m.username.Blur()
m.username.Reset()
m.password.Blur()
m.password.Reset()
}
type postLoginMsg struct{}
func (m *LandingModel) postLogin() tea.Cmd {
return func() tea.Msg {
resp, err := m.BaseModel.client.R().
SetBasicAuth(m.username.Value(), m.password.Value()).
Post("/auth/login")
if err == nil {
switch resp.StatusCode() {
case http.StatusOK:
m.BaseModel.client.SetBasicAuth(
m.username.Value(), m.password.Value())
m.info = "login success.\n"
m.err = nil
case http.StatusUnauthorized:
m.err = fmt.Errorf("user not exist or password incorrect, %s",
string(resp.Body()))
default:
m.err = fmt.Errorf("unknown server error, %s",
string(resp.Body()))
}
} else {
m.err = fmt.Errorf("failed to post login, %w", err)
}
return postLoginMsg{}
}
}
type postRegisterMsg struct{}
func (m *LandingModel) postRegister() tea.Cmd {
return func() tea.Msg {
resp, err := m.BaseModel.client.R().
SetBody(models.User{
Username: m.username.Value(),
Password: m.password.Value(),
}).
Post("/auth/register")
if err == nil {
switch resp.StatusCode() {
case http.StatusOK:
m.info = "register success.\n"
m.err = nil
case http.StatusBadRequest:
m.err = fmt.Errorf("username already exist, %s",
string(resp.Body()))
default:
m.err = fmt.Errorf("unknown server error, %s",
string(resp.Body()))
}
} else {
m.err = fmt.Errorf("failed to post register, %s",
string(resp.Body()))
}
return postRegisterMsg{}
}
}
func (m *LandingModel) Init() tea.Cmd {
return tea.ClearScreen
}
func (m *LandingModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
var cmds []tea.Cmd
switch msg := msg.(type) {
case tea.KeyMsg:
switch msg.String() {
case "ctrl+c":
return m, tea.Quit
case "L", "l":
if m.op == landingOperationChoose {
m.op = landingOperationLoginCred
m.focus = focusTargetUsername
cmds = append(cmds, m.username.Focus())
return m, tea.Batch(cmds...)
}
case "R", "r":
if m.op == landingOperationChoose {
m.op = landingOperationRegistCred
m.focus = focusTargetUsername
cmds = append(cmds, m.username.Focus())
return m, tea.Batch(cmds...)
}
case "shift+tab", "up":
if m.op == landingOperationLoginCred ||
m.op == landingOperationRegistCred {
switch m.focus {
case focusTargetUsername:
m.username.Blur()
m.focus = focusTargetPassword
cmds = append(cmds, m.password.Focus())
case focusTargetPassword:
m.password.Blur()
m.focus = focusTargetUsername
cmds = append(cmds, m.username.Focus())
}
}
case "tab", "down", "enter":
if m.op == landingOperationLoginCred ||
m.op == landingOperationRegistCred {
switch m.focus {
case focusTargetUsername:
m.username.Blur()
m.focus = focusTargetPassword
cmds = append(cmds, m.password.Focus())
case focusTargetPassword:
if msg.String() == "enter" {
switch m.op {
case landingOperationLoginCred:
cmds = append(cmds, m.postLogin())
case landingOperationRegistCred:
cmds = append(cmds, m.postRegister())
}
} else {
m.password.Blur()
m.focus = focusTargetUsername
cmds = append(cmds, m.username.Focus())
}
}
}
}
case postLoginMsg:
if m.err == nil {
*m.queue = append(*m.queue,
tea.NewProgram(NewLobbyModel(m.BaseModel)))
return m, tea.Quit
} else {
m.reset()
}
case postRegisterMsg:
m.reset()
}
var cmd tea.Cmd
m.username, cmd = m.username.Update(msg)
cmds = append(cmds, cmd)
m.password, cmd = m.password.Update(msg)
cmds = append(cmds, cmd)
return m, tea.Batch(cmds...)
}
func (m *LandingModel) View() string {
var b strings.Builder
switch m.op {
case landingOperationChoose:
fmt.Fprintf(&b, "Choose Operation\n(L)ogin / (R)egister\n")
case landingOperationLoginCred:
fmt.Fprintf(&b, "Login: \n")
b.WriteString(m.username.View() + "\n")
b.WriteString(m.password.View() + "\n")
case landingOperationRegistCred:
fmt.Fprintf(&b, "Register: \n")
b.WriteString(m.username.View() + "\n")
b.WriteString(m.password.View() + "\n")
}
if m.info != "" {
b.WriteString(m.info + "\n")
}
if m.err != nil {
b.WriteString("----------\n")
b.WriteString(m.err.Error() + "\n")
}
return b.String()
}