package ui import ( "cmp" "slices" "strings" "github.com/ayn2op/arikawa/v3/discord" "github.com/ayn2op/discordo/internal/config" "github.com/ayn2op/ningen/v3" "github.com/ayn2op/tview" "github.com/ayn2op/tview/box" "github.com/ayn2op/tview/picker" "github.com/ayn2op/tview/scrollbar" ) // Box returns child in a box styled by the theme, highlighted while focused. func Box(child tview.Element, theme *config.Theme, focused bool) box.Widget { padding := theme.Border.Padding b := box.New(child). Padding(padding[0], padding[1], padding[2], padding[3]). TitleAlignment(theme.Title.Alignment.Alignment). FooterAlignment(theme.Footer.Alignment.Alignment) if theme.Border.Enabled { b = b.Borders(tview.BordersAll) } if focused { return b.BorderStyle(theme.Border.ActiveStyle.Style). BorderSet(theme.Border.ActiveSet.BorderSet). TitleStyle(theme.Title.ActiveStyle.Style). FooterStyle(theme.Footer.ActiveStyle.Style) } return b.BorderStyle(theme.Border.NormalStyle.Style). BorderSet(theme.Border.NormalSet.BorderSet). TitleStyle(theme.Title.NormalStyle.Style). FooterStyle(theme.Footer.NormalStyle.Style) } // Picker returns a picker of items searched with searchState, with the configured scroll bar and keybinds. func Picker(items picker.Items, searchState *picker.SearchState, cfg *config.Config) picker.Widget { bar := scrollbar.New(). TrackStyle(cfg.Theme.ScrollBar.TrackStyle.Style). ThumbStyle(cfg.Theme.ScrollBar.ThumbStyle.Style). GlyphSet(cfg.Theme.ScrollBar.GlyphSet.GlyphSet). Arrows(scrollbar.ArrowsBoth) return picker.New(items, searchState). ScrollBar(bar, cfg.Theme.ScrollBar.Visibility.ScrollBarVisibility). Keybinds(PickerKeybinds(cfg)) } // PickerKeybinds returns the configured picker keybinds. func PickerKeybinds(cfg *config.Config) picker.Keybinds { kbs := cfg.Keybinds.Picker return picker.Keybinds{ Cancel: kbs.Cancel.Keybind, Select: kbs.Select.Keybind, SelectUp: kbs.SelectUp.Keybind, SelectDown: kbs.SelectDown.Keybind, SelectTop: kbs.SelectTop.Keybind, SelectBottom: kbs.SelectBottom.Keybind, } } // ChannelToString returns how channel is shown in the UI: an icon for its type and its name, or the recipients' names for a DM. func ChannelToString(channel discord.Channel, icons config.Icons, state *ningen.State) string { var icon string switch channel.Type { case discord.DirectMessage, discord.GroupDM: if channel.Name != "" { return channel.Name } recipients := make([]string, len(channel.DMRecipients)) for i, r := range channel.DMRecipients { if state != nil && channel.Type == discord.DirectMessage { if rel, ok := state.RelationshipState.FullRelationship(r.ID); ok && rel.Type == discord.FriendRelationship { if rel.Nickname != nil && *rel.Nickname != "" { recipients[i] = *rel.Nickname continue } } } recipients[i] = r.DisplayOrUsername() } return strings.Join(recipients, ", ") case discord.GuildCategory: icon = icons.GuildCategory case discord.GuildText: icon = icons.GuildText case discord.GuildVoice: icon = icons.GuildVoice case discord.GuildStageVoice: icon = icons.GuildStageVoice case discord.GuildAnnouncementThread: icon = icons.GuildAnnouncementThread case discord.GuildPublicThread: icon = icons.GuildPublicThread case discord.GuildPrivateThread: icon = icons.GuildPrivateThread case discord.GuildAnnouncement: icon = icons.GuildAnnouncement case discord.GuildForum: icon = icons.GuildForum case discord.GuildStore: icon = icons.GuildStore } return icon + channel.Name } func SortGuildChannels(channels []discord.Channel) { slices.SortFunc(channels, func(a, b discord.Channel) int { return cmp.Compare(a.Position, b.Position) }) } func SortPrivateChannels(channels []discord.Channel) { slices.SortFunc(channels, func(a, b discord.Channel) int { // Descending order return cmp.Compare(getMessageIDFromChannel(b), getMessageIDFromChannel(a)) }) } func getMessageIDFromChannel(channel discord.Channel) discord.MessageID { if channel.LastMessageID.IsValid() { return channel.LastMessageID } return discord.MessageID(channel.ID) } // IsMe reports whether id is the logged in user. func IsMe(state *ningen.State, id discord.UserID) bool { me, _ := state.Cabinet.Me() return me != nil && id == me.ID }