Skip to content
This repository was archived by the owner on Dec 16, 2021. It is now read-only.

Commit 42a4104

Browse files
committed
Reaction rendering
Reactions can now be rendered inline. This can be toggled via the `ShowReactionsInline` configuration field.
1 parent 041a842 commit 42a4104

File tree

4 files changed

+146
-2
lines changed

4 files changed

+146
-2
lines changed

config/config.go

+4
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,9 @@ type Config struct {
145145
// application, as there are some childish goons that deem it funny
146146
// to impersonate people or change their name every 5 minutes.
147147
ShowNicknames bool
148+
// ShowReactionsInline decides whether reactions are displayed below a
149+
// message.
150+
ShowReactionsInline bool
148151

149152
// FileHandlers allow registering specific file-handers for certain
150153
FileOpenHandlers map[string]string
@@ -208,6 +211,7 @@ func createDefaultConfig() *Config {
208211
IndicateChannelAccessRestriction: false,
209212
ShowBottomBar: true,
210213
ShowNicknames: true,
214+
ShowReactionsInline: true,
211215
FileOpenHandlers: make(map[string]string),
212216
FileOpenSaveFilesPermanently: false,
213217
FileDownloadSaveLocation: "~/Downloads",

discordutil/message.go

+48
Original file line numberDiff line numberDiff line change
@@ -245,3 +245,51 @@ func ReplaceMentions(message *discordgo.Message) string {
245245
}
246246
return strings.NewReplacer(replaceInstructions...).Replace(message.Content)
247247
}
248+
249+
// HandleReactionAdd adds a new reaction to a message or updates the count if
250+
// that message already has a reaction with that same emoji.
251+
func HandleReactionAdd(state *discordgo.State,
252+
message *discordgo.Message,
253+
newReaction *discordgo.MessageReactionAdd) {
254+
for _, reaction := range message.Reactions {
255+
//Only custom emojis have IDs and non custom unes have unique names.
256+
if reaction.Emoji.ID == newReaction.Emoji.ID && reaction.Emoji.Name == newReaction.Emoji.Name {
257+
//Match found, so we can add one to the count.
258+
reaction.Count++
259+
return
260+
}
261+
}
262+
263+
//FIXME Better look up emoji in cache if possible?
264+
message.Reactions = append(message.Reactions, &discordgo.MessageReactions{
265+
Count: 1,
266+
Emoji: &newReaction.Emoji,
267+
Me: newReaction.UserID == state.User.ID,
268+
})
269+
}
270+
271+
// HandleReactionRemove removes an existing reaction to a message or updates
272+
// the count if the same message still has reactions with the same emoji left.
273+
func HandleReactionRemove(state *discordgo.State,
274+
message *discordgo.Message,
275+
newReaction *discordgo.MessageReactionRemove) {
276+
for index, reaction := range message.Reactions {
277+
//Only custom emojis have IDs and non custom unes have unique names.
278+
if reaction.Emoji.ID == newReaction.Emoji.ID && reaction.Emoji.Name == newReaction.Emoji.Name {
279+
if reaction.Count <= 1 {
280+
message.Reactions = append(message.Reactions[:index], message.Reactions[index+1:]...)
281+
//No more reactions of that emoji would be left, therefore we remove the array entry.
282+
} else {
283+
//Only a single user removed his reaction, so we keep the array entry.
284+
reaction.Count--
285+
}
286+
return
287+
}
288+
}
289+
}
290+
291+
// HandleReactionRemoveAll removes all reactions from all users in a message.
292+
func HandleReactionRemoveAll(state *discordgo.State,
293+
message *discordgo.Message) {
294+
message.Reactions = message.Reactions[0:0]
295+
}

ui/chatview.go

+26-2
Original file line numberDiff line numberDiff line change
@@ -714,8 +714,32 @@ func (chatView *ChatView) formatDefaultMessageText(message *discordgo.Message) s
714714
}
715715
}
716716

717+
var reactionText string
718+
if len(message.Reactions) > 0 {
719+
var reactionBuilder strings.Builder
720+
reactionBuilder.Grow(10 + len(message.Reactions)*8)
721+
reactionBuilder.WriteString("\nReactions: ")
722+
for rIndex, reaction := range message.Reactions {
723+
if reaction.Emoji.Name != "" {
724+
reactionBuilder.WriteString(tviewutil.Escape(reaction.Emoji.Name))
725+
if reaction.Me {
726+
reactionBuilder.WriteString("[::r]")
727+
}
728+
reactionBuilder.WriteRune('-')
729+
reactionBuilder.WriteString(strconv.FormatInt(int64(reaction.Count), 10))
730+
if reaction.Me {
731+
reactionBuilder.WriteString("[::-]")
732+
}
733+
if rIndex != len(message.Reactions)-1 {
734+
reactionBuilder.WriteRune(' ')
735+
}
736+
}
737+
}
738+
reactionText = reactionBuilder.String()
739+
}
740+
717741
if !hasRichEmbed {
718-
return messageText
742+
return messageText + reactionText
719743
}
720744

721745
var messageBuffer strings.Builder
@@ -808,7 +832,7 @@ func (chatView *ChatView) formatDefaultMessageText(message *discordgo.Message) s
808832
embedBuffer.WriteRune('\n')
809833
}
810834

811-
return messageBuffer.String()
835+
return messageBuffer.String() + reactionText
812836
}
813837

814838
func parseCustomEmojis(text string) string {

ui/window.go

+68
Original file line numberDiff line numberDiff line change
@@ -742,6 +742,7 @@ func NewWindow(app *tview.Application, session *discordgo.Session, readyEvent *d
742742

743743
window.registerMessageEventHandler(messageInputChan, messageEditChan, messageDeleteChan, messageBulkDeleteChan)
744744
window.startMessageHandlerRoutines(messageInputChan, messageEditChan, messageDeleteChan, messageBulkDeleteChan)
745+
window.registerReactionEventHandlers()
745746

746747
window.userList = NewUserTree(window.session.State)
747748

@@ -1653,6 +1654,73 @@ func (window *Window) registerMessageEventHandler(input, edit, delete chan *disc
16531654
})
16541655
}
16551656

1657+
// registerReactionEventHandlers are responsible for updating the cache if
1658+
// reactions are added or removed and updating the chatview if needed.
1659+
func (window *Window) registerReactionEventHandlers() {
1660+
window.session.AddHandler(func(s *discordgo.Session, m *discordgo.MessageReactionAdd) {
1661+
message, stateError := s.State.Message(m.ChannelID, m.MessageID)
1662+
if message != nil && stateError == nil {
1663+
s.State.Lock()
1664+
defer func() {
1665+
selectedChannel := window.selectedChannel
1666+
if selectedChannel != nil && selectedChannel.ID == m.ChannelID {
1667+
window.app.QueueUpdateDraw(func() {
1668+
window.chatView.Lock()
1669+
defer window.chatView.Unlock()
1670+
1671+
window.chatView.UpdateMessage(message)
1672+
})
1673+
}
1674+
}()
1675+
defer s.State.Unlock()
1676+
1677+
discordutil.HandleReactionAdd(s.State, message, m)
1678+
}
1679+
})
1680+
1681+
window.session.AddHandler(func(s *discordgo.Session, m *discordgo.MessageReactionRemove) {
1682+
message, stateError := s.State.Message(m.ChannelID, m.MessageID)
1683+
if message != nil && stateError == nil {
1684+
s.State.Lock()
1685+
defer func() {
1686+
selectedChannel := window.selectedChannel
1687+
if selectedChannel != nil && selectedChannel.ID == m.ChannelID {
1688+
window.app.QueueUpdateDraw(func() {
1689+
window.chatView.Lock()
1690+
defer window.chatView.Unlock()
1691+
1692+
window.chatView.UpdateMessage(message)
1693+
})
1694+
}
1695+
}()
1696+
defer s.State.Unlock()
1697+
1698+
discordutil.HandleReactionRemove(s.State, message, m)
1699+
}
1700+
})
1701+
1702+
window.session.AddHandler(func(s *discordgo.Session, m *discordgo.MessageReactionRemoveAll) {
1703+
message, stateError := s.State.Message(m.ChannelID, m.MessageID)
1704+
if message != nil && stateError == nil {
1705+
s.State.Lock()
1706+
defer func() {
1707+
selectedChannel := window.selectedChannel
1708+
if selectedChannel != nil && selectedChannel.ID == m.ChannelID {
1709+
window.app.QueueUpdateDraw(func() {
1710+
window.chatView.Lock()
1711+
defer window.chatView.Unlock()
1712+
1713+
window.chatView.UpdateMessage(message)
1714+
})
1715+
}
1716+
}()
1717+
defer s.State.Unlock()
1718+
1719+
discordutil.HandleReactionRemoveAll(s.State, message)
1720+
}
1721+
})
1722+
}
1723+
16561724
// QueueUpdateDrawSynchronized is meant to be used by goroutines that aren't
16571725
// the main goroutine in order to wait for the UI-Thread to execute the given
16581726
// If this method is ever called from the main thread, the application will

0 commit comments

Comments
 (0)