diff options
| author | Kyren223 <Kyren223@proton.me> | 2025-01-26 17:37:58 +0200 |
|---|---|---|
| committer | Kyren223 <Kyren223@proton.me> | 2025-01-26 17:37:58 +0200 |
| commit | bcd13d0afba8fae352b87556b31b1cf5d1a6e7c3 (patch) | |
| tree | 095c9a79a31fdc06f69c44b5a49aeac700a99298 /internal | |
| parent | 8abb4518e90830b74928a166a6b83955a78c645d (diff) | |
Added basic peer list
Diffstat (limited to 'internal')
| -rw-r--r-- | internal/client/ui/core/banlist/banlist.go | 12 | ||||
| -rw-r--r-- | internal/client/ui/core/chat/chat.go | 12 | ||||
| -rw-r--r-- | internal/client/ui/core/core.go | 61 | ||||
| -rw-r--r-- | internal/client/ui/core/helppopup.go | 22 | ||||
| -rw-r--r-- | internal/client/ui/core/memberlist/memberlist.go | 12 | ||||
| -rw-r--r-- | internal/client/ui/core/peerlist/peerlist.go | 205 | ||||
| -rw-r--r-- | internal/client/ui/core/state/state.go | 2 | ||||
| -rw-r--r-- | internal/client/ui/ui.go | 15 |
8 files changed, 301 insertions, 40 deletions
diff --git a/internal/client/ui/core/banlist/banlist.go b/internal/client/ui/core/banlist/banlist.go index c6c0a46..96f9b23 100644 --- a/internal/client/ui/core/banlist/banlist.go +++ b/internal/client/ui/core/banlist/banlist.go @@ -95,19 +95,19 @@ func (m Model) View() string { var userStyle lipgloss.Style if isTrusted && keysMatch { if ownerId == member.UserID { - userStyle = ui.TrustedOwnerMemberStyle + userStyle = ui.TrustedOwnerStyle } else if member.IsAdmin { - userStyle = ui.TrustedAdminMemberStyle + userStyle = ui.TrustedAdminStyle } else { - userStyle = ui.TrustedNormalMemberStyle + userStyle = ui.TrustedMemberStyle } } else { if ownerId == member.UserID { - userStyle = ui.OwnerMemberStyle + userStyle = ui.OwnerStyle } else if member.IsAdmin { - userStyle = ui.AdminMemberStyle + userStyle = ui.AdminStyle } else { - userStyle = ui.NormalMemberStyle + userStyle = ui.UserStyle } } memberName := state.State.Users[member.UserID].Name diff --git a/internal/client/ui/core/chat/chat.go b/internal/client/ui/core/chat/chat.go index 67079f9..c045c41 100644 --- a/internal/client/ui/core/chat/chat.go +++ b/internal/client/ui/core/chat/chat.go @@ -988,19 +988,19 @@ func (m *Model) renderHeader(message data.Message, selected bool) []byte { var senderStyle lipgloss.Style if isTrusted && keysMatch { if ownerId == member.UserID { - senderStyle = ui.TrustedOwnerMemberStyle + senderStyle = ui.TrustedOwnerStyle } else if member.IsAdmin { - senderStyle = ui.TrustedAdminMemberStyle + senderStyle = ui.TrustedAdminStyle } else { - senderStyle = ui.TrustedNormalMemberStyle + senderStyle = ui.TrustedMemberStyle } } else { if ownerId == member.UserID { - senderStyle = ui.OwnerMemberStyle + senderStyle = ui.OwnerStyle } else if member.IsAdmin { - senderStyle = ui.AdminMemberStyle + senderStyle = ui.AdminStyle } else { - senderStyle = ui.NormalMemberStyle + senderStyle = ui.UserStyle } } diff --git a/internal/client/ui/core/core.go b/internal/client/ui/core/core.go index 5898741..b5cd8ba 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/peerlist" "github.com/kyren223/eko/internal/client/ui/core/state" "github.com/kyren223/eko/internal/client/ui/core/usersettings" "github.com/kyren223/eko/internal/client/ui/loadscreen" @@ -76,6 +77,7 @@ type Model struct { banReasonPopup *banreason.Model banViewPopup *banview.Model networkList networklist.Model + peerList peerlist.Model frequencyList frequencylist.Model memberList memberlist.Model chat chat.Model @@ -100,6 +102,7 @@ func New(privKey ed25519.PrivateKey, name string) Model { banReasonPopup: nil, banViewPopup: nil, networkList: networklist.New(), + peerList: peerlist.New(), frequencyList: frequencylist.New(), memberList: memberlist.New(), chat: chat.New(), @@ -120,7 +123,12 @@ func (m Model) View() string { } networkList := m.networkList.View() - leftSidebar := m.frequencyList.View() + var leftSidebar string + if m.networkList.Index() == networklist.PeersIndex { + leftSidebar = m.peerList.View() + } else { + leftSidebar = m.frequencyList.View() + } chat := m.chat.View() rightSidebar := m.memberList.View() result := lipgloss.JoinHorizontal(lipgloss.Top, networkList, leftSidebar, chat, rightSidebar) @@ -238,6 +246,7 @@ func (m *Model) updateConnected(msg tea.Msg) tea.Cmd { // log.Println("sidebarWidth:", sidebarWidth) // log.Println("chatWidth:", chatWidth) + m.peerList.SetWidth(sidebarWidth) m.frequencyList.SetWidth(sidebarWidth) m.memberList.SetWidth(sidebarWidth) m.chat.SetWidth(chatWidth) @@ -327,17 +336,21 @@ func (m *Model) updateConnected(msg tea.Msg) tea.Cmd { } case FocusLeftSidebar: if !m.HasPopup() { - networkId := state.NetworkId(m.networkList.Index()) - if networkId == nil { - return nil - } - member := state.State.Members[*networkId][*state.UserID] - if !member.IsAdmin { + if m.networkList.Index() == networklist.PeersIndex { + // TODO: add n keybind for receiver + } else { + networkId := state.NetworkId(m.networkList.Index()) + if networkId == nil { + return nil + } + member := state.State.Members[*networkId][*state.UserID] + if !member.IsAdmin { + return nil + } + popup := frequencycreation.New(*networkId) + m.frequencyCreationPopup = &popup return nil } - popup := frequencycreation.New(*networkId) - m.frequencyCreationPopup = &popup - return nil } } @@ -404,7 +417,11 @@ func (m *Model) updateConnected(msg tea.Msg) tea.Cmd { case FocusNetworkList: m.helpPopup = NewHelpPopup(HelpNetworkList) case FocusLeftSidebar: - m.helpPopup = NewHelpPopup(HelpFrequencyList) + if m.networkList.Index() == networklist.PeersIndex { + m.helpPopup = NewHelpPopup(HelpPeerList) + } else { + m.helpPopup = NewHelpPopup(HelpFrequencyList) + } case FocusChat: if m.chat.Locked() { m.helpPopup = NewHelpPopup(HelpVim) @@ -510,9 +527,14 @@ func (m *Model) updateConnected(msg tea.Msg) tea.Cmd { m.networkList, cmd = m.networkList.Update(msg) cmds = append(cmds, cmd) - m.frequencyList.SetNetworkIndex(m.networkList.Index()) - m.frequencyList, cmd = m.frequencyList.Update(msg) - cmds = append(cmds, cmd) + if m.networkList.Index() == networklist.PeersIndex { + m.peerList, cmd = m.peerList.Update(msg) + cmds = append(cmds, cmd) + } else { + m.frequencyList.SetNetworkIndex(m.networkList.Index()) + m.frequencyList, cmd = m.frequencyList.Update(msg) + cmds = append(cmds, cmd) + } m.memberList.SetNetworkAndFrequency(m.networkList.Index(), m.frequencyList.Index()) m.memberList, cmd = m.memberList.Update(msg) @@ -541,6 +563,7 @@ func (m *Model) move(direction int) { switch m.focus { case FocusNetworkList: + m.peerList.Blur() m.frequencyList.Blur() m.memberList.Blur() m.chat.Blur() @@ -549,13 +572,21 @@ func (m *Model) move(direction int) { m.networkList.Blur() m.memberList.Blur() m.chat.Blur() - m.frequencyList.Focus() + if m.networkList.Index() == networklist.PeersIndex { + m.frequencyList.Blur() + m.peerList.Focus() + } else { + m.peerList.Blur() + m.frequencyList.Focus() + } case FocusChat: + m.peerList.Blur() m.networkList.Blur() m.memberList.Blur() m.frequencyList.Blur() m.chat.Focus() case FocusRightSidebar: + m.peerList.Blur() m.networkList.Blur() m.frequencyList.Blur() m.chat.Blur() diff --git a/internal/client/ui/core/helppopup.go b/internal/client/ui/core/helppopup.go index 74c9ef7..0e77607 100644 --- a/internal/client/ui/core/helppopup.go +++ b/internal/client/ui/core/helppopup.go @@ -34,6 +34,7 @@ var ( const ( HelpNetworkList = iota + HelpPeerList HelpFrequencyList HelpChat HelpMemberList @@ -75,6 +76,8 @@ func (m HelpPopup) View() string { switch m.help { case HelpNetworkList: keymapLists = m.HelpNetworkList() + case HelpPeerList: + keymapLists = m.HelpPeerList() case HelpFrequencyList: keymapLists = m.HelpFrequencyList() case HelpChat: @@ -129,6 +132,8 @@ func (m HelpPopup) Title() string { switch m.help { case HelpNetworkList: return "Network" + case HelpPeerList: + return "Signals" case HelpFrequencyList: return "Frequency" case HelpChat: @@ -194,6 +199,23 @@ func (m HelpPopup) HelpFrequencyList() [][]Keymap { }} } +func (m HelpPopup) HelpPeerList() [][]Keymap { + return [][]Keymap{{ + {"k", "Move up a user"}, + {"j", "Move down a user"}, + {"ctrl+u", "Move half a page up"}, + {"ctrl+d", "Move half a page down"}, + {"g", "Move to the top"}, + {"G", "Move to the bottom"}, + }, { + {"n", "New user conversation"}, + {"c", "Close user conversation"}, + {"T", "Trust/untrust user"}, + {"B", "Block user"}, + {"U", "Unblock user"}, + }} +} + func (m HelpPopup) HelpChat() [][]Keymap { return [][]Keymap{{ {"k", "Move up a message"}, diff --git a/internal/client/ui/core/memberlist/memberlist.go b/internal/client/ui/core/memberlist/memberlist.go index f6b3845..ee61868 100644 --- a/internal/client/ui/core/memberlist/memberlist.go +++ b/internal/client/ui/core/memberlist/memberlist.go @@ -104,19 +104,19 @@ func (m Model) View() string { var userStyle lipgloss.Style if isTrusted && keysMatch { if ownerId == member.UserID { - userStyle = ui.TrustedOwnerMemberStyle + userStyle = ui.TrustedOwnerStyle } else if member.IsAdmin { - userStyle = ui.TrustedAdminMemberStyle + userStyle = ui.TrustedAdminStyle } else { - userStyle = ui.TrustedNormalMemberStyle + userStyle = ui.TrustedMemberStyle } } else { if ownerId == member.UserID { - userStyle = ui.OwnerMemberStyle + userStyle = ui.OwnerStyle } else if member.IsAdmin { - userStyle = ui.AdminMemberStyle + userStyle = ui.AdminStyle } else { - userStyle = ui.NormalMemberStyle + userStyle = ui.UserStyle } } memberName := m.Users()[member.UserID].Name diff --git a/internal/client/ui/core/peerlist/peerlist.go b/internal/client/ui/core/peerlist/peerlist.go new file mode 100644 index 0000000..b062cb2 --- /dev/null +++ b/internal/client/ui/core/peerlist/peerlist.go @@ -0,0 +1,205 @@ +package peerlist + +import ( + "bytes" + "strings" + + tea "github.com/charmbracelet/bubbletea" + "github.com/charmbracelet/lipgloss" + "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/pkg/snowflake" +) + +var ( + sepStyle = lipgloss.NewStyle().Width(0). + 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). + Border(lipgloss.ThickBorder(), false, false, true) + + margin = 2 + padding = 1 + peerStyle = lipgloss.NewStyle(). + Margin(0, margin).Padding(0, padding).Align(lipgloss.Left) + + symbolReadWrite = " " + symbolReadOnly = " " + symbolReadOnlyAdmin = " " + symbolNoAccess = " " + symbolNoAccessAdmin = " " + symbolWidth = 2 + + widthWithoutUser = ((margin + padding) * 2) + symbolWidth + + ellipsis = "…" + + BackgroundStyle = lipgloss.NewStyle().Background(colors.BackgroundDim) +) + +type Model struct { + base int + index int + focus bool + width int + height int +} + +func New() Model { + return Model{ + base: 0, + index: -1, + focus: false, + width: -1, + height: 1, + } +} + +func (m Model) Init() tea.Cmd { + return nil +} + +func (m Model) View() string { + peerStyle := peerStyle.Width(m.width - (margin * 2)) + backgroundStyle := BackgroundStyle.Width(m.width) + maxUserWidth := m.width - widthWithoutUser + + var builder strings.Builder + + builder.WriteString(m.renderHeader()) + + builder.WriteString("\n") + peers := m.Peers() + upper := min(m.base+m.height, len(peers)) + peers = peers[m.base:upper] + for i, peer := range peers { + peerStyle := peerStyle + if m.index == m.base+i { + peerStyle = peerStyle.Background(colors.BackgroundHighlight) + } + + user := state.State.Users[peer] + trustedPublicKey, isTrusted := state.State.Trusteds[user.ID] + keysMatch := bytes.Equal(trustedPublicKey, user.PublicKey) + + var userStyle lipgloss.Style + if isTrusted && keysMatch { + userStyle = ui.TrustedUserStyle + } else { + userStyle = ui.UserStyle + } + + username := user.Name + username = userStyle.Render(username) + if isTrusted && !keysMatch { + username = ui.UntrustedSymbol + username + } + + if lipgloss.Width(username) <= maxUserWidth { + username = lipgloss.NewStyle(). + MaxWidth(maxUserWidth). + Render(username) + } else { + ellipsisStyle := lipgloss.NewStyle(). + Background(peerStyle.GetBackground()).Foreground(userStyle.GetForeground()) + username = lipgloss.NewStyle(). + MaxWidth(maxUserWidth-1). + Render(username) + ellipsisStyle.Render(ellipsis) + } + + builder.WriteString(backgroundStyle.Render(peerStyle.Render(username))) + builder.WriteString("\n") + } + + sidebar := builder.String() + sep := sepStyle.Height(ui.Height) + if m.focus { + sep = sep.BorderForeground(colors.Focus) + } + result := lipgloss.JoinHorizontal(lipgloss.Top, sidebar, sep.String()) + + return BackgroundStyle.Render(result) +} + +func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) { + // Calculate height for frequencies + m.height = ui.Height + m.height -= lipgloss.Height(m.renderHeader()) + m.height -= 1 + m.SetIndex(m.index) + + switch msg := msg.(type) { + case tea.KeyMsg: + if !m.focus { + return m, nil + } + + key := msg.String() + switch key { + case "k": + m.SetIndex(m.index - 1) + case "j": + m.SetIndex(m.index + 1) + case "g": + m.SetIndex(0) + case "G": + m.SetIndex(m.FrequenciesLength() - 1) + case "ctrl+u": + m.SetIndex(m.index - m.height/2) + case "ctrl+d": + m.SetIndex(m.index + m.height/2) + + } + } + + return m, nil +} + +func (m *Model) Focus() { + m.focus = true +} + +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 +} + +func (m *Model) Index() int { + return m.index +} + +func (m *Model) SetIndex(index int) { + m.index = min(max(index, 0), m.FrequenciesLength()-1) + if m.index < m.base { + m.base = max(m.index, 0) + } else if m.index >= m.base+m.height { + m.base = 1 + m.index - m.height + } +} + +func (m Model) renderHeader() string { + nameStyle := nameStyle.Background(colors.DarkerCyan).Foreground(colors.Turquoise).Width(m.width) + if m.focus { + nameStyle = nameStyle.BorderForeground(colors.Focus) + } + peersName := nameStyle.Render("User Signals") + + return lipgloss.JoinVertical(0, peersName) +} + +func (m *Model) SetWidth(width int) { + m.width = width +} diff --git a/internal/client/ui/core/state/state.go b/internal/client/ui/core/state/state.go index 044de2b..c67fe04 100644 --- a/internal/client/ui/core/state/state.go +++ b/internal/client/ui/core/state/state.go @@ -45,10 +45,12 @@ var State state = state{ type UserData struct { Networks []snowflake.ID + Peers []snowflake.ID } var Data UserData = UserData{ Networks: []snowflake.ID{}, + Peers: []snowflake.ID{}, } var UserID *snowflake.ID = nil diff --git a/internal/client/ui/ui.go b/internal/client/ui/ui.go index 02fb757..3d13ee8 100644 --- a/internal/client/ui/ui.go +++ b/internal/client/ui/ui.go @@ -29,13 +29,14 @@ var ( Height int Program *tea.Program - NormalMemberStyle = lipgloss.NewStyle().Foreground(colors.Purple).SetString("") - AdminMemberStyle = lipgloss.NewStyle().Foreground(colors.Red).Bold(true).SetString("") - OwnerMemberStyle = AdminMemberStyle.Foreground(colors.Gold).SetString("") - TrustedNormalMemberStyle = NormalMemberStyle.SetString("") - TrustedAdminMemberStyle = AdminMemberStyle.SetString("") - TrustedOwnerMemberStyle = OwnerMemberStyle.SetString("") - UntrustedSymbol = lipgloss.NewStyle().Foreground(colors.Red).Render("") + UserStyle = lipgloss.NewStyle().Foreground(colors.Purple).SetString("") + AdminStyle = lipgloss.NewStyle().Foreground(colors.Red).Bold(true).SetString("") + OwnerStyle = AdminStyle.Foreground(colors.Gold).SetString("") + TrustedUserStyle = UserStyle.Foreground(colors.Turquoise).SetString("") + TrustedMemberStyle = UserStyle.SetString("") + TrustedAdminStyle = AdminStyle.SetString("") + TrustedOwnerStyle = OwnerStyle.SetString("") + UntrustedSymbol = lipgloss.NewStyle().Foreground(colors.Red).Render("") ) var NewAuth func() tea.Model |
