Skip to content

Commit

Permalink
Implement inline replies feature (#1408)
Browse files Browse the repository at this point in the history
* Message#reply and replyFormat
* MessageAction#reference and referenceById
* MessageAction#mentionRepliedUser and setDefaultMentionRepliedUser isDefaultMentionRepliedUser
* New MessageType INLINE_REPLY
* Improve handling of mentions in messages
  • Loading branch information
MinnDevelopment authored Nov 21, 2020
1 parent 4b52902 commit 2ccd6b9
Show file tree
Hide file tree
Showing 9 changed files with 371 additions and 23 deletions.
181 changes: 181 additions & 0 deletions src/main/java/net/dv8tion/jda/api/entities/Message.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import net.dv8tion.jda.api.requests.restaction.AuditableRestAction;
import net.dv8tion.jda.api.requests.restaction.MessageAction;
import net.dv8tion.jda.api.requests.restaction.pagination.ReactionPaginationAction;
import net.dv8tion.jda.api.utils.AttachmentOption;
import net.dv8tion.jda.internal.JDAImpl;
import net.dv8tion.jda.internal.requests.FunctionalCallback;
import net.dv8tion.jda.internal.requests.Requester;
Expand Down Expand Up @@ -199,6 +200,18 @@ public interface Message extends ISnowflake, Formattable
"(?:\\?\\S*)?(?:#\\S*)?", // Useless query or URN appendix
Pattern.CASE_INSENSITIVE);

/**
* Referenced message.
*
* <p>This will have different meaning depending on the {@link #getType() type} of message.
* Usually, this is a {@link MessageType#INLINE_REPLY INLINE_REPLY} reference.
* This can be null even if the type is {@link MessageType#INLINE_REPLY INLINE_REPLY}, when the message it references doesn't exist or discord wasn't able to resolve it in time.
*
* @return The referenced message, or null
*/
@Nullable
Message getReferencedMessage();

/**
* An immutable list of all mentioned {@link net.dv8tion.jda.api.entities.User Users}.
* <br>If no user was mentioned, this list is empty. Elements are sorted in order of appearance. This only
Expand Down Expand Up @@ -948,6 +961,174 @@ default boolean isFromGuild()
@CheckReturnValue
MessageAction editMessage(@Nonnull Message newContent);

/**
* Replies and references this message.
* <br>This is identical to {@code message.getChannel().sendMessage(content).reference(message)}.
* You can use {@link MessageAction#mentionRepliedUser(boolean) mentionRepliedUser(false)} to not mention the author of the message.
*
* <p>For further info, see {@link MessageChannel#sendMessage(CharSequence)} and {@link MessageAction#reference(Message)}.
*
* @param content
* The content of the reply message
*
* @return {@link MessageAction} Providing the {@link Message} created from this upload.
*/
@Nonnull
@CheckReturnValue
default MessageAction reply(@Nonnull CharSequence content)
{
return getChannel().sendMessage(content).reference(this);
}

/**
* Replies and references this message.
* <br>This is identical to {@code message.getChannel().sendMessage(content).reference(message)}.
* You can use {@link MessageAction#mentionRepliedUser(boolean) mentionRepliedUser(false)} to not mention the author of the message.
*
* <p>For further info, see {@link MessageChannel#sendMessage(MessageEmbed)} and {@link MessageAction#reference(Message)}.
*
* @param content
* The content of the reply message
*
* @return {@link MessageAction} Providing the {@link Message} created from this upload.
*/
@Nonnull
@CheckReturnValue
default MessageAction reply(@Nonnull MessageEmbed content)
{
return getChannel().sendMessage(content).reference(this);
}

/**
* Replies and references this message.
* <br>This is identical to {@code message.getChannel().sendMessage(content).reference(message)}.
* You can use {@link MessageAction#mentionRepliedUser(boolean) mentionRepliedUser(false)} to not mention the author of the message.
*
* <p>For further info, see {@link MessageChannel#sendMessage(Message)} and {@link MessageAction#reference(Message)}.
*
* @param content
* The content of the reply message
*
* @return {@link MessageAction} Providing the {@link Message} created from this upload.
*/
@Nonnull
@CheckReturnValue
default MessageAction reply(@Nonnull Message content)
{
return getChannel().sendMessage(content).reference(this);
}

/**
* Replies and references this message.
* <br>This is identical to {@code message.getChannel().sendMessageFormat(content, args).reference(message)}.
* You can use {@link MessageAction#mentionRepliedUser(boolean) mentionRepliedUser(false)} to not mention the author of the message.
*
* <p>For further info, see {@link MessageChannel#sendMessageFormat(String, Object...)} and {@link MessageAction#reference(Message)}.
*
* @param format
* The string that should be formatted, if this is null or empty the content of the Message would be empty and cause a builder exception.
* @param args
* The arguments for your format
*
* @return {@link MessageAction} Providing the {@link Message} created from this upload.
*/
@Nonnull
@CheckReturnValue
default MessageAction replyFormat(@Nonnull String format, @Nonnull Object... args)
{
return getChannel().sendMessageFormat(format, args).reference(this);
}

/**
* Replies and references this message.
* <br>This is identical to {@code message.getChannel().sendFile(file, options).reference(message)}.
* You can use {@link MessageAction#mentionRepliedUser(boolean) mentionRepliedUser(false)} to not mention the author of the message.
*
* <p>For further info, see {@link MessageChannel#sendFile(File, net.dv8tion.jda.api.utils.AttachmentOption...)} and {@link MessageAction#reference(Message)}.
*
* @param file
* The file to upload to the channel in the reply
* @param options
* Possible options to apply to this attachment, such as marking it as spoiler image
*
* @return {@link MessageAction} Providing the {@link Message} created from this upload.
*/
@Nonnull
@CheckReturnValue
default MessageAction reply(@Nonnull File file, @Nonnull AttachmentOption... options)
{
return getChannel().sendFile(file, options).reference(this);
}

/**
* Replies and references this message.
* <br>This is identical to {@code message.getChannel().sendFile(data, name, options).reference(message)}.
* You can use {@link MessageAction#mentionRepliedUser(boolean) mentionRepliedUser(false)} to not mention the author of the message.
*
* <p>For further info, see {@link MessageChannel#sendFile(File, String, net.dv8tion.jda.api.utils.AttachmentOption...)} and {@link MessageAction#reference(Message)}.
*
* @param data
* The data to upload to the channel in the reply
* @param name
* The name that should be sent to discord
* @param options
* Possible options to apply to this attachment, such as marking it as spoiler image
*
* @return {@link MessageAction} Providing the {@link Message} created from this upload.
*/
@Nonnull
@CheckReturnValue
default MessageAction reply(@Nonnull File data, @Nonnull String name, @Nonnull AttachmentOption... options)
{
return getChannel().sendFile(data, name, options).reference(this);
}

/**
* Replies and references this message.
* <br>This is identical to {@code message.getChannel().sendFile(data, name, options).reference(message)}.
* You can use {@link MessageAction#mentionRepliedUser(boolean) mentionRepliedUser(false)} to not mention the author of the message.
*
* <p>For further info, see {@link MessageChannel#sendFile(InputStream, String, net.dv8tion.jda.api.utils.AttachmentOption...)} and {@link MessageAction#reference(Message)}.
*
* @param data
* The data to upload to the channel in the reply
* @param name
* The name that should be sent to discord
* @param options
* Possible options to apply to this attachment, such as marking it as spoiler image
*
* @return {@link MessageAction} Providing the {@link Message} created from this upload.
*/
@Nonnull
@CheckReturnValue
default MessageAction reply(@Nonnull InputStream data, @Nonnull String name, @Nonnull AttachmentOption... options)
{
return getChannel().sendFile(data, name, options).reference(this);
}

/**
* Replies and references this message.
* <br>This is identical to {@code message.getChannel().sendFile(data, name, options).reference(message)}.
* You can use {@link MessageAction#mentionRepliedUser(boolean) mentionRepliedUser(false)} to not mention the author of the message.
*
* <p>For further info, see {@link MessageChannel#sendFile(byte[], String, net.dv8tion.jda.api.utils.AttachmentOption...)} and {@link MessageAction#reference(Message)}.
*
* @param data
* The data to upload to the channel in the reply
* @param name
* The name that should be sent to discord
* @param options
* Possible options to apply to this attachment, such as marking it as spoiler image
*
* @return {@link MessageAction} Providing the {@link Message} created from this upload.
*/
@Nonnull
@CheckReturnValue
default MessageAction reply(@Nonnull byte[] data, @Nonnull String name, @Nonnull AttachmentOption... options)
{
return getChannel().sendFile(data, name, options).reference(this);
}

/**
* Deletes this Message from Discord.
* <br>If this Message was not sent by the currently logged in account, then this will fail unless the Message is from
Expand Down
5 changes: 5 additions & 0 deletions src/main/java/net/dv8tion/jda/api/entities/MessageType.java
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,11 @@ public enum MessageType
*/
CHANNEL_FOLLOW_ADD(12),

/**
* Reply to another message. This usually comes with a {@link Message#getReferencedMessage() referenced message}.
*/
INLINE_REPLY(19),

/**
* Unknown MessageType.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,14 @@

package net.dv8tion.jda.api.requests.restaction;

import net.dv8tion.jda.api.MessageBuilder;
import net.dv8tion.jda.api.entities.IMentionable;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.MessageChannel;
import net.dv8tion.jda.api.entities.MessageEmbed;
import net.dv8tion.jda.api.requests.RestAction;
import net.dv8tion.jda.api.utils.AttachmentOption;
import net.dv8tion.jda.api.utils.MiscUtil;
import net.dv8tion.jda.internal.requests.restaction.MessageActionImpl;
import net.dv8tion.jda.internal.utils.Checks;

Expand Down Expand Up @@ -123,6 +125,33 @@ static EnumSet<Message.MentionType> getDefaultMentions()
return MessageActionImpl.getDefaultMentions();
}

/**
* Sets the default value for {@link #mentionRepliedUser(boolean)}
*
* <p>Default: <b>true</b>
*
* @param mention
* True, if replies should mention by default
*/
static void setDefaultMentionRepliedUser(boolean mention)
{
MessageActionImpl.setDefaultMentionRepliedUser(mention);
}

/**
* Returns the default mention behavior for replies.
* <br>If this is {@code true} then all replies will mention the author of the target message by default.
* You can specify this individually with {@link #mentionRepliedUser(boolean)} for each message.
*
* <p>Default: <b>true</b>
*
* @return True, if replies mention by default
*/
static boolean isDefaultMentionRepliedUser()
{
return MessageActionImpl.isDefaultMentionRepliedUser();
}

@Nonnull
@Override
MessageAction setCheck(@Nullable BooleanSupplier checks);
Expand Down Expand Up @@ -181,6 +210,85 @@ static EnumSet<Message.MentionType> getDefaultMentions()
@CheckReturnValue
MessageAction apply(@Nullable final Message message);

/**
* Make the message a reply to the referenced message.
* <br>You can only reply to messages from the same channel!
* <br>This will mention the author of the target message. You can disable this through {@link #mentionRepliedUser(boolean)}.
*
* <p>This requires {@link net.dv8tion.jda.api.Permission#MESSAGE_HISTORY Permission.MESSAGE_HISTORY} in the channel!
*
* @param messageId
* The target message
*
* @return Updated MessageAction for chaining convenience
*/
@Nonnull
@CheckReturnValue
MessageAction referenceById(long messageId);

/**
* Make the message a reply to the referenced message.
* <br>You can only reply to messages from the same channel!
* <br>This will mention the author of the target message. You can disable this through {@link #mentionRepliedUser(boolean)}.
*
* <p>This requires {@link net.dv8tion.jda.api.Permission#MESSAGE_HISTORY Permission.MESSAGE_HISTORY} in the channel!
* You cannot reply to system messages (such as {@link net.dv8tion.jda.api.entities.MessageType#CHANNEL_PINNED_ADD CHANNEL_PINNED_ADD} and similar).
*
* @param messageId
* The target message
*
* @throws IllegalArgumentException
* If the provided ID is null or not a valid snowflake
*
* @return Updated MessageAction for chaining convenience
*/
@Nonnull
@CheckReturnValue
default MessageAction referenceById(@Nonnull String messageId)
{
return referenceById(MiscUtil.parseSnowflake(messageId));
}

/**
* Make the message a reply to the referenced message.
* <br>You can only reply to messages from the same channel!
* <br>This will mention the author of the target message. You can disable this through {@link #mentionRepliedUser(boolean)}.
*
* <p>This requires {@link net.dv8tion.jda.api.Permission#MESSAGE_HISTORY Permission.MESSAGE_HISTORY} in the channel!
*
* @param message
* The target message
*
* @throws IllegalArgumentException
* If the provided message is null
* @throws UnsupportedOperationException
* If the provided message is from a {@link MessageBuilder}
*
* @return Updated MessageAction for chaining convenience
*/
@Nonnull
@CheckReturnValue
default MessageAction reference(@Nonnull Message message)
{
Checks.notNull(message, "Message");
return referenceById(message.getIdLong());
}

/**
* Whether to mention the used, when replying to a message.
* <br>This only matters in combination with {@link #reference(Message)} and {@link #referenceById(long)}!
*
* <p>This is true by default but can be configured using {@link #setDefaultMentionRepliedUser(boolean)}!
*
* @param mention
* True, to mention the author if the referenced message
*
* @return Updated MessageAction for chaining convenience
*/
@Nonnull
@CheckReturnValue
MessageAction mentionRepliedUser(boolean mention);

/**
* Enable/Disable Text-To-Speech for the resulting message.
* <br>This is only relevant to MessageActions that are not {@code isEdit() == true}!
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,12 @@ protected void appendFormat(Formatter formatter, int width, int precision, boole
}
}

@Override
public Message getReferencedMessage()
{
return null;
}

@Nonnull
@Override
public Bag<User> getMentionedUsersBag()
Expand Down
Loading

0 comments on commit 2ccd6b9

Please sign in to comment.