diff --git a/src/Discord.Net.Core/Entities/Messages/IMessage.cs b/src/Discord.Net.Core/Entities/Messages/IMessage.cs index 36fa602a7..1eba1e076 100644 --- a/src/Discord.Net.Core/Entities/Messages/IMessage.cs +++ b/src/Discord.Net.Core/Entities/Messages/IMessage.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Threading.Tasks; namespace Discord { @@ -138,5 +139,89 @@ namespace Discord /// A message's application, if any is associated. /// MessageApplication Application { get; } + + /// + /// Gets all reactions included in this message. + /// + IReadOnlyDictionary Reactions { get; } + + /// + /// Adds a reaction to this message. + /// + /// + /// The following example adds the reaction, 💕, to the message. + /// + /// await msg.AddReactionAsync(new Emoji("\U0001f495")); + /// + /// + /// The emoji used to react to this message. + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous operation for adding a reaction to this message. + /// + /// + Task AddReactionAsync(IEmote emote, RequestOptions options = null); + /// + /// Removes a reaction from message. + /// + /// + /// The following example removes the reaction, 💕, added by the message author from the message. + /// + /// await msg.RemoveReactionAsync(new Emoji("\U0001f495"), msg.Author); + /// + /// + /// The emoji used to react to this message. + /// The user that added the emoji. + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous operation for removing a reaction to this message. + /// + /// + Task RemoveReactionAsync(IEmote emote, IUser user, RequestOptions options = null); + /// + /// Removes a reaction from message. + /// + /// + /// The following example removes the reaction, 💕, added by the user with ID 84291986575613952 from the message. + /// + /// await msg.RemoveReactionAsync(new Emoji("\U0001f495"), 84291986575613952); + /// + /// + /// The emoji used to react to this message. + /// The ID of the user that added the emoji. + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous operation for removing a reaction to this message. + /// + /// + Task RemoveReactionAsync(IEmote emote, ulong userId, RequestOptions options = null); + /// + /// Removes all reactions from this message. + /// + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous removal operation. + /// + Task RemoveAllReactionsAsync(RequestOptions options = null); + + /// + /// Gets all users that reacted to a message with a given emote. + /// + /// + /// The following example gets the users that have reacted with the emoji 💕 to the message. + /// + /// var emoji = new Emoji("\U0001f495"); + /// var reactedUsers = await message.GetReactionUsersAsync(emoji, 100).FlattenAsync(); + /// + /// + /// The emoji that represents the reaction that you wish to get. + /// The number of users to request. + /// The options to be used when sending the request. + /// + /// A paged collection containing a read-only collection of users that has reacted to this message. + /// Flattening the paginated response into a collection of users with + /// is required if you wish to access the users. + /// + IAsyncEnumerable> GetReactionUsersAsync(IEmote emoji, int limit, RequestOptions options = null); } } diff --git a/src/Discord.Net.Core/Entities/Messages/IUserMessage.cs b/src/Discord.Net.Core/Entities/Messages/IUserMessage.cs index 934350aea..be2523b21 100644 --- a/src/Discord.Net.Core/Entities/Messages/IUserMessage.cs +++ b/src/Discord.Net.Core/Entities/Messages/IUserMessage.cs @@ -58,90 +58,6 @@ namespace Discord Task UnpinAsync(RequestOptions options = null); /// - /// Gets all reactions included in this message. - /// - IReadOnlyDictionary Reactions { get; } - - /// - /// Adds a reaction to this message. - /// - /// - /// The following example adds the reaction, 💕, to the message. - /// - /// await msg.AddReactionAsync(new Emoji("\U0001f495")); - /// - /// - /// The emoji used to react to this message. - /// The options to be used when sending the request. - /// - /// A task that represents the asynchronous operation for adding a reaction to this message. - /// - /// - Task AddReactionAsync(IEmote emote, RequestOptions options = null); - /// - /// Removes a reaction from message. - /// - /// - /// The following example removes the reaction, 💕, added by the message author from the message. - /// - /// await msg.RemoveReactionAsync(new Emoji("\U0001f495"), msg.Author); - /// - /// - /// The emoji used to react to this message. - /// The user that added the emoji. - /// The options to be used when sending the request. - /// - /// A task that represents the asynchronous operation for removing a reaction to this message. - /// - /// - Task RemoveReactionAsync(IEmote emote, IUser user, RequestOptions options = null); - /// - /// Removes a reaction from message. - /// - /// - /// The following example removes the reaction, 💕, added by the user with ID 84291986575613952 from the message. - /// - /// await msg.RemoveReactionAsync(new Emoji("\U0001f495"), 84291986575613952); - /// - /// - /// The emoji used to react to this message. - /// The ID of the user that added the emoji. - /// The options to be used when sending the request. - /// - /// A task that represents the asynchronous operation for removing a reaction to this message. - /// - /// - Task RemoveReactionAsync(IEmote emote, ulong userId, RequestOptions options = null); - /// - /// Removes all reactions from this message. - /// - /// The options to be used when sending the request. - /// - /// A task that represents the asynchronous removal operation. - /// - Task RemoveAllReactionsAsync(RequestOptions options = null); - - /// - /// Gets all users that reacted to a message with a given emote. - /// - /// - /// The following example gets the users that have reacted with the emoji 💕 to the message. - /// - /// var emoji = new Emoji("\U0001f495"); - /// var reactedUsers = await message.GetReactionUsersAsync(emoji, 100).FlattenAsync(); - /// - /// - /// The emoji that represents the reaction that you wish to get. - /// The number of users to request. - /// The options to be used when sending the request. - /// - /// A paged collection containing a read-only collection of users that has reacted to this message. - /// Flattening the paginated response into a collection of users with - /// is required if you wish to access the users. - /// - IAsyncEnumerable> GetReactionUsersAsync(IEmote emoji, int limit, RequestOptions options = null); - - /// /// Transforms this message's text into a human-readable form by resolving its tags. /// /// Determines how the user tag should be handled. diff --git a/src/Discord.Net.Rest/Entities/Messages/RestMessage.cs b/src/Discord.Net.Rest/Entities/Messages/RestMessage.cs index fa1c91376..29a9c9bd2 100644 --- a/src/Discord.Net.Rest/Entities/Messages/RestMessage.cs +++ b/src/Discord.Net.Rest/Entities/Messages/RestMessage.cs @@ -13,6 +13,7 @@ namespace Discord.Rest public abstract class RestMessage : RestEntity, IMessage, IUpdateable { private long _timestampTicks; + private ImmutableArray _reactions = ImmutableArray.Create(); /// public IMessageChannel Channel { get; } @@ -106,6 +107,22 @@ namespace Discord.Rest PartyId = model.Activity.Value.PartyId.GetValueOrDefault() }; } + + if (model.Reactions.IsSpecified) + { + var value = model.Reactions.Value; + if (value.Length > 0) + { + var reactions = ImmutableArray.CreateBuilder(value.Length); + for (int i = 0; i < value.Length; i++) + reactions.Add(RestReaction.Create(value[i])); + _reactions = reactions.ToImmutable(); + } + else + _reactions = ImmutableArray.Create(); + } + else + _reactions = ImmutableArray.Create(); } /// @@ -135,5 +152,24 @@ namespace Discord.Rest IReadOnlyCollection IMessage.Embeds => Embeds; /// IReadOnlyCollection IMessage.MentionedUserIds => MentionedUsers.Select(x => x.Id).ToImmutableArray(); + + /// + public IReadOnlyDictionary Reactions => _reactions.ToDictionary(x => x.Emote, x => new ReactionMetadata { ReactionCount = x.Count, IsMe = x.Me }); + + /// + 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.Id, emote, Discord, options); + /// + public Task RemoveReactionAsync(IEmote emote, ulong userId, RequestOptions options = null) + => MessageHelper.RemoveReactionAsync(this, userId, emote, Discord, options); + /// + public Task RemoveAllReactionsAsync(RequestOptions options = null) + => MessageHelper.RemoveAllReactionsAsync(this, Discord, options); + /// + public IAsyncEnumerable> GetReactionUsersAsync(IEmote emote, int limit, RequestOptions options = null) + => MessageHelper.GetReactionUsersAsync(this, emote, limit, Discord, options); } } diff --git a/src/Discord.Net.Rest/Entities/Messages/RestUserMessage.cs b/src/Discord.Net.Rest/Entities/Messages/RestUserMessage.cs index 3260ecf70..7d652687a 100644 --- a/src/Discord.Net.Rest/Entities/Messages/RestUserMessage.cs +++ b/src/Discord.Net.Rest/Entities/Messages/RestUserMessage.cs @@ -2,7 +2,6 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; -using System.Linq; using System.Threading.Tasks; using Model = Discord.API.Message; @@ -19,7 +18,6 @@ namespace Discord.Rest private ImmutableArray _attachments = ImmutableArray.Create(); private ImmutableArray _embeds = ImmutableArray.Create(); private ImmutableArray _tags = ImmutableArray.Create(); - private ImmutableArray _reactions = ImmutableArray.Create(); /// public override bool IsTTS => _isTTS; @@ -41,8 +39,6 @@ namespace Discord.Rest public override IReadOnlyCollection MentionedUsers => MessageHelper.FilterTagsByValue(TagType.UserMention, _tags); /// public override IReadOnlyCollection Tags => _tags; - /// - public IReadOnlyDictionary 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) @@ -117,22 +113,6 @@ namespace Discord.Rest } } - if (model.Reactions.IsSpecified) - { - var value = model.Reactions.Value; - if (value.Length > 0) - { - var reactions = ImmutableArray.CreateBuilder(value.Length); - for (int i = 0; i < value.Length; i++) - reactions.Add(RestReaction.Create(value[i])); - _reactions = reactions.ToImmutable(); - } - else - _reactions = ImmutableArray.Create(); - } - else - _reactions = ImmutableArray.Create(); - if (model.Content.IsSpecified) { var text = model.Content.Value; @@ -151,22 +131,6 @@ namespace Discord.Rest } /// - 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.Id, emote, Discord, options); - /// - public Task RemoveReactionAsync(IEmote emote, ulong userId, RequestOptions options = null) - => MessageHelper.RemoveReactionAsync(this, userId, emote, Discord, options); - /// - public Task RemoveAllReactionsAsync(RequestOptions options = null) - => MessageHelper.RemoveAllReactionsAsync(this, Discord, options); - /// - public IAsyncEnumerable> GetReactionUsersAsync(IEmote emote, int limit, RequestOptions options = null) - => MessageHelper.GetReactionUsersAsync(this, emote, limit, Discord, options); - - /// public Task PinAsync(RequestOptions options = null) => MessageHelper.PinAsync(this, Discord, options); /// diff --git a/src/Discord.Net.WebSocket/Entities/Messages/SocketMessage.cs b/src/Discord.Net.WebSocket/Entities/Messages/SocketMessage.cs index 4d3efa656..ae42d9d61 100644 --- a/src/Discord.Net.WebSocket/Entities/Messages/SocketMessage.cs +++ b/src/Discord.Net.WebSocket/Entities/Messages/SocketMessage.cs @@ -14,6 +14,7 @@ namespace Discord.WebSocket public abstract class SocketMessage : SocketEntity, IMessage { private long _timestampTicks; + private readonly List _reactions = new List(); /// /// Gets the author of this message. @@ -89,6 +90,8 @@ namespace Discord.WebSocket public virtual IReadOnlyCollection MentionedUsers => ImmutableArray.Create(); /// public virtual IReadOnlyCollection Tags => ImmutableArray.Create(); + /// + public IReadOnlyDictionary 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) }); /// public DateTimeOffset Timestamp => DateTimeUtils.FromTicks(_timestampTicks); @@ -169,5 +172,35 @@ namespace Discord.WebSocket IReadOnlyCollection IMessage.MentionedRoleIds => MentionedRoles.Select(x => x.Id).ToImmutableArray(); /// IReadOnlyCollection IMessage.MentionedUserIds => MentionedUsers.Select(x => x.Id).ToImmutableArray(); + + internal void AddReaction(SocketReaction reaction) + { + _reactions.Add(reaction); + } + internal void RemoveReaction(SocketReaction reaction) + { + if (_reactions.Contains(reaction)) + _reactions.Remove(reaction); + } + internal void ClearReactions() + { + _reactions.Clear(); + } + + /// + 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.Id, emote, Discord, options); + /// + public Task RemoveReactionAsync(IEmote emote, ulong userId, RequestOptions options = null) + => MessageHelper.RemoveReactionAsync(this, userId, emote, Discord, options); + /// + public Task RemoveAllReactionsAsync(RequestOptions options = null) + => MessageHelper.RemoveAllReactionsAsync(this, Discord, options); + /// + public IAsyncEnumerable> GetReactionUsersAsync(IEmote emote, int limit, RequestOptions options = null) + => MessageHelper.GetReactionUsersAsync(this, emote, limit, Discord, options); } } diff --git a/src/Discord.Net.WebSocket/Entities/Messages/SocketUserMessage.cs b/src/Discord.Net.WebSocket/Entities/Messages/SocketUserMessage.cs index 948e4576e..b26dfe5fb 100644 --- a/src/Discord.Net.WebSocket/Entities/Messages/SocketUserMessage.cs +++ b/src/Discord.Net.WebSocket/Entities/Messages/SocketUserMessage.cs @@ -15,7 +15,6 @@ namespace Discord.WebSocket [DebuggerDisplay(@"{DebuggerDisplay,nq}")] public class SocketUserMessage : SocketMessage, IUserMessage { - private readonly List _reactions = new List(); private bool _isMentioningEveryone, _isTTS, _isPinned, _isSuppressed; private long? _editedTimestampTicks; private ImmutableArray _attachments = ImmutableArray.Create(); @@ -42,8 +41,6 @@ namespace Discord.WebSocket public override IReadOnlyCollection MentionedRoles => MessageHelper.FilterTagsByValue(TagType.RoleMention, _tags); /// public override IReadOnlyCollection MentionedUsers => MessageHelper.FilterTagsByValue(TagType.UserMention, _tags); - /// - public IReadOnlyDictionary 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) @@ -126,20 +123,7 @@ namespace Discord.WebSocket model.Content = text; } } - internal void AddReaction(SocketReaction reaction) - { - _reactions.Add(reaction); - } - internal void RemoveReaction(SocketReaction reaction) - { - if (_reactions.Contains(reaction)) - _reactions.Remove(reaction); - } - internal void ClearReactions() - { - _reactions.Clear(); - } - + /// /// Only the author of a message may modify the message. /// Message content is too long, length must be less or equal to . @@ -147,22 +131,6 @@ namespace Discord.WebSocket => MessageHelper.ModifyAsync(this, Discord, func, 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.Id, emote, Discord, options); - /// - public Task RemoveReactionAsync(IEmote emote, ulong userId, RequestOptions options = null) - => MessageHelper.RemoveReactionAsync(this, userId, emote, Discord, options); - /// - public Task RemoveAllReactionsAsync(RequestOptions options = null) - => MessageHelper.RemoveAllReactionsAsync(this, Discord, options); - /// - public IAsyncEnumerable> GetReactionUsersAsync(IEmote emote, int limit, RequestOptions options = null) - => MessageHelper.GetReactionUsersAsync(this, emote, limit, Discord, options); - - /// public Task PinAsync(RequestOptions options = null) => MessageHelper.PinAsync(this, Discord, options); ///