namespace NadekoBot.Extensions; public static class MessageChannelExtensions { private static readonly IEmote _arrowLeft = new Emoji("⬅"); private static readonly IEmote _arrowRight = new Emoji("➡"); public static Task EmbedAsync(this IMessageChannel ch, IEmbedBuilder embed, string msg = "") => ch.SendMessageAsync(msg, embed: embed.Build(), options: new() { RetryMode = RetryMode.AlwaysRetry }); public static Task SendAsync( this IMessageChannel channel, string? plainText, Embed? embed, bool sanitizeAll = false) { plainText = sanitizeAll ? plainText?.SanitizeAllMentions() ?? "" : plainText?.SanitizeMentions() ?? ""; return channel.SendMessageAsync(plainText, embed: embed); } public static Task SendAsync(this IMessageChannel channel, SmartText text, bool sanitizeAll = false) => text switch { SmartEmbedText set => channel.SendAsync(set.PlainText, set.GetEmbed().Build(), sanitizeAll), SmartPlainText st => channel.SendAsync(st.Text, null, sanitizeAll), _ => throw new ArgumentOutOfRangeException(nameof(text)) }; // this is a huge problem, because now i don't have // access to embed builder service // as this is an extension of the message channel public static Task SendErrorAsync( this IMessageChannel ch, IEmbedBuilderService eb, string title, string error, string? url = null, string? footer = null) { var embed = eb.Create().WithErrorColor().WithDescription(error).WithTitle(title); if (url != null && Uri.IsWellFormedUriString(url, UriKind.Absolute)) embed.WithUrl(url); if (!string.IsNullOrWhiteSpace(footer)) embed.WithFooter(footer); return ch.SendMessageAsync("", embed: embed.Build()); } public static Task SendErrorAsync(this IMessageChannel ch, IEmbedBuilderService eb, string error) => ch.SendMessageAsync("", embed: eb.Create().WithErrorColor().WithDescription(error).Build()); public static Task SendPendingAsync(this IMessageChannel ch, IEmbedBuilderService eb, string message) => ch.SendMessageAsync("", embed: eb.Create().WithPendingColor().WithDescription(message).Build()); public static Task SendConfirmAsync( this IMessageChannel ch, IEmbedBuilderService eb, string title, string text, string? url = null, string? footer = null) { var embed = eb.Create().WithOkColor().WithDescription(text).WithTitle(title); if (url != null && Uri.IsWellFormedUriString(url, UriKind.Absolute)) embed.WithUrl(url); if (!string.IsNullOrWhiteSpace(footer)) embed.WithFooter(footer); return ch.SendMessageAsync("", embed: embed.Build()); } public static Task SendConfirmAsync(this IMessageChannel ch, IEmbedBuilderService eb, string text) => ch.SendMessageAsync("", embed: eb.Create().WithOkColor().WithDescription(text).Build()); public static Task SendTableAsync( this IMessageChannel ch, string seed, IEnumerable items, Func howToPrint, int columns = 3) => ch.SendMessageAsync($@"{seed}```css {string.Join("\n", items.Chunk(columns) .Select(ig => string.Concat(ig.Select(howToPrint))))} ```"); public static Task SendTableAsync( this IMessageChannel ch, IEnumerable items, Func howToPrint, int columns = 3) => ch.SendTableAsync("", items, howToPrint, columns); public static Task SendPaginatedConfirmAsync( this ICommandContext ctx, int currentPage, Func pageFunc, int totalElements, int itemsPerPage, bool addPaginatedFooter = true) => ctx.SendPaginatedConfirmAsync(currentPage, x => Task.FromResult(pageFunc(x)), totalElements, itemsPerPage, addPaginatedFooter); /// /// danny kamisama /// public static async Task SendPaginatedConfirmAsync( this ICommandContext ctx, int currentPage, Func> pageFunc, int totalElements, int itemsPerPage, bool addPaginatedFooter = true) { var embed = await pageFunc(currentPage); var lastPage = (totalElements - 1) / itemsPerPage; var canPaginate = true; if (ctx.Guild is SocketGuild sg && !sg.CurrentUser.GetPermissions((IGuildChannel)ctx.Channel).AddReactions) canPaginate = false; if (!canPaginate) embed.WithFooter("⚠️ AddReaction permission required for pagination."); else if (addPaginatedFooter) embed.AddPaginatedFooter(currentPage, lastPage); var msg = await ctx.Channel.EmbedAsync(embed); if (lastPage == 0 || !canPaginate) return; await msg.AddReactionAsync(_arrowLeft); await msg.AddReactionAsync(_arrowRight); await Task.Delay(2000); var lastPageChange = DateTime.MinValue; async Task ChangePage(SocketReaction r) { try { if (r.UserId != ctx.User.Id) return; if (DateTime.UtcNow - lastPageChange < TimeSpan.FromSeconds(1)) return; if (r.Emote.Name == _arrowLeft.Name) { if (currentPage == 0) return; lastPageChange = DateTime.UtcNow; var toSend = await pageFunc(--currentPage); if (addPaginatedFooter) toSend.AddPaginatedFooter(currentPage, lastPage); await msg.ModifyAsync(x => x.Embed = toSend.Build()); } else if (r.Emote.Name == _arrowRight.Name) { if (lastPage > currentPage) { lastPageChange = DateTime.UtcNow; var toSend = await pageFunc(++currentPage); if (addPaginatedFooter) toSend.AddPaginatedFooter(currentPage, lastPage); await msg.ModifyAsync(x => x.Embed = toSend.Build()); } } } catch (Exception) { //ignored } } using (msg.OnReaction((DiscordSocketClient)ctx.Client, ChangePage, ChangePage)) { await Task.Delay(30000); } try { if (msg.Channel is ITextChannel && ((SocketGuild)ctx.Guild).CurrentUser.GuildPermissions.ManageMessages) await msg.RemoveAllReactionsAsync(); else await msg.Reactions.Where(x => x.Value.IsMe) .Select(x => msg.RemoveReactionAsync(x.Key, ctx.Client.CurrentUser)) .WhenAll(); } catch { // ignored } } public static Task OkAsync(this ICommandContext ctx) => ctx.Message.AddReactionAsync(new Emoji("✅")); public static Task ErrorAsync(this ICommandContext ctx) => ctx.Message.AddReactionAsync(new Emoji("❌")); public static Task WarningAsync(this ICommandContext ctx) => ctx.Message.AddReactionAsync(new Emoji("⚠️")); }