Quellcode durchsuchen

fix(ui/chat): ensure all guilds appear in tree including orphans (#741)

Ayyan vor 2 Monaten
Ursprung
Commit
4c61e7c67a
2 geänderte Dateien mit 50 neuen und 24 gelöschten Zeilen
  1. 4 8
      internal/ui/chat/guilds_tree.go
  2. 46 16
      internal/ui/chat/state.go

+ 4 - 8
internal/ui/chat/guilds_tree.go

@@ -59,7 +59,7 @@ func (gt *guildsTree) resetNodeIndex() {
 	gt.dmRootNode = nil
 }
 
-func (gt *guildsTree) createFolderNode(folder gateway.GuildFolder) {
+func (gt *guildsTree) createFolderNode(folder gateway.GuildFolder, guildsByID map[discord.GuildID]*gateway.GuildCreateEvent) {
 	name := "Folder"
 	if folder.Name != "" {
 		name = folder.Name
@@ -72,14 +72,10 @@ func (gt *guildsTree) createFolderNode(folder gateway.GuildFolder) {
 	}
 	gt.GetRoot().AddChild(folderNode)
 
-	for _, gID := range folder.GuildIDs {
-		guild, err := gt.chatView.state.Cabinet.Guild(gID)
-		if err != nil {
-			slog.Error("failed to get guild from state", "guild_id", gID, "err", err)
-			continue
+	for _, guildID := range folder.GuildIDs {
+		if guildEvent, ok := guildsByID[guildID]; ok {
+			gt.createGuildNode(folderNode, guildEvent.Guild)
 		}
-
-		gt.createGuildNode(folderNode, *guild)
 	}
 }
 

+ 46 - 16
internal/ui/chat/state.go

@@ -80,34 +80,64 @@ func (v *View) onRaw(event *ws.RawEvent) {
 	)
 }
 
-func (v *View) onReady(r *gateway.ReadyEvent) {
-	dmNode := tview.NewTreeNode("Direct Messages").SetReference(dmNode{})
+func (v *View) onReady(event *gateway.ReadyEvent) {
 	// Rebuild indexes from scratch so reconnects and account switches do not
 	// retain stale pointers to detached tree nodes.
 	v.guildsTree.resetNodeIndex()
+
+	dmNode := tview.NewTreeNode("Direct Messages").SetReference(dmNode{})
 	v.guildsTree.dmRootNode = dmNode
+
 	root := v.guildsTree.
 		GetRoot().
 		ClearChildren().
 		AddChild(dmNode)
 
-	for _, folder := range r.UserSettings.GuildFolders {
+	// Track guilds already in folders to find orphans (newly joined guilds may not be synced to GuildFolders yet but always appear in GuildPositions)
+	guildsInFolders := make(map[discord.GuildID]bool)
+	for _, folder := range event.UserSettings.GuildFolders {
+		for _, guildID := range folder.GuildIDs {
+			guildsInFolders[guildID] = true
+		}
+	}
+
+	// Build index of all available guilds.
+	guildsByID := make(map[discord.GuildID]*gateway.GuildCreateEvent, len(event.Guilds))
+	for index := range event.Guilds {
+		guildsByID[event.Guilds[index].ID] = &event.Guilds[index]
+	}
+
+	// Use GuildPositions for ordering (it's the canonical order).
+	// Guilds not in any folder are "orphans" - add them directly to root.
+	positions := event.UserSettings.GuildPositions
+	// Fallback: GuildPositions shouldn't be nil but handle gracefully
+	if len(positions) == 0 {
+		positions = make([]discord.GuildID, 0, len(event.Guilds))
+		for _, guildEvent := range event.Guilds {
+			positions = append(positions, guildEvent.ID)
+		}
+	}
+
+	for _, guildID := range positions {
+		// Already handled in folder processing below
+		if guildsInFolders[guildID] {
+			continue
+		}
+
+		// Orphan guild - add directly to root in order
+		if guildEvent, ok := guildsByID[guildID]; ok {
+			v.guildsTree.createGuildNode(root, guildEvent.Guild)
+		}
+	}
+
+	// Process folders (real folders and single-guild "folders")
+	for _, folder := range event.UserSettings.GuildFolders {
 		if folder.ID == 0 && len(folder.GuildIDs) == 1 {
-			guild, err := v.state.Cabinet.Guild(folder.GuildIDs[0])
-			if err != nil {
-				slog.Error(
-					"failed to get guild from state",
-					"guild_id",
-					folder.GuildIDs[0],
-					"err",
-					err,
-				)
-				continue
+			if guild, ok := guildsByID[folder.GuildIDs[0]]; ok {
+				v.guildsTree.createGuildNode(root, guild.Guild)
 			}
-
-			v.guildsTree.createGuildNode(root, *guild)
 		} else {
-			v.guildsTree.createFolderNode(folder)
+			v.guildsTree.createFolderNode(folder, guildsByID)
 		}
 	}