diff --git a/src/main/java/net/dv8tion/jda/api/EmbedBuilder.java b/src/main/java/net/dv8tion/jda/api/EmbedBuilder.java index c8c6be38a8..2516fa5aa9 100644 --- a/src/main/java/net/dv8tion/jda/api/EmbedBuilder.java +++ b/src/main/java/net/dv8tion/jda/api/EmbedBuilder.java @@ -432,7 +432,7 @@ public EmbedBuilder setColor(int color) * *

Uploading images with Embeds *
When uploading an image - * (using {@link net.dv8tion.jda.api.entities.MessageChannel#sendFile(java.io.File, net.dv8tion.jda.api.utils.AttachmentOption...) MessageChannel.sendFile(...)}) + * (using {@link net.dv8tion.jda.api.entities.MessageChannel#sendFiles(net.dv8tion.jda.api.utils.FileUpload...) MessageChannel.sendFiles(...)}) * you can reference said image using the specified filename as URI {@code attachment://filename.ext}. * *

Example @@ -442,7 +442,7 @@ public EmbedBuilder setColor(int color) * InputStream file = new URL("https://http.cat/500").openStream(); * embed.setThumbnail("attachment://cat.png") // we specify this in sendFile as "cat.png" * .setDescription("This is a cute cat :3"); - * channel.sendFile(file, "cat.png").setEmbeds(embed.build()).queue(); + * channel.sendFiles(FileUpload.fromData(file, "cat.png")).setEmbeds(embed.build()).queue(); * * * @param url @@ -479,7 +479,7 @@ public EmbedBuilder setThumbnail(@Nullable String url) * *

Uploading images with Embeds *
When uploading an image - * (using {@link net.dv8tion.jda.api.entities.MessageChannel#sendFile(java.io.File, net.dv8tion.jda.api.utils.AttachmentOption...) MessageChannel.sendFile(...)}) + * (using {@link net.dv8tion.jda.api.entities.MessageChannel#sendFiles(net.dv8tion.jda.api.utils.FileUpload...) MessageChannel.sendFiles(...)}) * you can reference said image using the specified filename as URI {@code attachment://filename.ext}. * *

Example @@ -489,7 +489,7 @@ public EmbedBuilder setThumbnail(@Nullable String url) * InputStream file = new URL("https://http.cat/500").openStream(); * embed.setImage("attachment://cat.png") // we specify this in sendFile as "cat.png" * .setDescription("This is a cute cat :3"); - * channel.sendFile(file, "cat.png").setEmbeds(embed.build()).queue(); + * channel.sendFiles(FileUpload.fromData(file, "cat.png")).setEmbeds(embed.build()).queue(); * * * @param url @@ -504,7 +504,7 @@ public EmbedBuilder setThumbnail(@Nullable String url) * * @return the builder after the image has been set * - * @see net.dv8tion.jda.api.entities.MessageChannel#sendFile(java.io.File, String, net.dv8tion.jda.api.utils.AttachmentOption...) MessageChannel.sendFile(...) + * @see net.dv8tion.jda.api.entities.MessageChannel#sendFiles(net.dv8tion.jda.api.utils.FileUpload...) MessageChannel.sendFiles(...) */ @Nonnull public EmbedBuilder setImage(@Nullable String url) @@ -580,7 +580,7 @@ public EmbedBuilder setAuthor(@Nullable String name, @Nullable String url) * *

Uploading images with Embeds *
When uploading an image - * (using {@link net.dv8tion.jda.api.entities.MessageChannel#sendFile(java.io.File, net.dv8tion.jda.api.utils.AttachmentOption...) MessageChannel.sendFile(...)}) + * (using {@link net.dv8tion.jda.api.entities.MessageChannel#sendFiles(net.dv8tion.jda.api.utils.FileUpload...) MessageChannel.sendFiles(...)}) * you can reference said image using the specified filename as URI {@code attachment://filename.ext}. * *

Example @@ -590,7 +590,7 @@ public EmbedBuilder setAuthor(@Nullable String name, @Nullable String url) * InputStream file = new URL("https://http.cat/500").openStream(); * embed.setAuthor("Minn", null, "attachment://cat.png") // we specify this in sendFile as "cat.png" * .setDescription("This is a cute cat :3"); - * channel.sendFile(file, "cat.png").setEmbeds(embed.build()).queue(); + * channel.sendFiles(FileUpload.fromData(file, "cat.png")).setEmbeds(embed.build()).queue(); * * * @param name @@ -660,7 +660,7 @@ public EmbedBuilder setFooter(@Nullable String text) * *

Uploading images with Embeds *
When uploading an image - * (using {@link net.dv8tion.jda.api.entities.MessageChannel#sendFile(java.io.File, net.dv8tion.jda.api.utils.AttachmentOption...) MessageChannel.sendFile(...)}) + * (using {@link net.dv8tion.jda.api.entities.MessageChannel#sendFiles(net.dv8tion.jda.api.utils.FileUpload...) MessageChannel.sendFiles(...)}) * you can reference said image using the specified filename as URI {@code attachment://filename.ext}. * *

Example @@ -670,7 +670,7 @@ public EmbedBuilder setFooter(@Nullable String text) * InputStream file = new URL("https://http.cat/500").openStream(); * embed.setFooter("Cool footer!", "attachment://cat.png") // we specify this in sendFile as "cat.png" * .setDescription("This is a cute cat :3"); - * channel.sendFile(file, "cat.png").setEmbeds(embed.build()).queue(); + * channel.sendFiles(FileUpload.fromData(file, "cat.png")).setEmbeds(embed.build()).queue(); * * * @param text diff --git a/src/main/java/net/dv8tion/jda/api/JDAInfo.java b/src/main/java/net/dv8tion/jda/api/JDAInfo.java index a4504b2509..dca0d2d4ba 100644 --- a/src/main/java/net/dv8tion/jda/api/JDAInfo.java +++ b/src/main/java/net/dv8tion/jda/api/JDAInfo.java @@ -20,7 +20,7 @@ */ public class JDAInfo { - public static final int DISCORD_GATEWAY_VERSION = 10; + public static final int DISCORD_GATEWAY_VERSION = 9; public static final int DISCORD_REST_VERSION = 10; public static final int AUDIO_GATEWAY_VERSION = 4; public static final String GITHUB = "https://github.com/DV8FromTheWorld/JDA"; diff --git a/src/main/java/net/dv8tion/jda/api/MessageBuilder.java b/src/main/java/net/dv8tion/jda/api/MessageBuilder.java deleted file mode 100644 index ac2d79d653..0000000000 --- a/src/main/java/net/dv8tion/jda/api/MessageBuilder.java +++ /dev/null @@ -1,1281 +0,0 @@ -/* - * Copyright 2015 Austin Keener, Michael Ritter, Florian Spieß, and the JDA contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package net.dv8tion.jda.api; - -import net.dv8tion.jda.api.entities.*; -import net.dv8tion.jda.api.entities.sticker.Sticker; -import net.dv8tion.jda.api.entities.sticker.StickerSnowflake; -import net.dv8tion.jda.api.interactions.components.ActionRow; -import net.dv8tion.jda.api.interactions.components.LayoutComponent; -import net.dv8tion.jda.api.requests.restaction.MessageAction; -import net.dv8tion.jda.internal.entities.DataMessage; -import net.dv8tion.jda.internal.utils.Checks; -import net.dv8tion.jda.internal.utils.Helpers; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import java.util.*; -import java.util.stream.Collectors; - -/** - * Builder system used to build {@link net.dv8tion.jda.api.entities.Message Messages}. - *
Internally the builder uses a {@link java.lang.StringBuilder} to take advantage of the efficiencies offered by the - * StringBuilder, and the methods provided by this class are a combination of those offered by the StringBuilder and - * {@link String#format(String, Object...)}. - * - * @since 1.0 - * @author Michael Ritter - * @author Aljoscha Grebe - */ -public class MessageBuilder implements Appendable -{ - protected final StringBuilder builder = new StringBuilder(); - - protected final List embeds = new ArrayList<>(); - protected final List components = new ArrayList<>(); - protected final List stickers = new ArrayList<>(); - protected boolean isTTS = false; - protected String nonce; - protected EnumSet allowedMentions = null; - protected Set mentionedUsers = new HashSet<>(); - protected Set mentionedRoles = new HashSet<>(); - - public MessageBuilder() {} - - public MessageBuilder(@Nullable CharSequence content) - { - if (content != null) - builder.append(content); - } - - public MessageBuilder(@Nullable Message message) - { - if (message != null) - { - isTTS = message.isTTS(); - builder.append(message.getContentRaw()); - List embeds = message.getEmbeds(); - if (embeds != null) - embeds.stream().filter(it -> it.getType() == EmbedType.RICH).forEach(this.embeds::add); - components.addAll(message.getActionRows()); - if (message instanceof DataMessage) - { - DataMessage data = (DataMessage) message; - if (data.getAllowedMentions() != null) - this.allowedMentions = Helpers.copyEnumSet(Message.MentionType.class, data.getAllowedMentions()); - Collections.addAll(this.mentionedUsers, data.getMentionedUsersWhitelist()); - Collections.addAll(this.mentionedRoles, data.getMentionedRolesWhitelist()); - stickers.addAll(data.getStickerSnowflakes()); - } - else - { - stickers.addAll(message.getStickers().stream() - .map(Sticker::getId) - .map(Sticker::fromId) - .collect(Collectors.toList())); - } - } - } - - public MessageBuilder(@Nullable MessageBuilder builder) - { - if (builder != null) - { - this.isTTS = builder.isTTS; - this.builder.append(builder.builder); - this.nonce = builder.nonce; - this.embeds.addAll(builder.embeds); - this.components.addAll(builder.components); - this.stickers.addAll(builder.stickers); - if (builder.allowedMentions != null) - this.allowedMentions = Helpers.copyEnumSet(Message.MentionType.class, builder.allowedMentions); - this.mentionedRoles.addAll(builder.mentionedRoles); - this.mentionedUsers.addAll(builder.mentionedUsers); - } - } - - public MessageBuilder(@Nullable EmbedBuilder builder) - { - if (builder != null) - this.embeds.add(builder.build()); - } - - public MessageBuilder(@Nullable MessageEmbed embed) - { - if (embed != null) - this.embeds.add(embed); - } - - /** - * Makes the created Message a TTS message. - *
TTS stands for Text-To-Speech. When a TTS method is received by the Discord client, - * it is vocalized so long as the user has not disabled TTS. - * - * @param tts - * whether the created Message should be a tts message - * - * @return The MessageBuilder instance. Useful for chaining. - */ - @Nonnull - public MessageBuilder setTTS(boolean tts) - { - this.isTTS = tts; - return this; - } - - /** - * Adds up to {@value Message#MAX_EMBED_COUNT} {@link net.dv8tion.jda.api.entities.MessageEmbed MessageEmbeds} to the Message. Embeds can be built using - * the {@link net.dv8tion.jda.api.EmbedBuilder} and offer specialized formatting. - * - * @param embeds - * the embeds to add, or empty array to remove - * - * @throws java.lang.IllegalArgumentException - * If any of the provided MessageEmbeds is null or not sendable according to {@link net.dv8tion.jda.api.entities.MessageEmbed#isSendable() MessageEmbed.isSendable()}! - * The sum of all {@link MessageEmbed#getLength()} must not be greater than {@link MessageEmbed#EMBED_MAX_LENGTH_BOT}! - * - * @return The MessageBuilder instance. Useful for chaining. - */ - @Nonnull - public MessageBuilder setEmbeds(@Nonnull MessageEmbed... embeds) - { - Checks.noneNull(embeds, "MessageEmbeds"); - return setEmbeds(Arrays.asList(embeds)); - } - - /** - * Adds up to {@value Message#MAX_EMBED_COUNT} {@link net.dv8tion.jda.api.entities.MessageEmbed MessageEmbeds} to the Message. Embeds can be built using - * the {@link net.dv8tion.jda.api.EmbedBuilder} and offer specialized formatting. - * - * @param embeds - * the embeds to add, or empty list to remove - * - * @throws java.lang.IllegalArgumentException - * If any of the provided MessageEmbeds is null or not sendable according to {@link net.dv8tion.jda.api.entities.MessageEmbed#isSendable() MessageEmbed.isSendable()}! - * The sum of all {@link MessageEmbed#getLength()} must not be greater than {@link MessageEmbed#EMBED_MAX_LENGTH_BOT}! - * - * @return The MessageBuilder instance. Useful for chaining. - */ - @Nonnull - public MessageBuilder setEmbeds(@Nonnull Collection embeds) - { - - Checks.noneNull(embeds, "MessageEmbeds"); - embeds.forEach(embed -> - Checks.check(embed.isSendable(), - "Provided Message contains an empty embed or an embed with a length greater than %d characters, which is the max for bot accounts!", - MessageEmbed.EMBED_MAX_LENGTH_BOT) - ); - Checks.check(embeds.size() <= Message.MAX_EMBED_COUNT, "Cannot have more than %d embeds in a message!", Message.MAX_EMBED_COUNT); - Checks.check(embeds.stream().mapToInt(MessageEmbed::getLength).sum() <= MessageEmbed.EMBED_MAX_LENGTH_BOT, "The sum of all MessageEmbeds may not exceed %d!", MessageEmbed.EMBED_MAX_LENGTH_BOT); - this.embeds.clear(); - this.embeds.addAll(embeds); - return this; - } - - /** - * Set the action rows for the message. - * - * @param rows - * The new action rows, or null to reset the components - * - * @throws IllegalArgumentException - * If null is provided in the collection or more than 5 actions rows are provided - * - * @return The MessageBuilder instance. Useful for chaining. - */ - @Nonnull - public MessageBuilder setActionRows(@Nullable Collection rows) - { - if (rows == null) - { - this.components.clear(); - return this; - } - Checks.noneNull(rows, "ActionRows"); - Checks.check(rows.size() <= 5, "Can only have 5 action rows per message!"); - this.components.clear(); - this.components.addAll(rows); - return this; - } - - /** - * Set the action rows for the message. - * - * @param rows - * The new action rows, or null to reset the components - * - * @throws IllegalArgumentException - * If null is provided in the array or more than 5 actions rows are provided - * - * @return The MessageBuilder instance. Useful for chaining. - */ - @Nonnull - public MessageBuilder setActionRows(@Nullable ActionRow... rows) - { - if (rows == null) - { - this.components.clear(); - return this; - } - return setActionRows(Arrays.asList(rows)); - } - - /** - * Set the stickers to send alongside this message. - *
This is not supported for message edits. - * - * @param stickers - * The stickers to send, or null to not send any stickers - * - * @throws IllegalArgumentException - * If more than {@value Message#MAX_STICKER_COUNT} stickers or null stickers are provided - * - * @return The MessageBuilder instance. Useful for chaining. - * - * @see Sticker#fromId(long) - */ - @Nonnull - public MessageBuilder setStickers(@Nullable Collection stickers) - { - this.stickers.clear(); - if (stickers == null || stickers.isEmpty()) - return this; - Checks.noneNull(stickers, "Stickers"); - Checks.check(stickers.size() <= Message.MAX_STICKER_COUNT, - "Cannot send more than %d stickers in a message!", Message.MAX_STICKER_COUNT); - - stickers.stream() - .map(StickerSnowflake::getId) - .map(StickerSnowflake::fromId) - .forEach(this.stickers::add); - return this; - } - - /** - * Set the stickers to send alongside this message. - *
This is not supported for message edits. - * - * @param stickers - * The stickers to send, or null to not send any stickers - * - * @throws IllegalArgumentException - * If more than {@value Message#MAX_STICKER_COUNT} stickers or null stickers are provided - * - * @return The MessageBuilder instance. Useful for chaining. - * - * @see Sticker#fromId(long) - */ - @Nonnull - public MessageBuilder setStickers(@Nullable StickerSnowflake... stickers) - { - if (stickers != null) - Checks.noneNull(stickers, "Stickers"); - return setStickers(stickers == null ? null : Arrays.asList(stickers)); - } - - /** - * Sets the nonce - * of the built message(s). It is recommended to have only 100% unique strings to validate messages via this nonce. - *
The nonce will be available from the resulting message via {@link net.dv8tion.jda.api.entities.Message#getNonce() Message.getNonce()} - * in message received by events and RestAction responses. - *
When {@code null} is provided no nonce will be used. - * - * @param nonce - * Validation nonce string - * - * @return The MessageBuilder instance. Useful for chaining. - * - * @see net.dv8tion.jda.api.entities.Message#getNonce() - * @see Cryptographic Nonce - Wikipedia - */ - @Nonnull - public MessageBuilder setNonce(@Nullable String nonce) - { - this.nonce = nonce; - return this; - } - - /** - * Sets the content of the resulting Message - *
This will replace already added content. - * - * @param content - * The content to use, or {@code null} to reset the content - * - * @return The MessageBuilder instance. Useful for chaining. - * - * @see net.dv8tion.jda.api.entities.Message#getContentRaw() - */ - @Nonnull - public MessageBuilder setContent(@Nullable String content) - { - if (content == null) - { - builder.setLength(0); - } - else - { - final int newLength = Math.max(builder.length(), content.length()); - builder.replace(0, newLength, content); - } - return this; - } - - @Nonnull - @Override - public MessageBuilder append(@Nullable CharSequence text) - { - builder.append(text); - return this; - } - - @Nonnull - @Override - public MessageBuilder append(@Nullable CharSequence text, int start, int end) - { - builder.append(text, start, end); - return this; - } - - @Nonnull - @Override - public MessageBuilder append(char c) - { - builder.append(c); - return this; - } - - /** - * Appends the string representation of an object to the Message. - *
This is the same as {@link #append(CharSequence) append(String.valueOf(object))} - * - * @param object - * the object to append - * - * @return The MessageBuilder instance. Useful for chaining. - */ - @Nonnull - public MessageBuilder append(@Nullable Object object) - { - return append(String.valueOf(object)); - } - - /** - * Appends a mention to the Message. - *
Typical usage would be providing an {@link net.dv8tion.jda.api.entities.IMentionable IMentionable} like - * {@link net.dv8tion.jda.api.entities.User User} or {@link net.dv8tion.jda.api.entities.TextChannel TextChannel}. - * - *

This will not add a rule to mention a {@link User} or {@link Role}. You have to use {@link #mention(IMentionable...)} - * in addition to this method. - * - * @param mention - * the mention to append - * - * @throws java.lang.IllegalArgumentException - * If provided with null - * - * @return The MessageBuilder instance. Useful for chaining. - */ - @Nonnull - public MessageBuilder append(@Nonnull IMentionable mention) - { - Checks.notNull(mention, "Mentionable"); - builder.append(mention.getAsMention()); - return this; - } - - /** - * Appends a String using the specified chat {@link net.dv8tion.jda.api.MessageBuilder.Formatting Formatting(s)}. - * - * @param text - * the text to append. - * @param format - * the format(s) to apply to the text. - * - * @return The MessageBuilder instance. Useful for chaining. - */ - @Nonnull - public MessageBuilder append(@Nullable CharSequence text, @Nonnull Formatting... format) - { - boolean blockPresent = false; - for (Formatting formatting : format) - { - if (formatting == Formatting.BLOCK) - { - blockPresent = true; - continue; - } - builder.append(formatting.getTag()); - } - if (blockPresent) - builder.append(Formatting.BLOCK.getTag()); - - builder.append(text); - - if (blockPresent) - builder.append(Formatting.BLOCK.getTag()); - for (int i = format.length - 1; i >= 0; i--) - { - if (format[i] == Formatting.BLOCK) continue; - builder.append(format[i].getTag()); - } - return this; - } - - /** - * This method is an extended form of {@link String#format(String, Object...)}. It allows for all of - * the token replacement functionality that String.format(String, Object...) supports. - *
A lot of JDA entities implement {@link java.util.Formattable Formattable} and will provide - * specific format outputs for their specific type. - *

- * - *

Example: - *
If you placed the following code in an method handling a - * {@link net.dv8tion.jda.api.events.message.MessageReceivedEvent MessageReceivedEvent} - *

{@code
-     * User user = event.getAuthor();
-     * MessageBuilder builder = new MessageBuilder();
-     * builder.appendFormat("%#s is really cool!", user);
-     * builder.build();
-     * }
- * - * It would build a message that mentions the author and says that he is really cool!. If the user's - * name was "Minn" and his discriminator "6688", it would say: - *
  "Minn#6688 is really cool!"
- *
Note that this uses the {@code #} flag to utilize the alternative format for {@link net.dv8tion.jda.api.entities.User User}. - *
By default it would fallback to {@link net.dv8tion.jda.api.entities.IMentionable#getAsMention()} - * - * @param format - * a format string. - * @param args - * an array objects that will be used to replace the tokens, they must be - * provided in the order that the tokens appear in the provided format string. - * - * @throws java.lang.IllegalArgumentException - * If the provided format string is {@code null} or empty - * @throws java.util.IllegalFormatException - * If a format string contains an illegal syntax, - * a format specifier that is incompatible with the given arguments, - * insufficient arguments given the format string, or other illegal conditions. - * For specification of all possible formatting errors, - * see the Details - * section of the formatter class specification. - * - * @return The MessageBuilder instance. Useful for chaining. - */ - @Nonnull - public MessageBuilder appendFormat(@Nonnull String format, @Nonnull Object... args) - { - Checks.notEmpty(format, "Format String"); - this.append(String.format(format, args)); - return this; - } - - /** - * Appends a code-line to the Message. - * Code Lines are similar to code-blocks, however they are displayed in-line and do not support language specific highlighting. - * - * @param text - * the code to append - * - * @return The MessageBuilder instance. Useful for chaining. - */ - @Nonnull - public MessageBuilder appendCodeLine(@Nullable CharSequence text) - { - this.append(text, Formatting.BLOCK); - return this; - } - - /** - * Appends a code-block to the Message. - *
Discord uses Highlight.js for its language highlighting support. You can find out what - * specific languages are supported here. - * - * @param text - * the code to append - * @param language - * the language of the code. If unknown use an empty string - * - * @return The MessageBuilder instance. Useful for chaining. - */ - @Nonnull - public MessageBuilder appendCodeBlock(@Nullable CharSequence text, @Nullable CharSequence language) - { - builder.append("```").append(language).append('\n').append(text).append("\n```"); - return this; - } - - /** - * Returns the current length of the content that will be built into a {@link net.dv8tion.jda.api.entities.Message Message} - * when {@link #build()} is called. - *
If this value is {@code 0} (and there is no embed) or greater than {@code 2000} when {@link #build()} is called, an exception - * will be raised as you cannot send an empty message to Discord and Discord has a hard limit of 2000 characters per message. - * - *

Hint: You can use {@link #build(int, int)} or - * {@link #buildAll(net.dv8tion.jda.api.MessageBuilder.SplitPolicy...) buildAll(SplitPolicy...)} as possible ways to - * deal with the 2000 character cap. - * - * @return the current length of the content that will be built into a Message. - */ - public int length() - { - return builder.length(); - } - - /** - * Checks if the message contains any contend. This includes text as well as embeds. - * - * @return whether the message contains content - */ - public boolean isEmpty() { - return builder.length() == 0 && embeds.isEmpty(); - } - - /** - * Replaces each substring that matches the target string with the specified replacement string. - * The replacement proceeds from the beginning of the string to the end, for example, replacing - * "aa" with "b" in the message "aaa" will result in "ba" rather than "ab". - * - * @param target - * the sequence of char values to be replaced - * @param replacement - * the replacement sequence of char values - * - * @return The MessageBuilder instance. Useful for chaining. - */ - @Nonnull - public MessageBuilder replace(@Nonnull String target, @Nonnull String replacement) - { - int index = builder.indexOf(target); - while (index != -1) - { - builder.replace(index, index + target.length(), replacement); - index = builder.indexOf(target, index + replacement.length()); - } - return this; - } - - /** - * Replaces the first substring that matches the target string with the specified replacement string. - * - * @param target - * the sequence of char values to be replaced - * @param replacement - * the replacement sequence of char values - * - * @return The MessageBuilder instance. Useful for chaining. - */ - @Nonnull - public MessageBuilder replaceFirst(@Nonnull String target, @Nonnull String replacement) - { - int index = builder.indexOf(target); - if (index != -1) - { - builder.replace(index, index + target.length(), replacement); - } - return this; - } - - /** - * Replaces the last substring that matches the target string with the specified replacement string. - * - * @param target - * the sequence of char values to be replaced - * @param replacement - * the replacement sequence of char values - * - * @return The MessageBuilder instance. Useful for chaining. - */ - @Nonnull - public MessageBuilder replaceLast(@Nonnull String target, @Nonnull String replacement) - { - int index = builder.lastIndexOf(target); - if (index != -1) - { - builder.replace(index, index + target.length(), replacement); - } - return this; - } - - /** - * Removes the whitelist of mentioned users. - *
If {@link #setAllowedMentions(Collection)} does not contain {@link net.dv8tion.jda.api.entities.Message.MentionType#USER MentionType.USER} - * then no user will be mentioned. - * - * @return The MessageBuilder instance. Useful for chaining. - */ - @Nonnull - public MessageBuilder clearMentionedUsers() - { - mentionedUsers.clear(); - return this; - } - - /** - * Removes the whitelist of mentioned roles. - *
If {@link #setAllowedMentions(Collection)} does not contain {@link net.dv8tion.jda.api.entities.Message.MentionType#ROLE MentionType.ROLE} - * then no role will be mentioned. - * - * @return The MessageBuilder instance. Useful for chaining. - */ - @Nonnull - public MessageBuilder clearMentionedRoles() - { - mentionedRoles.clear(); - return this; - } - - /** - * Combination of {@link #clearMentionedRoles()} and {@link #clearMentionedUsers()}. - * - *

This will not affect {@link #setAllowedMentions(Collection)}. You can reset those to default - * by using {@code setAllowedMentions(null)}. - * - * @return The MessageBuilder instance. Useful for chaining. - */ - @Nonnull - public MessageBuilder clearMentions() - { - return clearMentionedUsers().clearMentionedRoles(); - } - - /** - * Sets which {@link net.dv8tion.jda.api.entities.Message.MentionType MentionTypes} should be parsed from - * the input. This will use {@link MessageAction#getDefaultMentions()} by default, or if {@code null} is provided. - * - * @param mentionTypes - * Collection of allowed mention types, or null to use {@link MessageAction#getDefaultMentions()}. - * - * @return The MessageBuilder instance. Useful for chaining. - */ - @Nonnull - public MessageBuilder setAllowedMentions(@Nullable Collection mentionTypes) - { - this.allowedMentions = mentionTypes == null - ? MessageAction.getDefaultMentions() - : Helpers.copyEnumSet(Message.MentionType.class, mentionTypes); - return this; - } - - /** - * Adds the provided {@link net.dv8tion.jda.api.entities.Message.MentionType MentionTypes} to the whitelist. - * - * @param types - * The mention types to allow - * - * @throws IllegalArgumentException - * If null is provided - * - * @return The MessageBuilder instance. Useful for chaining. - */ - @Nonnull - public MessageBuilder allowMentions(@Nonnull Message.MentionType... types) - { - Checks.noneNull(types, "MentionTypes"); - if (types.length > 0) - { - if (allowedMentions == null) - allowedMentions = MessageAction.getDefaultMentions(); - Collections.addAll(allowedMentions, types); - } - return this; - } - - /** - * Removes the provided {@link net.dv8tion.jda.api.entities.Message.MentionType MentionTypes} from the whitelist. - * - * @param types - * The mention types to deny - * - * @throws IllegalArgumentException - * If null is provided - * - * @return The MessageBuilder instance. Useful for chaining. - */ - @Nonnull - public MessageBuilder denyMentions(@Nonnull Message.MentionType... types) - { - Checks.noneNull(types, "MentionTypes"); - if (types.length > 0) - { - if (allowedMentions == null) - allowedMentions = MessageAction.getDefaultMentions(); - for (Message.MentionType type : types) - allowedMentions.remove(type); - } - return this; - } - - /** - * Adds the provided {@link IMentionable IMentionable} instance to the whitelist of mentions. - *
This will only affect instances of {@link User}, {@link Member}, and {@link Role}. - *
The content will not be affected by this. To append a mention use {@link #append(IMentionable)}. - * - *

See {@link MessageAction#mention(IMentionable...)} for more details. - * - * @param mentions - * Whitelist of mentions to apply - * - * @throws IllegalArgumentException - * If null is provided - * - * @return The MessageBuilder instance. Useful for chaining. - * - * @see #clearMentions() - * @see MessageAction#mention(IMentionable...) - */ - @Nonnull - public MessageBuilder mention(@Nonnull IMentionable... mentions) - { - Checks.noneNull(mentions, "Mentions"); - - for (IMentionable mention : mentions) - { - if (mention instanceof User || mention instanceof Member) - mentionedUsers.add(mention.getId()); - else if (mention instanceof Role) - mentionedRoles.add(mention.getId()); - } - return this; - } - - /** - * Adds the provided {@link IMentionable IMentionable} instance to the whitelist of mentions. - *
This will only affect instances of {@link User}, {@link Member}, and {@link Role}. - *
The content will not be affected by this. To append a mention use {@link #append(IMentionable)}. - * - *

See {@link MessageAction#mention(IMentionable...)} for more details. - * - * @param mentions - * Whitelist of mentions to apply - * - * @throws IllegalArgumentException - * If null is provided - * - * @return The MessageBuilder instance. Useful for chaining. - * - * @see #clearMentions() - * @see MessageAction#mention(IMentionable...) - */ - @Nonnull - public MessageBuilder mention(@Nonnull Collection mentions) - { - Checks.noneNull(mentions, "Mentions"); - return mention(mentions.toArray(new IMentionable[0])); - } - - /** - * Adds the provided {@link User Users} to the whitelist of mentions. - *
The provided list must only contain IDs of users. - *
The content will not be affected by this. - * To append a mention use {@code append("<@").append(id).append(">")}. - * - *

See {@link MessageAction#mentionUsers(String...)} for more details. - * - * @param users - * Whitelist of user IDs to apply - * - * @throws IllegalArgumentException - * If null is provided - * - * @return The MessageBuilder instance. Useful for chaining. - * - * @see #clearMentionedUsers() - * @see MessageAction#mentionUsers(String...) - */ - @Nonnull - public MessageBuilder mentionUsers(@Nonnull String... users) - { - Checks.noneNull(users, "Users"); - Collections.addAll(mentionedUsers, users); - return this; - } - - /** - * Adds the provided {@link Role Roles} to the whitelist of mentions. - *
The provided list must only contain IDs of roles. - *
The content will not be affected by this. - * To append a mention use {@code append("<@&").append(id).append(">")}. - * - *

See {@link MessageAction#mentionRoles(String...)} for more details. - * - * @param roles - * Whitelist of role IDs to apply - * - * @throws IllegalArgumentException - * If null is provided - * - * @return The MessageBuilder instance. Useful for chaining. - * - * @see #clearMentionedRoles() - * @see MessageAction#mentionRoles(String...) - */ - @Nonnull - public MessageBuilder mentionRoles(@Nonnull String... roles) - { - Checks.noneNull(roles, "Roles"); - Collections.addAll(mentionedRoles, roles); - return this; - } - - /** - * Adds the provided {@link User Users} to the whitelist of mentions. - *
The provided list must only contain IDs of users. - *
The content will not be affected by this. - * To append a mention use {@code append("<@").append(id).append(">")}. - * - *

See {@link MessageAction#mentionUsers(long...)} for more details. - * - * @param users - * Whitelist of user IDs to apply - * - * @throws IllegalArgumentException - * If null is provided - * - * @return The MessageBuilder instance. Useful for chaining. - * - * @see #clearMentionedUsers() - * @see MessageAction#mentionUsers(long...) - */ - @Nonnull - public MessageBuilder mentionUsers(@Nonnull long... users) - { - Checks.notNull(users, "Users"); - return mentionUsers(toStringArray(users)); - } - - /** - * Adds the provided {@link Role Roles} to the whitelist of mentions. - *
The provided list must only contain IDs of roles. - *
The content will not be affected by this. - * To append a mention use {@code append("<@&").append(id).append(">")}. - * - *

See {@link MessageAction#mentionRoles(long...)} for more details. - * - * @param roles - * Whitelist of role IDs to apply - * - * @throws IllegalArgumentException - * If null is provided - * - * @return The MessageBuilder instance. Useful for chaining. - * - * @see #clearMentionedRoles() - * @see MessageAction#mentionRoles(long...) - */ - @Nonnull - public MessageBuilder mentionRoles(@Nonnull long... roles) - { - Checks.notNull(roles, "Roles"); - return mentionRoles(toStringArray(roles)); - } - - /** - * Returns the underlying {@link StringBuilder}. - * - * @return The {@link StringBuilder} used by this {@link MessageBuilder} - */ - @Nonnull - public StringBuilder getStringBuilder() - { - return this.builder; - } - - /** - * Clears the current builder. Useful for mass message creation. - * - *

This will not clear the allowed mentions. - * - * @return The MessageBuilder instance. Useful for chaining. - */ - @Nonnull - public MessageBuilder clear() { - this.builder.setLength(0); - this.embeds.clear(); - this.isTTS = false; - return this; - } - - /** - * Returns the index within this string of the first occurrence of the - * specified substring between the specified indices. - * - *

If no such value of {@code target} exists, then {@code -1} is returned. - * - * @param target - * the substring to search for. - * @param fromIndex - * the index from which to start the search. - * @param endIndex - * the index at which to end the search. - * - * @throws java.lang.IndexOutOfBoundsException - *

- * - * @return the index of the first occurrence of the specified substring between - * the specified indices or {@code -1} if there is no such occurrence. - */ - public int indexOf(@Nonnull CharSequence target, int fromIndex, int endIndex) - { - if (fromIndex < 0) - throw new IndexOutOfBoundsException("index out of range: " + fromIndex); - if (endIndex < 0) - throw new IndexOutOfBoundsException("index out of range: " + endIndex); - if (fromIndex > length()) - throw new IndexOutOfBoundsException("fromIndex > length()"); - if (fromIndex > endIndex) - throw new IndexOutOfBoundsException("fromIndex > endIndex"); - - if (endIndex >= builder.length()) - { - endIndex = builder.length() - 1; - } - - int targetCount = target.length(); - if (targetCount == 0) - { - return fromIndex; - } - - char strFirstChar = target.charAt(0); - int max = endIndex + targetCount - 1; - - lastCharSearch: - for (int i = fromIndex; i <= max; i++) - { - if (builder.charAt(i) == strFirstChar) - { - for (int j = 1; j < targetCount; j++) - { - if (builder.charAt(i + j) != target.charAt(j)) - { - continue lastCharSearch; - } - } - return i; - } - } - return -1; - } - - /** - * Returns the index within this string of the last occurrence of the - * specified substring between the specified indices. - * - * If no such value of {@code target} exists, then {@code -1} is returned. - * - * @param target - * the substring to search for. - * @param fromIndex - * the index from which to start the search. - * @param endIndex - * the index at which to end the search. - * - * @throws java.lang.IndexOutOfBoundsException - * - * - * @return the index of the last occurrence of the specified substring between - * the specified indices or {@code -1} if there is no such occurrence. - */ - public int lastIndexOf(@Nonnull CharSequence target, int fromIndex, int endIndex) - { - if (fromIndex < 0) - throw new IndexOutOfBoundsException("index out of range: " + fromIndex); - if (endIndex < 0) - throw new IndexOutOfBoundsException("index out of range: " + endIndex); - if (fromIndex > length()) - throw new IndexOutOfBoundsException("fromIndex > length()"); - if (fromIndex > endIndex) - throw new IndexOutOfBoundsException("fromIndex > endIndex"); - - if (endIndex >= builder.length()) - { - endIndex = builder.length() - 1; - } - - int targetCount = target.length(); - if (targetCount == 0) - { - return endIndex; - } - - int rightIndex = endIndex - targetCount; - - if (fromIndex > rightIndex) - { - fromIndex = rightIndex; - } - - int strLastIndex = targetCount - 1; - char strLastChar = target.charAt(strLastIndex); - - int min = fromIndex + targetCount - 1; - - lastCharSearch: - for (int i = endIndex; i >= min; i--) - { - if (builder.charAt(i) == strLastChar) - { - for (int j = strLastIndex - 1, k = 1; j >= 0; j--, k++) - { - if (builder.charAt(i - k) != target.charAt(j)) - { - continue lastCharSearch; - } - } - return i - target.length() + 1; - } - } - return -1; - } - - /** - * Creates a {@link net.dv8tion.jda.api.entities.Message Message} object from this MessageBuilder - * - *

Hint: You can use {@link #build(int, int)} or - * {@link #buildAll(net.dv8tion.jda.api.MessageBuilder.SplitPolicy...) buildAll(SplitPolicy...)} as possible ways to - * deal with the 2000 character cap. - * - * @throws java.lang.IllegalStateException - *

- * - * @return the created {@link net.dv8tion.jda.api.entities.Message Message} - */ - @Nonnull - public Message build() - { - String message = builder.toString(); - if (this.isEmpty()) - throw new IllegalStateException("Cannot build a Message with no content. (You never added any content to the message)"); - if (message.length() > Message.MAX_CONTENT_LENGTH) - throw new IllegalStateException("Cannot build a Message with more than " + Message.MAX_CONTENT_LENGTH + " characters. Please limit your input."); - - String[] ids = new String[0]; - return new DataMessage(isTTS, message, nonce, embeds, - allowedMentions, mentionedUsers.toArray(ids), mentionedRoles.toArray(ids), - components.toArray(new LayoutComponent[0]), - new ArrayList<>(stickers)); - } - - /** - * Creates a {@link java.util.Queue Queue} of {@link net.dv8tion.jda.api.entities.Message Message} objects from this MessageBuilder. - * - *

This method splits the content if it exceeds 2000 chars. The splitting behaviour can be customized using {@link SplitPolicy SplitPolicies}. - * The method will try the policies in the order they are passed to it. - *
If no SplitPolicy is provided each message will be split after exactly 2000 chars. - * - *

This is not Markdown safe. An easy workaround is to include Zero Width Spaces - * as predetermined breaking points to the message and only split on them. - * - * @param policy - * The {@link net.dv8tion.jda.api.MessageBuilder.SplitPolicy} defining how to split the text in the - * MessageBuilder into different, individual messages. - * - * @return the created {@link net.dv8tion.jda.api.entities.Message Messages} - */ - @Nonnull - public Queue buildAll(@Nullable SplitPolicy... policy) - { - if (this.isEmpty()) - throw new UnsupportedOperationException("Cannot build a Message with no content. (You never added any content to the message)"); - - LinkedList messages = new LinkedList<>(); - - if (builder.length() <= Message.MAX_CONTENT_LENGTH) - { - messages.add(this.build()); - return messages; - } - - if (policy == null || policy.length == 0) - policy = new SplitPolicy[]{ SplitPolicy.ANYWHERE }; - - int currentBeginIndex = 0; - - messageLoop: - while (currentBeginIndex < builder.length() - Message.MAX_CONTENT_LENGTH) - { - for (SplitPolicy splitPolicy : policy) - { - int currentEndIndex = splitPolicy.nextMessage(currentBeginIndex, this); - if (currentEndIndex != -1) - { - messages.add(build(currentBeginIndex, currentEndIndex)); - currentBeginIndex = currentEndIndex; - continue messageLoop; - } - } - throw new IllegalStateException("Failed to split the messages"); - } - - if (currentBeginIndex < builder.length()) - messages.add(build(currentBeginIndex, builder.length())); - - if (!this.embeds.isEmpty()) - ((DataMessage) messages.get(messages.size() - 1)).setEmbeds(embeds); - - return messages; - } - - @Nonnull - protected DataMessage build(int beginIndex, int endIndex) - { - String[] ids = new String[0]; - return new DataMessage(isTTS, builder.substring(beginIndex, endIndex), null, null, - allowedMentions, mentionedUsers.toArray(ids), mentionedRoles.toArray(ids), - components.toArray(new LayoutComponent[0]), - new ArrayList<>(stickers)); - } - - private String[] toStringArray(long[] users) - { - String[] ids = new String[users.length]; - for (int i = 0; i < ids.length; i++) - ids[i] = Long.toUnsignedString(users[i]); - return ids; - } - - /** - * Interface to allow custom implementation of Splitting rules for - * {@link #buildAll(net.dv8tion.jda.api.MessageBuilder.SplitPolicy...) MessageBuilder.buildAll(SplitPolicy...)}. - */ - public interface SplitPolicy - { - /** - * Splits on newline chars {@code `\n`}. - */ - SplitPolicy NEWLINE = new CharSequenceSplitPolicy("\n", true); - - /** - * Splits on space chars {@code `\u0020`}. - */ - SplitPolicy SPACE = new CharSequenceSplitPolicy(" ", true); - - /** - * Splits exactly after 2000 chars. - */ - SplitPolicy ANYWHERE = (i, b) -> Math.min(i + Message.MAX_CONTENT_LENGTH, b.length()); - - /** - * Creates a new {@link SplitPolicy} splitting on the specified chars. - * - * @param chars - * the chars to split on - * @param remove - * whether to remove the chars when splitting on them - * - * @return a new {@link SplitPolicy} - */ - @Nonnull - static SplitPolicy onChars(@Nonnull CharSequence chars, boolean remove) - { - return new CharSequenceSplitPolicy(chars, remove); - } - - /** - * Default {@link SplitPolicy} implementation. Splits on a specified {@link CharSequence}. - */ - class CharSequenceSplitPolicy implements SplitPolicy - { - private final boolean remove; - private final CharSequence chars; - - private CharSequenceSplitPolicy(@Nonnull final CharSequence chars, final boolean remove) - { - this.chars = chars; - this.remove = remove; - } - - @Override - public int nextMessage(final int currentBeginIndex, final MessageBuilder builder) - { - int currentEndIndex = builder.lastIndexOf(this.chars, currentBeginIndex, currentBeginIndex + 2000 - (this.remove ? this.chars.length() : 0)); - if (currentEndIndex < 0) - { - return -1; - } - else - { - return currentEndIndex + this.chars.length(); - } - } - } - - /** - * Calculates the endIndex for the next {@link net.dv8tion.jda.api.entities.Message Message}. - * - * @param currentBeginIndex - * the index the next {@link net.dv8tion.jda.api.entities.Message Message} should start from - * @param builder - * the {@link net.dv8tion.jda.api.MessageBuilder MessageBuilder} - * - * @return the end Index of the next {@link net.dv8tion.jda.api.entities.Message Message} - * - * @throws java.lang.IllegalStateException when splitting fails - * - */ - int nextMessage(int currentBeginIndex, MessageBuilder builder); - } - - /** - * Holds the available formatting used in {@link MessageBuilder#append(java.lang.CharSequence, net.dv8tion.jda.api.MessageBuilder.Formatting...)} - */ - public enum Formatting - { - ITALICS("*"), - BOLD("**"), - STRIKETHROUGH("~~"), - UNDERLINE("__"), - BLOCK("`"); - - private final String tag; - - Formatting(String tag) - { - this.tag = tag; - } - - @Nonnull - private String getTag() - { - return tag; - } - } -} diff --git a/src/main/java/net/dv8tion/jda/api/entities/GuildMessageChannel.java b/src/main/java/net/dv8tion/jda/api/entities/GuildMessageChannel.java index baccecaf76..43d7747512 100644 --- a/src/main/java/net/dv8tion/jda/api/entities/GuildMessageChannel.java +++ b/src/main/java/net/dv8tion/jda/api/entities/GuildMessageChannel.java @@ -8,7 +8,7 @@ import net.dv8tion.jda.api.exceptions.InsufficientPermissionException; import net.dv8tion.jda.api.exceptions.MissingAccessException; import net.dv8tion.jda.api.requests.RestAction; -import net.dv8tion.jda.api.requests.restaction.MessageAction; +import net.dv8tion.jda.api.requests.restaction.MessageCreateAction; import net.dv8tion.jda.internal.utils.Checks; import javax.annotation.CheckReturnValue; @@ -423,13 +423,13 @@ default RestAction clearReactionsById(long messageId, @Nonnull Emoji emoji *

  • If null is provided
  • * * - * @return {@link MessageAction} + * @return {@link MessageCreateAction} * * @see Sticker#fromId(long) */ @Nonnull @CheckReturnValue - MessageAction sendStickers(@Nonnull Collection stickers); + MessageCreateAction sendStickers(@Nonnull Collection stickers); /** * Send up to 3 stickers in this channel. @@ -454,13 +454,13 @@ default RestAction clearReactionsById(long messageId, @Nonnull Emoji emoji *
  • If null is provided
  • * * - * @return {@link MessageAction} + * @return {@link MessageCreateAction} * * @see Sticker#fromId(long) */ @Nonnull @CheckReturnValue - default MessageAction sendStickers(@Nonnull StickerSnowflake... stickers) + default MessageCreateAction sendStickers(@Nonnull StickerSnowflake... stickers) { Checks.notEmpty(stickers, "Stickers"); return sendStickers(Arrays.asList(stickers)); diff --git a/src/main/java/net/dv8tion/jda/api/entities/Message.java b/src/main/java/net/dv8tion/jda/api/entities/Message.java index e477101bf9..6b9225173a 100644 --- a/src/main/java/net/dv8tion/jda/api/entities/Message.java +++ b/src/main/java/net/dv8tion/jda/api/entities/Message.java @@ -18,7 +18,6 @@ import net.dv8tion.jda.annotations.ForRemoval; import net.dv8tion.jda.annotations.ReplaceWith; import net.dv8tion.jda.api.JDA; -import net.dv8tion.jda.api.MessageBuilder; import net.dv8tion.jda.api.Permission; import net.dv8tion.jda.api.entities.channel.unions.GuildMessageChannelUnion; import net.dv8tion.jda.api.entities.channel.unions.MessageChannelUnion; @@ -36,20 +35,26 @@ import net.dv8tion.jda.api.interactions.components.ActionRow; import net.dv8tion.jda.api.interactions.components.LayoutComponent; import net.dv8tion.jda.api.interactions.components.buttons.Button; -import net.dv8tion.jda.api.interactions.components.selections.SelectMenu; import net.dv8tion.jda.api.requests.RestAction; import net.dv8tion.jda.api.requests.restaction.AuditableRestAction; -import net.dv8tion.jda.api.requests.restaction.MessageAction; +import net.dv8tion.jda.api.requests.restaction.MessageCreateAction; +import net.dv8tion.jda.api.requests.restaction.MessageEditAction; import net.dv8tion.jda.api.requests.restaction.ThreadChannelAction; import net.dv8tion.jda.api.requests.restaction.pagination.ReactionPaginationAction; -import net.dv8tion.jda.api.utils.AttachmentOption; +import net.dv8tion.jda.api.utils.AttachedFile; import net.dv8tion.jda.api.utils.AttachmentProxy; +import net.dv8tion.jda.api.utils.FileUpload; +import net.dv8tion.jda.api.utils.data.DataObject; +import net.dv8tion.jda.api.utils.messages.MessageCreateData; +import net.dv8tion.jda.api.utils.messages.MessageEditData; +import net.dv8tion.jda.api.utils.messages.MessageRequest; import net.dv8tion.jda.internal.JDAImpl; import net.dv8tion.jda.internal.entities.ReceivedMessage; import net.dv8tion.jda.internal.requests.FunctionalCallback; import net.dv8tion.jda.internal.requests.Requester; import net.dv8tion.jda.internal.utils.Checks; import net.dv8tion.jda.internal.utils.IOUtil; +import okhttp3.MultipartBody; import okhttp3.OkHttpClient; import okhttp3.Request; @@ -72,7 +77,7 @@ * as {@link net.dv8tion.jda.api.events.message.MessageUpdateEvent MessageUpdateEvent} and similar. * *

    Message Differences
    - * There are 3 implementations of this interface in JDA. + * There are 2 implementations of this interface in JDA. *

      *
    1. Received Message *
      Messages received through events or history query. @@ -82,10 +87,6 @@ *
      Specification of Received Messages that are generated by Discord * on certain events. Commonly this is used in groups or to indicate a pin within a MessageChannel. * The different types can be found in the {@link net.dv8tion.jda.api.entities.MessageType MessageType} enum.
    2. - *
    3. Data Message - *
      This type is produced by {@link MessageBuilder MessageBuilder} - * and only holds sendable information such as content or nonce. These messages do not allow - * any modifications via RestActions or information that is generated when sent such as the id to be used.
    4. *
    * *

    When a feature is not available it will throw an {@link java.lang.UnsupportedOperationException UnsupportedOperationException} @@ -116,9 +117,6 @@ * *

    More information on formatting syntax can be found in the {@link java.util.Formatter format syntax documentation}! * - * @see MessageBuilder MessageBuilder - * @see MessageChannel#sendMessage(Message) - * * @see MessageChannel#getIterableHistory() * @see MessageChannel#getHistory() * @see MessageChannel#getHistoryAfter(String, int) @@ -138,21 +136,21 @@ public interface Message extends ISnowflake, Formattable /** * The maximum sendable file size (8 MiB) * - * @see MessageAction#addFile(java.io.File, net.dv8tion.jda.api.utils.AttachmentOption...) MessageAction.addFile(...) + * @see MessageRequest#setFiles(Collection) */ int MAX_FILE_SIZE = 8 << 20; /** * The maximum sendable file size for nitro (50 MiB) * - * @see MessageAction#addFile(java.io.File, net.dv8tion.jda.api.utils.AttachmentOption...) MessageAction.addFile(...) + * @see MessageRequest#setFiles(Collection) */ int MAX_FILE_SIZE_NITRO = 50 << 20; /** * The maximum amount of files sendable within a single message ({@value}) * - * @see MessageAction#addFile(java.io.File, net.dv8tion.jda.api.utils.AttachmentOption...) MessageAction.addFile(...) + * @see MessageRequest#setFiles(Collection) */ int MAX_FILE_AMOUNT = 10; @@ -160,7 +158,7 @@ public interface Message extends ISnowflake, Formattable * The maximum amount of characters sendable in one message. ({@value}) *
    This only applies to the raw content and not embeds! * - * @see MessageAction#append(CharSequence) MessageAction.append(...) + * @see MessageRequest#setContent(String) */ int MAX_CONTENT_LENGTH = 2000; @@ -175,7 +173,7 @@ public interface Message extends ISnowflake, Formattable * The maximum amount of Embeds that can be added to one message ({@value}) * * @see MessageChannel#sendMessageEmbeds(Collection) - * @see MessageAction#setEmbeds(Collection) + * @see MessageRequest#setEmbeds(Collection) */ int MAX_EMBED_COUNT = 10; @@ -183,10 +181,20 @@ public interface Message extends ISnowflake, Formattable * The maximum amount of {@link Sticker Stickers} that can be added to a message ({@value}) * * @see GuildMessageChannel#sendStickers(StickerSnowflake...) - * @see MessageAction#setStickers(StickerSnowflake...) + * @see MessageCreateAction#setStickers(StickerSnowflake...) */ int MAX_STICKER_COUNT = 3; + /** + * The maximum amount of {@link LayoutComponent LayoutComponents} that can be added to a message ({@value}) + */ + int MAX_COMPONENT_COUNT = 5; + + /** + * The maximum character length for a {@link #getNonce() nonce} ({@value}) + */ + int MAX_NONCE_LENGTH = 25; + /** * Pattern used to find instant invites in strings. * @@ -299,9 +307,6 @@ default Message getReferencedMessage() * System.out.println("Message used these custom emojis: " + message.getMentions().getCustomEmojis()); * } * - * @throws UnsupportedOperationException - * If this is a Data Message (output of {@link MessageBuilder MessageBuilder}) - * * @return {@link Mentions} for this message. */ @Nonnull @@ -310,9 +315,6 @@ default Message getReferencedMessage() /** * Returns whether or not this Message has been edited before. * - * @throws UnsupportedOperationException - * If this is a Data Message (output of {@link MessageBuilder MessageBuilder}) - * * @return True if this message has been edited. */ boolean isEdited(); @@ -322,9 +324,6 @@ default Message getReferencedMessage() * edited. If this Message has not been edited ({@link #isEdited()} is {@code false}), then this method * will return {@code null}. * - * @throws UnsupportedOperationException - * If this is a Data Message (output of {@link MessageBuilder MessageBuilder}) - * * @return Time of the most recent edit, or {@code null} if the Message has never been edited. */ @Nullable @@ -333,9 +332,6 @@ default Message getReferencedMessage() /** * The author of this Message * - * @throws UnsupportedOperationException - * If this is a Data Message (output of {@link MessageBuilder MessageBuilder}) - * * @return Message author */ @Nonnull @@ -351,9 +347,6 @@ default Message getReferencedMessage() * This will return null if the message was retrieved through {@link MessageChannel#retrieveMessageById(long)} or similar means, * unless the member is already cached. * - * @throws UnsupportedOperationException - * If this is a Data Message (output of {@link MessageBuilder MessageBuilder}) - * * @return Message author, or {@code null} if the message was not sent in a GuildMessageChannel, or if the message was sent by a Webhook. * * @see #isWebhookMessage() @@ -365,9 +358,6 @@ default Message getReferencedMessage() * Returns the jump-to URL for the received message. Clicking this URL in the Discord client will cause the client to * jump to the specified message. * - * @throws java.lang.UnsupportedOperationException - * If this is a data message - * * @return A String representing the jump-to URL for the message */ @Nonnull @@ -389,9 +379,6 @@ default Message getReferencedMessage() * *

    Requires {@link net.dv8tion.jda.api.requests.GatewayIntent#MESSAGE_CONTENT GatewayIntent.MESSAGE_CONTENT} * - * @throws UnsupportedOperationException - * If this is a Data Message (output of {@link MessageBuilder MessageBuilder}) - * * @return The textual content of the message with mentions resolved to be visually like the Discord client. */ @Nonnull @@ -417,9 +404,6 @@ default Message getReferencedMessage() * *

    Requires {@link net.dv8tion.jda.api.requests.GatewayIntent#MESSAGE_CONTENT GatewayIntent.MESSAGE_CONTENT} * - * @throws UnsupportedOperationException - * If this is a Data Message (output of {@link MessageBuilder MessageBuilder}) - * * @return The textual content from {@link #getContentDisplay()} with all text formatting characters removed or escaped. */ @Nonnull @@ -435,9 +419,6 @@ default Message getReferencedMessage() *

    You can use the codes to retrieve/validate invites via * {@link net.dv8tion.jda.api.entities.Invite#resolve(JDA, String) Invite.resolve(JDA, String)} * - * @throws UnsupportedOperationException - * If this is a Data Message (output of {@link MessageBuilder MessageBuilder}) - * * @return Immutable list of invite codes */ @Nonnull @@ -446,13 +427,11 @@ default Message getReferencedMessage() /** * Validation nonce for this Message *
    This can be used to validate that a Message was properly sent to the Discord Service. - *
    To set a nonce before sending you may use {@link MessageBuilder#setNonce(String) MessageBuilder.setNonce(String)}! + *
    To set a nonce before sending you may use {@link MessageCreateAction#setNonce(String) MessageCreateAction.setNonce(String)}! * * @return The validation nonce * - * @since 3.4.0 - * - * @see MessageBuilder#setNonce(String) + * @see MessageCreateAction#setNonce(String) * @see Cryptographic Nonce - Wikipedia */ @Nullable @@ -461,17 +440,12 @@ default Message getReferencedMessage() /** * Used to determine if this Message was received from a {@link net.dv8tion.jda.api.entities.MessageChannel MessageChannel} * of the {@link net.dv8tion.jda.api.entities.ChannelType ChannelType} specified. - *
    This will always be false for {@link net.dv8tion.jda.api.entities.ChannelType#VOICE} as Messages can't be sent to - * {@link net.dv8tion.jda.api.entities.VoiceChannel VoiceChannels}. * *

    Useful for restricting functionality to a certain type of channels. * * @param type * The {@link net.dv8tion.jda.api.entities.ChannelType ChannelType} to check against. * - * @throws UnsupportedOperationException - * If this is a Data Message (output of {@link MessageBuilder MessageBuilder}) - * * @return True if the {@link net.dv8tion.jda.api.entities.ChannelType ChannelType} which this message was received * from is the same as the one specified by {@code type}. */ @@ -481,9 +455,6 @@ default Message getReferencedMessage() * Whether this message was sent in a {@link net.dv8tion.jda.api.entities.Guild Guild}. *
    If this is {@code false} then {@link #getGuild()} will throw an {@link java.lang.IllegalStateException}. * - * @throws UnsupportedOperationException - * If this is a Data Message (output of {@link MessageBuilder MessageBuilder}) - * * @return True, if {@link #getChannelType()}.{@link ChannelType#isGuild() isGuild()} is true. */ default boolean isFromGuild() @@ -493,11 +464,6 @@ default boolean isFromGuild() /** * Gets the {@link net.dv8tion.jda.api.entities.ChannelType ChannelType} that this message was received from. - *
    This will never be {@link net.dv8tion.jda.api.entities.ChannelType#VOICE} as Messages can't be sent to - * {@link net.dv8tion.jda.api.entities.VoiceChannel VoiceChannels}. - * - * @throws UnsupportedOperationException - * If this is a Data Message (output of {@link MessageBuilder MessageBuilder}) * * @return The ChannelType which this message was received from. */ @@ -509,9 +475,6 @@ default boolean isFromGuild() * {@link User User}. *
    Useful if you want to ignore non-users. * - * @throws UnsupportedOperationException - * If this is a Data Message (output of {@link MessageBuilder MessageBuilder}) - * * @return True if this message was sent by a {@link net.dv8tion.jda.api.entities.Webhook Webhook}. */ boolean isWebhookMessage(); @@ -519,9 +482,6 @@ default boolean isFromGuild() /** * Returns the {@link net.dv8tion.jda.api.entities.MessageChannel MessageChannel} that this message was sent in. * - * @throws UnsupportedOperationException - * If this is a Data Message (output of {@link MessageBuilder MessageBuilder}) - * * @return The MessageChannel of this Message */ @Nonnull @@ -531,8 +491,6 @@ default boolean isFromGuild() * Returns the {@link net.dv8tion.jda.api.entities.GuildMessageChannel GuildMessageChannel} that this message was sent in * if it was sent in a Guild. * - * @throws UnsupportedOperationException - * If this is a Data Message (output of {@link MessageBuilder MessageBuilder}) * @throws java.lang.IllegalStateException * If this was not sent in a {@link net.dv8tion.jda.api.entities.Guild}. * @@ -546,9 +504,6 @@ default boolean isFromGuild() * message was sent in. This will always be {@code null} for DMs. *
    Equivalent to {@code getGuildChannel().getParentCategory()} if this was sent in a {@link GuildMessageChannel}. * - * @throws UnsupportedOperationException - * If this is a Data Message (output of {@link MessageBuilder MessageBuilder}) - * * @return {@link net.dv8tion.jda.api.entities.Category Category} for this message */ @Nullable @@ -560,8 +515,6 @@ default boolean isFromGuild() *
    This is only valid if the Message was actually sent in a GuildMessageChannel. *
    You can check the type of channel this message was sent from using {@link #isFromType(ChannelType)} or {@link #getChannelType()}. * - * @throws UnsupportedOperationException - * If this is a Data Message (output of {@link MessageBuilder MessageBuilder}) * @throws java.lang.IllegalStateException * If this was not sent in a {@link net.dv8tion.jda.api.entities.GuildChannel}. * @@ -580,9 +533,6 @@ default boolean isFromGuild() * *

    Requires {@link net.dv8tion.jda.api.requests.GatewayIntent#MESSAGE_CONTENT GatewayIntent.MESSAGE_CONTENT} * - * @throws UnsupportedOperationException - * If this is a Data Message (output of {@link MessageBuilder MessageBuilder}) - * * @return Immutable list of {@link net.dv8tion.jda.api.entities.Message.Attachment Attachments}. */ @Nonnull @@ -598,9 +548,24 @@ default boolean isFromGuild() @Nonnull List getEmbeds(); + /** + * Layouts of interactive components, usually {@link ActionRow ActionRows}. + *
    You can use {@link MessageRequest#setComponents(LayoutComponent...)} to update these. + * + *

    Requires {@link net.dv8tion.jda.api.requests.GatewayIntent#MESSAGE_CONTENT GatewayIntent.MESSAGE_CONTENT} + * + * @return Immutable {@link List} of {@link LayoutComponent} + * + * @see #getActionRows() + * @see #getButtons() + * @see #getButtonById(String) + */ + @Nonnull + List getComponents(); + /** * Rows of interactive components such as {@link Button Buttons}. - *
    You can use {@link MessageAction#setActionRows(ActionRow...)} to update these. + *
    You can use {@link MessageRequest#setComponents(LayoutComponent...)} to update these. * *

    Requires {@link net.dv8tion.jda.api.requests.GatewayIntent#MESSAGE_CONTENT GatewayIntent.MESSAGE_CONTENT} * @@ -610,7 +575,14 @@ default boolean isFromGuild() * @see #getButtonById(String) */ @Nonnull - List getActionRows(); + default List getActionRows() + { + return getComponents() + .stream() + .filter(ActionRow.class::isInstance) + .map(ActionRow.class::cast) + .collect(Collectors.toList()); + } /** * All {@link Button Buttons} attached to this message. @@ -622,8 +594,8 @@ default boolean isFromGuild() @Nonnull default List