Skip to content

Redesigning Interactivity #2153

@OoLunar

Description

@OoLunar

Summary

Per "As some of y'all may know, Interactivity has had multiple bugs over the years, most of them being a result from the design. Since we haven't really maintained it recently - or even added more features to it - should we completely rewrite it from scratch?", there were 135 votes to merge Interactivity with the new Commands extension, 32 votes to keep Interactivity separate and rewrite it from scratch and 6 votes to just keep the current implementation and fix the bugs.

A screenshot of the above mentioned poll with reactions/votes shown below the message.

We've decided to do the following solution, quoted directly from @akiraveliara:

if i had to design this for v6, i would make an Interactivity.Stateful and an Interactivity.Stateless internal package (PrivateAssets="all")
and have Commands include and frontend the first one
have Interactivity proper include and frontend both of them
i do respect that interactivity integrated into and understanding commands is really good UX
especially if it can automatically decide the "right thing" for different contexts
(though, that stuff will need some work to work with custom contexts)

I will be working on the DSharpPlus.Interactivity.Stateful package, which will directly interface with DSharpPlus.Commands. Here is the following API:

public async ValueTask PromptAsync(CommandContext context, string question, Func<PromptData, ValueTask> callback);
public async ValueTask ChooseAsync(CommandContext context, string question, IReadOnlyList<string> answers, Func<ChooseData, ValueTask> callback);
public async ValueTask ConfirmAsync(CommandContext context, string question, Func<ConfirmData ValueTask> callback);
public async ValueTask PaginateAsync(CommandContext context, IEnumerable<DiscordMessageBuilder> pages, PaginationControls? controls = null);

Note

ALL methods above are non-blocking.

PromptAsync

This method will utilize each processor's available feature set to nicely present the question to the user:

  • Interaction-based contexts will use modals
  • Text command-based contexts will use modals via a button

Prompts can timeout and it will be the callback's responsibility to check for that by reading the PromptData.IsTimedOut property.

ChooseAsync

The user will be presented with multiple choices through a select component and will return a single (or optionally multiple) responses within the callback data. This method has the same API timeout behavior as the PromptAsync method.

ConfirmAsync

This method will ask the user to confirm their decision, which will be returned via a bool property within the callback data. This method has the same API timeout behavior as the PromptAsync method.

PaginateAsync

PaginateAsync is nearly identical to the existing pagination API that you're already familiar from the DSharpPlus.Interactivity extension. The PaginationControls? controls = null parameter will act as an override for the default PaginationControls defined within the interactivity/commands (tbd) configuration. The PaginationControls contains the control buttons (previous page, stop, next page, etc) for the user, which will attempt to be appended onto the message builder and will throw when it fails. PaginationControls will also contain a property (likely flags enum or delegate) that defines what to do when a non-author of a pagination clicks on the control buttons. The default implementations available are:

  • Act as the author
  • Copy and respond (non)ephemerally
  • Error ephemerally
  • Ignore

Notes

If there are any other API methods that you would like to see on CommandContext specifically, please comment down below.

Metadata

Metadata

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions