diff --git a/src/EllieBot/Common/Interaction/EllieInteraction.cs b/src/EllieBot/Common/Interaction/EllieInteraction.cs new file mode 100644 index 0000000..e77fede --- /dev/null +++ b/src/EllieBot/Common/Interaction/EllieInteraction.cs @@ -0,0 +1,82 @@ +namespace EllieBot; + +public sealed class EllieInteraction +{ + private readonly ulong _authorId; + private readonly ButtonBuilder _button; + private readonly Func _onClick; + private readonly bool _onlyAuthor; + public DiscordSocketClient Client { get; } + + private readonly TaskCompletionSource _interactionCompletedSource; + + private IUserMessage message = null!; + + public EllieInteraction(DiscordSocketClient client, + ulong authorId, + ButtonBuilder button, + Func onClick, + bool onlyAuthor) + { + _authorId = authorId; + _button = button; + _onClick = onClick; + _onlyAuthor = onlyAuthor; + _interactionCompletedSource = new(TaskCreationOptions.RunContinuationsAsynchronously); + + Client = client; + } + + public async Task RunAsync(IUserMessage msg) + { + message = msg; + + Client.InteractionCreated += OnInteraction; + await Task.WhenAny(Task.Delay(15_000), _interactionCompletedSource.Task); + Client.InteractionCreated -= OnInteraction; + + await msg.ModifyAsync(m => m.Components = new ComponentBuilder().Build()); + } + + private Task OnInteraction(SocketInteraction arg) + { + if (arg is not SocketMessageComponent smc) + return Task.CompletedTask; + + if (smc.Message.Id != message.Id) + return Task.CompletedTask; + + if (_onlyAuthor && smc.User.Id != _authorId) + return Task.CompletedTask; + + if (smc.Data.CustomId != _button.CustomId) + return Task.CompletedTask; + + _ = Task.Run(async () => + { + await ExecuteOnActionAsync(smc); + + // this should only be a thing on single-response buttons + _interactionCompletedSource.TrySetResult(true); + + if (!smc.HasResponded) + { + await smc.DeferAsync(); + } + }); + + return Task.CompletedTask; + } + + + public MessageComponent CreateComponent() + { + var comp = new ComponentBuilder() + .WithButton(_button); + + return comp.Build(); + } + + public Task ExecuteOnActionAsync(SocketMessageComponent smc) + => _onClick(smc); +} \ No newline at end of file diff --git a/src/EllieBot/Common/Interaction/EllieInteractionData.cs b/src/EllieBot/Common/Interaction/EllieInteractionData.cs new file mode 100644 index 0000000..3e25606 --- /dev/null +++ b/src/EllieBot/Common/Interaction/EllieInteractionData.cs @@ -0,0 +1,8 @@ +namespace EllieBot; + +/// +/// Represents essential interacation data +/// +/// Emote which will show on a button +/// Custom interaction id +public record EllieInteractionData(IEmote Emote, string CustomId, string? Text = null); \ No newline at end of file diff --git a/src/EllieBot/Common/Interaction/EllieInteractionService.cs b/src/EllieBot/Common/Interaction/EllieInteractionService.cs new file mode 100644 index 0000000..3e97ec1 --- /dev/null +++ b/src/EllieBot/Common/Interaction/EllieInteractionService.cs @@ -0,0 +1,20 @@ +namespace EllieBot; + +public class EllieInteractionService : IEllieInteractionService, IEService +{ + private readonly DiscordSocketClient _client; + + public EllieInteractionService(DiscordSocketClient client) + { + _client = client; + } + + public EllieInteraction Create( + ulong userId, + SimpleInteraction inter) + => new EllieInteraction(_client, + userId, + inter.Button, + inter.TriggerAsync, + onlyAuthor: true); +} \ No newline at end of file diff --git a/src/EllieBot/Common/Interaction/IEllieInteractionService.cs b/src/EllieBot/Common/Interaction/IEllieInteractionService.cs new file mode 100644 index 0000000..03a3ba1 --- /dev/null +++ b/src/EllieBot/Common/Interaction/IEllieInteractionService.cs @@ -0,0 +1,8 @@ +namespace EllieBot; + +public interface IEllieInteractionService +{ + public EllieInteraction Create( + ulong userId, + SimpleInteraction inter); +} \ No newline at end of file diff --git a/src/EllieBot/Common/Interaction/SimpleInteraction.cs b/src/EllieBot/Common/Interaction/SimpleInteraction.cs new file mode 100644 index 0000000..045d4fc --- /dev/null +++ b/src/EllieBot/Common/Interaction/SimpleInteraction.cs @@ -0,0 +1,20 @@ +namespace EllieBot; + +public class SimpleInteraction +{ + public ButtonBuilder Button { get; } + private readonly Func _onClick; + private readonly T? _state; + + public SimpleInteraction(ButtonBuilder button, Func onClick, T? state = default) + { + Button = button; + _onClick = onClick; + _state = state; + } + + public async Task TriggerAsync(SocketMessageComponent smc) + { + await _onClick(smc, _state!); + } +} \ No newline at end of file