From 8ccfc564657f32553cef4abe464d334f14e4986f Mon Sep 17 00:00:00 2001 From: freya02 <41875020+freya022@users.noreply.github.com> Date: Sun, 3 Nov 2024 14:35:53 +0100 Subject: [PATCH] Add premium buttons (#2752) Deprecates replyWithPremiumRequired --- .../jda/api/entities/SkuSnowflake.java | 61 ++++++ .../GenericCommandInteractionEvent.java | 1 + ...enericComponentInteractionCreateEvent.java | 1 + .../jda/api/interactions/Interaction.java | 2 - .../IPremiumRequiredReplyCallback.java | 13 +- .../components/LayoutComponent.java | 6 +- .../components/buttons/Button.java | 180 ++++++++++-------- .../components/buttons/ButtonStyle.java | 2 + .../InteractionCallbackAction.java | 10 +- .../PremiumRequiredCallbackAction.java | 6 + .../internal/entities/SkuSnowflakeImpl.java | 58 ++++++ .../interactions/component/ButtonImpl.java | 65 ++++++- .../jda/internal/utils/ComponentsUtil.java | 43 +++++ .../jda/test/interactions/ButtonTests.java | 141 ++++++++++++++ .../jda/test/util/ComponentsUtilTest.java | 48 +++++ 15 files changed, 546 insertions(+), 91 deletions(-) create mode 100644 src/main/java/net/dv8tion/jda/api/entities/SkuSnowflake.java create mode 100644 src/main/java/net/dv8tion/jda/internal/entities/SkuSnowflakeImpl.java create mode 100644 src/main/java/net/dv8tion/jda/internal/utils/ComponentsUtil.java create mode 100644 src/test/java/net/dv8tion/jda/test/interactions/ButtonTests.java create mode 100644 src/test/java/net/dv8tion/jda/test/util/ComponentsUtilTest.java diff --git a/src/main/java/net/dv8tion/jda/api/entities/SkuSnowflake.java b/src/main/java/net/dv8tion/jda/api/entities/SkuSnowflake.java new file mode 100644 index 0000000000..6cbb6191f5 --- /dev/null +++ b/src/main/java/net/dv8tion/jda/api/entities/SkuSnowflake.java @@ -0,0 +1,61 @@ +/* + * 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.entities; + +import net.dv8tion.jda.api.utils.MiscUtil; +import net.dv8tion.jda.internal.entities.SkuSnowflakeImpl; + +import javax.annotation.Nonnull; + +/** + * Represents an abstract SKU reference by only the SKU ID. + * + *

This is used for methods which only need a SKU ID to function, you cannot use this for getting any properties. + */ +public interface SkuSnowflake extends ISnowflake +{ + /** + * Creates a SKU instance which only wraps an ID. + * + * @param id + * The SKU id + * + * @return A SKU snowflake instance + */ + @Nonnull + static SkuSnowflake fromId(long id) + { + return new SkuSnowflakeImpl(id); + } + + /** + * Creates a SKU instance which only wraps an ID. + * + * @param id + * The SKU id + * + * @throws IllegalArgumentException + * If the provided ID is not a valid snowflake + * + * @return A SKU snowflake instance + */ + @Nonnull + static SkuSnowflake fromId(@Nonnull String id) + { + return fromId(MiscUtil.parseSnowflake(id)); + } +} diff --git a/src/main/java/net/dv8tion/jda/api/events/interaction/command/GenericCommandInteractionEvent.java b/src/main/java/net/dv8tion/jda/api/events/interaction/command/GenericCommandInteractionEvent.java index b3bb9dc6d9..7a0c4ef531 100644 --- a/src/main/java/net/dv8tion/jda/api/events/interaction/command/GenericCommandInteractionEvent.java +++ b/src/main/java/net/dv8tion/jda/api/events/interaction/command/GenericCommandInteractionEvent.java @@ -125,6 +125,7 @@ public ModalCallbackAction replyModal(@Nonnull Modal modal) @Nonnull @Override + @Deprecated @CheckReturnValue public PremiumRequiredCallbackAction replyWithPremiumRequired() { diff --git a/src/main/java/net/dv8tion/jda/api/events/interaction/component/GenericComponentInteractionCreateEvent.java b/src/main/java/net/dv8tion/jda/api/events/interaction/component/GenericComponentInteractionCreateEvent.java index 7e766e76ef..a470852bea 100644 --- a/src/main/java/net/dv8tion/jda/api/events/interaction/component/GenericComponentInteractionCreateEvent.java +++ b/src/main/java/net/dv8tion/jda/api/events/interaction/component/GenericComponentInteractionCreateEvent.java @@ -132,6 +132,7 @@ public ModalCallbackAction replyModal(@Nonnull Modal modal) @Nonnull @Override + @Deprecated @CheckReturnValue public PremiumRequiredCallbackAction replyWithPremiumRequired() { diff --git a/src/main/java/net/dv8tion/jda/api/interactions/Interaction.java b/src/main/java/net/dv8tion/jda/api/interactions/Interaction.java index 32fbb0d545..9f2e154d5e 100644 --- a/src/main/java/net/dv8tion/jda/api/interactions/Interaction.java +++ b/src/main/java/net/dv8tion/jda/api/interactions/Interaction.java @@ -48,8 +48,6 @@ *
Which supports choice suggestions for auto-complete interactions via {@link IAutoCompleteCallback#replyChoices(Command.Choice...)} *

  • {@link IModalCallback} *
    Which supports replying using a {@link Modal} via {@link IModalCallback#replyModal(Modal)}
  • - *
  • {@link IPremiumRequiredReplyCallback} - *
    Which will reply stating that an {@link Entitlement Entitlement} is required
  • * * *

    Once the interaction is acknowledged, you can not reply with these methods again. If the interaction is a {@link IDeferrableCallback deferrable}, diff --git a/src/main/java/net/dv8tion/jda/api/interactions/callbacks/IPremiumRequiredReplyCallback.java b/src/main/java/net/dv8tion/jda/api/interactions/callbacks/IPremiumRequiredReplyCallback.java index a25b923c94..03339af158 100644 --- a/src/main/java/net/dv8tion/jda/api/interactions/callbacks/IPremiumRequiredReplyCallback.java +++ b/src/main/java/net/dv8tion/jda/api/interactions/callbacks/IPremiumRequiredReplyCallback.java @@ -16,8 +16,10 @@ package net.dv8tion.jda.api.interactions.callbacks; -import net.dv8tion.jda.api.requests.restaction.interactions.PremiumRequiredCallbackAction; import net.dv8tion.jda.api.entities.Entitlement; +import net.dv8tion.jda.api.entities.SkuSnowflake; +import net.dv8tion.jda.api.interactions.components.buttons.Button; +import net.dv8tion.jda.api.requests.restaction.interactions.PremiumRequiredCallbackAction; import javax.annotation.CheckReturnValue; import javax.annotation.Nonnull; @@ -28,10 +30,19 @@ *

    Replying with {@link #replyWithPremiumRequired()} will automatically acknowledge this interaction. * *

    Note:This interaction requires monetization to be enabled. + * + * @deprecated Replaced with {@link Button#premium(SkuSnowflake)}, + * see the Discord change logs for more details. */ +@Deprecated public interface IPremiumRequiredReplyCallback extends IDeferrableCallback { + /** + * @deprecated Replaced with {@link Button#premium(SkuSnowflake)}, + * see the Discord change logs for more details. + */ @Nonnull + @Deprecated @CheckReturnValue PremiumRequiredCallbackAction replyWithPremiumRequired(); } diff --git a/src/main/java/net/dv8tion/jda/api/interactions/components/LayoutComponent.java b/src/main/java/net/dv8tion/jda/api/interactions/components/LayoutComponent.java index 167c4868d6..15070e0271 100644 --- a/src/main/java/net/dv8tion/jda/api/interactions/components/LayoutComponent.java +++ b/src/main/java/net/dv8tion/jda/api/interactions/components/LayoutComponent.java @@ -20,6 +20,7 @@ import net.dv8tion.jda.api.interactions.components.buttons.ButtonStyle; import net.dv8tion.jda.api.utils.data.SerializableData; import net.dv8tion.jda.internal.utils.Checks; +import net.dv8tion.jda.internal.utils.ComponentsUtil; import net.dv8tion.jda.internal.utils.Helpers; import org.jetbrains.annotations.Unmodifiable; @@ -207,7 +208,8 @@ default boolean isValid() *
    This will locate and replace the existing component with the specified ID. If you provide null it will be removed instead. * * @param id - * The custom id of this component, can also be a URL for a {@link Button} with {@link ButtonStyle#LINK} + * The custom id of this component, can also be a URL for a {@link Button} with {@link ButtonStyle#LINK}, + * or an SKU id for {@link ButtonStyle#PREMIUM} * @param newComponent * The new component or null to remove it * @@ -227,7 +229,7 @@ default ItemComponent updateComponent(@Nonnull String id, @Nullable ItemComponen if (!(component instanceof ActionComponent)) continue; ActionComponent action = (ActionComponent) component; - if (id.equals(action.getId()) || (action instanceof Button && id.equals(((Button) action).getUrl()))) + if (ComponentsUtil.isSameIdentifier(action, id)) { if (newComponent == null) it.remove(); diff --git a/src/main/java/net/dv8tion/jda/api/interactions/components/buttons/Button.java b/src/main/java/net/dv8tion/jda/api/interactions/components/buttons/Button.java index a13b6807e2..deddd28f0c 100644 --- a/src/main/java/net/dv8tion/jda/api/interactions/components/buttons/Button.java +++ b/src/main/java/net/dv8tion/jda/api/interactions/components/buttons/Button.java @@ -16,6 +16,7 @@ package net.dv8tion.jda.api.interactions.components.buttons; +import net.dv8tion.jda.api.entities.SkuSnowflake; import net.dv8tion.jda.api.entities.emoji.Emoji; import net.dv8tion.jda.api.entities.emoji.EmojiUnion; import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent; @@ -91,7 +92,8 @@ public interface Button extends ActionComponent int URL_MAX_LENGTH = 512; /** - * The visible text on the button. + * The visible text on the button, + * or an empty string if this is a {@link ButtonStyle#PREMIUM PREMIUM}-style button. * * @return The button label */ @@ -114,6 +116,14 @@ public interface Button extends ActionComponent @Nullable String getUrl(); + /** + * The target SKU for this button, if it is a {@link ButtonStyle#PREMIUM PREMIUM}-style Button. + * + * @return The target SKU or {@code null} + */ + @Nullable + SkuSnowflake getSku(); + /** * The emoji attached to this button. *
    This can be either {@link Emoji.Type#UNICODE unicode} or {@link Emoji.Type#CUSTOM custom}. @@ -143,7 +153,7 @@ default Button asEnabled() @CheckReturnValue default Button withDisabled(boolean disabled) { - return new ButtonImpl(getId(), getLabel(), getStyle(), getUrl(), disabled, getEmoji()); + return new ButtonImpl(getId(), getLabel(), getStyle(), getUrl(), getSku(), disabled, getEmoji()).checkValid(); } /** @@ -152,13 +162,16 @@ default Button withDisabled(boolean disabled) * @param emoji * The emoji to use * + * @throws IllegalArgumentException + * If this is a {@link ButtonStyle#PREMIUM PREMIUM}-styled button + * * @return New button with emoji */ @Nonnull @CheckReturnValue default Button withEmoji(@Nullable Emoji emoji) { - return new ButtonImpl(getId(), getLabel(), getStyle(), getUrl(), isDisabled(), emoji); + return new ButtonImpl(getId(), getLabel(), getStyle(), getUrl(), null, isDisabled(), emoji).checkValid(); } /** @@ -169,6 +182,7 @@ default Button withEmoji(@Nullable Emoji emoji) * * @throws IllegalArgumentException *