diff --git a/BotCommands-core/src/main/kotlin/io/github/freya022/botcommands/api/parameters/resolvers/ModalParameterResolver.kt b/BotCommands-core/src/main/kotlin/io/github/freya022/botcommands/api/parameters/resolvers/ModalParameterResolver.kt index fabeb010f..24247ab09 100644 --- a/BotCommands-core/src/main/kotlin/io/github/freya022/botcommands/api/parameters/resolvers/ModalParameterResolver.kt +++ b/BotCommands-core/src/main/kotlin/io/github/freya022/botcommands/api/parameters/resolvers/ModalParameterResolver.kt @@ -6,6 +6,9 @@ import io.github.freya022.botcommands.api.modals.annotations.ModalInput import io.github.freya022.botcommands.api.modals.options.ModalOption import io.github.freya022.botcommands.api.parameters.ParameterResolver import net.dv8tion.jda.api.components.attachmentupload.AttachmentUpload +import net.dv8tion.jda.api.components.checkbox.Checkbox +import net.dv8tion.jda.api.components.checkboxgroup.CheckboxGroup +import net.dv8tion.jda.api.components.radiogroup.RadioGroup import net.dv8tion.jda.api.components.selections.EntitySelectMenu import net.dv8tion.jda.api.components.selections.StringSelectMenu import net.dv8tion.jda.api.components.textinput.TextInput @@ -21,11 +24,36 @@ import kotlin.reflect.KType * Needs to be implemented alongside a [ParameterResolver] subclass. * * ### Types supported by default - * - [TextInput] : `String` - * - [StringSelectMenu] : `List`, `String` - * - [EntitySelectMenu] : [Mentions], `T` and `List` where `T` is one of: + * **Note:** For `null` to be supported, the parameter must be explicitly nullable. + * + * #### [TextInput] + * - `String` (can be empty, supports `null` when empty) + * + * #### [StringSelectMenu] + * - `String` when a single value can be selected (supports `null` when none selected) + * - `List` (can be empty) + * + * #### [EntitySelectMenu] + * - [Mentions] + * - `T` (supports `null` when none selected) + * - `List` (can be empty) + * + * Where `T` is one of: * [IMentionable], [Role], [User], [InputUser], [Member], [GuildChannel] - * - [AttachmentUpload] : `List` of [Message.Attachment], [Message.Attachment] + * + * #### [AttachmentUpload] + * - `List` of [Message.Attachment] (can be empty) + * - [Message.Attachment] (supports `null` when none selected) + * + * #### [RadioGroup] + * - `String` (supports `null` when none selected) + * + * #### [CheckboxGroup] + * - `List` (can be empty) + * - `String` when a single value can be selected + * + * #### [Checkbox] + * - (primitive) `Boolean` * * @param T Type of the implementation * @param R Type of the returned resolved objects diff --git a/BotCommands-core/src/main/kotlin/io/github/freya022/botcommands/internal/modals/resolvers/ModalBooleanResolver.kt b/BotCommands-core/src/main/kotlin/io/github/freya022/botcommands/internal/modals/resolvers/ModalBooleanResolver.kt new file mode 100644 index 000000000..a0a189598 --- /dev/null +++ b/BotCommands-core/src/main/kotlin/io/github/freya022/botcommands/internal/modals/resolvers/ModalBooleanResolver.kt @@ -0,0 +1,20 @@ +package io.github.freya022.botcommands.internal.modals.resolvers + +import io.github.freya022.botcommands.api.core.service.annotations.Resolver +import io.github.freya022.botcommands.api.modals.ModalEvent +import io.github.freya022.botcommands.api.modals.options.ModalOption +import io.github.freya022.botcommands.api.parameters.ClassParameterResolver +import io.github.freya022.botcommands.api.parameters.resolvers.ModalParameterResolver +import net.dv8tion.jda.api.interactions.modals.ModalMapping + +@Resolver +internal object ModalBooleanResolver : + ClassParameterResolver(Boolean::class), + ModalParameterResolver { + + override suspend fun resolveSuspend( + option: ModalOption, + event: ModalEvent, + modalMapping: ModalMapping, + ): Boolean = modalMapping.asBoolean +} diff --git a/BotCommands-core/src/main/kotlin/io/github/freya022/botcommands/internal/modals/resolvers/ModalStringResolver.kt b/BotCommands-core/src/main/kotlin/io/github/freya022/botcommands/internal/modals/resolvers/ModalStringResolver.kt index 8a8db8241..ec8f4bbd5 100644 --- a/BotCommands-core/src/main/kotlin/io/github/freya022/botcommands/internal/modals/resolvers/ModalStringResolver.kt +++ b/BotCommands-core/src/main/kotlin/io/github/freya022/botcommands/internal/modals/resolvers/ModalStringResolver.kt @@ -5,6 +5,8 @@ import io.github.freya022.botcommands.api.modals.ModalEvent import io.github.freya022.botcommands.api.modals.options.ModalOption import io.github.freya022.botcommands.api.parameters.ClassParameterResolver import io.github.freya022.botcommands.api.parameters.resolvers.ModalParameterResolver +import io.github.freya022.botcommands.internal.utils.ReflectionUtils.function +import io.github.freya022.botcommands.internal.utils.throwArgument import net.dv8tion.jda.api.components.Component import net.dv8tion.jda.api.interactions.modals.ModalMapping @@ -19,13 +21,20 @@ internal object ModalStringResolver : modalMapping: ModalMapping, ): String? { return when (modalMapping.type) { - Component.Type.STRING_SELECT -> { + Component.Type.STRING_SELECT, Component.Type.CHECKBOX_GROUP -> { val values = modalMapping.asStringList - if (values.size > 1) - error("Cannot get a String from a string select menu with more than a single value") + if (values.size > 1) { + throwArgument( + option.kParameter.function, + "Cannot get a String from a ${modalMapping.type} with more than a single value" + ) + } values.firstOrNull() } - Component.Type.TEXT_INPUT -> modalMapping.asString + Component.Type.TEXT_INPUT, Component.Type.RADIO_GROUP -> when { + option.isRequired -> modalMapping.asString + else -> modalMapping.asOptionalString + } else -> error("Cannot get a String from a ${modalMapping.type} input") } } diff --git a/BotCommands-core/src/test/kotlin/io/github/freya022/botcommands/modals/ModalInputResolverTests.kt b/BotCommands-core/src/test/kotlin/io/github/freya022/botcommands/modals/ModalInputResolverTests.kt index 035da2d1d..31078102b 100644 --- a/BotCommands-core/src/test/kotlin/io/github/freya022/botcommands/modals/ModalInputResolverTests.kt +++ b/BotCommands-core/src/test/kotlin/io/github/freya022/botcommands/modals/ModalInputResolverTests.kt @@ -84,11 +84,13 @@ object ModalInputResolverTests { } val resolvers = ResolverContainer(serviceContainer, listOf(ModalIMentionableResolverFactory)) - val request = ResolverRequest(ParameterWrapper(::userFunc.valueParameters[index])) + val parameter = ::userFunc.valueParameters[index] + val request = ResolverRequest(ParameterWrapper(parameter)) val resolver = resolvers.getResolver(ModalParameterResolver::class, request) val modalMapping = mockk { every { asString } returns STRING + every { asOptionalString } returns null every { asStringList } returns strings every { asMentions } returns mentions every { asAttachmentList } returns attachments @@ -96,7 +98,9 @@ object ModalInputResolverTests { } val value = resolver.resolveSuspend( - mockk(), + mockk { + every { isRequired } returns !(parameter.isOptional || parameter.type.isMarkedNullable) + }, mockk(), modalMapping, ) @@ -108,6 +112,8 @@ object ModalInputResolverTests { fun modalInputs(): List { val listOf = listOf( arguments("TextInput String", 0, TEXT_INPUT, STRING), + arguments("TextInput empty as null", 18, TEXT_INPUT, null), + arguments("TextInput empty with default value", 19, TEXT_INPUT, null), arguments("Select menu string", 16, STRING_SELECT, STRING), arguments("Select menu strings", 1, STRING_SELECT, strings), arguments("Select menu mentionable", 2, MENTIONABLE_SELECT, role), @@ -151,5 +157,7 @@ object ModalInputResolverTests { @Suppress("unused") attachments: List, @Suppress("unused") selectedString: String, @Suppress("unused") attachment: Message.Attachment, + @Suppress("unused") emptyTextInputAsNull: String?, + @Suppress("unused") emptyTextInputAsOptional: String = "default value", ) {} } diff --git a/BotCommands-jda-ktx/src/main/kotlin/dev/freya02/botcommands/jda/ktx/components/Checkbox.kt b/BotCommands-jda-ktx/src/main/kotlin/dev/freya02/botcommands/jda/ktx/components/Checkbox.kt new file mode 100644 index 000000000..9a074045b --- /dev/null +++ b/BotCommands-jda-ktx/src/main/kotlin/dev/freya02/botcommands/jda/ktx/components/Checkbox.kt @@ -0,0 +1,68 @@ +package dev.freya02.botcommands.jda.ktx.components + +import dev.freya02.botcommands.jda.ktx.components.utils.checkInit +import net.dv8tion.jda.api.components.checkbox.Checkbox + +private val DUMMY_CHECKBOX = Checkbox.of("id") + +class InlineCheckbox : InlineComponent { + + private var component: Checkbox = DUMMY_CHECKBOX + + override var uniqueId: Int + get() = component.uniqueId + set(value) { + component = component.withUniqueId(value) + } + + private var _customId: String? = null + /** The custom ID, it can be used to pass data, then be read from an interaction */ + var customId: String + get() = _customId.checkInit("custom ID") + set(value) { + component = component.withCustomId(value) + _customId = value + } + + /** + * Whether this checkbox is selected by default. + */ + var isDefault: Boolean + get() = component.isDefault + set(value) { + component = component.withDefault(value) + } + + fun build(): Checkbox { + customId.checkInit() + return component + } +} + +/** + * A component displaying a box which can be checked. Useful for simple yes/no questions. + * + * @param customId Custom identifier of this component, see [Checkbox.withCustomId] + * @param uniqueId Unique identifier of this component, see [Checkbox.withUniqueId] + * @param isDefault Whether it is checked by default + * @param block Lambda allowing further configuration + * + * @see net.dv8tion.jda.api.components.checkbox.Checkbox Checkbox + */ +inline fun Checkbox( + customId: String, + uniqueId: Int = -1, + isDefault: Boolean = false, + block: InlineCheckbox.() -> Unit = {}, +): Checkbox { + return InlineCheckbox() + .apply { + this.customId = customId + if (uniqueId != -1) + this.uniqueId = uniqueId + if (isDefault) + this.isDefault = true + block() + } + .build() +} diff --git a/BotCommands-jda-ktx/src/main/kotlin/dev/freya02/botcommands/jda/ktx/components/CheckboxGroup.kt b/BotCommands-jda-ktx/src/main/kotlin/dev/freya02/botcommands/jda/ktx/components/CheckboxGroup.kt new file mode 100644 index 000000000..de26c70dd --- /dev/null +++ b/BotCommands-jda-ktx/src/main/kotlin/dev/freya02/botcommands/jda/ktx/components/CheckboxGroup.kt @@ -0,0 +1,110 @@ +package dev.freya02.botcommands.jda.ktx.components + +import dev.freya02.botcommands.jda.ktx.components.utils.MutableAccumulator +import dev.freya02.botcommands.jda.ktx.ranges.setRequiredRange +import net.dv8tion.jda.api.components.checkboxgroup.CheckboxGroup +import net.dv8tion.jda.api.components.checkboxgroup.CheckboxGroupOption + +class InlineCheckboxGroup(val builder: CheckboxGroup.Builder) : InlineComponent { + + override var uniqueId: Int + get() = builder.uniqueId + set(value) { + builder.uniqueId = value + } + + /** The custom ID, it can be used to pass data, then be read from an interaction */ + var customId: String + get() = builder.customId + set(value) { + builder.setCustomId(value) + } + + /** Options of this checkbox group, see [CheckboxGroup.Builder.addOptions] */ + val options = MutableAccumulator(builder.options) + + /** + * Whether the user must select at least [the minimum amount of options][minValues]. + * + * @see [CheckboxGroup.Builder.setRequired]. + */ + var required: Boolean + get() = builder.isRequired + set(value) { + builder.isRequired = value + } + + /** The minimum and maximum amount of values a user can select, must not exceed [CheckboxGroup.OPTIONS_MAX_AMOUNT] */ + var valueRange: IntRange + get() = builder.minValues..builder.maxValues + set(value) { + builder.setRequiredRange(value) + } + + /** The minimum amount of values a user must select, default to `1` */ + var minValues: Int + get() = builder.minValues + set(value) { + builder.setMinValues(value) + } + + /** The maximum amount of values a user can select, must not exceed [CheckboxGroup.OPTIONS_MAX_AMOUNT] */ + var maxValues: Int + get() = builder.maxValues + set(value) { + builder.setMaxValues(value) + } + + /** + * Adds an option to this checkbox group. + * + * @param label The label of this option, see [CheckboxGroupOption.withLabel] + * @param value The value of this option, this is what the bot receives, see [CheckboxGroupOption.withValue] + * @param description The description of this option, see [CheckboxGroupOption.withDescription] + * @param default Whether this option is selected by default + */ + fun option( + label: String, + value: String, + description: String? = null, + default: Boolean = false, + ) { + options += CheckboxGroupOption(label, value, description, default) + } + + fun build(): CheckboxGroup { + return builder.build() + } +} + +/** + * A component displaying a group of up to [OPTIONS_MAX_AMOUNT][CheckboxGroup.OPTIONS_MAX_AMOUNT] checkboxes + * which can be checked independently. + * + * @param customId Custom identifier of this component, see [CheckboxGroup.Builder.setCustomId] + * @param uniqueId Unique identifier of this component, see [CheckboxGroup.Builder.setUniqueId] + * @param valueRange The minimum and maximum amount of values a user can select, must not exceed [CheckboxGroup.OPTIONS_MAX_AMOUNT] + * @param required Whether the user must populate at least the minimum amount of options + * @param block Lambda allowing further configuration + * + * @see net.dv8tion.jda.api.components.checkboxgroup.CheckboxGroup + */ +inline fun CheckboxGroup( + customId: String, + uniqueId: Int = -1, + valueRange: IntRange? = null, + required: Boolean = true, + block: InlineCheckboxGroup.() -> Unit, +): CheckboxGroup { + return InlineCheckboxGroup(CheckboxGroup.create(customId)) + .apply { + if (uniqueId != -1) + this.uniqueId = uniqueId + if (valueRange != null) + this.valueRange = valueRange + if (!required) + this.required = false + block() + } + .build() +} diff --git a/BotCommands-jda-ktx/src/main/kotlin/dev/freya02/botcommands/jda/ktx/components/CheckboxGroups.kt b/BotCommands-jda-ktx/src/main/kotlin/dev/freya02/botcommands/jda/ktx/components/CheckboxGroups.kt new file mode 100644 index 000000000..a3de1291a --- /dev/null +++ b/BotCommands-jda-ktx/src/main/kotlin/dev/freya02/botcommands/jda/ktx/components/CheckboxGroups.kt @@ -0,0 +1,34 @@ +package dev.freya02.botcommands.jda.ktx.components + +import net.dv8tion.jda.api.components.checkboxgroup.CheckboxGroup +import net.dv8tion.jda.api.components.checkboxgroup.CheckboxGroupOption + +/** + * Creates a [CheckboxGroupOption][net.dv8tion.jda.api.components.checkboxgroup.CheckboxGroupOption]. + * + * @param label The label of this option, see [CheckboxGroupOption.withLabel] + * @param value The value of this option, this is what the bot receives, see [CheckboxGroupOption.withValue] + * @param description The description of this option, see [CheckboxGroupOption.withDescription] + * @param default Whether this option is selected by default + */ +fun CheckboxGroupOption( + label: String, + value: String, + description: String? = null, + default: Boolean = false, +) = CheckboxGroupOption.of(label, value, description, default) + +/** + * Adds an option to this select menu, see [CheckboxGroupOption]. + * + * @param label The label of this option, see [CheckboxGroupOption.withLabel] + * @param value The value of this option, this is what the bot receives, see [CheckboxGroupOption.withValue] + * @param description The description of this option, see [CheckboxGroupOption.withDescription] + * @param default Whether this option is selected by default + */ +fun CheckboxGroup.Builder.option( + label: String, + value: String, + description: String? = null, + default: Boolean = false, +) = addOptions(CheckboxGroupOption(label, value, description, default)) diff --git a/BotCommands-jda-ktx/src/main/kotlin/dev/freya02/botcommands/jda/ktx/components/RadioGroup.kt b/BotCommands-jda-ktx/src/main/kotlin/dev/freya02/botcommands/jda/ktx/components/RadioGroup.kt new file mode 100644 index 000000000..cbb31a7ea --- /dev/null +++ b/BotCommands-jda-ktx/src/main/kotlin/dev/freya02/botcommands/jda/ktx/components/RadioGroup.kt @@ -0,0 +1,84 @@ +package dev.freya02.botcommands.jda.ktx.components + +import dev.freya02.botcommands.jda.ktx.components.utils.MutableAccumulator +import net.dv8tion.jda.api.components.radiogroup.RadioGroup +import net.dv8tion.jda.api.components.radiogroup.RadioGroupOption + +class InlineRadioGroup(val builder: RadioGroup.Builder) : InlineComponent { + + override var uniqueId: Int + get() = builder.uniqueId + set(value) { + builder.uniqueId = value + } + + /** The custom ID, it can be used to pass data, then be read from an interaction */ + var customId: String + get() = builder.customId + set(value) { + builder.setCustomId(value) + } + + /** Options of this select menu, see [RadioGroup.Builder.addOptions] */ + val options = MutableAccumulator(builder.options) + + /** + * Whether the user must select an option. + * + * @see [RadioGroup.Builder.setRequired]. + */ + var required: Boolean + get() = builder.isRequired + set(value) { + builder.isRequired = value + } + + /** + * Adds an option to this radio group. + * + * @param label The label of this option, see [RadioGroupOption.withLabel] + * @param value The value of this option, this is what the bot receives, see [RadioGroupOption.withValue] + * @param description The description of this option, see [RadioGroupOption.withDescription] + * @param default Whether this option is selected by default + */ + fun option( + label: String, + value: String, + description: String? = null, + default: Boolean = false, + ) { + options += RadioGroupOption(label, value, description, default) + } + + fun build(): RadioGroup { + return builder.build() + } +} + +/** + * A component displaying a group of up to [OPTIONS_MAX_AMOUNT][RadioGroup.OPTIONS_MAX_AMOUNT] radio buttons, + * in which only one can be chosen. + * + * @param customId Custom identifier of this component, see [RadioGroup.Builder.setCustomId] + * @param uniqueId Unique identifier of this component, see [RadioGroup.Builder.setUniqueId] + * @param required Whether the user must select an option + * @param block Lambda allowing further configuration + * + * @see net.dv8tion.jda.api.components.radiogroup.RadioGroup RadioGroup + */ +inline fun RadioGroup( + customId: String, + uniqueId: Int = -1, + required: Boolean = true, + block: InlineRadioGroup.() -> Unit, +): RadioGroup { + return InlineRadioGroup(RadioGroup.create(customId)) + .apply { + if (uniqueId != -1) + this.uniqueId = uniqueId + if (!required) + this.required = false + block() + } + .build() +} diff --git a/BotCommands-jda-ktx/src/main/kotlin/dev/freya02/botcommands/jda/ktx/components/RadioGroups.kt b/BotCommands-jda-ktx/src/main/kotlin/dev/freya02/botcommands/jda/ktx/components/RadioGroups.kt new file mode 100644 index 000000000..6130c979f --- /dev/null +++ b/BotCommands-jda-ktx/src/main/kotlin/dev/freya02/botcommands/jda/ktx/components/RadioGroups.kt @@ -0,0 +1,34 @@ +package dev.freya02.botcommands.jda.ktx.components + +import net.dv8tion.jda.api.components.radiogroup.RadioGroup +import net.dv8tion.jda.api.components.radiogroup.RadioGroupOption + +/** + * Creates a [RadioGroupOption][net.dv8tion.jda.api.components.radiogroup.RadioGroupOption]. + * + * @param label The label of this option, see [RadioGroupOption.withLabel] + * @param value The value of this option, this is what the bot receives, see [RadioGroupOption.withValue] + * @param description The description of this option, see [RadioGroupOption.withDescription] + * @param default Whether this option is selected by default + */ +fun RadioGroupOption( + label: String, + value: String, + description: String? = null, + default: Boolean = false, +) = RadioGroupOption.of(label, value, description, default) + +/** + * Adds an option to this select menu, see [RadioGroupOption]. + * + * @param label The label of this option, see [RadioGroupOption.withLabel] + * @param value The value of this option, this is what the bot receives, see [RadioGroupOption.withValue] + * @param description The description of this option, see [RadioGroupOption.withDescription] + * @param default Whether this option is selected by default + */ +fun RadioGroup.Builder.option( + label: String, + value: String, + description: String? = null, + default: Boolean = false, +) = addOptions(RadioGroupOption(label, value, description, default)) diff --git a/BotCommands-jda-ktx/src/main/kotlin/dev/freya02/botcommands/jda/ktx/ranges/Ranges.kt b/BotCommands-jda-ktx/src/main/kotlin/dev/freya02/botcommands/jda/ktx/ranges/Ranges.kt index 5f443b141..04b34c67c 100644 --- a/BotCommands-jda-ktx/src/main/kotlin/dev/freya02/botcommands/jda/ktx/ranges/Ranges.kt +++ b/BotCommands-jda-ktx/src/main/kotlin/dev/freya02/botcommands/jda/ktx/ranges/Ranges.kt @@ -1,6 +1,7 @@ package dev.freya02.botcommands.jda.ktx.ranges import dev.freya02.botcommands.jda.ktx.DeprecatedInBcCore +import net.dv8tion.jda.api.components.checkboxgroup.CheckboxGroup import net.dv8tion.jda.api.components.selections.SelectMenu /** @@ -8,3 +9,10 @@ import net.dv8tion.jda.api.components.selections.SelectMenu */ @DeprecatedInBcCore fun > SelectMenu.Builder<*, B>.setRequiredRange(range: IntRange): B = setRequiredRange(range.first, range.last) + +/** + * Sets the minimum and maximum number of values the user has to select, must not exceed [CheckboxGroup.OPTIONS_MAX_AMOUNT]. + * + * @see CheckboxGroup.Builder.setRequiredRange + */ +fun CheckboxGroup.Builder.setRequiredRange(range: IntRange): CheckboxGroup.Builder = setRequiredRange(range.first, range.last) diff --git a/BotCommands-jda-ktx/src/test/resources/ksp_snapshot.zip b/BotCommands-jda-ktx/src/test/resources/ksp_snapshot.zip index 4e1d3f590..92eeac683 100644 Binary files a/BotCommands-jda-ktx/src/test/resources/ksp_snapshot.zip and b/BotCommands-jda-ktx/src/test/resources/ksp_snapshot.zip differ diff --git a/buildSrc/src/main/kotlin/repositories-conventions.gradle.kts b/buildSrc/src/main/kotlin/repositories-conventions.gradle.kts index e69b970fb..f5e27fb4c 100644 --- a/buildSrc/src/main/kotlin/repositories-conventions.gradle.kts +++ b/buildSrc/src/main/kotlin/repositories-conventions.gradle.kts @@ -1,4 +1,13 @@ repositories { mavenCentral() + exclusiveContent { + forRepository { + maven("https://jitpack.io") + } + + filter { + includeModule("io.github.JDA-Fork", "JDA") + } + } mavenLocal() } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 81fdabadc..0322f20d3 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -10,7 +10,7 @@ h2 = "2.3.232" hikaricp = "6.2.1" jackson = "2.20.0" java-string-similarity = "2.0.0" -jda = "6.3.0" +jda = "aa61a91fa0" jda-emojis = "3.0.0" jda-ktx = "0.12.0" jemoji = "1.7.5" @@ -57,7 +57,7 @@ jackson-databind = { module = "com.fasterxml.jackson.core:jackson-databind", ver jackson-dataformat-yaml = { module = "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml", version.ref = "jackson" } jackson-module-kotlin = { module = "com.fasterxml.jackson.module:jackson-module-kotlin", version.ref = "jackson" } java-string-similarity = { module = "info.debatty:java-string-similarity", version.ref = "java-string-similarity" } -jda = { module = "net.dv8tion:JDA", version.ref = "jda" } +jda = { module = "io.github.JDA-Fork:JDA", version.ref = "jda" } jda-emojis = { module = "dev.freya02:jda-emojis", version.ref = "jda-emojis" } jda-ktx = { module = "club.minnced:jda-ktx", version.ref = "jda-ktx" } jemoji = { module = "net.fellbaum:jemoji", version.ref = "jemoji" } diff --git a/test-bot/src/test/kotlin/dev/freya02/botcommands/bot/commands/slash/SlashModals4.kt b/test-bot/src/test/kotlin/dev/freya02/botcommands/bot/commands/slash/SlashModals4.kt new file mode 100644 index 000000000..e7da91769 --- /dev/null +++ b/test-bot/src/test/kotlin/dev/freya02/botcommands/bot/commands/slash/SlashModals4.kt @@ -0,0 +1,74 @@ +package dev.freya02.botcommands.bot.commands.slash + +import dev.freya02.botcommands.jda.ktx.components.Checkbox +import dev.freya02.botcommands.jda.ktx.components.CheckboxGroup +import dev.freya02.botcommands.jda.ktx.components.RadioGroup +import io.github.freya022.botcommands.api.commands.annotations.Command +import io.github.freya022.botcommands.api.commands.application.slash.GuildSlashEvent +import io.github.freya022.botcommands.api.commands.application.slash.annotations.JDASlashCommand +import io.github.freya022.botcommands.api.commands.application.slash.annotations.TopLevelSlashCommandData +import io.github.freya022.botcommands.api.modals.ModalEvent +import io.github.freya022.botcommands.api.modals.Modals +import io.github.freya022.botcommands.api.modals.annotations.ModalHandler +import io.github.freya022.botcommands.api.modals.annotations.ModalInput +import io.github.freya022.botcommands.api.modals.create +import net.dv8tion.jda.api.interactions.IntegrationType +import net.dv8tion.jda.api.interactions.InteractionContextType + +private const val MODAL_NAME = "SlashModals4: modal" +private const val CHECKBOX_ID = "checkbox-id" +private const val RADIO_GROUP_ID = "radio_group-id" +private const val CHECKBOX_GROUP_ID = "checkbox_group-id" + +@Command +class SlashModals4(private val modals: Modals) { + @TopLevelSlashCommandData( + contexts = [InteractionContextType.GUILD], + integrationTypes = [IntegrationType.USER_INSTALL] + ) + @JDASlashCommand(name = "modals4") + fun onSlashModals4(event: GuildSlashEvent) { + val modal = modals.create("Modal") { + label("I like checking boxes") { + child = Checkbox(CHECKBOX_ID, isDefault = true) + } + + label("Which Discord client do you use?") { + child = RadioGroup(RADIO_GROUP_ID, required = false) { + option("Discord (Stable)", "stable", "The vanilla option", default = true) + option("Discord PTB", "ptb", "A peek into the future") + option("Discord Canary", "canary", "Living on the edge") + } + } + + label("Which modal components do you use?") { + child = CheckboxGroup(CHECKBOX_GROUP_ID) { + option("Text Inputs", "textinputs") + option("Select Menus", "selectmenus") + option("File Uploads", "fileuploads") + option("Checkbox groups", "checkboxgroups", default = true) + } + } + + bindTo(MODAL_NAME) + } + + event.replyModal(modal).queue() + } + + @ModalHandler(MODAL_NAME) + fun onModal( + event: ModalEvent, + @ModalInput(CHECKBOX_ID) doTheyLikeCheckingBoxes: Boolean, + @ModalInput(RADIO_GROUP_ID) client: String = "", + @ModalInput(CHECKBOX_GROUP_ID) features: List, + ) { + event.reply(""" + Do you like checking boxes? $doTheyLikeCheckingBoxes + On what client? $client + Using what features? $features + """.trimIndent()) + .setEphemeral(true) + .queue() + } +}