All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.github.freya022.botcommands.api.pagination.nested.AbstractNestedPaginator.kt Maven / Gradle / Ivy

Go to download

A Kotlin-first (and Java) framework that makes creating Discord bots a piece of cake, using the JDA library.

The newest version!
package io.github.freya022.botcommands.api.pagination.nested

import io.github.freya022.botcommands.api.components.event.StringSelectEvent
import io.github.freya022.botcommands.api.components.utils.SelectContent
import io.github.freya022.botcommands.api.core.BContext
import io.github.freya022.botcommands.api.core.utils.toImmutableList
import io.github.freya022.botcommands.api.pagination.paginator.AbstractPaginator
import io.github.freya022.botcommands.internal.utils.throwArgument
import net.dv8tion.jda.api.EmbedBuilder
import net.dv8tion.jda.api.interactions.InteractionHook
import net.dv8tion.jda.api.interactions.components.selections.StringSelectMenu
import net.dv8tion.jda.api.utils.messages.MessageCreateBuilder
import net.dv8tion.jda.internal.utils.Checks

/**
 * @param T Type of the implementor
 */
abstract class AbstractNestedPaginator> protected constructor(
    context: BContext,
    builder: AbstractNestedPaginatorBuilder<*, T>
) : AbstractPaginator(
    context,
    builder
) {
    val usePaginatorControls: Boolean = builder.usePaginatorControls

    private val items: List> = builder.items.toImmutableList()
    private val selectOptions = items.mapIndexed { i, item -> item.content.toSelectOption(i.toString()) }

    var selectedItemIndex: Int = 0
        protected set(value) {
            selectedItem.page = page
            field = value
            page = selectedItem.page
            maxPages = selectedItem.maxPages
        }
    val selectedItem: NestedPaginationItem
        get() = items[selectedItemIndex]

    override var maxPages: Int = selectedItem.maxPages

    init {
        require(items.isNotEmpty()) { "No wrapped paginator have been added" }

        setSelectedItem(0)
    }

    protected open fun createSelectMenu(): StringSelectMenu {
        val options = selectOptions.mapIndexed { i, it -> it.withDefault(i == selectedItemIndex) }

        return selectMenus.stringSelectMenu().ephemeral()
            .bindTo(this::onItemSelected)
            .singleUse(true)
            .constraints(constraints)
            .addOptions(options)
            .build()
    }

    private fun onItemSelected(event: StringSelectEvent) {
        selectedItemIndex = event.values[0].toInt()
        event.editMessage(getCurrentMessage()).queue()
    }

    /**
     * Sets the selected wrapped pagination.
     *
     * This does not update the active pagination,
     * you can use [getCurrentMessage] and [InteractionHook.editOriginal] in order to update the message.
     *
     * @param index Index of the wrapped pagination, from `0` to `[the number of paginators] - 1`
     *
     * @return This instance for chaining convenience
     */
    fun setSelectedItem(index: Int): T {
        Checks.check(index >= 0, "Item index cannot be negative")
        Checks.check(index < items.size, "Item index cannot be higher than max items count (%d)", items.size)

        this.selectedItemIndex = index

        @Suppress("UNCHECKED_CAST")
        return this as T
    }

    /**
     * Sets the selected wrapped pagination.
     *
     * This does not update the active pagination,
     * you can use [getCurrentMessage] and [InteractionHook.editOriginal] in order to update the message.
     *
     * @param itemLabel Label which must be matched against [SelectContent.label]
     *
     * @return This instance for chaining convenience
     */
    fun setSelectedItem(itemLabel: String): T {
        Checks.notEmpty(itemLabel, "Item name cannot be empty")

        items.forEachIndexed { i, item ->
            if (item.content.label == itemLabel) {
                return setSelectedItem(i)
            }
        }

        throwArgument("Item named '$itemLabel' cannot be found in this pagination wrapper")
    }

    override fun writeMessage(builder: MessageCreateBuilder) {
        super.writeMessage(builder)

        val embedBuilder = EmbedBuilder()
        @Suppress("UNCHECKED_CAST")
        selectedItem.pageEditor.accept(this as T, builder, embedBuilder, page)
        builder.setEmbeds(embedBuilder.build())
    }

    override fun putComponents(builder: MessageCreateBuilder) {
        if (usePaginatorControls) {
            super.putComponents(builder)
        }

        builder.addActionRow(createSelectMenu())
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy