1
0
Fork 0
mirror of https://github.com/diamondburned/cchat-discord.git synced 2025-02-02 23:46:43 +00:00

Added Typing indicator support; bumped cchat to v0.0.37

This commit is contained in:
diamondburned (Forefront) 2020-06-29 20:14:44 -07:00
parent 0a66a65fcf
commit 53111f3186
6 changed files with 131 additions and 26 deletions

View file

@ -2,6 +2,7 @@ package discord
import (
"context"
"time"
"github.com/diamondburned/arikawa/api"
"github.com/diamondburned/arikawa/discord"
@ -63,13 +64,14 @@ type Channel struct {
}
var (
_ cchat.Server = (*Channel)(nil)
_ cchat.ServerMessage = (*Channel)(nil)
_ cchat.ServerMessageSender = (*Channel)(nil)
_ cchat.ServerMessageSendCompleter = (*Channel)(nil)
_ cchat.ServerNickname = (*Channel)(nil)
_ cchat.ServerMessageEditor = (*Channel)(nil)
_ cchat.ServerMessageActioner = (*Channel)(nil)
_ cchat.Server = (*Channel)(nil)
_ cchat.ServerMessage = (*Channel)(nil)
_ cchat.ServerMessageSender = (*Channel)(nil)
_ cchat.ServerMessageSendCompleter = (*Channel)(nil)
_ cchat.ServerNickname = (*Channel)(nil)
_ cchat.ServerMessageEditor = (*Channel)(nil)
_ cchat.ServerMessageActioner = (*Channel)(nil)
_ cchat.ServerMessageTypingIndicator = (*Channel)(nil)
)
func NewChannel(s *Session, ch discord.Channel) *Channel {
@ -114,10 +116,10 @@ func (ch *Channel) Name() text.Rich {
}
}
func (ch *Channel) Nickname(ctx context.Context, labeler cchat.LabelContainer) error {
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() {
return nil
return func() {}, nil
}
state := ch.session.WithContext(ctx)
@ -125,12 +127,12 @@ func (ch *Channel) Nickname(ctx context.Context, labeler cchat.LabelContainer) e
// MemberColor should fill up the state cache.
c, err := state.MemberColor(ch.guildID, ch.session.userID)
if err != nil {
return errors.Wrap(err, "Failed to get self member color")
return nil, errors.Wrap(err, "Failed to get self member color")
}
m, err := state.Member(ch.guildID, ch.session.userID)
if err != nil {
return errors.Wrap(err, "Failed to get self member")
return nil, errors.Wrap(err, "Failed to get self member")
}
var rich = text.Rich{Content: m.User.Username}
@ -144,7 +146,29 @@ func (ch *Channel) Nickname(ctx context.Context, labeler cchat.LabelContainer) e
}
labeler.SetLabel(rich)
return nil
// Copy the user ID to use.
var selfID = m.User.ID
return ch.session.AddHandler(func(g *gateway.GuildMemberUpdateEvent) {
if g.GuildID != ch.guildID || g.User.ID != selfID {
return
}
var rich = text.Rich{Content: m.User.Username}
if m.Nick != "" {
rich.Content = m.Nick
}
c, err := ch.session.MemberColor(g.GuildID, selfID)
if err == nil {
rich.Segments = []text.Segment{
segments.NewColored(len(rich.Content), c.Uint32()),
}
}
labeler.SetLabel(rich)
}), nil
}
func (ch *Channel) JoinServer(ctx context.Context, ct cchat.MessagesContainer) (func(), error) {
@ -370,6 +394,10 @@ func (ch *Channel) canManageMessages(userID discord.Snowflake) bool {
return p.Has(discord.PermissionManageMessages)
}
// CompleteMessage implements message input completion capability for Discord.
// This method supports user mentions, channel mentions and emojis.
//
// For the individual implementations, refer to channel_completion.go.
func (ch *Channel) CompleteMessage(words []string, i int) (entries []cchat.CompletionEntry) {
var word = words[i]
// Word should have at least a character for the char check.
@ -389,6 +417,52 @@ func (ch *Channel) CompleteMessage(words []string, i int) (entries []cchat.Compl
return
}
func (ch *Channel) Typing() error {
return ch.session.Typing(ch.id)
}
// TypingTimeout returns 8 seconds.
func (ch *Channel) TypingTimeout() time.Duration {
return 8 * time.Second
}
func (ch *Channel) TypingSubscribe(ti cchat.TypingIndicator) (func(), error) {
return ch.session.AddHandler(func(t *gateway.TypingStartEvent) {
if t.ChannelID != ch.id {
return
}
if ch.guildID.Valid() {
g, err := ch.session.Store.Guild(t.GuildID)
if err != nil {
return
}
if t.Member == nil {
t.Member, err = ch.session.Store.Member(t.GuildID, t.UserID)
if err != nil {
return
}
}
ti.AddTyper(NewGuildMember(*t.Member, *g))
return
}
c, err := ch.self()
if err != nil {
return
}
for _, user := range c.DMRecipients {
if user.ID == t.UserID {
ti.AddTyper(NewUser(user))
return
}
}
}), nil
}
func newCancels() func(...func()) []func() {
var cancels []func()
return func(appended ...func()) []func() {

2
go.mod
View file

@ -4,7 +4,7 @@ go 1.14
require (
github.com/diamondburned/arikawa v0.9.5
github.com/diamondburned/cchat v0.0.35
github.com/diamondburned/cchat v0.0.37
github.com/diamondburned/ningen v0.1.1-0.20200621014632-6babb812b249
github.com/go-test/deep v1.0.6
github.com/pkg/errors v0.9.1

4
go.sum
View file

@ -29,6 +29,10 @@ github.com/diamondburned/cchat v0.0.34 h1:BGiVxMRA9dmW3rLilIldBvjVan7eTTpaWCCfX9
github.com/diamondburned/cchat v0.0.34/go.mod h1:+zXktogE45A0om4fT6B/z6Ii7FXNafjxsNspI0rlhbU=
github.com/diamondburned/cchat v0.0.35 h1:WiMGl8BQJgbP9E4xRxgLGlqUsHpTcJgDKDt8/6a7lBk=
github.com/diamondburned/cchat v0.0.35/go.mod h1:+zXktogE45A0om4fT6B/z6Ii7FXNafjxsNspI0rlhbU=
github.com/diamondburned/cchat v0.0.36 h1:fOD84RV7EUCjoOSogX/Hu5pe4tzHk3Qh7taKaojIAGc=
github.com/diamondburned/cchat v0.0.36/go.mod h1:+zXktogE45A0om4fT6B/z6Ii7FXNafjxsNspI0rlhbU=
github.com/diamondburned/cchat v0.0.37 h1:yGz9yls5Lb/vLkU/DU53GjC80WOqoRe229DXsu5mtaY=
github.com/diamondburned/cchat v0.0.37/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/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=

View file

@ -128,17 +128,25 @@ func (g *Guild) Name() text.Rich {
return text.Rich{Content: s.Name}
}
func (g *Guild) Icon(ctx context.Context, iconer cchat.IconContainer) error {
func (g *Guild) Icon(ctx context.Context, iconer cchat.IconContainer) (func(), error) {
s, err := g.self(ctx)
if err != nil {
// This shouldn't happen.
return errors.Wrap(err, "Failed to get guild")
return nil, errors.Wrap(err, "Failed to get guild")
}
if s.Icon != "" {
iconer.SetIcon(s.IconURL() + "?size=64")
// Used for comparison.
var hash = s.Icon
if hash != "" {
iconer.SetIcon(AvatarURL(s.IconURL()))
}
return nil
return g.session.AddHandler(func(g *gateway.GuildUpdateEvent) {
if g.Icon != hash {
hash = g.Icon
iconer.SetIcon(AvatarURL(s.IconURL()))
}
}), nil
}
func (g *Guild) Servers(container cchat.ServersContainer) error {

View file

@ -1,6 +1,7 @@
package discord
import (
"net/url"
"time"
"github.com/diamondburned/arikawa/discord"
@ -51,6 +52,20 @@ func (m messageHeader) Time() time.Time {
return m.time.Time()
}
// AvatarURL wraps the URL with URL queries for the avatar.
func AvatarURL(URL string) string {
u, err := url.Parse(URL)
if err != nil {
return URL
}
q := u.Query()
q.Set("size", "64")
u.RawQuery = q.Encode()
return u.String()
}
type Author struct {
id discord.Snowflake
name text.Rich
@ -61,7 +76,7 @@ func NewUser(u discord.User) Author {
return Author{
id: u.ID,
name: text.Rich{Content: u.Username},
avatar: u.AvatarURL(),
avatar: AvatarURL(u.AvatarURL()),
}
}
@ -69,7 +84,7 @@ func NewGuildMember(m discord.Member, g discord.Guild) Author {
return Author{
id: m.User.ID,
name: RenderMemberName(m, g),
avatar: m.User.AvatarURL(),
avatar: AvatarURL(m.User.AvatarURL()),
}
}

View file

@ -4,6 +4,7 @@ import (
"context"
"github.com/diamondburned/arikawa/discord"
"github.com/diamondburned/arikawa/gateway"
"github.com/diamondburned/arikawa/state"
"github.com/diamondburned/cchat"
"github.com/diamondburned/cchat/services"
@ -30,9 +31,9 @@ func (Service) Name() text.Rich {
return text.Rich{Content: "Discord"}
}
func (Service) Icon(ctx context.Context, iconer cchat.IconContainer) error {
func (Service) Icon(ctx context.Context, iconer cchat.IconContainer) (func(), error) {
iconer.SetIcon("https://discord.com/assets/2c21aeda16de354ba5334551a883b481.png")
return nil
return func() {}, nil
}
func (Service) Authenticate() cchat.Authenticator {
@ -122,15 +123,18 @@ func (s *Session) Name() text.Rich {
return text.Rich{Content: u.Username + "#" + u.Discriminator}
}
func (s *Session) Icon(ctx context.Context, iconer cchat.IconContainer) error {
func (s *Session) Icon(ctx context.Context, iconer cchat.IconContainer) (func(), error) {
u, err := s.Me()
if err != nil {
return errors.Wrap(err, "Failed to get the current user")
return nil, errors.Wrap(err, "Failed to get the current user")
}
// Thanks to arikawa, AvatarURL is never empty.
iconer.SetIcon(u.AvatarURL())
return nil
iconer.SetIcon(AvatarURL(u.AvatarURL()))
return s.AddHandler(func(u *gateway.UserUpdateEvent) {
iconer.SetIcon(AvatarURL(u.AvatarURL()))
}), nil
}
func (s *Session) Disconnect() error {