/
embed_menus.go
179 lines (158 loc) · 4.81 KB
/
embed_menus.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
package gommand
import (
"context"
"fmt"
"github.com/andersfylling/disgord"
"github.com/andersfylling/snowflake/v4"
"sync"
)
// This is used to represent all of the current menus.
var menuCache = map[string]*EmbedMenu{}
// This is the thread lock for the menu cache.
var menuCacheLock = sync.RWMutex{}
// MenuInfo contains the information about the menu.
type MenuInfo struct {
Author string
Info []string
}
// MenuButton is the datatype containing information about the button.
type MenuButton struct {
Emoji string
Name string
Description string
}
// MenuReaction represents the button and the function which it triggers.
type MenuReaction struct {
Button MenuButton
Function func(ChannelID, MessageID snowflake.Snowflake, _ *EmbedMenu, client disgord.Session)
}
// MenuReactions are all of the reactions which the menu has.
type MenuReactions struct {
ReactionSlice []MenuReaction
}
// EmbedMenu is the base menu.
type EmbedMenu struct {
Reactions *MenuReactions
parent *EmbedMenu
Embed *disgord.Embed
MenuInfo *MenuInfo
}
// Add is used to add a menu reaction.
func (mr *MenuReactions) Add(reaction MenuReaction) {
Slice := append(mr.ReactionSlice, reaction)
mr.ReactionSlice = Slice
}
// AddParent is used to add a new parent menu.
func (e *EmbedMenu) AddParentMenu(Menu *EmbedMenu) {
e.parent = Menu
}
// Display is used to show a menu. This is un-protected so that people can write their own things on top of embed menus, but you probably want to use ctx.DisplayEmbedMenu(menu).
func (e *EmbedMenu) Display(ChannelID, MessageID snowflake.Snowflake, client disgord.Session) error {
menuCacheLock.Lock()
menuCache[MessageID.String()] = e
menuCacheLock.Unlock()
EmbedCopy := e.Embed.DeepCopy().(*disgord.Embed)
Fields := make([]*disgord.EmbedField, 0)
for _, k := range e.Reactions.ReactionSlice {
Fields = append(Fields, &disgord.EmbedField{
Name: fmt.Sprintf("%s %s", k.Button.Emoji, k.Button.Name),
Value: k.Button.Description,
Inline: false,
})
}
EmbedCopy.Fields = append(EmbedCopy.Fields, Fields...)
_, err := client.UpdateMessage(context.TODO(), ChannelID, MessageID).SetContent("").SetEmbed(EmbedCopy).Execute()
if err != nil {
return err
}
for _, k := range e.Reactions.ReactionSlice {
err := client.CreateReaction(context.TODO(), ChannelID, MessageID, k.Button.Emoji)
if err != nil {
return err
}
}
return nil
}
// NewChildMenu is used to create a new child menu.
func (e *EmbedMenu) NewChildMenu(embed *disgord.Embed, item MenuButton) *EmbedMenu {
NewEmbedMenu := &EmbedMenu{
Reactions: &MenuReactions{
ReactionSlice: []MenuReaction{},
},
Embed: embed,
MenuInfo: e.MenuInfo,
}
NewEmbedMenu.parent = e
Reaction := MenuReaction{
Button: item,
Function: func(ChannelID, MessageID snowflake.Snowflake, _ *EmbedMenu, client disgord.Session) {
_ = client.DeleteAllReactions(context.TODO(), ChannelID, MessageID)
_ = NewEmbedMenu.Display(ChannelID, MessageID, client)
},
}
e.Reactions.Add(Reaction)
return NewEmbedMenu
}
// AddBackButton is used to add a back Button to the page.
func (e *EmbedMenu) AddBackButton() {
Reaction := MenuReaction{
Button: MenuButton{
Description: "Goes back to the parent menu.",
Name: "Back",
Emoji: "⬆",
},
Function: func(ChannelID, MessageID snowflake.Snowflake, _ *EmbedMenu, client disgord.Session) {
_ = client.DeleteAllReactions(context.TODO(), ChannelID, MessageID)
_ = e.parent.Display(ChannelID, MessageID, client)
},
}
e.Reactions.Add(Reaction)
}
// NewEmbedMenu is used to create a new menu handler.
func NewEmbedMenu(embed *disgord.Embed, ctx *Context) *EmbedMenu {
var reactions []MenuReaction
menu := &EmbedMenu{
Reactions: &MenuReactions{
ReactionSlice: reactions,
},
Embed: embed,
MenuInfo: &MenuInfo{
Author: ctx.Message.Author.ID.String(),
Info: []string{},
},
}
return menu
}
// This is used to handle menu reactions.
func handleMenuReactionEdit(s disgord.Session, evt *disgord.MessageReactionAdd) {
go func() {
// Get the menu if it exists.
menuCacheLock.RLock()
menu := menuCache[evt.MessageID.String()]
if menu == nil {
menuCacheLock.RUnlock()
return
}
menuCacheLock.RUnlock()
// Remove the reaction.
_ = s.DeleteUserReaction(context.TODO(), evt.ChannelID, evt.MessageID, evt.UserID, evt.PartialEmoji)
// Check the author of the reaction.
if menu.MenuInfo.Author != evt.UserID.String() {
return
}
for _, v := range menu.Reactions.ReactionSlice {
if v.Button.Emoji == evt.PartialEmoji.Name {
v.Function(evt.ChannelID, evt.MessageID, menu, s)
return
}
}
}()
}
// Handle messages being deleted to stop memory leaks.
func handleEmbedMenuMessageDelete(s disgord.Session, evt *disgord.MessageDelete) {
go func() {
menuCacheLock.Lock()
delete(menuCache, evt.MessageID.String())
menuCacheLock.Unlock()
}()
}