PluralKit/PluralKit.Bot/Interactive/YesNoPrompt.cs

131 lines
3.6 KiB
C#
Raw Normal View History

using Autofac;
2021-05-30 16:45:29 +02:00
2025-03-29 17:55:01 +00:00
using Myriad.Cache;
using Myriad.Gateway;
using Myriad.Rest.Types;
2021-05-30 16:45:29 +02:00
using Myriad.Types;
using PluralKit.Core;
namespace PluralKit.Bot.Interactive;
public class YesNoPrompt: BaseInteractive
2021-05-30 16:45:29 +02:00
{
public YesNoPrompt(Context ctx) : base(ctx)
2021-05-30 16:45:29 +02:00
{
User = ctx.Author.Id;
}
2021-05-30 16:45:29 +02:00
public bool? Result { get; private set; }
public ulong? User { get; set; }
public string Message { get; set; } = "Are you sure?";
2021-05-30 16:45:29 +02:00
public string AcceptLabel { get; set; } = "OK";
public ButtonStyle AcceptStyle { get; set; } = ButtonStyle.Primary;
2021-08-27 11:03:47 -04:00
public string CancelLabel { get; set; } = "Cancel";
public ButtonStyle CancelStyle { get; set; } = ButtonStyle.Secondary;
public override async Task Start()
{
AddButton(ctx => OnButtonClick(ctx, true), AcceptLabel, AcceptStyle);
AddButton(ctx => OnButtonClick(ctx, false), CancelLabel, CancelStyle);
AllowedMentions mentions = null;
if (User != _ctx.Author.Id)
mentions = new AllowedMentions { Users = new[] { User!.Value } };
2021-05-30 16:45:29 +02:00
await Send(Message, mentions: mentions);
}
2021-05-30 16:45:29 +02:00
private async Task OnButtonClick(InteractionContext ctx, bool result)
{
if (ctx.User.Id != User)
{
await Error(ctx, Errors.InteractionWrongAccount(User ?? 0));
return;
}
Result = result;
await Finish(ctx);
}
private bool MessagePredicate(MessageCreateEvent e)
{
if (e.ChannelId != _ctx.Channel.Id) return false;
if (e.Author.Id != User) return false;
var response = e.Content.ToLowerInvariant();
if (response == "y" || response == "yes")
{
Result = true;
return true;
}
if (response == "n" || response == "no")
{
Result = false;
return true;
}
2025-03-29 17:55:01 +00:00
// no need to reawait message
// gateway will already have sent us only matching messages
return false;
}
public new async Task Run()
{
// todo: can we split this up somehow so it doesn't need to be *completely* copied from BaseInteractive?
var cts = new CancellationTokenSource(Timeout.ToTimeSpan());
if (_running)
throw new InvalidOperationException("Action is already running");
_running = true;
2021-08-27 11:03:47 -04:00
var queue = _ctx.Services.Resolve<HandlerQueue<MessageCreateEvent>>();
async Task WaitForMessage()
{
try
{
2025-03-29 17:55:01 +00:00
// check if http gateway and set listener
// todo: this one needs to handle options for message
if (_ctx.Cache is HttpDiscordCache)
await (_ctx.Cache as HttpDiscordCache).AwaitMessage(
_ctx.Guild?.Id ?? 0,
_ctx.Channel.Id,
_ctx.Author.Id,
Timeout,
options: new[] { "yes", "y", "no", "n" }
);
await queue.WaitFor(MessagePredicate, Timeout, cts.Token);
}
catch (TimeoutException e)
{
if (e.Message != "HandlerQueue#WaitFor timed out")
throw;
}
}
2021-08-27 11:03:47 -04:00
await Start();
var messageDispatch = WaitForMessage();
cts.Token.Register(() => _tcs.TrySetException(new TimeoutException("YesNoPrompt timed out")));
try
{
var doneTask = await Task.WhenAny(_tcs.Task, messageDispatch);
}
finally
2021-05-30 16:45:29 +02:00
{
await Finish();
Cleanup();
2021-05-30 16:45:29 +02:00
}
}
}