From 64ed5311cb764b353d968be1667276051e89de0b Mon Sep 17 00:00:00 2001 From: Matthew Trip Date: Sun, 5 Jul 2020 14:27:04 +0100 Subject: [PATCH 01/22] Internal => Public --- SampleApp/Program.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SampleApp/Program.cs b/SampleApp/Program.cs index 92f6399..19921a5 100644 --- a/SampleApp/Program.cs +++ b/SampleApp/Program.cs @@ -1,4 +1,4 @@ -using Discord; +using Discord; using Discord.Addons.Interactive; using Discord.Commands; using Discord.WebSocket; @@ -10,7 +10,7 @@ namespace SampleApp { - internal class Program + public class Program { private static void Main(string[] args) => new Program().MainAsync().GetAwaiter().GetResult(); From 22149a4b428fed929379043ce9f3ce545144465f Mon Sep 17 00:00:00 2001 From: Matthew Trip Date: Sun, 5 Jul 2020 14:27:46 +0100 Subject: [PATCH 02/22] Implement Async Main --- SampleApp/Program.cs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/SampleApp/Program.cs b/SampleApp/Program.cs index 19921a5..e6226a4 100644 --- a/SampleApp/Program.cs +++ b/SampleApp/Program.cs @@ -12,14 +12,11 @@ namespace SampleApp { public class Program { - private static void Main(string[] args) - => new Program().MainAsync().GetAwaiter().GetResult(); - - private DiscordSocketClient _client; - private CommandService _commands; - private IServiceProvider _services; - - public async Task MainAsync() + private static DiscordSocketClient _client; + private static CommandService _commands; + private static IServiceProvider _services; + + public static async Task Main(string[] args) { var token = File.ReadAllText("token.ignore"); From 5f8ab7a5371bf694657e03de95005cbc3e9b8f32 Mon Sep 17 00:00:00 2001 From: Matthew Trip Date: Sun, 5 Jul 2020 14:28:39 +0100 Subject: [PATCH 03/22] Improve Command Handling --- SampleApp/Program.cs | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/SampleApp/Program.cs b/SampleApp/Program.cs index e6226a4..44423b7 100644 --- a/SampleApp/Program.cs +++ b/SampleApp/Program.cs @@ -46,14 +46,19 @@ public static async Task Main(string[] args) public async Task HandleCommandAsync(SocketMessage m) { - if (!(m is SocketUserMessage msg)) return; - if (msg.Author.IsBot) return; - + if (!(socketMessage is SocketUserMessage message) + || !(message.Author is IGuildUser guildUser) + || guildUser.IsBot) + { + return; + } + var argPos = 0; - if (!(msg.HasStringPrefix("i~>", ref argPos))) return; - - var context = new SocketCommandContext(_client, msg); - await _commands.ExecuteAsync(context, argPos, _services); + if (message.HasStringPrefix("!!", ref argPos)) + { + var context = new SocketCommandContext(_client, message); + await _commands.ExecuteAsync(context, argPos, _services); + } } } } \ No newline at end of file From 35506163ad2d11a278e334f18064c253450a8b89 Mon Sep 17 00:00:00 2001 From: Matthew Trip Date: Sun, 5 Jul 2020 14:29:00 +0100 Subject: [PATCH 04/22] Separate Service Collection Method --- SampleApp/Program.cs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/SampleApp/Program.cs b/SampleApp/Program.cs index 44423b7..e9144c1 100644 --- a/SampleApp/Program.cs +++ b/SampleApp/Program.cs @@ -44,7 +44,19 @@ public static async Task Main(string[] args) await Task.Delay(-1); } - public async Task HandleCommandAsync(SocketMessage m) + private static IServiceProvider ConfigureServices() + { + var client = new DiscordSocketClient(); + var commands = new CommandService(); + + return new ServiceCollection() + .AddSingleton(client) + .AddSingleton(commands) + .AddSingleton() + .BuildServiceProvider(); + } + + private static async Task HandleCommandAsync(SocketMessage socketMessage) { if (!(socketMessage is SocketUserMessage message) || !(message.Author is IGuildUser guildUser) From 94f91582531b6730d59f4b861df77247f478d9df Mon Sep 17 00:00:00 2001 From: Matthew Trip Date: Sun, 5 Jul 2020 14:29:24 +0100 Subject: [PATCH 05/22] Separate Service Collection Method --- SampleApp/Program.cs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/SampleApp/Program.cs b/SampleApp/Program.cs index e9144c1..bf45b56 100644 --- a/SampleApp/Program.cs +++ b/SampleApp/Program.cs @@ -30,15 +30,9 @@ public static async Task Main(string[] args) await _client.LoginAsync(TokenType.Bot, token); await _client.StartAsync(); - - _services = new ServiceCollection() - .AddSingleton(_client) - .AddSingleton() - .BuildServiceProvider(); - - _commands = new CommandService(); - await _commands.AddModulesAsync(Assembly.GetEntryAssembly(), _services); - + + await _commands.AddModulesAsync(typeof(Program).Assembly, _services); + _client.MessageReceived += HandleCommandAsync; await Task.Delay(-1); From 80a9fc37a2e4ba2dcd37fe83d6d36687674854f8 Mon Sep 17 00:00:00 2001 From: Matthew Trip Date: Sun, 5 Jul 2020 14:30:58 +0100 Subject: [PATCH 06/22] Initialize Fields Via Service Collection --- SampleApp/Program.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/SampleApp/Program.cs b/SampleApp/Program.cs index bf45b56..e7df156 100644 --- a/SampleApp/Program.cs +++ b/SampleApp/Program.cs @@ -18,9 +18,10 @@ public class Program public static async Task Main(string[] args) { - var token = File.ReadAllText("token.ignore"); - - _client = new DiscordSocketClient(); + _services = ConfigureServices(); + + _client = _services.GetRequiredService(); + _commands = _services.GetRequiredService(); _client.Log += log => { From d32197a9dbf221c8f1743a2bbe74eaddcd1f4d33 Mon Sep 17 00:00:00 2001 From: Matthew Trip Date: Sun, 5 Jul 2020 14:31:37 +0100 Subject: [PATCH 07/22] Unused Namespace --- SampleApp/Program.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/SampleApp/Program.cs b/SampleApp/Program.cs index e7df156..7120b77 100644 --- a/SampleApp/Program.cs +++ b/SampleApp/Program.cs @@ -5,7 +5,6 @@ using Microsoft.Extensions.DependencyInjection; using System; using System.IO; -using System.Reflection; using System.Threading.Tasks; namespace SampleApp From e11c463ac95a403791524f18146339fc85373507 Mon Sep 17 00:00:00 2001 From: Matthew Trip Date: Sun, 5 Jul 2020 14:33:03 +0100 Subject: [PATCH 08/22] Re-introduce Token Variable --- SampleApp/Program.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/SampleApp/Program.cs b/SampleApp/Program.cs index 7120b77..7c92d3d 100644 --- a/SampleApp/Program.cs +++ b/SampleApp/Program.cs @@ -1,4 +1,4 @@ -using Discord; +using Discord; using Discord.Addons.Interactive; using Discord.Commands; using Discord.WebSocket; @@ -28,6 +28,8 @@ public static async Task Main(string[] args) return Task.CompletedTask; }; + var token = File.ReadAllText("token.ignore"); + await _client.LoginAsync(TokenType.Bot, token); await _client.StartAsync(); From 722a84eab598e5e4d218c4f0be9cbc7168259d0a Mon Sep 17 00:00:00 2001 From: Matthew Trip Date: Mon, 6 Jul 2020 10:43:43 +0100 Subject: [PATCH 09/22] Rework Paginator Example --- SampleApp/Modules/SampleModule.cs | 50 +++++++++++++++++++++++++++---- 1 file changed, 45 insertions(+), 5 deletions(-) diff --git a/SampleApp/Modules/SampleModule.cs b/SampleApp/Modules/SampleModule.cs index fb4bd49..c0e15a4 100644 --- a/SampleApp/Modules/SampleModule.cs +++ b/SampleApp/Modules/SampleModule.cs @@ -1,9 +1,11 @@ -using Discord; +using Discord; using Discord.Addons.Interactive; using Discord.Addons.Interactive.InlineReaction; using Discord.Commands; using System; +using System.Collections.Generic; using System.Threading.Tasks; +using Discord.Addons.Interactive.Paginator; namespace SampleApp.Modules { @@ -33,14 +35,52 @@ public async Task Test_NextMessageAsync() } // PagedReplyAsync will send a paginated message to the channel - // You can customize the paginator by creating a PaginatedMessage object - // You can customize the criteria for the paginator as well, which defaults to restricting to the source user + // You can customize the paginator by creating a EmbedPage objects, which each represent a single page. There + // are lots of options for you to explore. + // You can customize the criteria for the paginator as well, which defaults to restricting to the source user. // This method will not block. [Command("paginator")] public async Task Test_Paginator() { - var pages = new[] { "Page 1", "Page 2", "Page 3", "aaaaaa", "Page 5" }; - await PagedReplyAsync(pages); + // Use an object initializer ideally. This code is written the way it is for demonstration purposes. + var pages = new List(); + + var p1 = new EmbedPage + { + Title = "First Page", + Description = "Interesting Information", + }; + + var p2 = new EmbedPage + { + Title = "Second Page", + AlternateAuthorTitle = Context.User.Username, + AlteranteAuthorIcon = Context.User.GetAvatarUrl() + }; + + var p3 = new EmbedPage + { + ImageUrl = "https://img2.gelbooru.com/samples/a5/9c/sample_a59c7a3eefe67b062ea37825ce6cea83.jpg", + }; + + pages.Add(p1); + pages.Add(p2); + pages.Add(p3); + + var options = new PaginatedAppearanceOptions + { + InformationText = "This fancy embed is called a Paginator", + Timeout = TimeSpan.FromSeconds(30), + }; + + var pagedEmbed = new PaginatedMessage + { + Pages = pages, + Options = options, + FooterOverride = new EmbedFooterBuilder().WithText("Nice Footer") + }; + + await PagedReplyAsync(pagedEmbed, new ReactionList()); } // InlineReactionReplyAsync will send a message and adds reactions on it. From bf6b101e224b4be81b2e00017cbb3d749e6c8889 Mon Sep 17 00:00:00 2001 From: Matthew Trip Date: Mon, 6 Jul 2020 10:44:02 +0100 Subject: [PATCH 10/22] Cleaning --- SampleApp/Modules/SampleModule.cs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/SampleApp/Modules/SampleModule.cs b/SampleApp/Modules/SampleModule.cs index c0e15a4..87a796a 100644 --- a/SampleApp/Modules/SampleModule.cs +++ b/SampleApp/Modules/SampleModule.cs @@ -1,4 +1,4 @@ -using Discord; +using Discord; using Discord.Addons.Interactive; using Discord.Addons.Interactive.InlineReaction; using Discord.Commands; @@ -11,7 +11,7 @@ namespace SampleApp.Modules { public class SampleModule : InteractiveBase { - // DeleteAfterAsync will send a message and asynchronously delete it after the timeout has popped + // DeleteAfterAsync will send a message and asynchronously delete it after the timeout has popped. // This method will not block. [Command("delete")] public async Task Test_DeleteAfterAsync() @@ -21,17 +21,22 @@ public async Task Test_DeleteAfterAsync() } // NextMessageAsync will wait for the next message to come in over the gateway, given certain criteria - // By default, this will be limited to messages from the source user in the source channel + // By default, this will be limited to messages from the source user in the source channel. // This method will block the gateway, so it should be ran in async mode. [Command("next", RunMode = RunMode.Async)] public async Task Test_NextMessageAsync() { await ReplyAsync("What is 2+2?"); + var response = await NextMessageAsync(); if (response != null) + { await ReplyAsync($"You replied: {response.Content}"); + } else + { await ReplyAsync("You did not reply before the timeout"); + } } // PagedReplyAsync will send a paginated message to the channel @@ -85,15 +90,14 @@ public async Task Test_Paginator() // InlineReactionReplyAsync will send a message and adds reactions on it. // Once an user adds a reaction, the callback is fired. - // If callback was successful next callback is not handled + // If callback was successful next callback is not handled. // Unsuccessful callback is a reaction that did not have a callback. [Command("reaction")] public async Task Test_ReactionReply() { await InlineReactionReplyAsync(new ReactionCallbackData("text", null, false, false) .WithCallback(new Emoji("👍"), (c, r) => c.Channel.SendMessageAsync($"{r.User.Value.Mention} replied with 👍")) - .WithCallback(new Emoji("👎"), (c, r) => c.Channel.SendMessageAsync($"{r.User.Value.Mention} replied with 👎")) - ); + .WithCallback(new Emoji("👎"), (c, r) => c.Channel.SendMessageAsync($"{r.User.Value.Mention} replied with 👎"))); } } } \ No newline at end of file From fb9ae6136554de2090b8a03e932cb21babb6976d Mon Sep 17 00:00:00 2001 From: Matthew Trip Date: Mon, 6 Jul 2020 10:44:28 +0100 Subject: [PATCH 11/22] Create Reaction List --- .../Paginator/ReactionList.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 Discord.Addons.Interactive/Paginator/ReactionList.cs diff --git a/Discord.Addons.Interactive/Paginator/ReactionList.cs b/Discord.Addons.Interactive/Paginator/ReactionList.cs new file mode 100644 index 0000000..ef5120a --- /dev/null +++ b/Discord.Addons.Interactive/Paginator/ReactionList.cs @@ -0,0 +1,13 @@ +namespace Discord.Addons.Interactive.Paginator +{ + public class ReactionList + { + public bool First { get; set; } = true; + public bool Last { get; set; } = true; + public bool Forward { get; set; } = true; + public bool Backward { get; set; } = true; + public bool Jump { get; set; } = true; + public bool Trash { get; set; } = true; + public bool Info { get; set; } = true; + } +} \ No newline at end of file From 400a13dc1be1596f9984c1f32d0e6f30722af6c1 Mon Sep 17 00:00:00 2001 From: Matthew Trip Date: Mon, 6 Jul 2020 10:45:23 +0100 Subject: [PATCH 12/22] Support Multiple Custom Pages in Callback + Cleaning --- .../Paginator/PaginatedMessageCallback.cs | 162 ++++++++++++------ 1 file changed, 108 insertions(+), 54 deletions(-) diff --git a/Discord.Addons.Interactive/Paginator/PaginatedMessageCallback.cs b/Discord.Addons.Interactive/Paginator/PaginatedMessageCallback.cs index d18c0eb..7c879a0 100644 --- a/Discord.Addons.Interactive/Paginator/PaginatedMessageCallback.cs +++ b/Discord.Addons.Interactive/Paginator/PaginatedMessageCallback.cs @@ -1,32 +1,31 @@ using Discord.Addons.Interactive.Callbacks; using Discord.Addons.Interactive.Criteria; +using Discord.Addons.Interactive.Paginator; using Discord.Commands; +using Discord.Rest; using Discord.WebSocket; using System; -using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -namespace Discord.Addons.Interactive.Paginator +namespace Discord.Addons.Interactive { public class PaginatedMessageCallback : IReactionCallback { - public SocketCommandContext Context { get; } - public InteractiveService Interactive { get; } - public IUserMessage Message { get; private set; } - public RunMode RunMode => RunMode.Sync; - public ICriterion Criterion { get; } public TimeSpan? Timeout => Options.Timeout; - private readonly PaginatedMessage _pager; - private PaginatedAppearanceOptions Options => _pager.Options; + private readonly int _pages; - private int _page = 1; - public PaginatedMessageCallback(InteractiveService interactive, + private readonly PaginatedMessage _pager; + + private int _currentPage = 1; + + public PaginatedMessageCallback( + InteractiveService interactive, SocketCommandContext sourceContext, PaginatedMessage pager, ICriterion criterion = null) @@ -36,70 +35,93 @@ public PaginatedMessageCallback(InteractiveService interactive, Criterion = criterion ?? new EmptyCriterion(); _pager = pager; _pages = _pager.Pages.Count(); - - if (_pager.Pages is IEnumerable) - _pages = ((_pager.Pages.Count() - 1) / Options.FieldsPerPage) + 1; } - public async Task DisplayAsync() + public SocketCommandContext Context { get; } + + public InteractiveService Interactive { get; } + + public ICriterion Criterion { get; } + + public IUserMessage Message { get; private set; } + + public async Task DisplayAsync(ReactionList reactionList) { var embed = BuildEmbed(); var message = await Context.Channel.SendMessageAsync(_pager.Content, embed: embed).ConfigureAwait(false); + Message = message; Interactive.AddReactionCallback(message, this); - // Reactions take a while to add, don't wait for them + _ = Task.Run(async () => { - await message.AddReactionAsync(Options.First); - await message.AddReactionAsync(Options.Back); - await message.AddReactionAsync(Options.Next); - await message.AddReactionAsync(Options.Last); + if (reactionList.First) + await message.AddReactionAsync(Options.First); + + if (reactionList.Backward) + await message.AddReactionAsync(Options.Back); + + if (reactionList.Forward) + await message.AddReactionAsync(Options.Next); - var manageMessages = (Context.Channel is IGuildChannel guildChannel) && ((IGuildUser)Context.User).GetPermissions(guildChannel).ManageMessages; + if (reactionList.Last) + await message.AddReactionAsync(Options.Last); - if (Options.JumpDisplayOptions == JumpDisplayOptions.Always - || (Options.JumpDisplayOptions == JumpDisplayOptions.WithManageMessages && manageMessages)) + var manageMessages = Context.Channel is IGuildChannel guildChannel && + (Context.User as IGuildUser).GetPermissions(guildChannel).ManageMessages; + + if (reactionList.Jump + && Options.JumpDisplayOptions == JumpDisplayOptions.Always + || Options.JumpDisplayOptions == JumpDisplayOptions.WithManageMessages && manageMessages) await message.AddReactionAsync(Options.Jump); - await message.AddReactionAsync(Options.Stop); + if (reactionList.Trash) + await message.AddReactionAsync(Options.Stop); - if (Options.DisplayInformationIcon) + if (reactionList.Info && Options.DisplayInformationIcon) await message.AddReactionAsync(Options.Info); }); - // TODO: (Next major version) timeouts need to be handled at the service-level! + if (Timeout.HasValue) + DisplayTimeout(message, Message); + } + + public void DisplayTimeout(RestUserMessage m1, IUserMessage m2) + { if (Timeout.HasValue) { _ = Task.Delay(Timeout.Value).ContinueWith(_ => { - Interactive.RemoveReactionCallback(message); - _ = Message.DeleteAsync(); + Interactive.RemoveReactionCallback(m1); + m2.RemoveAllReactionsAsync(); }); } } - + public async Task HandleCallbackAsync(SocketReaction reaction) { var emote = reaction.Emote; if (emote.Equals(Options.First)) - _page = 1; + { + _currentPage = 1; + } else if (emote.Equals(Options.Next)) { - if (_page >= _pages) - return false; - ++_page; + if (_currentPage >= _pages) return false; + ++_currentPage; } else if (emote.Equals(Options.Back)) { - if (_page <= 1) - return false; - --_page; + if (_currentPage <= 1) return false; + --_currentPage; } else if (emote.Equals(Options.Last)) - _page = _pages; + { + _currentPage = _pages; + } else if (emote.Equals(Options.Stop)) { - await Message.DeleteAsync().ConfigureAwait(false); + await Message.RemoveAllReactionsAsync().ConfigureAwait(false); return true; } else if (emote.Equals(Options.Jump)) @@ -110,7 +132,9 @@ public async Task HandleCallbackAsync(SocketReaction reaction) .AddCriterion(new EnsureSourceChannelCriterion()) .AddCriterion(new EnsureFromUserCriterion(reaction.UserId)) .AddCriterion(new EnsureIsIntegerCriterion()); + var response = await Interactive.NextMessageAsync(Context, criteria, TimeSpan.FromSeconds(15)); + var request = int.Parse(response.Content); if (request < 1 || request > _pages) { @@ -118,45 +142,75 @@ public async Task HandleCallbackAsync(SocketReaction reaction) await Interactive.ReplyAndDeleteAsync(Context, Options.Stop.Name); return; } - _page = request; + + _currentPage = request; _ = response.DeleteAsync().ConfigureAwait(false); await RenderAsync().ConfigureAwait(false); }); } else if (emote.Equals(Options.Info)) { - await Interactive.ReplyAndDeleteAsync(Context, Options.InformationText, timeout: Options.InfoTimeout); + await Interactive.ReplyAndDeleteAsync(Context, null, embed: + new EmbedBuilder() + .WithTitle(Options.InformationTitle) + .WithDescription(Options.InformationText) + .WithColor(Options.InformationColor) + .Build(), + timeout: Options.InfoTimeout); + return false; } + _ = Message.RemoveReactionAsync(reaction.Emote, reaction.User.Value); await RenderAsync().ConfigureAwait(false); return false; } - - protected virtual Embed BuildEmbed() + + protected Embed BuildEmbed() { - var builder = new EmbedBuilder() - .WithAuthor(_pager.Author) - .WithColor(_pager.Color) - .WithFooter(f => f.Text = string.Format(Options.FooterFormat, _page, _pages)) - .WithTitle(_pager.Title); - if (_pager.Pages is IEnumerable efb) + var current = _pager.Pages.ElementAt(_currentPage - 1); + var builder = new EmbedBuilder { - builder.Fields = efb.Skip((_page - 1) * Options.FieldsPerPage).Take(Options.FieldsPerPage).ToList(); - builder.Description = _pager.AlternateDescription; + Title = current.Title ?? _pager.Title, + Url = current.Url ?? _pager.Url, + Description = current.Description ?? _pager.Description, + ImageUrl = current.ImageUrl ?? _pager.ImageUrl, + Color = current.Color ?? _pager.Color, + Fields = current.Fields ?? _pager.Fields, + Footer = current.FooterOverride ?? _pager.FooterOverride ?? new EmbedFooterBuilder + { + Text = string.Format(Options.FooterFormat, _currentPage, _pages) + }, + ThumbnailUrl = current.ThumbnailUrl ?? _pager.ThumbnailUrl, + Timestamp = current.TimeStamp ?? _pager.TimeStamp + }; + + if (current.DisplayTotalFieldsCount) + { + builder + .WithAuthor(author => + { + author.Name = $"{current.AlternateAuthorTitle}\nPage {_currentPage}/{_pages} ({Math.Round(_pager.Pages.Sum(x => x.Fields.Count) * current.TotalFieldsCountConstant)} {current.TotalFieldsMessage})"; + author.IconUrl = current.AlteranteAuthorIcon; + }); } else { - builder.Description = _pager.Pages.ElementAt(_page - 1).ToString(); + builder + .WithAuthor(author => + { + author.Name = $"{current.AlternateAuthorTitle}\nPage {_currentPage}/{_pages}"; + author.IconUrl = current.AlteranteAuthorIcon; + }); } return builder.Build(); } - - private async Task RenderAsync() + + private Task RenderAsync() { var embed = BuildEmbed(); - await Message.ModifyAsync(m => m.Embed = embed).ConfigureAwait(false); + return Message.ModifyAsync(m => m.Embed = embed); } } } \ No newline at end of file From a94833e0d58ebe2120091f48aa44c366928c2899 Mon Sep 17 00:00:00 2001 From: Matthew Trip Date: Mon, 6 Jul 2020 10:46:18 +0100 Subject: [PATCH 13/22] Create EmbedPage --- .../Paginator/PaginatedMessage.cs | 34 ++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/Discord.Addons.Interactive/Paginator/PaginatedMessage.cs b/Discord.Addons.Interactive/Paginator/PaginatedMessage.cs index 3299c50..95520b5 100644 --- a/Discord.Addons.Interactive/Paginator/PaginatedMessage.cs +++ b/Discord.Addons.Interactive/Paginator/PaginatedMessage.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; namespace Discord.Addons.Interactive.Paginator { @@ -37,4 +38,35 @@ public class PaginatedMessage public PaginatedAppearanceOptions Options { get; set; } = PaginatedAppearanceOptions.Default; } + + public class EmbedPage + { + public string AlternateAuthorTitle { get; set; } + + public string AlteranteAuthorIcon { get; set; } + + public bool DisplayTotalFieldsCount { get; set; } = false; + + public string TotalFieldsMessage { get; set; } = null; + + public double TotalFieldsCountConstant { get; set; } = 1; + + public string Title { get; set; } + + public string Url { get; set; } = null; + + public string Description { get; set; } + + public string ImageUrl { get; set; } + + public string ThumbnailUrl { get; set; } = null; + + public List Fields { get; set; } = new List(); + + public EmbedFooterBuilder FooterOverride { get; set; } = null; + + public DateTimeOffset? TimeStamp { get; set; } = null; + + public Color? Color { get; set; } = null; + } } \ No newline at end of file From ac2ce0816030704e29a818a4ff43f4e933a6f726 Mon Sep 17 00:00:00 2001 From: Matthew Trip Date: Mon, 6 Jul 2020 10:46:58 +0100 Subject: [PATCH 14/22] Remove Bad Documentation + Add Properties --- .../Paginator/PaginatedMessage.cs | 43 ++++++++----------- 1 file changed, 17 insertions(+), 26 deletions(-) diff --git a/Discord.Addons.Interactive/Paginator/PaginatedMessage.cs b/Discord.Addons.Interactive/Paginator/PaginatedMessage.cs index 95520b5..a7cfbcb 100644 --- a/Discord.Addons.Interactive/Paginator/PaginatedMessage.cs +++ b/Discord.Addons.Interactive/Paginator/PaginatedMessage.cs @@ -1,41 +1,32 @@ -using System; +using System; using System.Collections.Generic; namespace Discord.Addons.Interactive.Paginator { public class PaginatedMessage { - /// - /// Pages contains a collection of elements to page over in the embed. It is expected - /// that a string-like object is used in this collection, as objects will be converted - /// to a displayable string only through their generic ToString method, with the - /// exception of EmbedFieldBuilders. - /// - /// If this collection is of EmbedFieldBuilder, then the pages will be displayed in - /// batches of , and the - /// embed's description will be populated with the field. - /// - public IEnumerable Pages { get; set; } + public IEnumerable Pages { get; set; } = new List(); - /// - /// Content sets the content of the message, displayed above the embed. This may remain empty. - /// - public string Content { get; set; } = ""; - - /// - /// Author sets the property directly. - /// + public string Content { get; set; } = string.Empty; + public EmbedAuthorBuilder Author { get; set; } = null; public Color Color { get; set; } = Color.Default; - public string Title { get; set; } = ""; + public string Title { get; set; } = null; + + public string Url { get; set; } = null; + + public string Description { get; set; } = string.Empty; - /// - /// AlternateDescription will be used as the description of the pager only when - /// is a collection of . - /// - public string AlternateDescription { get; set; } = ""; + public string ImageUrl { get; set; } = null; + public string ThumbnailUrl { get; set; } = null; + + public List Fields { get; set; } = new List(); + + public EmbedFooterBuilder FooterOverride { get; set; } = null; + + public DateTimeOffset? TimeStamp { get; set; } = null; public PaginatedAppearanceOptions Options { get; set; } = PaginatedAppearanceOptions.Default; } From 96c59773aaea48ae62883306501760b42e05cd21 Mon Sep 17 00:00:00 2001 From: Matthew Trip Date: Mon, 6 Jul 2020 10:48:10 +0100 Subject: [PATCH 15/22] Field => Property --- .../Paginator/PaginatedAppearanceOptions.cs | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/Discord.Addons.Interactive/Paginator/PaginatedAppearanceOptions.cs b/Discord.Addons.Interactive/Paginator/PaginatedAppearanceOptions.cs index 3d98a11..35dc9ef 100644 --- a/Discord.Addons.Interactive/Paginator/PaginatedAppearanceOptions.cs +++ b/Discord.Addons.Interactive/Paginator/PaginatedAppearanceOptions.cs @@ -1,18 +1,24 @@ -using System; +using System; namespace Discord.Addons.Interactive.Paginator { public class PaginatedAppearanceOptions { - public static PaginatedAppearanceOptions Default = new PaginatedAppearanceOptions(); + public IEmote First { get; set; } = new Emoji("⏮"); + + public IEmote Back { get; set; } = new Emoji("◀"); + + public IEmote Next { get; set; } = new Emoji("▶"); + + public IEmote Last { get; set; } = new Emoji("⏭"); + + public IEmote Stop { get; set; } = new Emoji("⏹"); + + public IEmote Jump { get; set; } = new Emoji("🔢"); + + public IEmote Info { get; set; } = new Emoji("ℹ"); - public IEmote First = new Emoji("⏮"); - public IEmote Back = new Emoji("◀"); - public IEmote Next = new Emoji("▶"); - public IEmote Last = new Emoji("⏭"); - public IEmote Stop = new Emoji("⏹"); - public IEmote Jump = new Emoji("🔢"); - public IEmote Info = new Emoji("ℹ"); + public string FooterFormat { get; set; } = "Page {0}/{1}"; public string FooterFormat = "Page {0}/{1}"; public string InformationText = "This is a paginator. React with the respective icons to change page."; From a3fb4810bf5c83249182a79fcbc0405517492c95 Mon Sep 17 00:00:00 2001 From: Matthew Trip Date: Mon, 6 Jul 2020 10:48:37 +0100 Subject: [PATCH 16/22] Add Options --- .../Paginator/PaginatedAppearanceOptions.cs | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/Discord.Addons.Interactive/Paginator/PaginatedAppearanceOptions.cs b/Discord.Addons.Interactive/Paginator/PaginatedAppearanceOptions.cs index 35dc9ef..3454104 100644 --- a/Discord.Addons.Interactive/Paginator/PaginatedAppearanceOptions.cs +++ b/Discord.Addons.Interactive/Paginator/PaginatedAppearanceOptions.cs @@ -1,4 +1,4 @@ -using System; +using System; namespace Discord.Addons.Interactive.Paginator { @@ -20,16 +20,21 @@ public class PaginatedAppearanceOptions public string FooterFormat { get; set; } = "Page {0}/{1}"; - public string FooterFormat = "Page {0}/{1}"; - public string InformationText = "This is a paginator. React with the respective icons to change page."; - - public JumpDisplayOptions JumpDisplayOptions = JumpDisplayOptions.WithManageMessages; - public bool DisplayInformationIcon = true; + public string InformationTitle { get; set; } = "Paginator Information"; + + public string InformationText { get; set; } = "This funny-looking embed is called a **Paginator**. It's just like a book. You can flip through the pages using the arrows, enter the number of the page you want to navigate to, or close the it entirely."; - public TimeSpan? Timeout = null; - public TimeSpan InfoTimeout = TimeSpan.FromSeconds(30); + public Color InformationColor { get; set; } = new Color(252, 166, 205); + + public JumpDisplayOptions JumpDisplayOptions { get; set; } = JumpDisplayOptions.WithManageMessages; + + public bool DisplayInformationIcon { get; set; } = true; + + public TimeSpan? Timeout { get; set; } = null; + + public TimeSpan InfoTimeout { get; set; } = TimeSpan.FromSeconds(10); - public int FieldsPerPage = 6; + public static PaginatedAppearanceOptions Default { get; set; } = new PaginatedAppearanceOptions(); } public enum JumpDisplayOptions From c132ddadae123199e6c1ec473406c7bb8cbf08f4 Mon Sep 17 00:00:00 2001 From: Matthew Trip Date: Mon, 6 Jul 2020 10:50:23 +0100 Subject: [PATCH 17/22] Remove Bad Documentation + Support Multiple Custom Pages --- .../InteractiveService.cs | 31 +++++++------------ 1 file changed, 11 insertions(+), 20 deletions(-) diff --git a/Discord.Addons.Interactive/InteractiveService.cs b/Discord.Addons.Interactive/InteractiveService.cs index 5c52967..06fa2e8 100644 --- a/Discord.Addons.Interactive/InteractiveService.cs +++ b/Discord.Addons.Interactive/InteractiveService.cs @@ -1,4 +1,4 @@ -using Discord.Addons.Interactive.Callbacks; +using Discord.Addons.Interactive.Callbacks; using Discord.Addons.Interactive.Criteria; using Discord.Addons.Interactive.InlineReaction; using Discord.Addons.Interactive.Paginator; @@ -18,7 +18,7 @@ public class InteractiveService : IDisposable private readonly Dictionary _callbacks; private readonly TimeSpan _defaultTimeout; - // helpers to allow DI containers to resolve without a custom factory + // Helpers to allow DI containers to resolve without a custom factory public InteractiveService(DiscordSocketClient discord, InteractiveServiceConfig config = null) : this((BaseSocketClient)discord, config) { } @@ -43,10 +43,13 @@ public Task NextMessageAsync(SocketCommandContext context, CancellationToken token = default) { var criterion = new Criteria(); + if (fromSourceUser) criterion.AddCriterion(new EnsureSourceUserCriterion()); + if (inSourceChannel) criterion.AddCriterion(new EnsureSourceChannelCriterion()); + return NextMessageAsync(context, criterion, timeout, token); } @@ -97,23 +100,10 @@ public async Task ReplyAndDeleteAsync(SocketCommandContext context .ConfigureAwait(false); return message; } - - /// - /// Sends a message with reaction callbacks - /// - /// - /// The context. - /// - /// - /// The callbacks. - /// - /// - /// The from source user. - /// - /// - /// The . - /// - public async Task SendMessageWithReactionCallbacksAsync(SocketCommandContext context, ReactionCallbackData reactionCallbackData, bool fromSourceUser = true) + + public async Task SendMessageWithReactionCallbacksAsync(SocketCommandContext context, + ReactionCallbackData reactionCallbackData, + bool fromSourceUser = true) { var criterion = new Criteria(); if (fromSourceUser) @@ -128,10 +118,11 @@ public async Task SendMessageWithReactionCallbacksAsync(SocketComm public async Task SendPaginatedMessageAsync(SocketCommandContext context, PaginatedMessage pager, + ReactionList reactions, ICriterion criterion = null) { var callback = new PaginatedMessageCallback(this, context, pager, criterion); - await callback.DisplayAsync().ConfigureAwait(false); + await callback.DisplayAsync(reactions).ConfigureAwait(false); return callback.Message; } From e8794e717687c9d9f2f75a1d5ab06fd0cdb74a4c Mon Sep 17 00:00:00 2001 From: Matthew Trip Date: Mon, 6 Jul 2020 10:50:33 +0100 Subject: [PATCH 18/22] Cleaning --- Discord.Addons.Interactive/InteractiveService.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Discord.Addons.Interactive/InteractiveService.cs b/Discord.Addons.Interactive/InteractiveService.cs index 06fa2e8..741ebc6 100644 --- a/Discord.Addons.Interactive/InteractiveService.cs +++ b/Discord.Addons.Interactive/InteractiveService.cs @@ -1,4 +1,4 @@ -using Discord.Addons.Interactive.Callbacks; +using Discord.Addons.Interactive.Callbacks; using Discord.Addons.Interactive.Criteria; using Discord.Addons.Interactive.InlineReaction; using Discord.Addons.Interactive.Paginator; @@ -83,8 +83,7 @@ async Task Handler(SocketMessage message) if (task == trigger) return await trigger.ConfigureAwait(false); - else - return null; + return null; } public async Task ReplyAndDeleteAsync(SocketCommandContext context, From ba5ffa35cf93c04ad5b469a6c66ec9a10601544f Mon Sep 17 00:00:00 2001 From: Matthew Trip Date: Mon, 6 Jul 2020 10:50:55 +0100 Subject: [PATCH 19/22] Support Multiple Custom Pages --- Discord.Addons.Interactive/InteractiveBase.cs | 22 +++++-------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/Discord.Addons.Interactive/InteractiveBase.cs b/Discord.Addons.Interactive/InteractiveBase.cs index 6d58c7a..1c3c0f9 100644 --- a/Discord.Addons.Interactive/InteractiveBase.cs +++ b/Discord.Addons.Interactive/InteractiveBase.cs @@ -15,8 +15,7 @@ public abstract class InteractiveBase : InteractiveBase { } - public abstract class InteractiveBase : ModuleBase - where T : SocketCommandContext + public abstract class InteractiveBase : ModuleBase where T : SocketCommandContext { public InteractiveService Interactive { get; set; } @@ -31,26 +30,17 @@ public Task ReplyAndDeleteAsync(string content, bool isTTS = false public Task InlineReactionReplyAsync(ReactionCallbackData data, bool fromSourceUser = true) => Interactive.SendMessageWithReactionCallbacksAsync(Context, data, fromSourceUser); - - public Task PagedReplyAsync(IEnumerable pages, bool fromSourceUser = true) - { - var pager = new PaginatedMessage - { - Pages = pages - }; - return PagedReplyAsync(pager, fromSourceUser); - } - - public Task PagedReplyAsync(PaginatedMessage pager, bool fromSourceUser = true) + + public Task PagedReplyAsync(PaginatedMessage pager, ReactionList reactions, bool fromSourceUser = true) { var criterion = new Criteria(); if (fromSourceUser) criterion.AddCriterion(new EnsureReactionFromSourceUserCriterion()); - return PagedReplyAsync(pager, criterion); + return PagedReplyAsync(pager, reactions, criterion); } - public Task PagedReplyAsync(PaginatedMessage pager, ICriterion criterion) - => Interactive.SendPaginatedMessageAsync(Context, pager, criterion); + public Task PagedReplyAsync(PaginatedMessage pager, ReactionList reactions, ICriterion criterion) + => Interactive.SendPaginatedMessageAsync(Context, pager, reactions, criterion); public RuntimeResult Ok(string reason = null) => new OkResult(reason); } From 39f53031cc5f138ab4f6fcdcd99db3216f4c15c4 Mon Sep 17 00:00:00 2001 From: Matthew Trip Date: Mon, 6 Jul 2020 10:51:11 +0100 Subject: [PATCH 20/22] Infer Type --- Discord.Addons.Interactive/Criteria/EnsureFromUserCriterion.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Discord.Addons.Interactive/Criteria/EnsureFromUserCriterion.cs b/Discord.Addons.Interactive/Criteria/EnsureFromUserCriterion.cs index 5e77acd..a612de3 100644 --- a/Discord.Addons.Interactive/Criteria/EnsureFromUserCriterion.cs +++ b/Discord.Addons.Interactive/Criteria/EnsureFromUserCriterion.cs @@ -17,7 +17,7 @@ public EnsureFromUserCriterion(ulong id) public Task JudgeAsync(SocketCommandContext sourceContext, IMessage parameter) { - bool ok = _id == parameter.Author.Id; + var ok = _id == parameter.Author.Id; return Task.FromResult(ok); } } From 309d2298bb2223a14f6215e76416929921f1c1e6 Mon Sep 17 00:00:00 2001 From: uchuu Date: Sat, 28 Nov 2020 11:04:30 +0000 Subject: [PATCH 21/22] Improve Sample App --- SampleApp/Program.cs | 15 ++++++++++++--- SampleApp/SampleApp.csproj | 9 +++++++++ SampleApp/appsettings.json | 3 +++ 3 files changed, 24 insertions(+), 3 deletions(-) create mode 100644 SampleApp/appsettings.json diff --git a/SampleApp/Program.cs b/SampleApp/Program.cs index 7c92d3d..5308dae 100644 --- a/SampleApp/Program.cs +++ b/SampleApp/Program.cs @@ -6,6 +6,7 @@ using System; using System.IO; using System.Threading.Tasks; +using Microsoft.Extensions.Configuration; namespace SampleApp { @@ -14,9 +15,16 @@ public class Program private static DiscordSocketClient _client; private static CommandService _commands; private static IServiceProvider _services; + private static IConfigurationRoot _configuration; public static async Task Main(string[] args) { + var builder = new ConfigurationBuilder() + .SetBasePath(Directory.GetCurrentDirectory()) + .AddJsonFile("appsettings.json"); + + _configuration = builder.Build(); + _services = ConfigureServices(); _client = _services.GetRequiredService(); @@ -28,7 +36,7 @@ public static async Task Main(string[] args) return Task.CompletedTask; }; - var token = File.ReadAllText("token.ignore"); + var token = _configuration["Token"]; await _client.LoginAsync(TokenType.Bot, token); await _client.StartAsync(); @@ -48,6 +56,7 @@ private static IServiceProvider ConfigureServices() return new ServiceCollection() .AddSingleton(client) .AddSingleton(commands) + .AddSingleton(_configuration) .AddSingleton() .BuildServiceProvider(); } @@ -58,9 +67,9 @@ private static async Task HandleCommandAsync(SocketMessage socketMessage) || !(message.Author is IGuildUser guildUser) || guildUser.IsBot) { - return; + return; } - + var argPos = 0; if (message.HasStringPrefix("!!", ref argPos)) { diff --git a/SampleApp/SampleApp.csproj b/SampleApp/SampleApp.csproj index 420f6f7..061b496 100644 --- a/SampleApp/SampleApp.csproj +++ b/SampleApp/SampleApp.csproj @@ -8,6 +8,9 @@ + + + @@ -15,4 +18,10 @@ + + + PreserveNewest + + + \ No newline at end of file diff --git a/SampleApp/appsettings.json b/SampleApp/appsettings.json new file mode 100644 index 0000000..25319e3 --- /dev/null +++ b/SampleApp/appsettings.json @@ -0,0 +1,3 @@ +{ + "Token": "NzMxNjYzMzQ2NzE3MTYzNTcx.XwpUlw.BRipVdGod_EB8tq5qhg2BMwWh6A" +} \ No newline at end of file From b3338537fa19879391def5d12292d20ad07999f7 Mon Sep 17 00:00:00 2001 From: uchuu Date: Sat, 28 Nov 2020 11:05:06 +0000 Subject: [PATCH 22/22] Remove Token because I'm an idiot --- SampleApp/appsettings.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SampleApp/appsettings.json b/SampleApp/appsettings.json index 25319e3..45d94ce 100644 --- a/SampleApp/appsettings.json +++ b/SampleApp/appsettings.json @@ -1,3 +1,3 @@ { - "Token": "NzMxNjYzMzQ2NzE3MTYzNTcx.XwpUlw.BRipVdGod_EB8tq5qhg2BMwWh6A" + "Token": "" } \ No newline at end of file