Skip to content

Commit

Permalink
Implement Modals properly
Browse files Browse the repository at this point in the history
  • Loading branch information
schnapster committed Jan 28, 2024
1 parent dc5bada commit bf934b6
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@ import dev.capybaralabs.shipa.discord.interaction.UnifiedInteractionMsg.Delete
import dev.capybaralabs.shipa.discord.interaction.UnifiedInteractionMsg.Edit
import dev.capybaralabs.shipa.discord.interaction.UnifiedInteractionMsg.Fetch
import dev.capybaralabs.shipa.discord.interaction.UnifiedInteractionMsg.Followup
import dev.capybaralabs.shipa.discord.interaction.UnifiedInteractionMsg.ShowModal
import dev.capybaralabs.shipa.discord.interaction.model.InteractionCallback
import dev.capybaralabs.shipa.discord.interaction.model.InteractionCallback.Flags
import dev.capybaralabs.shipa.discord.interaction.model.InteractionCallback.Modal
import dev.capybaralabs.shipa.discord.interaction.model.InteractionObject.InteractionWithData
import dev.capybaralabs.shipa.discord.interaction.model.InteractionObject.InteractionWithData.MessageComponent
import dev.capybaralabs.shipa.discord.interaction.model.InteractionResponse
Expand Down Expand Up @@ -125,6 +127,11 @@ interface InteractionStateHolder {
* Respond to an autocomplete interaction with a bunch of choices
*/
fun autocomplete(choices: List<OptionChoice>): Deferred<Result.Completed>

/**
* Show a modal to the user
*/
fun showModal(modal: Modal): Deferred<Result.Completed>
}

enum class AutoAckTactic {
Expand Down Expand Up @@ -195,6 +202,12 @@ private sealed interface UnifiedInteractionMsg<E : Result> {
val choices: List<OptionChoice>,
override val response: CompletableDeferred<Result.Completed>,
) : UnifiedInteractionMsg<Result.Completed>

data class ShowModal(
val modal: Modal,
override val response: CompletableDeferred<Result.Completed>,
) : UnifiedInteractionMsg<Result.Completed>

}


Expand Down Expand Up @@ -235,6 +248,7 @@ internal class UnifiedInteractionService(
is Fetch -> msg.response.complete(state.fetch(msg.messageId))
is Delete -> msg.response.complete(state.delete(msg.messageId))
is Autocomplete -> state.autocomplete(msg.choices).let { msg.response.complete(Result.Completed) }
is ShowModal -> state.showModal(msg.modal).let { msg.response.complete(Result.Completed) }
}
}
} catch (t: TimeoutCancellationException) {
Expand Down Expand Up @@ -368,6 +382,12 @@ private class InteractionStateHolderImpl(
send(Autocomplete(choices, response))
return response
}

override fun showModal(modal: Modal): Deferred<Result.Completed> {
val response = CompletableDeferred<Result.Completed>()
send(ShowModal(modal, response))
return response
}
}


Expand Down Expand Up @@ -487,4 +507,13 @@ private class UnifiedInteractionState(
initialResponse.complete(InteractionResponse.Autocomplete(InteractionCallback.Autocomplete(choices)))
}

fun showModal(modal: Modal) {
if (initialResponse.isCompleted) {
logger().warn("Cannot send Modal to acked interaction")
return
}

initialResponse.complete(InteractionResponse.Modal(modal))
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package dev.capybaralabs.shipa.discord.interaction.model
import com.fasterxml.jackson.annotation.JsonProperty
import com.fasterxml.jackson.annotation.JsonTypeInfo
import com.fasterxml.jackson.annotation.JsonTypeInfo.Id.DEDUCTION
import java.awt.TextComponent
import dev.capybaralabs.shipa.discord.interaction.model.MessageComponent.ComponentType

/**
* [Discord Interaction Data](https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-object-interaction-data)
Expand Down Expand Up @@ -51,7 +51,21 @@ sealed interface InteractionData {
*/
data class ModalSubmitData(
@JsonProperty("custom_id") val customId: String,
val components: List<TextComponent>,
) : InteractionData
val components: List<SubmitActionRow>,
) : InteractionData {

data class SubmitActionRow(
val components: List<SubmitTextInput>,
) {
val type = ComponentType.ACTION_ROW
}

data class SubmitTextInput(
val customId: String,
val value: String,
) {
val type = ComponentType.TEXT_INPUT
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import dev.capybaralabs.shipa.discord.interaction.model.InteractionCallbackType.
import dev.capybaralabs.shipa.discord.interaction.model.InteractionCallbackType.PONG
import dev.capybaralabs.shipa.discord.interaction.model.InteractionCallbackType.UPDATE_MESSAGE
import dev.capybaralabs.shipa.discord.interaction.model.MessageComponent.ActionRow
import dev.capybaralabs.shipa.discord.interaction.model.MessageComponent.TextInput
import dev.capybaralabs.shipa.discord.interaction.model.MessageComponent.ModalActionRow
import dev.capybaralabs.shipa.discord.model.AllowedMentions
import dev.capybaralabs.shipa.discord.model.Embed
import dev.capybaralabs.shipa.discord.model.IntBitfield
Expand Down Expand Up @@ -126,7 +126,7 @@ sealed interface InteractionCallback {
data class Modal(
val customId: String,
val title: String,
val components: List<TextInput>,
val components: List<ModalActionRow>,
) : InteractionCallback

}
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,21 @@ sealed interface MessageComponent {
}
}

data class ModalActionRow internal constructor(
val components: List<TextInput>,
) : MessageComponent {

override val type = ACTION_ROW

companion object {
fun textInputs(inputs: List<TextInput>): ModalActionRow {
Assert.isTrue(inputs.isNotEmpty(), "At least one text input is required")
Assert.isTrue(inputs.size <= 5, "Only a maximum of 5 text inputs is allowed in a Modal ActionRow")
return ModalActionRow(inputs)
}
}
}


data class PartialEmoji(
val id: Optional<Long> = Optional.empty(),
Expand Down

0 comments on commit bf934b6

Please sign in to comment.