diff options
| author | Kyren223 <Kyren223@proton.me> | 2025-01-26 18:17:50 +0200 |
|---|---|---|
| committer | Kyren223 <Kyren223@proton.me> | 2025-01-26 18:17:50 +0200 |
| commit | 1d76c3f8316fe09c0ade190d94adcab02e28a1e9 (patch) | |
| tree | abbc8477baa1d49b8a801cd507f7a7dedb9e48ac /internal | |
| parent | bcd13d0afba8fae352b87556b31b1cf5d1a6e7c3 (diff) | |
Added adding/removing user signals (direct messages)
Diffstat (limited to 'internal')
| -rw-r--r-- | internal/client/ui/core/core.go | 35 | ||||
| -rw-r--r-- | internal/client/ui/core/helppopup.go | 4 | ||||
| -rw-r--r-- | internal/client/ui/core/networkjoin/networkjoin.go | 2 | ||||
| -rw-r--r-- | internal/client/ui/core/peeradd/peeradd.go | 190 | ||||
| -rw-r--r-- | internal/client/ui/core/peerlist/peerlist.go | 47 |
5 files changed, 252 insertions, 26 deletions
diff --git a/internal/client/ui/core/core.go b/internal/client/ui/core/core.go index b5cd8ba..6e53fbe 100644 --- a/internal/client/ui/core/core.go +++ b/internal/client/ui/core/core.go @@ -25,6 +25,7 @@ import ( "github.com/kyren223/eko/internal/client/ui/core/networkjoin" "github.com/kyren223/eko/internal/client/ui/core/networklist" "github.com/kyren223/eko/internal/client/ui/core/networkupdate" + "github.com/kyren223/eko/internal/client/ui/core/peeradd" "github.com/kyren223/eko/internal/client/ui/core/peerlist" "github.com/kyren223/eko/internal/client/ui/core/state" "github.com/kyren223/eko/internal/client/ui/core/usersettings" @@ -76,6 +77,7 @@ type Model struct { frequencyUpdatePopup *frequencyupdate.Model banReasonPopup *banreason.Model banViewPopup *banview.Model + peerAddPopup *peeradd.Model networkList networklist.Model peerList peerlist.Model frequencyList frequencylist.Model @@ -101,6 +103,7 @@ func New(privKey ed25519.PrivateKey, name string) Model { frequencyUpdatePopup: nil, banReasonPopup: nil, banViewPopup: nil, + peerAddPopup: nil, networkList: networklist.New(), peerList: peerlist.New(), frequencyList: frequencylist.New(), @@ -158,6 +161,8 @@ func (m Model) View() string { popup = m.banReasonPopup.View() } else if m.banViewPopup != nil { popup = m.banViewPopup.View() + } else if m.peerAddPopup != nil { + popup = m.peerAddPopup.View() } if popup != "" { @@ -355,10 +360,17 @@ func (m *Model) updateConnected(msg tea.Msg) tea.Cmd { } case "a": - if m.focus == FocusNetworkList && !m.HasPopup() { - popup := networkjoin.New() - m.networkJoinPopup = &popup - return nil + if !m.HasPopup() { + if m.focus == FocusNetworkList { + popup := networkjoin.New() + m.networkJoinPopup = &popup + return nil + } + if m.focus == FocusLeftSidebar && m.networkList.Index() == networklist.PeersIndex { + popup := peeradd.New() + m.peerAddPopup = &popup + return nil + } } case "i": @@ -449,6 +461,7 @@ func (m *Model) updateConnected(msg tea.Msg) tea.Cmd { m.networkJoinPopup = nil m.banReasonPopup = nil m.banViewPopup = nil + m.peerAddPopup = nil } case "enter": @@ -498,6 +511,13 @@ func (m *Model) updateConnected(msg tea.Msg) tea.Cmd { return cmd } else if m.banViewPopup != nil { m.banViewPopup = nil + } else if m.peerAddPopup != nil { + cmd, i := m.peerAddPopup.Select() + if i != -1 { + m.peerAddPopup = nil + m.peerList.SetIndex(i) + } + return cmd } default: @@ -633,6 +653,10 @@ func (m *Model) updatePopups(msg tea.Msg) tea.Cmd { popup, cmd := m.banViewPopup.Update(msg) m.banViewPopup = &popup return cmd + } else if m.peerAddPopup != nil { + popup, cmd := m.peerAddPopup.Update(msg) + m.peerAddPopup = &popup + return cmd } return nil } @@ -646,5 +670,6 @@ func (m *Model) HasPopup() bool { m.frequencyUpdatePopup != nil || m.networkJoinPopup != nil || m.banReasonPopup != nil || - m.banViewPopup != nil + m.banViewPopup != nil || + m.peerAddPopup != nil } diff --git a/internal/client/ui/core/helppopup.go b/internal/client/ui/core/helppopup.go index 0e77607..ad22fba 100644 --- a/internal/client/ui/core/helppopup.go +++ b/internal/client/ui/core/helppopup.go @@ -208,8 +208,8 @@ func (m HelpPopup) HelpPeerList() [][]Keymap { {"g", "Move to the top"}, {"G", "Move to the bottom"}, }, { - {"n", "New user conversation"}, - {"c", "Close user conversation"}, + {"a", "Add new user signal"}, + {"c", "Close user signal"}, {"T", "Trust/untrust user"}, {"B", "Block user"}, {"U", "Unblock user"}, diff --git a/internal/client/ui/core/networkjoin/networkjoin.go b/internal/client/ui/core/networkjoin/networkjoin.go index 1efd5e8..a0b8039 100644 --- a/internal/client/ui/core/networkjoin/networkjoin.go +++ b/internal/client/ui/core/networkjoin/networkjoin.go @@ -74,7 +74,7 @@ func New() Model { return errors.New("cannot be empty") } if _, err := strconv.ParseInt(s, 10, 64); err != nil { - return err + return errors.New("invalid invite code") } return nil diff --git a/internal/client/ui/core/peeradd/peeradd.go b/internal/client/ui/core/peeradd/peeradd.go new file mode 100644 index 0000000..a80e78f --- /dev/null +++ b/internal/client/ui/core/peeradd/peeradd.go @@ -0,0 +1,190 @@ +package peeradd + +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") + + i := -1 + for i, peer := range state.Data.Peers { + if peer == id { + i = i + break + } + } + + if i != -1 { + return nil, i + } + + state.Data.Peers = slices.Insert(state.Data.Peers, 0, id) + log.Println("Peers:", state.Data.Peers) + + data := state.JsonUserData() + return gateway.Send(&packet.SetUserData{ + Data: &data, + User: nil, + }), 0 +} diff --git a/internal/client/ui/core/peerlist/peerlist.go b/internal/client/ui/core/peerlist/peerlist.go index b062cb2..477f791 100644 --- a/internal/client/ui/core/peerlist/peerlist.go +++ b/internal/client/ui/core/peerlist/peerlist.go @@ -2,13 +2,16 @@ package peerlist import ( "bytes" + "slices" "strings" tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/lipgloss" + "github.com/kyren223/eko/internal/client/gateway" "github.com/kyren223/eko/internal/client/ui" "github.com/kyren223/eko/internal/client/ui/colors" "github.com/kyren223/eko/internal/client/ui/core/state" + "github.com/kyren223/eko/internal/packet" "github.com/kyren223/eko/pkg/snowflake" ) @@ -17,10 +20,7 @@ var ( Border(lipgloss.ThickBorder(), false, true, false, false) nameStyle = lipgloss.NewStyle(). - Padding(1).Align(lipgloss.Center). - Border(lipgloss.ThickBorder(), false, false, true) - networkIdStyle = lipgloss.NewStyle(). - MarginBottom(1).Padding(1, 2).Align(lipgloss.Center). + MarginBottom(1).Padding(1).Align(lipgloss.Center). Border(lipgloss.ThickBorder(), false, false, true) margin = 2 @@ -28,13 +28,7 @@ var ( peerStyle = lipgloss.NewStyle(). Margin(0, margin).Padding(0, padding).Align(lipgloss.Left) - symbolReadWrite = " " - symbolReadOnly = " " - symbolReadOnlyAdmin = " " - symbolNoAccess = " " - symbolNoAccessAdmin = " " - symbolWidth = 2 - + symbolWidth = 2 widthWithoutUser = ((margin + padding) * 2) + symbolWidth ellipsis = "…" @@ -148,12 +142,34 @@ func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) { case "g": m.SetIndex(0) case "G": - m.SetIndex(m.FrequenciesLength() - 1) + m.SetIndex(len(m.Peers()) - 1) case "ctrl+u": m.SetIndex(m.index - m.height/2) case "ctrl+d": m.SetIndex(m.index + m.height/2) + case "c": + if m.index == -1 { + return m, nil + } + state.Data.Peers = slices.Delete(state.Data.Peers, m.index, m.index+1) + if m.index == len(state.Data.Peers) { + m.SetIndex(m.index - 1) + } + + case "T": + if m.index == -1 { + return m, nil + } + userId := state.Data.Peers[m.index] + + _, isTrusting := state.State.Trusteds[userId] + + return m, gateway.Send(&packet.TrustUser{ + User: userId, + Trust: !isTrusting, + }) + } } @@ -168,11 +184,6 @@ func (m *Model) Blur() { m.focus = false } -func (m Model) FrequenciesLength() int { - // TODO: - return len(state.State.Frequencies[0]) -} - func (m Model) Peers() []snowflake.ID { return state.Data.Peers } @@ -182,7 +193,7 @@ func (m *Model) Index() int { } func (m *Model) SetIndex(index int) { - m.index = min(max(index, 0), m.FrequenciesLength()-1) + m.index = min(max(index, 0), len(m.Peers())-1) if m.index < m.base { m.base = max(m.index, 0) } else if m.index >= m.base+m.height { |
