From 52e7d6ed0ef0af78c7ad5e5525db4440ed8d8e12 Mon Sep 17 00:00:00 2001 From: ayn2op Date: Sun, 30 Aug 2026 21:10:37 -0400 Subject: [PATCH] fix(ui): sort dms on message create (#835) --- internal/ui/chat/guilds_tree.go | 14 ++++++++ internal/ui/chat/guilds_tree_test.go | 53 ++++++++++++++++++++++++++++ internal/ui/chat/state.go | 4 +++ 3 files changed, 71 insertions(+) create mode 100644 internal/ui/chat/guilds_tree_test.go diff --git a/internal/ui/chat/guilds_tree.go b/internal/ui/chat/guilds_tree.go index 8ef14ce..cbde2e3 100644 --- a/internal/ui/chat/guilds_tree.go +++ b/internal/ui/chat/guilds_tree.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "log/slog" + "slices" "github.com/ayn2op/arikawa/v3/discord" "github.com/ayn2op/arikawa/v3/gateway" @@ -87,6 +88,19 @@ func (gt *guildsTree) updateDMNodeStyle(userID discord.UserID) { gt.setNodeLineStyle(node, gt.channelNodeStyle(*channel)) } +func (gt *guildsTree) moveDMToFront(channelID discord.ChannelID) { + if gt.dmRootNode == nil { + return + } + + node := gt.channelNodeByID[channelID] + children := gt.dmRootNode.Children() + if index := slices.Index(children, node); index > 0 { + copy(children[1:index+1], children[:index]) + children[0] = node + } +} + func (gt *guildsTree) createFolderNode(folder gateway.GuildFolder, guildsByID map[discord.GuildID]*gateway.GuildCreateEvent) { name := "Folder" if folder.Name != "" { diff --git a/internal/ui/chat/guilds_tree_test.go b/internal/ui/chat/guilds_tree_test.go new file mode 100644 index 0000000..0e53bbb --- /dev/null +++ b/internal/ui/chat/guilds_tree_test.go @@ -0,0 +1,53 @@ +package chat + +import ( + "slices" + "testing" + + "github.com/ayn2op/arikawa/v3/discord" + "github.com/ayn2op/arikawa/v3/gateway" + "github.com/ayn2op/tview/tree" +) + +func TestMessageCreatePromotesDMChannel(t *testing.T) { + firstID := discord.ChannelID(1) + secondID := discord.ChannelID(2) + thirdID := discord.ChannelID(3) + + first := tree.NewNode("first").SetReference(firstID) + second := tree.NewNode("second").SetReference(secondID) + third := tree.NewNode("third").SetReference(thirdID) + dmRoot := tree.NewNode("Direct Messages").SetChildren([]*tree.Node{first, second, third}) + m := Model{guildsTree: &guildsTree{ + dmRootNode: dmRoot, + channelNodeByID: map[discord.ChannelID]*tree.Node{ + firstID: first, + secondID: second, + thirdID: third, + }, + }} + + m.onMessageCreate(&gateway.MessageCreateEvent{Message: discord.Message{ChannelID: thirdID}}) + + want := []*tree.Node{third, first, second} + if !slices.Equal(dmRoot.Children(), want) { + t.Fatalf("children = %v, want %v", dmRoot.Children(), want) + } +} + +func TestMessageCreateIgnoresUnrenderedDMChannel(t *testing.T) { + firstID := discord.ChannelID(1) + first := tree.NewNode("first").SetReference(firstID) + dmRoot := tree.NewNode("Direct Messages").SetChildren([]*tree.Node{first}) + m := Model{guildsTree: &guildsTree{ + dmRootNode: dmRoot, + channelNodeByID: map[discord.ChannelID]*tree.Node{}, + }} + + m.onMessageCreate(&gateway.MessageCreateEvent{Message: discord.Message{ChannelID: 2}}) + + children := dmRoot.Children() + if len(children) != 1 || children[0] != first { + t.Fatalf("children = %v, want the original DM node", children) + } +} diff --git a/internal/ui/chat/state.go b/internal/ui/chat/state.go index b843e65..acabddc 100644 --- a/internal/ui/chat/state.go +++ b/internal/ui/chat/state.go @@ -96,6 +96,10 @@ func (m *Model) onReady(event *gateway.ReadyEvent) tview.Cmd { } func (m *Model) onMessageCreate(message *gateway.MessageCreateEvent) tview.Cmd { + if !message.GuildID.IsValid() { + m.guildsTree.moveDMToFront(message.ChannelID) + } + selectedChannel, ok := m.SelectedChannel() if ok && selectedChannel.ID == message.ChannelID { m.removeTyper(message.Author.ID)