diff --git a/ui.go b/ui.go index 784a703..2b258a0 100644 --- a/ui.go +++ b/ui.go @@ -75,11 +75,11 @@ func onChannelsTreeSelected(n *tview.TreeNode) { }) // Top-level channels - createTopLevelChannelsTreeNodes(n, g.Channels) + util.CreateTopLevelChannelsNodes(channelsTree, session.State, n, g.Channels) // Category channels - createCategoryChannelsTreeNodes(n, g.Channels) + util.CreateCategoryChannelsNodes(channelsTree, session.State, n, g.Channels) // Second-level channels - createSecondLevelChannelsTreeNodes(g.Channels) + util.CreateSecondLevelChannelsNodes(channelsTree, session.State, g.Channels) } } diff --git a/util.go b/util.go deleted file mode 100644 index e22dffa..0000000 --- a/util.go +++ /dev/null @@ -1,88 +0,0 @@ -package main - -import ( - "github.com/ayntgl/discordgo" - "github.com/ayntgl/discordo/util" - "github.com/rivo/tview" -) - -func createTopLevelChannelsTreeNodes( - n *tview.TreeNode, - cs []*discordgo.Channel, -) { - for _, c := range cs { - if (c.Type == discordgo.ChannelTypeGuildText || c.Type == discordgo.ChannelTypeGuildNews) && - (c.ParentID == "") { - p, err := session.State.UserChannelPermissions(session.State.User.ID, c.ID) - if err != nil || p&discordgo.PermissionViewChannel != discordgo.PermissionViewChannel { - continue - } - - var tag string - if util.ChannelIsUnread(session.State, c) { - tag = "[::b]" - } else { - tag = "[::d]" - } - - cn := tview.NewTreeNode(tag + util.ChannelToString(c) + "[::-]"). - SetReference(c.ID) - n.AddChild(cn) - continue - } - } -} - -func createCategoryChannelsTreeNodes( - n *tview.TreeNode, - cs []*discordgo.Channel, -) { -CategoryLoop: - for _, c := range cs { - if c.Type == discordgo.ChannelTypeGuildCategory { - p, err := session.State.UserChannelPermissions(session.State.User.ID, c.ID) - if err != nil || p&discordgo.PermissionViewChannel != discordgo.PermissionViewChannel { - continue - } - - for _, child := range cs { - if child.ParentID == c.ID { - cn := tview.NewTreeNode(c.Name). - SetReference(c.ID) - n.AddChild(cn) - continue CategoryLoop - } - } - - cn := tview.NewTreeNode(c.Name). - SetReference(c.ID) - n.AddChild(cn) - } - } -} - -func createSecondLevelChannelsTreeNodes(cs []*discordgo.Channel) { - for _, c := range cs { - if (c.Type == discordgo.ChannelTypeGuildText || c.Type == discordgo.ChannelTypeGuildNews) && - (c.ParentID != "") { - p, err := session.State.UserChannelPermissions(session.State.User.ID, c.ID) - if err != nil || p&discordgo.PermissionViewChannel != discordgo.PermissionViewChannel { - continue - } - - var tag string - if util.ChannelIsUnread(session.State, c) { - tag = "[::b]" - } else { - tag = "[::d]" - } - - pn := util.GetTreeNodeByReference(channelsTree, c.ParentID) - if pn != nil { - cn := tview.NewTreeNode(tag + util.ChannelToString(c) + "[::-]"). - SetReference(c.ID) - pn.AddChild(cn) - } - } - } -} diff --git a/util/ui.go b/util/ui.go index 17cf0ad..a735004 100644 --- a/util/ui.go +++ b/util/ui.go @@ -1,6 +1,9 @@ package util -import "github.com/rivo/tview" +import ( + "github.com/ayntgl/discordgo" + "github.com/rivo/tview" +) // GetTreeNodeByReference walks the root `*TreeNode` of the given `*TreeView` *treeView* and returns the TreeNode whose reference is equal to the given reference *r*. If the `*TreeNode` is not found, `nil` is returned instead. func GetTreeNodeByReference(treeView *tview.TreeView, r interface{}) (mn *tview.TreeNode) { @@ -15,3 +18,86 @@ func GetTreeNodeByReference(treeView *tview.TreeView, r interface{}) (mn *tview. return } + +// CreateTopLevelChannelsNodes builds and creates `*tview.TreeNode`s for top-level (channels that have an empty parent ID and of type GUILD_TEXT, GUILD_NEWS) channels. If the client user does not have the VIEW_CHANNEL permission for a channel, the channel is excluded from the parent. +func CreateTopLevelChannelsNodes(treeView *tview.TreeView, s *discordgo.State, n *tview.TreeNode, cs []*discordgo.Channel) { + for _, c := range cs { + if (c.Type == discordgo.ChannelTypeGuildText || c.Type == discordgo.ChannelTypeGuildNews) && + (c.ParentID == "") { + if !HasPermission(s, c.ID, discordgo.PermissionViewChannel) { + continue + } + + n.AddChild(CreateChannelNode(s, c)) + continue + } + } +} + +// CreateCategoryChannelsNodes builds and creates `*tview.TreeNode`s for category (type: GUILD_CATEGORY) channels. If the client user does not have the VIEW_CHANNEL permission for a channel, the channel is excluded from the parent. +func CreateCategoryChannelsNodes(treeView *tview.TreeView, s *discordgo.State, n *tview.TreeNode, cs []*discordgo.Channel) { +CategoryLoop: + for _, c := range cs { + if c.Type == discordgo.ChannelTypeGuildCategory { + if !HasPermission(s, c.ID, discordgo.PermissionViewChannel) { + continue + } + + for _, child := range cs { + if child.ParentID == c.ID { + n.AddChild(CreateChannelNode(s, c)) + continue CategoryLoop + } + } + + n.AddChild(CreateChannelNode(s, c)) + } + } +} + +// CreateSecondLevelChannelsNodes builds and creates `*tview.TreeNode`s for second-level (channels that have a non-empty parent ID and of type GUILD_TEXT, GUILD_NEWS) channels. If the client user does not have the VIEW_CHANNEL permission for a channel, the channel is excluded from the parent. +func CreateSecondLevelChannelsNodes(treeView *tview.TreeView, s *discordgo.State, cs []*discordgo.Channel) { + for _, c := range cs { + if (c.Type == discordgo.ChannelTypeGuildText || c.Type == discordgo.ChannelTypeGuildNews) && + (c.ParentID != "") { + if !HasPermission(s, c.ID, discordgo.PermissionViewChannel) { + continue + } + + pn := GetTreeNodeByReference(treeView, c.ParentID) + if pn != nil { + pn.AddChild(CreateChannelNode(s, c)) + } + } + } +} + +// CreateChannelNode builds (encorporates unread channels in bold tag, otherwise dim, etc.) and returns a node according to the type of the given channel *c*. +func CreateChannelNode(s *discordgo.State, c *discordgo.Channel) *tview.TreeNode { + var cn *tview.TreeNode + switch c.Type { + case discordgo.ChannelTypeGuildText, discordgo.ChannelTypeGuildNews: + tag := "[::d]" + if ChannelIsUnread(s, c) { + tag = "[::b]" + } + + cn = tview.NewTreeNode(tag + ChannelToString(c) + "[::-]"). + SetReference(c.ID) + case discordgo.ChannelTypeGuildCategory: + cn = tview.NewTreeNode(c.Name). + SetReference(c.ID) + } + + return cn +} + +// HasPermission returns a boolean that indicates whether the client user has the given permission *p* in the given channel ID *cID*. +func HasPermission(s *discordgo.State, cID string, p int64) bool { + perm, err := s.UserChannelPermissions(s.User.ID, cID) + if err != nil { + return false + } + + return perm&p == p +}