Skip to content
This repository has been archived by the owner on Nov 1, 2023. It is now read-only.

Release 4.4.0 #67

Merged
merged 2 commits into from
Nov 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ pubspec.lock
.packages
private_test.dart
.vscode/
doc/**
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## 4.4.0
__14.11.022__

- feature: Add support for new select menus components (#62)

## 4.3.2
__09.11.2022__

Expand Down
4 changes: 2 additions & 2 deletions example/buttons_and_dropdowns.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ final singleCommand = SlashCommandBuilder("help", "This is example help command"
// Adding selects is as easy as adding buttons. Use MultiselectBuilder with custom id
// and list of multiselect options.
final firstRow = ComponentRowBuilder()
..addComponent(ButtonBuilder("This is button label", "thisisid", ComponentStyle.success))
..addComponent(ButtonBuilder("This is another button label", "thisisid2", ComponentStyle.success));
..addComponent(ButtonBuilder("This is button label", "thisisid", ButtonStyle.success))
..addComponent(ButtonBuilder("This is another button label", "thisisid2", ButtonStyle.primary));
final secondRow = ComponentRowBuilder()
..addComponent(MultiselectBuilder("customId", [
MultiselectOptionBuilder("example option 1", "option1"),
Expand Down
27 changes: 23 additions & 4 deletions lib/nyxx_interactions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ export 'src/builders/component_builder.dart'
MultiselectBuilder,
MultiselectOptionBuilder,
TextInputBuilder,
TextInputStyle;
TextInputStyle,
UserMultiSelectBuilder,
RoleMultiSelectBuilder,
MentionableMultiSelectBuilder,
ChannelMultiSelectBuilder;
export 'src/builders/modal_builder.dart' show ModalBuilder;
export 'src/builders/slash_command_builder.dart' show SlashCommandBuilder;
export 'src/events/interaction_event.dart'
Expand All @@ -27,7 +31,11 @@ export 'src/events/interaction_event.dart'
InteractionEventWithAcknowledge,
ISlashCommandInteractionEvent,
IModalResponseMixin,
IModalInteractionEvent;
IModalInteractionEvent,
IUserMultiSelectInteractionEvent,
IRoleMultiSelectInteractionEvent,
IMentionableMultiSelectInteractionEvent,
IChannelMultiSelectInteractionEvent;
export 'src/exceptions/already_responded.dart' show AlreadyRespondedError;
export 'src/exceptions/interaction_expired.dart' show InteractionExpiredError;
export 'src/exceptions/response_required.dart' show ResponseRequiredError;
Expand All @@ -40,8 +48,19 @@ export 'src/internal/utils.dart' show slashCommandNameRegex;
export 'src/models/arg_choice.dart' show IArgChoice;
export 'src/models/command_option.dart' show ICommandOption, CommandOptionType;
export 'src/models/interaction.dart'
show IComponentInteraction, IInteraction, IButtonInteraction, IMultiselectInteraction, ISlashCommandInteraction, IModalInteraction;
export 'src/models/interaction_data_resolved.dart' show IInteractionDataResolved, IPartialChannel;
show
IComponentInteraction,
IInteraction,
IButtonInteraction,
IMultiselectInteraction,
ISlashCommandInteraction,
IModalInteraction,
IUserMultiSelectInteraction,
IRoleMultiSelectInteraction,
IMentionableMultiSelectInteraction,
IChannelMultiSelectInteraction,
IResolvedSelectInteraction;
export 'src/models/interaction_data_resolved.dart' show IInteractionDataResolved, IPartialChannel, IInteractionSlashDataResolved;
export 'src/models/interaction_option.dart' show IInteractionOption;
export 'src/models/slash_command_permission.dart' show ISlashCommandPermissionOverride, ISlashCommandPermissionOverrides, SlashCommandPermissionType;
export 'src/models/slash_command.dart' show ISlashCommand;
Expand Down
108 changes: 78 additions & 30 deletions lib/src/builders/component_builder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,41 @@ abstract class ComponentBuilderAbstract extends Builder {
};
}

/// Allows to create multi select option for [MultiselectBuilder]
/// Abstract base class that represents any multi select builer.
abstract class MultiSelectBuilderAbstract extends ComponentBuilderAbstract {
/// Id for the select menu; max 100 characters.
final String customId;

/// Placeholder text if nothing is selected; max 150 characters.
String? placeholder;

/// Minimum number of items that must be chosen (defaults to 1); min 0, max 25.
int? minValues;

/// Maximum number of items that can be chosen (defaults to 1); max 25.
int? maxValues;

/// Whether select menu is disabled (defaults to `false`).
bool? disabled;

MultiSelectBuilderAbstract(this.customId) {
if (customId.length > 100) {
throw ArgumentError("Custom Id for Select cannot have more than 100 characters");
}
}

@override
Map<String, dynamic> build() => {
...super.build(),
'custom_id': customId,
if (placeholder != null) 'placeholder': placeholder,
if (minValues != null) 'min_values': minValues,
if (maxValues != null) 'max_values': maxValues,
if (disabled != null) 'disabled': disabled,
};
}

/// Allows to create multi select options for [MultiselectBuilder].
class MultiselectOptionBuilder extends Builder {
/// User-facing name of the option
final String label;
Expand Down Expand Up @@ -47,36 +81,15 @@ class MultiselectOptionBuilder extends Builder {
}

/// Allows to create multi select interactive components.
class MultiselectBuilder extends ComponentBuilderAbstract {
class MultiselectBuilder extends MultiSelectBuilderAbstract {
@override
ComponentType get type => ComponentType.select;

/// Max: 100 characters
final String customId;
ComponentType get type => ComponentType.multiSelect;

/// Max: 25
final List<MultiselectOptionBuilder> options = [];

/// Custom placeholder when nothing selected
String? placeholder;

/// Minimum number of options that can be chosen.
/// Default: 1, min: 1, max: 25
int? minValues;

/// Maximum numbers of options that can be chosen
/// Default: 1, min: 1, max: 25
int? maxValues;

/// Whether disable the select menu.
bool? disabled;

/// Creates instance of [MultiselectBuilder]
MultiselectBuilder(this.customId, [Iterable<MultiselectOptionBuilder>? options]) {
if (customId.length > 100) {
throw ArgumentError("Custom Id for Select cannot have more than 100 characters");
}

MultiselectBuilder(super.customId, [Iterable<MultiselectOptionBuilder>? options]) {
if (options != null) {
this.options.addAll(options);
}
Expand All @@ -88,12 +101,47 @@ class MultiselectBuilder extends ComponentBuilderAbstract {
@override
Map<String, dynamic> build() => {
...super.build(),
"custom_id": customId,
"options": [for (final optionBuilder in options) optionBuilder.build()],
if (placeholder != null) "placeholder": placeholder,
if (minValues != null) "min_values": minValues,
if (maxValues != null) "max_values": maxValues,
if (disabled != null) "disabled": disabled,
};
}

/// Builder to create select menu with [IUser]s inside of it.
class UserMultiSelectBuilder extends MultiSelectBuilderAbstract {
@override
ComponentType get type => ComponentType.userMultiSelect;

UserMultiSelectBuilder(super.customId);
}

/// Builder to create select menu with [IRole]s inside of it.
class RoleMultiSelectBuilder extends MultiSelectBuilderAbstract {
@override
ComponentType get type => ComponentType.roleMultiSelect;

RoleMultiSelectBuilder(super.customId);
}

/// Builder to create select menu with mentionables ([IRole]s & [IUser]s) inside of it.
class MentionableMultiSelectBuilder extends MultiSelectBuilderAbstract {
@override
ComponentType get type => ComponentType.mentionableMultiSelect;

MentionableMultiSelectBuilder(super.customId);
}

/// Builder to create select menu with [IChannel]s inside of it.
class ChannelMultiSelectBuilder extends MultiSelectBuilderAbstract {
@override
ComponentType get type => ComponentType.channelMultiSelect;

List<ChannelType>? channelTypes;

ChannelMultiSelectBuilder(super.customId, [this.channelTypes]);

@override
Map<String, dynamic> build() => {
...super.build(),
if (channelTypes != null) 'channel_types': channelTypes!.map((e) => e.value).toList(),
};
}

Expand Down
45 changes: 45 additions & 0 deletions lib/src/events/interaction_event.dart
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,51 @@ class MultiselectInteractionEvent extends ComponentInteractionEvent<IMultiselect
}
}

abstract class IUserMultiSelectInteractionEvent implements ComponentInteractionEvent<IUserMultiSelectInteraction> {}

class UserMultiSelectInteractionEvent extends ComponentInteractionEvent<IUserMultiSelectInteraction> implements IUserMultiSelectInteractionEvent {
@override
late final IUserMultiSelectInteraction interaction;

UserMultiSelectInteractionEvent(Interactions interactions, RawApiMap raw) : super(interactions, raw) {
interaction = UserMultiSelectInteraction(client, raw);
}
}

abstract class IRoleMultiSelectInteractionEvent implements ComponentInteractionEvent<IRoleMultiSelectInteraction> {}

class RoleMultiSelectInteractionEvent extends ComponentInteractionEvent<IRoleMultiSelectInteraction> implements IRoleMultiSelectInteractionEvent {
@override
late final IRoleMultiSelectInteraction interaction;

RoleMultiSelectInteractionEvent(Interactions interactions, RawApiMap raw) : super(interactions, raw) {
interaction = RoleMultiSelectInteraction(client, raw);
}
}

abstract class IMentionableMultiSelectInteractionEvent implements ComponentInteractionEvent<IMentionableMultiSelectInteraction> {}

class MentionableMultiSelectInteractionEvent extends ComponentInteractionEvent<IMentionableMultiSelectInteraction>
implements IMentionableMultiSelectInteractionEvent {
@override
late final IMentionableMultiSelectInteraction interaction;

MentionableMultiSelectInteractionEvent(Interactions interactions, RawApiMap raw) : super(interactions, raw) {
interaction = MentionableMultiSelectInteraction(client, raw);
}
}

abstract class IChannelMultiSelectInteractionEvent implements ComponentInteractionEvent<IChannelMultiSelectInteraction> {}

class ChannelMultiSelectInteractionEvent extends ComponentInteractionEvent<IChannelMultiSelectInteraction> implements IChannelMultiSelectInteractionEvent {
@override
late final IChannelMultiSelectInteraction interaction;

ChannelMultiSelectInteractionEvent(Interactions interactions, RawApiMap raw) : super(interactions, raw) {
interaction = ChannelMultiSelectInteraction(client, raw);
}
}

mixin IModalResponseMixin {
IInteractions get interactions;
IInteraction get interaction;
Expand Down
90 changes: 90 additions & 0 deletions lib/src/interactions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,18 @@ abstract class IInteractions {
/// Register callback for dropdown event for given [id]
void registerMultiselectHandler(String id, MultiselectInteractionHandler handler);

/// Register callback for user dropdown event for given [id].
void registerUserMultiSelectHandler(String id, UserMultiSelectInteractionHandler handler);

/// Register callback for role dropdown event for given [id].
void registerRoleMultiSelectHandler(String id, RoleMultiSelectInteractionHandler handler);

/// Register callback for mentionable dropdown event for given [id].
void registerMentionableMultiSelectHandler(String id, MentionableMultiSelectInteractionHandler handler);

/// Register callback for channel dropdown event for given [id].
void registerChannelMultiSelectHandler(String id, ChannelMultiSelectInteractionHandler handler);

/// Allows to register new [SlashCommandBuilder]
void registerSlashCommand(SlashCommandBuilder slashCommandBuilder);

Expand Down Expand Up @@ -89,6 +101,10 @@ class Interactions implements IInteractions {
final _buttonHandlers = <String, ButtonInteractionHandler>{};
final _autocompleteHandlers = <String, AutocompleteInteractionHandler>{};
final _multiselectHandlers = <String, MultiselectInteractionHandler>{};
final _userMultiSelectHandlers = <String, UserMultiSelectInteractionHandler>{};
final _roleMultiSelectHandlers = <String, RoleMultiSelectInteractionHandler>{};
final _mentionableMultiSelectHandlers = <String, MentionableMultiSelectInteractionHandler>{};
final _channelMultiSelectHandlers = <String, ChannelMultiSelectInteractionHandler>{};

final permissionOverridesCache = <Snowflake, Map<Snowflake, SlashCommandPermissionOverrides>>{};

Expand Down Expand Up @@ -133,12 +149,30 @@ class Interactions implements IInteractions {
final componentType = rawData["d"]["data"]["component_type"] as int;

switch (componentType) {
// ComponentType.button
case 2:
(events as EventController).onButtonEventController.add(ButtonInteractionEvent(this, rawData["d"] as Map<String, dynamic>));
break;
// ComponentType.select
case 3:
(events as EventController).onMultiselectEventController.add(MultiselectInteractionEvent(this, rawData["d"] as Map<String, dynamic>));
break;
// ComponentType.userMultiSelect
case 5:
(events as EventController).onUserMultiSelectController.add(UserMultiSelectInteractionEvent(this, rawData['d'] as RawApiMap));
break;
// ComponentType.roleMultiSelect
case 6:
(events as EventController).onRoleMultiSelectController.add(RoleMultiSelectInteractionEvent(this, rawData['d'] as RawApiMap));
break;
// ComponentType.mentionableMultiSelect
case 7:
(events as EventController).onMentionableMultiSelectController.add(MentionableMultiSelectInteractionEvent(this, rawData['d'] as RawApiMap));
break;
// ComponentType.channelMultiSelect
case 8:
(events as EventController).onChannelMultiSelectController.add(ChannelMultiSelectInteractionEvent(this, rawData['d'] as RawApiMap));
break;
default:
_logger.warning("Unknown componentType type: [$componentType]; Payload: ${jsonEncode(rawData)}");
}
Expand Down Expand Up @@ -254,6 +288,50 @@ class Interactions implements IInteractions {
});
}

if (_userMultiSelectHandlers.isNotEmpty) {
events.onUserMultiSelect.listen((event) {
if (_userMultiSelectHandlers.containsKey(event.interaction.customId)) {
_logger.info("Executing user select with id [${event.interaction.customId}]");
_userMultiSelectHandlers[event.interaction.customId]!(event);
} else {
_logger.warning("Received event for unknown user select: ${event.interaction.customId}");
}
});
}

if (_roleMultiSelectHandlers.isNotEmpty) {
events.onRoleMultiSelect.listen((event) {
if (_roleMultiSelectHandlers.containsKey(event.interaction.customId)) {
_logger.info("Executing role select with id [${event.interaction.customId}]");
_roleMultiSelectHandlers[event.interaction.customId]!(event);
} else {
_logger.warning("Received event for unknown role select: ${event.interaction.customId}");
}
});
}

if (_mentionableMultiSelectHandlers.isNotEmpty) {
events.onMentionableMultiSelect.listen((event) {
if (_mentionableMultiSelectHandlers.containsKey(event.interaction.customId)) {
_logger.info("Executing mentionable select with id [${event.interaction.customId}]");
_mentionableMultiSelectHandlers[event.interaction.customId]!(event);
} else {
_logger.warning("Received event for unknown mentionable select: ${event.interaction.customId}");
}
});
}

if (_channelMultiSelectHandlers.isNotEmpty) {
events.onChannelMultiSelect.listen((event) {
if (_channelMultiSelectHandlers.containsKey(event.interaction.customId)) {
_logger.info("Executing channel select with id [${event.interaction.customId}]");
_channelMultiSelectHandlers[event.interaction.customId]!(event);
} else {
_logger.warning("Received event for unknown channel select: ${event.interaction.customId}");
}
});
}

if (_autocompleteHandlers.isNotEmpty) {
events.onAutocompleteEvent.listen((event) {
final name = event.focusedOption.name;
Expand Down Expand Up @@ -289,6 +367,18 @@ class Interactions implements IInteractions {
@override
void registerSlashCommandHandler(String id, SlashCommandHandler handler) => _commandHandlers[id] = handler;

@override
void registerRoleMultiSelectHandler(String id, RoleMultiSelectInteractionHandler handler) => _roleMultiSelectHandlers[id] = handler;

@override
void registerUserMultiSelectHandler(String id, UserMultiSelectInteractionHandler handler) => _userMultiSelectHandlers[id] = handler;

@override
void registerMentionableMultiSelectHandler(String id, MentionableMultiSelectInteractionHandler handler) => _mentionableMultiSelectHandlers[id] = handler;

@override
void registerChannelMultiSelectHandler(String id, ChannelMultiSelectInteractionHandler handler) => _channelMultiSelectHandlers[id] = handler;

/// Deletes global command
@override
Future<void> deleteGlobalCommand(Snowflake commandId) => interactionsEndpoints.deleteGlobalCommand(client.appId, commandId);
Expand Down
Loading