1+ package org .togetherjava .tjbot .commands ;
2+
3+ import net .dv8tion .jda .api .events .interaction .command .SlashCommandInteractionEvent ;
4+ import net .dv8tion .jda .api .events .interaction .component .ButtonInteractionEvent ;
5+ import net .dv8tion .jda .api .events .interaction .component .SelectMenuInteractionEvent ;
6+ import net .dv8tion .jda .api .interactions .commands .Command ;
7+ import net .dv8tion .jda .api .interactions .commands .build .CommandData ;
8+ import org .jetbrains .annotations .Contract ;
9+ import org .jetbrains .annotations .NotNull ;
10+ import org .togetherjava .tjbot .commands .componentids .ComponentId ;
11+ import org .togetherjava .tjbot .commands .componentids .ComponentIdGenerator ;
12+ import org .togetherjava .tjbot .commands .componentids .Lifespan ;
13+
14+ import java .util .Arrays ;
15+ import java .util .List ;
16+ import java .util .Objects ;
17+
18+ /**
19+ * Adapter implementation of a {@link BotCommand}. The minimal setup only requires implementation of
20+ * their respective command method. A new command can then be registered by adding it to
21+ * {@link Features}.
22+ * <p>
23+ * Further, {@link #onButtonClick(ButtonInteractionEvent, List)} and
24+ * {@link #onSelectionMenu(SelectMenuInteractionEvent, List)} can be overridden if desired. The
25+ * default implementation is empty, the adapter will not react to such events.
26+ * <p>
27+ * <p>
28+ * The adapter manages some getters for you, you've to create the {@link CommandData} yourself. See
29+ * {@link #BotCommandAdapter(CommandData, CommandVisibility)}} for more info on that. Minimal
30+ * modifications can be done on the {@link CommandData} returned by {@link #getData()}.
31+ * <p>
32+ * <p>
33+ * If implementations want to add buttons or selection menus, it is highly advised to use component
34+ * IDs generated by {@link #generateComponentId(String...)}, which will automatically create IDs
35+ * that are valid per {@link SlashCommand#onSlashCommand(SlashCommandInteractionEvent)}.
36+ * <p>
37+ * <p>
38+ * Some example commands are available in {@link org.togetherjava.tjbot.commands.basic}.
39+ * Registration of commands can be done in {@link Features}.
40+ */
41+ public abstract class BotCommandAdapter implements BotCommand {
42+ private final String name ;
43+ private final Command .Type type ;
44+ private final CommandVisibility visibility ;
45+ private final CommandData data ;
46+ private ComponentIdGenerator componentIdGenerator ;
47+
48+ /**
49+ * Creates a new adapter with the given data.
50+ *
51+ * @param data the data for this command
52+ * @param visibility the visibility of the command
53+ */
54+ protected BotCommandAdapter (@ NotNull CommandData data , @ NotNull CommandVisibility visibility ) {
55+ this .data = Objects .requireNonNull (data , "The data shouldn't be null" );
56+ this .visibility = Objects .requireNonNull (visibility , "The visibility shouldn't be null" );
57+
58+ this .name = data .getName ();
59+ this .type = data .getType ();
60+ }
61+
62+ @ Override
63+ public final @ NotNull String getName () {
64+ return name ;
65+ }
66+
67+ @ NotNull
68+ @ Override
69+ public Command .Type getType () {
70+ return type ;
71+ }
72+
73+ @ Override
74+ public final @ NotNull CommandVisibility getVisibility () {
75+ return visibility ;
76+ }
77+
78+ @ Override
79+ public @ NotNull CommandData getData () {
80+ return data ;
81+ }
82+
83+ @ Override
84+ @ Contract (mutates = "this" )
85+ public final void acceptComponentIdGenerator (@ NotNull ComponentIdGenerator generator ) {
86+ componentIdGenerator =
87+ Objects .requireNonNull (generator , "The given generator cannot be null" );
88+ }
89+
90+ @ SuppressWarnings ("NoopMethodInAbstractClass" )
91+ @ Override
92+ public void onButtonClick (@ NotNull ButtonInteractionEvent event , @ NotNull List <String > args ) {
93+ // Adapter does not react by default, subclasses may change this behavior
94+ }
95+
96+ @ SuppressWarnings ("NoopMethodInAbstractClass" )
97+ @ Override
98+ public void onSelectionMenu (@ NotNull SelectMenuInteractionEvent event ,
99+ @ NotNull List <String > args ) {
100+ // Adapter does not react by default, subclasses may change this behavior
101+ }
102+
103+ /**
104+ * Helper method to generate component IDs that are considered valid per
105+ * {@link #acceptComponentIdGenerator(ComponentIdGenerator)}.
106+ * <p>
107+ * They can be used to create buttons or selection menus and transport additional data
108+ * throughout the event (e.g. the user id who created the button dialog).
109+ * <p>
110+ * IDs generated by this method have a regular lifespan, meaning that they might get evicted and
111+ * expire after not being used for a long time. Use
112+ * {@link #generateComponentId(Lifespan, String...)} to set other lifespans, if desired.
113+ *
114+ * @param args the extra arguments that should be part of the ID
115+ * @return the generated component ID
116+ */
117+ @ SuppressWarnings ("OverloadedVarargsMethod" )
118+ protected final @ NotNull String generateComponentId (@ NotNull String ... args ) {
119+ return generateComponentId (Lifespan .REGULAR , args );
120+ }
121+
122+ /**
123+ * Helper method to generate component IDs that are considered valid per
124+ * {@link #acceptComponentIdGenerator(ComponentIdGenerator)}.
125+ * <p>
126+ * They can be used to create buttons or selection menus and transport additional data
127+ * throughout the event (e.g. the user id who created the button dialog).
128+ *
129+ * @param lifespan the lifespan of the component id, controls when an id that was not used for a
130+ * long time might be evicted and expire
131+ * @param args the extra arguments that should be part of the ID
132+ * @return the generated component ID
133+ */
134+ @ SuppressWarnings ({"OverloadedVarargsMethod" , "WeakerAccess" })
135+ protected final @ NotNull String generateComponentId (@ NotNull Lifespan lifespan ,
136+ @ NotNull String ... args ) {
137+ return componentIdGenerator .generate (new ComponentId (getName (), Arrays .asList (args )),
138+ lifespan );
139+ }
140+ }
0 commit comments