Guild Creates/removes will now trigger updates in the UI.
MODIFY
ui/channeltree.go
ui/channeltree.go
@@ -58,6 +58,13 @@ func NewChannelTree(state *discordgo.State) *ChannelTree {
return channelTree
}
+// Clear resets all current state.
+func (channelTree *ChannelTree) Clear() {
+ channelTree.channelStates = make(map[*tview.TreeNode]channelState)
+ channelTree.channelPosition = make(map[string]int)
+ channelTree.internalTreeView.GetRoot().ClearChildren()
+}
+
// LoadGuild accesses the state in order to load all locally present channels
// for the passed guild.
func (channelTree *ChannelTree) LoadGuild(guildID string) error {
@@ -66,9 +73,7 @@ func (channelTree *ChannelTree) LoadGuild(guildID string) error {
return cacheError
}
- channelTree.channelStates = make(map[*tview.TreeNode]channelState)
- channelTree.channelPosition = make(map[string]int)
- channelTree.internalTreeView.GetRoot().ClearChildren()
+ channelTree.Clear()
channels := guild.Channels
sort.Slice(channels, func(a, b int) bool {
@@ -222,15 +227,9 @@ func (channelTree *ChannelTree) removeNode(node, parent *tview.TreeNode, channel
}
}
- if childIndex == 0 {
- parent.SetChildren(children[1:])
- } else if childIndex == len(children)-1 {
- parent.SetChildren(children[:len(children)-1])
- } else {
parent.SetChildren(append(children[:childIndex], children[childIndex+1:]...))
}
}
-}
// GetRoot returns the root node of the treeview.
func (channelTree *ChannelTree) GetRoot() *tview.TreeNode {

MODIFY
ui/chatview.go
ui/chatview.go
@@ -251,6 +251,17 @@ OUTER_LOOP:
chatView.Rerender()
}
+// ClearViewAndCache clears the TextView buffer and removes all data for
+// all messages.
+func (chatView *ChatView) ClearViewAndCache() {
+ chatView.data = make([]*discordgo.Message, 0)
+ chatView.showSpoilerContent = make(map[string]bool)
+ chatView.formattedMessages = make(map[string]string)
+ chatView.selection = -1
+ chatView.internalTextView.SetText("")
+ chatView.SetTitle("")
+}
+
func (chatView *ChatView) addMessageInternal(message *discordgo.Message) {
isBlocked := discordutil.IsBlocked(chatView.session.State, message.Author)

ADD
ui/guildlist.go
+package ui
+
+import (
+ "github.com/Bios-Marcel/cordless/config"
+ "github.com/Bios-Marcel/discordgo"
+ "github.com/Bios-Marcel/tview"
+)
+
+// GuildList is the UI component to hold all user guilds and allow loading
+// one of them.
+type GuildList struct {
+ *tview.TreeView
+ onGuildSelect func(node *tview.TreeNode, guildID string)
+}
+
+// NewGuildList creates and initializes a ready to use GuildList.
+func NewGuildList(guilds []*discordgo.Guild, window *Window) *GuildList {
+ guildList := &GuildList{
+ TreeView: tview.NewTreeView(),
+ }
+
+ guildList.
+ SetVimBindingsEnabled(config.GetConfig().OnTypeInListBehaviour == config.DoNothingOnTypeInList).
+ SetCycleSelection(true).
+ SetTopLevel(1).
+ SetBorder(true)
+
+ root := tview.NewTreeNode("")
+ guildList.SetRoot(root)
+ guildList.SetSelectedFunc(func(node *tview.TreeNode) {
+ guildID, ok := node.GetReference().(string)
+ if ok && guildList.onGuildSelect != nil {
+ guildList.onGuildSelect(node, guildID)
+ }
+ })
+
+ for _, guild := range guilds {
+ guildNode := tview.NewTreeNode(guild.Name)
+ guildNode.SetReference(guild.ID)
+ root.AddChild(guildNode)
+
+ window.updateServerReadStatus(guild.ID, guildNode, false)
+
+ guildNode.SetSelectable(true)
+ }
+
+ if len(root.GetChildren()) > 0 {
+ guildList.SetCurrentNode(root)
+ }
+
+ return guildList
+}
+
+// SetOnGuildSelect sets the handler for when a guild is selected.
+func (g *GuildList) SetOnGuildSelect(handler func(node *tview.TreeNode, guildID string)) {
+ g.onGuildSelect = handler
+}
+
+// RemoveGuild removes the node that refers to the given guildID.
+func (g *GuildList) RemoveGuild(guildID string) {
+ children := g.GetRoot().GetChildren()
+ indexToRemove := -1
+ for index, node := range children {
+ if node.GetReference() == guildID {
+ indexToRemove = index
+ break
+ }
+ }
+
+ if indexToRemove != -1 {
+ g.GetRoot().SetChildren(append(children[:indexToRemove], children[indexToRemove+1:]...))
+ }
+}
+
+// AddGuild adds a new node that references the given guildID and shows the
+// given name.
+func (g *GuildList) AddGuild(guildID, name string) {
+ node := tview.NewTreeNode(name)
+ node.SetReference(guildID)
+ g.GetRoot().AddChild(node)
+}

MODIFY
ui/window.go
ui/window.go
@@ -51,7 +51,7 @@ type Window struct {
currentContainer tview.Primitive
leftArea *tview.Pages
- guildList *tview.TreeView
+ guildList *GuildList
channelTree *ChannelTree
privateList *PrivateChatList
@@ -87,7 +87,7 @@ type Window struct {
//necessary handlers and functions. If this function returns an error, we can't
//start the application.
func NewWindow(doRestart chan bool, app *tview.Application, session *discordgo.Session, readyEvent *discordgo.Ready) (*Window, error) {
- window := Window{
+ window := &Window{
doRestart: doRestart,
session: session,
app: app,
@@ -139,26 +139,13 @@ func NewWindow(doRestart chan bool, app *tview.Application, session *discordgo.S
})
window.registerGuildChannelHandler()
- guildList := tview.NewTreeView().
- SetVimBindingsEnabled(config.GetConfig().OnTypeInListBehaviour == config.DoNothingOnTypeInList).
- SetCycleSelection(true)
- window.guildList = guildList
-
- guildRootNode := tview.NewTreeNode("")
- guildList.SetRoot(guildRootNode)
- guildList.SetBorder(true)
- guildList.SetTopLevel(1)
- guildList.SetSelectedFunc(func(node *tview.TreeNode) {
+ discordutil.SortGuilds(window.session.State.Settings, guilds)
+ guildList := NewGuildList(guilds, window)
+ guildList.SetOnGuildSelect(func(node *tview.TreeNode, guildID string) {
if window.selectedGuildNode != nil {
window.updateServerReadStatus(window.selectedGuild.ID, window.selectedGuildNode, false)
}
- guildID, ok := node.GetReference().(string)
- if !ok {
- window.ShowErrorDialog("Guild couldn't be loaded.")
- return
- }
-
guild, cacheError := window.session.Guild(guildID)
if cacheError != nil {
window.ShowErrorDialog(cacheError.Error())
@@ -191,26 +178,11 @@ func NewWindow(doRestart chan bool, app *tview.Application, session *discordgo.S
window.RefreshLayout()
})
+ window.guildList = guildList
+ window.registerGuildHandlers()
window.registerGuildMemberHandlers()
- discordutil.SortGuilds(window.session.State.Settings, guilds)
-
- for _, tempGuild := range guilds {
- guild := tempGuild
- guildNode := tview.NewTreeNode(guild.Name)
- guildNode.SetReference(guild.ID)
- guildRootNode.AddChild(guildNode)
-
- window.updateServerReadStatus(guild.ID, guildNode, false)
-
- guildNode.SetSelectable(true)
- }
-
- if len(guildRootNode.GetChildren()) > 0 {
- guildList.SetCurrentNode(guildRootNode)
- }
-
guildPage.AddItem(guildList, 0, 1, true)
guildPage.AddItem(channelTree.internalTreeView, 0, 2, true)
@@ -947,7 +919,7 @@ func NewWindow(doRestart chan bool, app *tview.Application, session *discordgo.S
log.SetOutput(window.commandView)
- return &window, nil
+ return window, nil
}
func (window *Window) updateServerReadStatus(guildID string, guildNode *tview.TreeNode, isSelected bool) {
@@ -1362,6 +1334,55 @@ func (window *Window) startMessageHandlerRoutines(input, edit, delete chan *disc
}()
}
+func (window *Window) registerGuildHandlers() {
+ //Using buffered channels with a size of three, since this shouldn't really happen often
+
+ guildCreateChannel := make(chan *discordgo.GuildCreate, 3)
+ window.session.AddHandler(func(s *discordgo.Session, guildCreate *discordgo.GuildCreate) {
+ guildCreateChannel <- guildCreate
+ })
+
+ guildRemoveChannel := make(chan *discordgo.GuildDelete, 3)
+ window.session.AddHandler(func(s *discordgo.Session, guildRemove *discordgo.GuildDelete) {
+ guildRemoveChannel <- guildRemove
+ })
+
+ go func() {
+ for guildCreate := range guildCreateChannel {
+ window.app.QueueUpdateDraw(func() {
+ window.guildList.AddGuild(guildCreate.ID, guildCreate.Name)
+ })
+ }
+ }()
+
+ go func() {
+ for guildRemove := range guildRemoveChannel {
+ clearChannelTree := window.selectedGuildNode.GetReference() == guildRemove.ID
+ var isInGuildChannel bool
+
+ if window.selectedChannel != nil && window.selectedChannel.GuildID == guildRemove.ID {
+ isInGuildChannel = true
+ }
+
+ window.selectedGuildNode = nil
+ window.selectedGuild = nil
+
+ window.app.QueueUpdateDraw(func() {
+ if clearChannelTree {
+ window.channelTree.Clear()
+ }
+
+ if isInGuildChannel {
+ window.userList.Clear()
+ window.chatView.ClearViewAndCache()
+ }
+
+ window.guildList.RemoveGuild(guildRemove.ID)
+ })
+ }
+ }()
+}
+
func (window *Window) registerGuildMemberHandlers() {
window.session.AddHandler(func(s *discordgo.Session, event *discordgo.GuildMembersChunk) {
if window.selectedGuild != nil && window.selectedGuild.ID == event.GuildID {

Guild Creates/removes will now trigger updates in the UI.