From 79ca9188942edc11413a9ce4a67961f31c7e8c2d Mon Sep 17 00:00:00 2001 From: Lala Sabathil Date: Thu, 12 Dec 2024 14:25:27 +0100 Subject: [PATCH 01/33] =?UTF-8?q?chore:=20something=20=E2=84=A2=EF=B8=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Enums/Interaction/ComponentType.cs | 22 ++++++++++++++++++- DisCatSharp/Enums/Message/MessageFlags.cs | 7 +++++- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/DisCatSharp/Enums/Interaction/ComponentType.cs b/DisCatSharp/Enums/Interaction/ComponentType.cs index c1ecfc4c33..669448c75c 100644 --- a/DisCatSharp/Enums/Interaction/ComponentType.cs +++ b/DisCatSharp/Enums/Interaction/ComponentType.cs @@ -45,8 +45,28 @@ public enum ComponentType /// ChannelSelect = 8, + /// + /// A text display. + /// + TextDisplay = 10, + + /// + /// A media gallery. + /// + MediaGallery = 12, + /// /// A file. /// - File = 13 + File = 13, + + /// + /// A seperator. + /// + Seperator = 14, + + /// + /// Cannot be used by bots. + /// + ContentInventoryEntry = 15 } diff --git a/DisCatSharp/Enums/Message/MessageFlags.cs b/DisCatSharp/Enums/Message/MessageFlags.cs index 2ea21e97e7..a100f85176 100644 --- a/DisCatSharp/Enums/Message/MessageFlags.cs +++ b/DisCatSharp/Enums/Message/MessageFlags.cs @@ -86,5 +86,10 @@ public enum MessageFlags /// /// The message is a voice message. /// - IsVoiceMessage = 1 << 13 + IsVoiceMessage = 1 << 13, + + /// + /// The message uses the UI Kit. + /// + UIKit = 1 << 15 } From d57f2cd322025143b9b785682d5b8a29efc64931 Mon Sep 17 00:00:00 2001 From: Lala Sabathil Date: Sat, 14 Dec 2024 21:07:06 +0100 Subject: [PATCH 02/33] chore: some stuff --- .../UIKit/DiscordFileDisplayComponent.cs | 57 +++++++++++++ .../UIKit/DiscordMediaGalleryComponent.cs | 51 ++++++++++++ .../UIKit/DiscordMediaGalleryItem.cs | 46 +++++++++++ .../Components/UIKit/DiscordMediaItem.cs | 30 +++++++ .../UIKit/DiscordSeperatorComponent.cs | 58 ++++++++++++++ .../UIKit/DiscordTextDisplayComponent.cs | 48 +++++++++++ .../DiscordInteractionResponseBuilder.cs | 2 +- .../Entities/Message/DiscordMessage.cs | 18 ++--- .../Entities/Message/DiscordMessageBuilder.cs | 79 +++++++++++++++---- .../Enums/Interaction/SeperatorSpacingSize.cs | 17 ++++ .../Abstractions/Rest/RestChannelPayloads.cs | 2 +- DisCatSharp/Net/Rest/DiscordApiClient.cs | 6 +- .../DiscordComponentJsonConverter.cs | 4 + 13 files changed, 388 insertions(+), 30 deletions(-) create mode 100644 DisCatSharp/Entities/Interaction/Components/UIKit/DiscordFileDisplayComponent.cs create mode 100644 DisCatSharp/Entities/Interaction/Components/UIKit/DiscordMediaGalleryComponent.cs create mode 100644 DisCatSharp/Entities/Interaction/Components/UIKit/DiscordMediaGalleryItem.cs create mode 100644 DisCatSharp/Entities/Interaction/Components/UIKit/DiscordMediaItem.cs create mode 100644 DisCatSharp/Entities/Interaction/Components/UIKit/DiscordSeperatorComponent.cs create mode 100644 DisCatSharp/Entities/Interaction/Components/UIKit/DiscordTextDisplayComponent.cs create mode 100644 DisCatSharp/Enums/Interaction/SeperatorSpacingSize.cs diff --git a/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordFileDisplayComponent.cs b/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordFileDisplayComponent.cs new file mode 100644 index 0000000000..ec70580611 --- /dev/null +++ b/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordFileDisplayComponent.cs @@ -0,0 +1,57 @@ +using System; + +using DisCatSharp.Enums; + +using Newtonsoft.Json; + +namespace DisCatSharp.Entities; + +/// +/// Represents a file display component that can be submitted. Fires +/// event when submitted. +/// +public sealed class DiscordFileDisplayComponent : DiscordComponent +{ + /// + /// Constructs a new . + /// + internal DiscordFileDisplayComponent() + { + this.Type = ComponentType.File; + } + + /// + /// Constructs a new file display component based on another file display component. + /// + /// The button to copy. + public DiscordFileDisplayComponent(DiscordFileDisplayComponent other) + : this() + { + this.File = other.File; + this.Spoiler = other.Spoiler; + } + + /// + /// Constructs a new file display component field with the specified options. + /// + /// The file url. + /// Whether this file should be marked as spoiler. + public DiscordFileDisplayComponent(string url, bool? spoiler) + { + this.File = new(url); + this.Spoiler = spoiler; + this.Type = ComponentType.File; + } + + /// + /// Gets the file. + /// + [JsonProperty("media")] + public DiscordMediaItem File { get; internal set; } + + /// + /// Gets whether this file should be marked as spoiler. + /// + [JsonProperty("spoiler", NullValueHandling = NullValueHandling.Ignore)] + public bool? Spoiler { get; internal set; } +} diff --git a/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordMediaGalleryComponent.cs b/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordMediaGalleryComponent.cs new file mode 100644 index 0000000000..df03272c2f --- /dev/null +++ b/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordMediaGalleryComponent.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +using DisCatSharp.Enums; + +using Newtonsoft.Json; + +namespace DisCatSharp.Entities; + +/// +/// Represents a media gallery component that can be submitted. Fires +/// event when submitted. +/// +public sealed class DiscordMediaGalleryComponent : DiscordComponent +{ + /// + /// Constructs a new . + /// + internal DiscordMediaGalleryComponent() + { + this.Type = ComponentType.MediaGallery; + } + + /// + /// Constructs a new media gallery component based on another media gallery component. + /// + /// The button to copy. + public DiscordMediaGalleryComponent(DiscordMediaGalleryComponent other) + : this() + { + this.Items = other.Items; + } + + /// + /// Constructs a new media gallery component field with the specified options. + /// + /// The media gallery items. + /// Is thrown when no label is set. + public DiscordMediaGalleryComponent(IEnumerable items) + { + this.Items = items.ToList(); + this.Type = ComponentType.MediaGallery; + } + + /// + /// The content for the media gallery. + /// + [JsonProperty("content", NullValueHandling = NullValueHandling.Ignore)] + public IReadOnlyList Items { get; internal set; } = []; +} diff --git a/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordMediaGalleryItem.cs b/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordMediaGalleryItem.cs new file mode 100644 index 0000000000..c673abeabd --- /dev/null +++ b/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordMediaGalleryItem.cs @@ -0,0 +1,46 @@ +using Newtonsoft.Json; + +namespace DisCatSharp.Entities; + +/// +/// Represents a media gallery item. +/// +public sealed class DiscordMediaGalleryItem +{ + /// + /// Constructs a new empty . + /// + internal DiscordMediaGalleryItem() + { } + + /// + /// Constructs a new . + /// + /// The url. + /// The description. + /// Whether this item should be marked as spoiler. + public DiscordMediaGalleryItem(string url, string? description, bool? spoiler) + { + this.Media = new(url); + this.Description = description; + this.Spoiler = spoiler; + } + + /// + /// Gets the media item. + /// + [JsonProperty("media")] + public DiscordMediaItem Media { get; internal set; } + + /// + /// Gets the description. + /// + [JsonProperty("description", NullValueHandling = NullValueHandling.Ignore)] + public string? Description { get; internal set; } + + /// + /// Gets whether this gallery item should be marked as spoiler. + /// + [JsonProperty("spoiler", NullValueHandling = NullValueHandling.Ignore)] + public bool? Spoiler { get; internal set; } +} diff --git a/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordMediaItem.cs b/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordMediaItem.cs new file mode 100644 index 0000000000..00f7f1c588 --- /dev/null +++ b/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordMediaItem.cs @@ -0,0 +1,30 @@ +using Newtonsoft.Json; + +namespace DisCatSharp.Entities; + +/// +/// Represents a media item. +/// +public sealed class DiscordMediaItem +{ + /// + /// Constructs a new empty . + /// + internal DiscordMediaItem() + { } + + /// + /// Constructs a new . + /// + /// The items url. + internal DiscordMediaItem(string url) + { + this.Url = url; + } + + /// + /// Gets the url. + /// + [JsonProperty("url")] + public string Url { get; internal set; } +} diff --git a/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordSeperatorComponent.cs b/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordSeperatorComponent.cs new file mode 100644 index 0000000000..031a378e01 --- /dev/null +++ b/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordSeperatorComponent.cs @@ -0,0 +1,58 @@ +using System; + +using DisCatSharp.Enums; + +using Newtonsoft.Json; + +namespace DisCatSharp.Entities; + +/// +/// Represents a seperator component that can be submitted. Fires +/// event when submitted. +/// +public sealed class DiscordSeperatorComponent : DiscordComponent +{ + /// + /// Constructs a new . + /// + internal DiscordSeperatorComponent() + { + this.Type = ComponentType.Seperator; + } + + /// + /// Constructs a new seperator component based on another seperator component. + /// + /// The button to copy. + public DiscordSeperatorComponent(DiscordSeperatorComponent other) + : this() + { + this.Divider = other.Divider; + this.Spacing = other.Spacing; + } + + /// + /// Constructs a new seperator component field with the specified options. + /// + /// Whether this is a divider. + /// The spacing size. + /// Is thrown when no label is set. + public DiscordSeperatorComponent(bool? divider = null, SeperatorSpacingSize? spacing = null) + { + this.Divider = divider; + this.Spacing = spacing; + this.Type = ComponentType.Seperator; + } + + /// + /// The spacing size. + /// + [JsonProperty("spacing", NullValueHandling = NullValueHandling.Ignore)] + public SeperatorSpacingSize? Spacing { get; set; } + + /// + /// Whether this is a divider. + /// + [JsonProperty("divider", NullValueHandling = NullValueHandling.Ignore)] + public bool? Divider { get; internal set; } +} diff --git a/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordTextDisplayComponent.cs b/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordTextDisplayComponent.cs new file mode 100644 index 0000000000..7e72998b84 --- /dev/null +++ b/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordTextDisplayComponent.cs @@ -0,0 +1,48 @@ +using System; + +using DisCatSharp.Enums; + +using Newtonsoft.Json; + +namespace DisCatSharp.Entities; + +/// +/// Represents a text display component that can be submitted. Fires +/// event when submitted. +/// +public sealed class DiscordTextDisplayComponent : DiscordComponent +{ + /// + /// Constructs a new . + /// + internal DiscordTextDisplayComponent() + { + this.Type = ComponentType.TextDisplay; + } + + /// + /// Constructs a new text display component based on another text display component. + /// + /// The button to copy. + public DiscordTextDisplayComponent(DiscordTextDisplayComponent other) + : this() + { + this.Content = other.Content; + } + + /// + /// Constructs a new text display component field with the specified options. + /// + /// The content for the text display. + public DiscordTextDisplayComponent(string content) + { + this.Content = content; + this.Type = ComponentType.TextDisplay; + } + + /// + /// The content for the text display. + /// + [JsonProperty("content")] + public string Content { get; internal set; } +} diff --git a/DisCatSharp/Entities/Interaction/DiscordInteractionResponseBuilder.cs b/DisCatSharp/Entities/Interaction/DiscordInteractionResponseBuilder.cs index 627e362477..25c7cfb811 100644 --- a/DisCatSharp/Entities/Interaction/DiscordInteractionResponseBuilder.cs +++ b/DisCatSharp/Entities/Interaction/DiscordInteractionResponseBuilder.cs @@ -45,7 +45,7 @@ public DiscordInteractionResponseBuilder(DiscordMessageBuilder builder) this._content = builder.Content; this.Mentions = builder.Mentions; this._embeds.AddRange(builder.Embeds); - this._components.AddRange(builder.Components); + this._components.AddRange(builder.ActionRowComponents); } /// diff --git a/DisCatSharp/Entities/Message/DiscordMessage.cs b/DisCatSharp/Entities/Message/DiscordMessage.cs index d8a4f59c4d..f5fb98cf8d 100644 --- a/DisCatSharp/Entities/Message/DiscordMessage.cs +++ b/DisCatSharp/Entities/Message/DiscordMessage.cs @@ -635,8 +635,8 @@ internal void PopulateMentions() if (!string.IsNullOrWhiteSpace(this.Content)) if (guild != null) { - this.MentionedRolesInternal = this.MentionedRolesInternal.Union(this.MentionedRoleIds.Select(xid => guild.GetRole(xid))).ToList(); - this.MentionedChannelsInternal = this.MentionedChannelsInternal.Union(Utilities.GetChannelMentions(this.Content).Select(xid => guild.GetChannel(xid))).ToList(); + this.MentionedRolesInternal = [.. this.MentionedRolesInternal.Union(this.MentionedRoleIds.Select(guild.GetRole))!]; + this.MentionedChannelsInternal = [.. this.MentionedChannelsInternal.Union(Utilities.GetChannelMentions(this.Content).Select(guild.GetChannel))!]; } this.MentionedUsersInternal = [.. mentionedUsers]; @@ -651,7 +651,7 @@ internal void PopulateMentions() /// Thrown when an invalid parameter was provided. /// Thrown when Discord is unable to process the request. public Task ModifyAsync(Optional content) - => this.Discord.ApiClient.EditMessageAsync(this.ChannelId, this.Id, content, default, this.GetMentions(), default, default, Array.Empty(), default); + => this.Flags?.HasMessageFlag(MessageFlags.UIKit) ?? false ? throw new InvalidOperationException("UI Kit messages can not have content.") : this.Discord.ApiClient.EditMessageAsync(this.ChannelId, this.Id, content, default, this.GetMentions(), default, default, [], default); /// /// Edits the message. @@ -662,7 +662,7 @@ public Task ModifyAsync(Optional content) /// Thrown when an invalid parameter was provided. /// Thrown when Discord is unable to process the request. public Task ModifyAsync(Optional embed = default) - => this.Discord.ApiClient.EditMessageAsync(this.ChannelId, this.Id, default, embed.Map(v => new[] { v }).ValueOr([]), this.GetMentions(), default, default, Array.Empty(), default); + => this.Flags?.HasMessageFlag(MessageFlags.UIKit) ?? false ? throw new InvalidOperationException("UI Kit messages can not have embeds.") : this.Discord.ApiClient.EditMessageAsync(this.ChannelId, this.Id, default, embed.Map(v => new[] { v }).ValueOr([]), this.GetMentions(), default, default, [], default); /// /// Edits the message. @@ -674,7 +674,7 @@ public Task ModifyAsync(Optional embed = default) /// Thrown when an invalid parameter was provided. /// Thrown when Discord is unable to process the request. public Task ModifyAsync(Optional content, Optional embed = default) - => this.Discord.ApiClient.EditMessageAsync(this.ChannelId, this.Id, content, embed.Map(v => new[] { v }).ValueOr([]), this.GetMentions(), default, default, Array.Empty(), default); + => this.Flags?.HasMessageFlag(MessageFlags.UIKit) ?? false ? throw new InvalidOperationException("UI Kit messages can not have content or embeds.") : this.Discord.ApiClient.EditMessageAsync(this.ChannelId, this.Id, content, embed.Map(v => new[] { v }).ValueOr([]), this.GetMentions(), default, default, [], default); /// /// Edits the message. @@ -686,7 +686,7 @@ public Task ModifyAsync(Optional content, OptionalThrown when an invalid parameter was provided. /// Thrown when Discord is unable to process the request. public Task ModifyAsync(Optional content, Optional> embeds = default) - => this.Discord.ApiClient.EditMessageAsync(this.ChannelId, this.Id, content, embeds, this.GetMentions(), default, default, Array.Empty(), default); + => this.Flags?.HasMessageFlag(MessageFlags.UIKit) ?? false ? throw new InvalidOperationException("UI Kit messages can not have content or embeds.") : this.Discord.ApiClient.EditMessageAsync(this.ChannelId, this.Id, content, embeds, this.GetMentions(), default, default, [], default); /// /// Edits the message. @@ -699,7 +699,7 @@ public Task ModifyAsync(Optional content, Optional ModifyAsync(DiscordMessageBuilder builder) { builder.Validate(true); - return await this.Discord.ApiClient.EditMessageAsync(this.ChannelId, this.Id, builder.Content, Optional.Some(builder.Embeds.AsEnumerable()), builder.Mentions, builder.Components, builder.Suppressed, builder.Files, builder.Attachments.Count > 0 + return await this.Discord.ApiClient.EditMessageAsync(this.ChannelId, this.Id, builder.Content, Optional.Some(builder.Embeds.AsEnumerable()), builder.Mentions, builder.ActionRowComponents, builder.Suppressed, builder.Files, builder.Attachments.Count > 0 ? Optional.Some(builder.Attachments.AsEnumerable()) : builder.KeepAttachmentsInternal.HasValue ? builder.KeepAttachmentsInternal.Value && this.Attachments is not null ? Optional.Some(this.Attachments.AsEnumerable()) : Array.Empty() @@ -737,7 +737,7 @@ public async Task ModifyAsync(Action acti var builder = new DiscordMessageBuilder(); action(builder); builder.Validate(true); - return await this.Discord.ApiClient.EditMessageAsync(this.ChannelId, this.Id, builder.Content, Optional.Some(builder.Embeds.AsEnumerable()), builder.Mentions, builder.Components, builder.Suppressed, builder.Files, builder.Attachments.Count > 0 + return await this.Discord.ApiClient.EditMessageAsync(this.ChannelId, this.Id, builder.Content, Optional.Some(builder.Embeds.AsEnumerable()), builder.Mentions, builder.ActionRowComponents, builder.Suppressed, builder.Files, builder.Attachments.Count > 0 ? Optional.Some(builder.Attachments.AsEnumerable()) : builder.KeepAttachmentsInternal.HasValue ? builder.KeepAttachmentsInternal.Value && this.Attachments is not null ? Optional.Some(this.Attachments.AsEnumerable()) : Array.Empty() @@ -983,7 +983,7 @@ private async Task> GetReactionsInternalAsync(Discord throw new ArgumentException("Cannot get a negative number of reactions' users."); if (limit == 0) - return Array.Empty(); + return []; var users = new List(limit); var remaining = limit; diff --git a/DisCatSharp/Entities/Message/DiscordMessageBuilder.cs b/DisCatSharp/Entities/Message/DiscordMessageBuilder.cs index dc9640e599..0e357b0514 100644 --- a/DisCatSharp/Entities/Message/DiscordMessageBuilder.cs +++ b/DisCatSharp/Entities/Message/DiscordMessageBuilder.cs @@ -13,9 +13,11 @@ public sealed class DiscordMessageBuilder { private readonly List _embeds = []; + internal readonly List ActionRowComponentsInternal = new(5); + internal readonly List AttachmentsInternal = []; - internal readonly List ComponentsInternal = new(5); + internal readonly List ComponentsInternal = new(10); internal readonly List FilesInternal = []; @@ -80,6 +82,11 @@ public DiscordEmbed Embed /// public bool IsVoiceMessage { get; private set; } + /// + /// Whether to send with ui kit. + /// + public bool IsUIKit { get; private set; } + /// /// Gets the Allowed Mentions for the message to be sent. /// @@ -90,10 +97,16 @@ public DiscordEmbed Embed /// public IReadOnlyCollection Files => this.FilesInternal; + /// + /// Gets the action row components that will be attached to the message. + /// + public IReadOnlyList ActionRowComponents => this.ActionRowComponentsInternal; + /// /// Gets the components that will be attached to the message. + /// Can only be used if used with ui kit. /// - public IReadOnlyList Components => this.ComponentsInternal; + public IReadOnlyList Components => this.ComponentsInternal; /// /// Gets the Attachments to be sent in the Message. @@ -219,11 +232,11 @@ public DiscordMessageBuilder AddComponents(IEnumerable 5) + if (ara.Length + this.ActionRowComponentsInternal.Count > 5) throw new ArgumentException("ActionRow count exceeds maximum of five."); foreach (var ar in ara) - this.ComponentsInternal.Add(ar); + this.ActionRowComponentsInternal.Add(ar); return this; } @@ -239,16 +252,31 @@ public DiscordMessageBuilder AddComponents(IEnumerable compone var cmpArr = components.ToArray(); var count = cmpArr.Length; - switch (count) + if (this.IsUIKit) { - case 0: - throw new ArgumentOutOfRangeException(nameof(components), "You must provide at least one component"); - case > 5: - throw new ArgumentException("Cannot add more than 5 components per action row!"); + switch (count) + { + case 0: + throw new ArgumentOutOfRangeException(nameof(components), "You must provide at least one component"); + case > 10: + throw new ArgumentException("Cannot add more than 10 components!"); + } + + this.ComponentsInternal.AddRange(cmpArr); + } + else + { + switch (count) + { + case 0: + throw new ArgumentOutOfRangeException(nameof(components), "You must provide at least one component"); + case > 5: + throw new ArgumentException("Cannot add more than 5 components per action row!"); + } + + var comp = new DiscordActionRowComponent(cmpArr); + this.ActionRowComponentsInternal.Add(comp); } - - var comp = new DiscordActionRowComponent(cmpArr); - this.ComponentsInternal.Add(comp); return this; } @@ -273,6 +301,15 @@ public DiscordMessageBuilder SuppressEmbeds(bool suppress = true) return this; } + /// + /// Sets the message to be send with ui kit. + /// + public DiscordMessageBuilder AsUiKitMessage(bool asUiKitMessage = true) + { + this.IsUIKit = asUiKitMessage; + return this; + } + /// /// Sets the message to be send as voice message. /// @@ -355,7 +392,7 @@ public DiscordMessageBuilder WithAllowedMentions(IEnumerable allowedMe if (this.Mentions != null) this.Mentions.AddRange(allowedMentions); else - this.Mentions = allowedMentions.ToList(); + this.Mentions = [.. allowedMentions]; return this; } @@ -508,7 +545,7 @@ public Task ModifyAsync(DiscordMessage msg) /// Clears all message components on this builder. /// public void ClearComponents() - => this.ComponentsInternal.Clear(); + => this.ActionRowComponentsInternal.Clear(); /// /// Clears the poll from this builder. @@ -528,6 +565,7 @@ public void Clear() this.FilesInternal.Clear(); this.ReplyId = null; this.MentionOnReply = false; + this.ActionRowComponentsInternal.Clear(); this.ComponentsInternal.Clear(); this.Suppressed = false; this.Sticker = null; @@ -537,6 +575,7 @@ public void Clear() this.EnforceNonce = false; this.Poll = null; this.IsVoiceMessage = false; + this.IsUIKit = false; } /// @@ -553,13 +592,19 @@ internal void Validate(bool isModify = false) if (!isModify) { - if (this.Files?.Count == 0 && string.IsNullOrEmpty(this.Content) && (!this.Embeds?.Any() ?? true) && this.Sticker is null && (!this.Components?.Any() ?? true) && this.Poll is null && this?.Attachments.Count == 0) + if (this.Files?.Count == 0 && string.IsNullOrEmpty(this.Content) && (!this.Embeds?.Any() ?? true) && this.Sticker is null && (!this.ActionRowComponents?.Any() ?? true) && (!this.Components?.Any() ?? true) && this.Poll is null && this?.Attachments.Count == 0) throw new ArgumentException("You must specify content, an embed, a sticker, a component, a poll or at least one file."); - if (this.Components.Count > 5) + if (this.IsUIKit && (!string.IsNullOrEmpty(this.Content) || (this.Embeds?.Any() ?? false))) + throw new ArgumentException("Using UI Kit mode. You cannot specify content or embeds."); + + if (this.IsUIKit && this.Components?.Count > 10) + throw new InvalidOperationException("You can only have 10 components per message."); + + if (!this.IsUIKit && this.ActionRowComponents?.Count > 5) throw new InvalidOperationException("You can only have 5 action rows per message."); - if (this.Components.Any(c => c.Components.Count > 5)) + if (this.ActionRowComponents?.Any(c => c.Components.Count > 5) ?? false) throw new InvalidOperationException("Action rows can only have 5 components"); if (this.EnforceNonce && string.IsNullOrEmpty(this.Nonce)) diff --git a/DisCatSharp/Enums/Interaction/SeperatorSpacingSize.cs b/DisCatSharp/Enums/Interaction/SeperatorSpacingSize.cs new file mode 100644 index 0000000000..50cd4ed5e1 --- /dev/null +++ b/DisCatSharp/Enums/Interaction/SeperatorSpacingSize.cs @@ -0,0 +1,17 @@ +namespace DisCatSharp.Enums; + +/// +/// Represents the sperator spacing size of a . +/// +public enum SeperatorSpacingSize +{ + /// + /// A small spacing size. + /// + Small = 1, + + /// + /// A large spacing size. + /// + Large = 2 +} diff --git a/DisCatSharp/Net/Abstractions/Rest/RestChannelPayloads.cs b/DisCatSharp/Net/Abstractions/Rest/RestChannelPayloads.cs index a890c6c672..64706c5292 100644 --- a/DisCatSharp/Net/Abstractions/Rest/RestChannelPayloads.cs +++ b/DisCatSharp/Net/Abstractions/Rest/RestChannelPayloads.cs @@ -280,7 +280,7 @@ internal class RestChannelMessageEditPayload : ObservableApiObject /// Gets or sets the components. /// [JsonProperty("components", NullValueHandling = NullValueHandling.Ignore)] - public IReadOnlyCollection Components { get; set; } + public IReadOnlyCollection Components { get; set; } /// /// Gets or sets a value indicating whether has embed. diff --git a/DisCatSharp/Net/Rest/DiscordApiClient.cs b/DisCatSharp/Net/Rest/DiscordApiClient.cs index 79ad62e6e4..58cef10851 100644 --- a/DisCatSharp/Net/Rest/DiscordApiClient.cs +++ b/DisCatSharp/Net/Rest/DiscordApiClient.cs @@ -3115,6 +3115,8 @@ internal async Task CreateMessageAsync(ulong channelId, DiscordM flags |= MessageFlags.SuppressNotifications; if (builder.IsVoiceMessage) flags |= MessageFlags.IsVoiceMessage; + if (builder.IsUIKit) + flags |= MessageFlags.UIKit; var pld = new RestChannelMessageCreatePayload { @@ -3126,7 +3128,7 @@ internal async Task CreateMessageAsync(ulong channelId, DiscordM IsTts = builder.IsTts, HasEmbed = builder.Embeds != null, Embeds = builder.Embeds, - Components = builder.Components, + Components = builder.IsUIKit ? builder.Components : builder.ActionRowComponents, Nonce = builder.Nonce, EnforceNonce = builder.EnforceNonce, DiscordPollRequest = builder.Poll?.Build(), @@ -5750,7 +5752,7 @@ internal async Task CreateThreadAsync( { Content = builder.Content, Attachments = builder.Attachments, - Components = builder.Components, + Components = builder.ActionRowComponents, HasContent = true, Embeds = builder.Embeds, //Flags = builder.Flags, diff --git a/DisCatSharp/Net/Serialization/DiscordComponentJsonConverter.cs b/DisCatSharp/Net/Serialization/DiscordComponentJsonConverter.cs index f1e57fe39e..5eaca716fb 100644 --- a/DisCatSharp/Net/Serialization/DiscordComponentJsonConverter.cs +++ b/DisCatSharp/Net/Serialization/DiscordComponentJsonConverter.cs @@ -54,6 +54,10 @@ public override void WriteJson(JsonWriter writer, object? value, JsonSerializer ComponentType.RoleSelect => new DiscordRoleSelectComponent(), ComponentType.MentionableSelect => new DiscordMentionableSelectComponent(), ComponentType.ChannelSelect => new DiscordChannelSelectComponent(), + ComponentType.TextDisplay => new DiscordTextDisplayComponent(), + ComponentType.MediaGallery => new DiscordMediaGalleryComponent(), + ComponentType.File => new DiscordFileDisplayComponent(), + ComponentType.Seperator => new DiscordSeperatorComponent(), _ => new() { Type = type From 58f8a3d94ffd5c5a672ed97d6303bccd1a92539a Mon Sep 17 00:00:00 2001 From: Lala Sabathil Date: Sun, 15 Dec 2024 23:55:56 +0100 Subject: [PATCH 03/33] minor inconvinience --- DisCatSharp/DisCatSharp.csproj | 6 ------ .../Interaction/Components/DiscordComponent.cs | 10 ++++++++-- .../Interaction/DiscordFollowupMessageBuilder.cs | 4 ++-- ...DiscordInteractionApplicationCommandCallbackData.cs | 2 +- .../Interaction/DiscordInteractionModalBuilder.cs | 8 ++++---- .../Interaction/DiscordInteractionResponseBuilder.cs | 4 ++-- DisCatSharp/Entities/Webhook/DiscordWebhookBuilder.cs | 6 +++--- .../Rest/RestApplicationCommandPayloads.cs | 2 +- .../Net/Abstractions/Rest/RestWebhookPayloads.cs | 4 ++-- DisCatSharp/Net/Rest/DiscordApiClient.cs | 6 +++--- 10 files changed, 26 insertions(+), 26 deletions(-) diff --git a/DisCatSharp/DisCatSharp.csproj b/DisCatSharp/DisCatSharp.csproj index 441caf96db..f5553fc95a 100644 --- a/DisCatSharp/DisCatSharp.csproj +++ b/DisCatSharp/DisCatSharp.csproj @@ -56,12 +56,6 @@ - - - - - - diff --git a/DisCatSharp/Entities/Interaction/Components/DiscordComponent.cs b/DisCatSharp/Entities/Interaction/Components/DiscordComponent.cs index ee2508d5dd..b52de451d8 100644 --- a/DisCatSharp/Entities/Interaction/Components/DiscordComponent.cs +++ b/DisCatSharp/Entities/Interaction/Components/DiscordComponent.cs @@ -24,8 +24,14 @@ internal DiscordComponent() public ComponentType Type { get; internal set; } /// - /// The Id of this component, if applicable. Not applicable on ActionRow(s) and link buttons. + /// The custom Id of this component, if applicable. Not applicable on ActionRow(s) and link buttons. /// [JsonProperty("custom_id", NullValueHandling = NullValueHandling.Ignore)] - public string CustomId { get; internal set; } + public string? CustomId { get; internal set; } + + /// + /// Gets the Id of the compenent. Determined by Discord. + /// + [JsonProperty("id", NullValueHandling = NullValueHandling.Ignore)] + public uint Id { get; internal set; } } diff --git a/DisCatSharp/Entities/Interaction/DiscordFollowupMessageBuilder.cs b/DisCatSharp/Entities/Interaction/DiscordFollowupMessageBuilder.cs index c1c958d333..1bc0f13f2c 100644 --- a/DisCatSharp/Entities/Interaction/DiscordFollowupMessageBuilder.cs +++ b/DisCatSharp/Entities/Interaction/DiscordFollowupMessageBuilder.cs @@ -10,7 +10,7 @@ namespace DisCatSharp.Entities; /// public sealed class DiscordFollowupMessageBuilder { - private readonly List _components = []; + private readonly List _components = []; private readonly List _embeds = []; @@ -119,7 +119,7 @@ public string Content /// /// Components to send on this followup message. /// - public IReadOnlyList Components => this._components; + public IReadOnlyList Components => this._components; /// /// Attachments to be send with this followup request. diff --git a/DisCatSharp/Entities/Interaction/DiscordInteractionApplicationCommandCallbackData.cs b/DisCatSharp/Entities/Interaction/DiscordInteractionApplicationCommandCallbackData.cs index f8776f5019..e7ca7da632 100644 --- a/DisCatSharp/Entities/Interaction/DiscordInteractionApplicationCommandCallbackData.cs +++ b/DisCatSharp/Entities/Interaction/DiscordInteractionApplicationCommandCallbackData.cs @@ -45,7 +45,7 @@ internal class DiscordInteractionApplicationCommandCallbackData : ObservableApiO /// Gets the components. /// [JsonProperty("components", NullValueHandling = NullValueHandling.Ignore)] - public IReadOnlyCollection? Components { get; internal set; } + public IReadOnlyCollection? Components { get; internal set; } /// /// Gets the autocomplete choices. diff --git a/DisCatSharp/Entities/Interaction/DiscordInteractionModalBuilder.cs b/DisCatSharp/Entities/Interaction/DiscordInteractionModalBuilder.cs index 6ac377b6d3..b73391c2a3 100644 --- a/DisCatSharp/Entities/Interaction/DiscordInteractionModalBuilder.cs +++ b/DisCatSharp/Entities/Interaction/DiscordInteractionModalBuilder.cs @@ -11,7 +11,7 @@ public sealed class DiscordInteractionModalBuilder { private readonly List _callbackHints = []; - private readonly List _components = []; + private readonly List _components = []; private string _title; @@ -47,7 +47,7 @@ public string Title /// /// Components to send on this interaction response. /// - public IReadOnlyList ModalComponents => this._components; + public IReadOnlyList ModalComponents => this._components; /// /// The hints to send on this interaction response. @@ -146,7 +146,7 @@ public DiscordInteractionModalBuilder AddModalComponents(params DiscordComponent throw new ArgumentException($"You try to add too many components. We already have {this._components.Count}."); foreach (var ar in ara) - this._components.Add(new(new List + this._components.Add(new DiscordActionRowComponent(new List { ar })); @@ -180,7 +180,7 @@ public DiscordInteractionModalBuilder AddModalComponents(IEnumerableThe current builder to chain calls with. internal DiscordInteractionModalBuilder AddModalComponents(DiscordComponent component) { - this._components.Add(new(new List + this._components.Add(new DiscordActionRowComponent(new List { component })); diff --git a/DisCatSharp/Entities/Interaction/DiscordInteractionResponseBuilder.cs b/DisCatSharp/Entities/Interaction/DiscordInteractionResponseBuilder.cs index 25c7cfb811..563357148c 100644 --- a/DisCatSharp/Entities/Interaction/DiscordInteractionResponseBuilder.cs +++ b/DisCatSharp/Entities/Interaction/DiscordInteractionResponseBuilder.cs @@ -14,7 +14,7 @@ public sealed class DiscordInteractionResponseBuilder private readonly List _choices = []; - private readonly List _components = []; + private readonly List _components = []; private readonly List _embeds = []; @@ -142,7 +142,7 @@ public string Content /// /// Components to send on this interaction response. /// - public IReadOnlyList Components => this._components; + public IReadOnlyList Components => this._components; /// /// The choices to send on this interaction response. diff --git a/DisCatSharp/Entities/Webhook/DiscordWebhookBuilder.cs b/DisCatSharp/Entities/Webhook/DiscordWebhookBuilder.cs index 319a9e6eb6..e08ae139bd 100644 --- a/DisCatSharp/Entities/Webhook/DiscordWebhookBuilder.cs +++ b/DisCatSharp/Entities/Webhook/DiscordWebhookBuilder.cs @@ -15,7 +15,7 @@ public sealed class DiscordWebhookBuilder { private readonly List _appliedTags = []; - private readonly List _components = []; + private readonly List _components = []; private readonly List _embeds = []; @@ -111,7 +111,7 @@ public string Content /// /// Gets the components. /// - public IReadOnlyList Components => this._components; + public IReadOnlyList Components => this._components; /// /// Attachments to keep on this webhook request. @@ -416,7 +416,7 @@ public DiscordWebhookBuilder AddMentions(IEnumerable mentions) if (this.Mentions != null) this.Mentions.AddRange(mentions); else - this.Mentions = mentions.ToList(); + this.Mentions = [.. mentions]; return this; } diff --git a/DisCatSharp/Net/Abstractions/Rest/RestApplicationCommandPayloads.cs b/DisCatSharp/Net/Abstractions/Rest/RestApplicationCommandPayloads.cs index b667cc1a98..2d949a59b0 100644 --- a/DisCatSharp/Net/Abstractions/Rest/RestApplicationCommandPayloads.cs +++ b/DisCatSharp/Net/Abstractions/Rest/RestApplicationCommandPayloads.cs @@ -265,7 +265,7 @@ internal sealed class RestFollowupMessageCreatePayload : ObservableApiObject /// Gets the components. /// [JsonProperty("components", NullValueHandling = NullValueHandling.Ignore)] - public IReadOnlyCollection Components { get; set; } + public IReadOnlyCollection Components { get; set; } /// /// Gets attachments. diff --git a/DisCatSharp/Net/Abstractions/Rest/RestWebhookPayloads.cs b/DisCatSharp/Net/Abstractions/Rest/RestWebhookPayloads.cs index 7caedb5cf4..0b616b4dd9 100644 --- a/DisCatSharp/Net/Abstractions/Rest/RestWebhookPayloads.cs +++ b/DisCatSharp/Net/Abstractions/Rest/RestWebhookPayloads.cs @@ -88,7 +88,7 @@ internal sealed class RestWebhookExecutePayload : ObservableApiObject /// Gets or sets the components. /// [JsonProperty("components", NullValueHandling = NullValueHandling.Ignore)] - public IEnumerable Components { get; set; } + public IEnumerable Components { get; set; } /// /// Gets or sets the attachments. @@ -148,7 +148,7 @@ internal sealed class RestWebhookMessageEditPayload : ObservableApiObject /// Gets or sets the components. /// [JsonProperty("components", NullValueHandling = NullValueHandling.Ignore)] - public IEnumerable Components { get; set; } + public IEnumerable Components { get; set; } [JsonProperty("flags", NullValueHandling = NullValueHandling.Ignore)] public MessageFlags? Flags { get; set; } diff --git a/DisCatSharp/Net/Rest/DiscordApiClient.cs b/DisCatSharp/Net/Rest/DiscordApiClient.cs index 58cef10851..420b024864 100644 --- a/DisCatSharp/Net/Rest/DiscordApiClient.cs +++ b/DisCatSharp/Net/Rest/DiscordApiClient.cs @@ -3038,7 +3038,7 @@ internal async Task GetMessageAsync(ulong channelId, ulong messa /// Thrown when the exceeds 2000 characters or is empty and /// if neither content, sticker, components and embeds are definied.. /// - internal async Task CreateMessageAsync(ulong channelId, string content, IEnumerable embeds, DiscordSticker sticker, ulong? replyMessageId, bool mentionReply, bool failOnInvalidReply, ReadOnlyCollection? components = null) + internal async Task CreateMessageAsync(ulong channelId, string content, IEnumerable embeds, DiscordSticker sticker, ulong? replyMessageId, bool mentionReply, bool failOnInvalidReply, ReadOnlyCollection? components = null) { if (content is { Length: > 2000 }) throw new ArgumentException("Message content length cannot exceed 2000 characters."); @@ -3473,7 +3473,7 @@ internal async Task GetChannelMessageAsync(ulong channelId, ulon /// The suppress_embed. /// The files. /// The attachments to keep. - internal async Task EditMessageAsync(ulong channelId, ulong messageId, Optional content, Optional> embeds, Optional> mentions, IReadOnlyList components, Optional suppressEmbed, IReadOnlyCollection files, Optional> attachments) + internal async Task EditMessageAsync(ulong channelId, ulong messageId, Optional content, Optional> embeds, Optional> mentions, IReadOnlyList components, Optional suppressEmbed, IReadOnlyCollection files, Optional> attachments) { if (embeds is { HasValue: true, Value: not null }) foreach (var embed in embeds.Value) @@ -7182,7 +7182,7 @@ internal async Task CreateInteractionRespons /// The builder. internal async Task CreateInteractionModalResponseAsync(ulong interactionId, string interactionToken, InteractionResponseType type, DiscordInteractionModalBuilder builder) { - if (builder.ModalComponents.Any(mc => mc.Components.Any(c => c.Type != ComponentType.InputText))) + if (builder.ModalComponents.Select(x => x as DiscordActionRowComponent).Any(mc => mc.Components.Any(c => c.Type != ComponentType.InputText))) throw new NotSupportedException("Can't send any other type then Input Text as Modal Component."); var pld = new RestInteractionModalResponsePayload From 4af87c2b4aee1dcf3a2c02e80f7b1e8251260451 Mon Sep 17 00:00:00 2001 From: Lala Sabathil Date: Mon, 16 Dec 2024 00:17:33 +0100 Subject: [PATCH 04/33] i love breaking stuff --- .../Entities/Core/DisCatSharpBuilder.cs | 19 +++++++ .../DiscordFollowupMessageBuilder.cs | 23 +++----- .../DiscordInteractionModalBuilder.cs | 32 +++++------ .../DiscordInteractionResponseBuilder.cs | 27 ++++----- .../Entities/Message/DiscordMessage.cs | 4 +- .../Entities/Message/DiscordMessageBuilder.cs | 49 ++++++---------- .../Entities/Webhook/DiscordWebhookBuilder.cs | 20 +++---- DisCatSharp/Net/Rest/DiscordApiClient.cs | 56 +++++++++---------- 8 files changed, 109 insertions(+), 121 deletions(-) create mode 100644 DisCatSharp/Entities/Core/DisCatSharpBuilder.cs diff --git a/DisCatSharp/Entities/Core/DisCatSharpBuilder.cs b/DisCatSharp/Entities/Core/DisCatSharpBuilder.cs new file mode 100644 index 0000000000..2d0e5b56d2 --- /dev/null +++ b/DisCatSharp/Entities/Core/DisCatSharpBuilder.cs @@ -0,0 +1,19 @@ +using System.Collections.Generic; + +namespace DisCatSharp.Entities.Core; + +/// +/// Represents the common base for most builders. +/// +public class DisCatSharpBuilder +{ + /// + /// The components. + /// + internal readonly List ComponentsInternal = []; + + /// + /// Components to send. + /// + public IReadOnlyList Components => this.ComponentsInternal; +} diff --git a/DisCatSharp/Entities/Interaction/DiscordFollowupMessageBuilder.cs b/DisCatSharp/Entities/Interaction/DiscordFollowupMessageBuilder.cs index 1bc0f13f2c..04126d5137 100644 --- a/DisCatSharp/Entities/Interaction/DiscordFollowupMessageBuilder.cs +++ b/DisCatSharp/Entities/Interaction/DiscordFollowupMessageBuilder.cs @@ -3,15 +3,15 @@ using System.IO; using System.Linq; +using DisCatSharp.Entities.Core; + namespace DisCatSharp.Entities; /// /// Constructs a followup message to an interaction. /// -public sealed class DiscordFollowupMessageBuilder +public sealed class DiscordFollowupMessageBuilder : DisCatSharpBuilder { - private readonly List _components = []; - private readonly List _embeds = []; private readonly List _files = []; @@ -116,11 +116,6 @@ public string Content /// public IReadOnlyList Files => this._files; - /// - /// Components to send on this followup message. - /// - public IReadOnlyList Components => this._components; - /// /// Attachments to be send with this followup request. /// @@ -154,11 +149,11 @@ public DiscordFollowupMessageBuilder AddComponents(IEnumerable 5) + if (ara.Length + this.ComponentsInternal.Count > 5) throw new ArgumentException("ActionRow count exceeds maximum of five."); foreach (var ar in ara) - this._components.Add(ar); + this.ComponentsInternal.Add(ar); return this; } @@ -178,7 +173,7 @@ public DiscordFollowupMessageBuilder AddComponents(IEnumerable throw new ArgumentException("Cannot add more than 5 components per action row!"); var arc = new DiscordActionRowComponent(compArr); - this._components.Add(arc); + this.ComponentsInternal.Add(arc); return this; } @@ -342,7 +337,7 @@ public DiscordFollowupMessageBuilder AddMentions(IEnumerable mentions) if (this.Mentions != null) this.Mentions.AddRange(mentions); else - this.Mentions = mentions.ToList(); + this.Mentions = [.. mentions]; return this; } @@ -390,7 +385,7 @@ public DiscordFollowupMessageBuilder AsSilentMessage() /// Clears all message components on this builder. /// public void ClearComponents() - => this._components.Clear(); + => this.ComponentsInternal.Clear(); /// /// Clears the poll from this builder. @@ -409,7 +404,7 @@ public void Clear() this.Mentions = null; this._files.Clear(); this.IsEphemeral = false; - this._components.Clear(); + this.ComponentsInternal.Clear(); } /// diff --git a/DisCatSharp/Entities/Interaction/DiscordInteractionModalBuilder.cs b/DisCatSharp/Entities/Interaction/DiscordInteractionModalBuilder.cs index b73391c2a3..0a999cd6b8 100644 --- a/DisCatSharp/Entities/Interaction/DiscordInteractionModalBuilder.cs +++ b/DisCatSharp/Entities/Interaction/DiscordInteractionModalBuilder.cs @@ -2,17 +2,17 @@ using System.Collections.Generic; using System.Linq; +using DisCatSharp.Entities.Core; + namespace DisCatSharp.Entities; /// /// Constructs an interaction modal response. /// -public sealed class DiscordInteractionModalBuilder +public sealed class DiscordInteractionModalBuilder : DisCatSharpBuilder { private readonly List _callbackHints = []; - private readonly List _components = []; - private string _title; /// @@ -47,7 +47,7 @@ public string Title /// /// Components to send on this interaction response. /// - public IReadOnlyList ModalComponents => this._components; + public IReadOnlyList ModalComponents => this.Components.Select(c => c as DiscordActionRowComponent).ToList()!; /// /// The hints to send on this interaction response. @@ -142,14 +142,14 @@ public DiscordInteractionModalBuilder AddModalComponents(params DiscordComponent throw new ArgumentException("You can only add 5 components to modals."); - if (this._components.Count + ara.Length > 5) - throw new ArgumentException($"You try to add too many components. We already have {this._components.Count}."); + if (this.ComponentsInternal.Count + ara.Length > 5) + throw new ArgumentException($"You try to add too many components. We already have {this.ComponentsInternal.Count}."); foreach (var ar in ara) - this._components.Add(new DiscordActionRowComponent(new List - { + this.ComponentsInternal.Add(new DiscordActionRowComponent( + [ ar - })); + ])); return this; } @@ -164,11 +164,11 @@ public DiscordInteractionModalBuilder AddModalComponents(IEnumerable 5) + if (ara.Length + this.ComponentsInternal.Count > 5) throw new ArgumentException("ActionRow count exceeds maximum of five."); foreach (var ar in ara) - this._components.Add(ar); + this.ComponentsInternal.Add(ar); return this; } @@ -180,10 +180,10 @@ public DiscordInteractionModalBuilder AddModalComponents(IEnumerableThe current builder to chain calls with. internal DiscordInteractionModalBuilder AddModalComponents(DiscordComponent component) { - this._components.Add(new DiscordActionRowComponent(new List - { + this.ComponentsInternal.Add(new DiscordActionRowComponent( + [ component - })); + ])); return this; } @@ -192,14 +192,14 @@ internal DiscordInteractionModalBuilder AddModalComponents(DiscordComponent comp /// Clears all message components on this builder. /// public void ClearComponents() - => this._components.Clear(); + => this.ComponentsInternal.Clear(); /// /// Allows for clearing the Interaction Response Builder so that it can be used again to send a new response. /// public void Clear() { - this._components.Clear(); + this.ComponentsInternal.Clear(); this.Title = null!; this.CustomId = null!; } diff --git a/DisCatSharp/Entities/Interaction/DiscordInteractionResponseBuilder.cs b/DisCatSharp/Entities/Interaction/DiscordInteractionResponseBuilder.cs index 563357148c..53139c92e8 100644 --- a/DisCatSharp/Entities/Interaction/DiscordInteractionResponseBuilder.cs +++ b/DisCatSharp/Entities/Interaction/DiscordInteractionResponseBuilder.cs @@ -3,19 +3,19 @@ using System.IO; using System.Linq; +using DisCatSharp.Entities.Core; + namespace DisCatSharp.Entities; /// /// Constructs an interaction response. /// -public sealed class DiscordInteractionResponseBuilder +public sealed class DiscordInteractionResponseBuilder : DisCatSharpBuilder { private readonly List _callbackHints = []; private readonly List _choices = []; - private readonly List _components = []; - private readonly List _embeds = []; private readonly List _files = []; @@ -45,7 +45,7 @@ public DiscordInteractionResponseBuilder(DiscordMessageBuilder builder) this._content = builder.Content; this.Mentions = builder.Mentions; this._embeds.AddRange(builder.Embeds); - this._components.AddRange(builder.ActionRowComponents); + this.ComponentsInternal.AddRange(builder.Components); } /// @@ -139,11 +139,6 @@ public string Content /// public IReadOnlyList Files => this._files; - /// - /// Components to send on this interaction response. - /// - public IReadOnlyList Components => this._components; - /// /// The choices to send on this interaction response. /// Mutually exclusive with content, embed, and components. @@ -208,11 +203,11 @@ public DiscordInteractionResponseBuilder AddComponents(IEnumerable 5) + if (ara.Length + this.ComponentsInternal.Count > 5) throw new ArgumentException("ActionRow count exceeds maximum of five."); foreach (var ar in ara) - this._components.Add(ar); + this.ComponentsInternal.Add(ar); return this; } @@ -232,7 +227,7 @@ public DiscordInteractionResponseBuilder AddComponents(IEnumerable menti if (this.Mentions != null) this.Mentions.AddRange(mentions); else - this.Mentions = mentions.ToList(); + this.Mentions = [.. mentions]; return this; } @@ -478,7 +473,7 @@ public DiscordInteractionResponseBuilder AddAutoCompleteChoices(params DiscordAp /// Clears all message components on this builder. /// public void ClearComponents() - => this._components.Clear(); + => this.ComponentsInternal.Clear(); /// /// Clears the poll from this builder. @@ -491,12 +486,12 @@ public void ClearPoll() /// public void Clear() { - this.Content = null; + this.Content = null!; this._embeds.Clear(); this.IsTts = false; this.IsEphemeral = false; this.Mentions = null; - this._components.Clear(); + this.ComponentsInternal.Clear(); this._choices.Clear(); this._files.Clear(); this.Poll = null; diff --git a/DisCatSharp/Entities/Message/DiscordMessage.cs b/DisCatSharp/Entities/Message/DiscordMessage.cs index f5fb98cf8d..39260fbe42 100644 --- a/DisCatSharp/Entities/Message/DiscordMessage.cs +++ b/DisCatSharp/Entities/Message/DiscordMessage.cs @@ -699,7 +699,7 @@ public Task ModifyAsync(Optional content, Optional ModifyAsync(DiscordMessageBuilder builder) { builder.Validate(true); - return await this.Discord.ApiClient.EditMessageAsync(this.ChannelId, this.Id, builder.Content, Optional.Some(builder.Embeds.AsEnumerable()), builder.Mentions, builder.ActionRowComponents, builder.Suppressed, builder.Files, builder.Attachments.Count > 0 + return await this.Discord.ApiClient.EditMessageAsync(this.ChannelId, this.Id, builder.Content, Optional.Some(builder.Embeds.AsEnumerable()), builder.Mentions, builder.Components, builder.Suppressed, builder.Files, builder.Attachments.Count > 0 ? Optional.Some(builder.Attachments.AsEnumerable()) : builder.KeepAttachmentsInternal.HasValue ? builder.KeepAttachmentsInternal.Value && this.Attachments is not null ? Optional.Some(this.Attachments.AsEnumerable()) : Array.Empty() @@ -737,7 +737,7 @@ public async Task ModifyAsync(Action acti var builder = new DiscordMessageBuilder(); action(builder); builder.Validate(true); - return await this.Discord.ApiClient.EditMessageAsync(this.ChannelId, this.Id, builder.Content, Optional.Some(builder.Embeds.AsEnumerable()), builder.Mentions, builder.ActionRowComponents, builder.Suppressed, builder.Files, builder.Attachments.Count > 0 + return await this.Discord.ApiClient.EditMessageAsync(this.ChannelId, this.Id, builder.Content, Optional.Some(builder.Embeds.AsEnumerable()), builder.Mentions, builder.Components, builder.Suppressed, builder.Files, builder.Attachments.Count > 0 ? Optional.Some(builder.Attachments.AsEnumerable()) : builder.KeepAttachmentsInternal.HasValue ? builder.KeepAttachmentsInternal.Value && this.Attachments is not null ? Optional.Some(this.Attachments.AsEnumerable()) : Array.Empty() diff --git a/DisCatSharp/Entities/Message/DiscordMessageBuilder.cs b/DisCatSharp/Entities/Message/DiscordMessageBuilder.cs index 0e357b0514..df3a0d393a 100644 --- a/DisCatSharp/Entities/Message/DiscordMessageBuilder.cs +++ b/DisCatSharp/Entities/Message/DiscordMessageBuilder.cs @@ -4,21 +4,19 @@ using System.Linq; using System.Threading.Tasks; +using DisCatSharp.Entities.Core; + namespace DisCatSharp.Entities; /// -/// Constructs a Message to be sent. +/// Constructs a message to be sent. /// -public sealed class DiscordMessageBuilder +public sealed class DiscordMessageBuilder : DisCatSharpBuilder { private readonly List _embeds = []; - internal readonly List ActionRowComponentsInternal = new(5); - internal readonly List AttachmentsInternal = []; - internal readonly List ComponentsInternal = new(10); - internal readonly List FilesInternal = []; private string _content; @@ -97,17 +95,6 @@ public DiscordEmbed Embed /// public IReadOnlyCollection Files => this.FilesInternal; - /// - /// Gets the action row components that will be attached to the message. - /// - public IReadOnlyList ActionRowComponents => this.ActionRowComponentsInternal; - - /// - /// Gets the components that will be attached to the message. - /// Can only be used if used with ui kit. - /// - public IReadOnlyList Components => this.ComponentsInternal; - /// /// Gets the Attachments to be sent in the Message. /// @@ -232,11 +219,11 @@ public DiscordMessageBuilder AddComponents(IEnumerable 5) + if (ara.Length + this.ComponentsInternal.Count > 5) throw new ArgumentException("ActionRow count exceeds maximum of five."); foreach (var ar in ara) - this.ActionRowComponentsInternal.Add(ar); + this.ComponentsInternal.Add(ar); return this; } @@ -275,7 +262,7 @@ public DiscordMessageBuilder AddComponents(IEnumerable compone } var comp = new DiscordActionRowComponent(cmpArr); - this.ActionRowComponentsInternal.Add(comp); + this.ComponentsInternal.Add(comp); } return this; @@ -545,7 +532,7 @@ public Task ModifyAsync(DiscordMessage msg) /// Clears all message components on this builder. /// public void ClearComponents() - => this.ActionRowComponentsInternal.Clear(); + => this.ComponentsInternal.Clear(); /// /// Clears the poll from this builder. @@ -565,10 +552,9 @@ public void Clear() this.FilesInternal.Clear(); this.ReplyId = null; this.MentionOnReply = false; - this.ActionRowComponentsInternal.Clear(); this.ComponentsInternal.Clear(); this.Suppressed = false; - this.Sticker = null; + this.Sticker = null!; this.AttachmentsInternal.Clear(); this.KeepAttachmentsInternal = false; this.Nonce = null; @@ -592,20 +578,19 @@ internal void Validate(bool isModify = false) if (!isModify) { - if (this.Files?.Count == 0 && string.IsNullOrEmpty(this.Content) && (!this.Embeds?.Any() ?? true) && this.Sticker is null && (!this.ActionRowComponents?.Any() ?? true) && (!this.Components?.Any() ?? true) && this.Poll is null && this?.Attachments.Count == 0) + if (this.Files?.Count == 0 && string.IsNullOrEmpty(this.Content) && (!this.Embeds?.Any() ?? true) && this.Sticker is null && (!this.Components?.Any() ?? true) && this.Poll is null && this?.Attachments.Count == 0) throw new ArgumentException("You must specify content, an embed, a sticker, a component, a poll or at least one file."); if (this.IsUIKit && (!string.IsNullOrEmpty(this.Content) || (this.Embeds?.Any() ?? false))) throw new ArgumentException("Using UI Kit mode. You cannot specify content or embeds."); - if (this.IsUIKit && this.Components?.Count > 10) - throw new InvalidOperationException("You can only have 10 components per message."); - - if (!this.IsUIKit && this.ActionRowComponents?.Count > 5) - throw new InvalidOperationException("You can only have 5 action rows per message."); - - if (this.ActionRowComponents?.Any(c => c.Components.Count > 5) ?? false) - throw new InvalidOperationException("Action rows can only have 5 components"); + switch (this.IsUIKit) + { + case true when this.Components?.Count > 10: + throw new InvalidOperationException("You can only have 10 components per message."); + case false when this.Components?.Count > 5: + throw new InvalidOperationException("You can only have 5 action rows per message."); + } if (this.EnforceNonce && string.IsNullOrEmpty(this.Nonce)) throw new InvalidOperationException("Nonce enforcement is enabled, but no nonce is set."); diff --git a/DisCatSharp/Entities/Webhook/DiscordWebhookBuilder.cs b/DisCatSharp/Entities/Webhook/DiscordWebhookBuilder.cs index e08ae139bd..50ae089730 100644 --- a/DisCatSharp/Entities/Webhook/DiscordWebhookBuilder.cs +++ b/DisCatSharp/Entities/Webhook/DiscordWebhookBuilder.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Threading.Tasks; +using DisCatSharp.Entities.Core; using DisCatSharp.Enums; namespace DisCatSharp.Entities; @@ -11,12 +12,10 @@ namespace DisCatSharp.Entities; /// /// Constructs ready-to-send webhook requests. /// -public sealed class DiscordWebhookBuilder +public sealed class DiscordWebhookBuilder : DisCatSharpBuilder { private readonly List _appliedTags = []; - private readonly List _components = []; - private readonly List _embeds = []; private readonly List _files = []; @@ -108,11 +107,6 @@ public string Content /// public List? Mentions { get; private set; } - /// - /// Gets the components. - /// - public IReadOnlyList Components => this._components; - /// /// Attachments to keep on this webhook request. /// @@ -176,11 +170,11 @@ public DiscordWebhookBuilder AddComponents(IEnumerable 5) + if (ara.Length + this.ComponentsInternal.Count > 5) throw new ArgumentException("ActionRow count exceeds maximum of five."); foreach (var ar in ara) - this._components.Add(ar); + this.ComponentsInternal.Add(ar); return this; } @@ -205,7 +199,7 @@ public DiscordWebhookBuilder AddComponents(IEnumerable compone } var comp = new DiscordActionRowComponent(cmpArr); - this._components.Add(comp); + this.ComponentsInternal.Add(comp); return this; } @@ -483,7 +477,7 @@ public DiscordWebhookBuilder WithAppliedTags(IEnumerable tags) /// Clears all message components on this builder. /// public void ClearComponents() - => this._components.Clear(); + => this.ComponentsInternal.Clear(); /// /// Clears the poll from this builder. @@ -502,7 +496,7 @@ public void Clear() this.Mentions = null; this._files.Clear(); this.AttachmentsInternal.Clear(); - this._components.Clear(); + this.ComponentsInternal.Clear(); this.KeepAttachmentsInternal = false; this.ThreadName = null; this.Poll = null; diff --git a/DisCatSharp/Net/Rest/DiscordApiClient.cs b/DisCatSharp/Net/Rest/DiscordApiClient.cs index 420b024864..b4433ff931 100644 --- a/DisCatSharp/Net/Rest/DiscordApiClient.cs +++ b/DisCatSharp/Net/Rest/DiscordApiClient.cs @@ -105,7 +105,7 @@ internal DiscordApiClient(IWebProxy proxy, TimeSpan timeout, bool useRelativeRat /// /// The values. /// Whether this query will be transmitted via POST. - private static string BuildQueryString(IDictionary values, bool post = false) + private static string BuildQueryString(Dictionary values, bool post = false) { if (values == null || values.Count == 0) return string.Empty; @@ -130,7 +130,7 @@ private DiscordMessage PrepareMessage(JToken msgRaw) this.PopulateMessage(author, ret); var referencedMsg = msgRaw["referenced_message"]; - if (ret is { InternalReference: { Type: ReferenceType.Default }, MessageType: MessageType.Reply } && !string.IsNullOrWhiteSpace(referencedMsg?.ToString())) + if (ret is { InternalReference.Type: ReferenceType.Default, MessageType: MessageType.Reply } && !string.IsNullOrWhiteSpace(referencedMsg?.ToString())) { author = referencedMsg["author"].ToObject(); ret.ReferencedMessage.Discord = this.Discord; @@ -1106,7 +1106,7 @@ internal async Task> GetGuildBansAsync(ulong guildId, xb.User = usr; return xb; }); - var bans = new ReadOnlyCollection(new List(bansRaw)); + var bans = new ReadOnlyCollection([.. bansRaw]); return bans; } @@ -1159,7 +1159,7 @@ internal async Task CreateGuildBulkBanAsync(ulong guildI var pld = new RestGuildBulkBanPayload { - UserIds = userIds.ToList(), + UserIds = [.. userIds], DeleteMessageSeconds = deleteMessageSeconds }; @@ -1500,18 +1500,18 @@ internal async Task GetGuildWidgetAsync(ulong guildId) ret.Guild = this.Discord.Guilds.ContainsKey(guildId) ? this.Discord.Guilds[guildId] : null; ret.Channels = ret.Guild == null - ? rawChannels.Select(r => new DiscordChannel + ? [.. rawChannels.Select(r => new DiscordChannel { Id = (ulong)r["id"], Name = r["name"].ToString(), Position = (int)r["position"] - }).ToList() - : rawChannels.Select(r => + })] + : [.. rawChannels.Select(r => { var c = ret.Guild.GetChannel((ulong)r["id"]); c.Position = (int)r["position"]; return c; - }).ToList(); + })]; return ret; } @@ -1588,7 +1588,7 @@ internal async Task> GetGuildTemplatesAsync( var templatesRaw = JsonConvert.DeserializeObject>(res.Response); - return new ReadOnlyCollection(new List(templatesRaw)); + return new ReadOnlyCollection([.. templatesRaw]); } /// @@ -3128,7 +3128,7 @@ internal async Task CreateMessageAsync(ulong channelId, DiscordM IsTts = builder.IsTts, HasEmbed = builder.Embeds != null, Embeds = builder.Embeds, - Components = builder.IsUIKit ? builder.Components : builder.ActionRowComponents, + Components = builder.Components, Nonce = builder.Nonce, EnforceNonce = builder.EnforceNonce, DiscordPollRequest = builder.Poll?.Build(), @@ -3278,7 +3278,7 @@ internal async Task> GetGuildChannelsAsync(ulong g foreach (var ret in channelsRaw) ret.Initialize(this.Discord); - return new ReadOnlyCollection(new List(channelsRaw)); + return new ReadOnlyCollection([.. channelsRaw]); } /// @@ -3436,7 +3436,7 @@ internal async Task> GetChannelMessagesAsync(ulong foreach (var xj in msgsRaw) msgs.Add(this.PrepareMessage(xj)); - return new ReadOnlyCollection(new List(msgs)); + return new ReadOnlyCollection([.. msgs]); } /// @@ -3676,7 +3676,7 @@ internal async Task> GetAnswerVotersAsync(ulong voters.Add(usr); } - return new(new List(voters)); + return new([.. voters]); } /// @@ -3722,7 +3722,7 @@ internal async Task> GetChannelInvitesAsync(ulong c return xi; }); - return new ReadOnlyCollection(new List(invitesRaw)); + return new ReadOnlyCollection([.. invitesRaw]); } /// @@ -3861,7 +3861,7 @@ internal async Task> GetPinnedMessagesAsync(ulong foreach (var xj in msgsRaw) msgs.Add(this.PrepareMessage(xj)); - return new ReadOnlyCollection(new List(msgs)); + return new ReadOnlyCollection([.. msgs]); } /// @@ -4211,7 +4211,7 @@ internal async Task> GetCurrentUserGuildsAsync(int l { var guildsRaw = DiscordJson.DeserializeIEnumerableObject>(res.Response, this.Discord); var glds = guildsRaw.Select(xug => (this.Discord as DiscordClient)?.GuildsInternal[xug.Id]); - return new ReadOnlyCollection(new List(glds)); + return new ReadOnlyCollection([.. glds]); } return DiscordJson.DeserializeIEnumerableObject>(res.Response, this.Discord); @@ -4979,7 +4979,7 @@ internal async Task> GetChannelWebhooksAsync(ulong xw.ApiClient = this; return xw; }); - return webhooksRaw.ToList(); + return [.. webhooksRaw]; } /// @@ -5002,7 +5002,7 @@ internal async Task> GetGuildWebhooksAsync(ulong g xw.ApiClient = this; return xw; }); - return webhooksRaw.ToList(); + return [.. webhooksRaw]; } /// @@ -5663,7 +5663,7 @@ internal async Task> GetReactionsAsync(ulong channelI reacters.Add(usr); } - return new ReadOnlyCollection(new List(reacters)); + return new ReadOnlyCollection([.. reacters]); } /// @@ -5752,7 +5752,7 @@ internal async Task CreateThreadAsync( { Content = builder.Content, Attachments = builder.Attachments, - Components = builder.ActionRowComponents, + Components = builder.Components, HasContent = true, Embeds = builder.Embeds, //Flags = builder.Flags, @@ -6322,7 +6322,7 @@ internal async Task> GetApplicationEmojis var emojisRaw = JsonConvert.DeserializeObject(res.Response); - return this.Discord.UpdateCachedApplicationEmojis(emojisRaw?.Value("items")).Select(x => x.Value).ToList(); + return [.. this.Discord.UpdateCachedApplicationEmojis(emojisRaw?.Value("items")).Select(x => x.Value)]; } /// @@ -6491,7 +6491,7 @@ internal async Task> GetStickerPacksAsync() var json = JObject.Parse(res.Response)["sticker_packs"] as JArray; var ret = json.ToDiscordObject(); - return ret.ToList(); + return [.. ret]; } /// @@ -6648,7 +6648,7 @@ internal async Task> GetGlobalApplicati var res = await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.GET, route).ConfigureAwait(false); var ret = DiscordJson.DeserializeIEnumerableObject>(res.Response, this.Discord); - return ret.ToList(); + return [.. ret]; } /// @@ -6685,7 +6685,7 @@ internal async Task> BulkOverwriteGloba var res = await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.PUT, route, payload: DiscordJson.SerializeObject(pld)).ConfigureAwait(false); var ret = DiscordJson.DeserializeIEnumerableObject>(res.Response, this.Discord); - return ret.ToList(); + return [.. ret]; } /// @@ -6849,7 +6849,7 @@ internal async Task> GetGuildApplicatio var res = await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.GET, route).ConfigureAwait(false); var ret = DiscordJson.DeserializeIEnumerableObject>(res.Response, this.Discord); - return ret.ToList(); + return [.. ret]; } /// @@ -6887,7 +6887,7 @@ internal async Task> BulkOverwriteGuild var res = await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.PUT, route, payload: DiscordJson.SerializeObject(pld)).ConfigureAwait(false); var ret = DiscordJson.DeserializeIEnumerableObject>(res.Response, this.Discord); - return ret.ToList(); + return [.. ret]; } /// @@ -7182,7 +7182,7 @@ internal async Task CreateInteractionRespons /// The builder. internal async Task CreateInteractionModalResponseAsync(ulong interactionId, string interactionToken, InteractionResponseType type, DiscordInteractionModalBuilder builder) { - if (builder.ModalComponents.Select(x => x as DiscordActionRowComponent).Any(mc => mc.Components.Any(c => c.Type != ComponentType.InputText))) + if (builder.ModalComponents.Any(mc => mc.Components.Any(c => c.Type != ComponentType.InputText))) throw new NotSupportedException("Can't send any other type then Input Text as Modal Component."); var pld = new RestInteractionModalResponsePayload @@ -7670,7 +7670,7 @@ internal async Task> GetApplicationAssets asset.Application = application; } - return new ReadOnlyCollection(new List(assets)); + return new ReadOnlyCollection([.. assets]); } /// From 8d252955b238cf3eb719212c4e1cf08698bedf92 Mon Sep 17 00:00:00 2001 From: Lala Sabathil Date: Mon, 16 Dec 2024 00:51:04 +0100 Subject: [PATCH 05/33] moved common builder base to single file --- .../CommandsNextExtension.cs | 2 +- .../EventHandling/Paginator.cs | 2 +- .../InteractivityExtension.cs | 4 +- .../Entities/Core/DisCatSharpBuilder.cs | 81 +++++++++++++++- .../DiscordFollowupMessageBuilder.cs | 86 ++++------------- .../DiscordInteractionModalBuilder.cs | 20 ++-- .../DiscordInteractionResponseBuilder.cs | 94 +++++------------- .../Entities/Message/DiscordMessageBuilder.cs | 87 ++--------------- .../Entities/Webhook/DiscordWebhookBuilder.cs | 96 ++++++------------- 9 files changed, 170 insertions(+), 302 deletions(-) diff --git a/DisCatSharp.CommandsNext/CommandsNextExtension.cs b/DisCatSharp.CommandsNext/CommandsNextExtension.cs index 5955d8e5ec..c8671306a6 100644 --- a/DisCatSharp.CommandsNext/CommandsNextExtension.cs +++ b/DisCatSharp.CommandsNext/CommandsNextExtension.cs @@ -380,7 +380,7 @@ public async Task DefaultHelpAsync(CommandContext ctx, [Description("Command to var helpMessage = helpBuilder.Build(); - var builder = new DiscordMessageBuilder().WithContent(helpMessage.Content).WithEmbed(helpMessage.Embed); + var builder = new DiscordMessageBuilder().WithContent(helpMessage.Content).AddEmbed(helpMessage.Embed); if (!ctx.Config.DmHelp || ctx.Channel is DiscordDmChannel || ctx.Guild == null) await ctx.RespondAsync(builder).ConfigureAwait(false); diff --git a/DisCatSharp.Interactivity/EventHandling/Paginator.cs b/DisCatSharp.Interactivity/EventHandling/Paginator.cs index 5600978159..9907455897 100644 --- a/DisCatSharp.Interactivity/EventHandling/Paginator.cs +++ b/DisCatSharp.Interactivity/EventHandling/Paginator.cs @@ -249,7 +249,7 @@ private async Task PaginateAsync(IPaginationRequest p, DiscordEmoji emoji) var page = await p.GetPageAsync().ConfigureAwait(false); var builder = new DiscordMessageBuilder() .WithContent(page.Content) - .WithEmbed(page.Embed); + .AddEmbed(page.Embed); await builder.ModifyAsync(msg).ConfigureAwait(false); } diff --git a/DisCatSharp.Interactivity/InteractivityExtension.cs b/DisCatSharp.Interactivity/InteractivityExtension.cs index 7c6c68da67..436c15eb7f 100644 --- a/DisCatSharp.Interactivity/InteractivityExtension.cs +++ b/DisCatSharp.Interactivity/InteractivityExtension.cs @@ -746,7 +746,7 @@ public async Task SendPaginatedMessageAsync( var builder = new DiscordMessageBuilder() .WithContent(pages.First().Content) - .WithEmbed(pages.First().Embed) + .AddEmbed(pages.First().Embed) .AddComponents(bts.ButtonArray); var message = await builder.SendAsync(channel).ConfigureAwait(false); @@ -830,7 +830,7 @@ public async Task SendPaginatedMessageAsync( { var builder = new DiscordMessageBuilder() .WithContent(pages.First().Content) - .WithEmbed(pages.First().Embed); + .AddEmbed(pages.First().Embed); var m = await builder.SendAsync(channel).ConfigureAwait(false); var timeout = timeoutOverride ?? this.Config.Timeout; diff --git a/DisCatSharp/Entities/Core/DisCatSharpBuilder.cs b/DisCatSharp/Entities/Core/DisCatSharpBuilder.cs index 2d0e5b56d2..c944e17f49 100644 --- a/DisCatSharp/Entities/Core/DisCatSharpBuilder.cs +++ b/DisCatSharp/Entities/Core/DisCatSharpBuilder.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; namespace DisCatSharp.Entities.Core; @@ -8,12 +9,86 @@ namespace DisCatSharp.Entities.Core; public class DisCatSharpBuilder { /// - /// The components. + /// The attachments of this builder. /// - internal readonly List ComponentsInternal = []; + internal List AttachmentsInternal { get; } = []; /// - /// Components to send. + /// The components of this builder. + /// + internal List ComponentsInternal { get; } = []; + + /// + /// The embeds of this builder. + /// + internal List EmbedsInternal { get; } = []; + + /// + /// The files of this builder. + /// + internal List FilesInternal { get; } = []; + + /// + /// The content of this builder. + /// + internal string? ContentInternal { get; set; } + + /// + /// The components of this builder. /// public IReadOnlyList Components => this.ComponentsInternal; + + /// + /// The content of this builder. + /// + public string? Content + { + get => this.ContentInternal; + set + { + if (value is { Length: > 2000 }) + throw new ArgumentException("Content length cannot exceed 2000 characters.", nameof(value)); + + this.ContentInternal = value; + } + } + + /// + /// The embeds for this builder. + /// + public IReadOnlyList Embeds => this.EmbedsInternal; + + /// + /// The attachments of this builder. + /// + public IReadOnlyList Attachments => this.AttachmentsInternal; + + /// + /// The files of this builder. + /// + public IReadOnlyList Files => this.FilesInternal; + + /// + /// Clears the components on this builder. + /// + public void ClearComponents() + => this.ComponentsInternal.Clear(); + + /// + /// Allows for clearing the builder so that it can be used again. + /// + public virtual void Clear() + { + this.Content = null; + this.FilesInternal.Clear(); + this.EmbedsInternal.Clear(); + this.AttachmentsInternal.Clear(); + this.ComponentsInternal.Clear(); + } + + /// + /// Validates the builder. + /// + internal virtual void Validate() + { } } diff --git a/DisCatSharp/Entities/Interaction/DiscordFollowupMessageBuilder.cs b/DisCatSharp/Entities/Interaction/DiscordFollowupMessageBuilder.cs index 04126d5137..b5693d456f 100644 --- a/DisCatSharp/Entities/Interaction/DiscordFollowupMessageBuilder.cs +++ b/DisCatSharp/Entities/Interaction/DiscordFollowupMessageBuilder.cs @@ -12,14 +12,6 @@ namespace DisCatSharp.Entities; /// public sealed class DiscordFollowupMessageBuilder : DisCatSharpBuilder { - private readonly List _embeds = []; - - private readonly List _files = []; - - internal readonly List AttachmentsInternal = []; - - private string _content; - /// /// Whether flags were changed. /// @@ -91,36 +83,6 @@ public bool NotificationsSuppressed private bool NOTI_SUP { get; set; } - /// - /// Message to send on followup message. - /// - public string Content - { - get => this._content; - set - { - if (value is { Length: > 2000 }) - throw new ArgumentException("Content length cannot exceed 2000 characters.", nameof(value)); - - this._content = value; - } - } - - /// - /// Embeds to send on followup message. - /// - public IReadOnlyList Embeds => this._embeds; - - /// - /// Files to send on this followup message. - /// - public IReadOnlyList Files => this._files; - - /// - /// Attachments to be send with this followup request. - /// - public IReadOnlyList Attachments => this.AttachmentsInternal; - /// /// Mentions to send on this followup message. /// @@ -217,7 +179,7 @@ public DiscordFollowupMessageBuilder WithContent(string content) /// The builder to chain calls with. public DiscordFollowupMessageBuilder AddEmbed(DiscordEmbed embed) { - this._embeds.Add(embed); + this.EmbedsInternal.Add(embed); return this; } @@ -228,7 +190,7 @@ public DiscordFollowupMessageBuilder AddEmbed(DiscordEmbed embed) /// The builder to chain calls with. public DiscordFollowupMessageBuilder AddEmbeds(IEnumerable embeds) { - this._embeds.AddRange(embeds); + this.EmbedsInternal.AddRange(embeds); return this; } @@ -248,13 +210,13 @@ public DiscordFollowupMessageBuilder AddFile(string filename, Stream data, bool if (this.Files.Count >= 10) throw new ArgumentException("Cannot send more than 10 files with a single message."); - if (this._files.Any(x => x.Filename == filename)) + if (this.FilesInternal.Any(x => x.Filename == filename)) throw new ArgumentException("A File with that filename already exists"); if (resetStreamPosition) - this._files.Add(new(filename, data, data.Position, description: description)); + this.FilesInternal.Add(new(filename, data, data.Position, description: description)); else - this._files.Add(new(filename, data, null, description: description)); + this.FilesInternal.Add(new(filename, data, null, description: description)); return this; } @@ -274,13 +236,13 @@ public DiscordFollowupMessageBuilder AddFile(FileStream stream, bool resetStream if (this.Files.Count >= 10) throw new ArgumentException("Cannot send more than 10 files with a single message."); - if (this._files.Any(x => x.Filename == stream.Name)) + if (this.FilesInternal.Any(x => x.Filename == stream.Name)) throw new ArgumentException("A File with that filename already exists"); if (resetStreamPosition) - this._files.Add(new(stream.Name, stream, stream.Position, description: description)); + this.FilesInternal.Add(new(stream.Name, stream, stream.Position, description: description)); else - this._files.Add(new(stream.Name, stream, null, description: description)); + this.FilesInternal.Add(new(stream.Name, stream, null, description: description)); return this; } @@ -301,13 +263,13 @@ public DiscordFollowupMessageBuilder AddFiles(Dictionary files, foreach (var file in files) { - if (this._files.Any(x => x.Filename == file.Key)) + if (this.FilesInternal.Any(x => x.Filename == file.Key)) throw new ArgumentException("A File with that filename already exists"); if (resetStreamPosition) - this._files.Add(new(file.Key, file.Value, file.Value.Position)); + this.FilesInternal.Add(new(file.Key, file.Value, file.Value.Position)); else - this._files.Add(new(file.Key, file.Value, null)); + this.FilesInternal.Add(new(file.Key, file.Value, null)); } return this; @@ -381,40 +343,28 @@ public DiscordFollowupMessageBuilder AsSilentMessage() return this; } - /// - /// Clears all message components on this builder. - /// - public void ClearComponents() - => this.ComponentsInternal.Clear(); - /// /// Clears the poll from this builder. /// public void ClearPoll() => this.Poll = null; - /// - /// Allows for clearing the Followup Message builder so that it can be used again to send a new message. - /// - public void Clear() + /// + public override void Clear() { - this.Content = null; - this._embeds.Clear(); this.IsTts = false; this.Mentions = null; - this._files.Clear(); this.IsEphemeral = false; - this.ComponentsInternal.Clear(); + base.Clear(); } - /// - /// Validates the builder. - /// - internal void Validate() + /// + internal override void Validate() { - if (this.Files?.Count == 0 && string.IsNullOrEmpty(this.Content) && !this.Embeds.Any() && !this.Components.Any() && this.Poll is null && this?.Attachments.Count == 0) + if (this.Files?.Count == 0 && string.IsNullOrEmpty(this.Content) && this.EmbedsInternal.Count == 0 && this.ComponentsInternal.Count == 0 && this.Poll is null && this.AttachmentsInternal.Count == 0) throw new ArgumentException("You must specify content, an embed, a component, a poll, or at least one file."); this.Poll?.Validate(); + base.Validate(); } } diff --git a/DisCatSharp/Entities/Interaction/DiscordInteractionModalBuilder.cs b/DisCatSharp/Entities/Interaction/DiscordInteractionModalBuilder.cs index 0a999cd6b8..42ddc26e4d 100644 --- a/DisCatSharp/Entities/Interaction/DiscordInteractionModalBuilder.cs +++ b/DisCatSharp/Entities/Interaction/DiscordInteractionModalBuilder.cs @@ -9,10 +9,15 @@ namespace DisCatSharp.Entities; /// /// Constructs an interaction modal response. /// -public sealed class DiscordInteractionModalBuilder : DisCatSharpBuilder +public sealed class DiscordInteractionModalBuilder { private readonly List _callbackHints = []; + /// + /// The components. + /// + internal readonly List ComponentsInternal = []; + private string _title; /// @@ -24,6 +29,11 @@ public DiscordInteractionModalBuilder(string title = null, string customId = nul this.CustomId = customId ?? Guid.NewGuid().ToString(); } + /// + /// Components to send. Please use instead. + /// + public IReadOnlyList Components => this.ComponentsInternal; + /// /// Title of modal. /// @@ -147,9 +157,7 @@ public DiscordInteractionModalBuilder AddModalComponents(params DiscordComponent foreach (var ar in ara) this.ComponentsInternal.Add(new DiscordActionRowComponent( - [ - ar - ])); + [ar])); return this; } @@ -181,9 +189,7 @@ public DiscordInteractionModalBuilder AddModalComponents(IEnumerable _callbackHints = []; - private readonly List _choices = []; - - private readonly List _embeds = []; - - private readonly List _files = []; - - internal readonly List AttachmentsInternal = []; - - private string _content; - /// /// Whether flags were changed. /// @@ -42,12 +32,14 @@ public DiscordInteractionResponseBuilder() /// The builder to copy. public DiscordInteractionResponseBuilder(DiscordMessageBuilder builder) { - this._content = builder.Content; + this.Content = builder.Content; this.Mentions = builder.Mentions; - this._embeds.AddRange(builder.Embeds); + this.EmbedsInternal.AddRange(builder.Embeds); this.ComponentsInternal.AddRange(builder.Components); } + internal List ChoicesInternal { get; } = []; + /// /// Whether this interaction response is text-to-speech. /// @@ -114,41 +106,11 @@ internal bool IsVoiceMessage private bool VOICE_MSG { get; set; } - /// - /// Content of the message to send. - /// - public string Content - { - get => this._content; - set - { - if (value is { Length: > 2000 }) - throw new ArgumentException("Content length cannot exceed 2000 characters.", nameof(value)); - - this._content = value; - } - } - - /// - /// Embeds to send on this interaction response. - /// - public IReadOnlyList Embeds => this._embeds; - - /// - /// Files to send on this interaction response. - /// - public IReadOnlyList Files => this._files; - /// /// The choices to send on this interaction response. /// Mutually exclusive with content, embed, and components. /// - public IReadOnlyList Choices => this._choices; - - /// - /// Attachments to be send with this interaction response. - /// - public IReadOnlyList Attachments => this.AttachmentsInternal; + public IReadOnlyList Choices => this.ChoicesInternal; /// /// Mentions to send on this interaction response. @@ -315,7 +277,7 @@ public DiscordInteractionResponseBuilder WithContent(string content) public DiscordInteractionResponseBuilder AddEmbed(DiscordEmbed embed) { if (embed != null) - this._embeds.Add(embed); // Interactions will 400 silently // + this.EmbedsInternal.Add(embed); // Interactions will 400 silently // return this; } @@ -326,7 +288,7 @@ public DiscordInteractionResponseBuilder AddEmbed(DiscordEmbed embed) /// The current builder to chain calls with. public DiscordInteractionResponseBuilder AddEmbeds(IEnumerable embeds) { - this._embeds.AddRange(embeds); + this.EmbedsInternal.AddRange(embeds); return this; } @@ -346,13 +308,13 @@ public DiscordInteractionResponseBuilder AddFile(string filename, Stream data, b if (this.Files.Count >= 10) throw new ArgumentException("Cannot send more than 10 files with a single message."); - if (this._files.Any(x => x.Filename == filename)) + if (this.FilesInternal.Any(x => x.Filename == filename)) throw new ArgumentException("A File with that filename already exists"); if (resetStreamPosition) - this._files.Add(new(filename, data, data.Position, description: description)); + this.FilesInternal.Add(new(filename, data, data.Position, description: description)); else - this._files.Add(new(filename, data, null, description: description)); + this.FilesInternal.Add(new(filename, data, null, description: description)); return this; } @@ -372,13 +334,13 @@ public DiscordInteractionResponseBuilder AddFile(FileStream stream, bool resetSt if (this.Files.Count >= 10) throw new ArgumentException("Cannot send more than 10 files with a single message."); - if (this._files.Any(x => x.Filename == stream.Name)) + if (this.FilesInternal.Any(x => x.Filename == stream.Name)) throw new ArgumentException("A File with that filename already exists"); if (resetStreamPosition) - this._files.Add(new(stream.Name, stream, stream.Position, description: description)); + this.FilesInternal.Add(new(stream.Name, stream, stream.Position, description: description)); else - this._files.Add(new(stream.Name, stream, null, description: description)); + this.FilesInternal.Add(new(stream.Name, stream, null, description: description)); return this; } @@ -399,13 +361,13 @@ public DiscordInteractionResponseBuilder AddFiles(Dictionary fil foreach (var file in files) { - if (this._files.Any(x => x.Filename == file.Key)) + if (this.FilesInternal.Any(x => x.Filename == file.Key)) throw new ArgumentException("A File with that filename already exists"); if (resetStreamPosition) - this._files.Add(new(file.Key, file.Value, file.Value.Position)); + this.FilesInternal.Add(new(file.Key, file.Value, file.Value.Position)); else - this._files.Add(new(file.Key, file.Value, null)); + this.FilesInternal.Add(new(file.Key, file.Value, null)); } return this; @@ -446,7 +408,7 @@ public DiscordInteractionResponseBuilder AddMentions(IEnumerable menti /// The current builder to chain calls with. public DiscordInteractionResponseBuilder AddAutoCompleteChoice(DiscordApplicationCommandAutocompleteChoice choice) { - this._choices.Add(choice); + this.ChoicesInternal.Add(choice); return this; } @@ -457,7 +419,7 @@ public DiscordInteractionResponseBuilder AddAutoCompleteChoice(DiscordApplicatio /// The current builder to chain calls with. public DiscordInteractionResponseBuilder AddAutoCompleteChoices(IEnumerable choices) { - this._choices.AddRange(choices); + this.ChoicesInternal.AddRange(choices); return this; } @@ -469,34 +431,22 @@ public DiscordInteractionResponseBuilder AddAutoCompleteChoices(IEnumerable this.AddAutoCompleteChoices((IEnumerable)choices); - /// - /// Clears all message components on this builder. - /// - public void ClearComponents() - => this.ComponentsInternal.Clear(); - /// /// Clears the poll from this builder. /// public void ClearPoll() => this.Poll = null; - /// - /// Allows for clearing the Interaction Response Builder so that it can be used again to send a new response. - /// - public void Clear() + /// + public override void Clear() { - this.Content = null!; - this._embeds.Clear(); - this.IsTts = false; this.IsEphemeral = false; this.Mentions = null; - this.ComponentsInternal.Clear(); - this._choices.Clear(); - this._files.Clear(); + this.ChoicesInternal.Clear(); this.Poll = null; this.IsVoiceMessage = false; this.NotificationsSuppressed = false; this.EmbedsSuppressed = false; + base.Clear(); } } diff --git a/DisCatSharp/Entities/Message/DiscordMessageBuilder.cs b/DisCatSharp/Entities/Message/DiscordMessageBuilder.cs index df3a0d393a..d81cc14e14 100644 --- a/DisCatSharp/Entities/Message/DiscordMessageBuilder.cs +++ b/DisCatSharp/Entities/Message/DiscordMessageBuilder.cs @@ -13,57 +13,16 @@ namespace DisCatSharp.Entities; /// public sealed class DiscordMessageBuilder : DisCatSharpBuilder { - private readonly List _embeds = []; - - internal readonly List AttachmentsInternal = []; - - internal readonly List FilesInternal = []; - - private string _content; - /// /// Whether to keep previous attachments. /// internal bool? KeepAttachmentsInternal; - /// - /// Gets or Sets the Message to be sent. - /// - public string Content - { - get => this._content; - set - { - if (value is { Length: > 2000 }) - throw new ArgumentException("Content cannot exceed 2000 characters.", nameof(value)); - - this._content = value; - } - } - - /// - /// Gets or sets the embed for the builder. This will always set the builder to have one embed. - /// - public DiscordEmbed Embed - { - get => this._embeds.Count > 0 ? this._embeds[0] : null; - set - { - this._embeds.Clear(); - this._embeds.Add(value); - } - } - /// /// Gets the Sticker to be send. /// public DiscordSticker Sticker { get; set; } - /// - /// Gets the Embeds to be sent. - /// - public IReadOnlyList Embeds => this._embeds; - /// /// Gets or Sets if the message should be TTS. /// @@ -90,16 +49,6 @@ public DiscordEmbed Embed /// public List? Mentions { get; private set; } - /// - /// Gets the Files to be sent in the Message. - /// - public IReadOnlyCollection Files => this.FilesInternal; - - /// - /// Gets the Attachments to be sent in the Message. - /// - public IReadOnlyList Attachments => this.AttachmentsInternal; - /// /// Gets the Reply Message ID. /// @@ -315,20 +264,6 @@ public DiscordMessageBuilder AsSilentMessage(bool silent = true) return this; } - /// - /// Sets the embed for the current builder. - /// - /// The embed that should be set. - /// The current builder to be chained. - public DiscordMessageBuilder WithEmbed(DiscordEmbed embed) - { - if (embed == null) - return this; - - this.Embed = embed; - return this; - } - /// /// Appends an embed to the current builder. /// @@ -339,7 +274,7 @@ public DiscordMessageBuilder AddEmbed(DiscordEmbed embed) if (embed == null) return this; //Providing null embeds will produce a 400 response from Discord.// - this._embeds.Add(embed); + this.EmbedsInternal.Add(embed); return this; } @@ -350,7 +285,7 @@ public DiscordMessageBuilder AddEmbed(DiscordEmbed embed) /// The current builder to be chained. public DiscordMessageBuilder AddEmbeds(IEnumerable embeds) { - this._embeds.AddRange(embeds); + this.EmbedsInternal.AddRange(embeds); return this; } @@ -528,12 +463,6 @@ public Task SendAsync(DiscordChannel channel) public Task ModifyAsync(DiscordMessage msg) => msg.ModifyAsync(this); - /// - /// Clears all message components on this builder. - /// - public void ClearComponents() - => this.ComponentsInternal.Clear(); - /// /// Clears the poll from this builder. /// @@ -543,25 +472,21 @@ public void ClearPoll() /// /// Allows for clearing the Message Builder so that it can be used again to send a new message. /// - public void Clear() + public override void Clear() { - this.Content = ""; - this._embeds.Clear(); this.IsTts = false; this.Mentions = null; - this.FilesInternal.Clear(); this.ReplyId = null; this.MentionOnReply = false; - this.ComponentsInternal.Clear(); this.Suppressed = false; this.Sticker = null!; - this.AttachmentsInternal.Clear(); this.KeepAttachmentsInternal = false; this.Nonce = null; this.EnforceNonce = false; this.Poll = null; this.IsVoiceMessage = false; this.IsUIKit = false; + base.Clear(); } /// @@ -570,7 +495,7 @@ public void Clear() /// Tells the method to perform the Modify Validation or Create Validation. internal void Validate(bool isModify = false) { - if (this._embeds.Count > 10) + if (this.EmbedsInternal.Count > 10) throw new ArgumentException("A message can only have up to 10 embeds."); if (isModify) @@ -599,5 +524,7 @@ internal void Validate(bool isModify = false) } else if (this.Poll is not null) throw new InvalidOperationException("Messages with polls can't be edited."); + + base.Validate(); } } diff --git a/DisCatSharp/Entities/Webhook/DiscordWebhookBuilder.cs b/DisCatSharp/Entities/Webhook/DiscordWebhookBuilder.cs index 50ae089730..33b20a7f2a 100644 --- a/DisCatSharp/Entities/Webhook/DiscordWebhookBuilder.cs +++ b/DisCatSharp/Entities/Webhook/DiscordWebhookBuilder.cs @@ -16,14 +16,6 @@ public sealed class DiscordWebhookBuilder : DisCatSharpBuilder { private readonly List _appliedTags = []; - private readonly List _embeds = []; - - private readonly List _files = []; - - private string _content; - - internal readonly List AttachmentsInternal = []; - /// /// Whether flags were changed. /// @@ -71,47 +63,17 @@ public DiscordWebhookBuilder() /// public bool IsVoiceMessage { get; private set; } - /// - /// Message to send on this webhook request. - /// - public string Content - { - get => this._content; - set - { - if (value is { Length: > 2000 }) - throw new ArgumentException("Content length cannot exceed 2000 characters.", nameof(value)); - - this._content = value; - } - } - /// /// Name of the new thread. /// Only works if the webhook is send in a . /// public string? ThreadName { get; set; } - /// - /// Embeds to send on this webhook request. - /// - public IReadOnlyList Embeds => this._embeds; - - /// - /// Files to send on this webhook request. - /// - public IReadOnlyList Files => this._files; - /// /// Mentions to send on this webhook request. /// public List? Mentions { get; private set; } - /// - /// Attachments to keep on this webhook request. - /// - public IReadOnlyList Attachments => this.AttachmentsInternal; - /// /// Forum post tags to send on this webhook request. /// @@ -273,7 +235,7 @@ public DiscordWebhookBuilder WithThreadName(string name) public DiscordWebhookBuilder AddEmbed(DiscordEmbed embed) { if (embed != null) - this._embeds.Add(embed); + this.EmbedsInternal.Add(embed); return this; } @@ -284,7 +246,7 @@ public DiscordWebhookBuilder AddEmbed(DiscordEmbed embed) /// Embeds to add. public DiscordWebhookBuilder AddEmbeds(IEnumerable embeds) { - this._embeds.AddRange(embeds); + this.EmbedsInternal.AddRange(embeds); return this; } @@ -300,16 +262,16 @@ public DiscordWebhookBuilder AddEmbeds(IEnumerable embeds) /// Description of the file. public DiscordWebhookBuilder AddFile(string filename, Stream data, bool resetStreamPosition = false, string description = null) { - if (this.Files.Count > 10) + if (this.FilesInternal.Count > 10) throw new ArgumentException("Cannot send more than 10 files with a single message."); - if (this._files.Any(x => x.Filename == filename)) + if (this.FilesInternal.Any(x => x.Filename == filename)) throw new ArgumentException("A File with that filename already exists"); if (resetStreamPosition) - this._files.Add(new(filename, data, data.Position, description: description)); + this.FilesInternal.Add(new(filename, data, data.Position, description: description)); else - this._files.Add(new(filename, data, null, description: description)); + this.FilesInternal.Add(new(filename, data, null, description: description)); return this; } @@ -329,13 +291,13 @@ public DiscordWebhookBuilder AddFile(FileStream stream, bool resetStreamPosition if (this.Files.Count > 10) throw new ArgumentException("Cannot send more than 10 files with a single message."); - if (this._files.Any(x => x.Filename == stream.Name)) + if (this.FilesInternal.Any(x => x.Filename == stream.Name)) throw new ArgumentException("A File with that filename already exists"); if (resetStreamPosition) - this._files.Add(new(stream.Name, stream, stream.Position, description: description)); + this.FilesInternal.Add(new(stream.Name, stream, stream.Position, description: description)); else - this._files.Add(new(stream.Name, stream, null, description: description)); + this.FilesInternal.Add(new(stream.Name, stream, null, description: description)); return this; } @@ -355,13 +317,13 @@ public DiscordWebhookBuilder AddFiles(Dictionary files, bool res foreach (var file in files) { - if (this._files.Any(x => x.Filename == file.Key)) + if (this.FilesInternal.Any(x => x.Filename == file.Key)) throw new ArgumentException("A File with that filename already exists"); if (resetStreamPosition) - this._files.Add(new(file.Key, file.Value, file.Value.Position)); + this.FilesInternal.Add(new(file.Key, file.Value, file.Value.Position)); else - this._files.Add(new(file.Key, file.Value, null)); + this.FilesInternal.Add(new(file.Key, file.Value, null)); } return this; @@ -429,7 +391,8 @@ public DiscordWebhookBuilder WithAppliedTags(IEnumerable tags) /// /// The webhook that should be executed. /// The message sent - public async Task SendAsync(DiscordWebhook webhook) => await webhook.ExecuteAsync(this).ConfigureAwait(false); + public async Task SendAsync(DiscordWebhook webhook) + => await webhook.ExecuteAsync(this).ConfigureAwait(false); /// /// Executes a webhook. @@ -437,7 +400,8 @@ public DiscordWebhookBuilder WithAppliedTags(IEnumerable tags) /// The webhook that should be executed. /// Target thread id. /// The message sent - public async Task SendAsync(DiscordWebhook webhook, ulong threadId) => await webhook.ExecuteAsync(this, threadId.ToString()).ConfigureAwait(false); + public async Task SendAsync(DiscordWebhook webhook, ulong threadId) + => await webhook.ExecuteAsync(this, threadId.ToString()).ConfigureAwait(false); /// /// Sends the modified webhook message. @@ -445,7 +409,8 @@ public DiscordWebhookBuilder WithAppliedTags(IEnumerable tags) /// The webhook that should be executed. /// The message to modify. /// The modified message - public async Task ModifyAsync(DiscordWebhook webhook, DiscordMessage message) => await this.ModifyAsync(webhook, message.Id).ConfigureAwait(false); + public async Task ModifyAsync(DiscordWebhook webhook, DiscordMessage message) + => await this.ModifyAsync(webhook, message.Id).ConfigureAwait(false); /// /// Sends the modified webhook message. @@ -453,7 +418,8 @@ public DiscordWebhookBuilder WithAppliedTags(IEnumerable tags) /// The webhook that should be executed. /// The id of the message to modify. /// The modified message - public async Task ModifyAsync(DiscordWebhook webhook, ulong messageId) => await webhook.EditMessageAsync(messageId, this).ConfigureAwait(false); + public async Task ModifyAsync(DiscordWebhook webhook, ulong messageId) + => await webhook.EditMessageAsync(messageId, this).ConfigureAwait(false); /// /// Sends the modified webhook message. @@ -462,7 +428,8 @@ public DiscordWebhookBuilder WithAppliedTags(IEnumerable tags) /// The message to modify. /// Target thread. /// The modified message - public async Task ModifyAsync(DiscordWebhook webhook, DiscordMessage message, DiscordThreadChannel thread) => await this.ModifyAsync(webhook, message.Id, thread.Id).ConfigureAwait(false); + public async Task ModifyAsync(DiscordWebhook webhook, DiscordMessage message, DiscordThreadChannel thread) + => await this.ModifyAsync(webhook, message.Id, thread.Id).ConfigureAwait(false); /// /// Sends the modified webhook message. @@ -471,13 +438,8 @@ public DiscordWebhookBuilder WithAppliedTags(IEnumerable tags) /// The id of the message to modify. /// Target thread id. /// The modified message - public async Task ModifyAsync(DiscordWebhook webhook, ulong messageId, ulong threadId) => await webhook.EditMessageAsync(messageId, this, threadId.ToString()).ConfigureAwait(false); - - /// - /// Clears all message components on this builder. - /// - public void ClearComponents() - => this.ComponentsInternal.Clear(); + public async Task ModifyAsync(DiscordWebhook webhook, ulong messageId, ulong threadId) + => await webhook.EditMessageAsync(messageId, this, threadId.ToString()).ConfigureAwait(false); /// /// Clears the poll from this builder. @@ -488,15 +450,10 @@ public void ClearPoll() /// /// Allows for clearing the Webhook Builder so that it can be used again to send a new message. /// - public void Clear() + public override void Clear() { - this.Content = ""; - this._embeds.Clear(); this.IsTts = false; this.Mentions = null; - this._files.Clear(); - this.AttachmentsInternal.Clear(); - this.ComponentsInternal.Clear(); this.KeepAttachmentsInternal = false; this.ThreadName = null; this.Poll = null; @@ -504,6 +461,7 @@ public void Clear() this.NotificationsSuppressed = false; this.IsTts = false; this.IsVoiceMessage = false; + base.Clear(); } /// @@ -549,5 +507,7 @@ internal void Validate(bool isModify = false, bool isFollowup = false, bool isIn throw new ArgumentException("You must specify content, an embed, a component, a poll, or at least one file."); this.Poll?.Validate(); + + base.Validate(); } } From b3a5b61f447bb3833cca12b39f5f1d54dc89abe0 Mon Sep 17 00:00:00 2001 From: Lala Sabathil Date: Mon, 16 Dec 2024 01:03:01 +0100 Subject: [PATCH 06/33] i forgot some places --- .../Entities/Interaction/DiscordFollowupMessageBuilder.cs | 6 +++--- .../Interaction/DiscordInteractionResponseBuilder.cs | 6 +++--- DisCatSharp/Entities/Message/DiscordMessageBuilder.cs | 6 +++--- DisCatSharp/Entities/Webhook/DiscordWebhookBuilder.cs | 4 ++-- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/DisCatSharp/Entities/Interaction/DiscordFollowupMessageBuilder.cs b/DisCatSharp/Entities/Interaction/DiscordFollowupMessageBuilder.cs index b5693d456f..12d6b0a1b7 100644 --- a/DisCatSharp/Entities/Interaction/DiscordFollowupMessageBuilder.cs +++ b/DisCatSharp/Entities/Interaction/DiscordFollowupMessageBuilder.cs @@ -207,7 +207,7 @@ public DiscordFollowupMessageBuilder AddEmbeds(IEnumerable embeds) /// The builder to chain calls with. public DiscordFollowupMessageBuilder AddFile(string filename, Stream data, bool resetStreamPosition = false, string description = null) { - if (this.Files.Count >= 10) + if (this.FilesInternal.Count >= 10) throw new ArgumentException("Cannot send more than 10 files with a single message."); if (this.FilesInternal.Any(x => x.Filename == filename)) @@ -233,7 +233,7 @@ public DiscordFollowupMessageBuilder AddFile(string filename, Stream data, bool /// The builder to chain calls with. public DiscordFollowupMessageBuilder AddFile(FileStream stream, bool resetStreamPosition = false, string description = null) { - if (this.Files.Count >= 10) + if (this.FilesInternal.Count >= 10) throw new ArgumentException("Cannot send more than 10 files with a single message."); if (this.FilesInternal.Any(x => x.Filename == stream.Name)) @@ -258,7 +258,7 @@ public DiscordFollowupMessageBuilder AddFile(FileStream stream, bool resetStream /// The builder to chain calls with. public DiscordFollowupMessageBuilder AddFiles(Dictionary files, bool resetStreamPosition = false) { - if (this.Files.Count + files.Count > 10) + if (this.FilesInternal.Count + files.Count > 10) throw new ArgumentException("Cannot send more than 10 files with a single message."); foreach (var file in files) diff --git a/DisCatSharp/Entities/Interaction/DiscordInteractionResponseBuilder.cs b/DisCatSharp/Entities/Interaction/DiscordInteractionResponseBuilder.cs index df3d080907..38ee592cf9 100644 --- a/DisCatSharp/Entities/Interaction/DiscordInteractionResponseBuilder.cs +++ b/DisCatSharp/Entities/Interaction/DiscordInteractionResponseBuilder.cs @@ -305,7 +305,7 @@ public DiscordInteractionResponseBuilder AddEmbeds(IEnumerable emb /// The builder to chain calls with. public DiscordInteractionResponseBuilder AddFile(string filename, Stream data, bool resetStreamPosition = false, string description = null) { - if (this.Files.Count >= 10) + if (this.FilesInternal.Count >= 10) throw new ArgumentException("Cannot send more than 10 files with a single message."); if (this.FilesInternal.Any(x => x.Filename == filename)) @@ -331,7 +331,7 @@ public DiscordInteractionResponseBuilder AddFile(string filename, Stream data, b /// The builder to chain calls with. public DiscordInteractionResponseBuilder AddFile(FileStream stream, bool resetStreamPosition = false, string description = null) { - if (this.Files.Count >= 10) + if (this.FilesInternal.Count >= 10) throw new ArgumentException("Cannot send more than 10 files with a single message."); if (this.FilesInternal.Any(x => x.Filename == stream.Name)) @@ -356,7 +356,7 @@ public DiscordInteractionResponseBuilder AddFile(FileStream stream, bool resetSt /// The builder to chain calls with. public DiscordInteractionResponseBuilder AddFiles(Dictionary files, bool resetStreamPosition = false) { - if (this.Files.Count + files.Count > 10) + if (this.FilesInternal.Count + files.Count > 10) throw new ArgumentException("Cannot send more than 10 files with a single message."); foreach (var file in files) diff --git a/DisCatSharp/Entities/Message/DiscordMessageBuilder.cs b/DisCatSharp/Entities/Message/DiscordMessageBuilder.cs index d81cc14e14..c3ab565d87 100644 --- a/DisCatSharp/Entities/Message/DiscordMessageBuilder.cs +++ b/DisCatSharp/Entities/Message/DiscordMessageBuilder.cs @@ -332,7 +332,7 @@ public DiscordMessageBuilder WithAllowedMentions(IEnumerable allowedMe /// The current builder to be chained. public DiscordMessageBuilder WithFile(string fileName, Stream stream, bool resetStreamPosition = false, string description = null) { - if (this.Files.Count > 10) + if (this.FilesInternal.Count > 10) throw new ArgumentException("Cannot send more than 10 files with a single message."); if (this.FilesInternal.Any(x => x.Filename == fileName)) @@ -358,7 +358,7 @@ public DiscordMessageBuilder WithFile(string fileName, Stream stream, bool reset /// The current builder to be chained. public DiscordMessageBuilder WithFile(FileStream stream, bool resetStreamPosition = false, string description = null) { - if (this.Files.Count > 10) + if (this.FilesInternal.Count > 10) throw new ArgumentException("Cannot send more than 10 files with a single message."); if (this.FilesInternal.Any(x => x.Filename == stream.Name)) @@ -383,7 +383,7 @@ public DiscordMessageBuilder WithFile(FileStream stream, bool resetStreamPositio /// The current builder to be chained. public DiscordMessageBuilder WithFiles(Dictionary files, bool resetStreamPosition = false) { - if (this.Files.Count + files.Count > 10) + if (this.FilesInternal.Count + files.Count > 10) throw new ArgumentException("Cannot send more than 10 files with a single message."); foreach (var file in files) diff --git a/DisCatSharp/Entities/Webhook/DiscordWebhookBuilder.cs b/DisCatSharp/Entities/Webhook/DiscordWebhookBuilder.cs index 33b20a7f2a..8baa44960f 100644 --- a/DisCatSharp/Entities/Webhook/DiscordWebhookBuilder.cs +++ b/DisCatSharp/Entities/Webhook/DiscordWebhookBuilder.cs @@ -288,7 +288,7 @@ public DiscordWebhookBuilder AddFile(string filename, Stream data, bool resetStr /// public DiscordWebhookBuilder AddFile(FileStream stream, bool resetStreamPosition = false, string description = null) { - if (this.Files.Count > 10) + if (this.FilesInternal.Count > 10) throw new ArgumentException("Cannot send more than 10 files with a single message."); if (this.FilesInternal.Any(x => x.Filename == stream.Name)) @@ -312,7 +312,7 @@ public DiscordWebhookBuilder AddFile(FileStream stream, bool resetStreamPosition /// public DiscordWebhookBuilder AddFiles(Dictionary files, bool resetStreamPosition = false) { - if (this.Files.Count + files.Count > 10) + if (this.FilesInternal.Count + files.Count > 10) throw new ArgumentException("Cannot send more than 10 files with a single message."); foreach (var file in files) From 58fe7234ba219bb4d63d075a8ce2c8ad30bfb8ea Mon Sep 17 00:00:00 2001 From: Lala Sabathil Date: Mon, 16 Dec 2024 12:01:49 +0100 Subject: [PATCH 07/33] fix: fix mistakes - oppsie~ --- .../Entities/Core/DisCatSharpBuilder.cs | 54 ++++++++++++++-- .../UIKit/DiscordMediaGalleryComponent.cs | 2 +- .../DiscordFollowupMessageBuilder.cs | 53 +++++++-------- .../DiscordInteractionResponseBuilder.cs | 64 +++++++++++-------- .../Entities/Message/DiscordMessageBuilder.cs | 13 ++-- .../Entities/Webhook/DiscordWebhookBuilder.cs | 50 ++++++++++----- DisCatSharp/Net/Rest/DiscordApiClient.cs | 6 ++ 7 files changed, 160 insertions(+), 82 deletions(-) diff --git a/DisCatSharp/Entities/Core/DisCatSharpBuilder.cs b/DisCatSharp/Entities/Core/DisCatSharpBuilder.cs index c944e17f49..dc104a3d2d 100644 --- a/DisCatSharp/Entities/Core/DisCatSharpBuilder.cs +++ b/DisCatSharp/Entities/Core/DisCatSharpBuilder.cs @@ -33,10 +33,16 @@ public class DisCatSharpBuilder /// internal string? ContentInternal { get; set; } + /// + /// Whether flags were changed. + /// + internal bool FlagsChanged { get; set; } = false; + /// /// The components of this builder. /// - public IReadOnlyList Components => this.ComponentsInternal; + public IReadOnlyList Components + => this.ComponentsInternal; /// /// The content of this builder. @@ -56,17 +62,56 @@ public string? Content /// /// The embeds for this builder. /// - public IReadOnlyList Embeds => this.EmbedsInternal; + public IReadOnlyList Embeds + => this.EmbedsInternal; /// /// The attachments of this builder. /// - public IReadOnlyList Attachments => this.AttachmentsInternal; + public IReadOnlyList Attachments + => this.AttachmentsInternal; /// /// The files of this builder. /// - public IReadOnlyList Files => this.FilesInternal; + public IReadOnlyList Files + => this.FilesInternal; + + /// + /// Whether this message should be using UI Kit. + /// + public bool IsUIKit + { + get => this.UI_KIT; + set + { + this.UI_KIT = value; + this.FlagsChanged = true; + } + } + + /// + /// Whether this is using UI Kit. + /// + private bool UI_KIT { get; set; } + + /// + /// Whether to suppress embeds. + /// + public bool EmbedsSuppressed + { + get => this.EMB_SUP; + set + { + this.EMB_SUP = value; + this.FlagsChanged = true; + } + } + + /// + /// Whether embeds are suppressed. + /// + private bool EMB_SUP { get; set; } /// /// Clears the components on this builder. @@ -84,6 +129,7 @@ public virtual void Clear() this.EmbedsInternal.Clear(); this.AttachmentsInternal.Clear(); this.ComponentsInternal.Clear(); + this.FlagsChanged = false; } /// diff --git a/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordMediaGalleryComponent.cs b/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordMediaGalleryComponent.cs index df03272c2f..b4c0ae1f99 100644 --- a/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordMediaGalleryComponent.cs +++ b/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordMediaGalleryComponent.cs @@ -46,6 +46,6 @@ public DiscordMediaGalleryComponent(IEnumerable items) /// /// The content for the media gallery. /// - [JsonProperty("content", NullValueHandling = NullValueHandling.Ignore)] + [JsonProperty("items", NullValueHandling = NullValueHandling.Ignore)] public IReadOnlyList Items { get; internal set; } = []; } diff --git a/DisCatSharp/Entities/Interaction/DiscordFollowupMessageBuilder.cs b/DisCatSharp/Entities/Interaction/DiscordFollowupMessageBuilder.cs index 12d6b0a1b7..0d867f2fa8 100644 --- a/DisCatSharp/Entities/Interaction/DiscordFollowupMessageBuilder.cs +++ b/DisCatSharp/Entities/Interaction/DiscordFollowupMessageBuilder.cs @@ -12,11 +12,6 @@ namespace DisCatSharp.Entities; /// public sealed class DiscordFollowupMessageBuilder : DisCatSharpBuilder { - /// - /// Whether flags were changed. - /// - internal bool FlagsChanged = false; - /// /// Whether this followup message is text-to-speech. /// @@ -37,21 +32,6 @@ public bool IsEphemeral private bool EPH { get; set; } - /// - /// Whether to suppress embeds. - /// - public bool EmbedsSuppressed - { - get => this.EMB_SUP; - set - { - this.EMB_SUP = value; - this.FlagsChanged = true; - } - } - - private bool EMB_SUP { get; set; } - /// /// Whether to send as voice message. /// You can't use that on your own, it needs DisCatSharp.Experimental. @@ -128,14 +108,35 @@ public DiscordFollowupMessageBuilder AddComponents(IEnumerable contained more than 5 components. public DiscordFollowupMessageBuilder AddComponents(IEnumerable components) { - var compArr = components.ToArray(); - var count = compArr.Length; + var cmpArr = components.ToArray(); + var count = cmpArr.Length; - if (count > 5) - throw new ArgumentException("Cannot add more than 5 components per action row!"); + if (this.IsUIKit) + { + switch (count) + { + case 0: + throw new ArgumentOutOfRangeException(nameof(components), "You must provide at least one component"); + case > 10: + throw new ArgumentException("Cannot add more than 10 components!"); + } + + this.ComponentsInternal.AddRange(cmpArr); + } + else + { + switch (count) + { + case 0: + throw new ArgumentOutOfRangeException(nameof(components), "You must provide at least one component"); + case > 5: + throw new ArgumentException("Cannot add more than 5 components per action row!"); + } + + var comp = new DiscordActionRowComponent(cmpArr); + this.ComponentsInternal.Add(comp); + } - var arc = new DiscordActionRowComponent(compArr); - this.ComponentsInternal.Add(arc); return this; } diff --git a/DisCatSharp/Entities/Interaction/DiscordInteractionResponseBuilder.cs b/DisCatSharp/Entities/Interaction/DiscordInteractionResponseBuilder.cs index 38ee592cf9..ed8818541a 100644 --- a/DisCatSharp/Entities/Interaction/DiscordInteractionResponseBuilder.cs +++ b/DisCatSharp/Entities/Interaction/DiscordInteractionResponseBuilder.cs @@ -14,11 +14,6 @@ public sealed class DiscordInteractionResponseBuilder : DisCatSharpBuilder { private readonly List _callbackHints = []; - /// - /// Whether flags were changed. - /// - internal bool FlagsChanged = false; - /// /// Constructs a new empty interaction response builder. /// @@ -60,21 +55,6 @@ public bool IsEphemeral private bool EPH { get; set; } - /// - /// Whether to suppress embeds. - /// - public bool EmbedsSuppressed - { - get => this.EMB_SUP; - set - { - this.EMB_SUP = value; - this.FlagsChanged = true; - } - } - - private bool EMB_SUP { get; set; } - /// /// Whether to send as silent message. /// @@ -182,14 +162,35 @@ public DiscordInteractionResponseBuilder AddComponents(IEnumerableThrown when passing more than 5 components. public DiscordInteractionResponseBuilder AddComponents(IEnumerable components) { - var compArr = components.ToArray(); - var count = compArr.Length; + var cmpArr = components.ToArray(); + var count = cmpArr.Length; - if (count > 5) - throw new ArgumentException("Cannot add more than 5 components per action row!"); + if (this.IsUIKit) + { + switch (count) + { + case 0: + throw new ArgumentOutOfRangeException(nameof(components), "You must provide at least one component"); + case > 10: + throw new ArgumentException("Cannot add more than 10 components!"); + } + + this.ComponentsInternal.AddRange(cmpArr); + } + else + { + switch (count) + { + case 0: + throw new ArgumentOutOfRangeException(nameof(components), "You must provide at least one component"); + case > 5: + throw new ArgumentException("Cannot add more than 5 components per action row!"); + } + + var comp = new DiscordActionRowComponent(cmpArr); + this.ComponentsInternal.Add(comp); + } - var arc = new DiscordActionRowComponent(compArr); - this.ComponentsInternal.Add(arc); return this; } @@ -226,6 +227,17 @@ public DiscordInteractionResponseBuilder AsEphemeral() return this; } + /// + /// Sets that this builder should be using UI Kit. + /// + /// The current builder to chain calls with. + public DiscordInteractionResponseBuilder AsUIKitMessage() + { + this.FlagsChanged = true; + this.IsUIKit = true; + return this; + } + /// /// Sets the interaction response to suppress embeds. /// diff --git a/DisCatSharp/Entities/Message/DiscordMessageBuilder.cs b/DisCatSharp/Entities/Message/DiscordMessageBuilder.cs index c3ab565d87..9d7c37b397 100644 --- a/DisCatSharp/Entities/Message/DiscordMessageBuilder.cs +++ b/DisCatSharp/Entities/Message/DiscordMessageBuilder.cs @@ -39,11 +39,6 @@ public sealed class DiscordMessageBuilder : DisCatSharpBuilder /// public bool IsVoiceMessage { get; private set; } - /// - /// Whether to send with ui kit. - /// - public bool IsUIKit { get; private set; } - /// /// Gets the Allowed Mentions for the message to be sent. /// @@ -238,11 +233,13 @@ public DiscordMessageBuilder SuppressEmbeds(bool suppress = true) } /// - /// Sets the message to be send with ui kit. + /// Sets that this builder should be using UI Kit. /// - public DiscordMessageBuilder AsUiKitMessage(bool asUiKitMessage = true) + /// The current builder to chain calls with. + public DiscordMessageBuilder AsUIKitMessage() { - this.IsUIKit = asUiKitMessage; + this.FlagsChanged = true; + this.IsUIKit = true; return this; } diff --git a/DisCatSharp/Entities/Webhook/DiscordWebhookBuilder.cs b/DisCatSharp/Entities/Webhook/DiscordWebhookBuilder.cs index 8baa44960f..29bd37bca2 100644 --- a/DisCatSharp/Entities/Webhook/DiscordWebhookBuilder.cs +++ b/DisCatSharp/Entities/Webhook/DiscordWebhookBuilder.cs @@ -16,11 +16,6 @@ public sealed class DiscordWebhookBuilder : DisCatSharpBuilder { private readonly List _appliedTags = []; - /// - /// Whether flags were changed. - /// - internal bool FlagsChanged = false; - /// /// Whether to keep previous attachments. /// @@ -47,11 +42,6 @@ public DiscordWebhookBuilder() /// public bool IsTts { get; private set; } - /// - /// Whether to suppress embeds. - /// - public bool EmbedsSuppressed { get; private set; } - /// /// Whether to send as silent message. /// @@ -152,17 +142,43 @@ public DiscordWebhookBuilder AddComponents(IEnumerable compone var cmpArr = components.ToArray(); var count = cmpArr.Length; - switch (count) + if (this.IsUIKit) { - case 0: - throw new ArgumentOutOfRangeException(nameof(components), "You must provide at least one component"); - case > 5: - throw new ArgumentException("Cannot add more than 5 components per action row!"); + switch (count) + { + case 0: + throw new ArgumentOutOfRangeException(nameof(components), "You must provide at least one component"); + case > 10: + throw new ArgumentException("Cannot add more than 10 components!"); + } + + this.ComponentsInternal.AddRange(cmpArr); + } + else + { + switch (count) + { + case 0: + throw new ArgumentOutOfRangeException(nameof(components), "You must provide at least one component"); + case > 5: + throw new ArgumentException("Cannot add more than 5 components per action row!"); + } + + var comp = new DiscordActionRowComponent(cmpArr); + this.ComponentsInternal.Add(comp); } - var comp = new DiscordActionRowComponent(cmpArr); - this.ComponentsInternal.Add(comp); + return this; + } + /// + /// Sets that this builder should be using UI Kit. + /// + /// The current builder to chain calls with. + public DiscordWebhookBuilder AsUIKitMessage() + { + this.FlagsChanged = true; + this.IsUIKit = true; return this; } diff --git a/DisCatSharp/Net/Rest/DiscordApiClient.cs b/DisCatSharp/Net/Rest/DiscordApiClient.cs index b4433ff931..e53466a84c 100644 --- a/DisCatSharp/Net/Rest/DiscordApiClient.cs +++ b/DisCatSharp/Net/Rest/DiscordApiClient.cs @@ -5343,6 +5343,8 @@ internal async Task EditWebhookMessageAsync(ulong webhookId, str flags |= MessageFlags.SuppressedEmbeds; if (builder.NotificationsSuppressed) flags |= MessageFlags.SuppressNotifications; + if (builder.IsUIKit) + flags |= MessageFlags.UIKit; var pld = new RestWebhookMessageEditPayload { @@ -7063,6 +7065,8 @@ internal async Task CreateInteractionRespons flags |= MessageFlags.SuppressedEmbeds; if (builder.NotificationsSuppressed) flags |= MessageFlags.SuppressNotifications; + if (builder.IsUIKit) + flags |= MessageFlags.UIKit; } var data = builder is not null @@ -7297,6 +7301,8 @@ internal async Task CreateFollowupMessageAsync(ulong application flags |= MessageFlags.SuppressedEmbeds; if (builder.NotificationsSuppressed) flags |= MessageFlags.SuppressNotifications; + if (builder.IsUIKit) + flags |= MessageFlags.UIKit; var values = new Dictionary(); var pld = new RestFollowupMessageCreatePayload From 55a63502336e1dcd51857f923216cbe9429fdc5b Mon Sep 17 00:00:00 2001 From: Lala Sabathil Date: Mon, 16 Dec 2024 12:24:25 +0100 Subject: [PATCH 08/33] chore: more cleanup and more fixes --- .../Entities/Core/DisCatSharpBuilder.cs | 53 ++++++++++++++++-- .../DiscordFollowupMessageBuilder.cs | 41 +------------- .../DiscordInteractionResponseBuilder.cs | 54 +++---------------- .../Entities/Message/DiscordMessage.cs | 4 +- .../Entities/Message/DiscordMessageBuilder.cs | 21 +------- .../Entities/Webhook/DiscordWebhookBuilder.cs | 30 ++--------- DisCatSharp/Net/Rest/DiscordApiClient.cs | 2 +- 7 files changed, 66 insertions(+), 139 deletions(-) diff --git a/DisCatSharp/Entities/Core/DisCatSharpBuilder.cs b/DisCatSharp/Entities/Core/DisCatSharpBuilder.cs index dc104a3d2d..bee7fa33e3 100644 --- a/DisCatSharp/Entities/Core/DisCatSharpBuilder.cs +++ b/DisCatSharp/Entities/Core/DisCatSharpBuilder.cs @@ -77,6 +77,48 @@ public IReadOnlyList Attachments public IReadOnlyList Files => this.FilesInternal; + /// + /// Gets the Allowed Mentions for the message to be sent. + /// + public List? Mentions { get; internal set; } + + /// + /// Whether to send as voice message. + /// You can't use that on your own, it needs DisCatSharp.Experimental. + /// + internal bool IsVoiceMessage + { + get => this.VOICE_MSG; + set + { + this.VOICE_MSG = value; + this.FlagsChanged = true; + } + } + + /// + /// Whether to send as voice message. + /// + private bool VOICE_MSG { get; set; } + + /// + /// Whether to send as silent message. + /// + public bool NotificationsSuppressed + { + get => this.NOTIFICATIONS_SUPPRESSED; + set + { + this.NOTIFICATIONS_SUPPRESSED = value; + this.FlagsChanged = true; + } + } + + /// + /// Whether to send as silent message. + /// + private bool NOTIFICATIONS_SUPPRESSED { get; set; } + /// /// Whether this message should be using UI Kit. /// @@ -100,10 +142,10 @@ public bool IsUIKit /// public bool EmbedsSuppressed { - get => this.EMB_SUP; + get => this.EMBEDS_SUPPRESSED; set { - this.EMB_SUP = value; + this.EMBEDS_SUPPRESSED = value; this.FlagsChanged = true; } } @@ -111,7 +153,7 @@ public bool EmbedsSuppressed /// /// Whether embeds are suppressed. /// - private bool EMB_SUP { get; set; } + private bool EMBEDS_SUPPRESSED { get; set; } /// /// Clears the components on this builder. @@ -129,7 +171,12 @@ public virtual void Clear() this.EmbedsInternal.Clear(); this.AttachmentsInternal.Clear(); this.ComponentsInternal.Clear(); + this.IsVoiceMessage = false; + this.IsUIKit = false; + this.EmbedsSuppressed = false; + this.NotificationsSuppressed = false; this.FlagsChanged = false; + this.Mentions = null; } /// diff --git a/DisCatSharp/Entities/Interaction/DiscordFollowupMessageBuilder.cs b/DisCatSharp/Entities/Interaction/DiscordFollowupMessageBuilder.cs index 0d867f2fa8..dbe8d09c4e 100644 --- a/DisCatSharp/Entities/Interaction/DiscordFollowupMessageBuilder.cs +++ b/DisCatSharp/Entities/Interaction/DiscordFollowupMessageBuilder.cs @@ -32,42 +32,6 @@ public bool IsEphemeral private bool EPH { get; set; } - /// - /// Whether to send as voice message. - /// You can't use that on your own, it needs DisCatSharp.Experimental. - /// - internal bool IsVoiceMessage - { - get => this.VOICE_MSG; - set - { - this.VOICE_MSG = value; - this.FlagsChanged = true; - } - } - - private bool VOICE_MSG { get; set; } - - /// - /// Whether to send as silent message. - /// - public bool NotificationsSuppressed - { - get => this.NOTI_SUP; - set - { - this.NOTI_SUP = value; - this.FlagsChanged = true; - } - } - - private bool NOTI_SUP { get; set; } - - /// - /// Mentions to send on this followup message. - /// - public List? Mentions { get; private set; } - /// /// Gets the poll for this message. /// @@ -180,6 +144,7 @@ public DiscordFollowupMessageBuilder WithContent(string content) /// The builder to chain calls with. public DiscordFollowupMessageBuilder AddEmbed(DiscordEmbed embed) { + ArgumentNullException.ThrowIfNull(embed, nameof(embed)); this.EmbedsInternal.Add(embed); return this; } @@ -309,7 +274,6 @@ public DiscordFollowupMessageBuilder AddMentions(IEnumerable mentions) /// public DiscordFollowupMessageBuilder AsEphemeral() { - this.FlagsChanged = true; this.IsEphemeral = true; return this; } @@ -319,7 +283,6 @@ public DiscordFollowupMessageBuilder AsEphemeral() /// public DiscordFollowupMessageBuilder SuppressEmbeds() { - this.FlagsChanged = true; this.EmbedsSuppressed = true; return this; } @@ -329,7 +292,6 @@ public DiscordFollowupMessageBuilder SuppressEmbeds() /// internal DiscordFollowupMessageBuilder AsVoiceMessage(bool asVoiceMessage = true) { - this.FlagsChanged = true; this.IsVoiceMessage = asVoiceMessage; return this; } @@ -339,7 +301,6 @@ internal DiscordFollowupMessageBuilder AsVoiceMessage(bool asVoiceMessage = true /// public DiscordFollowupMessageBuilder AsSilentMessage() { - this.FlagsChanged = true; this.NotificationsSuppressed = true; return this; } diff --git a/DisCatSharp/Entities/Interaction/DiscordInteractionResponseBuilder.cs b/DisCatSharp/Entities/Interaction/DiscordInteractionResponseBuilder.cs index ed8818541a..883466e641 100644 --- a/DisCatSharp/Entities/Interaction/DiscordInteractionResponseBuilder.cs +++ b/DisCatSharp/Entities/Interaction/DiscordInteractionResponseBuilder.cs @@ -25,12 +25,16 @@ public DiscordInteractionResponseBuilder() /// . /// /// The builder to copy. - public DiscordInteractionResponseBuilder(DiscordMessageBuilder builder) + public DiscordInteractionResponseBuilder(DisCatSharpBuilder builder) { this.Content = builder.Content; this.Mentions = builder.Mentions; this.EmbedsInternal.AddRange(builder.Embeds); this.ComponentsInternal.AddRange(builder.Components); + this.EmbedsSuppressed = builder.EmbedsSuppressed; + this.IsUIKit = builder.IsUIKit; + this.FilesInternal.AddRange(builder.Files); + this.AttachmentsInternal.AddRange(builder.Attachments); } internal List ChoicesInternal { get; } = []; @@ -55,48 +59,12 @@ public bool IsEphemeral private bool EPH { get; set; } - /// - /// Whether to send as silent message. - /// - public bool NotificationsSuppressed - { - get => this.NOTI_SUP; - set - { - this.NOTI_SUP = value; - this.FlagsChanged = true; - } - } - - private bool NOTI_SUP { get; set; } - - /// - /// Whether to send as voice message. - /// You can't use that on your own, it needs DisCatSharp.Experimental. - /// - internal bool IsVoiceMessage - { - get => this.VOICE_MSG; - set - { - this.VOICE_MSG = value; - this.FlagsChanged = true; - } - } - - private bool VOICE_MSG { get; set; } - /// /// The choices to send on this interaction response. /// Mutually exclusive with content, embed, and components. /// public IReadOnlyList Choices => this.ChoicesInternal; - /// - /// Mentions to send on this interaction response. - /// - public List? Mentions { get; private set; } - /// /// The hints to send on this interaction response. /// @@ -222,7 +190,6 @@ public DiscordInteractionResponseBuilder WithTts(bool tts) /// The current builder to chain calls with. public DiscordInteractionResponseBuilder AsEphemeral() { - this.FlagsChanged = true; this.IsEphemeral = true; return this; } @@ -233,7 +200,6 @@ public DiscordInteractionResponseBuilder AsEphemeral() /// The current builder to chain calls with. public DiscordInteractionResponseBuilder AsUIKitMessage() { - this.FlagsChanged = true; this.IsUIKit = true; return this; } @@ -244,7 +210,6 @@ public DiscordInteractionResponseBuilder AsUIKitMessage() /// The current builder to chain calls with. public DiscordInteractionResponseBuilder SuppressEmbeds() { - this.FlagsChanged = true; this.EmbedsSuppressed = true; return this; } @@ -255,7 +220,6 @@ public DiscordInteractionResponseBuilder SuppressEmbeds() /// The current builder to chain calls with. public DiscordInteractionResponseBuilder AsSilentMessage() { - this.FlagsChanged = true; this.NotificationsSuppressed = true; return this; } @@ -265,7 +229,6 @@ public DiscordInteractionResponseBuilder AsSilentMessage() /// internal DiscordInteractionResponseBuilder AsVoiceMessage(bool asVoiceMessage = true) { - this.FlagsChanged = true; this.IsVoiceMessage = asVoiceMessage; return this; } @@ -288,8 +251,8 @@ public DiscordInteractionResponseBuilder WithContent(string content) /// The current builder to chain calls with. public DiscordInteractionResponseBuilder AddEmbed(DiscordEmbed embed) { - if (embed != null) - this.EmbedsInternal.Add(embed); // Interactions will 400 silently // + ArgumentNullException.ThrowIfNull(embed, nameof(embed)); + this.EmbedsInternal.Add(embed); return this; } @@ -456,9 +419,6 @@ public override void Clear() this.Mentions = null; this.ChoicesInternal.Clear(); this.Poll = null; - this.IsVoiceMessage = false; - this.NotificationsSuppressed = false; - this.EmbedsSuppressed = false; base.Clear(); } } diff --git a/DisCatSharp/Entities/Message/DiscordMessage.cs b/DisCatSharp/Entities/Message/DiscordMessage.cs index 39260fbe42..e7efaeb88f 100644 --- a/DisCatSharp/Entities/Message/DiscordMessage.cs +++ b/DisCatSharp/Entities/Message/DiscordMessage.cs @@ -699,7 +699,7 @@ public Task ModifyAsync(Optional content, Optional ModifyAsync(DiscordMessageBuilder builder) { builder.Validate(true); - return await this.Discord.ApiClient.EditMessageAsync(this.ChannelId, this.Id, builder.Content, Optional.Some(builder.Embeds.AsEnumerable()), builder.Mentions, builder.Components, builder.Suppressed, builder.Files, builder.Attachments.Count > 0 + return await this.Discord.ApiClient.EditMessageAsync(this.ChannelId, this.Id, builder.Content, Optional.Some(builder.Embeds.AsEnumerable()), builder.Mentions, builder.Components, builder.EmbedsSuppressed, builder.Files, builder.Attachments.Count > 0 ? Optional.Some(builder.Attachments.AsEnumerable()) : builder.KeepAttachmentsInternal.HasValue ? builder.KeepAttachmentsInternal.Value && this.Attachments is not null ? Optional.Some(this.Attachments.AsEnumerable()) : Array.Empty() @@ -737,7 +737,7 @@ public async Task ModifyAsync(Action acti var builder = new DiscordMessageBuilder(); action(builder); builder.Validate(true); - return await this.Discord.ApiClient.EditMessageAsync(this.ChannelId, this.Id, builder.Content, Optional.Some(builder.Embeds.AsEnumerable()), builder.Mentions, builder.Components, builder.Suppressed, builder.Files, builder.Attachments.Count > 0 + return await this.Discord.ApiClient.EditMessageAsync(this.ChannelId, this.Id, builder.Content, Optional.Some(builder.Embeds.AsEnumerable()), builder.Mentions, builder.Components, builder.EmbedsSuppressed, builder.Files, builder.Attachments.Count > 0 ? Optional.Some(builder.Attachments.AsEnumerable()) : builder.KeepAttachmentsInternal.HasValue ? builder.KeepAttachmentsInternal.Value && this.Attachments is not null ? Optional.Some(this.Attachments.AsEnumerable()) : Array.Empty() diff --git a/DisCatSharp/Entities/Message/DiscordMessageBuilder.cs b/DisCatSharp/Entities/Message/DiscordMessageBuilder.cs index 9d7c37b397..745bec5df1 100644 --- a/DisCatSharp/Entities/Message/DiscordMessageBuilder.cs +++ b/DisCatSharp/Entities/Message/DiscordMessageBuilder.cs @@ -39,11 +39,6 @@ public sealed class DiscordMessageBuilder : DisCatSharpBuilder /// public bool IsVoiceMessage { get; private set; } - /// - /// Gets the Allowed Mentions for the message to be sent. - /// - public List? Mentions { get; private set; } - /// /// Gets the Reply Message ID. /// @@ -54,11 +49,6 @@ public sealed class DiscordMessageBuilder : DisCatSharpBuilder /// public bool MentionOnReply { get; private set; } - /// - /// Gets if the embeds should be suppressed. - /// - public bool Suppressed { get; private set; } - /// /// Gets if the Reply will error if the Reply Message Id does not reference a valid message. /// If set to false, invalid replies are send as a regular message. @@ -228,7 +218,7 @@ public DiscordMessageBuilder HasTts(bool isTts) /// public DiscordMessageBuilder SuppressEmbeds(bool suppress = true) { - this.Suppressed = suppress; + this.EmbedsSuppressed = suppress; return this; } @@ -238,7 +228,6 @@ public DiscordMessageBuilder SuppressEmbeds(bool suppress = true) /// The current builder to chain calls with. public DiscordMessageBuilder AsUIKitMessage() { - this.FlagsChanged = true; this.IsUIKit = true; return this; } @@ -268,9 +257,7 @@ public DiscordMessageBuilder AsSilentMessage(bool silent = true) /// The current builder to be chained. public DiscordMessageBuilder AddEmbed(DiscordEmbed embed) { - if (embed == null) - return this; //Providing null embeds will produce a 400 response from Discord.// - + ArgumentNullException.ThrowIfNull(embed, nameof(embed)); this.EmbedsInternal.Add(embed); return this; } @@ -472,17 +459,13 @@ public void ClearPoll() public override void Clear() { this.IsTts = false; - this.Mentions = null; this.ReplyId = null; this.MentionOnReply = false; - this.Suppressed = false; this.Sticker = null!; this.KeepAttachmentsInternal = false; this.Nonce = null; this.EnforceNonce = false; this.Poll = null; - this.IsVoiceMessage = false; - this.IsUIKit = false; base.Clear(); } diff --git a/DisCatSharp/Entities/Webhook/DiscordWebhookBuilder.cs b/DisCatSharp/Entities/Webhook/DiscordWebhookBuilder.cs index 29bd37bca2..5d4fef36d9 100644 --- a/DisCatSharp/Entities/Webhook/DiscordWebhookBuilder.cs +++ b/DisCatSharp/Entities/Webhook/DiscordWebhookBuilder.cs @@ -25,7 +25,7 @@ public sealed class DiscordWebhookBuilder : DisCatSharpBuilder /// Constructs a new empty webhook request builder. /// public DiscordWebhookBuilder() - { } // I still see no point in initializing collections with empty collections. // + { } /// /// Username to use for this webhook request. @@ -42,28 +42,12 @@ public DiscordWebhookBuilder() /// public bool IsTts { get; private set; } - /// - /// Whether to send as silent message. - /// - public bool NotificationsSuppressed { get; private set; } - - /// - /// Whether to send as voice message. - /// You can't use that on your own, it needs DisCatSharp.Experimental. - /// - public bool IsVoiceMessage { get; private set; } - /// /// Name of the new thread. /// Only works if the webhook is send in a . /// public string? ThreadName { get; set; } - /// - /// Mentions to send on this webhook request. - /// - public List? Mentions { get; private set; } - /// /// Forum post tags to send on this webhook request. /// @@ -79,7 +63,6 @@ public DiscordWebhookBuilder() /// public DiscordWebhookBuilder SuppressEmbeds() { - this.FlagsChanged = true; this.EmbedsSuppressed = true; return this; } @@ -89,7 +72,6 @@ public DiscordWebhookBuilder SuppressEmbeds() /// public DiscordWebhookBuilder AsSilentMessage() { - this.FlagsChanged = true; this.NotificationsSuppressed = true; return this; } @@ -99,7 +81,6 @@ public DiscordWebhookBuilder AsSilentMessage() /// public DiscordWebhookBuilder AsVoiceMessage() { - this.FlagsChanged = true; this.IsVoiceMessage = true; return this; } @@ -250,9 +231,8 @@ public DiscordWebhookBuilder WithThreadName(string name) /// Embed to add. public DiscordWebhookBuilder AddEmbed(DiscordEmbed embed) { - if (embed != null) - this.EmbedsInternal.Add(embed); - + ArgumentNullException.ThrowIfNull(embed, nameof(embed)); + this.EmbedsInternal.Add(embed); return this; } @@ -473,10 +453,6 @@ public override void Clear() this.KeepAttachmentsInternal = false; this.ThreadName = null; this.Poll = null; - this.FlagsChanged = false; - this.NotificationsSuppressed = false; - this.IsTts = false; - this.IsVoiceMessage = false; base.Clear(); } diff --git a/DisCatSharp/Net/Rest/DiscordApiClient.cs b/DisCatSharp/Net/Rest/DiscordApiClient.cs index e53466a84c..5ef5aceb7f 100644 --- a/DisCatSharp/Net/Rest/DiscordApiClient.cs +++ b/DisCatSharp/Net/Rest/DiscordApiClient.cs @@ -3109,7 +3109,7 @@ internal async Task CreateMessageAsync(ulong channelId, DiscordM embed.Timestamp = embed.Timestamp.Value.ToUniversalTime(); var flags = MessageFlags.None; - if (builder.Suppressed) + if (builder.EmbedsSuppressed) flags |= MessageFlags.SuppressedEmbeds; if (builder.Silent) flags |= MessageFlags.SuppressNotifications; From d593e9838f377e1fc4b1acfca9caece17a692c8c Mon Sep 17 00:00:00 2001 From: Lala Sabathil Date: Tue, 17 Dec 2024 07:44:41 +0100 Subject: [PATCH 09/33] a --- DisCatSharp.CommandsNext/CommandsNextExtension.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DisCatSharp.CommandsNext/CommandsNextExtension.cs b/DisCatSharp.CommandsNext/CommandsNextExtension.cs index c8671306a6..643b9876e4 100644 --- a/DisCatSharp.CommandsNext/CommandsNextExtension.cs +++ b/DisCatSharp.CommandsNext/CommandsNextExtension.cs @@ -531,7 +531,7 @@ public CommandContext CreateContext(DiscordMessage msg, string prefix, Command c ChannelId = msg.ChannelId }; - if (cmd != null && (cmd.Module is TransientCommandModule || cmd.Module == null)) + if (cmd != null && cmd.Module is TransientCommandModule or null) { var scope = ctx.Services.CreateScope(); ctx.ServiceScopeContext = new(ctx.Services, scope); From a6b9cf00aeaa41051e15cfffd2ae52e4e77aa0b6 Mon Sep 17 00:00:00 2001 From: Lala Sabathil Date: Tue, 17 Dec 2024 07:48:48 +0100 Subject: [PATCH 10/33] Update DiscordMessageBuilder.cs --- DisCatSharp/Entities/Message/DiscordMessageBuilder.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DisCatSharp/Entities/Message/DiscordMessageBuilder.cs b/DisCatSharp/Entities/Message/DiscordMessageBuilder.cs index 745bec5df1..5a883779c7 100644 --- a/DisCatSharp/Entities/Message/DiscordMessageBuilder.cs +++ b/DisCatSharp/Entities/Message/DiscordMessageBuilder.cs @@ -483,10 +483,10 @@ internal void Validate(bool isModify = false) if (!isModify) { - if (this.Files?.Count == 0 && string.IsNullOrEmpty(this.Content) && (!this.Embeds?.Any() ?? true) && this.Sticker is null && (!this.Components?.Any() ?? true) && this.Poll is null && this?.Attachments.Count == 0) + if (this.Files?.Count == 0 && string.IsNullOrEmpty(this.Content) && !this.Embeds.Any() && this.Sticker is null && (!this.Components?.Any() ?? true) && this.Poll is null && this?.Attachments.Count == 0) throw new ArgumentException("You must specify content, an embed, a sticker, a component, a poll or at least one file."); - if (this.IsUIKit && (!string.IsNullOrEmpty(this.Content) || (this.Embeds?.Any() ?? false))) + if (this.IsUIKit && (!string.IsNullOrEmpty(this.Content) || this.Embeds.Any())) throw new ArgumentException("Using UI Kit mode. You cannot specify content or embeds."); switch (this.IsUIKit) From e5b50b2203bd069676e05894227f59d99133c701 Mon Sep 17 00:00:00 2001 From: Lala Sabathil Date: Tue, 17 Dec 2024 08:03:12 +0100 Subject: [PATCH 11/33] moved mentions to builder class and guarded real value in internal list --- .../Entities/Core/DisCatSharpBuilder.cs | 10 ++++- .../DiscordFollowupMessageBuilder.cs | 11 +---- .../DiscordInteractionResponseBuilder.cs | 13 ++---- .../Entities/Message/DiscordMessage.cs | 4 +- .../Entities/Message/DiscordMessageBuilder.cs | 42 ++++++++----------- .../Entities/Webhook/DiscordWebhookBuilder.cs | 11 +---- DisCatSharp/Net/Rest/DiscordApiClient.cs | 12 +++--- 7 files changed, 40 insertions(+), 63 deletions(-) diff --git a/DisCatSharp/Entities/Core/DisCatSharpBuilder.cs b/DisCatSharp/Entities/Core/DisCatSharpBuilder.cs index bee7fa33e3..1f99e806d4 100644 --- a/DisCatSharp/Entities/Core/DisCatSharpBuilder.cs +++ b/DisCatSharp/Entities/Core/DisCatSharpBuilder.cs @@ -80,7 +80,13 @@ public IReadOnlyList Files /// /// Gets the Allowed Mentions for the message to be sent. /// - public List? Mentions { get; internal set; } + public IReadOnlyList Mentions + => this.MentionsInternal; + + /// + /// Gets the Allowed Mentions for the message to be sent. + /// + internal List MentionsInternal { get; set; } = []; /// /// Whether to send as voice message. @@ -176,7 +182,7 @@ public virtual void Clear() this.EmbedsSuppressed = false; this.NotificationsSuppressed = false; this.FlagsChanged = false; - this.Mentions = null; + this.MentionsInternal.Clear(); } /// diff --git a/DisCatSharp/Entities/Interaction/DiscordFollowupMessageBuilder.cs b/DisCatSharp/Entities/Interaction/DiscordFollowupMessageBuilder.cs index dbe8d09c4e..2020dd859c 100644 --- a/DisCatSharp/Entities/Interaction/DiscordFollowupMessageBuilder.cs +++ b/DisCatSharp/Entities/Interaction/DiscordFollowupMessageBuilder.cs @@ -248,10 +248,7 @@ public DiscordFollowupMessageBuilder AddFiles(Dictionary files, /// The builder to chain calls with. public DiscordFollowupMessageBuilder AddMention(IMention mention) { - if (this.Mentions != null) - this.Mentions.Add(mention); - else - this.Mentions = [mention]; + this.MentionsInternal.Add(mention); return this; } @@ -262,10 +259,7 @@ public DiscordFollowupMessageBuilder AddMention(IMention mention) /// The builder to chain calls with. public DiscordFollowupMessageBuilder AddMentions(IEnumerable mentions) { - if (this.Mentions != null) - this.Mentions.AddRange(mentions); - else - this.Mentions = [.. mentions]; + this.MentionsInternal.AddRange(mentions); return this; } @@ -315,7 +309,6 @@ public void ClearPoll() public override void Clear() { this.IsTts = false; - this.Mentions = null; this.IsEphemeral = false; base.Clear(); } diff --git a/DisCatSharp/Entities/Interaction/DiscordInteractionResponseBuilder.cs b/DisCatSharp/Entities/Interaction/DiscordInteractionResponseBuilder.cs index 883466e641..a048e4737b 100644 --- a/DisCatSharp/Entities/Interaction/DiscordInteractionResponseBuilder.cs +++ b/DisCatSharp/Entities/Interaction/DiscordInteractionResponseBuilder.cs @@ -28,7 +28,7 @@ public DiscordInteractionResponseBuilder() public DiscordInteractionResponseBuilder(DisCatSharpBuilder builder) { this.Content = builder.Content; - this.Mentions = builder.Mentions; + this.MentionsInternal = builder.MentionsInternal; this.EmbedsInternal.AddRange(builder.Embeds); this.ComponentsInternal.AddRange(builder.Components); this.EmbedsSuppressed = builder.EmbedsSuppressed; @@ -355,10 +355,7 @@ public DiscordInteractionResponseBuilder AddFiles(Dictionary fil /// The current builder to chain calls with. public DiscordInteractionResponseBuilder AddMention(IMention mention) { - if (this.Mentions != null) - this.Mentions.Add(mention); - else - this.Mentions = [mention]; + this.MentionsInternal.Add(mention); return this; } @@ -369,10 +366,7 @@ public DiscordInteractionResponseBuilder AddMention(IMention mention) /// The current builder to chain calls with. public DiscordInteractionResponseBuilder AddMentions(IEnumerable mentions) { - if (this.Mentions != null) - this.Mentions.AddRange(mentions); - else - this.Mentions = [.. mentions]; + this.MentionsInternal.AddRange(mentions); return this; } @@ -416,7 +410,6 @@ public void ClearPoll() public override void Clear() { this.IsEphemeral = false; - this.Mentions = null; this.ChoicesInternal.Clear(); this.Poll = null; base.Clear(); diff --git a/DisCatSharp/Entities/Message/DiscordMessage.cs b/DisCatSharp/Entities/Message/DiscordMessage.cs index e7efaeb88f..6d83b6cde3 100644 --- a/DisCatSharp/Entities/Message/DiscordMessage.cs +++ b/DisCatSharp/Entities/Message/DiscordMessage.cs @@ -699,7 +699,7 @@ public Task ModifyAsync(Optional content, Optional ModifyAsync(DiscordMessageBuilder builder) { builder.Validate(true); - return await this.Discord.ApiClient.EditMessageAsync(this.ChannelId, this.Id, builder.Content, Optional.Some(builder.Embeds.AsEnumerable()), builder.Mentions, builder.Components, builder.EmbedsSuppressed, builder.Files, builder.Attachments.Count > 0 + return await this.Discord.ApiClient.EditMessageAsync(this.ChannelId, this.Id, builder.Content, Optional.Some(builder.Embeds.AsEnumerable()), Optional.Some(builder.Mentions.AsEnumerable()), builder.Components, builder.EmbedsSuppressed, builder.Files, builder.Attachments.Count > 0 ? Optional.Some(builder.Attachments.AsEnumerable()) : builder.KeepAttachmentsInternal.HasValue ? builder.KeepAttachmentsInternal.Value && this.Attachments is not null ? Optional.Some(this.Attachments.AsEnumerable()) : Array.Empty() @@ -737,7 +737,7 @@ public async Task ModifyAsync(Action acti var builder = new DiscordMessageBuilder(); action(builder); builder.Validate(true); - return await this.Discord.ApiClient.EditMessageAsync(this.ChannelId, this.Id, builder.Content, Optional.Some(builder.Embeds.AsEnumerable()), builder.Mentions, builder.Components, builder.EmbedsSuppressed, builder.Files, builder.Attachments.Count > 0 + return await this.Discord.ApiClient.EditMessageAsync(this.ChannelId, this.Id, builder.Content, Optional.Some(builder.Embeds.AsEnumerable()), Optional.Some(builder.Mentions.AsEnumerable()), builder.Components, builder.EmbedsSuppressed, builder.Files, builder.Attachments.Count > 0 ? Optional.Some(builder.Attachments.AsEnumerable()) : builder.KeepAttachmentsInternal.HasValue ? builder.KeepAttachmentsInternal.Value && this.Attachments is not null ? Optional.Some(this.Attachments.AsEnumerable()) : Array.Empty() diff --git a/DisCatSharp/Entities/Message/DiscordMessageBuilder.cs b/DisCatSharp/Entities/Message/DiscordMessageBuilder.cs index 5a883779c7..c95b810eff 100644 --- a/DisCatSharp/Entities/Message/DiscordMessageBuilder.cs +++ b/DisCatSharp/Entities/Message/DiscordMessageBuilder.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Threading.Tasks; +using DisCatSharp.Attributes; using DisCatSharp.Entities.Core; namespace DisCatSharp.Entities; @@ -33,12 +34,6 @@ public sealed class DiscordMessageBuilder : DisCatSharpBuilder /// public bool Silent { get; private set; } - /// - /// Whether to send as voice message. - /// You can't use that on your own, it needs DisCatSharp.Experimental. - /// - public bool IsVoiceMessage { get; private set; } - /// /// Gets the Reply Message ID. /// @@ -223,7 +218,7 @@ public DiscordMessageBuilder SuppressEmbeds(bool suppress = true) } /// - /// Sets that this builder should be using UI Kit. + /// Sets that this builder should be using UI Kit. /// /// The current builder to chain calls with. public DiscordMessageBuilder AsUIKitMessage() @@ -273,33 +268,33 @@ public DiscordMessageBuilder AddEmbeds(IEnumerable embeds) return this; } + [Deprecated("Replaced by AddMention")] + public DiscordMessageBuilder WithAllowedMention(IMention allowedMention) + => this.AddMention(allowedMention); + /// /// Sets if the message has allowed mentions. /// - /// The allowed Mention that should be sent. + /// The allowed Mention that should be sent. /// The current builder to be chained. - public DiscordMessageBuilder WithAllowedMention(IMention allowedMention) + public DiscordMessageBuilder AddMention(IMention mention) { - if (this.Mentions != null) - this.Mentions.Add(allowedMention); - else - this.Mentions = [allowedMention]; - + this.MentionsInternal.Add(mention); return this; } + [Deprecated("Replaced by AddMentions")] + public DiscordMessageBuilder WithAllowedMentions(IEnumerable allowedMentions) + => this.AddMentions(allowedMentions); + /// /// Sets if the message has allowed mentions. /// - /// The allowed Mentions that should be sent. + /// The allowed Mentions that should be sent. /// The current builder to be chained. - public DiscordMessageBuilder WithAllowedMentions(IEnumerable allowedMentions) + public DiscordMessageBuilder AddMentions(IEnumerable mentions) { - if (this.Mentions != null) - this.Mentions.AddRange(allowedMentions); - else - this.Mentions = [.. allowedMentions]; - + this.MentionsInternal.AddRange(mentions); return this; } @@ -419,10 +414,7 @@ public DiscordMessageBuilder WithReply(ulong messageId, bool mention = false, bo this.FailOnInvalidReply = failOnInvalidReply; if (mention) - { - this.Mentions ??= []; - this.Mentions.Add(new RepliedUserMention()); - } + this.MentionsInternal.Add(new RepliedUserMention()); return this; } diff --git a/DisCatSharp/Entities/Webhook/DiscordWebhookBuilder.cs b/DisCatSharp/Entities/Webhook/DiscordWebhookBuilder.cs index 5d4fef36d9..c64f5e5200 100644 --- a/DisCatSharp/Entities/Webhook/DiscordWebhookBuilder.cs +++ b/DisCatSharp/Entities/Webhook/DiscordWebhookBuilder.cs @@ -352,10 +352,7 @@ public DiscordWebhookBuilder KeepAttachments(bool keep) /// Mention to add. public DiscordWebhookBuilder AddMention(IMention mention) { - if (this.Mentions != null) - this.Mentions.Add(mention); - else - this.Mentions = [mention]; + this.MentionsInternal.Add(mention); return this; } @@ -365,10 +362,7 @@ public DiscordWebhookBuilder AddMention(IMention mention) /// Mentions to add. public DiscordWebhookBuilder AddMentions(IEnumerable mentions) { - if (this.Mentions != null) - this.Mentions.AddRange(mentions); - else - this.Mentions = [.. mentions]; + this.MentionsInternal.AddRange(mentions); return this; } @@ -449,7 +443,6 @@ public void ClearPoll() public override void Clear() { this.IsTts = false; - this.Mentions = null; this.KeepAttachmentsInternal = false; this.ThreadName = null; this.Poll = null; diff --git a/DisCatSharp/Net/Rest/DiscordApiClient.cs b/DisCatSharp/Net/Rest/DiscordApiClient.cs index 5ef5aceb7f..6b8f7d7884 100644 --- a/DisCatSharp/Net/Rest/DiscordApiClient.cs +++ b/DisCatSharp/Net/Rest/DiscordApiClient.cs @@ -3143,7 +3143,7 @@ internal async Task CreateMessageAsync(ulong channelId, DiscordM FailIfNotExists = builder.FailOnInvalidReply }; - pld.Mentions = new(builder.Mentions ?? Mentions.All, builder.Mentions?.Any() ?? false, builder.MentionOnReply); + pld.Mentions = new(builder.Mentions.Count == 0 ? Mentions.All : builder.Mentions, builder.Mentions.Any(), builder.MentionOnReply); if (builder.Files.Count == 0) { @@ -5208,7 +5208,7 @@ internal async Task ExecuteWebhookAsync(ulong webhookId, string DiscordPollRequest = builder.Poll?.Build() }; - if (builder.Mentions != null) + if (builder.Mentions.Any()) pld.Mentions = new(builder.Mentions, builder.Mentions.Count is not 0); if (builder.Files?.Count > 0) @@ -5248,7 +5248,7 @@ internal async Task ExecuteWebhookAsync(ulong webhookId, string } } - if (!string.IsNullOrEmpty(builder.Content) || builder.Embeds?.Count > 0 || builder.Files?.Count > 0 || builder.IsTts || builder.Mentions != null) + if (!string.IsNullOrEmpty(builder.Content) || builder.Embeds?.Count > 0 || builder.Files?.Count > 0 || builder.IsTts || builder.Mentions.Any()) values["payload_json"] = DiscordJson.SerializeObject(pld); var route = $"{Endpoints.WEBHOOKS}/:webhook_id/:webhook_token"; @@ -7148,7 +7148,7 @@ internal async Task CreateInteractionRespons var values = new Dictionary(); if (builder is not null) - if (!string.IsNullOrEmpty(builder.Content) || builder.Embeds?.Count > 0 || builder.IsTts || builder.Mentions is not null || builder.Files?.Count > 0 || builder.Components?.Count > 0) + if (!string.IsNullOrEmpty(builder.Content) || builder.Embeds?.Count > 0 || builder.IsTts || builder.Mentions.Any() || builder.Files?.Count > 0 || builder.Components?.Count > 0) values["payload_json"] = DiscordJson.SerializeObject(pld); var route = $"{Endpoints.INTERACTIONS}/:interaction_id/:interaction_token{Endpoints.CALLBACK}"; @@ -7352,10 +7352,10 @@ internal async Task CreateFollowupMessageAsync(ulong application } } - if (builder.Mentions != null) + if (builder.Mentions.Any()) pld.Mentions = new(builder.Mentions, builder.Mentions.Count is not 0); - if (!string.IsNullOrEmpty(builder.Content) || builder.Embeds?.Count > 0 || builder.IsTts || builder.Mentions != null || builder.Files?.Count > 0 || builder.Components?.Count > 0) + if (!string.IsNullOrEmpty(builder.Content) || builder.Embeds?.Count > 0 || builder.IsTts || builder.Mentions.Any() || builder.Files?.Count > 0 || builder.Components?.Count > 0) values["payload_json"] = DiscordJson.SerializeObject(pld); var route = $"{Endpoints.WEBHOOKS}/:application_id/:interaction_token"; From d913f310bd48188530ee89d3d63a0da5f0ba66d2 Mon Sep 17 00:00:00 2001 From: Lala Sabathil Date: Tue, 17 Dec 2024 08:12:03 +0100 Subject: [PATCH 12/33] fix some more stuff --- .../Entities/Core/DisCatSharpBuilder.cs | 56 ++++++++++--------- .../DiscordInteractionResponseBuilder.cs | 2 +- 2 files changed, 32 insertions(+), 26 deletions(-) diff --git a/DisCatSharp/Entities/Core/DisCatSharpBuilder.cs b/DisCatSharp/Entities/Core/DisCatSharpBuilder.cs index 1f99e806d4..07495d98c7 100644 --- a/DisCatSharp/Entities/Core/DisCatSharpBuilder.cs +++ b/DisCatSharp/Entities/Core/DisCatSharpBuilder.cs @@ -29,29 +29,31 @@ public class DisCatSharpBuilder internal List FilesInternal { get; } = []; /// - /// The content of this builder. + /// The allowed mentions of this builder. /// - internal string? ContentInternal { get; set; } + internal List MentionsInternal { get; } = []; /// - /// Whether flags were changed. + /// The content of this builder. /// - internal bool FlagsChanged { get; set; } = false; + internal string? ContentInternal { get; set; } /// - /// The components of this builder. + /// Whether flags were changed in this builder. /// - public IReadOnlyList Components - => this.ComponentsInternal; + internal bool FlagsChanged { get; set; } = false; /// - /// The content of this builder. + /// Sets the content of this builder. /// public string? Content { get => this.ContentInternal; set { + if (this.IsUIKit || this.IsVoiceMessage) + throw new InvalidOperationException("You cannot set the content for UI Kit / Voice messages"); + if (value is { Length: > 2000 }) throw new ArgumentException("Content length cannot exceed 2000 characters.", nameof(value)); @@ -60,36 +62,37 @@ public string? Content } /// - /// The embeds for this builder. + /// Gets the components of this builder. + /// + public IReadOnlyList Components + => this.ComponentsInternal; + + /// + /// Gets the embeds of this builder. /// public IReadOnlyList Embeds => this.EmbedsInternal; /// - /// The attachments of this builder. + /// Gets the attachments of this builder. /// public IReadOnlyList Attachments => this.AttachmentsInternal; /// - /// The files of this builder. + /// Gets the files of this builder. /// public IReadOnlyList Files => this.FilesInternal; /// - /// Gets the Allowed Mentions for the message to be sent. + /// Gets the allowed mentions of this builder. /// public IReadOnlyList Mentions => this.MentionsInternal; /// - /// Gets the Allowed Mentions for the message to be sent. - /// - internal List MentionsInternal { get; set; } = []; - - /// - /// Whether to send as voice message. + /// Sets whether this builder sends a voice message. /// You can't use that on your own, it needs DisCatSharp.Experimental. /// internal bool IsVoiceMessage @@ -103,12 +106,12 @@ internal bool IsVoiceMessage } /// - /// Whether to send as voice message. + /// Whether this builder sends a voice message. /// private bool VOICE_MSG { get; set; } /// - /// Whether to send as silent message. + /// Sets whether this builder should send a silent message. /// public bool NotificationsSuppressed { @@ -121,12 +124,12 @@ public bool NotificationsSuppressed } /// - /// Whether to send as silent message. + /// Whether this builder sends a silent message. /// private bool NOTIFICATIONS_SUPPRESSED { get; set; } /// - /// Whether this message should be using UI Kit. + /// Sets whether this builder should be using UI Kit. /// public bool IsUIKit { @@ -139,25 +142,28 @@ public bool IsUIKit } /// - /// Whether this is using UI Kit. + /// Whether this builder is using UI Kit. /// private bool UI_KIT { get; set; } /// - /// Whether to suppress embeds. + /// Sets whether this builder suppresses its embeds. /// public bool EmbedsSuppressed { get => this.EMBEDS_SUPPRESSED; set { + if (this.IsUIKit) + throw new InvalidOperationException("You cannot set embeds suppressed for UI Kit messages since they cannot have embeds"); + this.EMBEDS_SUPPRESSED = value; this.FlagsChanged = true; } } /// - /// Whether embeds are suppressed. + /// Whether this builder has its embeds suppressed. /// private bool EMBEDS_SUPPRESSED { get; set; } diff --git a/DisCatSharp/Entities/Interaction/DiscordInteractionResponseBuilder.cs b/DisCatSharp/Entities/Interaction/DiscordInteractionResponseBuilder.cs index a048e4737b..6f0c544cfe 100644 --- a/DisCatSharp/Entities/Interaction/DiscordInteractionResponseBuilder.cs +++ b/DisCatSharp/Entities/Interaction/DiscordInteractionResponseBuilder.cs @@ -28,7 +28,7 @@ public DiscordInteractionResponseBuilder() public DiscordInteractionResponseBuilder(DisCatSharpBuilder builder) { this.Content = builder.Content; - this.MentionsInternal = builder.MentionsInternal; + this.MentionsInternal.AddRange(builder.MentionsInternal); this.EmbedsInternal.AddRange(builder.Embeds); this.ComponentsInternal.AddRange(builder.Components); this.EmbedsSuppressed = builder.EmbedsSuppressed; From 30ac79f7769e545194edddd822cd84a7c68d8280 Mon Sep 17 00:00:00 2001 From: Lala Sabathil Date: Tue, 17 Dec 2024 08:14:36 +0100 Subject: [PATCH 13/33] hide callback hints, not released sadly --- .../Interaction/DiscordCallbackHintBuilder.cs | 12 ++++++------ .../Interaction/DiscordInteractionModalBuilder.cs | 2 +- .../DiscordInteractionResponseBuilder.cs | 14 +++++++++++--- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/DisCatSharp/Entities/Interaction/DiscordCallbackHintBuilder.cs b/DisCatSharp/Entities/Interaction/DiscordCallbackHintBuilder.cs index 462ff8a43e..c299bdb7c1 100644 --- a/DisCatSharp/Entities/Interaction/DiscordCallbackHintBuilder.cs +++ b/DisCatSharp/Entities/Interaction/DiscordCallbackHintBuilder.cs @@ -7,12 +7,12 @@ namespace DisCatSharp.Entities; /// /// Represents a callback hint builder for an interaction. /// -public sealed class DiscordCallbackHintBuilder +internal sealed class DiscordCallbackHintBuilder { /// /// Constructs a new . /// - public DiscordCallbackHintBuilder() + internal DiscordCallbackHintBuilder() { this.Clear(); } @@ -21,7 +21,7 @@ public DiscordCallbackHintBuilder() /// Constructs a new from an existing one. /// /// The existing . - public DiscordCallbackHintBuilder(DiscordCallbackHintBuilder other) + internal DiscordCallbackHintBuilder(DiscordCallbackHintBuilder other) { this.Clear(); this.CallbackHints.AddRange(other.CallbackHints); @@ -30,7 +30,7 @@ public DiscordCallbackHintBuilder(DiscordCallbackHintBuilder other) /// /// Gets the callback hints. /// - public List CallbackHints { get; internal set; } = []; + internal List CallbackHints { get; set; } = []; /// /// Adds a callback hint to the builder. @@ -39,7 +39,7 @@ public DiscordCallbackHintBuilder(DiscordCallbackHintBuilder other) /// The intended use of ephemeral. Required if it's only ephemeral. /// The intended required permissions. /// The updated . - public DiscordCallbackHintBuilder AddCallbackHint(InteractionResponseType intendedCallbackType, InteractionCallbackEphemerality intendedCallbackEphemerality = InteractionCallbackEphemerality.Optional, Permissions? intendedRequiredPermissions = null) + internal DiscordCallbackHintBuilder AddCallbackHint(InteractionResponseType intendedCallbackType, InteractionCallbackEphemerality intendedCallbackEphemerality = InteractionCallbackEphemerality.Optional, Permissions? intendedRequiredPermissions = null) { this.CallbackHints.Add(new() { @@ -53,6 +53,6 @@ public DiscordCallbackHintBuilder AddCallbackHint(InteractionResponseType intend /// /// Clears the callback hints. /// - public void Clear() + internal void Clear() => this.CallbackHints.Clear(); } diff --git a/DisCatSharp/Entities/Interaction/DiscordInteractionModalBuilder.cs b/DisCatSharp/Entities/Interaction/DiscordInteractionModalBuilder.cs index 42ddc26e4d..89d0c832d5 100644 --- a/DisCatSharp/Entities/Interaction/DiscordInteractionModalBuilder.cs +++ b/DisCatSharp/Entities/Interaction/DiscordInteractionModalBuilder.cs @@ -92,7 +92,7 @@ public DiscordInteractionModalBuilder WithCustomId(string customId) /// The hint builder. /// The current builder to chain calls with. /// Thrown when the is . - public DiscordInteractionModalBuilder WithCallbackHints(DiscordCallbackHintBuilder hintBuilder) + internal DiscordInteractionModalBuilder WithCallbackHints(DiscordCallbackHintBuilder hintBuilder) { if (hintBuilder == null) throw new ArgumentNullException(nameof(hintBuilder), "Callback hint builder cannot be null."); diff --git a/DisCatSharp/Entities/Interaction/DiscordInteractionResponseBuilder.cs b/DisCatSharp/Entities/Interaction/DiscordInteractionResponseBuilder.cs index 6f0c544cfe..4a2772c00e 100644 --- a/DisCatSharp/Entities/Interaction/DiscordInteractionResponseBuilder.cs +++ b/DisCatSharp/Entities/Interaction/DiscordInteractionResponseBuilder.cs @@ -12,6 +12,9 @@ namespace DisCatSharp.Entities; /// public sealed class DiscordInteractionResponseBuilder : DisCatSharpBuilder { + /// + /// Gets the callback hints. + /// private readonly List _callbackHints = []; /// @@ -37,6 +40,9 @@ public DiscordInteractionResponseBuilder(DisCatSharpBuilder builder) this.AttachmentsInternal.AddRange(builder.Attachments); } + /// + /// Gets the choices. + /// internal List ChoicesInternal { get; } = []; /// @@ -63,12 +69,14 @@ public bool IsEphemeral /// The choices to send on this interaction response. /// Mutually exclusive with content, embed, and components. /// - public IReadOnlyList Choices => this.ChoicesInternal; + public IReadOnlyList Choices + => this.ChoicesInternal; /// /// The hints to send on this interaction response. /// - public IReadOnlyList CallbackHints => this._callbackHints; + internal IReadOnlyList CallbackHints + => this._callbackHints; /// /// Gets the poll for this message. @@ -81,7 +89,7 @@ public bool IsEphemeral /// The hint builder. /// The current builder to chain calls with. /// Thrown when the is . - public DiscordInteractionResponseBuilder WithCallbackHints(DiscordCallbackHintBuilder hintBuilder) + internal DiscordInteractionResponseBuilder WithCallbackHints(DiscordCallbackHintBuilder hintBuilder) { if (hintBuilder == null) throw new ArgumentNullException(nameof(hintBuilder), "Callback hint builder cannot be null."); From 4e220ec3da8ed16c02697dce6a3add37d5063aa6 Mon Sep 17 00:00:00 2001 From: Lala Sabathil Date: Tue, 17 Dec 2024 08:32:32 +0100 Subject: [PATCH 14/33] Update DiscordMessageBuilder.cs --- DisCatSharp/Entities/Message/DiscordMessageBuilder.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DisCatSharp/Entities/Message/DiscordMessageBuilder.cs b/DisCatSharp/Entities/Message/DiscordMessageBuilder.cs index c95b810eff..b593ab4292 100644 --- a/DisCatSharp/Entities/Message/DiscordMessageBuilder.cs +++ b/DisCatSharp/Entities/Message/DiscordMessageBuilder.cs @@ -22,7 +22,7 @@ public sealed class DiscordMessageBuilder : DisCatSharpBuilder /// /// Gets the Sticker to be send. /// - public DiscordSticker Sticker { get; set; } + public DiscordSticker? Sticker { get; set; } /// /// Gets or Sets if the message should be TTS. From 11712e4554418d596f39b2507aed08a131689c90 Mon Sep 17 00:00:00 2001 From: Lala Sabathil Date: Thu, 19 Dec 2024 21:43:38 +0100 Subject: [PATCH 15/33] feat: add new components --- .../Components/DiscordComponent.cs | 2 +- .../UIKit/DiscordFileDisplayComponent.cs | 11 ++- .../UIKit/DiscordMediaGalleryComponent.cs | 9 +-- .../UIKit/DiscordMediaGalleryItem.cs | 2 +- .../UIKit/DiscordSectionAccessory.cs | 3 + .../UIKit/DiscordSectionComponent.cs | 69 +++++++++++++++++++ .../UIKit/DiscordSeperatorComponent.cs | 5 +- .../UIKit/DiscordTextDisplayComponent.cs | 9 +-- .../UIKit/DiscordThumnailComponent.cs | 51 ++++++++++++++ ...diaItem.cs => DiscordUnfurledMediaItem.cs} | 14 ++-- .../Enums/Interaction/ComponentType.cs | 18 +++-- 11 files changed, 158 insertions(+), 35 deletions(-) create mode 100644 DisCatSharp/Entities/Interaction/Components/UIKit/DiscordSectionAccessory.cs create mode 100644 DisCatSharp/Entities/Interaction/Components/UIKit/DiscordSectionComponent.cs create mode 100644 DisCatSharp/Entities/Interaction/Components/UIKit/DiscordThumnailComponent.cs rename DisCatSharp/Entities/Interaction/Components/UIKit/{DiscordMediaItem.cs => DiscordUnfurledMediaItem.cs} (50%) diff --git a/DisCatSharp/Entities/Interaction/Components/DiscordComponent.cs b/DisCatSharp/Entities/Interaction/Components/DiscordComponent.cs index b52de451d8..7d011b9c5b 100644 --- a/DisCatSharp/Entities/Interaction/Components/DiscordComponent.cs +++ b/DisCatSharp/Entities/Interaction/Components/DiscordComponent.cs @@ -30,7 +30,7 @@ internal DiscordComponent() public string? CustomId { get; internal set; } /// - /// Gets the Id of the compenent. Determined by Discord. + /// Gets the Id of the compenent. Determined by Discord. /// [JsonProperty("id", NullValueHandling = NullValueHandling.Ignore)] public uint Id { get; internal set; } diff --git a/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordFileDisplayComponent.cs b/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordFileDisplayComponent.cs index ec70580611..0ccf45d9b9 100644 --- a/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordFileDisplayComponent.cs +++ b/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordFileDisplayComponent.cs @@ -1,5 +1,3 @@ -using System; - using DisCatSharp.Enums; using Newtonsoft.Json; @@ -7,8 +5,7 @@ namespace DisCatSharp.Entities; /// -/// Represents a file display component that can be submitted. Fires -/// event when submitted. +/// Represents a file display component. /// public sealed class DiscordFileDisplayComponent : DiscordComponent { @@ -23,7 +20,7 @@ internal DiscordFileDisplayComponent() /// /// Constructs a new file display component based on another file display component. /// - /// The button to copy. + /// The file display component to copy. public DiscordFileDisplayComponent(DiscordFileDisplayComponent other) : this() { @@ -37,17 +34,17 @@ public DiscordFileDisplayComponent(DiscordFileDisplayComponent other) /// The file url. /// Whether this file should be marked as spoiler. public DiscordFileDisplayComponent(string url, bool? spoiler) + : this() { this.File = new(url); this.Spoiler = spoiler; - this.Type = ComponentType.File; } /// /// Gets the file. /// [JsonProperty("media")] - public DiscordMediaItem File { get; internal set; } + public DiscordUnfurledMediaItem File { get; internal set; } /// /// Gets whether this file should be marked as spoiler. diff --git a/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordMediaGalleryComponent.cs b/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordMediaGalleryComponent.cs index b4c0ae1f99..8157680e85 100644 --- a/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordMediaGalleryComponent.cs +++ b/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordMediaGalleryComponent.cs @@ -1,4 +1,3 @@ -using System; using System.Collections.Generic; using System.Linq; @@ -9,8 +8,7 @@ namespace DisCatSharp.Entities; /// -/// Represents a media gallery component that can be submitted. Fires -/// event when submitted. +/// Represents a media gallery component. /// public sealed class DiscordMediaGalleryComponent : DiscordComponent { @@ -25,7 +23,7 @@ internal DiscordMediaGalleryComponent() /// /// Constructs a new media gallery component based on another media gallery component. /// - /// The button to copy. + /// The media gallery component to copy. public DiscordMediaGalleryComponent(DiscordMediaGalleryComponent other) : this() { @@ -36,11 +34,10 @@ public DiscordMediaGalleryComponent(DiscordMediaGalleryComponent other) /// Constructs a new media gallery component field with the specified options. /// /// The media gallery items. - /// Is thrown when no label is set. public DiscordMediaGalleryComponent(IEnumerable items) + : this() { this.Items = items.ToList(); - this.Type = ComponentType.MediaGallery; } /// diff --git a/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordMediaGalleryItem.cs b/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordMediaGalleryItem.cs index c673abeabd..64d412f667 100644 --- a/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordMediaGalleryItem.cs +++ b/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordMediaGalleryItem.cs @@ -30,7 +30,7 @@ public DiscordMediaGalleryItem(string url, string? description, bool? spoiler) /// Gets the media item. /// [JsonProperty("media")] - public DiscordMediaItem Media { get; internal set; } + public DiscordUnfurledMediaItem Media { get; internal set; } /// /// Gets the description. diff --git a/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordSectionAccessory.cs b/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordSectionAccessory.cs new file mode 100644 index 0000000000..848177b235 --- /dev/null +++ b/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordSectionAccessory.cs @@ -0,0 +1,3 @@ +namespace DisCatSharp.Entities; + +public class DiscordSectionAccessory : DiscordComponent; diff --git a/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordSectionComponent.cs b/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordSectionComponent.cs new file mode 100644 index 0000000000..00e7e3d287 --- /dev/null +++ b/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordSectionComponent.cs @@ -0,0 +1,69 @@ +using System.Collections.Generic; +using System.Linq; + +using DisCatSharp.Enums; + +using Newtonsoft.Json; + +namespace DisCatSharp.Entities; + +/// +/// Represents a section component. +/// +public sealed class DiscordSectionComponent : DiscordComponent +{ + /// + /// Constructs a new . + /// + internal DiscordSectionComponent() + { + this.Type = ComponentType.Section; + } + + /// + /// Constructs a new section component based on another section component. + /// + /// The section component to copy. + public DiscordSectionComponent(DiscordSectionComponent other) + : this() + { + this.Components = other.Components; + this.Accessory = other.Accessory; + } + + /// + /// Constructs a new section component field with the specified options. + /// + /// The section components. + public DiscordSectionComponent(IEnumerable components) + : this() + { + this.Components = components.ToList(); + } + + /// + /// The content for the section. + /// + [JsonProperty("components", NullValueHandling = NullValueHandling.Ignore)] + public IReadOnlyList Components { get; internal set; } = []; + + /// + /// The accessory for the section. + /// Can be at the moment, but might include buttons later. + /// + [JsonProperty("accessory", NullValueHandling = NullValueHandling.Ignore)] + public DiscordSectionAccessory Accessory { get; internal set; } + + /// + /// Adds a thumbnail component to the section. + /// + /// The thumbnail url. + /// The description of the thumbnail. + /// Whether this thumbnail should be marked as spoiler.The current . + public DiscordSectionComponent WithThumbnailComponent(string url, string? description = null, bool? spoiler = null) + { + this.Accessory = new DiscordThumnailComponent(url, description, spoiler); + return this; + } +} diff --git a/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordSeperatorComponent.cs b/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordSeperatorComponent.cs index 031a378e01..81e2d77aac 100644 --- a/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordSeperatorComponent.cs +++ b/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordSeperatorComponent.cs @@ -7,8 +7,7 @@ namespace DisCatSharp.Entities; /// -/// Represents a seperator component that can be submitted. Fires -/// event when submitted. +/// Represents a seperator component. /// public sealed class DiscordSeperatorComponent : DiscordComponent { @@ -38,10 +37,10 @@ public DiscordSeperatorComponent(DiscordSeperatorComponent other) /// The spacing size. /// Is thrown when no label is set. public DiscordSeperatorComponent(bool? divider = null, SeperatorSpacingSize? spacing = null) + : this() { this.Divider = divider; this.Spacing = spacing; - this.Type = ComponentType.Seperator; } /// diff --git a/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordTextDisplayComponent.cs b/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordTextDisplayComponent.cs index 7e72998b84..9d97dd0992 100644 --- a/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordTextDisplayComponent.cs +++ b/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordTextDisplayComponent.cs @@ -1,5 +1,3 @@ -using System; - using DisCatSharp.Enums; using Newtonsoft.Json; @@ -7,8 +5,7 @@ namespace DisCatSharp.Entities; /// -/// Represents a text display component that can be submitted. Fires -/// event when submitted. +/// Represents a text display component. /// public sealed class DiscordTextDisplayComponent : DiscordComponent { @@ -23,7 +20,7 @@ internal DiscordTextDisplayComponent() /// /// Constructs a new text display component based on another text display component. /// - /// The button to copy. + /// The text display component to copy. public DiscordTextDisplayComponent(DiscordTextDisplayComponent other) : this() { @@ -35,9 +32,9 @@ public DiscordTextDisplayComponent(DiscordTextDisplayComponent other) /// /// The content for the text display. public DiscordTextDisplayComponent(string content) + : this() { this.Content = content; - this.Type = ComponentType.TextDisplay; } /// diff --git a/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordThumnailComponent.cs b/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordThumnailComponent.cs new file mode 100644 index 0000000000..7e53dd42c8 --- /dev/null +++ b/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordThumnailComponent.cs @@ -0,0 +1,51 @@ +using DisCatSharp.Enums; + +using Newtonsoft.Json; + +namespace DisCatSharp.Entities; + +/// +/// Represents a thumbnail component. +/// +public sealed class DiscordThumnailComponent : DiscordSectionAccessory +{ + /// + /// Constructs a new empty . + /// + internal DiscordThumnailComponent() + { + this.Type = ComponentType.Thumbnail; + } + + /// + /// Constructs a new . + /// + /// The thumbnail url. + /// The description of the thumbnail. + /// Whether this thumbnail should be marked as spoiler. + internal DiscordThumnailComponent(string url, string? description = null, bool? spoiler = null) + : this() + { + this.Image = new(url); + this.Description = description; + this.Spoiler = spoiler; + } + + /// + /// Gets the media item. + /// + [JsonProperty("image")] + public DiscordUnfurledMediaItem Image { get; internal set; } + + /// + /// Gets the description. + /// + [JsonProperty("description", NullValueHandling = NullValueHandling.Ignore)] + public string? Description { get; internal set; } + + /// + /// Gets whether this gallery item should be marked as spoiler. + /// + [JsonProperty("spoiler", NullValueHandling = NullValueHandling.Ignore)] + public bool? Spoiler { get; internal set; } +} diff --git a/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordMediaItem.cs b/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordUnfurledMediaItem.cs similarity index 50% rename from DisCatSharp/Entities/Interaction/Components/UIKit/DiscordMediaItem.cs rename to DisCatSharp/Entities/Interaction/Components/UIKit/DiscordUnfurledMediaItem.cs index 00f7f1c588..920ebc7c5a 100644 --- a/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordMediaItem.cs +++ b/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordUnfurledMediaItem.cs @@ -3,27 +3,27 @@ namespace DisCatSharp.Entities; /// -/// Represents a media item. +/// Represents a media item. /// -public sealed class DiscordMediaItem +public sealed class DiscordUnfurledMediaItem { /// - /// Constructs a new empty . + /// Constructs a new empty . /// - internal DiscordMediaItem() + internal DiscordUnfurledMediaItem() { } /// - /// Constructs a new . + /// Constructs a new . /// /// The items url. - internal DiscordMediaItem(string url) + internal DiscordUnfurledMediaItem(string url) { this.Url = url; } /// - /// Gets the url. + /// Gets the url. /// [JsonProperty("url")] public string Url { get; internal set; } diff --git a/DisCatSharp/Enums/Interaction/ComponentType.cs b/DisCatSharp/Enums/Interaction/ComponentType.cs index 669448c75c..a089bd08bc 100644 --- a/DisCatSharp/Enums/Interaction/ComponentType.cs +++ b/DisCatSharp/Enums/Interaction/ComponentType.cs @@ -46,12 +46,22 @@ public enum ComponentType ChannelSelect = 8, /// - /// A text display. + /// A section. + /// + Section = 9, + + /// + /// A text display. /// TextDisplay = 10, /// - /// A media gallery. + /// A thumbnail. + /// + Thumbnail = 16, + + /// + /// A media gallery. /// MediaGallery = 12, @@ -61,12 +71,12 @@ public enum ComponentType File = 13, /// - /// A seperator. + /// A seperator. /// Seperator = 14, /// - /// Cannot be used by bots. + /// Cannot be used by bots. /// ContentInventoryEntry = 15 } From b0c812ba0953f473563d11deea9dff2becdc9fe4 Mon Sep 17 00:00:00 2001 From: Lala Sabathil Date: Thu, 19 Dec 2024 21:44:40 +0100 Subject: [PATCH 16/33] fix: thumbnail is 11, not 16 --- DisCatSharp/Enums/Interaction/ComponentType.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DisCatSharp/Enums/Interaction/ComponentType.cs b/DisCatSharp/Enums/Interaction/ComponentType.cs index a089bd08bc..f41a7f9df3 100644 --- a/DisCatSharp/Enums/Interaction/ComponentType.cs +++ b/DisCatSharp/Enums/Interaction/ComponentType.cs @@ -58,7 +58,7 @@ public enum ComponentType /// /// A thumbnail. /// - Thumbnail = 16, + Thumbnail = 11, /// /// A media gallery. From 3842e53060328c205537490f606ea00537e53476 Mon Sep 17 00:00:00 2001 From: Lala Sabathil Date: Thu, 19 Dec 2024 21:51:01 +0100 Subject: [PATCH 17/33] fix: fix file naming --- .../{DiscordEmojiComponent.cs => DiscordComponentEmoji.cs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename DisCatSharp/Entities/Interaction/Components/{DiscordEmojiComponent.cs => DiscordComponentEmoji.cs} (100%) diff --git a/DisCatSharp/Entities/Interaction/Components/DiscordEmojiComponent.cs b/DisCatSharp/Entities/Interaction/Components/DiscordComponentEmoji.cs similarity index 100% rename from DisCatSharp/Entities/Interaction/Components/DiscordEmojiComponent.cs rename to DisCatSharp/Entities/Interaction/Components/DiscordComponentEmoji.cs From 797aab16cf0ba968813b7c92659947e77b7c776a Mon Sep 17 00:00:00 2001 From: Lala Sabathil Date: Thu, 19 Dec 2024 22:00:43 +0100 Subject: [PATCH 18/33] add more convert --- DisCatSharp/Net/Serialization/DiscordComponentJsonConverter.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/DisCatSharp/Net/Serialization/DiscordComponentJsonConverter.cs b/DisCatSharp/Net/Serialization/DiscordComponentJsonConverter.cs index 5eaca716fb..410a964019 100644 --- a/DisCatSharp/Net/Serialization/DiscordComponentJsonConverter.cs +++ b/DisCatSharp/Net/Serialization/DiscordComponentJsonConverter.cs @@ -54,7 +54,9 @@ public override void WriteJson(JsonWriter writer, object? value, JsonSerializer ComponentType.RoleSelect => new DiscordRoleSelectComponent(), ComponentType.MentionableSelect => new DiscordMentionableSelectComponent(), ComponentType.ChannelSelect => new DiscordChannelSelectComponent(), + ComponentType.Section => new DiscordThumnailComponent(), ComponentType.TextDisplay => new DiscordTextDisplayComponent(), + ComponentType.Thumbnail => new DiscordThumnailComponent(), ComponentType.MediaGallery => new DiscordMediaGalleryComponent(), ComponentType.File => new DiscordFileDisplayComponent(), ComponentType.Seperator => new DiscordSeperatorComponent(), From 0e4daa41b298f16e2d67ea4e08b7708cee72d880 Mon Sep 17 00:00:00 2001 From: Lala Sabathil Date: Thu, 19 Dec 2024 22:10:38 +0100 Subject: [PATCH 19/33] fix: add current limits and fix converter --- .../Components/UIKit/DiscordMediaGalleryComponent.cs | 7 ++++++- .../Components/UIKit/DiscordSectionComponent.cs | 9 +++++++-- .../Net/Serialization/DiscordComponentJsonConverter.cs | 2 +- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordMediaGalleryComponent.cs b/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordMediaGalleryComponent.cs index 8157680e85..04d6d74e16 100644 --- a/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordMediaGalleryComponent.cs +++ b/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordMediaGalleryComponent.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Linq; @@ -37,7 +38,11 @@ public DiscordMediaGalleryComponent(DiscordMediaGalleryComponent other) public DiscordMediaGalleryComponent(IEnumerable items) : this() { - this.Items = items.ToList(); + var it = items.ToList(); + if (it.Count > 10) + throw new ArgumentException("You can only have up to 10 items in a media gallery."); + + this.Items = it.ToList(); } /// diff --git a/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordSectionComponent.cs b/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordSectionComponent.cs index 00e7e3d287..41b3573daa 100644 --- a/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordSectionComponent.cs +++ b/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordSectionComponent.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Linq; @@ -34,11 +35,15 @@ public DiscordSectionComponent(DiscordSectionComponent other) /// /// Constructs a new section component field with the specified options. /// - /// The section components. + /// The section components. Max of 3. public DiscordSectionComponent(IEnumerable components) : this() { - this.Components = components.ToList(); + var comps = components.ToList(); + if (comps.Count > 3) + throw new ArgumentException("You can only have up to 3 components in a section."); + + this.Components = comps.ToList(); } /// diff --git a/DisCatSharp/Net/Serialization/DiscordComponentJsonConverter.cs b/DisCatSharp/Net/Serialization/DiscordComponentJsonConverter.cs index 410a964019..e0e334770e 100644 --- a/DisCatSharp/Net/Serialization/DiscordComponentJsonConverter.cs +++ b/DisCatSharp/Net/Serialization/DiscordComponentJsonConverter.cs @@ -54,7 +54,7 @@ public override void WriteJson(JsonWriter writer, object? value, JsonSerializer ComponentType.RoleSelect => new DiscordRoleSelectComponent(), ComponentType.MentionableSelect => new DiscordMentionableSelectComponent(), ComponentType.ChannelSelect => new DiscordChannelSelectComponent(), - ComponentType.Section => new DiscordThumnailComponent(), + ComponentType.Section => new DiscordSectionComponent(), ComponentType.TextDisplay => new DiscordTextDisplayComponent(), ComponentType.Thumbnail => new DiscordThumnailComponent(), ComponentType.MediaGallery => new DiscordMediaGalleryComponent(), From 79bc83f6effca0637b8571d06ea4af7dce573729 Mon Sep 17 00:00:00 2001 From: Lala Sabathil Date: Tue, 24 Dec 2024 10:57:19 +0100 Subject: [PATCH 20/33] fix!: Use WithAllowedMentions over AddMentions --- .../Interaction/DiscordFollowupMessageBuilder.cs | 4 ++-- .../Interaction/DiscordInteractionResponseBuilder.cs | 4 ++-- .../Entities/Message/DiscordMessageBuilder.cs | 12 ++---------- .../Entities/Webhook/DiscordWebhookBuilder.cs | 4 ++-- 4 files changed, 8 insertions(+), 16 deletions(-) diff --git a/DisCatSharp/Entities/Interaction/DiscordFollowupMessageBuilder.cs b/DisCatSharp/Entities/Interaction/DiscordFollowupMessageBuilder.cs index 2020dd859c..142563b517 100644 --- a/DisCatSharp/Entities/Interaction/DiscordFollowupMessageBuilder.cs +++ b/DisCatSharp/Entities/Interaction/DiscordFollowupMessageBuilder.cs @@ -246,7 +246,7 @@ public DiscordFollowupMessageBuilder AddFiles(Dictionary files, /// /// Mention to add. /// The builder to chain calls with. - public DiscordFollowupMessageBuilder AddMention(IMention mention) + public DiscordFollowupMessageBuilder WithAllowedMention(IMention mention) { this.MentionsInternal.Add(mention); return this; @@ -257,7 +257,7 @@ public DiscordFollowupMessageBuilder AddMention(IMention mention) /// /// Mentions to add. /// The builder to chain calls with. - public DiscordFollowupMessageBuilder AddMentions(IEnumerable mentions) + public DiscordFollowupMessageBuilder WithAllowedMentions(IEnumerable mentions) { this.MentionsInternal.AddRange(mentions); return this; diff --git a/DisCatSharp/Entities/Interaction/DiscordInteractionResponseBuilder.cs b/DisCatSharp/Entities/Interaction/DiscordInteractionResponseBuilder.cs index 4a2772c00e..61053b5972 100644 --- a/DisCatSharp/Entities/Interaction/DiscordInteractionResponseBuilder.cs +++ b/DisCatSharp/Entities/Interaction/DiscordInteractionResponseBuilder.cs @@ -361,7 +361,7 @@ public DiscordInteractionResponseBuilder AddFiles(Dictionary fil /// /// Mention to add. /// The current builder to chain calls with. - public DiscordInteractionResponseBuilder AddMention(IMention mention) + public DiscordInteractionResponseBuilder WithAllowedMention(IMention mention) { this.MentionsInternal.Add(mention); return this; @@ -372,7 +372,7 @@ public DiscordInteractionResponseBuilder AddMention(IMention mention) /// /// Mentions to add. /// The current builder to chain calls with. - public DiscordInteractionResponseBuilder AddMentions(IEnumerable mentions) + public DiscordInteractionResponseBuilder WithAllowedMentions(IEnumerable mentions) { this.MentionsInternal.AddRange(mentions); return this; diff --git a/DisCatSharp/Entities/Message/DiscordMessageBuilder.cs b/DisCatSharp/Entities/Message/DiscordMessageBuilder.cs index b593ab4292..b8e5d25181 100644 --- a/DisCatSharp/Entities/Message/DiscordMessageBuilder.cs +++ b/DisCatSharp/Entities/Message/DiscordMessageBuilder.cs @@ -268,31 +268,23 @@ public DiscordMessageBuilder AddEmbeds(IEnumerable embeds) return this; } - [Deprecated("Replaced by AddMention")] - public DiscordMessageBuilder WithAllowedMention(IMention allowedMention) - => this.AddMention(allowedMention); - /// /// Sets if the message has allowed mentions. /// /// The allowed Mention that should be sent. /// The current builder to be chained. - public DiscordMessageBuilder AddMention(IMention mention) + public DiscordMessageBuilder WithAllowedMention(IMention mention) { this.MentionsInternal.Add(mention); return this; } - [Deprecated("Replaced by AddMentions")] - public DiscordMessageBuilder WithAllowedMentions(IEnumerable allowedMentions) - => this.AddMentions(allowedMentions); - /// /// Sets if the message has allowed mentions. /// /// The allowed Mentions that should be sent. /// The current builder to be chained. - public DiscordMessageBuilder AddMentions(IEnumerable mentions) + public DiscordMessageBuilder WithAllowedMentions(IEnumerable mentions) { this.MentionsInternal.AddRange(mentions); return this; diff --git a/DisCatSharp/Entities/Webhook/DiscordWebhookBuilder.cs b/DisCatSharp/Entities/Webhook/DiscordWebhookBuilder.cs index c64f5e5200..bc1ac50a80 100644 --- a/DisCatSharp/Entities/Webhook/DiscordWebhookBuilder.cs +++ b/DisCatSharp/Entities/Webhook/DiscordWebhookBuilder.cs @@ -350,7 +350,7 @@ public DiscordWebhookBuilder KeepAttachments(bool keep) /// Adds the mention to the mentions to parse, etc. at the execution of the webhook. /// /// Mention to add. - public DiscordWebhookBuilder AddMention(IMention mention) + public DiscordWebhookBuilder WithAllowedMention(IMention mention) { this.MentionsInternal.Add(mention); return this; @@ -360,7 +360,7 @@ public DiscordWebhookBuilder AddMention(IMention mention) /// Adds the mentions to the mentions to parse, etc. at the execution of the webhook. /// /// Mentions to add. - public DiscordWebhookBuilder AddMentions(IEnumerable mentions) + public DiscordWebhookBuilder WithAllowedMentions(IEnumerable mentions) { this.MentionsInternal.AddRange(mentions); return this; From beb09df02f8befab99b0a6291ae9e61fab5f60be Mon Sep 17 00:00:00 2001 From: Lala Sabathil Date: Tue, 24 Dec 2024 16:35:14 +0100 Subject: [PATCH 21/33] fix(docs): fix missing closing tag --- .../Interaction/Components/UIKit/DiscordSectionComponent.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordSectionComponent.cs b/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordSectionComponent.cs index 41b3573daa..85c719e958 100644 --- a/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordSectionComponent.cs +++ b/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordSectionComponent.cs @@ -64,7 +64,7 @@ public DiscordSectionComponent(IEnumerable componen /// /// The thumbnail url. /// The description of the thumbnail. - /// Whether this thumbnail should be marked as spoiler.Whether this thumbnail should be marked as spoiler. /// The current . public DiscordSectionComponent WithThumbnailComponent(string url, string? description = null, bool? spoiler = null) { From 315ef194b21a7074ea318c08fd6e094d7421130b Mon Sep 17 00:00:00 2001 From: Lala Sabathil Date: Thu, 9 Jan 2025 02:01:06 +0100 Subject: [PATCH 22/33] feat: add container component --- .../UIKit/DiscordContainerComponent.cs | 71 +++++++++++++++++++ .../UIKit/DiscordSectionComponent.cs | 2 +- .../UIKit/DiscordThumnailComponent.cs | 6 +- .../Entities/Message/DiscordMessage.cs | 8 +-- .../Enums/Interaction/ComponentType.cs | 7 +- DisCatSharp/Enums/Message/MessageFlags.cs | 2 +- DisCatSharp/Net/Rest/DiscordApiClient.cs | 8 +-- 7 files changed, 90 insertions(+), 14 deletions(-) create mode 100644 DisCatSharp/Entities/Interaction/Components/UIKit/DiscordContainerComponent.cs diff --git a/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordContainerComponent.cs b/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordContainerComponent.cs new file mode 100644 index 0000000000..de9a696a9a --- /dev/null +++ b/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordContainerComponent.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +using DisCatSharp.Enums; + +using Newtonsoft.Json; + +namespace DisCatSharp.Entities; + +/// +/// Represents a container component. +/// +public sealed class DiscordContainerComponent : DiscordComponent +{ + /// + /// Constructs a new . + /// + internal DiscordContainerComponent() + { + this.Type = ComponentType.Container; + } + + /// + /// Constructs a new container component based on another container component. + /// + /// The container component to copy. + public DiscordContainerComponent(DiscordContainerComponent other) + : this() + { + this.Components = other.Components; + this.AccentColor = other.AccentColor; + this.Spoiler = other.Spoiler; + } + + /// + /// Constructs a new container component field with the specified options. + /// + /// The container components. Max of 3. + public DiscordContainerComponent(IEnumerable components) + : this() + { + var comps = components.ToList(); + if (comps.Count > 3) + throw new ArgumentException("You can only have up to 3 components in a container."); + + List allowedTypes = [ComponentType.ActionRow, ComponentType.TextDisplay, ComponentType.Section, ComponentType.MediaGallery, ComponentType.Seperator, ComponentType.File]; + if (comps.Any(c => !allowedTypes.Contains(c.Type))) + throw new ArgumentException("All components must be of type ActionRow, TextDisplay, Section, MediaGallery, Seperator, or File."); + + this.Components = comps.ToList(); + } + + /// + /// The components for the container. + /// + [JsonProperty("components", NullValueHandling = NullValueHandling.Ignore)] + public IReadOnlyList Components { get; internal set; } = []; + + /// + /// The accent color for the container. + /// + [JsonProperty("accent_color", NullValueHandling = NullValueHandling.Ignore)] + public DiscordColor? AccentColor { get; internal set; } + + /// + /// Gets whether this container should be marked as spoiler. + /// + [JsonProperty("spoiler", NullValueHandling = NullValueHandling.Ignore)] + public bool? Spoiler { get; internal set; } +} diff --git a/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordSectionComponent.cs b/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordSectionComponent.cs index 85c719e958..6947e52c81 100644 --- a/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordSectionComponent.cs +++ b/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordSectionComponent.cs @@ -47,7 +47,7 @@ public DiscordSectionComponent(IEnumerable componen } /// - /// The content for the section. + /// The components for the section. /// [JsonProperty("components", NullValueHandling = NullValueHandling.Ignore)] public IReadOnlyList Components { get; internal set; } = []; diff --git a/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordThumnailComponent.cs b/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordThumnailComponent.cs index 7e53dd42c8..11b4aa1408 100644 --- a/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordThumnailComponent.cs +++ b/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordThumnailComponent.cs @@ -26,7 +26,7 @@ internal DiscordThumnailComponent() internal DiscordThumnailComponent(string url, string? description = null, bool? spoiler = null) : this() { - this.Image = new(url); + this.Media = new(url); this.Description = description; this.Spoiler = spoiler; } @@ -34,8 +34,8 @@ internal DiscordThumnailComponent(string url, string? description = null, bool? /// /// Gets the media item. /// - [JsonProperty("image")] - public DiscordUnfurledMediaItem Image { get; internal set; } + [JsonProperty("media")] + public DiscordUnfurledMediaItem Media { get; internal set; } /// /// Gets the description. diff --git a/DisCatSharp/Entities/Message/DiscordMessage.cs b/DisCatSharp/Entities/Message/DiscordMessage.cs index 6d83b6cde3..7110a3e395 100644 --- a/DisCatSharp/Entities/Message/DiscordMessage.cs +++ b/DisCatSharp/Entities/Message/DiscordMessage.cs @@ -651,7 +651,7 @@ internal void PopulateMentions() /// Thrown when an invalid parameter was provided. /// Thrown when Discord is unable to process the request. public Task ModifyAsync(Optional content) - => this.Flags?.HasMessageFlag(MessageFlags.UIKit) ?? false ? throw new InvalidOperationException("UI Kit messages can not have content.") : this.Discord.ApiClient.EditMessageAsync(this.ChannelId, this.Id, content, default, this.GetMentions(), default, default, [], default); + => this.Flags?.HasMessageFlag(MessageFlags.IsComponentsV2) ?? false ? throw new InvalidOperationException("UI Kit messages can not have content.") : this.Discord.ApiClient.EditMessageAsync(this.ChannelId, this.Id, content, default, this.GetMentions(), default, default, [], default); /// /// Edits the message. @@ -662,7 +662,7 @@ public Task ModifyAsync(Optional content) /// Thrown when an invalid parameter was provided. /// Thrown when Discord is unable to process the request. public Task ModifyAsync(Optional embed = default) - => this.Flags?.HasMessageFlag(MessageFlags.UIKit) ?? false ? throw new InvalidOperationException("UI Kit messages can not have embeds.") : this.Discord.ApiClient.EditMessageAsync(this.ChannelId, this.Id, default, embed.Map(v => new[] { v }).ValueOr([]), this.GetMentions(), default, default, [], default); + => this.Flags?.HasMessageFlag(MessageFlags.IsComponentsV2) ?? false ? throw new InvalidOperationException("UI Kit messages can not have embeds.") : this.Discord.ApiClient.EditMessageAsync(this.ChannelId, this.Id, default, embed.Map(v => new[] { v }).ValueOr([]), this.GetMentions(), default, default, [], default); /// /// Edits the message. @@ -674,7 +674,7 @@ public Task ModifyAsync(Optional embed = default) /// Thrown when an invalid parameter was provided. /// Thrown when Discord is unable to process the request. public Task ModifyAsync(Optional content, Optional embed = default) - => this.Flags?.HasMessageFlag(MessageFlags.UIKit) ?? false ? throw new InvalidOperationException("UI Kit messages can not have content or embeds.") : this.Discord.ApiClient.EditMessageAsync(this.ChannelId, this.Id, content, embed.Map(v => new[] { v }).ValueOr([]), this.GetMentions(), default, default, [], default); + => this.Flags?.HasMessageFlag(MessageFlags.IsComponentsV2) ?? false ? throw new InvalidOperationException("UI Kit messages can not have content or embeds.") : this.Discord.ApiClient.EditMessageAsync(this.ChannelId, this.Id, content, embed.Map(v => new[] { v }).ValueOr([]), this.GetMentions(), default, default, [], default); /// /// Edits the message. @@ -686,7 +686,7 @@ public Task ModifyAsync(Optional content, OptionalThrown when an invalid parameter was provided. /// Thrown when Discord is unable to process the request. public Task ModifyAsync(Optional content, Optional> embeds = default) - => this.Flags?.HasMessageFlag(MessageFlags.UIKit) ?? false ? throw new InvalidOperationException("UI Kit messages can not have content or embeds.") : this.Discord.ApiClient.EditMessageAsync(this.ChannelId, this.Id, content, embeds, this.GetMentions(), default, default, [], default); + => this.Flags?.HasMessageFlag(MessageFlags.IsComponentsV2) ?? false ? throw new InvalidOperationException("UI Kit messages can not have content or embeds.") : this.Discord.ApiClient.EditMessageAsync(this.ChannelId, this.Id, content, embeds, this.GetMentions(), default, default, [], default); /// /// Edits the message. diff --git a/DisCatSharp/Enums/Interaction/ComponentType.cs b/DisCatSharp/Enums/Interaction/ComponentType.cs index f41a7f9df3..0a1a520285 100644 --- a/DisCatSharp/Enums/Interaction/ComponentType.cs +++ b/DisCatSharp/Enums/Interaction/ComponentType.cs @@ -78,5 +78,10 @@ public enum ComponentType /// /// Cannot be used by bots. /// - ContentInventoryEntry = 15 + ContentInventoryEntry = 15, + + /// + /// A container. + /// + Container = 17 } diff --git a/DisCatSharp/Enums/Message/MessageFlags.cs b/DisCatSharp/Enums/Message/MessageFlags.cs index a100f85176..4bc53b490c 100644 --- a/DisCatSharp/Enums/Message/MessageFlags.cs +++ b/DisCatSharp/Enums/Message/MessageFlags.cs @@ -91,5 +91,5 @@ public enum MessageFlags /// /// The message uses the UI Kit. /// - UIKit = 1 << 15 + IsComponentsV2 = 1 << 15 } diff --git a/DisCatSharp/Net/Rest/DiscordApiClient.cs b/DisCatSharp/Net/Rest/DiscordApiClient.cs index 6b8f7d7884..56fac8c146 100644 --- a/DisCatSharp/Net/Rest/DiscordApiClient.cs +++ b/DisCatSharp/Net/Rest/DiscordApiClient.cs @@ -3116,7 +3116,7 @@ internal async Task CreateMessageAsync(ulong channelId, DiscordM if (builder.IsVoiceMessage) flags |= MessageFlags.IsVoiceMessage; if (builder.IsUIKit) - flags |= MessageFlags.UIKit; + flags |= MessageFlags.IsComponentsV2; var pld = new RestChannelMessageCreatePayload { @@ -5344,7 +5344,7 @@ internal async Task EditWebhookMessageAsync(ulong webhookId, str if (builder.NotificationsSuppressed) flags |= MessageFlags.SuppressNotifications; if (builder.IsUIKit) - flags |= MessageFlags.UIKit; + flags |= MessageFlags.IsComponentsV2; var pld = new RestWebhookMessageEditPayload { @@ -7066,7 +7066,7 @@ internal async Task CreateInteractionRespons if (builder.NotificationsSuppressed) flags |= MessageFlags.SuppressNotifications; if (builder.IsUIKit) - flags |= MessageFlags.UIKit; + flags |= MessageFlags.IsComponentsV2; } var data = builder is not null @@ -7302,7 +7302,7 @@ internal async Task CreateFollowupMessageAsync(ulong application if (builder.NotificationsSuppressed) flags |= MessageFlags.SuppressNotifications; if (builder.IsUIKit) - flags |= MessageFlags.UIKit; + flags |= MessageFlags.IsComponentsV2; var values = new Dictionary(); var pld = new RestFollowupMessageCreatePayload From 59a6c45c4db64a5888fc986bcb4675e34e8790db Mon Sep 17 00:00:00 2001 From: Lala Sabathil Date: Thu, 9 Jan 2025 02:05:32 +0100 Subject: [PATCH 23/33] fix: container components limit is 10 --- .../Components/UIKit/DiscordContainerComponent.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordContainerComponent.cs b/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordContainerComponent.cs index de9a696a9a..8f9e2c9402 100644 --- a/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordContainerComponent.cs +++ b/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordContainerComponent.cs @@ -36,13 +36,13 @@ public DiscordContainerComponent(DiscordContainerComponent other) /// /// Constructs a new container component field with the specified options. /// - /// The container components. Max of 3. + /// The container components. Max of 10. public DiscordContainerComponent(IEnumerable components) : this() { var comps = components.ToList(); - if (comps.Count > 3) - throw new ArgumentException("You can only have up to 3 components in a container."); + if (comps.Count > 10) + throw new ArgumentException("You can only have up to 10 components in a container."); List allowedTypes = [ComponentType.ActionRow, ComponentType.TextDisplay, ComponentType.Section, ComponentType.MediaGallery, ComponentType.Seperator, ComponentType.File]; if (comps.Any(c => !allowedTypes.Contains(c.Type))) From b644845e02d0fa8cd940e5cc6f70da458de3d206 Mon Sep 17 00:00:00 2001 From: Lala Sabathil Date: Thu, 9 Jan 2025 14:05:53 +0100 Subject: [PATCH 24/33] chore: bump packages --- .../DisCatSharp.ApplicationCommands.csproj | 2 ++ DisCatSharp.CommandsNext/DisCatSharp.CommandsNext.csproj | 2 ++ DisCatSharp.Common/DisCatSharp.Common.csproj | 2 +- DisCatSharp.Configuration/DisCatSharp.Configuration.csproj | 2 ++ DisCatSharp.Experimental/DisCatSharp.Experimental.csproj | 2 ++ .../DisCatSharp.Hosting.DependencyInjection.csproj | 2 ++ DisCatSharp.Hosting/DisCatSharp.Hosting.csproj | 2 ++ DisCatSharp.Interactivity/DisCatSharp.Interactivity.csproj | 2 ++ DisCatSharp.Lavalink/DisCatSharp.Lavalink.csproj | 2 ++ .../DisCatSharp.Analyzer/DisCatSharp.Analyzer.csproj | 2 ++ DisCatSharp.VoiceNext/DisCatSharp.VoiceNext.csproj | 2 ++ DisCatSharp/DisCatSharp.csproj | 2 +- 12 files changed, 22 insertions(+), 2 deletions(-) diff --git a/DisCatSharp.ApplicationCommands/DisCatSharp.ApplicationCommands.csproj b/DisCatSharp.ApplicationCommands/DisCatSharp.ApplicationCommands.csproj index 5ee388c8c9..e53ef0b563 100644 --- a/DisCatSharp.ApplicationCommands/DisCatSharp.ApplicationCommands.csproj +++ b/DisCatSharp.ApplicationCommands/DisCatSharp.ApplicationCommands.csproj @@ -28,6 +28,7 @@ + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -36,6 +37,7 @@ + diff --git a/DisCatSharp.CommandsNext/DisCatSharp.CommandsNext.csproj b/DisCatSharp.CommandsNext/DisCatSharp.CommandsNext.csproj index 9557b04f90..613bf26405 100644 --- a/DisCatSharp.CommandsNext/DisCatSharp.CommandsNext.csproj +++ b/DisCatSharp.CommandsNext/DisCatSharp.CommandsNext.csproj @@ -34,6 +34,7 @@ + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -45,6 +46,7 @@ + diff --git a/DisCatSharp.Common/DisCatSharp.Common.csproj b/DisCatSharp.Common/DisCatSharp.Common.csproj index 78dedca9e0..1d32c0b8c1 100644 --- a/DisCatSharp.Common/DisCatSharp.Common.csproj +++ b/DisCatSharp.Common/DisCatSharp.Common.csproj @@ -26,7 +26,7 @@ - + diff --git a/DisCatSharp.Configuration/DisCatSharp.Configuration.csproj b/DisCatSharp.Configuration/DisCatSharp.Configuration.csproj index d0b0725ed5..1d009e8959 100644 --- a/DisCatSharp.Configuration/DisCatSharp.Configuration.csproj +++ b/DisCatSharp.Configuration/DisCatSharp.Configuration.csproj @@ -23,6 +23,7 @@ + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -32,6 +33,7 @@ + diff --git a/DisCatSharp.Experimental/DisCatSharp.Experimental.csproj b/DisCatSharp.Experimental/DisCatSharp.Experimental.csproj index 57369fdd55..57b8effc8c 100644 --- a/DisCatSharp.Experimental/DisCatSharp.Experimental.csproj +++ b/DisCatSharp.Experimental/DisCatSharp.Experimental.csproj @@ -26,6 +26,7 @@ + @@ -34,6 +35,7 @@ + diff --git a/DisCatSharp.Hosting.DependencyInjection/DisCatSharp.Hosting.DependencyInjection.csproj b/DisCatSharp.Hosting.DependencyInjection/DisCatSharp.Hosting.DependencyInjection.csproj index 3364dba1c9..14351f95ba 100644 --- a/DisCatSharp.Hosting.DependencyInjection/DisCatSharp.Hosting.DependencyInjection.csproj +++ b/DisCatSharp.Hosting.DependencyInjection/DisCatSharp.Hosting.DependencyInjection.csproj @@ -17,6 +17,7 @@ + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -24,6 +25,7 @@ + diff --git a/DisCatSharp.Hosting/DisCatSharp.Hosting.csproj b/DisCatSharp.Hosting/DisCatSharp.Hosting.csproj index 7a5e06609c..b199fc1c72 100644 --- a/DisCatSharp.Hosting/DisCatSharp.Hosting.csproj +++ b/DisCatSharp.Hosting/DisCatSharp.Hosting.csproj @@ -22,6 +22,7 @@ + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -34,6 +35,7 @@ + diff --git a/DisCatSharp.Interactivity/DisCatSharp.Interactivity.csproj b/DisCatSharp.Interactivity/DisCatSharp.Interactivity.csproj index 6d2d079baf..e3217838c6 100644 --- a/DisCatSharp.Interactivity/DisCatSharp.Interactivity.csproj +++ b/DisCatSharp.Interactivity/DisCatSharp.Interactivity.csproj @@ -28,6 +28,7 @@ + all @@ -36,6 +37,7 @@ + diff --git a/DisCatSharp.Lavalink/DisCatSharp.Lavalink.csproj b/DisCatSharp.Lavalink/DisCatSharp.Lavalink.csproj index d81fadeff4..6192b3271a 100644 --- a/DisCatSharp.Lavalink/DisCatSharp.Lavalink.csproj +++ b/DisCatSharp.Lavalink/DisCatSharp.Lavalink.csproj @@ -36,6 +36,7 @@ + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -47,6 +48,7 @@ + diff --git a/DisCatSharp.Tools/DisCatSharp.Analyzer/DisCatSharp.Analyzer/DisCatSharp.Analyzer.csproj b/DisCatSharp.Tools/DisCatSharp.Analyzer/DisCatSharp.Analyzer/DisCatSharp.Analyzer.csproj index caeba16893..94f4ee9c48 100644 --- a/DisCatSharp.Tools/DisCatSharp.Analyzer/DisCatSharp.Analyzer/DisCatSharp.Analyzer.csproj +++ b/DisCatSharp.Tools/DisCatSharp.Analyzer/DisCatSharp.Analyzer/DisCatSharp.Analyzer.csproj @@ -37,12 +37,14 @@ + all runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/DisCatSharp.VoiceNext/DisCatSharp.VoiceNext.csproj b/DisCatSharp.VoiceNext/DisCatSharp.VoiceNext.csproj index 73a0d91bdc..8f92fad5fe 100644 --- a/DisCatSharp.VoiceNext/DisCatSharp.VoiceNext.csproj +++ b/DisCatSharp.VoiceNext/DisCatSharp.VoiceNext.csproj @@ -29,6 +29,7 @@ + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -36,6 +37,7 @@ + diff --git a/DisCatSharp/DisCatSharp.csproj b/DisCatSharp/DisCatSharp.csproj index 43e506072b..a2f64e7917 100644 --- a/DisCatSharp/DisCatSharp.csproj +++ b/DisCatSharp/DisCatSharp.csproj @@ -26,7 +26,7 @@ - + From ace8facc96694d75ff9cacadf80a5ed003c6aa8f Mon Sep 17 00:00:00 2001 From: Lala Sabathil Date: Thu, 9 Jan 2025 14:05:57 +0100 Subject: [PATCH 25/33] fix: fix some stuff --- DisCatSharp/Entities/Core/DisCatSharpBuilder.cs | 14 +++++++------- .../Components/UIKit/DiscordContainerComponent.cs | 6 +++++- .../Components/UIKit/DiscordMediaGalleryItem.cs | 2 +- .../Components/UIKit/DiscordSectionComponent.cs | 2 +- .../Interaction/DiscordFollowupMessageBuilder.cs | 12 +++++++++++- .../DiscordInteractionResponseBuilder.cs | 8 ++++---- .../Entities/Message/DiscordMessageBuilder.cs | 11 +++++------ .../Entities/Webhook/DiscordWebhookBuilder.cs | 6 +++--- DisCatSharp/Net/Rest/DiscordApiClient.cs | 8 ++++---- 9 files changed, 41 insertions(+), 28 deletions(-) diff --git a/DisCatSharp/Entities/Core/DisCatSharpBuilder.cs b/DisCatSharp/Entities/Core/DisCatSharpBuilder.cs index 07495d98c7..7dabd46d16 100644 --- a/DisCatSharp/Entities/Core/DisCatSharpBuilder.cs +++ b/DisCatSharp/Entities/Core/DisCatSharpBuilder.cs @@ -51,7 +51,7 @@ public string? Content get => this.ContentInternal; set { - if (this.IsUIKit || this.IsVoiceMessage) + if (this.IsComponentsV2 || this.IsVoiceMessage) throw new InvalidOperationException("You cannot set the content for UI Kit / Voice messages"); if (value is { Length: > 2000 }) @@ -131,12 +131,12 @@ public bool NotificationsSuppressed /// /// Sets whether this builder should be using UI Kit. /// - public bool IsUIKit + public bool IsComponentsV2 { - get => this.UI_KIT; + get => this.IS_COMPONENTS_V2; set { - this.UI_KIT = value; + this.IS_COMPONENTS_V2 = value; this.FlagsChanged = true; } } @@ -144,7 +144,7 @@ public bool IsUIKit /// /// Whether this builder is using UI Kit. /// - private bool UI_KIT { get; set; } + private bool IS_COMPONENTS_V2 { get; set; } /// /// Sets whether this builder suppresses its embeds. @@ -154,7 +154,7 @@ public bool EmbedsSuppressed get => this.EMBEDS_SUPPRESSED; set { - if (this.IsUIKit) + if (this.IsComponentsV2) throw new InvalidOperationException("You cannot set embeds suppressed for UI Kit messages since they cannot have embeds"); this.EMBEDS_SUPPRESSED = value; @@ -184,7 +184,7 @@ public virtual void Clear() this.AttachmentsInternal.Clear(); this.ComponentsInternal.Clear(); this.IsVoiceMessage = false; - this.IsUIKit = false; + this.IsComponentsV2 = false; this.EmbedsSuppressed = false; this.NotificationsSuppressed = false; this.FlagsChanged = false; diff --git a/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordContainerComponent.cs b/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordContainerComponent.cs index 8f9e2c9402..3d0d07fe24 100644 --- a/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordContainerComponent.cs +++ b/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordContainerComponent.cs @@ -37,7 +37,9 @@ public DiscordContainerComponent(DiscordContainerComponent other) /// Constructs a new container component field with the specified options. /// /// The container components. Max of 10. - public DiscordContainerComponent(IEnumerable components) + /// Whether the container should be marked as spoiler. + /// The accent color for the container. + public DiscordContainerComponent(IEnumerable components, bool? spoiler = null, DiscordColor? accentColor = null) : this() { var comps = components.ToList(); @@ -49,6 +51,8 @@ public DiscordContainerComponent(IEnumerable components) throw new ArgumentException("All components must be of type ActionRow, TextDisplay, Section, MediaGallery, Seperator, or File."); this.Components = comps.ToList(); + this.Spoiler = spoiler; + this.AccentColor = accentColor; } /// diff --git a/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordMediaGalleryItem.cs b/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordMediaGalleryItem.cs index 64d412f667..c11ec2c823 100644 --- a/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordMediaGalleryItem.cs +++ b/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordMediaGalleryItem.cs @@ -19,7 +19,7 @@ internal DiscordMediaGalleryItem() /// The url. /// The description. /// Whether this item should be marked as spoiler. - public DiscordMediaGalleryItem(string url, string? description, bool? spoiler) + public DiscordMediaGalleryItem(string url, string? description = null, bool? spoiler = null) { this.Media = new(url); this.Description = description; diff --git a/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordSectionComponent.cs b/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordSectionComponent.cs index 6947e52c81..a9ac01ece8 100644 --- a/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordSectionComponent.cs +++ b/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordSectionComponent.cs @@ -57,7 +57,7 @@ public DiscordSectionComponent(IEnumerable componen /// Can be at the moment, but might include buttons later. /// [JsonProperty("accessory", NullValueHandling = NullValueHandling.Ignore)] - public DiscordSectionAccessory Accessory { get; internal set; } + public DiscordSectionAccessory? Accessory { get; internal set; } /// /// Adds a thumbnail component to the section. diff --git a/DisCatSharp/Entities/Interaction/DiscordFollowupMessageBuilder.cs b/DisCatSharp/Entities/Interaction/DiscordFollowupMessageBuilder.cs index 142563b517..5542120fa2 100644 --- a/DisCatSharp/Entities/Interaction/DiscordFollowupMessageBuilder.cs +++ b/DisCatSharp/Entities/Interaction/DiscordFollowupMessageBuilder.cs @@ -37,6 +37,16 @@ public bool IsEphemeral /// public DiscordPollBuilder? Poll { get; private set; } + /// + /// Sets that this builder should be using UI Kit. + /// + /// The current builder to chain calls with. + public DiscordFollowupMessageBuilder WithV2Components() + { + this.IsComponentsV2 = true; + return this; + } + /// /// Appends a collection of components to the message. /// @@ -75,7 +85,7 @@ public DiscordFollowupMessageBuilder AddComponents(IEnumerable var cmpArr = components.ToArray(); var count = cmpArr.Length; - if (this.IsUIKit) + if (this.IsComponentsV2) { switch (count) { diff --git a/DisCatSharp/Entities/Interaction/DiscordInteractionResponseBuilder.cs b/DisCatSharp/Entities/Interaction/DiscordInteractionResponseBuilder.cs index 61053b5972..1cc1338371 100644 --- a/DisCatSharp/Entities/Interaction/DiscordInteractionResponseBuilder.cs +++ b/DisCatSharp/Entities/Interaction/DiscordInteractionResponseBuilder.cs @@ -35,7 +35,7 @@ public DiscordInteractionResponseBuilder(DisCatSharpBuilder builder) this.EmbedsInternal.AddRange(builder.Embeds); this.ComponentsInternal.AddRange(builder.Components); this.EmbedsSuppressed = builder.EmbedsSuppressed; - this.IsUIKit = builder.IsUIKit; + this.IsComponentsV2 = builder.IsComponentsV2; this.FilesInternal.AddRange(builder.Files); this.AttachmentsInternal.AddRange(builder.Attachments); } @@ -141,7 +141,7 @@ public DiscordInteractionResponseBuilder AddComponents(IEnumerable /// The current builder to chain calls with. - public DiscordInteractionResponseBuilder AsUIKitMessage() + public DiscordInteractionResponseBuilder WithV2Components() { - this.IsUIKit = true; + this.IsComponentsV2 = true; return this; } diff --git a/DisCatSharp/Entities/Message/DiscordMessageBuilder.cs b/DisCatSharp/Entities/Message/DiscordMessageBuilder.cs index b8e5d25181..e981ab4eb2 100644 --- a/DisCatSharp/Entities/Message/DiscordMessageBuilder.cs +++ b/DisCatSharp/Entities/Message/DiscordMessageBuilder.cs @@ -4,7 +4,6 @@ using System.Linq; using System.Threading.Tasks; -using DisCatSharp.Attributes; using DisCatSharp.Entities.Core; namespace DisCatSharp.Entities; @@ -168,7 +167,7 @@ public DiscordMessageBuilder AddComponents(IEnumerable compone var cmpArr = components.ToArray(); var count = cmpArr.Length; - if (this.IsUIKit) + if (this.IsComponentsV2) { switch (count) { @@ -221,9 +220,9 @@ public DiscordMessageBuilder SuppressEmbeds(bool suppress = true) /// Sets that this builder should be using UI Kit. /// /// The current builder to chain calls with. - public DiscordMessageBuilder AsUIKitMessage() + public DiscordMessageBuilder WithV2Components() { - this.IsUIKit = true; + this.IsComponentsV2 = true; return this; } @@ -470,10 +469,10 @@ internal void Validate(bool isModify = false) if (this.Files?.Count == 0 && string.IsNullOrEmpty(this.Content) && !this.Embeds.Any() && this.Sticker is null && (!this.Components?.Any() ?? true) && this.Poll is null && this?.Attachments.Count == 0) throw new ArgumentException("You must specify content, an embed, a sticker, a component, a poll or at least one file."); - if (this.IsUIKit && (!string.IsNullOrEmpty(this.Content) || this.Embeds.Any())) + if (this.IsComponentsV2 && (!string.IsNullOrEmpty(this.Content) || this.Embeds.Any())) throw new ArgumentException("Using UI Kit mode. You cannot specify content or embeds."); - switch (this.IsUIKit) + switch (this.IsComponentsV2) { case true when this.Components?.Count > 10: throw new InvalidOperationException("You can only have 10 components per message."); diff --git a/DisCatSharp/Entities/Webhook/DiscordWebhookBuilder.cs b/DisCatSharp/Entities/Webhook/DiscordWebhookBuilder.cs index bc1ac50a80..2bceabd79e 100644 --- a/DisCatSharp/Entities/Webhook/DiscordWebhookBuilder.cs +++ b/DisCatSharp/Entities/Webhook/DiscordWebhookBuilder.cs @@ -123,7 +123,7 @@ public DiscordWebhookBuilder AddComponents(IEnumerable compone var cmpArr = components.ToArray(); var count = cmpArr.Length; - if (this.IsUIKit) + if (this.IsComponentsV2) { switch (count) { @@ -156,10 +156,10 @@ public DiscordWebhookBuilder AddComponents(IEnumerable compone /// Sets that this builder should be using UI Kit. /// /// The current builder to chain calls with. - public DiscordWebhookBuilder AsUIKitMessage() + public DiscordWebhookBuilder WithV2Components() { this.FlagsChanged = true; - this.IsUIKit = true; + this.IsComponentsV2 = true; return this; } diff --git a/DisCatSharp/Net/Rest/DiscordApiClient.cs b/DisCatSharp/Net/Rest/DiscordApiClient.cs index 56fac8c146..2182b2248c 100644 --- a/DisCatSharp/Net/Rest/DiscordApiClient.cs +++ b/DisCatSharp/Net/Rest/DiscordApiClient.cs @@ -3115,7 +3115,7 @@ internal async Task CreateMessageAsync(ulong channelId, DiscordM flags |= MessageFlags.SuppressNotifications; if (builder.IsVoiceMessage) flags |= MessageFlags.IsVoiceMessage; - if (builder.IsUIKit) + if (builder.IsComponentsV2) flags |= MessageFlags.IsComponentsV2; var pld = new RestChannelMessageCreatePayload @@ -5343,7 +5343,7 @@ internal async Task EditWebhookMessageAsync(ulong webhookId, str flags |= MessageFlags.SuppressedEmbeds; if (builder.NotificationsSuppressed) flags |= MessageFlags.SuppressNotifications; - if (builder.IsUIKit) + if (builder.IsComponentsV2) flags |= MessageFlags.IsComponentsV2; var pld = new RestWebhookMessageEditPayload @@ -7065,7 +7065,7 @@ internal async Task CreateInteractionRespons flags |= MessageFlags.SuppressedEmbeds; if (builder.NotificationsSuppressed) flags |= MessageFlags.SuppressNotifications; - if (builder.IsUIKit) + if (builder.IsComponentsV2) flags |= MessageFlags.IsComponentsV2; } @@ -7301,7 +7301,7 @@ internal async Task CreateFollowupMessageAsync(ulong application flags |= MessageFlags.SuppressedEmbeds; if (builder.NotificationsSuppressed) flags |= MessageFlags.SuppressNotifications; - if (builder.IsUIKit) + if (builder.IsComponentsV2) flags |= MessageFlags.IsComponentsV2; var values = new Dictionary(); From 7ac519b17ce37d5ea1deef6ec5ad6d081ebad1e7 Mon Sep 17 00:00:00 2001 From: Lala Sabathil Date: Thu, 9 Jan 2025 14:25:58 +0100 Subject: [PATCH 26/33] fix: fix color convert --- .../Components/UIKit/DiscordContainerComponent.cs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordContainerComponent.cs b/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordContainerComponent.cs index 3d0d07fe24..0e875c8779 100644 --- a/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordContainerComponent.cs +++ b/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordContainerComponent.cs @@ -50,7 +50,7 @@ public DiscordContainerComponent(IEnumerable components, bool? if (comps.Any(c => !allowedTypes.Contains(c.Type))) throw new ArgumentException("All components must be of type ActionRow, TextDisplay, Section, MediaGallery, Seperator, or File."); - this.Components = comps.ToList(); + this.Components = [.. comps]; this.Spoiler = spoiler; this.AccentColor = accentColor; } @@ -64,9 +64,16 @@ public DiscordContainerComponent(IEnumerable components, bool? /// /// The accent color for the container. /// - [JsonProperty("accent_color", NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore] public DiscordColor? AccentColor { get; internal set; } + /// + /// Gets the accent color int for the container. + /// + [JsonProperty("accent_color", NullValueHandling = NullValueHandling.Ignore)] + internal int? AccentColorInt + => this.AccentColor?.Value; + /// /// Gets whether this container should be marked as spoiler. /// From 42cd50fe7d82d4220b7fe332bd7739057612018b Mon Sep 17 00:00:00 2001 From: Lala Sabathil Date: Thu, 9 Jan 2025 14:35:23 +0100 Subject: [PATCH 27/33] fix: fix mention issues --- .../DiscordInteractionApplicationCommandCallbackData.cs | 2 +- .../Net/Abstractions/Rest/RestApplicationCommandPayloads.cs | 2 +- DisCatSharp/Net/Abstractions/Rest/RestWebhookPayloads.cs | 2 +- DisCatSharp/Net/Rest/DiscordApiClient.cs | 6 ++++-- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/DisCatSharp/Entities/Interaction/DiscordInteractionApplicationCommandCallbackData.cs b/DisCatSharp/Entities/Interaction/DiscordInteractionApplicationCommandCallbackData.cs index e7ca7da632..4b58349ae9 100644 --- a/DisCatSharp/Entities/Interaction/DiscordInteractionApplicationCommandCallbackData.cs +++ b/DisCatSharp/Entities/Interaction/DiscordInteractionApplicationCommandCallbackData.cs @@ -33,7 +33,7 @@ internal class DiscordInteractionApplicationCommandCallbackData : ObservableApiO /// Gets the mentions. /// [JsonProperty("allowed_mentions", NullValueHandling = NullValueHandling.Ignore)] - public IReadOnlyList? Mentions { get; internal set; } + public DiscordMentions? Mentions { get; internal set; } /// /// Gets the flags. diff --git a/DisCatSharp/Net/Abstractions/Rest/RestApplicationCommandPayloads.cs b/DisCatSharp/Net/Abstractions/Rest/RestApplicationCommandPayloads.cs index 2d949a59b0..b009199de6 100644 --- a/DisCatSharp/Net/Abstractions/Rest/RestApplicationCommandPayloads.cs +++ b/DisCatSharp/Net/Abstractions/Rest/RestApplicationCommandPayloads.cs @@ -253,7 +253,7 @@ internal sealed class RestFollowupMessageCreatePayload : ObservableApiObject /// Gets the mentions. /// [JsonProperty("allowed_mentions", NullValueHandling = NullValueHandling.Ignore)] - public DiscordMentions Mentions { get; set; } + public DiscordMentions? Mentions { get; set; } /// /// Gets the flags. diff --git a/DisCatSharp/Net/Abstractions/Rest/RestWebhookPayloads.cs b/DisCatSharp/Net/Abstractions/Rest/RestWebhookPayloads.cs index 0b616b4dd9..f4cfeeb14d 100644 --- a/DisCatSharp/Net/Abstractions/Rest/RestWebhookPayloads.cs +++ b/DisCatSharp/Net/Abstractions/Rest/RestWebhookPayloads.cs @@ -136,7 +136,7 @@ internal sealed class RestWebhookMessageEditPayload : ObservableApiObject /// Gets or sets the mentions. /// [JsonProperty("allowed_mentions", NullValueHandling = NullValueHandling.Ignore)] - public IEnumerable Mentions { get; set; } + public DiscordMentions? Mentions { get; set; } /// /// Gets or sets the attachments. diff --git a/DisCatSharp/Net/Rest/DiscordApiClient.cs b/DisCatSharp/Net/Rest/DiscordApiClient.cs index 2182b2248c..b26c38293c 100644 --- a/DisCatSharp/Net/Rest/DiscordApiClient.cs +++ b/DisCatSharp/Net/Rest/DiscordApiClient.cs @@ -5350,11 +5350,13 @@ internal async Task EditWebhookMessageAsync(ulong webhookId, str { Content = builder.Content, Embeds = builder.Embeds, - Mentions = builder.Mentions, Components = builder.Components, Flags = flags }; + if (builder.Mentions.Any()) + pld.Mentions = new(builder.Mentions, builder.Mentions.Count is not 0); + if (builder.Files?.Count > 0) { ulong fileId = 0; @@ -7075,7 +7077,7 @@ internal async Task CreateInteractionRespons Content = builder?.Content ?? null, Embeds = builder?.Embeds ?? null, IsTts = builder?.IsTts, - Mentions = builder?.Mentions ?? null, + Mentions = (builder?.Mentions.Any() ?? false) ? new(builder.Mentions, builder.Mentions.Count is not 0) : null, Flags = flags, Components = builder?.Components ?? null, Choices = null, From 672c6fbdfcff6a9182aaaafe4611a436194ac1f6 Mon Sep 17 00:00:00 2001 From: Lala Sabathil Date: Thu, 9 Jan 2025 14:38:43 +0100 Subject: [PATCH 28/33] fix: announced change wasn't made yet --- .../Interaction/Components/UIKit/DiscordThumnailComponent.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordThumnailComponent.cs b/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordThumnailComponent.cs index 11b4aa1408..afab198465 100644 --- a/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordThumnailComponent.cs +++ b/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordThumnailComponent.cs @@ -34,7 +34,8 @@ internal DiscordThumnailComponent(string url, string? description = null, bool? /// /// Gets the media item. /// - [JsonProperty("media")] + // TODO: rename image to media + [JsonProperty("image")] public DiscordUnfurledMediaItem Media { get; internal set; } /// From c5da2cbfb141b9461b9faf766992276bc80fce38 Mon Sep 17 00:00:00 2001 From: Lala Sabathil Date: Thu, 9 Jan 2025 14:50:31 +0100 Subject: [PATCH 29/33] fix: add missing primary_guild field Fixes DISCATSHARP-2EM Fixes DISCATSHARP-2EK --- DisCatSharp.Experimental/DiscordApiClientHook.cs | 1 + DisCatSharp/Clients/DiscordClient.Dispatch.cs | 3 +++ DisCatSharp/Clients/DiscordClient.cs | 4 ++++ DisCatSharp/Entities/Guild/DiscordGuild.cs | 1 + DisCatSharp/Entities/Guild/DiscordMember.cs | 10 ++++++++++ DisCatSharp/Entities/User/DiscordUser.cs | 7 +++++++ .../Net/Abstractions/Transport/TransportUser.cs | 6 ++++++ DisCatSharp/Net/Rest/DiscordApiClient.cs | 1 + 8 files changed, 33 insertions(+) diff --git a/DisCatSharp.Experimental/DiscordApiClientHook.cs b/DisCatSharp.Experimental/DiscordApiClientHook.cs index 9b5279e474..0e7b383a4a 100644 --- a/DisCatSharp.Experimental/DiscordApiClientHook.cs +++ b/DisCatSharp.Experimental/DiscordApiClientHook.cs @@ -236,6 +236,7 @@ internal async Task SearchGuildMembersAsync(u old.Locale = usr.Locale; old.GlobalName = usr.GlobalName; old.Clan = usr.Clan; + old.PrimaryGuild = usr.PrimaryGuild; return old; }); } diff --git a/DisCatSharp/Clients/DiscordClient.Dispatch.cs b/DisCatSharp/Clients/DiscordClient.Dispatch.cs index af9779ca0d..aa5894ac07 100644 --- a/DisCatSharp/Clients/DiscordClient.Dispatch.cs +++ b/DisCatSharp/Clients/DiscordClient.Dispatch.cs @@ -771,6 +771,7 @@ internal async Task OnReadyEventAsync(ReadyPayload ready, JArray rawGuilds) old.Locale = usr.Locale; old.GlobalName = usr.GlobalName; old.Clan = usr.Clan; + old.PrimaryGuild = usr.PrimaryGuild; return old; }); @@ -1971,6 +1972,7 @@ internal async Task OnGuildMemberAddEventAsync(TransportMember member, DiscordGu old.Locale = usr.Locale; old.GlobalName = usr.GlobalName; old.Clan = usr.Clan; + old.PrimaryGuild = usr.PrimaryGuild; return old; }); @@ -2045,6 +2047,7 @@ internal async Task OnGuildMemberUpdateEventAsync(TransportMember member, Discor old.Locale = usr.Locale; old.GlobalName = usr.GlobalName; old.Clan = usr.Clan; + old.PrimaryGuild = usr.PrimaryGuild; return old; }); diff --git a/DisCatSharp/Clients/DiscordClient.cs b/DisCatSharp/Clients/DiscordClient.cs index 2d4d1dc7d3..2f7701dfc4 100644 --- a/DisCatSharp/Clients/DiscordClient.cs +++ b/DisCatSharp/Clients/DiscordClient.cs @@ -538,6 +538,7 @@ public async Task GetUserAsync(ulong userId, bool fetch = false) old.Pronouns = usr.Pronouns; old.GlobalName = usr.GlobalName; old.Clan = usr.Clan; + old.PrimaryGuild = usr.PrimaryGuild; return old; }); @@ -1624,6 +1625,7 @@ private DiscordUser UpdateUser(DiscordUser usr, ulong? guildId, DiscordGuild? gu old.Locale = usr.Locale; old.GlobalName = usr.GlobalName; old.Clan = usr.Clan; + old.PrimaryGuild = usr.PrimaryGuild; return old; }); @@ -1662,6 +1664,7 @@ private DiscordUser UpdateUser(DiscordUser usr, ulong? guildId, DiscordGuild? gu old.Locale = usr.Locale; old.GlobalName = usr.GlobalName; old.Clan = usr.Clan; + old.PrimaryGuild = usr.PrimaryGuild; return old; }); @@ -1841,6 +1844,7 @@ private void UpdateCachedGuild(DiscordGuild newGuild, JArray? rawMembers) old.Locale = usr.Locale; old.GlobalName = usr.GlobalName; old.Clan = usr.Clan; + old.PrimaryGuild = usr.PrimaryGuild; return old; }); diff --git a/DisCatSharp/Entities/Guild/DiscordGuild.cs b/DisCatSharp/Entities/Guild/DiscordGuild.cs index c8b656975a..62786abc79 100644 --- a/DisCatSharp/Entities/Guild/DiscordGuild.cs +++ b/DisCatSharp/Entities/Guild/DiscordGuild.cs @@ -2078,6 +2078,7 @@ public async Task> GetAllMembersAsync() old.Locale = usr.Locale; old.GlobalName = usr.GlobalName; old.Clan = usr.Clan; + old.PrimaryGuild = usr.PrimaryGuild; return old; }); var mbr = new DiscordMember(xtm) diff --git a/DisCatSharp/Entities/Guild/DiscordMember.cs b/DisCatSharp/Entities/Guild/DiscordMember.cs index 1834e720cc..64f2f29fec 100644 --- a/DisCatSharp/Entities/Guild/DiscordMember.cs +++ b/DisCatSharp/Entities/Guild/DiscordMember.cs @@ -794,6 +794,16 @@ public override DiscordClan? Clan internal set => this.User.Clan = value; } + /// + /// Gets the member's primary guild. + /// + [JsonIgnore] + public override DiscordClan? PrimaryGuild + { + get => this.User.PrimaryGuild; + internal set => this.User.PrimaryGuild = value; + } + /// /// Gets whether the member is a bot. /// diff --git a/DisCatSharp/Entities/User/DiscordUser.cs b/DisCatSharp/Entities/User/DiscordUser.cs index 15c1b9a011..c574ace20b 100644 --- a/DisCatSharp/Entities/User/DiscordUser.cs +++ b/DisCatSharp/Entities/User/DiscordUser.cs @@ -65,6 +65,7 @@ internal DiscordUser(TransportUser transport) this.Pronouns = transport.Pronouns; this.GlobalName = transport.GlobalName; this.Clan = transport.Clan; + this.PrimaryGuild = transport.PrimaryGuild; } /// @@ -156,6 +157,12 @@ public string? BannerUrl [JsonProperty("clan", NullValueHandling = NullValueHandling.Ignore), DiscordUnreleased] public virtual DiscordClan? Clan { get; internal set; } + /// + /// Gets the users primary guild. + /// + [JsonProperty("primary_guild", NullValueHandling = NullValueHandling.Ignore), DiscordUnreleased] + public virtual DiscordClan? PrimaryGuild { get; internal set; } + /// /// Gets the user's avatar hash. /// diff --git a/DisCatSharp/Net/Abstractions/Transport/TransportUser.cs b/DisCatSharp/Net/Abstractions/Transport/TransportUser.cs index b8229cc39f..ed039ece2b 100644 --- a/DisCatSharp/Net/Abstractions/Transport/TransportUser.cs +++ b/DisCatSharp/Net/Abstractions/Transport/TransportUser.cs @@ -175,6 +175,12 @@ internal string UsernameWithGlobalName [JsonProperty("clan", NullValueHandling = NullValueHandling.Ignore)] public DiscordClan? Clan { get; internal set; } + /// + /// Gets the users primary guild. + /// + [JsonProperty("primary_guild", NullValueHandling = NullValueHandling.Ignore), DiscordUnreleased] + public DiscordClan? PrimaryGuild { get; internal set; } + /// /// Gets the users pronouns. /// diff --git a/DisCatSharp/Net/Rest/DiscordApiClient.cs b/DisCatSharp/Net/Rest/DiscordApiClient.cs index b26c38293c..ff249d0758 100644 --- a/DisCatSharp/Net/Rest/DiscordApiClient.cs +++ b/DisCatSharp/Net/Rest/DiscordApiClient.cs @@ -476,6 +476,7 @@ internal async Task> SearchGuildMembersAsync(ulong old.Locale = usr.Locale; old.GlobalName = usr.GlobalName; old.Clan = usr.Clan; + old.PrimaryGuild = usr.PrimaryGuild; return old; }); From 29d10b8659e85efcb1911b94d49d5399d634f5e6 Mon Sep 17 00:00:00 2001 From: Lala Sabathil Date: Thu, 9 Jan 2025 14:55:56 +0100 Subject: [PATCH 30/33] fix: fix naming I can't english these days honestly --- .../UIKit/DiscordContainerComponent.cs | 4 ++-- ...ponent.cs => DiscordSeparatorComponent.cs} | 20 +++++++++---------- .../Enums/Interaction/ComponentType.cs | 4 ++-- ...SpacingSize.cs => SeparatorSpacingSize.cs} | 4 ++-- .../DiscordComponentJsonConverter.cs | 2 +- 5 files changed, 17 insertions(+), 17 deletions(-) rename DisCatSharp/Entities/Interaction/Components/UIKit/{DiscordSeperatorComponent.cs => DiscordSeparatorComponent.cs} (63%) rename DisCatSharp/Enums/Interaction/{SeperatorSpacingSize.cs => SeparatorSpacingSize.cs} (77%) diff --git a/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordContainerComponent.cs b/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordContainerComponent.cs index 0e875c8779..c4d4ea6a93 100644 --- a/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordContainerComponent.cs +++ b/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordContainerComponent.cs @@ -46,9 +46,9 @@ public DiscordContainerComponent(IEnumerable components, bool? if (comps.Count > 10) throw new ArgumentException("You can only have up to 10 components in a container."); - List allowedTypes = [ComponentType.ActionRow, ComponentType.TextDisplay, ComponentType.Section, ComponentType.MediaGallery, ComponentType.Seperator, ComponentType.File]; + List allowedTypes = [ComponentType.ActionRow, ComponentType.TextDisplay, ComponentType.Section, ComponentType.MediaGallery, ComponentType.Separator, ComponentType.File]; if (comps.Any(c => !allowedTypes.Contains(c.Type))) - throw new ArgumentException("All components must be of type ActionRow, TextDisplay, Section, MediaGallery, Seperator, or File."); + throw new ArgumentException("All components must be of type ActionRow, TextDisplay, Section, MediaGallery, Separator, or File."); this.Components = [.. comps]; this.Spoiler = spoiler; diff --git a/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordSeperatorComponent.cs b/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordSeparatorComponent.cs similarity index 63% rename from DisCatSharp/Entities/Interaction/Components/UIKit/DiscordSeperatorComponent.cs rename to DisCatSharp/Entities/Interaction/Components/UIKit/DiscordSeparatorComponent.cs index 81e2d77aac..0630e0d5f1 100644 --- a/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordSeperatorComponent.cs +++ b/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordSeparatorComponent.cs @@ -7,23 +7,23 @@ namespace DisCatSharp.Entities; /// -/// Represents a seperator component. +/// Represents a separator component. /// -public sealed class DiscordSeperatorComponent : DiscordComponent +public sealed class DiscordSeparatorComponent : DiscordComponent { /// - /// Constructs a new . + /// Constructs a new . /// - internal DiscordSeperatorComponent() + internal DiscordSeparatorComponent() { - this.Type = ComponentType.Seperator; + this.Type = ComponentType.Separator; } /// - /// Constructs a new seperator component based on another seperator component. + /// Constructs a new separator component based on another separator component. /// /// The button to copy. - public DiscordSeperatorComponent(DiscordSeperatorComponent other) + public DiscordSeparatorComponent(DiscordSeparatorComponent other) : this() { this.Divider = other.Divider; @@ -31,12 +31,12 @@ public DiscordSeperatorComponent(DiscordSeperatorComponent other) } /// - /// Constructs a new seperator component field with the specified options. + /// Constructs a new separator component field with the specified options. /// /// Whether this is a divider. /// The spacing size. /// Is thrown when no label is set. - public DiscordSeperatorComponent(bool? divider = null, SeperatorSpacingSize? spacing = null) + public DiscordSeparatorComponent(bool? divider = null, SeparatorSpacingSize? spacing = null) : this() { this.Divider = divider; @@ -47,7 +47,7 @@ public DiscordSeperatorComponent(bool? divider = null, SeperatorSpacingSize? spa /// The spacing size. /// [JsonProperty("spacing", NullValueHandling = NullValueHandling.Ignore)] - public SeperatorSpacingSize? Spacing { get; set; } + public SeparatorSpacingSize? Spacing { get; set; } /// /// Whether this is a divider. diff --git a/DisCatSharp/Enums/Interaction/ComponentType.cs b/DisCatSharp/Enums/Interaction/ComponentType.cs index 0a1a520285..12864c84c4 100644 --- a/DisCatSharp/Enums/Interaction/ComponentType.cs +++ b/DisCatSharp/Enums/Interaction/ComponentType.cs @@ -71,9 +71,9 @@ public enum ComponentType File = 13, /// - /// A seperator. + /// A separator. /// - Seperator = 14, + Separator = 14, /// /// Cannot be used by bots. diff --git a/DisCatSharp/Enums/Interaction/SeperatorSpacingSize.cs b/DisCatSharp/Enums/Interaction/SeparatorSpacingSize.cs similarity index 77% rename from DisCatSharp/Enums/Interaction/SeperatorSpacingSize.cs rename to DisCatSharp/Enums/Interaction/SeparatorSpacingSize.cs index 50cd4ed5e1..b279af4885 100644 --- a/DisCatSharp/Enums/Interaction/SeperatorSpacingSize.cs +++ b/DisCatSharp/Enums/Interaction/SeparatorSpacingSize.cs @@ -1,9 +1,9 @@ namespace DisCatSharp.Enums; /// -/// Represents the sperator spacing size of a . +/// Represents the sperator spacing size of a . /// -public enum SeperatorSpacingSize +public enum SeparatorSpacingSize { /// /// A small spacing size. diff --git a/DisCatSharp/Net/Serialization/DiscordComponentJsonConverter.cs b/DisCatSharp/Net/Serialization/DiscordComponentJsonConverter.cs index e0e334770e..9d1fb23d91 100644 --- a/DisCatSharp/Net/Serialization/DiscordComponentJsonConverter.cs +++ b/DisCatSharp/Net/Serialization/DiscordComponentJsonConverter.cs @@ -59,7 +59,7 @@ public override void WriteJson(JsonWriter writer, object? value, JsonSerializer ComponentType.Thumbnail => new DiscordThumnailComponent(), ComponentType.MediaGallery => new DiscordMediaGalleryComponent(), ComponentType.File => new DiscordFileDisplayComponent(), - ComponentType.Seperator => new DiscordSeperatorComponent(), + ComponentType.Separator => new DiscordSeparatorComponent(), _ => new() { Type = type From 99b600d087615bb8ce42ae99837bebb58cf2b7ef Mon Sep 17 00:00:00 2001 From: Lala Sabathil Date: Thu, 9 Jan 2025 14:59:14 +0100 Subject: [PATCH 31/33] fix: folder naming --- .../{UIKit => V2Components}/DiscordContainerComponent.cs | 0 .../{UIKit => V2Components}/DiscordFileDisplayComponent.cs | 0 .../{UIKit => V2Components}/DiscordMediaGalleryComponent.cs | 0 .../Components/{UIKit => V2Components}/DiscordMediaGalleryItem.cs | 0 .../Components/{UIKit => V2Components}/DiscordSectionAccessory.cs | 0 .../Components/{UIKit => V2Components}/DiscordSectionComponent.cs | 0 .../{UIKit => V2Components}/DiscordSeparatorComponent.cs | 0 .../{UIKit => V2Components}/DiscordTextDisplayComponent.cs | 0 .../{UIKit => V2Components}/DiscordThumnailComponent.cs | 0 .../{UIKit => V2Components}/DiscordUnfurledMediaItem.cs | 0 10 files changed, 0 insertions(+), 0 deletions(-) rename DisCatSharp/Entities/Interaction/Components/{UIKit => V2Components}/DiscordContainerComponent.cs (100%) rename DisCatSharp/Entities/Interaction/Components/{UIKit => V2Components}/DiscordFileDisplayComponent.cs (100%) rename DisCatSharp/Entities/Interaction/Components/{UIKit => V2Components}/DiscordMediaGalleryComponent.cs (100%) rename DisCatSharp/Entities/Interaction/Components/{UIKit => V2Components}/DiscordMediaGalleryItem.cs (100%) rename DisCatSharp/Entities/Interaction/Components/{UIKit => V2Components}/DiscordSectionAccessory.cs (100%) rename DisCatSharp/Entities/Interaction/Components/{UIKit => V2Components}/DiscordSectionComponent.cs (100%) rename DisCatSharp/Entities/Interaction/Components/{UIKit => V2Components}/DiscordSeparatorComponent.cs (100%) rename DisCatSharp/Entities/Interaction/Components/{UIKit => V2Components}/DiscordTextDisplayComponent.cs (100%) rename DisCatSharp/Entities/Interaction/Components/{UIKit => V2Components}/DiscordThumnailComponent.cs (100%) rename DisCatSharp/Entities/Interaction/Components/{UIKit => V2Components}/DiscordUnfurledMediaItem.cs (100%) diff --git a/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordContainerComponent.cs b/DisCatSharp/Entities/Interaction/Components/V2Components/DiscordContainerComponent.cs similarity index 100% rename from DisCatSharp/Entities/Interaction/Components/UIKit/DiscordContainerComponent.cs rename to DisCatSharp/Entities/Interaction/Components/V2Components/DiscordContainerComponent.cs diff --git a/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordFileDisplayComponent.cs b/DisCatSharp/Entities/Interaction/Components/V2Components/DiscordFileDisplayComponent.cs similarity index 100% rename from DisCatSharp/Entities/Interaction/Components/UIKit/DiscordFileDisplayComponent.cs rename to DisCatSharp/Entities/Interaction/Components/V2Components/DiscordFileDisplayComponent.cs diff --git a/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordMediaGalleryComponent.cs b/DisCatSharp/Entities/Interaction/Components/V2Components/DiscordMediaGalleryComponent.cs similarity index 100% rename from DisCatSharp/Entities/Interaction/Components/UIKit/DiscordMediaGalleryComponent.cs rename to DisCatSharp/Entities/Interaction/Components/V2Components/DiscordMediaGalleryComponent.cs diff --git a/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordMediaGalleryItem.cs b/DisCatSharp/Entities/Interaction/Components/V2Components/DiscordMediaGalleryItem.cs similarity index 100% rename from DisCatSharp/Entities/Interaction/Components/UIKit/DiscordMediaGalleryItem.cs rename to DisCatSharp/Entities/Interaction/Components/V2Components/DiscordMediaGalleryItem.cs diff --git a/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordSectionAccessory.cs b/DisCatSharp/Entities/Interaction/Components/V2Components/DiscordSectionAccessory.cs similarity index 100% rename from DisCatSharp/Entities/Interaction/Components/UIKit/DiscordSectionAccessory.cs rename to DisCatSharp/Entities/Interaction/Components/V2Components/DiscordSectionAccessory.cs diff --git a/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordSectionComponent.cs b/DisCatSharp/Entities/Interaction/Components/V2Components/DiscordSectionComponent.cs similarity index 100% rename from DisCatSharp/Entities/Interaction/Components/UIKit/DiscordSectionComponent.cs rename to DisCatSharp/Entities/Interaction/Components/V2Components/DiscordSectionComponent.cs diff --git a/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordSeparatorComponent.cs b/DisCatSharp/Entities/Interaction/Components/V2Components/DiscordSeparatorComponent.cs similarity index 100% rename from DisCatSharp/Entities/Interaction/Components/UIKit/DiscordSeparatorComponent.cs rename to DisCatSharp/Entities/Interaction/Components/V2Components/DiscordSeparatorComponent.cs diff --git a/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordTextDisplayComponent.cs b/DisCatSharp/Entities/Interaction/Components/V2Components/DiscordTextDisplayComponent.cs similarity index 100% rename from DisCatSharp/Entities/Interaction/Components/UIKit/DiscordTextDisplayComponent.cs rename to DisCatSharp/Entities/Interaction/Components/V2Components/DiscordTextDisplayComponent.cs diff --git a/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordThumnailComponent.cs b/DisCatSharp/Entities/Interaction/Components/V2Components/DiscordThumnailComponent.cs similarity index 100% rename from DisCatSharp/Entities/Interaction/Components/UIKit/DiscordThumnailComponent.cs rename to DisCatSharp/Entities/Interaction/Components/V2Components/DiscordThumnailComponent.cs diff --git a/DisCatSharp/Entities/Interaction/Components/UIKit/DiscordUnfurledMediaItem.cs b/DisCatSharp/Entities/Interaction/Components/V2Components/DiscordUnfurledMediaItem.cs similarity index 100% rename from DisCatSharp/Entities/Interaction/Components/UIKit/DiscordUnfurledMediaItem.cs rename to DisCatSharp/Entities/Interaction/Components/V2Components/DiscordUnfurledMediaItem.cs From 361d60b3026ff891c22ba7ae0b3d8bf5784f512d Mon Sep 17 00:00:00 2001 From: Lala Sabathil Date: Tue, 14 Jan 2025 09:27:32 +0100 Subject: [PATCH 32/33] chore: thumbnail uses media now as property name instead of image --- .../Components/V2Components/DiscordThumnailComponent.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/DisCatSharp/Entities/Interaction/Components/V2Components/DiscordThumnailComponent.cs b/DisCatSharp/Entities/Interaction/Components/V2Components/DiscordThumnailComponent.cs index afab198465..11b4aa1408 100644 --- a/DisCatSharp/Entities/Interaction/Components/V2Components/DiscordThumnailComponent.cs +++ b/DisCatSharp/Entities/Interaction/Components/V2Components/DiscordThumnailComponent.cs @@ -34,8 +34,7 @@ internal DiscordThumnailComponent(string url, string? description = null, bool? /// /// Gets the media item. /// - // TODO: rename image to media - [JsonProperty("image")] + [JsonProperty("media")] public DiscordUnfurledMediaItem Media { get; internal set; } /// From 009d3ef1d0f99b4a5e8969de1088e5bb6634c4b0 Mon Sep 17 00:00:00 2001 From: Lala Sabathil Date: Wed, 15 Jan 2025 23:22:51 +0100 Subject: [PATCH 33/33] chore!: deprecated WithFile(s) => replaced by AddFile(s) --- .../Entities/Message/DiscordMessageBuilder.cs | 28 +++++++++++++++---- 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/DisCatSharp/Entities/Message/DiscordMessageBuilder.cs b/DisCatSharp/Entities/Message/DiscordMessageBuilder.cs index e981ab4eb2..fae2f4920c 100644 --- a/DisCatSharp/Entities/Message/DiscordMessageBuilder.cs +++ b/DisCatSharp/Entities/Message/DiscordMessageBuilder.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Threading.Tasks; +using DisCatSharp.Attributes; using DisCatSharp.Entities.Core; namespace DisCatSharp.Entities; @@ -289,8 +290,13 @@ public DiscordMessageBuilder WithAllowedMentions(IEnumerable mentions) return this; } + /// + [Deprecated("Replaced by AddFile to streamline builders.")] + public DiscordMessageBuilder WithFile(string fileName, Stream stream, bool resetStreamPosition = false, string description = null) + => this.AddFile(fileName, stream, resetStreamPosition, description); + /// - /// Sets if the message has files to be sent. + /// Adds a file to the message. /// /// The fileName that the file should be sent as. /// The Stream to the file. @@ -300,7 +306,7 @@ public DiscordMessageBuilder WithAllowedMentions(IEnumerable mentions) /// /// Description of the file. /// The current builder to be chained. - public DiscordMessageBuilder WithFile(string fileName, Stream stream, bool resetStreamPosition = false, string description = null) + public DiscordMessageBuilder AddFile(string fileName, Stream stream, bool resetStreamPosition = false, string? description = null) { if (this.FilesInternal.Count > 10) throw new ArgumentException("Cannot send more than 10 files with a single message."); @@ -316,8 +322,13 @@ public DiscordMessageBuilder WithFile(string fileName, Stream stream, bool reset return this; } + /// + [Deprecated("Replaced by AddFile to streamline builders.")] + public DiscordMessageBuilder WithFile(FileStream stream, bool resetStreamPosition = false, string description = null) + => this.AddFile(stream, resetStreamPosition, description); + /// - /// Sets if the message has files to be sent. + /// Adds a file to the message. /// /// The Stream to the file. /// @@ -326,7 +337,7 @@ public DiscordMessageBuilder WithFile(string fileName, Stream stream, bool reset /// /// Description of the file. /// The current builder to be chained. - public DiscordMessageBuilder WithFile(FileStream stream, bool resetStreamPosition = false, string description = null) + public DiscordMessageBuilder AddFile(FileStream stream, bool resetStreamPosition = false, string? description = null) { if (this.FilesInternal.Count > 10) throw new ArgumentException("Cannot send more than 10 files with a single message."); @@ -342,8 +353,13 @@ public DiscordMessageBuilder WithFile(FileStream stream, bool resetStreamPositio return this; } + /// + [Deprecated("Replaced by AddFiles to streamline builders.")] + public DiscordMessageBuilder WithFiles(Dictionary files, bool resetStreamPosition = false) + => this.AddFiles(files, resetStreamPosition); + /// - /// Sets if the message has files to be sent. + /// Adds file to the message. /// /// The Files that should be sent. /// @@ -351,7 +367,7 @@ public DiscordMessageBuilder WithFile(FileStream stream, bool resetStreamPositio /// sent. /// /// The current builder to be chained. - public DiscordMessageBuilder WithFiles(Dictionary files, bool resetStreamPosition = false) + public DiscordMessageBuilder AddFiles(Dictionary files, bool resetStreamPosition = false) { if (this.FilesInternal.Count + files.Count > 10) throw new ArgumentException("Cannot send more than 10 files with a single message.");