Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: more selector types #200

Merged
merged 10 commits into from
Sep 17, 2023
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,14 @@ import com.kotlindiscord.kord.extensions.components.buttons.EphemeralInteraction
import com.kotlindiscord.kord.extensions.components.buttons.LinkInteractionButton
import com.kotlindiscord.kord.extensions.components.buttons.PublicInteractionButton
import com.kotlindiscord.kord.extensions.components.forms.ModalForm
import com.kotlindiscord.kord.extensions.components.menus.EphemeralSelectMenu
import com.kotlindiscord.kord.extensions.components.menus.PublicSelectMenu
import com.kotlindiscord.kord.extensions.components.menus.channel.EphemeralChannelSelectMenu
import com.kotlindiscord.kord.extensions.components.menus.channel.PublicChannelSelectMenu
import com.kotlindiscord.kord.extensions.components.menus.role.EphemeralRoleSelectMenu
import com.kotlindiscord.kord.extensions.components.menus.role.PublicRoleSelectMenu
import com.kotlindiscord.kord.extensions.components.menus.string.EphemeralStringSelectMenu
import com.kotlindiscord.kord.extensions.components.menus.string.PublicStringSelectMenu
import com.kotlindiscord.kord.extensions.components.menus.user.EphemeralUserSelectMenu
import com.kotlindiscord.kord.extensions.components.menus.user.PublicUserSelectMenu
import dev.kord.rest.builder.message.create.MessageCreateBuilder
import dev.kord.rest.builder.message.modify.MessageModifyBuilder
import kotlin.time.Duration
Expand Down Expand Up @@ -97,53 +103,215 @@ public suspend fun <M : ModalForm> ComponentContainer.publicButton(
return component
}

/** DSL function for creating an ephemeral select menu and adding it to the current [ComponentContainer]. **/
public suspend fun ComponentContainer.ephemeralSelectMenu(
/** DSL function for creating an ephemeral string select menu and adding it to the current [ComponentContainer]. **/
public suspend fun ComponentContainer.ephemeralStringSelectMenu(
DeDiamondPro marked this conversation as resolved.
Show resolved Hide resolved
row: Int? = null,
builder: suspend EphemeralSelectMenu<ModalForm>.() -> Unit
): EphemeralSelectMenu<ModalForm> {
val component = EphemeralSelectMenu<ModalForm>(timeoutTask)
builder: suspend EphemeralStringSelectMenu<ModalForm>.() -> Unit
): EphemeralStringSelectMenu<ModalForm> {
val component = EphemeralStringSelectMenu<ModalForm>(timeoutTask)

builder(component)
add(component, row)

return component
}

/** DSL function for creating an ephemeral select menu and adding it to the current [ComponentContainer]. **/
public suspend fun <M : ModalForm> ComponentContainer.ephemeralSelectMenu(
/** DSL function for creating an ephemeral string select menu and adding it to the current [ComponentContainer]. **/
public suspend fun <M : ModalForm> ComponentContainer.ephemeralStringSelectMenu(
modal: (() -> M)?,
row: Int? = null,
builder: suspend EphemeralSelectMenu<M>.() -> Unit
): EphemeralSelectMenu<M> {
val component = EphemeralSelectMenu<M>(timeoutTask, modal)
builder: suspend EphemeralStringSelectMenu<M>.() -> Unit
): EphemeralStringSelectMenu<M> {
val component = EphemeralStringSelectMenu<M>(timeoutTask, modal)

builder(component)
add(component, row)

return component
}

/** DSL function for creating a public select menu and adding it to the current [ComponentContainer]. **/
public suspend fun ComponentContainer.publicSelectMenu(
/** DSL function for creating a public string select menu and adding it to the current [ComponentContainer]. **/
public suspend fun ComponentContainer.publicStringSelectMenu(
row: Int? = null,
builder: suspend PublicSelectMenu<ModalForm>.() -> Unit
): PublicSelectMenu<ModalForm> {
val component = PublicSelectMenu<ModalForm>(timeoutTask)
builder: suspend PublicStringSelectMenu<ModalForm>.() -> Unit
): PublicStringSelectMenu<ModalForm> {
val component = PublicStringSelectMenu<ModalForm>(timeoutTask)

builder(component)
add(component, row)

return component
}

/** DSL function for creating a public select menu and adding it to the current [ComponentContainer]. **/
public suspend fun <M : ModalForm> ComponentContainer.publicSelectMenu(
/** DSL function for creating a public string select menu and adding it to the current [ComponentContainer]. **/
public suspend fun <M : ModalForm> ComponentContainer.publicStringSelectMenu(
modal: (() -> M)?,
row: Int? = null,
builder: suspend PublicSelectMenu<M>.() -> Unit
): PublicSelectMenu<M> {
val component = PublicSelectMenu(timeoutTask, modal)
builder: suspend PublicStringSelectMenu<M>.() -> Unit
): PublicStringSelectMenu<M> {
val component = PublicStringSelectMenu(timeoutTask, modal)

builder(component)
add(component, row)

return component
}

/** DSL function for creating an ephemeral user select menu and adding it to the current [ComponentContainer]. **/
public suspend fun ComponentContainer.ephemeralUserSelectMenu(
row: Int? = null,
builder: suspend EphemeralUserSelectMenu<ModalForm>.() -> Unit
): EphemeralUserSelectMenu<ModalForm> {
val component = EphemeralUserSelectMenu<ModalForm>(timeoutTask)

builder(component)
add(component, row)

return component
}

/** DSL function for creating an ephemeral user select menu and adding it to the current [ComponentContainer]. **/
public suspend fun <M : ModalForm> ComponentContainer.ephemeralUserSelectMenu(
modal: (() -> M)?,
row: Int? = null,
builder: suspend EphemeralUserSelectMenu<M>.() -> Unit
): EphemeralUserSelectMenu<M> {
val component = EphemeralUserSelectMenu<M>(timeoutTask, modal)

builder(component)
add(component, row)

return component
}

/** DSL function for creating a public user select menu and adding it to the current [ComponentContainer]. **/
public suspend fun ComponentContainer.publicUserSelectMenu(
row: Int? = null,
builder: suspend PublicUserSelectMenu<ModalForm>.() -> Unit
): PublicUserSelectMenu<ModalForm> {
val component = PublicUserSelectMenu<ModalForm>(timeoutTask)

builder(component)
add(component, row)

return component
}

/** DSL function for creating a public user select menu and adding it to the current [ComponentContainer]. **/
public suspend fun <M : ModalForm> ComponentContainer.publicUserSelectMenu(
modal: (() -> M)?,
row: Int? = null,
builder: suspend PublicUserSelectMenu<M>.() -> Unit
): PublicUserSelectMenu<M> {
val component = PublicUserSelectMenu(timeoutTask, modal)

builder(component)
add(component, row)

return component
}

/** DSL function for creating an ephemeral user select menu and adding it to the current [ComponentContainer]. **/
public suspend fun ComponentContainer.ephemeralRoleSelectMenu(
row: Int? = null,
builder: suspend EphemeralRoleSelectMenu<ModalForm>.() -> Unit
): EphemeralRoleSelectMenu<ModalForm> {
val component = EphemeralRoleSelectMenu<ModalForm>(timeoutTask)

builder(component)
add(component, row)

return component
}

/** DSL function for creating an ephemeral user select menu and adding it to the current [ComponentContainer]. **/
public suspend fun <M : ModalForm> ComponentContainer.ephemeralRoleSelectMenu(
modal: (() -> M)?,
row: Int? = null,
builder: suspend EphemeralRoleSelectMenu<M>.() -> Unit
): EphemeralRoleSelectMenu<M> {
val component = EphemeralRoleSelectMenu<M>(timeoutTask, modal)

builder(component)
add(component, row)

return component
}

/** DSL function for creating a public user select menu and adding it to the current [ComponentContainer]. **/
public suspend fun ComponentContainer.publicRoleSelectMenu(
row: Int? = null,
builder: suspend PublicRoleSelectMenu<ModalForm>.() -> Unit
): PublicRoleSelectMenu<ModalForm> {
val component = PublicRoleSelectMenu<ModalForm>(timeoutTask)

builder(component)
add(component, row)

return component
}

/** DSL function for creating a public user select menu and adding it to the current [ComponentContainer]. **/
public suspend fun <M : ModalForm> ComponentContainer.publicRoleSelectMenu(
modal: (() -> M)?,
row: Int? = null,
builder: suspend PublicRoleSelectMenu<M>.() -> Unit
): PublicRoleSelectMenu<M> {
val component = PublicRoleSelectMenu(timeoutTask, modal)

builder(component)
add(component, row)

return component
}

/** DSL function for creating an ephemeral user select menu and adding it to the current [ComponentContainer]. **/
public suspend fun ComponentContainer.ephemeralChannelSelectMenu(
row: Int? = null,
builder: suspend EphemeralChannelSelectMenu<ModalForm>.() -> Unit
): EphemeralChannelSelectMenu<ModalForm> {
val component = EphemeralChannelSelectMenu<ModalForm>(timeoutTask)

builder(component)
add(component, row)

return component
}

/** DSL function for creating an ephemeral user select menu and adding it to the current [ComponentContainer]. **/
public suspend fun <M : ModalForm> ComponentContainer.ephemeralChannelSelectMenu(
modal: (() -> M)?,
row: Int? = null,
builder: suspend EphemeralChannelSelectMenu<M>.() -> Unit
): EphemeralChannelSelectMenu<M> {
val component = EphemeralChannelSelectMenu<M>(timeoutTask, modal)

builder(component)
add(component, row)

return component
}

/** DSL function for creating a public user select menu and adding it to the current [ComponentContainer]. **/
public suspend fun ComponentContainer.publicChannelSelectMenu(
row: Int? = null,
builder: suspend PublicChannelSelectMenu<ModalForm>.() -> Unit
): PublicChannelSelectMenu<ModalForm> {
val component = PublicChannelSelectMenu<ModalForm>(timeoutTask)

builder(component)
add(component, row)

return component
}

/** DSL function for creating a public user select menu and adding it to the current [ComponentContainer]. **/
public suspend fun <M : ModalForm> ComponentContainer.publicChannelSelectMenu(
modal: (() -> M)?,
row: Int? = null,
builder: suspend PublicChannelSelectMenu<M>.() -> Unit
): PublicChannelSelectMenu<M> {
val component = PublicChannelSelectMenu(timeoutTask, modal)

builder(component)
add(component, row)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,12 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/

@file:Suppress("TooGenericExceptionCaught")
@file:OptIn(KordUnsafe::class)

package com.kotlindiscord.kord.extensions.components.menus

import com.kotlindiscord.kord.extensions.DiscordRelayedException
import com.kotlindiscord.kord.extensions.components.forms.ModalForm
import com.kotlindiscord.kord.extensions.components.menus.channel.InitialEphemeralSelectMenuResponseBuilder
import com.kotlindiscord.kord.extensions.types.EphemeralInteractionContext
import com.kotlindiscord.kord.extensions.types.FailureReason
import com.kotlindiscord.kord.extensions.types.respond
import com.kotlindiscord.kord.extensions.utils.MutableStringKeyedMap
Expand All @@ -19,19 +18,16 @@ import com.kotlindiscord.kord.extensions.utils.scheduling.Task
import dev.kord.common.annotation.KordUnsafe
import dev.kord.core.behavior.interaction.modal
import dev.kord.core.behavior.interaction.respondEphemeral
import dev.kord.core.behavior.interaction.response.EphemeralMessageInteractionResponseBehavior
import dev.kord.core.event.interaction.SelectMenuInteractionCreateEvent
import dev.kord.rest.builder.message.create.InteractionResponseCreateBuilder

public typealias InitialEphemeralSelectMenuResponseBuilder =
(suspend InteractionResponseCreateBuilder.(SelectMenuInteractionCreateEvent) -> Unit)?

/** Class representing an ephemeral-only select (dropdown) menu. **/
public open class EphemeralSelectMenu<M : ModalForm>(
/** Interface for ephemeral select menus. **/
DeDiamondPro marked this conversation as resolved.
Show resolved Hide resolved
public abstract class EphemeralSelectMenu<C, M : ModalForm>(
gdude2002 marked this conversation as resolved.
Show resolved Hide resolved
timeoutTask: Task?,
public override val modal: (() -> M)? = null,
) : SelectMenu<EphemeralSelectMenuContext<M>, M>(timeoutTask) {
/** @suppress Initial response builder. **/
public open var initialResponseBuilder: InitialEphemeralSelectMenuResponseBuilder = null
/** Builder for the initial response, omit to ack instead. **/
public open var initialResponseBuilder: InitialEphemeralSelectMenuResponseBuilder = null,
) : SelectMenu<C, M>(timeoutTask) where C : SelectMenuContext, C : EphemeralInteractionContext {

/** Call this to open with a response, omit it to ack instead. **/
public fun initialResponse(body: InitialEphemeralSelectMenuResponseBuilder) {
Expand All @@ -46,6 +42,15 @@ public open class EphemeralSelectMenu<M : ModalForm>(
}
}

/** Function to create the context of the select menu. **/
public abstract fun createContext(
event: SelectMenuInteractionCreateEvent,
interactionResponse: EphemeralMessageInteractionResponseBehavior,
cache: MutableStringKeyedMap<Any>,
): C

@OptIn(KordUnsafe::class)
@Suppress("TooGenericExceptionCaught")
override suspend fun call(event: SelectMenuInteractionCreateEvent): Unit = withLock {
val cache: MutableStringKeyedMap<Any> = mutableMapOf()

Expand Down Expand Up @@ -96,7 +101,7 @@ public open class EphemeralSelectMenu<M : ModalForm>(
}
}

val context = EphemeralSelectMenuContext(this, event, response, cache)
val context = createContext(event, response, cache)

context.populate()

Expand All @@ -120,9 +125,9 @@ public open class EphemeralSelectMenu<M : ModalForm>(
}

override suspend fun respondText(
context: EphemeralSelectMenuContext<M>,
context: C,
message: String,
failureType: FailureReason<*>
failureType: FailureReason<*>,
) {
context.respond { settings.failureResponseBuilder(this, message, failureType) }
}
Expand Down
Loading