From 088baa6d3a63a7a6dea80afd07c48da99e2d19e8 Mon Sep 17 00:00:00 2001 From: Kyren223 Date: Thu, 30 Jan 2025 19:04:52 +0200 Subject: [PATCH] Implemented frequency-level notifications and pings --- internal/client/ui/core/chat/chat.go | 90 +++++++++++-------- .../ui/core/frequencylist/frequencylist.go | 70 ++++++++++++++- internal/client/ui/core/state/state.go | 4 +- 3 files changed, 122 insertions(+), 42 deletions(-) diff --git a/internal/client/ui/core/chat/chat.go b/internal/client/ui/core/chat/chat.go index ffdcd54..ceb8aeb 100644 --- a/internal/client/ui/core/chat/chat.go +++ b/internal/client/ui/core/chat/chat.go @@ -117,12 +117,12 @@ type Model struct { receiverIndex int frequencyIndex int - base int - index int - selectedMessage *data.Message - editingMessage *data.Message - lastReadMessageId *snowflake.ID - keepLastRead bool + base int + index int + selectedMessage *data.Message + editingMessage *data.Message + lastReadMsg *snowflake.ID + keepLastRead bool messagesHeight int maxMessagesHeight int @@ -152,7 +152,7 @@ func New() Model { index: Unselected, selectedMessage: nil, editingMessage: nil, - lastReadMessageId: nil, + lastReadMsg: nil, keepLastRead: false, messagesHeight: 0, maxMessagesHeight: -1, @@ -206,15 +206,17 @@ func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) { frequency := frequencies[m.frequencyIndex] member := state.State.Members[*networkId][*state.UserID] - if m.base == SnapToBottom { - lastRead := state.GetLastReadMessage(frequency.ID) - if lastRead != nil && m.lastReadMessageId != nil && - state.Data.LastReadMessage[frequency.ID] != nil && - *m.lastReadMessageId != *lastRead && - *m.lastReadMessageId != *state.Data.LastReadMessage[frequency.ID] { + lastMsg := state.GetLastReadMessage(frequency.ID) + if m.base != SnapToBottom { + m.keepLastRead = false + } else if lastMsg != nil { + lastReadMsg := state.Data.LastReadMessage[frequency.ID] + if m.keepLastRead && m.lastReadMsg != nil && lastReadMsg != nil && + *lastReadMsg != *lastMsg && *lastReadMsg != *m.lastReadMsg { m.keepLastRead = false } - m.lastReadMessageId = lastRead + + state.Data.LastReadMessage[frequency.ID] = lastMsg } m.hasReadAccess = frequency.Perms != packet.PermNoAccess || member.IsAdmin @@ -251,15 +253,17 @@ func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) { } else if m.receiverIndex != -1 { receiverId := state.Data.Peers[m.receiverIndex] - if m.base == SnapToBottom { - lastRead := state.GetLastReadMessage(receiverId) - if lastRead != nil && m.lastReadMessageId != nil && - state.Data.LastReadMessage[receiverId] != nil && - *m.lastReadMessageId != *lastRead && - *m.lastReadMessageId != *state.Data.LastReadMessage[receiverId] { - m.keepLastRead = false - } - m.lastReadMessageId = lastRead + lastMsg := state.GetLastReadMessage(receiverId) + if m.base == SnapToBottom && lastMsg != nil { + lastReadMsg := state.Data.LastReadMessage[receiverId] + + // if m.lastReadMsg != nil && lastReadMsg != nil && + // *lastReadMsg != *lastMsg && + // *lastReadMsg != *m.lastReadMsg { + // m.keepLastRead = false + // } + + *lastReadMsg = *lastMsg } } @@ -694,7 +698,7 @@ func (m *Model) ResetBeforeSwitch() { m.base = SnapToBottom m.SetIndex(Unselected) m.maxMessagesHeight = -1 - m.lastReadMessageId = nil + m.lastReadMsg = nil }() networkId := state.NetworkId(m.networkIndex) @@ -711,10 +715,7 @@ func (m *Model) ResetBeforeSwitch() { MaxHeight: m.maxMessagesHeight, } - if m.lastReadMessageId != nil { - log.Println("Setting last msg ID") - state.SetLastReadMessage(frequencyId, *m.lastReadMessageId) - } + state.SendUserDatUpdate() } else if m.receiverIndex != -1 { receiverId := state.Data.Peers[m.receiverIndex] @@ -725,9 +726,7 @@ func (m *Model) ResetBeforeSwitch() { MaxHeight: m.maxMessagesHeight, } - if m.lastReadMessageId != nil { - state.SetLastReadMessage(receiverId, *m.lastReadMessageId) - } + state.SendUserDatUpdate() } } @@ -739,8 +738,9 @@ func (m *Model) RestoreAfterSwitch() tea.Cmd { frequency := frequencies[m.frequencyIndex] log.Println("Restoring frequency:", frequency.ID) - m.lastReadMessageId = state.Data.LastReadMessage[frequency.ID] - if m.lastReadMessageId != nil { + m.lastReadMsg = state.Data.LastReadMessage[frequency.ID] + if m.lastReadMsg != nil { + log.Println("LAST READ MSG", m.lastReadMsg) m.keepLastRead = true } @@ -761,8 +761,8 @@ func (m *Model) RestoreAfterSwitch() tea.Cmd { receiverId := state.Data.Peers[m.receiverIndex] log.Println("Restoring signal:", receiverId) - m.lastReadMessageId = state.Data.LastReadMessage[receiverId] - if m.lastReadMessageId != nil { + m.lastReadMsg = state.Data.LastReadMessage[receiverId] + if m.lastReadMsg != nil { m.keepLastRead = true } @@ -881,18 +881,30 @@ func (m *Model) renderMessages(screenHeight int) string { renderedGroups := []string{} group := []data.Message{} - lastReadId := m.lastReadMessageId + lastReadId := state.Data.LastReadMessage[*id] if m.keepLastRead { - lastReadId = state.Data.LastReadMessage[*id] + // assert.NotNil(m.lastReadMsg, "TODO: REMOVE THIS", "lastReadId", lastReadId, "m.lastReadMsg", m.lastReadMsg) + // assert.Assert(*m.lastReadMsg != *lastReadId, "TODO: REMOVE THIS", "lastReadId", lastReadId, "m.lastReadMsg", m.lastReadMsg) + if m.lastReadMsg != nil && lastReadId != nil && *m.lastReadMsg == *lastReadId { + log.Println("TODO: REMOVE THIS", "lastReadId", lastReadId, "m.lastReadMsg", m.lastReadMsg) + } + lastReadId = m.lastReadMsg } last := snowflake.ID(0) btree.Descend(func(message data.Message) bool { last = message.ID - isLastRead := lastReadId != nil && *lastReadId == message.ID + // >= is needed so if the message was deleted + // Any prior messages will still be separated by "new" + isLastRead := lastReadId != nil && *lastReadId >= message.ID if len(group) == 0 { group = append(group, message) + + if isLastRead { + lastReadId = nil + } + return true } @@ -921,6 +933,8 @@ func (m *Model) renderMessages(screenHeight int) string { renderedGroups = append(renderedGroups, newSep+"\n") remainingHeight-- + + lastReadId = nil // Stop the rest of the messages from having NEW } return remainingHeight > 0 diff --git a/internal/client/ui/core/frequencylist/frequencylist.go b/internal/client/ui/core/frequencylist/frequencylist.go index 1c7fe22..537be56 100644 --- a/internal/client/ui/core/frequencylist/frequencylist.go +++ b/internal/client/ui/core/frequencylist/frequencylist.go @@ -14,6 +14,7 @@ import ( "github.com/kyren223/eko/internal/data" "github.com/kyren223/eko/internal/packet" "github.com/kyren223/eko/pkg/assert" + "github.com/kyren223/eko/pkg/snowflake" ) var ( @@ -44,6 +45,13 @@ var ( ellipsis = "…" BackgroundStyle = lipgloss.NewStyle().Background(colors.BackgroundDim) + + notifSymbol = []string{ + "  ", " 󰲠 ", " 󰲢 ", " 󰲤 ", " 󰲦 ", " 󰲨 ", " 󰲪 ", " 󰲬 ", " 󰲮 ", " 󰲰 ", " 󰲲 ", + } + notifStyleDot = lipgloss.NewStyle().Foreground(colors.White) + notifStyle = lipgloss.NewStyle().Foreground(colors.Red) + notifWidth = 3 ) type Model struct { @@ -91,6 +99,8 @@ func (m Model) View() string { upper := min(m.base+m.height, len(frequencies)) frequencies = frequencies[m.base:upper] for i, frequency := range frequencies { + maxFrequencyWidth := maxFrequencyWidth + frequencyStyle := frequencyStyle.Foreground(lipgloss.Color(frequency.HexColor)) if m.index == m.base+i { frequencyStyle = frequencyStyle.Background(colors.BackgroundHighlight) @@ -109,6 +119,24 @@ func (m Model) View() string { symbol = symbolNoAccessAdmin } + notif := "" + notifStyle := notifStyle + pings, hasNotif := m.getNotifCount(frequency.ID) + if pings == 0 && hasNotif { + notif = notifSymbol[0] + // notifStyle = notifStyleDot + } else if hasNotif { + notif = notifSymbol[min(pings, 10)] + } + + if m.index == m.base+i { + notifStyle = notifStyle.Background(colors.BackgroundHighlight) + } + if notif != "" { + maxFrequencyWidth -= notifWidth + notif = notifStyle.Render(notif) + } + frequencyName := "" if lipgloss.Width(frequency.Name) <= maxFrequencyWidth { frequencyName = lipgloss.NewStyle(). @@ -119,8 +147,10 @@ func (m Model) View() string { MaxWidth(maxFrequencyWidth-1). Render(frequency.Name) + ellipsis } + frequencyName = lipgloss.NewStyle().Width(maxFrequencyWidth). + Render(frequencyName) - frequency := frequencyStyle.Render(symbol + frequencyName) + frequency := frequencyStyle.Render(symbol + frequencyName + notif) builder.WriteString(backgroundStyle.Render(frequency)) builder.WriteString("\n") } @@ -330,3 +360,41 @@ func (m Model) renderNetworkName() string { func (m *Model) SetWidth(width int) { m.width = width } + +func (m *Model) getNotifCount(frequencyId snowflake.ID) (_ int, _ bool) { + lastReadMsg := state.Data.LastReadMessage[frequencyId] + if lastReadMsg == nil { + return 0, false + } + + btree := state.State.Messages[frequencyId] + if btree == nil { + return 0, false + } + + pings := 0 + hasNotif := false + + networkId := state.NetworkId(m.networkIndex) + isAdmin := state.State.Members[*networkId][*state.UserID].IsAdmin + + btree.AscendGreaterOrEqual(data.Message{ID: *lastReadMsg + 1}, func(item data.Message) bool { + hasNotif = true + + if item.Ping == nil { + return true + } + + if *item.Ping == packet.PingEveryone { + pings++ + } else if *item.Ping == packet.PingAdmins && isAdmin { + pings++ + } else if *item.Ping == *state.UserID { + pings++ + } + + return pings <= 10 + }) + + return pings, hasNotif +} diff --git a/internal/client/ui/core/state/state.go b/internal/client/ui/core/state/state.go index 04d592e..efa4732 100644 --- a/internal/client/ui/core/state/state.go +++ b/internal/client/ui/core/state/state.go @@ -236,9 +236,7 @@ func GetLastReadMessage(id snowflake.ID) *snowflake.ID { return &msg.ID } -func SetLastReadMessage(id snowflake.ID, message snowflake.ID) { - Data.LastReadMessage[id] = &message - +func SendUserDatUpdate() { data := JsonUserData() gateway.SendAsync(&packet.SetUserData{ Data: &data,