Added member list support

This commit is contained in:
diamondburned 2020-08-15 15:37:44 -07:00
parent afed1e13ad
commit cdd9b68043
13 changed files with 356 additions and 49 deletions

View File

@ -10,8 +10,8 @@ import (
)
type Category struct {
id discord.Snowflake
guildID discord.Snowflake
id discord.ChannelID
guildID discord.GuildID
session *Session
}

View File

@ -37,16 +37,16 @@ func filterAccessible(s *Session, chs []discord.Channel) []discord.Channel {
return filtered
}
func filterCategory(chs []discord.Channel, catID discord.Snowflake) []discord.Channel {
func filterCategory(chs []discord.Channel, catID discord.ChannelID) []discord.Channel {
var filtered = chs[:0]
var catvalid = catID.Valid()
var catvalid = catID.IsValid()
for _, ch := range chs {
switch {
// If the given ID is not valid, then we look for channels with
// similarly invalid category IDs, because yes, Discord really sends
// inconsistent responses.
case !catvalid && !ch.CategoryID.Valid():
case !catvalid && !ch.CategoryID.IsValid():
fallthrough
// Basic comparison.
case ch.CategoryID == catID:
@ -60,8 +60,8 @@ func filterCategory(chs []discord.Channel, catID discord.Snowflake) []discord.Ch
}
type Channel struct {
id discord.Snowflake
guildID discord.Snowflake
id discord.ChannelID
guildID discord.GuildID
session *Session
}
@ -109,7 +109,7 @@ func (ch *Channel) messages() ([]discord.Message, error) {
}
func (ch *Channel) guild() (*discord.Guild, error) {
if ch.guildID.Valid() {
if ch.guildID.IsValid() {
return ch.session.Guild(ch.guildID)
}
return nil, errors.New("channel not in a guild")
@ -134,7 +134,7 @@ func (ch *Channel) Name() text.Rich {
func (ch *Channel) Nickname(ctx context.Context, labeler cchat.LabelContainer) (func(), error) {
// We don't have a nickname if we're not in a guild.
if !ch.guildID.Valid() {
if !ch.guildID.IsValid() {
return func() {}, nil
}
@ -199,7 +199,7 @@ func (ch *Channel) JoinServer(ctx context.Context, ct cchat.MessagesContainer) (
var constructor func(discord.Message) cchat.MessageCreate
if ch.guildID.Valid() {
if ch.guildID.IsValid() {
// Create the backlog without any member information.
g, err := state.Guild(ch.guildID)
if err != nil {
@ -295,7 +295,7 @@ func (ch *Channel) MessageEditable(id string) bool {
return false
}
m, err := ch.session.Store.Message(ch.id, s)
m, err := ch.session.Store.Message(ch.id, discord.MessageID(s))
if err != nil {
return false
}
@ -310,7 +310,7 @@ func (ch *Channel) RawMessageContent(id string) (string, error) {
return "", errors.Wrap(err, "Failed to parse ID")
}
m, err := ch.session.Store.Message(ch.id, s)
m, err := ch.session.Store.Message(ch.id, discord.MessageID(s))
if err != nil {
return "", errors.Wrap(err, "Failed to get the message")
}
@ -325,7 +325,7 @@ func (ch *Channel) EditMessage(id, content string) error {
return errors.Wrap(err, "Failed to parse ID")
}
_, err = ch.session.EditText(ch.id, s, content)
_, err = ch.session.EditText(ch.id, discord.MessageID(s), content)
return err
}
@ -343,7 +343,7 @@ func (ch *Channel) DoMessageAction(action, id string) error {
switch action {
case ActionDelete:
return ch.session.DeleteMessage(ch.id, s)
return ch.session.DeleteMessage(ch.id, discord.MessageID(s))
default:
return ErrUnknownAction
}
@ -355,7 +355,7 @@ func (ch *Channel) MessageActions(id string) []string {
return nil
}
m, err := ch.session.Store.Message(ch.id, s)
m, err := ch.session.Store.Message(ch.id, discord.MessageID(s))
if err != nil {
return nil
}
@ -384,9 +384,9 @@ func (ch *Channel) MessageActions(id string) []string {
// canManageMessages returns whether or not the user is allowed to manage
// messages.
func (ch *Channel) canManageMessages(userID discord.Snowflake) bool {
func (ch *Channel) canManageMessages(userID discord.UserID) bool {
// If we're not in a guild, then clearly we cannot.
if !ch.guildID.Valid() {
if !ch.guildID.IsValid() {
return false
}
@ -438,7 +438,7 @@ func (ch *Channel) TypingSubscribe(ti cchat.TypingIndicator) (func(), error) {
// muted returns if this channel is muted. This includes the channel's category
// and guild.
func (ch *Channel) muted() bool {
return (ch.guildID.Valid() && ch.session.MutedState.Guild(ch.guildID, false)) ||
return (ch.guildID.IsValid() && ch.session.MutedState.Guild(ch.guildID, false)) ||
ch.session.MutedState.Channel(ch.id) ||
ch.session.MutedState.Category(ch.id)
}

View File

@ -40,7 +40,7 @@ func (ch *SendableChannel) completeMentions(word string) (entries []cchat.Comple
// Keep track of the number of authors.
// TODO: fix excess allocations
var authors = make(map[discord.Snowflake]struct{}, MaxCompletion)
var authors = make(map[discord.UserID]struct{}, MaxCompletion)
for _, msg := range msgs {
// If we've already added the author into the list, then skip.
@ -65,7 +65,7 @@ func (ch *SendableChannel) completeMentions(word string) (entries []cchat.Comple
var match = strings.ToLower(word)
// If we're not in a guild, then we can check the list of recipients.
if !ch.guildID.Valid() {
if !ch.guildID.IsValid() {
c, err := ch.self()
if err != nil {
return
@ -127,7 +127,7 @@ func (ch *SendableChannel) completeChannels(word string) (entries []cchat.Comple
}
// Ignore if we're not in a guild.
if !ch.guildID.Valid() {
if !ch.guildID.IsValid() {
return
}
@ -144,7 +144,7 @@ func (ch *SendableChannel) completeChannels(word string) (entries []cchat.Comple
}
var category string
if channel.CategoryID.Valid() {
if channel.CategoryID.IsValid() {
if c, _ := ch.session.Store.Channel(channel.CategoryID); c != nil {
category = c.Name
}

View File

@ -1 +1,276 @@
package discord
import (
"context"
"fmt"
"strconv"
"github.com/diamondburned/arikawa/discord"
"github.com/diamondburned/arikawa/gateway"
"github.com/diamondburned/cchat"
"github.com/diamondburned/cchat-discord/segments"
"github.com/diamondburned/cchat/text"
"github.com/diamondburned/ningen/states/member"
)
func seekPrevGroup(l *member.List, ix int) (item, group gateway.GuildMemberListOpItem) {
l.ViewItems(func(items []gateway.GuildMemberListOpItem) {
item = items[ix]
// Search backwards.
for i := ix; i >= 0; i-- {
if items[i].Group != nil {
group = items[i]
return
}
}
})
return
}
func (ch *Channel) ListMembers(ctx context.Context, c cchat.MemberListContainer) (func(), error) {
if !ch.guildID.IsValid() {
return func() {}, nil
}
cancel := ch.session.AddHandler(func(u *gateway.GuildMemberListUpdate) {
l, err := ch.session.MemberState.GetMemberList(ch.guildID, ch.id)
if err != nil {
return // wat
}
for _, ev := range u.Ops {
switch ev.Op {
case "SYNC":
ch.checkSync(c)
case "INSERT", "UPDATE":
item, group := seekPrevGroup(l, ev.Index)
if item.Member != nil && group.Group != nil {
c.SetMember(group.Group.ID, NewListMember(ev.Index, ch, item))
}
case "DELETE":
_, group := seekPrevGroup(l, ev.Index-1)
if group.Group != nil {
c.RemoveMember(group.Group.ID, strconv.Itoa(ev.Index))
}
}
}
})
ch.session.MemberState.RequestMemberList(ch.guildID, ch.id, 0)
return cancel, nil
}
func (ch *Channel) checkSync(c cchat.MemberListContainer) {
l, err := ch.session.MemberState.GetMemberList(ch.guildID, ch.id)
if err != nil {
ch.session.MemberState.RequestMemberList(ch.guildID, ch.id, 0)
return
}
var sectionKeys []string
var sectionsMap map[string]*ListSection
l.ViewGroups(func(groups []gateway.GuildMemberListGroup) {
sectionKeys = make([]string, 0, len(groups))
sectionsMap = make(map[string]*ListSection, len(groups))
for _, group := range groups {
sectionKeys = append(sectionKeys, group.ID)
sectionsMap[group.ID] = NewListSection(l.ID(), ch, group)
}
var sections = make([]cchat.MemberListSection, len(sectionKeys))
for i, key := range sectionKeys {
sections[i] = sectionsMap[key]
}
c.SetSections(sections)
})
l.ViewItems(func(items []gateway.GuildMemberListOpItem) {
var group gateway.GuildMemberListGroup
for i, item := range items {
switch {
case item.Group != nil:
group = *item.Group
case item.Member != nil:
c.SetMember(group.ID, NewListMember(i, ch, item))
}
}
})
}
type ListMember struct {
ix int // experiment with this being the index
// Keep stateful references to do on-demand loading.
channel *Channel
// constant states
userID discord.UserID
roleID discord.RoleID
origName string // use if cache is stale
}
var _ cchat.ListMember = (*ListMember)(nil)
// NewListMember creates a new list member. it.Member must not be nil.
func NewListMember(ix int, ch *Channel, it gateway.GuildMemberListOpItem) *ListMember {
roleID, _ := discord.ParseSnowflake(it.Member.HoistedRole)
return &ListMember{
ix: ix,
channel: ch,
userID: it.Member.User.ID,
roleID: discord.RoleID(roleID),
}
}
func (l *ListMember) ID() string {
return strconv.Itoa(l.ix)
}
func (l *ListMember) Name() text.Rich {
n, err := l.channel.session.MemberDisplayName(l.channel.guildID, l.userID)
if err != nil {
return text.Plain(l.origName)
}
r, err := l.channel.session.State.Role(l.channel.guildID, l.roleID)
if err != nil {
return text.Plain(l.origName)
}
return text.Rich{
Content: n,
Segments: []text.Segment{segments.NewColored(len(n), uint32(r.Color))},
}
}
func (l *ListMember) Status() cchat.UserStatus {
p, err := l.channel.session.State.Presence(l.channel.guildID, l.userID)
if err != nil {
return cchat.UnknownStatus
}
switch p.Status {
case discord.OnlineStatus:
return cchat.OnlineStatus
case discord.DoNotDisturbStatus:
return cchat.BusyStatus
case discord.IdleStatus:
return cchat.AwayStatus
case discord.OfflineStatus, discord.InvisibleStatus:
return cchat.OfflineStatus
default:
return cchat.UnknownStatus
}
}
func (l *ListMember) Secondary() text.Rich {
p, err := l.channel.session.State.Presence(l.channel.guildID, l.userID)
if err != nil {
return text.Plain("")
}
if p.Game != nil {
return segments.FormatActivity(*p.Game)
}
if len(p.Activities) > 0 {
return segments.FormatActivity(p.Activities[0])
}
return text.Plain("")
}
type ListSection struct {
// constant states
listID string
id string // roleID or online or offline
name string
total int
channel *Channel
}
var (
_ cchat.MemberListSection = (*ListSection)(nil)
_ cchat.MemberListDynamicSection = (*ListSection)(nil)
)
func NewListSection(listID string, ch *Channel, group gateway.GuildMemberListGroup) *ListSection {
var name string
switch group.ID {
case "online":
name = "Online"
case "offline":
name = "Offline"
default:
p, err := discord.ParseSnowflake(group.ID)
if err != nil {
name = group.ID
} else {
r, err := ch.session.Role(ch.guildID, discord.RoleID(p))
if err != nil {
name = fmt.Sprintf("<@#%s>", p.String())
} else {
name = r.Name
}
}
}
return &ListSection{
listID: listID,
channel: ch,
id: group.ID,
name: name,
total: int(group.Count),
}
}
func (s *ListSection) ID() string {
return s.id
// return fmt.Sprintf("%s-%s", s.listID, s.name)
}
func (s *ListSection) Name() text.Rich {
return text.Rich{Content: s.name}
}
func (s *ListSection) Total() int {
return s.total
}
// TODO: document that Load{More,Less} works more like a shifting window.
func (s *ListSection) LoadMore() bool {
// This variable is here purely to make lines shorter.
var memstate = s.channel.session.MemberState
chunk := memstate.GetMemberListChunk(s.channel.guildID, s.channel.id)
if chunk < 0 {
chunk = 0
}
return memstate.RequestMemberList(s.channel.guildID, s.channel.id, chunk) != nil
}
func (s *ListSection) LoadLess() bool {
var memstate = s.channel.session.MemberState
chunk := memstate.GetMemberListChunk(s.channel.guildID, s.channel.id)
if chunk <= 0 {
return false
}
memstate.RequestMemberList(s.channel.guildID, s.channel.id, chunk-1)
return true
}

6
go.mod
View File

@ -3,9 +3,9 @@ module github.com/diamondburned/cchat-discord
go 1.14
require (
github.com/diamondburned/arikawa v0.12.4
github.com/diamondburned/cchat v0.0.46
github.com/diamondburned/ningen v0.1.1-0.20200717072304-e483f86c08e6
github.com/diamondburned/arikawa v1.1.6
github.com/diamondburned/cchat v0.0.48
github.com/diamondburned/ningen v0.1.1-0.20200815214034-638820c48066
github.com/dustin/go-humanize v1.0.0
github.com/go-test/deep v1.0.6
github.com/pkg/errors v0.9.1

18
go.sum
View File

@ -33,6 +33,10 @@ github.com/diamondburned/arikawa v0.10.5 h1:o5lBopooA+8cXlKZdct5qF0xztuZZ35phvQr
github.com/diamondburned/arikawa v0.10.5/go.mod h1:nIhVIatzTQhPUa7NB8w4koG1RF9gYbpAr8Fj8sKq660=
github.com/diamondburned/arikawa v0.12.4 h1:lhWJqcGkIIMiOYWdsoEuGlri2UbMkzMeh+VfuJPkXt4=
github.com/diamondburned/arikawa v0.12.4/go.mod h1:nIhVIatzTQhPUa7NB8w4koG1RF9gYbpAr8Fj8sKq660=
github.com/diamondburned/arikawa v1.1.4 h1:+fctDxzPCF84DFL+POBQgG4CuSpSepE09mdR3Y4vNRQ=
github.com/diamondburned/arikawa v1.1.4/go.mod h1:nIhVIatzTQhPUa7NB8w4koG1RF9gYbpAr8Fj8sKq660=
github.com/diamondburned/arikawa v1.1.6 h1:Y/ioTYipS2v/NXfcAEhCnMTzrpxDjWlkjLKKcX29n6o=
github.com/diamondburned/arikawa v1.1.6/go.mod h1:nIhVIatzTQhPUa7NB8w4koG1RF9gYbpAr8Fj8sKq660=
github.com/diamondburned/cchat v0.0.34 h1:BGiVxMRA9dmW3rLilIldBvjVan7eTTpaWCCfX9IKBYU=
github.com/diamondburned/cchat v0.0.34/go.mod h1:+zXktogE45A0om4fT6B/z6Ii7FXNafjxsNspI0rlhbU=
github.com/diamondburned/cchat v0.0.35 h1:WiMGl8BQJgbP9E4xRxgLGlqUsHpTcJgDKDt8/6a7lBk=
@ -57,6 +61,10 @@ github.com/diamondburned/cchat v0.0.45 h1:HMVSKx1h6lh2OenWaBTvMSK531hWaXAW7I0tKZ
github.com/diamondburned/cchat v0.0.45/go.mod h1:+zXktogE45A0om4fT6B/z6Ii7FXNafjxsNspI0rlhbU=
github.com/diamondburned/cchat v0.0.46 h1:fzm2XA9uGasX0uaic1AFfUMGA53PlO+GGmkYbx49A5k=
github.com/diamondburned/cchat v0.0.46/go.mod h1:+zXktogE45A0om4fT6B/z6Ii7FXNafjxsNspI0rlhbU=
github.com/diamondburned/cchat v0.0.47 h1:qU2TNeXlqru8za4qAgMPWTw6k8HGGOyic08GPPZJ6r8=
github.com/diamondburned/cchat v0.0.47/go.mod h1:+zXktogE45A0om4fT6B/z6Ii7FXNafjxsNspI0rlhbU=
github.com/diamondburned/cchat v0.0.48 h1:MAzGzKY20JBh/LnirOZVPwbMq07xfqu4Lb4XsV9/sXQ=
github.com/diamondburned/cchat v0.0.48/go.mod h1:+zXktogE45A0om4fT6B/z6Ii7FXNafjxsNspI0rlhbU=
github.com/diamondburned/ningen v0.1.1-0.20200621014632-6babb812b249 h1:yP7kJ+xCGpDz6XbcfACJcju4SH1XDPwlrvbofz3lP8I=
github.com/diamondburned/ningen v0.1.1-0.20200621014632-6babb812b249/go.mod h1:xW9hpBZsGi8KpAh10TyP+YQlYBo+Xc+2w4TR6N0951A=
github.com/diamondburned/ningen v0.1.1-0.20200708085949-b64e350f3b8c h1:3h/kyk6HplYZF3zLi106itjYJWjbuMK/twijeGLEy2M=
@ -83,6 +91,16 @@ github.com/diamondburned/ningen v0.1.1-0.20200717070406-6dc482b394c0 h1:DkzeHISw
github.com/diamondburned/ningen v0.1.1-0.20200717070406-6dc482b394c0/go.mod h1:Sunqp1b9Tc0+DtWKslhf83Zepgj/TELB6h8J9HZCPqQ=
github.com/diamondburned/ningen v0.1.1-0.20200717072304-e483f86c08e6 h1:YN0cj0aOCa+tKmx0aD5qsbSYaIJnyrA0/+eygMKP+/w=
github.com/diamondburned/ningen v0.1.1-0.20200717072304-e483f86c08e6/go.mod h1:Sunqp1b9Tc0+DtWKslhf83Zepgj/TELB6h8J9HZCPqQ=
github.com/diamondburned/ningen v0.1.1-0.20200814175234-6d546fac7724 h1:889IwdXZdIJlwlARBHZ2xxZ05Qfjd0yrVnpivyjfxTo=
github.com/diamondburned/ningen v0.1.1-0.20200814175234-6d546fac7724/go.mod h1:Lcgkgu/QfaTqnBQqYb2LlnhM9aR509uEt07y61UQNGg=
github.com/diamondburned/ningen v0.1.1-0.20200814183847-6722b606d3e1 h1:t3UPOrtdabeRqlHN+KIIht9MI6BdyCil7r5A8kz9hq4=
github.com/diamondburned/ningen v0.1.1-0.20200814183847-6722b606d3e1/go.mod h1:Lcgkgu/QfaTqnBQqYb2LlnhM9aR509uEt07y61UQNGg=
github.com/diamondburned/ningen v0.1.1-0.20200815001935-477d5b58b555 h1:NGxGSTnUWlNL8rUlU6hKxaOCbpM8Jrgwh/51pBu28UQ=
github.com/diamondburned/ningen v0.1.1-0.20200815001935-477d5b58b555/go.mod h1:Lcgkgu/QfaTqnBQqYb2LlnhM9aR509uEt07y61UQNGg=
github.com/diamondburned/ningen v0.1.1-0.20200815192814-e630cb3debe2 h1:9GZLZhVlqqTSwKX9CTf+fmj+/kpF8B1p+uYLdaUAHVI=
github.com/diamondburned/ningen v0.1.1-0.20200815192814-e630cb3debe2/go.mod h1:PIsJWdDhjgN9OiR+qrDPD8KGQ8UyFuRVrgs3Ewu6a3c=
github.com/diamondburned/ningen v0.1.1-0.20200815214034-638820c48066 h1:TOLTl0zLJ+idYB7i6C4oGfmVF1Y0AFoNfVQWU3hmc4A=
github.com/diamondburned/ningen v0.1.1-0.20200815214034-638820c48066/go.mod h1:PIsJWdDhjgN9OiR+qrDPD8KGQ8UyFuRVrgs3Ewu6a3c=
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=

View File

@ -3,6 +3,7 @@ package discord
import (
"context"
"sort"
"strconv"
"strings"
"github.com/diamondburned/arikawa/discord"
@ -44,7 +45,7 @@ func NewGuildFolder(s *Session, gf gateway.GuildFolder) *GuildFolder {
}
func (gf *GuildFolder) ID() string {
return gf.GuildFolder.ID.String()
return strconv.FormatInt(int64(gf.GuildFolder.ID), 10)
}
func (gf *GuildFolder) Name() text.Rich {
@ -80,7 +81,7 @@ func (gf *GuildFolder) Servers(container cchat.ServersContainer) error {
}
type Guild struct {
id discord.Snowflake
id discord.GuildID
session *Session
}
@ -97,7 +98,7 @@ func NewGuild(s *Session, g *discord.Guild) *Guild {
}
}
func NewGuildFromID(s *Session, gID discord.Snowflake) (*Guild, error) {
func NewGuildFromID(s *Session, gID discord.GuildID) (*Guild, error) {
g, err := s.Guild(gID)
if err != nil {
return nil, err
@ -156,7 +157,7 @@ func (g *Guild) Servers(container cchat.ServersContainer) error {
}
// Only get top-level channels (those with category ID being null).
var toplevels = filterAccessible(g.session, filterCategory(c, discord.NullSnowflake))
var toplevels = filterAccessible(g.session, filterCategory(c, 0))
// Sort so that positions are correct.
sort.SliceStable(toplevels, func(i, j int) bool {

View File

@ -12,10 +12,10 @@ import (
)
type messageHeader struct {
id discord.Snowflake
id discord.MessageID
time discord.Timestamp
channelID discord.Snowflake
guildID discord.Snowflake
channelID discord.ChannelID
guildID discord.GuildID
nonce string
}
@ -29,7 +29,7 @@ func newHeader(msg discord.Message) messageHeader {
guildID: msg.GuildID,
nonce: msg.Nonce,
}
if msg.EditedTimestamp.Valid() {
if msg.EditedTimestamp.IsValid() {
h.time = msg.EditedTimestamp
}
return h
@ -58,7 +58,7 @@ func AvatarURL(URL string) string {
}
type Author struct {
id discord.Snowflake
id discord.UserID
name text.Rich
avatar string
}
@ -198,7 +198,7 @@ func NewMessageCreate(c *gateway.MessageCreateEvent, s *Session) Message {
func NewBacklogMessage(m discord.Message, s *Session, g discord.Guild) Message {
// If the message doesn't have a guild, then we don't need all the
// complicated member fetching process.
if !m.GuildID.Valid() {
if !m.GuildID.IsValid() {
return NewMessage(m, s, NewUser(m.Author, s))
}
@ -220,7 +220,7 @@ func NewMessage(m discord.Message, s *Session, author Author) Message {
var content = segments.ParseMessage(&m, s.Store)
// Request members in mentions if we're in a guild.
if m.GuildID.Valid() {
if m.GuildID.IsValid() {
for _, segment := range content.Segments {
if mention, ok := segment.(*segments.MentionSegment); ok {
// If this is not a user mention, then skip.
@ -231,7 +231,7 @@ func NewMessage(m discord.Message, s *Session, author Author) Message {
// If we already have a member, then skip. We could check this
// using the timestamp, as we might have a user set into the
// member field
if m := mention.GuildUser.Member; m != nil && m.Joined.Valid() {
if m := mention.GuildUser.Member; m != nil && m.Joined.IsValid() {
continue
}
@ -249,7 +249,7 @@ func NewMessage(m discord.Message, s *Session, author Author) Message {
}
func (m Message) Author() cchat.MessageAuthor {
if !m.author.id.Valid() {
if !m.author.id.IsValid() {
return nil
}
return m.author

View File

@ -115,7 +115,7 @@ func (r *TextRenderer) renderEmbed(embed discord.Embed, m *discord.Message, s st
r.ensureBreak()
}
if embed.Timestamp.Valid() {
if embed.Timestamp.IsValid() {
if embed.Footer != nil {
r.buf.WriteString(" - ")
}

View File

@ -70,7 +70,7 @@ type MentionSegment struct {
*md.Mention
store state.Store
guild discord.Snowflake
guild discord.GuildID
}
var (
@ -241,7 +241,7 @@ func userInfo(guild discord.Guild, member discord.Member, state *ningen.State) t
}
// Write extra information if any, but only if we have the guild state.
if len(member.RoleIDs) > 0 && guild.ID.Valid() {
if len(member.RoleIDs) > 0 && guild.ID.IsValid() {
// Write a prepended new line, as role writes will always prepend a new
// line. This is to prevent a trailing new line.
formatSectionf(&segment, &content, "Roles")
@ -275,7 +275,7 @@ func userInfo(guild discord.Guild, member discord.Member, state *ningen.State) t
formatActivity(&segment, &content, ac)
content.WriteString("\n\n")
}
} else if guild.ID.Valid() {
} else if guild.ID.IsValid() {
// If we're still in a guild, then we can ask Discord for that
// member with their presence attached.
state.MemberState.RequestMember(guild.ID, member.User.ID)
@ -312,6 +312,16 @@ func formatSectionf(segment *text.Rich, content *bytes.Buffer, f string, argv ..
segmentadd(segment, InlineSegment{start, end, text.AttrBold | text.AttrUnderline})
}
func FormatActivity(ac discord.Activity) text.Rich {
var rich text.Rich
var cbuf bytes.Buffer
formatActivity(&rich, &cbuf, ac)
rich.Content = cbuf.String()
return rich
}
func formatActivity(segment *text.Rich, content *bytes.Buffer, ac discord.Activity) {
switch ac.Type {
case discord.GameActivity:
@ -331,7 +341,7 @@ func formatActivity(segment *text.Rich, content *bytes.Buffer, ac discord.Activi
content.WriteByte('\n')
if ac.Emoji != nil {
if !ac.Emoji.ID.Valid() {
if !ac.Emoji.ID.IsValid() {
content.WriteString(ac.Emoji.Name)
} else {
segmentadd(segment, EmojiSegment{
@ -367,7 +377,10 @@ func formatActivity(segment *text.Rich, content *bytes.Buffer, ac discord.Activi
}
}
func getPresence(state *ningen.State, guildID, userID discord.Snowflake) *discord.Activity {
func getPresence(
state *ningen.State,
guildID discord.GuildID, userID discord.UserID) *discord.Activity {
p, err := state.Presence(guildID, userID)
if err != nil {
return nil
@ -380,7 +393,7 @@ func getPresence(state *ningen.State, guildID, userID discord.Snowflake) *discor
return p.Game
}
func findRole(roles []discord.Role, id discord.Snowflake) (discord.Role, bool) {
func findRole(roles []discord.Role, id discord.RoleID) (discord.Role, bool) {
for _, role := range roles {
if role.ID == id {
return role, true

View File

@ -72,7 +72,7 @@ func (Authenticator) Authenticate(form []string) (cchat.Session, error) {
type Session struct {
*ningen.State
userID discord.Snowflake
userID discord.UserID
}
var (
@ -168,7 +168,7 @@ func (s *Session) Servers(container cchat.ServersContainer) error {
for _, folder := range s.Ready.Settings.GuildFolders {
// TODO: correct.
switch {
case folder.ID.Valid():
case folder.ID > 0:
fallthrough
case len(folder.GuildIDs) > 1:
toplevels = append(toplevels, NewGuildFolder(s, folder))

View File

@ -24,7 +24,7 @@ func NewTyperAuthor(author Author, ev *gateway.TypingStartEvent) Typer {
}
func NewTyper(s *Session, ev *gateway.TypingStartEvent) (*Typer, error) {
if ev.GuildID.Valid() {
if ev.GuildID.IsValid() {
g, err := s.Store.Guild(ev.GuildID)
if err != nil {
return nil, err

View File

@ -59,7 +59,7 @@ func ExtIs(URL string, exts []string) bool {
}
// AssetURL generates the image URL from the given asset image ID.
func AssetURL(appID discord.Snowflake, imageID string) string {
func AssetURL(appID discord.AppID, imageID string) string {
if strings.HasPrefix(imageID, "spotify:") {
return "https://i.scdn.co/image/" + strings.TrimPrefix(imageID, "spotify:")
}