From 8a8c4e9abc1006da92969e0234bb2d42f587c149 Mon Sep 17 00:00:00 2001 From: Kyren223 Date: Wed, 5 Feb 2025 16:54:09 +0200 Subject: Refactored all instances of the word "peer" and it's variants to "signal" and it's variants as this is the new terminology for "user signals" which are direct messages between 2 users --- internal/client/ui/core/signaladd/signaladd.go | 190 +++++++++++++++++++++++++ 1 file changed, 190 insertions(+) create mode 100644 internal/client/ui/core/signaladd/signaladd.go (limited to 'internal/client/ui/core/signaladd') diff --git a/internal/client/ui/core/signaladd/signaladd.go b/internal/client/ui/core/signaladd/signaladd.go new file mode 100644 index 0000000..781b16a --- /dev/null +++ b/internal/client/ui/core/signaladd/signaladd.go @@ -0,0 +1,190 @@ +package signaladd + +import ( + "errors" + "log" + "slices" + "strconv" + "strings" + + tea "github.com/charmbracelet/bubbletea" + "github.com/charmbracelet/lipgloss" + "github.com/kyren223/eko/internal/client/gateway" + "github.com/kyren223/eko/internal/client/ui/colors" + "github.com/kyren223/eko/internal/client/ui/core/state" + "github.com/kyren223/eko/internal/client/ui/field" + "github.com/kyren223/eko/internal/client/ui/layouts/flex" + "github.com/kyren223/eko/internal/packet" + "github.com/kyren223/eko/pkg/assert" + "github.com/kyren223/eko/pkg/snowflake" +) + +var ( + width = 48 + + style = lipgloss.NewStyle(). + Border(lipgloss.ThickBorder()). + Padding(1, 4). + Align(lipgloss.Center, lipgloss.Center) + + headerStyle = lipgloss.NewStyle().Foreground(colors.Turquoise) + + fieldBlurredStyle = lipgloss.NewStyle(). + PaddingLeft(1). + Border(lipgloss.RoundedBorder()). + BorderForeground(colors.DarkCyan) + fieldFocusedStyle = fieldBlurredStyle. + BorderForeground(colors.Focus). + Border(lipgloss.ThickBorder()) + + blurredCreate = lipgloss.NewStyle(). + Background(colors.Gray).Padding(0, 1).Render("Add user signal") + focusedCreate = lipgloss.NewStyle(). + Background(colors.Blue).Padding(0, 1).Render("Add user signal") +) + +const ( + MaxIconLength = 2 + MaxHexDigits = 6 +) + +const ( + NameField = iota + CreateField + FieldCount +) + +type Model struct { + name field.Model + create string + + selected int + nameWidth int +} + +func New() Model { + name := field.New(width) + name.Header = "User ID" + name.HeaderStyle = headerStyle + name.FocusedStyle = fieldFocusedStyle + name.BlurredStyle = fieldBlurredStyle + name.ErrorStyle = lipgloss.NewStyle().Foreground(colors.Error) + name.Input.CharLimit = width + name.Focus() + name.Input.Validate = func(s string) error { + if strings.TrimSpace(s) == "" { + return errors.New("cannot be empty") + } + if _, err := strconv.ParseInt(s, 10, 64); err != nil { + return errors.New("invalid user id") + } + + return nil + } + + nameWidth := lipgloss.Width(name.View()) + + return Model{ + name: name, + create: blurredCreate, + nameWidth: nameWidth, + } +} + +func (m Model) Init() tea.Cmd { + return nil +} + +func (m Model) View() string { + name := m.name.View() + create := lipgloss.NewStyle(). + Width(m.nameWidth).Align(lipgloss.Center). + Render(m.create) + + content := flex.NewVertical(name, create).WithGap(1).View() + return style.Render(content) +} + +func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) { + switch msg := msg.(type) { + case tea.KeyMsg: + key := msg.Type + switch key { + case tea.KeyTab: + return m, m.cycle(1) + case tea.KeyShiftTab: + return m, m.cycle(-1) + + default: + var cmd tea.Cmd + switch m.selected { + case NameField: + m.name, cmd = m.name.Update(msg) + } + return m, cmd + } + } + + return m, nil +} + +func (m *Model) cycle(step int) tea.Cmd { + m.selected += step + if m.selected < 0 { + m.selected = FieldCount - 1 + } else { + m.selected %= FieldCount + } + return m.updateFocus() +} + +func (m *Model) updateFocus() tea.Cmd { + m.name.Blur() + m.create = blurredCreate + switch m.selected { + case NameField: + return m.name.Focus() + case CreateField: + m.create = focusedCreate + return nil + default: + assert.Never("missing switch statement field in update focus", "selected", m.selected) + return nil + } +} + +func (m *Model) Select() (tea.Cmd, int) { + if m.selected != CreateField { + return nil, -1 + } + + m.name.Input.Err = m.name.Input.Validate(m.name.Input.Value()) + if m.name.Input.Err != nil { + return nil, -1 + } + name := m.name.Input.Value() + num, err := strconv.ParseInt(name, 10, 64) + id := snowflake.ID(num) + assert.NoError(err, "input is already validated to be valid") + + index := -1 + for i, signal := range state.Data.Signals { + if signal == id { + index = i + break + } + } + + if index != -1 { + return nil, index + } + + state.Data.Signals = slices.Insert(state.Data.Signals, 0, id) + log.Println("Signals:", state.Data.Signals) + + data := state.JsonUserData() + return gateway.Send(&packet.SetUserData{ + Data: &data, + User: nil, + }), 0 +} -- cgit v1.3.1