| @@ -0,0 +1,23 @@ | |||
| namespace Discord | |||
| { | |||
| /// <summary> | |||
| /// A unicode emoji | |||
| /// </summary> | |||
| public class Emoji : IEmote | |||
| { | |||
| // TODO: need to constrain this to unicode-only emojis somehow | |||
| /// <summary> | |||
| /// Creates a unciode emoji. | |||
| /// </summary> | |||
| /// <param name="unicode">The pure UTF-8 encoding of an emoji</param> | |||
| public Emoji(string unicode) | |||
| { | |||
| Name = unicode; | |||
| } | |||
| /// <summary> | |||
| /// The unicode representation of this emote. | |||
| /// </summary> | |||
| public string Name { get; } | |||
| } | |||
| } | |||
| @@ -0,0 +1,63 @@ | |||
| using System; | |||
| using System.Globalization; | |||
| namespace Discord | |||
| { | |||
| /// <summary> | |||
| /// A custom image-based emote | |||
| /// </summary> | |||
| public class Emote : IEmote, ISnowflakeEntity | |||
| { | |||
| /// <summary> | |||
| /// The display name (tooltip) of this emote | |||
| /// </summary> | |||
| public string Name { get; } | |||
| /// <summary> | |||
| /// The ID of this emote | |||
| /// </summary> | |||
| public ulong Id { get; } | |||
| public DateTimeOffset CreatedAt => SnowflakeUtils.FromSnowflake(Id); | |||
| public string Url => CDN.GetEmojiUrl(Id); | |||
| internal Emote(ulong id, string name) | |||
| { | |||
| Id = id; | |||
| Name = name; | |||
| } | |||
| /// <summary> | |||
| /// Parse an Emote from its raw format | |||
| /// </summary> | |||
| /// <param name="text">The raw encoding of an emote; for example, <:dab:277855270321782784></param> | |||
| /// <returns>An emote</returns> | |||
| public static Emote Parse(string text) | |||
| { | |||
| if (TryParse(text, out Emote result)) | |||
| return result; | |||
| throw new ArgumentException("Invalid emote format", nameof(text)); | |||
| } | |||
| public static bool TryParse(string text, out Emote result) | |||
| { | |||
| result = null; | |||
| if (text.Length >= 4 && text[0] == '<' && text[1] == ':' && text[text.Length - 1] == '>') | |||
| { | |||
| int splitIndex = text.IndexOf(':', 2); | |||
| if (splitIndex == -1) | |||
| return false; | |||
| if (!ulong.TryParse(text.Substring(splitIndex + 1, text.Length - splitIndex - 2), NumberStyles.None, CultureInfo.InvariantCulture, out ulong id)) | |||
| return false; | |||
| string name = text.Substring(2, splitIndex - 2); | |||
| result = new Emote(id, name); | |||
| return true; | |||
| } | |||
| return false; | |||
| } | |||
| private string DebuggerDisplay => $"{Name} ({Id})"; | |||
| public override string ToString() => Name; | |||
| } | |||
| } | |||
| @@ -3,19 +3,18 @@ using System.Diagnostics; | |||
| namespace Discord | |||
| { | |||
| /// <summary> | |||
| /// An image-based emote that is attached to a guild | |||
| /// </summary> | |||
| [DebuggerDisplay(@"{DebuggerDisplay,nq}")] | |||
| public struct GuildEmoji | |||
| public class GuildEmote : Emote | |||
| { | |||
| public ulong Id { get; } | |||
| public string Name { get; } | |||
| public bool IsManaged { get; } | |||
| public bool RequireColons { get; } | |||
| public IReadOnlyList<ulong> RoleIds { get; } | |||
| internal GuildEmoji(ulong id, string name, bool isManaged, bool requireColons, IReadOnlyList<ulong> roleIds) | |||
| internal GuildEmote(ulong id, string name, bool isManaged, bool requireColons, IReadOnlyList<ulong> roleIds) : base(id, name) | |||
| { | |||
| Id = id; | |||
| Name = name; | |||
| IsManaged = isManaged; | |||
| RequireColons = requireColons; | |||
| RoleIds = roleIds; | |||
| @@ -0,0 +1,13 @@ | |||
| namespace Discord | |||
| { | |||
| /// <summary> | |||
| /// A general container for any type of emote in a message. | |||
| /// </summary> | |||
| public interface IEmote | |||
| { | |||
| /// <summary> | |||
| /// The display name or unicode representation of this emote | |||
| /// </summary> | |||
| string Name { get; } | |||
| } | |||
| } | |||
| @@ -45,7 +45,7 @@ namespace Discord | |||
| /// <summary> Gets the built-in role containing all users in this guild. </summary> | |||
| IRole EveryoneRole { get; } | |||
| /// <summary> Gets a collection of all custom emojis for this guild. </summary> | |||
| IReadOnlyCollection<GuildEmoji> Emojis { get; } | |||
| IReadOnlyCollection<GuildEmote> Emotes { get; } | |||
| /// <summary> Gets a collection of all extra features added to this guild. </summary> | |||
| IReadOnlyCollection<string> Features { get; } | |||
| /// <summary> Gets a collection of all roles in this guild. </summary> | |||
| @@ -1,51 +0,0 @@ | |||
| using System; | |||
| using System.Diagnostics; | |||
| using System.Globalization; | |||
| namespace Discord | |||
| { | |||
| [DebuggerDisplay("{DebuggerDisplay,nq}")] | |||
| public struct Emoji | |||
| { | |||
| public ulong? Id { get; } | |||
| public string Name { get; } | |||
| public string Url => Id != null ? CDN.GetEmojiUrl(Id.Value) : null; | |||
| internal Emoji(ulong? id, string name) | |||
| { | |||
| Id = id; | |||
| Name = name; | |||
| } | |||
| public static Emoji Parse(string text) | |||
| { | |||
| if (TryParse(text, out Emoji result)) | |||
| return result; | |||
| throw new ArgumentException("Invalid emoji format", nameof(text)); | |||
| } | |||
| public static bool TryParse(string text, out Emoji result) | |||
| { | |||
| result = default(Emoji); | |||
| if (text.Length >= 4 && text[0] == '<' && text[1] == ':' && text[text.Length - 1] == '>') | |||
| { | |||
| int splitIndex = text.IndexOf(':', 2); | |||
| if (splitIndex == -1) | |||
| return false; | |||
| if (!ulong.TryParse(text.Substring(splitIndex + 1, text.Length - splitIndex - 2), NumberStyles.None, CultureInfo.InvariantCulture, out ulong id)) | |||
| return false; | |||
| string name = text.Substring(2, splitIndex - 2); | |||
| result = new Emoji(id, name); | |||
| return true; | |||
| } | |||
| return false; | |||
| } | |||
| private string DebuggerDisplay => $"{Name} ({Id})"; | |||
| public override string ToString() => Name; | |||
| } | |||
| } | |||
| @@ -2,6 +2,6 @@ | |||
| { | |||
| public interface IReaction | |||
| { | |||
| Emoji Emoji { get; } | |||
| IEmote Emote { get; } | |||
| } | |||
| } | |||
| @@ -14,16 +14,12 @@ namespace Discord | |||
| Task UnpinAsync(RequestOptions options = null); | |||
| /// <summary> Returns all reactions included in this message. </summary> | |||
| IReadOnlyDictionary<Emoji, ReactionMetadata> Reactions { get; } | |||
| IReadOnlyDictionary<IEmote, ReactionMetadata> Reactions { get; } | |||
| /// <summary> Adds a reaction to this message. </summary> | |||
| Task AddReactionAsync(Emoji emoji, RequestOptions options = null); | |||
| /// <summary> Adds a reaction to this message. </summary> | |||
| Task AddReactionAsync(string emoji, RequestOptions options = null); | |||
| Task AddReactionAsync(IEmote emote, RequestOptions options = null); | |||
| /// <summary> Removes a reaction from message. </summary> | |||
| Task RemoveReactionAsync(Emoji emoji, IUser user, RequestOptions options = null); | |||
| /// <summary> Removes a reaction from this message. </summary> | |||
| Task RemoveReactionAsync(string emoji, IUser user, RequestOptions options = null); | |||
| Task RemoveReactionAsync(IEmote emote, IUser user, RequestOptions options = null); | |||
| /// <summary> Removes all reactions from this message. </summary> | |||
| Task RemoveAllReactionsAsync(RequestOptions options = null); | |||
| Task<IReadOnlyCollection<IUser>> GetReactionUsersAsync(string emoji, int limit = 100, ulong? afterUserId = null, RequestOptions options = null); | |||
| @@ -252,7 +252,7 @@ namespace Discord | |||
| { | |||
| if (mode != TagHandling.Remove) | |||
| { | |||
| Emoji emoji = (Emoji)tag.Value; | |||
| Emote emoji = (Emote)tag.Value; | |||
| //Remove if its name contains any bad chars (prevents a few tag exploits) | |||
| for (int i = 0; i < emoji.Name.Length; i++) | |||
| @@ -3,10 +3,10 @@ using System; | |||
| using System.Collections.Generic; | |||
| using System.Collections.Immutable; | |||
| using System.Diagnostics; | |||
| using System.Linq; | |||
| using System.Threading.Tasks; | |||
| using Model = Discord.API.Guild; | |||
| using EmbedModel = Discord.API.GuildEmbed; | |||
| using System.Linq; | |||
| using Model = Discord.API.Guild; | |||
| namespace Discord.Rest | |||
| { | |||
| @@ -14,7 +14,7 @@ namespace Discord.Rest | |||
| public class RestGuild : RestEntity<ulong>, IGuild, IUpdateable | |||
| { | |||
| private ImmutableDictionary<ulong, RestRole> _roles; | |||
| private ImmutableArray<GuildEmoji> _emojis; | |||
| private ImmutableArray<GuildEmote> _emotes; | |||
| private ImmutableArray<string> _features; | |||
| public string Name { get; private set; } | |||
| @@ -39,7 +39,7 @@ namespace Discord.Rest | |||
| public RestRole EveryoneRole => GetRole(Id); | |||
| public IReadOnlyCollection<RestRole> Roles => _roles.ToReadOnlyCollection(); | |||
| public IReadOnlyCollection<GuildEmoji> Emojis => _emojis; | |||
| public IReadOnlyCollection<GuildEmote> Emotes => _emotes; | |||
| public IReadOnlyCollection<string> Features => _features; | |||
| internal RestGuild(BaseDiscordClient client, ulong id) | |||
| @@ -69,13 +69,13 @@ namespace Discord.Rest | |||
| if (model.Emojis != null) | |||
| { | |||
| var emojis = ImmutableArray.CreateBuilder<GuildEmoji>(model.Emojis.Length); | |||
| var emotes = ImmutableArray.CreateBuilder<GuildEmote>(model.Emojis.Length); | |||
| for (int i = 0; i < model.Emojis.Length; i++) | |||
| emojis.Add(model.Emojis[i].ToEntity()); | |||
| _emojis = emojis.ToImmutableArray(); | |||
| emotes.Add(model.Emojis[i].ToEntity()); | |||
| _emotes = emotes.ToImmutableArray(); | |||
| } | |||
| else | |||
| _emojis = ImmutableArray.Create<GuildEmoji>(); | |||
| _emotes = ImmutableArray.Create<GuildEmote>(); | |||
| if (model.Features != null) | |||
| _features = model.Features.ToImmutableArray(); | |||
| @@ -28,19 +28,14 @@ namespace Discord.Rest | |||
| await client.ApiClient.DeleteMessageAsync(msg.Channel.Id, msg.Id, options).ConfigureAwait(false); | |||
| } | |||
| public static async Task AddReactionAsync(IMessage msg, Emoji emoji, BaseDiscordClient client, RequestOptions options) | |||
| => await AddReactionAsync(msg, $"{emoji.Name}:{emoji.Id}", client, options).ConfigureAwait(false); | |||
| public static async Task AddReactionAsync(IMessage msg, string emoji, BaseDiscordClient client, RequestOptions options) | |||
| public static async Task AddReactionAsync(IMessage msg, IEmote emote, BaseDiscordClient client, RequestOptions options) | |||
| { | |||
| await client.ApiClient.AddReactionAsync(msg.Channel.Id, msg.Id, emoji, options).ConfigureAwait(false); | |||
| await client.ApiClient.AddReactionAsync(msg.Channel.Id, msg.Id, emote is Emote e ? $"{e.Name}:{e.Id}" : emote.Name, options).ConfigureAwait(false); | |||
| } | |||
| public static async Task RemoveReactionAsync(IMessage msg, IUser user, Emoji emoji, BaseDiscordClient client, RequestOptions options) | |||
| => await RemoveReactionAsync(msg, user, emoji.Id == null ? emoji.Name : $"{emoji.Name}:{emoji.Id}", client, options).ConfigureAwait(false); | |||
| public static async Task RemoveReactionAsync(IMessage msg, IUser user, string emoji, BaseDiscordClient client, | |||
| RequestOptions options) | |||
| public static async Task RemoveReactionAsync(IMessage msg, IUser user, IEmote emote, BaseDiscordClient client, RequestOptions options) | |||
| { | |||
| await client.ApiClient.RemoveReactionAsync(msg.Channel.Id, msg.Id, user.Id, emoji, options).ConfigureAwait(false); | |||
| await client.ApiClient.RemoveReactionAsync(msg.Channel.Id, msg.Id, user.Id, emote is Emote e ? $"{e.Name}:{e.Id}" : emote.Name, options).ConfigureAwait(false); | |||
| } | |||
| public static async Task RemoveAllReactionsAsync(IMessage msg, BaseDiscordClient client, RequestOptions options) | |||
| @@ -109,8 +104,8 @@ namespace Discord.Rest | |||
| mentionedRole = guild.GetRole(id); | |||
| tags.Add(new Tag<IRole>(TagType.RoleMention, index, content.Length, id, mentionedRole)); | |||
| } | |||
| else if (Emoji.TryParse(content, out var emoji)) | |||
| tags.Add(new Tag<Emoji>(TagType.Emoji, index, content.Length, emoji.Id ?? 0, emoji)); | |||
| else if (Emote.TryParse(content, out var emoji)) | |||
| tags.Add(new Tag<Emote>(TagType.Emoji, index, content.Length, emoji.Id, emoji)); | |||
| else //Bad Tag | |||
| { | |||
| index = index + 1; | |||
| @@ -4,19 +4,24 @@ namespace Discord.Rest | |||
| { | |||
| public class RestReaction : IReaction | |||
| { | |||
| public Emoji Emoji { get; } | |||
| public IEmote Emote { get; } | |||
| public int Count { get; } | |||
| public bool Me { get; } | |||
| internal RestReaction(Emoji emoji, int count, bool me) | |||
| internal RestReaction(IEmote emote, int count, bool me) | |||
| { | |||
| Emoji = emoji; | |||
| Emote = emote; | |||
| Count = count; | |||
| Me = me; | |||
| } | |||
| internal static RestReaction Create(Model model) | |||
| { | |||
| return new RestReaction(new Emoji(model.Emoji.Id, model.Emoji.Name), model.Count, model.Me); | |||
| IEmote emote; | |||
| if (model.Emoji.Id.HasValue) | |||
| emote = new Emote(model.Emoji.Id.Value, model.Emoji.Name); | |||
| else | |||
| emote = new Emoji(model.Emoji.Name); | |||
| return new RestReaction(emote, model.Count, model.Me); | |||
| } | |||
| } | |||
| } | |||
| @@ -27,7 +27,7 @@ namespace Discord.Rest | |||
| public override IReadOnlyCollection<ulong> MentionedRoleIds => MessageHelper.FilterTagsByKey(TagType.RoleMention, _tags); | |||
| public override IReadOnlyCollection<RestUser> MentionedUsers => MessageHelper.FilterTagsByValue<RestUser>(TagType.UserMention, _tags); | |||
| public override IReadOnlyCollection<ITag> Tags => _tags; | |||
| public IReadOnlyDictionary<Emoji, ReactionMetadata> Reactions => _reactions.ToDictionary(x => x.Emoji, x => new ReactionMetadata { ReactionCount = x.Count, IsMe = x.Me }); | |||
| public IReadOnlyDictionary<IEmote, ReactionMetadata> Reactions => _reactions.ToDictionary(x => x.Emote, x => new ReactionMetadata { ReactionCount = x.Count, IsMe = x.Me }); | |||
| internal RestUserMessage(BaseDiscordClient discord, ulong id, IMessageChannel channel, IUser author, MessageSource source) | |||
| : base(discord, id, channel, author, source) | |||
| @@ -130,21 +130,15 @@ namespace Discord.Rest | |||
| Update(model); | |||
| } | |||
| public Task AddReactionAsync(Emoji emoji, RequestOptions options = null) | |||
| => MessageHelper.AddReactionAsync(this, emoji, Discord, options); | |||
| public Task AddReactionAsync(string emoji, RequestOptions options = null) | |||
| => MessageHelper.AddReactionAsync(this, emoji, Discord, options); | |||
| public Task RemoveReactionAsync(Emoji emoji, IUser user, RequestOptions options = null) | |||
| => MessageHelper.RemoveReactionAsync(this, user, emoji, Discord, options); | |||
| public Task RemoveReactionAsync(string emoji, IUser user, RequestOptions options = null) | |||
| => MessageHelper.RemoveReactionAsync(this, user, emoji, Discord, options); | |||
| public Task AddReactionAsync(IEmote emote, RequestOptions options = null) | |||
| => MessageHelper.AddReactionAsync(this, emote, Discord, options); | |||
| public Task RemoveReactionAsync(IEmote emote, IUser user, RequestOptions options = null) | |||
| => MessageHelper.RemoveReactionAsync(this, user, emote, Discord, options); | |||
| public Task RemoveAllReactionsAsync(RequestOptions options = null) | |||
| => MessageHelper.RemoveAllReactionsAsync(this, Discord, options); | |||
| public Task<IReadOnlyCollection<IUser>> GetReactionUsersAsync(string emoji, int limit = 100, ulong? afterUserId = null, RequestOptions options = null) | |||
| => MessageHelper.GetReactionUsersAsync(this, emoji, x => { x.Limit = limit; x.AfterUserId = afterUserId.HasValue ? afterUserId.Value : Optional.Create<ulong>(); }, Discord, options); | |||
| => MessageHelper.GetReactionUsersAsync(this, emoji, x => { x.Limit = limit; x.AfterUserId = afterUserId ?? Optional.Create<ulong>(); }, Discord, options); | |||
| public Task PinAsync(RequestOptions options = null) | |||
| @@ -5,9 +5,9 @@ namespace Discord.Rest | |||
| { | |||
| internal static class EntityExtensions | |||
| { | |||
| public static GuildEmoji ToEntity(this API.Emoji model) | |||
| public static GuildEmote ToEntity(this API.Emoji model) | |||
| { | |||
| return new GuildEmoji(model.Id.Value, model.Name, model.Managed, model.RequireColons, ImmutableArray.Create(model.Roles)); | |||
| return new GuildEmote(model.Id.Value, model.Name, model.Managed, model.RequireColons, ImmutableArray.Create(model.Roles)); | |||
| } | |||
| public static Embed ToEntity(this API.Embed model) | |||
| @@ -29,7 +29,7 @@ namespace Discord.Rpc | |||
| public override IReadOnlyCollection<ulong> MentionedRoleIds => MessageHelper.FilterTagsByKey(TagType.RoleMention, _tags); | |||
| public override IReadOnlyCollection<ulong> MentionedUserIds => MessageHelper.FilterTagsByKey(TagType.UserMention, _tags); | |||
| public override IReadOnlyCollection<ITag> Tags => _tags; | |||
| public IReadOnlyDictionary<Emoji, ReactionMetadata> Reactions => ImmutableDictionary.Create<Emoji, ReactionMetadata>(); | |||
| public IReadOnlyDictionary<IEmote, ReactionMetadata> Reactions => ImmutableDictionary.Create<IEmote, ReactionMetadata>(); | |||
| internal RpcUserMessage(DiscordRpcClient discord, ulong id, RestVirtualMessageChannel channel, RpcUser author, MessageSource source) | |||
| : base(discord, id, channel, author, source) | |||
| @@ -102,16 +102,10 @@ namespace Discord.Rpc | |||
| public Task ModifyAsync(Action<MessageProperties> func, RequestOptions options) | |||
| => MessageHelper.ModifyAsync(this, Discord, func, options); | |||
| public Task AddReactionAsync(Emoji emoji, RequestOptions options = null) | |||
| => MessageHelper.AddReactionAsync(this, emoji, Discord, options); | |||
| public Task AddReactionAsync(string emoji, RequestOptions options = null) | |||
| => MessageHelper.AddReactionAsync(this, emoji, Discord, options); | |||
| public Task RemoveReactionAsync(Emoji emoji, IUser user, RequestOptions options = null) | |||
| => MessageHelper.RemoveReactionAsync(this, user, emoji, Discord, options); | |||
| public Task RemoveReactionAsync(string emoji, IUser user, RequestOptions options = null) | |||
| => MessageHelper.RemoveReactionAsync(this, user, emoji, Discord, options); | |||
| public Task AddReactionAsync(IEmote emote, RequestOptions options = null) | |||
| => MessageHelper.AddReactionAsync(this, emote, Discord, options); | |||
| public Task RemoveReactionAsync(IEmote emote, IUser user, RequestOptions options = null) | |||
| => MessageHelper.RemoveReactionAsync(this, user, emote, Discord, options); | |||
| public Task RemoveAllReactionsAsync(RequestOptions options = null) | |||
| => MessageHelper.RemoveAllReactionsAsync(this, Discord, options); | |||
| @@ -30,7 +30,7 @@ namespace Discord.WebSocket | |||
| private ConcurrentDictionary<ulong, SocketGuildUser> _members; | |||
| private ConcurrentDictionary<ulong, SocketRole> _roles; | |||
| private ConcurrentDictionary<ulong, SocketVoiceState> _voiceStates; | |||
| private ImmutableArray<GuildEmoji> _emojis; | |||
| private ImmutableArray<GuildEmote> _emotes; | |||
| private ImmutableArray<string> _features; | |||
| private AudioClient _audioClient; | |||
| @@ -93,7 +93,7 @@ namespace Discord.WebSocket | |||
| return channels.Select(x => state.GetChannel(x) as SocketGuildChannel).Where(x => x != null).ToReadOnlyCollection(channels); | |||
| } | |||
| } | |||
| public IReadOnlyCollection<GuildEmoji> Emojis => _emojis; | |||
| public IReadOnlyCollection<GuildEmote> Emotes => _emotes; | |||
| public IReadOnlyCollection<string> Features => _features; | |||
| public IReadOnlyCollection<SocketGuildUser> Users => _members.ToReadOnlyCollection(); | |||
| public IReadOnlyCollection<SocketRole> Roles => _roles.ToReadOnlyCollection(); | |||
| @@ -102,7 +102,7 @@ namespace Discord.WebSocket | |||
| : base(client, id) | |||
| { | |||
| _audioLock = new SemaphoreSlim(1, 1); | |||
| _emojis = ImmutableArray.Create<GuildEmoji>(); | |||
| _emotes = ImmutableArray.Create<GuildEmote>(); | |||
| _features = ImmutableArray.Create<string>(); | |||
| } | |||
| internal static SocketGuild Create(DiscordSocketClient discord, ClientState state, ExtendedModel model) | |||
| @@ -201,13 +201,13 @@ namespace Discord.WebSocket | |||
| if (model.Emojis != null) | |||
| { | |||
| var emojis = ImmutableArray.CreateBuilder<GuildEmoji>(model.Emojis.Length); | |||
| var emojis = ImmutableArray.CreateBuilder<GuildEmote>(model.Emojis.Length); | |||
| for (int i = 0; i < model.Emojis.Length; i++) | |||
| emojis.Add(model.Emojis[i].ToEntity()); | |||
| _emojis = emojis.ToImmutable(); | |||
| _emotes = emojis.ToImmutable(); | |||
| } | |||
| else | |||
| _emojis = ImmutableArray.Create<GuildEmoji>(); | |||
| _emotes = ImmutableArray.Create<GuildEmote>(); | |||
| if (model.Features != null) | |||
| _features = model.Features.ToImmutableArray(); | |||
| @@ -253,10 +253,10 @@ namespace Discord.WebSocket | |||
| internal void Update(ClientState state, EmojiUpdateModel model) | |||
| { | |||
| var emojis = ImmutableArray.CreateBuilder<GuildEmoji>(model.Emojis.Length); | |||
| var emotes = ImmutableArray.CreateBuilder<GuildEmote>(model.Emojis.Length); | |||
| for (int i = 0; i < model.Emojis.Length; i++) | |||
| emojis.Add(model.Emojis[i].ToEntity()); | |||
| _emojis = emojis.ToImmutable(); | |||
| emotes.Add(model.Emojis[i].ToEntity()); | |||
| _emotes = emotes.ToImmutable(); | |||
| } | |||
| //General | |||
| @@ -9,20 +9,25 @@ namespace Discord.WebSocket | |||
| public ulong MessageId { get; } | |||
| public Optional<SocketUserMessage> Message { get; } | |||
| public ISocketMessageChannel Channel { get; } | |||
| public Emoji Emoji { get; } | |||
| public IEmote Emote { get; } | |||
| internal SocketReaction(ISocketMessageChannel channel, ulong messageId, Optional<SocketUserMessage> message, ulong userId, Optional<IUser> user, Emoji emoji) | |||
| internal SocketReaction(ISocketMessageChannel channel, ulong messageId, Optional<SocketUserMessage> message, ulong userId, Optional<IUser> user, IEmote emoji) | |||
| { | |||
| Channel = channel; | |||
| MessageId = messageId; | |||
| Message = message; | |||
| UserId = userId; | |||
| User = user; | |||
| Emoji = emoji; | |||
| Emote = emoji; | |||
| } | |||
| internal static SocketReaction Create(Model model, ISocketMessageChannel channel, Optional<SocketUserMessage> message, Optional<IUser> user) | |||
| { | |||
| return new SocketReaction(channel, model.MessageId, message, model.UserId, user, new Emoji(model.Emoji.Id, model.Emoji.Name)); | |||
| IEmote emote; | |||
| if (model.Emoji.Id.HasValue) | |||
| emote = new Emote(model.Emoji.Id.Value, model.Emoji.Name); | |||
| else | |||
| emote = new Emoji(model.Emoji.Name); | |||
| return new SocketReaction(channel, model.MessageId, message, model.UserId, user, emote); | |||
| } | |||
| } | |||
| } | |||
| @@ -28,7 +28,7 @@ namespace Discord.WebSocket | |||
| public override IReadOnlyCollection<SocketGuildChannel> MentionedChannels => MessageHelper.FilterTagsByValue<SocketGuildChannel>(TagType.ChannelMention, _tags); | |||
| public override IReadOnlyCollection<SocketRole> MentionedRoles => MessageHelper.FilterTagsByValue<SocketRole>(TagType.RoleMention, _tags); | |||
| public override IReadOnlyCollection<SocketUser> MentionedUsers => MessageHelper.FilterTagsByValue<SocketUser>(TagType.UserMention, _tags); | |||
| public IReadOnlyDictionary<Emoji, ReactionMetadata> Reactions => _reactions.GroupBy(r => r.Emoji).ToDictionary(x => x.Key, x => new ReactionMetadata { ReactionCount = x.Count(), IsMe = x.Any(y => y.UserId == Discord.CurrentUser.Id) }); | |||
| public IReadOnlyDictionary<IEmote, ReactionMetadata> Reactions => _reactions.GroupBy(r => r.Emote).ToDictionary(x => x.Key, x => new ReactionMetadata { ReactionCount = x.Count(), IsMe = x.Any(y => y.UserId == Discord.CurrentUser.Id) }); | |||
| internal SocketUserMessage(DiscordSocketClient discord, ulong id, ISocketMessageChannel channel, SocketUser author, MessageSource source) | |||
| : base(discord, id, channel, author, source) | |||
| @@ -124,16 +124,10 @@ namespace Discord.WebSocket | |||
| public Task ModifyAsync(Action<MessageProperties> func, RequestOptions options = null) | |||
| => MessageHelper.ModifyAsync(this, Discord, func, options); | |||
| public Task AddReactionAsync(Emoji emoji, RequestOptions options = null) | |||
| => MessageHelper.AddReactionAsync(this, emoji, Discord, options); | |||
| public Task AddReactionAsync(string emoji, RequestOptions options = null) | |||
| => MessageHelper.AddReactionAsync(this, emoji, Discord, options); | |||
| public Task RemoveReactionAsync(Emoji emoji, IUser user, RequestOptions options = null) | |||
| => MessageHelper.RemoveReactionAsync(this, user, emoji, Discord, options); | |||
| public Task RemoveReactionAsync(string emoji, IUser user, RequestOptions options = null) | |||
| => MessageHelper.RemoveReactionAsync(this, user, emoji, Discord, options); | |||
| public Task AddReactionAsync(IEmote emote, RequestOptions options = null) | |||
| => MessageHelper.AddReactionAsync(this, emote, Discord, options); | |||
| public Task RemoveReactionAsync(IEmote emote, IUser user, RequestOptions options = null) | |||
| => MessageHelper.RemoveReactionAsync(this, user, emote, Discord, options); | |||
| public Task RemoveAllReactionsAsync(RequestOptions options = null) | |||
| => MessageHelper.RemoveAllReactionsAsync(this, Discord, options); | |||