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

io.github.freya022.botcommands.api.pagination.interactive.BasicInteractiveMenu 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.

There is a newer version: 3.0.0-alpha.18
Show newest version
package io.github.freya022.botcommands.api.pagination.interactive;

import io.github.freya022.botcommands.api.components.Components;
import io.github.freya022.botcommands.api.components.data.InteractionConstraints;
import io.github.freya022.botcommands.api.components.event.StringSelectEvent;
import io.github.freya022.botcommands.api.pagination.TimeoutInfo;
import io.github.freya022.botcommands.api.pagination.paginator.BasicPaginator;
import io.github.freya022.botcommands.api.utils.ButtonContent;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.entities.MessageEmbed;
import net.dv8tion.jda.api.interactions.InteractionHook;
import net.dv8tion.jda.api.interactions.components.selections.SelectOption;
import net.dv8tion.jda.api.interactions.components.selections.StringSelectMenu;
import net.dv8tion.jda.api.utils.messages.MessageEditData;
import net.dv8tion.jda.internal.utils.Checks;
import org.jetbrains.annotations.NotNull;

import java.util.List;

/**
 * @param  Type of the implementor
 */
@SuppressWarnings("unchecked")
public abstract class BasicInteractiveMenu> extends BasicPaginator {
	protected final List> items;

	protected int selectedItem = 0;
	protected final boolean usePaginator;

	protected BasicInteractiveMenu(@NotNull Components componentsService,
								   InteractionConstraints constraints, TimeoutInfo timeout, boolean hasDeleteButton,
								   ButtonContent firstContent, ButtonContent previousContent, ButtonContent nextContent, ButtonContent lastContent, ButtonContent deleteContent,
								   @NotNull List> items, boolean usePaginator) {
		super(componentsService, constraints, timeout, 0, (a, b, c, d) -> new EmbedBuilder().build(), hasDeleteButton, firstContent, previousContent, nextContent, lastContent, deleteContent);

		if (items.isEmpty()) throw new IllegalStateException("No interactive menu items has been added");

		this.usePaginator = usePaginator;
		this.items = items;
		setSelectedItem(0);
	}

	@NotNull
	protected StringSelectMenu createSelectMenu() {
		return componentsService.ephemeralStringSelectMenu(selectBuilder -> {
			selectBuilder.bindTo(this::onItemSelected);
			selectBuilder.setOneUse(true);
			selectBuilder.setConstraints(constraints);

			final SelectOption[] options = new SelectOption[items.size()];
			for (int i = 0, itemsSize = items.size(); i < itemsSize; i++) {
				InteractiveMenuItem item = items.get(i);

				SelectOption option = item.content().toSelectOption(String.valueOf(i));
				if (i == selectedItem) option = option.withDefault(true);

				options[i] = option;
			}
			selectBuilder.addOptions(options);
		});
	}

	private void onItemSelected(StringSelectEvent event) {
		selectedItem = Integer.parseInt(event.getValues().get(0));

		event.editMessage(get()).queue();
	}

	public int getSelectedItem() {
		return selectedItem;
	}

	public SelectContent getSelectedItemContent() {
		return items.get(selectedItem).content();
	}

	/**
	 * Sets the interactive menu item number, this does not update the embed in any way,
	 * you can use {@link #get()} with an {@code editOriginal} in order to update the embed on Discord
	 *
	 * @param itemIndex Index of the item, from {@code 0} to {@code [the number of menus] - 1}
	 *
	 * @return This instance for chaining convenience
	 */
	public T setSelectedItem(int itemIndex) {
		Checks.check(itemIndex >= 0, "Item index cannot be negative");
		Checks.check(itemIndex < items.size(), "Item index cannot be higher than max items count (%d)", items.size());

		this.selectedItem = itemIndex;
		setMaxPages(items.get(itemIndex).maxPages());
		setPage(0);

		return (T) this;
	}

	/**
	 * Sets the interactive menu item number, via it's label (O(n) search), this does not update the embed in any way,
	 * you can use {@link #get()} with an {@link InteractionHook#editOriginal(MessageEditData)} in order to update the embed on Discord
	 *
	 * @param itemLabel Label of the item, must be a valid label from any of the interactive menu items
	 *
	 * @return This instance for chaining convenience
	 */
	public T setSelectedItem(String itemLabel) {
		Checks.notEmpty(itemLabel, "Item name cannot be empty");

		for (int i = 0; i < items.size(); i++) {
			final String label = items.get(i).content().label();

			if (label.equals(itemLabel)) {
				return setSelectedItem(i);
			}
		}

		throw new IllegalArgumentException("Item name '" + itemLabel + "' cannot be found in this interactive menu");
	}

	@Override
	public MessageEditData get() {
		onPreGet();

		if (usePaginator) {
			putComponents();
		}

		components.addComponents(createSelectMenu());

		final MessageEmbed embed = items.get(selectedItem).supplier().get((T) this, getPage(), messageBuilder, components);
		messageBuilder.setEmbeds(embed);
		messageBuilder.setComponents(components.getActionRows());

		onPostGet();

		return messageBuilder.build();
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy