|
@@ -3,6 +3,7 @@ package chat
|
|
|
import (
|
|
import (
|
|
|
"fmt"
|
|
"fmt"
|
|
|
"log/slog"
|
|
"log/slog"
|
|
|
|
|
+ "strings"
|
|
|
|
|
|
|
|
"github.com/ayn2op/discordo/internal/config"
|
|
"github.com/ayn2op/discordo/internal/config"
|
|
|
"github.com/ayn2op/tview"
|
|
"github.com/ayn2op/tview"
|
|
@@ -21,6 +22,9 @@ type emojiPicker struct {
|
|
|
browseMode bool
|
|
browseMode bool
|
|
|
favorites *emojiFavorites
|
|
favorites *emojiFavorites
|
|
|
|
|
|
|
|
|
|
+ // allItems is cached on picker open; only favorites change on toggle.
|
|
|
|
|
+ allItems []picker.Item
|
|
|
|
|
+
|
|
|
targetMessageID discord.MessageID
|
|
targetMessageID discord.MessageID
|
|
|
targetChannelID discord.ChannelID
|
|
targetChannelID discord.ChannelID
|
|
|
}
|
|
}
|
|
@@ -95,19 +99,29 @@ var commonEmoji = []struct {
|
|
|
{"🏳️", "white_flag surrender"},
|
|
{"🏳️", "white_flag surrender"},
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+// update loads all emoji items (cached) and rebuilds with favorites.
|
|
|
func (ep *emojiPicker) update() {
|
|
func (ep *emojiPicker) update() {
|
|
|
- items := make(picker.Items, 0, maxFavoriteEmoji+len(commonEmoji)+50)
|
|
|
|
|
|
|
+ if ep.allItems == nil {
|
|
|
|
|
+ ep.loadItems()
|
|
|
|
|
+ }
|
|
|
|
|
+ ep.rebuildWithFavorites()
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
- allItems := make(picker.Items, 0, len(commonEmoji)+50)
|
|
|
|
|
|
|
+// loadItems builds the static emoji list (common + guild). Called once per picker open.
|
|
|
|
|
+func (ep *emojiPicker) loadItems() {
|
|
|
|
|
+ items := make(picker.Items, 0, len(commonEmoji)+50)
|
|
|
for _, e := range commonEmoji {
|
|
for _, e := range commonEmoji {
|
|
|
- allItems = append(allItems, picker.Item{
|
|
|
|
|
- Text: e.emoji + " " + e.names[:min(len(e.names), indexOf(e.names, ' '))],
|
|
|
|
|
|
|
+ firstName := e.names
|
|
|
|
|
+ if i := strings.IndexByte(e.names, ' '); i != -1 {
|
|
|
|
|
+ firstName = e.names[:i]
|
|
|
|
|
+ }
|
|
|
|
|
+ items = append(items, picker.Item{
|
|
|
|
|
+ Text: e.emoji + " " + firstName,
|
|
|
FilterText: e.names,
|
|
FilterText: e.names,
|
|
|
Reference: discord.APIEmoji(e.emoji),
|
|
Reference: discord.APIEmoji(e.emoji),
|
|
|
})
|
|
})
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // Guild custom emoji
|
|
|
|
|
selectedChannel := ep.chatView.SelectedChannel()
|
|
selectedChannel := ep.chatView.SelectedChannel()
|
|
|
if selectedChannel != nil && selectedChannel.GuildID.IsValid() {
|
|
if selectedChannel != nil && selectedChannel.GuildID.IsValid() {
|
|
|
emojis, err := ep.chatView.state.Cabinet.Emojis(selectedChannel.GuildID)
|
|
emojis, err := ep.chatView.state.Cabinet.Emojis(selectedChannel.GuildID)
|
|
@@ -116,7 +130,7 @@ func (ep *emojiPicker) update() {
|
|
|
if !emoji.Available {
|
|
if !emoji.Available {
|
|
|
continue
|
|
continue
|
|
|
}
|
|
}
|
|
|
- allItems = append(allItems, picker.Item{
|
|
|
|
|
|
|
+ items = append(items, picker.Item{
|
|
|
Text: ":" + emoji.Name + ":",
|
|
Text: ":" + emoji.Name + ":",
|
|
|
FilterText: emoji.Name,
|
|
FilterText: emoji.Name,
|
|
|
Reference: emoji.APIString(),
|
|
Reference: emoji.APIString(),
|
|
@@ -124,14 +138,17 @@ func (ep *emojiPicker) update() {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+ ep.allItems = items
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
- // Index for favorite lookup.
|
|
|
|
|
- byKey := make(map[string]picker.Item, len(allItems))
|
|
|
|
|
- for _, item := range allItems {
|
|
|
|
|
|
|
+// rebuildWithFavorites prepends favorites to the cached item list.
|
|
|
|
|
+func (ep *emojiPicker) rebuildWithFavorites() {
|
|
|
|
|
+ byKey := make(map[string]picker.Item, len(ep.allItems))
|
|
|
|
|
+ for _, item := range ep.allItems {
|
|
|
byKey[emojiItemKey(item)] = item
|
|
byKey[emojiItemKey(item)] = item
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // Prepend favorites.
|
|
|
|
|
|
|
+ items := make(picker.Items, 0, maxFavoriteEmoji+len(ep.allItems))
|
|
|
favSet := make(map[string]struct{})
|
|
favSet := make(map[string]struct{})
|
|
|
for _, key := range ep.favorites.list() {
|
|
for _, key := range ep.favorites.list() {
|
|
|
if item, ok := byKey[key]; ok {
|
|
if item, ok := byKey[key]; ok {
|
|
@@ -144,7 +161,7 @@ func (ep *emojiPicker) update() {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- for _, item := range allItems {
|
|
|
|
|
|
|
+ for _, item := range ep.allItems {
|
|
|
if _, isFav := favSet[emojiItemKey(item)]; !isFav {
|
|
if _, isFav := favSet[emojiItemKey(item)]; !isFav {
|
|
|
items = append(items, item)
|
|
items = append(items, item)
|
|
|
}
|
|
}
|
|
@@ -160,15 +177,6 @@ func emojiItemKey(item picker.Item) string {
|
|
|
return ""
|
|
return ""
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-func indexOf(s string, c byte) int {
|
|
|
|
|
- for i := range len(s) {
|
|
|
|
|
- if s[i] == c {
|
|
|
|
|
- return i
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- return len(s)
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
func (ep *emojiPicker) HandleEvent(event tview.Event) tview.Command {
|
|
func (ep *emojiPicker) HandleEvent(event tview.Event) tview.Command {
|
|
|
switch event := event.(type) {
|
|
switch event := event.(type) {
|
|
|
case *tview.KeyEvent:
|
|
case *tview.KeyEvent:
|