Path: blob/main/internal/messages/composer/autocomplete_emojis.go
366 views
package composer12import (3"context"4"fmt"5"html"6"sort"7"time"89"github.com/diamondburned/arikawa/v3/discord"10"github.com/diamondburned/chatkit/components/autocomplete"11"github.com/diamondburned/gotk4/pkg/gtk/v4"12"github.com/diamondburned/gotk4/pkg/pango"13"github.com/diamondburned/gotkit/components/onlineimage"14"github.com/diamondburned/gotkit/gtkutil/cssutil"15"github.com/diamondburned/gotkit/gtkutil/imgutil"16"github.com/diamondburned/ningen/v3/states/emoji"17"github.com/sahilm/fuzzy"18"libdb.so/dissent/internal/gtkcord"1920unicodeemoji "github.com/enescakir/emoji"21)2223const (24maxAutocompletion = 1525emojiCacheExpiry = time.Minute26)2728type emojis []EmojiData2930func (e emojis) Len() int { return len(e) }31func (e emojis) String(i int) string { return e[i].EmojiName + " " + e[i].GuildName }3233type emojiCompleter struct {34emojis emojis35matched []autocomplete.Data36updated time.Time37guildID discord.GuildID38}3940var unicodeEmojis = unicodeemoji.Map()4142// NewEmojiCompleter creaets a new autocomplete searcher that searches for43// emojis.44func NewEmojiCompleter(gID discord.GuildID) autocomplete.Searcher {45return &emojiCompleter{46guildID: gID,47matched: make([]autocomplete.Data, 0, maxAutocompletion),48}49}5051func (c *emojiCompleter) Rune() rune { return ':' }5253func (c *emojiCompleter) Search(ctx context.Context, str string) []autocomplete.Data {54if len(str) < 2 {55return nil56}5758now := time.Now()5960state := gtkcord.FromContext(ctx)61hasNitro := state.EmojiState.HasNitro()6263if c.emojis != nil && c.updated.Add(emojiCacheExpiry).After(now) {64return c.search(str, hasNitro)65}6667c.updated = now6869if c.emojis != nil {70c.emojis = c.emojis[:0]71} else {72c.emojis = make(emojis, 0, len(unicodeEmojis)+64)73}7475for name, unicode := range unicodeEmojis {76c.emojis = append(c.emojis, EmojiData{77Emoji: &discord.Emoji{Name: unicode},78EmojiName: name,79})80}8182var emojis []emoji.Guild83if showAllEmojis.Value() {84emojis, _ = state.EmojiState.AllEmojis()85} else {86emojis, _ = state.EmojiState.ForGuild(c.guildID)87}8889for i, guild := range emojis {90for j, emoji := range guild.Emojis {91c.emojis = append(c.emojis, EmojiData{92GuildID: guild.ID,93GuildName: guild.Name,94Emoji: &emojis[i].Emojis[j],95EmojiName: emoji.Name,96})97}98}99100return c.search(str, hasNitro)101}102103func (c *emojiCompleter) search(str string, hasNitro bool) []autocomplete.Data {104res := fuzzy.FindFrom(str, c.emojis)105if len(res) > maxAutocompletion {106res = res[:maxAutocompletion]107}108109data := c.matched[:0]110for _, r := range res {111data = append(data, c.emojis[r.Index])112}113114// Put the guild emojis first if we don't have Nitro.115if !hasNitro {116sort.SliceStable(data, func(i, j int) bool {117a := data[i].(EmojiData)118b := data[j].(EmojiData)119correctA := a.GuildID == c.guildID120correctB := b.GuildID == c.guildID121return correctA && !correctB122})123}124125return data126}127128// EmojiData is the Data structure for each emoji.129type EmojiData struct {130GuildID discord.GuildID131GuildName string132Emoji *discord.Emoji133EmojiName string134}135136const emojiSize = 32 // px137138var _ = cssutil.WriteCSS(`139.autocompleter-unicode {140font-size: 26px;141}142`)143144// Row satisfies autocomplete.Data.145func (d EmojiData) Row(ctx context.Context) *gtk.ListBoxRow {146b := gtk.NewBox(gtk.OrientationHorizontal, 4)147markup := html.EscapeString(d.EmojiName)148149if !d.Emoji.ID.IsValid() {150l := gtk.NewLabel(d.Emoji.Name)151l.AddCSSClass("autocompleter-unicode")152153b.Append(l)154} else {155i := onlineimage.NewImage(ctx, imgutil.HTTPProvider)156i.AddCSSClass("autocompleter-customemoji")157i.SetSizeRequest(emojiSize, emojiSize)158i.SetFromURL(gtkcord.EmojiURL(d.Emoji.ID.String(), false))159160b.Append(i)161162markup += "\n" + fmt.Sprintf(163`<span size="smaller" fgalpha="75%%" rise="-1200">%s</span>`,164html.EscapeString(d.GuildName),165)166}167168l := gtk.NewLabel("")169l.SetMaxWidthChars(35)170l.SetEllipsize(pango.EllipsizeEnd)171l.SetMarkup(markup)172b.Append(l)173174r := gtk.NewListBoxRow()175r.AddCSSClass("autocomplete-emoji")176r.SetChild(b)177178return r179}180181182