From fc4858830c317591158c91de87931eb7f0a2b795 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 2 May 2024 06:47:01 +0000 Subject: [PATCH] Finished new response system --- CHANGELOG.md | 2 + src/NadekoBot.Tests/BotStringsTests.cs | 2 +- .../Modules/Administration/Administration.cs | 2 +- .../DangerousCommands/DangerousCommands.cs | 32 +- .../Administration/GreetBye/GreetService.cs | 21 +- .../Administration/LocalizationCommands.cs | 2 +- .../Administration/Mute/MuteService.cs | 4 +- .../DiscordPermOverrideCommands.cs | 49 +-- .../Protection/ProtectionCommands.cs | 2 +- .../Role/ReactionRoleCommands.cs | 81 +++-- .../Self/CheckForUpdatesService.cs | 2 +- .../Administration/Self/SelfCommands.cs | 55 +-- .../SelfAssignedRolesCommands.cs | 87 ++--- .../ServerLog/ServerLogCommandService.cs | 34 +- .../ServerLog/ServerLogCommands.cs | 2 +- .../Timezone/TimeZoneCommands.cs | 21 +- .../UserPunish/UserPunishCommands.cs | 153 ++++---- .../Administration/VcRole/VcRoleCommands.cs | 2 +- .../Expressions/NadekoExpressionExtensions.cs | 4 +- .../Modules/Expressions/NadekoExpressions.cs | 51 +-- .../Expressions/NadekoExpressionsService.cs | 2 +- .../AnimalRacing/AnimalRacingCommands.cs | 2 +- .../Modules/Gambling/Bank/BankCommands.cs | 2 +- .../Gambling/BlackJack/BlackJackCommands.cs | 2 +- .../Gambling/Connect4/Connect4Commands.cs | 4 +- .../Gambling/DiceRoll/DiceRollCommands.cs | 8 +- .../Modules/Gambling/Draw/DrawCommands.cs | 4 +- .../Gambling/Events/CurrencyEventsCommands.cs | 4 +- .../Gambling/FlipCoin/FlipCoinCommands.cs | 4 +- src/NadekoBot/Modules/Gambling/Gambling.cs | 106 +++--- .../PlantPick/PlantAndPickCommands.cs | 26 +- .../Modules/Gambling/Shop/ShopCommands.cs | 53 +-- .../Modules/Gambling/Slot/SlotCommands.cs | 2 +- .../Gambling/Waifus/WaifuClaimCommands.cs | 84 ++--- .../Games/Acrophobia/AcropobiaCommands.cs | 8 +- src/NadekoBot/Modules/Games/Games.cs | 2 +- .../Modules/Games/Hangman/HangmanCommands.cs | 10 +- .../Modules/Games/Hangman/HangmanService.cs | 2 +- .../Games/SpeedTyping/SpeedTypingCommands.cs | 2 +- .../Modules/Games/SpeedTyping/TypingGame.cs | 3 +- .../Modules/Games/TicTacToe/TicTacToe.cs | 2 +- src/NadekoBot/Modules/Games/Trivia/Games.cs | 8 +- src/NadekoBot/Modules/Help/Help.cs | 70 ++-- src/NadekoBot/Modules/Help/HelpService.cs | 27 +- src/NadekoBot/Modules/Medusae/Medusa.cs | 179 +++++----- src/NadekoBot/Modules/Music/Music.cs | 88 ++--- .../Modules/Music/PlaylistCommands.cs | 34 +- .../Modules/Music/Services/MusicService.cs | 30 +- .../Patronage/CurrencyRewardService.cs | 2 +- .../Modules/Patronage/PatronageCommands.cs | 4 +- .../Modules/Patronage/PatronageService.cs | 6 +- .../Blacklist/BlacklistCommands.cs | 4 +- .../CommandCooldown/CmdCdsCommands.cs | 28 +- .../Permissions/Filter/FilterCommands.cs | 39 +- .../GlobalPermissionCommands.cs | 2 +- .../Searches/Anime/AnimeSearchCommands.cs | 8 +- .../Modules/Searches/Crypto/CryptoCommands.cs | 8 +- .../Modules/Searches/Feeds/FeedCommands.cs | 36 +- .../Modules/Searches/Feeds/FeedsService.cs | 76 ++-- .../Modules/Searches/MemegenCommands.cs | 25 +- src/NadekoBot/Modules/Searches/OsuCommands.cs | 6 +- .../Modules/Searches/PathOfExileCommands.cs | 83 ++--- .../Modules/Searches/PokemonSearchCommands.cs | 4 +- .../Modules/Searches/Search/SearchCommands.cs | 6 +- src/NadekoBot/Modules/Searches/Searches.cs | 119 ++++--- .../StreamNotificationCommands.cs | 4 +- .../StreamNotificationService.cs | 156 ++++---- .../Searches/Translate/TranslateService.cs | 2 +- .../Searches/Translate/TranslatorCommands.cs | 4 +- .../Modules/Searches/XkcdCommands.cs | 4 +- .../Modules/Utility/Alias/AliasCommands.cs | 24 +- .../Modules/Utility/ConfigCommands.cs | 12 +- .../Utility/Giveaway/GiveawayCommands.cs | 4 +- .../Utility/Giveaway/GiveawayService.cs | 2 +- .../Modules/Utility/Info/InfoCommands.cs | 10 +- .../Modules/Utility/Info/InviteCommands.cs | 4 +- .../Modules/Utility/Quote/QuoteCommands.cs | 34 +- .../Modules/Utility/Remind/RemindCommands.cs | 2 +- .../Modules/Utility/Remind/RemindService.cs | 2 +- .../Utility/Repeater/RepeatCommands.cs | 6 +- .../Utility/Repeater/RepeaterService.cs | 61 ++-- .../Modules/Utility/Todo/TodoCommands.cs | 88 ++--- .../UnitConversion/UnitConversionCommands.cs | 2 +- src/NadekoBot/Modules/Utility/Utility.cs | 97 ++--- src/NadekoBot/Modules/Xp/Club/Club.cs | 63 ++-- src/NadekoBot/Modules/Xp/Xp.cs | 246 +++++++------ src/NadekoBot/Modules/Xp/XpRewards.cs | 51 +-- src/NadekoBot/_common/CleanupModuleBase.cs | 2 +- .../_common/Interaction/SimpleInteraction.cs | 18 +- src/NadekoBot/_common/NadekoModule.cs | 3 +- .../_common/Sender/IMessageSenderService.cs | 2 + .../Sender/MessageChannelExtensions.cs | 280 --------------- .../_common/Sender/MessageSenderService.cs | 40 ++- .../ResponseBuilder.PaginationSender.cs | 56 ++- .../_common/Sender/ResponseBuilder.cs | 336 +++++++++++------- .../Sender/ResponseBuilderExtensions.cs | 26 +- .../_common/Sender/ResponseMessageModel.cs | 16 +- .../_common/Services/IEmbedBuilderService.cs | 17 - .../Services/Impl/CommandsUtilityService.cs | 2 +- .../_Extensions/CommandContextExtensions.cs | 30 ++ .../_common/_Extensions/Extensions.cs | 19 +- .../SocketMessageComponentExtensions.cs | 72 +--- 102 files changed, 1811 insertions(+), 1818 deletions(-) delete mode 100644 src/NadekoBot/_common/Sender/MessageChannelExtensions.cs delete mode 100644 src/NadekoBot/_common/Services/IEmbedBuilderService.cs create mode 100644 src/NadekoBot/_common/_Extensions/CommandContextExtensions.cs diff --git a/CHANGELOG.md b/CHANGELOG.md index 374ffd360..fae904405 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,7 @@ Experimental changelog. Mostly based on [keepachangelog](https://keepachangelog. - Added `.clubrename` command to uh rename your club - For self-hosters: - Added `.sqlselectcsv` which will return results in a csv file instead of an embed. +- Added a page parameter to `.feedlist` ### Changed @@ -46,6 +47,7 @@ Experimental changelog. Mostly based on [keepachangelog](https://keepachangelog. - `.feed` should now correctly accept (and show) the message which can be passed as the third parameter - `.say` will now correctly report errors if the user or the bot don't have sufficent perms to send a message in the targeted channel +- Fixed a bug in .invitelist not paginating correctly ### Removed diff --git a/src/NadekoBot.Tests/BotStringsTests.cs b/src/NadekoBot.Tests/BotStringsTests.cs index bef6214a2..bca83076a 100644 --- a/src/NadekoBot.Tests/BotStringsTests.cs +++ b/src/NadekoBot.Tests/BotStringsTests.cs @@ -58,7 +58,7 @@ namespace NadekoBot.Tests aliasesPath); var methodNames = GetCommandMethodNames(); - + var isSuccess = true; foreach (var methodName in methodNames) { diff --git a/src/NadekoBot/Modules/Administration/Administration.cs b/src/NadekoBot/Modules/Administration/Administration.cs index 59f2fdaba..97511fc3d 100644 --- a/src/NadekoBot/Modules/Administration/Administration.cs +++ b/src/NadekoBot/Modules/Administration/Administration.cs @@ -95,7 +95,7 @@ public partial class Administration : NadekoModule var guild = (SocketGuild)ctx.Guild; var (enabled, channels) = _service.GetDelMsgOnCmdData(ctx.Guild.Id); - var embed = new EmbedBuilder() + var embed = _sender.CreateEmbed() .WithOkColor() .WithTitle(GetText(strs.server_delmsgoncmd)) .WithDescription(enabled ? "✅" : "❌"); diff --git a/src/NadekoBot/Modules/Administration/DangerousCommands/DangerousCommands.cs b/src/NadekoBot/Modules/Administration/DangerousCommands/DangerousCommands.cs index d766b55d0..597b7fd24 100644 --- a/src/NadekoBot/Modules/Administration/DangerousCommands/DangerousCommands.cs +++ b/src/NadekoBot/Modules/Administration/DangerousCommands/DangerousCommands.cs @@ -35,22 +35,22 @@ public partial class Administration { var result = _ds.SelectSql(sql); - return ctx.SendPaginatedConfirmAsync(0, - cur => - { - var items = result.Results.Skip(cur * 20).Take(20).ToList(); + return Response() + .Paginated() + .Items(result.Results) + .PageSize(20) + .Page((items, _) => + { + if (!items.Any()) + return _sender.CreateEmbed().WithErrorColor().WithFooter(sql).WithDescription("-"); - if (!items.Any()) - return new EmbedBuilder().WithErrorColor().WithFooter(sql).WithDescription("-"); - - return new EmbedBuilder() + return _sender.CreateEmbed() .WithOkColor() .WithFooter(sql) .WithTitle(string.Join(" ║ ", result.ColumnNames)) .WithDescription(string.Join('\n', items.Select(x => string.Join(" ║ ", x)))); - }, - result.Results.Count, - 20); + }) + .SendAsync(); } [Cmd] @@ -99,9 +99,9 @@ public partial class Administration { try { - var embed = new EmbedBuilder() - .WithTitle(GetText(strs.sql_confirm_exec)) - .WithDescription(Format.Code(sql)); + var embed = _sender.CreateEmbed() + .WithTitle(GetText(strs.sql_confirm_exec)) + .WithDescription(Format.Code(sql)); if (!await PromptUserConfirmAsync(embed)) return; @@ -119,8 +119,8 @@ public partial class Administration [OwnerOnly] public async Task PurgeUser(ulong userId) { - var embed = new EmbedBuilder() - .WithDescription(GetText(strs.purge_user_confirm(Format.Bold(userId.ToString())))); + var embed = _sender.CreateEmbed() + .WithDescription(GetText(strs.purge_user_confirm(Format.Bold(userId.ToString())))); if (!await PromptUserConfirmAsync(embed)) return; diff --git a/src/NadekoBot/Modules/Administration/GreetBye/GreetService.cs b/src/NadekoBot/Modules/Administration/GreetBye/GreetService.cs index 6ee80891a..6477afeb7 100644 --- a/src/NadekoBot/Modules/Administration/GreetBye/GreetService.cs +++ b/src/NadekoBot/Modules/Administration/GreetBye/GreetService.cs @@ -97,7 +97,7 @@ public class GreetService : INService, IReadyExecutor { var newContent = await _repSvc.ReplaceAsync(toSend, new(client: _client, guild: user.Guild, channel: channel, users: user)); - var toDelete = await channel.SendAsync(newContent); + var toDelete = await _sender.Response(channel).Text(newContent).SendAsync(); if (conf.BoostMessageDeleteAfter > 0) toDelete.DeleteAfter(conf.BoostMessageDeleteAfter); @@ -217,12 +217,12 @@ public class GreetService : INService, IReadyExecutor text = await _repSvc.ReplaceAsync(text, repCtx); try { - var toDelete = await channel.SendAsync(text); + var toDelete = await _sender.Response(channel).Text(text).SendAsync(); if (conf.AutoDeleteByeMessagesTimer > 0) toDelete.DeleteAfter(conf.AutoDeleteByeMessagesTimer); } - catch (HttpException ex) when (ex.DiscordCode == DiscordErrorCode.InsufficientPermissions || - ex.DiscordCode == DiscordErrorCode.UnknownChannel) + catch (HttpException ex) when (ex.DiscordCode == DiscordErrorCode.InsufficientPermissions + || ex.DiscordCode == DiscordErrorCode.UnknownChannel) { Log.Warning(ex, "Missing permissions to send a bye message, the bye message will be disabled on server: {GuildId}", @@ -258,12 +258,12 @@ public class GreetService : INService, IReadyExecutor text = await _repSvc.ReplaceAsync(text, repCtx); try { - var toDelete = await channel.SendAsync(text); + var toDelete = await _sender.Response(channel).Text(text).SendAsync(); if (conf.AutoDeleteGreetMessagesTimer > 0) toDelete.DeleteAfter(conf.AutoDeleteGreetMessagesTimer); } - catch (HttpException ex) when (ex.DiscordCode == DiscordErrorCode.InsufficientPermissions || - ex.DiscordCode == DiscordErrorCode.UnknownChannel) + catch (HttpException ex) when (ex.DiscordCode == DiscordErrorCode.InsufficientPermissions + || ex.DiscordCode == DiscordErrorCode.UnknownChannel) { Log.Warning(ex, "Missing permissions to send a bye message, the greet message will be disabled on server: {GuildId}", @@ -352,9 +352,10 @@ public class GreetService : INService, IReadyExecutor { // if there is less than 10 embeds, add an embed with footer only seta.Embeds = seta.Embeds.Append(new SmartEmbedArrayElementText() - { - Footer = CreateFooterSource(user) - }).ToArray(); + { + Footer = CreateFooterSource(user) + }) + .ToArray(); } } } diff --git a/src/NadekoBot/Modules/Administration/LocalizationCommands.cs b/src/NadekoBot/Modules/Administration/LocalizationCommands.cs index bb0190f65..9f9eecb67 100644 --- a/src/NadekoBot/Modules/Administration/LocalizationCommands.cs +++ b/src/NadekoBot/Modules/Administration/LocalizationCommands.cs @@ -112,7 +112,7 @@ public partial class Administration [Cmd] public async Task LanguagesList() - => await Response().Embed(new EmbedBuilder() + => await Response().Embed(_sender.CreateEmbed() .WithOkColor() .WithTitle(GetText(strs.lang_list)) .WithDescription(string.Join("\n", diff --git a/src/NadekoBot/Modules/Administration/Mute/MuteService.cs b/src/NadekoBot/Modules/Administration/Mute/MuteService.cs index 23b821d72..24686e7c1 100644 --- a/src/NadekoBot/Modules/Administration/Mute/MuteService.cs +++ b/src/NadekoBot/Modules/Administration/Mute/MuteService.cs @@ -123,7 +123,7 @@ public class MuteService : INService return; _ = Task.Run(() => _sender.Response(user) - .Embed(new EmbedBuilder() + .Embed(_sender.CreateEmbed() .WithDescription($"You've been muted in {user.Guild} server") .AddField("Mute Type", type.ToString()) .AddField("Moderator", mod.ToString()) @@ -141,7 +141,7 @@ public class MuteService : INService return; _ = Task.Run(() => _sender.Response(user) - .Embed(new EmbedBuilder() + .Embed(_sender.CreateEmbed() .WithDescription($"You've been unmuted in {user.Guild} server") .AddField("Unmute Type", type.ToString()) .AddField("Moderator", mod.ToString()) diff --git a/src/NadekoBot/Modules/Administration/PermOverrides/DiscordPermOverrideCommands.cs b/src/NadekoBot/Modules/Administration/PermOverrides/DiscordPermOverrideCommands.cs index 8d03e22a8..d30b50286 100644 --- a/src/NadekoBot/Modules/Administration/PermOverrides/DiscordPermOverrideCommands.cs +++ b/src/NadekoBot/Modules/Administration/PermOverrides/DiscordPermOverrideCommands.cs @@ -25,8 +25,10 @@ public partial class Administration var aggregatePerms = perms.Aggregate((acc, seed) => seed | acc); await _service.AddOverride(ctx.Guild.Id, cmd.Name, aggregatePerms); - await Response().Confirm(strs.perm_override(Format.Bold(aggregatePerms.ToString()), - Format.Code(cmd.Name))).SendAsync(); + await Response() + .Confirm(strs.perm_override(Format.Bold(aggregatePerms.ToString()), + Format.Code(cmd.Name))) + .SendAsync(); } [Cmd] @@ -34,9 +36,9 @@ public partial class Administration [UserPerm(GuildPerm.Administrator)] public async Task DiscordPermOverrideReset() { - var result = await PromptUserConfirmAsync(new EmbedBuilder() - .WithOkColor() - .WithDescription(GetText(strs.perm_override_all_confirm))); + var result = await PromptUserConfirmAsync(_sender.CreateEmbed() + .WithOkColor() + .WithDescription(GetText(strs.perm_override_all_confirm))); if (!result) return; @@ -54,27 +56,28 @@ public partial class Administration if (--page < 0) return; - var overrides = await _service.GetAllOverrides(ctx.Guild.Id); + var allOverrides = await _service.GetAllOverrides(ctx.Guild.Id); - await ctx.SendPaginatedConfirmAsync(page, - curPage => - { - var eb = new EmbedBuilder().WithTitle(GetText(strs.perm_overrides)).WithOkColor(); + await Response() + .Paginated() + .Items(allOverrides) + .PageSize(9) + .CurrentPage(page) + .Page((items, _) => + { + var eb = _sender.CreateEmbed().WithTitle(GetText(strs.perm_overrides)).WithOkColor(); - var thisPageOverrides = overrides.Skip(9 * curPage).Take(9).ToList(); + if (items.Count == 0) + eb.WithDescription(GetText(strs.perm_override_page_none)); + else + { + eb.WithDescription(items.Select(ov => $"{ov.Command} => {ov.Perm.ToString()}") + .Join("\n")); + } - if (thisPageOverrides.Count == 0) - eb.WithDescription(GetText(strs.perm_override_page_none)); - else - { - eb.WithDescription(thisPageOverrides.Select(ov => $"{ov.Command} => {ov.Perm.ToString()}") - .Join("\n")); - } - - return eb; - }, - overrides.Count, - 9); + return eb; + }) + .SendAsync(); } } } \ No newline at end of file diff --git a/src/NadekoBot/Modules/Administration/Protection/ProtectionCommands.cs b/src/NadekoBot/Modules/Administration/Protection/ProtectionCommands.cs index 8c6659fab..a44c29c64 100644 --- a/src/NadekoBot/Modules/Administration/Protection/ProtectionCommands.cs +++ b/src/NadekoBot/Modules/Administration/Protection/ProtectionCommands.cs @@ -241,7 +241,7 @@ public partial class Administration return; } - var embed = new EmbedBuilder().WithOkColor().WithTitle(GetText(strs.prot_active)); + var embed = _sender.CreateEmbed().WithOkColor().WithTitle(GetText(strs.prot_active)); if (spam is not null) embed.AddField("Anti-Spam", GetAntiSpamString(spam).TrimTo(1024), true); diff --git a/src/NadekoBot/Modules/Administration/Role/ReactionRoleCommands.cs b/src/NadekoBot/Modules/Administration/Role/ReactionRoleCommands.cs index d82420bc8..9aa423f46 100644 --- a/src/NadekoBot/Modules/Administration/Role/ReactionRoleCommands.cs +++ b/src/NadekoBot/Modules/Administration/Role/ReactionRoleCommands.cs @@ -12,7 +12,7 @@ public partial class Administration { _rero = rero; } - + [Cmd] [RequireContext(ContextType.Guild)] [UserPerm(GuildPerm.ManageRoles)] @@ -29,15 +29,16 @@ public partial class Administration if (levelReq < 0) return; - + var msg = await ctx.Channel.GetMessageAsync(messageId); if (msg is null) { await Response().Error(strs.not_found).SendAsync(); return; } - - if (ctx.User.Id != ctx.Guild.OwnerId && ((IGuildUser)ctx.User).GetRoles().Max(x => x.Position) <= role.Position) + + if (ctx.User.Id != ctx.Guild.OwnerId + && ((IGuildUser)ctx.User).GetRoles().Max(x => x.Position) <= role.Position) { await Response().Error(strs.hierarchy).SendAsync(); return; @@ -71,48 +72,52 @@ public partial class Administration { if (--page < 0) return; - - var reros = await _rero.GetReactionRolesAsync(ctx.Guild.Id); - await ctx.SendPaginatedConfirmAsync(page, curPage => - { - var embed = new EmbedBuilder() - .WithOkColor(); + var allReros = await _rero.GetReactionRolesAsync(ctx.Guild.Id); - var content = string.Empty; - foreach (var g in reros.OrderBy(x => x.Group) - .Skip(curPage * 10) - .GroupBy(x => x.MessageId) - .OrderBy(x => x.Key)) - { - var messageId = g.Key; - content += - $"[{messageId}](https://discord.com/channels/{ctx.Guild.Id}/{g.First().ChannelId}/{g.Key})\n"; + await Response() + .Paginated() + .Items(allReros.OrderBy(x => x.Group).ToList()) + .PageSize(10) + .CurrentPage(page) + .Page((items, _) => + { + var embed = _sender.CreateEmbed() + .WithOkColor(); - var groupGroups = g.GroupBy(x => x.Group); + var content = string.Empty; + foreach (var g in items + .GroupBy(x => x.MessageId) + .OrderBy(x => x.Key)) + { + var messageId = g.Key; + content += + $"[{messageId}](https://discord.com/channels/{ctx.Guild.Id}/{g.First().ChannelId}/{g.Key})\n"; - foreach (var ggs in groupGroups) - { - content += $"`< {(g.Key == 0 ? ("Not Exclusive (Group 0)") : ($"Group {ggs.Key}"))} >`\n"; + var groupGroups = g.GroupBy(x => x.Group); - foreach (var rero in ggs) - { - content += - $"\t{rero.Emote} -> {(ctx.Guild.GetRole(rero.RoleId)?.Mention ?? "")}"; - if (rero.LevelReq > 0) - content += $" (lvl {rero.LevelReq}+)"; - content += '\n'; - } - } + foreach (var ggs in groupGroups) + { + content += $"`< {(g.Key == 0 ? ("Not Exclusive (Group 0)") : ($"Group {ggs.Key}"))} >`\n"; - } + foreach (var rero in ggs) + { + content += + $"\t{rero.Emote} -> {(ctx.Guild.GetRole(rero.RoleId)?.Mention ?? "")}"; + if (rero.LevelReq > 0) + content += $" (lvl {rero.LevelReq}+)"; + content += '\n'; + } + } + } - embed.WithDescription(string.IsNullOrWhiteSpace(content) - ? "There are no reaction roles on this server" - : content); + embed.WithDescription(string.IsNullOrWhiteSpace(content) + ? "There are no reaction roles on this server" + : content); - return embed; - }, reros.Count, 10); + return embed; + }) + .SendAsync(); } [Cmd] diff --git a/src/NadekoBot/Modules/Administration/Self/CheckForUpdatesService.cs b/src/NadekoBot/Modules/Administration/Self/CheckForUpdatesService.cs index f8bcb01d7..754315615 100644 --- a/src/NadekoBot/Modules/Administration/Self/CheckForUpdatesService.cs +++ b/src/NadekoBot/Modules/Administration/Self/CheckForUpdatesService.cs @@ -78,7 +78,7 @@ public sealed class CheckForUpdatesService : INService, IReadyExecutor if (user is null) return; - var eb = new EmbedBuilder() + var eb = _sender.CreateEmbed() .WithOkColor() .WithAuthor($"NadekoBot v{latestVersion} Released!") .WithTitle("Changelog") diff --git a/src/NadekoBot/Modules/Administration/Self/SelfCommands.cs b/src/NadekoBot/Modules/Administration/Self/SelfCommands.cs index 9d050b8a1..7c262928d 100644 --- a/src/NadekoBot/Modules/Administration/Self/SelfCommands.cs +++ b/src/NadekoBot/Modules/Administration/Self/SelfCommands.cs @@ -51,7 +51,6 @@ public partial class Administration { var downloadUsersTask = guild.DownloadUsersAsync(); var message = await Response().Pending(strs.cache_users_pending).SendAsync(); - using var dbContext = _db.GetDbContext(); await downloadUsersTask; @@ -62,10 +61,10 @@ public partial class Administration var (added, updated) = await _service.RefreshUsersAsync(users); await message.ModifyAsync(x => - x.Embed = new EmbedBuilder() - .WithDescription(GetText(strs.cache_users_done(added, updated))) - .WithOkColor() - .Build() + x.Embed = _sender.CreateEmbed() + .WithDescription(GetText(strs.cache_users_done(added, updated))) + .WithOkColor() + .Build() ); } @@ -81,6 +80,7 @@ public partial class Administration && ctx.Message is SocketUserMessage msg) { var fakeMessage = new DoAsUserMessage(msg, user, message); + await _cmdHandler.TryRunCommand(sg, ch, fakeMessage); } @@ -113,14 +113,16 @@ public partial class Administration }; _service.AddNewAutoCommand(cmd); - await Response().Embed(new EmbedBuilder() - .WithOkColor() - .WithTitle(GetText(strs.scadd)) - .AddField(GetText(strs.server), - cmd.GuildId is null ? "-" : $"{cmd.GuildName}/{cmd.GuildId}", - true) - .AddField(GetText(strs.channel), $"{cmd.ChannelName}/{cmd.ChannelId}", true) - .AddField(GetText(strs.command_text), cmdText)).SendAsync(); + await Response() + .Embed(_sender.CreateEmbed() + .WithOkColor() + .WithTitle(GetText(strs.scadd)) + .AddField(GetText(strs.server), + cmd.GuildId is null ? "-" : $"{cmd.GuildName}/{cmd.GuildId}", + true) + .AddField(GetText(strs.channel), $"{cmd.ChannelName}/{cmd.ChannelId}", true) + .AddField(GetText(strs.command_text), cmdText)) + .SendAsync(); } [Cmd] @@ -328,18 +330,21 @@ public partial class Administration + $"| {st.GuildCount.ToString().PadBoth(maxGuildCountLength)} `"; }) .ToArray(); - await ctx.SendPaginatedConfirmAsync(page, - curPage => - { - var str = string.Join("\n", allShardStrings.Skip(25 * curPage).Take(25)); + await Response() + .Paginated() + .Items(allShardStrings) + .PageSize(25) + .CurrentPage(page) + .Page((items, _) => + { + var str = string.Join("\n", items); - if (string.IsNullOrWhiteSpace(str)) - str = GetText(strs.no_shards_on_page); + if (string.IsNullOrWhiteSpace(str)) + str = GetText(strs.no_shards_on_page); - return new EmbedBuilder().WithOkColor().WithDescription($"{status}\n\n{str}"); - }, - allShardStrings.Length, - 25); + return _sender.CreateEmbed().WithOkColor().WithDescription($"{status}\n\n{str}"); + }) + .SendAsync(); } private static string ConnectionStateToEmoji(ShardStatus status) @@ -566,7 +571,7 @@ public partial class Administration return; text = await repSvc.ReplaceAsync(text, repCtx); - await ch.SendAsync(text); + await Response().Channel(ch).Text(text).SendAsync(); } else if (ids[1].ToUpperInvariant().StartsWith("U:", StringComparison.InvariantCulture)) { @@ -577,7 +582,7 @@ public partial class Administration var ch = await user.CreateDMChannelAsync(); text = await repSvc.ReplaceAsync(text, repCtx); - await ch.SendAsync(text); + await Response().Channel(ch).Text(text).SendAsync(); } else { diff --git a/src/NadekoBot/Modules/Administration/SelfAssignableRoles/SelfAssignedRolesCommands.cs b/src/NadekoBot/Modules/Administration/SelfAssignableRoles/SelfAssignedRolesCommands.cs index d005773a3..d892807a7 100644 --- a/src/NadekoBot/Modules/Administration/SelfAssignableRoles/SelfAssignedRolesCommands.cs +++ b/src/NadekoBot/Modules/Administration/SelfAssignableRoles/SelfAssignedRolesCommands.cs @@ -98,53 +98,54 @@ public partial class Administration var (exclusive, roles, groups) = _service.GetRoles(ctx.Guild); - await ctx.SendPaginatedConfirmAsync(page, - cur => - { - var rolesStr = new StringBuilder(); - var roleGroups = roles.OrderBy(x => x.Model.Group) - .Skip(cur * 20) - .Take(20) - .GroupBy(x => x.Model.Group) - .OrderBy(x => x.Key); + await Response() + .Paginated() + .Items(roles.OrderBy(x => x.Model.Group).ToList()) + .PageSize(20) + .CurrentPage(page) + .Page((items, _) => + { + var rolesStr = new StringBuilder(); + var roleGroups = items + .GroupBy(x => x.Model.Group) + .OrderBy(x => x.Key); - foreach (var kvp in roleGroups) - { - string groupNameText; - if (!groups.TryGetValue(kvp.Key, out var name)) - groupNameText = Format.Bold(GetText(strs.self_assign_group(kvp.Key))); - else - groupNameText = Format.Bold($"{kvp.Key} - {name.TrimTo(25, true)}"); + foreach (var kvp in roleGroups) + { + string groupNameText; + if (!groups.TryGetValue(kvp.Key, out var name)) + groupNameText = Format.Bold(GetText(strs.self_assign_group(kvp.Key))); + else + groupNameText = Format.Bold($"{kvp.Key} - {name.TrimTo(25, true)}"); - rolesStr.AppendLine("\t\t\t\t ⟪" + groupNameText + "⟫"); - foreach (var (model, role) in kvp.AsEnumerable()) - { - if (role is null) - { - } - else - { - // first character is invisible space - if (model.LevelRequirement == 0) - rolesStr.AppendLine("‌‌ " + role.Name); - else - rolesStr.AppendLine("‌‌ " + role.Name + $" (lvl {model.LevelRequirement}+)"); - } - } + rolesStr.AppendLine("\t\t\t\t ⟪" + groupNameText + "⟫"); + foreach (var (model, role) in kvp.AsEnumerable()) + { + if (role is null) + { + } + else + { + // first character is invisible space + if (model.LevelRequirement == 0) + rolesStr.AppendLine("‌‌ " + role.Name); + else + rolesStr.AppendLine("‌‌ " + role.Name + $" (lvl {model.LevelRequirement}+)"); + } + } - rolesStr.AppendLine(); - } + rolesStr.AppendLine(); + } - return new EmbedBuilder() - .WithOkColor() - .WithTitle(Format.Bold(GetText(strs.self_assign_list(roles.Count())))) - .WithDescription(rolesStr.ToString()) - .WithFooter(exclusive - ? GetText(strs.self_assign_are_exclusive) - : GetText(strs.self_assign_are_not_exclusive)); - }, - roles.Count(), - 20); + return _sender.CreateEmbed() + .WithOkColor() + .WithTitle(Format.Bold(GetText(strs.self_assign_list(roles.Count())))) + .WithDescription(rolesStr.ToString()) + .WithFooter(exclusive + ? GetText(strs.self_assign_are_exclusive) + : GetText(strs.self_assign_are_not_exclusive)); + }) + .SendAsync(); } [Cmd] diff --git a/src/NadekoBot/Modules/Administration/ServerLog/ServerLogCommandService.cs b/src/NadekoBot/Modules/Administration/ServerLog/ServerLogCommandService.cs index 447c8733f..18d117959 100644 --- a/src/NadekoBot/Modules/Administration/ServerLog/ServerLogCommandService.cs +++ b/src/NadekoBot/Modules/Administration/ServerLog/ServerLogCommandService.cs @@ -164,7 +164,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor var title = GetText(logChannel.Guild, strs.thread_deleted); - await _sender.Response(logChannel).Embed(new EmbedBuilder() + await _sender.Response(logChannel).Embed(_sender.CreateEmbed() .WithOkColor() .WithTitle("🗑 " + title) .WithDescription($"{ch.Name} | {ch.Id}") @@ -194,7 +194,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor var title = GetText(logChannel.Guild, strs.thread_created); - await _sender.Response(logChannel).Embed(new EmbedBuilder() + await _sender.Response(logChannel).Embed(_sender.CreateEmbed() .WithOkColor() .WithTitle("🆕 " + title) .WithDescription($"{ch.Name} | {ch.Id}") @@ -327,7 +327,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor if ((logChannel = await TryGetLogChannel(g, logSetting, LogType.UserWarned)) is null) return; - var embed = new EmbedBuilder() + var embed = _sender.CreateEmbed() .WithOkColor() .WithTitle($"⚠️ User Warned") .WithDescription($"<@{arg.UserId}> | {arg.UserId}") @@ -356,7 +356,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor if ((logChannel = await TryGetLogChannel(g, logSetting, LogType.UserUpdated)) is null) return; - var embed = new EmbedBuilder(); + var embed = _sender.CreateEmbed(); if (before.Username != after.Username) { @@ -495,7 +495,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor break; } - var embed = new EmbedBuilder() + var embed = _sender.CreateEmbed() .WithAuthor(mutes) .WithTitle($"{usr.Username}#{usr.Discriminator} | {usr.Id}") .WithFooter(CurrentTime(usr.Guild)) @@ -542,7 +542,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor break; } - var embed = new EmbedBuilder() + var embed = _sender.CreateEmbed() .WithAuthor(mutes) .WithTitle($"{usr.Username}#{usr.Discriminator} | {usr.Id}") .WithFooter($"{CurrentTime(usr.Guild)}") @@ -596,7 +596,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor break; } - var embed = new EmbedBuilder() + var embed = _sender.CreateEmbed() .WithAuthor($"🛡 Anti-{protection}") .WithTitle(GetText(logChannel.Guild, strs.users) + " " + punishment) .WithDescription(string.Join("\n", users.Select(u => u.ToString()))) @@ -649,7 +649,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor if (logSetting.UserUpdatedId is not null && (logChannel = await TryGetLogChannel(before.Guild, logSetting, LogType.UserUpdated)) is not null) { - var embed = new EmbedBuilder() + var embed = _sender.CreateEmbed() .WithOkColor() .WithFooter(CurrentTime(before.Guild)) .WithTitle($"{before.Username}#{before.Discriminator} | {before.Id}"); @@ -720,7 +720,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor if ((logChannel = await TryGetLogChannel(before.Guild, logSetting, LogType.ChannelUpdated)) is null) return; - var embed = new EmbedBuilder().WithOkColor().WithFooter(CurrentTime(before.Guild)); + var embed = _sender.CreateEmbed().WithOkColor().WithFooter(CurrentTime(before.Guild)); var beforeTextChannel = cbefore as ITextChannel; var afterTextChannel = cafter as ITextChannel; @@ -776,7 +776,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor else title = GetText(logChannel.Guild, strs.text_chan_destroyed); - await _sender.Response(logChannel).Embed(new EmbedBuilder() + await _sender.Response(logChannel).Embed(_sender.CreateEmbed() .WithOkColor() .WithTitle("🆕 " + title) .WithDescription($"{ch.Name} | {ch.Id}") @@ -812,7 +812,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor else title = GetText(logChannel.Guild, strs.text_chan_created); - await _sender.Response(logChannel).Embed(new EmbedBuilder() + await _sender.Response(logChannel).Embed(_sender.CreateEmbed() .WithOkColor() .WithTitle("🆕 " + title) .WithDescription($"{ch.Name} | {ch.Id}") @@ -915,7 +915,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor ITextChannel? logChannel; if ((logChannel = await TryGetLogChannel(guild, logSetting, LogType.UserLeft)) is null) return; - var embed = new EmbedBuilder() + var embed = _sender.CreateEmbed() .WithOkColor() .WithTitle("❌ " + GetText(logChannel.Guild, strs.user_left)) .WithDescription(usr.ToString()) @@ -948,7 +948,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor if ((logChannel = await TryGetLogChannel(usr.Guild, logSetting, LogType.UserJoined)) is null) return; - var embed = new EmbedBuilder() + var embed = _sender.CreateEmbed() .WithOkColor() .WithTitle("✅ " + GetText(logChannel.Guild, strs.user_joined)) .WithDescription($"{usr.Mention} `{usr}`") @@ -989,7 +989,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor ITextChannel? logChannel; if ((logChannel = await TryGetLogChannel(guild, logSetting, LogType.UserUnbanned)) is null) return; - var embed = new EmbedBuilder() + var embed = _sender.CreateEmbed() .WithOkColor() .WithTitle("♻️ " + GetText(logChannel.Guild, strs.user_unbanned)) .WithDescription(usr.ToString()!) @@ -1036,7 +1036,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor { } - var embed = new EmbedBuilder() + var embed = _sender.CreateEmbed() .WithOkColor() .WithTitle("🚫 " + GetText(logChannel.Guild, strs.user_banned)) .WithDescription(usr.ToString()!) @@ -1087,7 +1087,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor return; var resolvedMessage = msg.Resolve(TagHandling.FullName); - var embed = new EmbedBuilder() + var embed = _sender.CreateEmbed() .WithOkColor() .WithTitle("🗑 " + GetText(logChannel.Guild, strs.msg_del(((ITextChannel)msg.Channel).Name))) @@ -1147,7 +1147,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor || logChannel.Id == after.Channel.Id) return; - var embed = new EmbedBuilder() + var embed = _sender.CreateEmbed() .WithOkColor() .WithTitle("📝 " + GetText(logChannel.Guild, diff --git a/src/NadekoBot/Modules/Administration/ServerLog/ServerLogCommands.cs b/src/NadekoBot/Modules/Administration/ServerLog/ServerLogCommands.cs index d3c7be60b..ee3036cae 100644 --- a/src/NadekoBot/Modules/Administration/ServerLog/ServerLogCommands.cs +++ b/src/NadekoBot/Modules/Administration/ServerLog/ServerLogCommands.cs @@ -35,7 +35,7 @@ public partial class Administration var usrs = settings?.LogIgnores.Where(x => x.ItemType == IgnoredItemType.User).ToList() ?? new List(); - var eb = new EmbedBuilder() + var eb = _sender.CreateEmbed() .WithOkColor() .AddField(GetText(strs.log_ignored_channels), chs.Count == 0 diff --git a/src/NadekoBot/Modules/Administration/Timezone/TimeZoneCommands.cs b/src/NadekoBot/Modules/Administration/Timezone/TimeZoneCommands.cs index 0df0ecc80..aacee8713 100644 --- a/src/NadekoBot/Modules/Administration/Timezone/TimeZoneCommands.cs +++ b/src/NadekoBot/Modules/Administration/Timezone/TimeZoneCommands.cs @@ -33,17 +33,20 @@ public partial class Administration if (flip) return $"{offset} {Format.Code(nameStr)}"; return $"{Format.Code(offset)} {nameStr}"; - }); + }) + .ToList(); - await ctx.SendPaginatedConfirmAsync(page, - curPage => new EmbedBuilder() - .WithOkColor() - .WithTitle(GetText(strs.timezones_available)) - .WithDescription(string.Join("\n", - timezoneStrings.Skip(curPage * timezonesPerPage).Take(timezonesPerPage))), - timezones.Length, - timezonesPerPage); + await Response() + .Paginated() + .Items(timezoneStrings) + .PageSize(timezonesPerPage) + .CurrentPage(page) + .Page((items, _) => _sender.CreateEmbed() + .WithOkColor() + .WithTitle(GetText(strs.timezones_available)) + .WithDescription(string.Join("\n", items))) + .SendAsync(); } [Cmd] diff --git a/src/NadekoBot/Modules/Administration/UserPunish/UserPunishCommands.cs b/src/NadekoBot/Modules/Administration/UserPunish/UserPunishCommands.cs index 6ba7ed294..d1d6cca36 100644 --- a/src/NadekoBot/Modules/Administration/UserPunish/UserPunishCommands.cs +++ b/src/NadekoBot/Modules/Administration/UserPunish/UserPunishCommands.cs @@ -66,7 +66,7 @@ public partial class Administration try { await _sender.Response(user) - .Embed(new EmbedBuilder() + .Embed(_sender.CreateEmbed() .WithErrorColor() .WithDescription(GetText(strs.warned_on(ctx.Guild.ToString()))) .AddField(GetText(strs.moderator), ctx.User.ToString()) @@ -86,7 +86,7 @@ public partial class Administration catch (Exception ex) { Log.Warning(ex, "Exception occured while warning a user"); - var errorEmbed = new EmbedBuilder().WithErrorColor() + var errorEmbed = _sender.CreateEmbed().WithErrorColor() .WithDescription(GetText(strs.cant_apply_punishment)); if (dmFailed) @@ -96,7 +96,7 @@ public partial class Administration return; } - var embed = new EmbedBuilder().WithOkColor(); + var embed = _sender.CreateEmbed().WithOkColor(); if (punishment is null) embed.WithDescription(GetText(strs.user_warned(Format.Bold(user.ToString())))); else @@ -197,45 +197,46 @@ public partial class Administration var allWarnings = _service.UserWarnings(ctx.Guild.Id, userId); - await ctx.SendPaginatedConfirmAsync(inputPage, - page => - { - var warnings = allWarnings.Skip(page * 9).Take(9).ToArray(); + await Response() + .Paginated() + .Items(allWarnings) + .PageSize(9) + .CurrentPage(inputPage) + .Page((warnings, page) => + { + var user = (ctx.Guild as SocketGuild)?.GetUser(userId)?.ToString() ?? userId.ToString(); + var embed = _sender.CreateEmbed().WithOkColor().WithTitle(GetText(strs.warnlog_for(user))); - var user = (ctx.Guild as SocketGuild)?.GetUser(userId)?.ToString() ?? userId.ToString(); - var embed = new EmbedBuilder().WithOkColor().WithTitle(GetText(strs.warnlog_for(user))); + if (!warnings.Any()) + embed.WithDescription(GetText(strs.warnings_none)); + else + { + var descText = GetText(strs.warn_count( + Format.Bold(warnings.Where(x => !x.Forgiven).Sum(x => x.Weight).ToString()), + Format.Bold(warnings.Sum(x => x.Weight).ToString()))); - if (!warnings.Any()) - embed.WithDescription(GetText(strs.warnings_none)); - else - { - var descText = GetText(strs.warn_count( - Format.Bold(warnings.Where(x => !x.Forgiven).Sum(x => x.Weight).ToString()), - Format.Bold(warnings.Sum(x => x.Weight).ToString()))); + embed.WithDescription(descText); - embed.WithDescription(descText); + var i = page * 9; + foreach (var w in warnings) + { + i++; + var name = GetText(strs.warned_on_by(w.DateAdded?.ToString("dd.MM.yyy"), + w.DateAdded?.ToString("HH:mm"), + w.Moderator)); - var i = page * 9; - foreach (var w in warnings) - { - i++; - var name = GetText(strs.warned_on_by(w.DateAdded?.ToString("dd.MM.yyy"), - w.DateAdded?.ToString("HH:mm"), - w.Moderator)); - - if (w.Forgiven) - name = $"{Format.Strikethrough(name)} {GetText(strs.warn_cleared_by(w.ForgivenBy))}"; + if (w.Forgiven) + name = $"{Format.Strikethrough(name)} {GetText(strs.warn_cleared_by(w.ForgivenBy))}"; - embed.AddField($"#`{i}` " + name, - Format.Code(GetText(strs.warn_weight(w.Weight))) + '\n' + w.Reason.TrimTo(1000)); - } - } + embed.AddField($"#`{i}` " + name, + Format.Code(GetText(strs.warn_weight(w.Weight))) + '\n' + w.Reason.TrimTo(1000)); + } + } - return embed; - }, - allWarnings.Length, - 9); + return embed; + }) + .SendAsync(); } [Cmd] @@ -245,31 +246,32 @@ public partial class Administration { if (--page < 0) return; - var warnings = _service.WarnlogAll(ctx.Guild.Id); + var allWarnings = _service.WarnlogAll(ctx.Guild.Id); - await ctx.SendPaginatedConfirmAsync(page, - curPage => - { - var ws = warnings.Skip(curPage * 15) - .Take(15) - .ToArray() - .Select(x => - { - var all = x.Count(); - var forgiven = x.Count(y => y.Forgiven); - var total = all - forgiven; - var usr = ((SocketGuild)ctx.Guild).GetUser(x.Key); - return (usr?.ToString() ?? x.Key.ToString()) - + $" | {total} ({all} - {forgiven})"; - }); + await Response() + .Paginated() + .Items(allWarnings) + .PageSize(15) + .CurrentPage(page) + .Page((warnings, _) => + { + var ws = warnings + .Select(x => + { + var all = x.Count(); + var forgiven = x.Count(y => y.Forgiven); + var total = all - forgiven; + var usr = ((SocketGuild)ctx.Guild).GetUser(x.Key); + return (usr?.ToString() ?? x.Key.ToString()) + + $" | {total} ({all} - {forgiven})"; + }); - return new EmbedBuilder() - .WithOkColor() - .WithTitle(GetText(strs.warnings_list)) - .WithDescription(string.Join("\n", ws)); - }, - warnings.Length, - 15); + return _sender.CreateEmbed() + .WithOkColor() + .WithTitle(GetText(strs.warnings_list)) + .WithDescription(string.Join("\n", ws)); + }) + .SendAsync(); } [Cmd] @@ -450,7 +452,7 @@ public partial class Administration var user = await ctx.Client.GetUserAsync(userId); var banPrune = await _service.GetBanPruneAsync(ctx.Guild.Id) ?? 7; await _mute.TimedBan(ctx.Guild, userId, time.Time, (ctx.User + " | " + msg).TrimTo(512), banPrune); - var toSend = new EmbedBuilder() + var toSend = _sender.CreateEmbed() .WithOkColor() .WithTitle("⛔️ " + GetText(strs.banned_user)) .AddField(GetText(strs.username), user?.ToString() ?? userId.ToString(), true) @@ -478,10 +480,11 @@ public partial class Administration var banPrune = await _service.GetBanPruneAsync(ctx.Guild.Id) ?? 7; await ctx.Guild.AddBanAsync(userId, banPrune, (ctx.User + " | " + msg).TrimTo(512)); - await ctx.Channel.EmbedAsync(new EmbedBuilder() + await Response().Embed(_sender.CreateEmbed() .WithOkColor() .WithTitle("⛔️ " + GetText(strs.banned_user)) - .AddField("ID", userId.ToString(), true)); + .AddField("ID", userId.ToString(), true)) + .SendAsync(); } else await Ban(user, msg); @@ -514,7 +517,7 @@ public partial class Administration var banPrune = await _service.GetBanPruneAsync(ctx.Guild.Id) ?? 7; await ctx.Guild.AddBanAsync(user, banPrune, (ctx.User + " | " + msg).TrimTo(512)); - var toSend = new EmbedBuilder() + var toSend = _sender.CreateEmbed() .WithOkColor() .WithTitle("⛔️ " + GetText(strs.banned_user)) .AddField(GetText(strs.username), user.ToString(), true) @@ -709,7 +712,7 @@ public partial class Administration try { await ctx.Guild.RemoveBanAsync(user); } catch { await ctx.Guild.RemoveBanAsync(user); } - var toSend = new EmbedBuilder() + var toSend = _sender.CreateEmbed() .WithOkColor() .WithTitle("☣ " + GetText(strs.sb_user)) .AddField(GetText(strs.username), user.ToString(), true) @@ -764,7 +767,7 @@ public partial class Administration await user.KickAsync((ctx.User + " | " + msg).TrimTo(512)); - var toSend = new EmbedBuilder() + var toSend = _sender.CreateEmbed() .WithOkColor() .WithTitle(GetText(strs.kicked_user)) .AddField(GetText(strs.username), user.ToString(), true) @@ -797,7 +800,7 @@ public partial class Administration { var dmMessage = GetText(strs.timeoutdm(Format.Bold(ctx.Guild.Name), msg)); await _sender.Response(user) - .Embed(new EmbedBuilder() + .Embed(_sender.CreateEmbed() .WithPendingColor() .WithDescription(dmMessage)) .SendAsync(); @@ -809,7 +812,7 @@ public partial class Administration await user.SetTimeOutAsync(time.Time); - var toSend = new EmbedBuilder() + var toSend = _sender.CreateEmbed() .WithOkColor() .WithTitle("⏳ " + GetText(strs.timedout_user)) .AddField(GetText(strs.username), user.ToString(), true) @@ -870,7 +873,7 @@ public partial class Administration if (string.IsNullOrWhiteSpace(missStr)) missStr = "-"; - var toSend = new EmbedBuilder() + var toSend = _sender.CreateEmbed() .WithDescription(GetText(strs.mass_ban_in_progress(banning.Count))) .AddField(GetText(strs.invalid(missing.Count)), missStr) .WithPendingColor(); @@ -890,7 +893,7 @@ public partial class Administration } } - await banningMessage.ModifyAsync(x => x.Embed = new EmbedBuilder() + await banningMessage.ModifyAsync(x => x.Embed = _sender.CreateEmbed() .WithDescription( GetText(strs.mass_ban_completed(banning.Count()))) .AddField(GetText(strs.invalid(missing.Count)), missStr) @@ -915,11 +918,13 @@ public partial class Administration missStr = "-"; //send a message but don't wait for it - var banningMessageTask = ctx.Channel.EmbedAsync(new EmbedBuilder() - .WithDescription( - GetText(strs.mass_kill_in_progress(bans.Count()))) - .AddField(GetText(strs.invalid(missing)), missStr) - .WithPendingColor()); + var banningMessageTask = Response() + .Embed(_sender.CreateEmbed() + .WithDescription( + GetText(strs.mass_kill_in_progress(bans.Count()))) + .AddField(GetText(strs.invalid(missing)), missStr) + .WithPendingColor()) + .SendAsync(); var banPrune = await _service.GetBanPruneAsync(ctx.Guild.Id) ?? 7; //do the banning @@ -935,7 +940,7 @@ public partial class Administration //wait for the message and edit it var banningMessage = await banningMessageTask; - await banningMessage.ModifyAsync(x => x.Embed = new EmbedBuilder() + await banningMessage.ModifyAsync(x => x.Embed = _sender.CreateEmbed() .WithDescription( GetText(strs.mass_kill_completed(bans.Count()))) .AddField(GetText(strs.invalid(missing)), missStr) diff --git a/src/NadekoBot/Modules/Administration/VcRole/VcRoleCommands.cs b/src/NadekoBot/Modules/Administration/VcRole/VcRoleCommands.cs index 84e658d7e..f7f89875f 100644 --- a/src/NadekoBot/Modules/Administration/VcRole/VcRoleCommands.cs +++ b/src/NadekoBot/Modules/Administration/VcRole/VcRoleCommands.cs @@ -68,7 +68,7 @@ public partial class Administration else text = GetText(strs.no_vcroles); - await Response().Embed(new EmbedBuilder() + await Response().Embed(_sender.CreateEmbed() .WithOkColor() .WithTitle(GetText(strs.vc_role_list)) .WithDescription(text)).SendAsync(); diff --git a/src/NadekoBot/Modules/Expressions/NadekoExpressionExtensions.cs b/src/NadekoBot/Modules/Expressions/NadekoExpressionExtensions.cs index 309956eab..add39481e 100644 --- a/src/NadekoBot/Modules/Expressions/NadekoExpressionExtensions.cs +++ b/src/NadekoBot/Modules/Expressions/NadekoExpressionExtensions.cs @@ -14,7 +14,7 @@ public static class NadekoExpressionExtensions IUserMessage ctx, IReplacementService repSvc, DiscordSocketClient client, - bool sanitize) + IMessageSenderService sender) { var channel = cr.DmResponse ? await ctx.Author.CreateDMChannelAsync() : ctx.Channel; @@ -46,7 +46,7 @@ public static class NadekoExpressionExtensions var text = SmartText.CreateFrom(cr.Response); text = await repSvc.ReplaceAsync(text, repCtx); - return await channel.SendAsync(text, sanitize); + return await sender.Response(channel).Text(text).Sanitize(false).SendAsync(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/NadekoBot/Modules/Expressions/NadekoExpressions.cs b/src/NadekoBot/Modules/Expressions/NadekoExpressions.cs index 80d6f1df3..29815a4cb 100644 --- a/src/NadekoBot/Modules/Expressions/NadekoExpressions.cs +++ b/src/NadekoBot/Modules/Expressions/NadekoExpressions.cs @@ -33,7 +33,7 @@ public partial class NadekoExpressions : NadekoModule var ex = await _service.AddAsync(ctx.Guild?.Id, key, message); await Response() - .Embed(new EmbedBuilder() + .Embed(_sender.CreateEmbed() .WithOkColor() .WithTitle(GetText(strs.expr_new)) .WithDescription($"#{new kwum(ex.Id)}") @@ -66,6 +66,7 @@ public partial class NadekoExpressions : NadekoModule await ExprAddInternalAsync(key, message); } + [Cmd] public async Task ExprAdd(string key, [Leftover] string message) { @@ -102,13 +103,15 @@ public partial class NadekoExpressions : NadekoModule var ex = await _service.EditAsync(ctx.Guild?.Id, id, message); if (ex is not null) { - await ctx.Channel.EmbedAsync(new EmbedBuilder() - .WithOkColor() - .WithTitle(GetText(strs.expr_edited)) - .WithDescription($"#{id}") - .AddField(GetText(strs.trigger), ex.Trigger) - .AddField(GetText(strs.response), - message.Length > 1024 ? GetText(strs.redacted_too_long) : message)); + await Response() + .Embed(_sender.CreateEmbed() + .WithOkColor() + .WithTitle(GetText(strs.expr_edited)) + .WithDescription($"#{id}") + .AddField(GetText(strs.trigger), ex.Trigger) + .AddField(GetText(strs.response), + message.Length > 1024 ? GetText(strs.redacted_too_long) : message)) + .SendAsync(); } else { @@ -152,7 +155,7 @@ public partial class NadekoExpressions : NadekoModule : " // " + string.Join(" ", ex.GetReactions()))) .Join('\n'); - return new EmbedBuilder().WithOkColor().WithTitle(GetText(strs.expressions)).WithDescription(desc); + return _sender.CreateEmbed().WithOkColor().WithTitle(GetText(strs.expressions)).WithDescription(desc); }) .SendAsync(); } @@ -168,12 +171,14 @@ public partial class NadekoExpressions : NadekoModule return; } - await ctx.Channel.EmbedAsync(new EmbedBuilder() - .WithOkColor() - .WithDescription($"#{id}") - .AddField(GetText(strs.trigger), found.Trigger.TrimTo(1024)) - .AddField(GetText(strs.response), - found.Response.TrimTo(1000).Replace("](", "]\\("))); + await Response() + .Embed(_sender.CreateEmbed() + .WithOkColor() + .WithDescription($"#{id}") + .AddField(GetText(strs.trigger), found.Trigger.TrimTo(1024)) + .AddField(GetText(strs.response), + found.Response.TrimTo(1000).Replace("](", "]\\("))) + .SendAsync(); } public async Task ExprDeleteInternalAsync(kwum id) @@ -182,12 +187,14 @@ public partial class NadekoExpressions : NadekoModule if (ex is not null) { - await ctx.Channel.EmbedAsync(new EmbedBuilder() - .WithOkColor() - .WithTitle(GetText(strs.expr_deleted)) - .WithDescription($"#{id}") - .AddField(GetText(strs.trigger), ex.Trigger.TrimTo(1024)) - .AddField(GetText(strs.response), ex.Response.TrimTo(1024))); + await Response() + .Embed(_sender.CreateEmbed() + .WithOkColor() + .WithTitle(GetText(strs.expr_deleted)) + .WithDescription($"#{id}") + .AddField(GetText(strs.trigger), ex.Trigger.TrimTo(1024)) + .AddField(GetText(strs.response), ex.Response.TrimTo(1024))) + .SendAsync(); } else { @@ -332,7 +339,7 @@ public partial class NadekoExpressions : NadekoModule [UserPerm(GuildPerm.Administrator)] public async Task ExprClear() { - if (await PromptUserConfirmAsync(new EmbedBuilder() + if (await PromptUserConfirmAsync(_sender.CreateEmbed() .WithTitle("Expression clear") .WithDescription("This will delete all expressions on this server."))) { diff --git a/src/NadekoBot/Modules/Expressions/NadekoExpressionsService.cs b/src/NadekoBot/Modules/Expressions/NadekoExpressionsService.cs index d981951e6..6056f2e80 100644 --- a/src/NadekoBot/Modules/Expressions/NadekoExpressionsService.cs +++ b/src/NadekoBot/Modules/Expressions/NadekoExpressionsService.cs @@ -280,7 +280,7 @@ public sealed class NadekoExpressionsService : IExecOnMessage, IReadyExecutor } } - var sentMsg = await expr.Send(msg, _repSvc, _client, false); + var sentMsg = await expr.Send(msg, _repSvc, _client, _sender); var reactions = expr.GetReactions(); foreach (var reaction in reactions) diff --git a/src/NadekoBot/Modules/Gambling/AnimalRacing/AnimalRacingCommands.cs b/src/NadekoBot/Modules/Gambling/AnimalRacing/AnimalRacingCommands.cs index ddae2edde..265e72c15 100644 --- a/src/NadekoBot/Modules/Gambling/AnimalRacing/AnimalRacingCommands.cs +++ b/src/NadekoBot/Modules/Gambling/AnimalRacing/AnimalRacingCommands.cs @@ -128,7 +128,7 @@ public partial class Gambling raceMessage = await Response().Confirm(text).SendAsync(); else { - await msg.ModifyAsync(x => x.Embed = new EmbedBuilder() + await msg.ModifyAsync(x => x.Embed = _sender.CreateEmbed() .WithTitle(GetText(strs.animal_race)) .WithDescription(text) .WithOkColor() diff --git a/src/NadekoBot/Modules/Gambling/Bank/BankCommands.cs b/src/NadekoBot/Modules/Gambling/Bank/BankCommands.cs index 4ad9d97b0..7bf993fa0 100644 --- a/src/NadekoBot/Modules/Gambling/Bank/BankCommands.cs +++ b/src/NadekoBot/Modules/Gambling/Bank/BankCommands.cs @@ -59,7 +59,7 @@ public partial class Gambling { var bal = await _bank.GetBalanceAsync(ctx.User.Id); - var eb = new EmbedBuilder() + var eb = _sender.CreateEmbed() .WithOkColor() .WithDescription(GetText(strs.bank_balance(N(bal)))); diff --git a/src/NadekoBot/Modules/Gambling/BlackJack/BlackJackCommands.cs b/src/NadekoBot/Modules/Gambling/BlackJack/BlackJackCommands.cs index dc42a792a..103860dbd 100644 --- a/src/NadekoBot/Modules/Gambling/BlackJack/BlackJackCommands.cs +++ b/src/NadekoBot/Modules/Gambling/BlackJack/BlackJackCommands.cs @@ -95,7 +95,7 @@ public partial class Gambling var cStr = string.Concat(c.Select(x => x[..^1] + " ")); cStr += "\n" + string.Concat(c.Select(x => x.Last() + " ")); - var embed = new EmbedBuilder() + var embed = _sender.CreateEmbed() .WithOkColor() .WithTitle("BlackJack") .AddField($"{dealerIcon} Dealer's Hand | Value: {bj.Dealer.GetHandValue()}", cStr); diff --git a/src/NadekoBot/Modules/Gambling/Connect4/Connect4Commands.cs b/src/NadekoBot/Modules/Gambling/Connect4/Connect4Commands.cs index 9bf3d43b6..d405fec9b 100644 --- a/src/NadekoBot/Modules/Gambling/Connect4/Connect4Commands.cs +++ b/src/NadekoBot/Modules/Gambling/Connect4/Connect4Commands.cs @@ -150,7 +150,7 @@ public partial class Gambling else title = GetText(strs.connect4_draw); - return msg.ModifyAsync(x => x.Embed = new EmbedBuilder() + return msg.ModifyAsync(x => x.Embed = _sender.CreateEmbed() .WithTitle(title) .WithDescription(GetGameStateText(game)) .WithOkColor() @@ -160,7 +160,7 @@ public partial class Gambling private async Task Game_OnGameStateUpdated(Connect4Game game) { - var embed = new EmbedBuilder() + var embed = _sender.CreateEmbed() .WithTitle($"{game.CurrentPlayer.Username} vs {game.OtherPlayer.Username}") .WithDescription(GetGameStateText(game)) .WithOkColor(); diff --git a/src/NadekoBot/Modules/Gambling/DiceRoll/DiceRollCommands.cs b/src/NadekoBot/Modules/Gambling/DiceRoll/DiceRollCommands.cs index b37b680e3..2ffeeae28 100644 --- a/src/NadekoBot/Modules/Gambling/DiceRoll/DiceRollCommands.cs +++ b/src/NadekoBot/Modules/Gambling/DiceRoll/DiceRollCommands.cs @@ -38,7 +38,7 @@ public partial class Gambling var fileName = $"dice.{format.FileExtensions.First()}"; - var eb = new EmbedBuilder() + var eb = _sender.CreateEmbed() .WithOkColor() .WithAuthor(ctx.User) .AddField(GetText(strs.roll2), gen) @@ -115,7 +115,7 @@ public partial class Gambling d.Dispose(); var imageName = $"dice.{format.FileExtensions.First()}"; - var eb = new EmbedBuilder() + var eb = _sender.CreateEmbed() .WithOkColor() .WithAuthor(ctx.User) .AddField(GetText(strs.rolls), values.Select(x => Format.Code(x.ToString())).Join(' '), true) @@ -141,7 +141,7 @@ public partial class Gambling for (var i = 0; i < n1; i++) rolls.Add(_fateRolls[rng.Next(0, _fateRolls.Length)]); - var embed = new EmbedBuilder() + var embed = _sender.CreateEmbed() .WithOkColor() .WithAuthor(ctx.User) .WithDescription(GetText(strs.dice_rolled_num(Format.Bold(n1.ToString())))) @@ -170,7 +170,7 @@ public partial class Gambling arr[i] = rng.Next(1, n2 + 1); var sum = arr.Sum(); - var embed = new EmbedBuilder() + var embed = _sender.CreateEmbed() .WithOkColor() .WithAuthor(ctx.User) .WithDescription(GetText(strs.dice_rolled_num(n1 + $"`1 - {n2}`"))) diff --git a/src/NadekoBot/Modules/Gambling/Draw/DrawCommands.cs b/src/NadekoBot/Modules/Gambling/Draw/DrawCommands.cs index 017aafeed..ee6dc1354 100644 --- a/src/NadekoBot/Modules/Gambling/Draw/DrawCommands.cs +++ b/src/NadekoBot/Modules/Gambling/Draw/DrawCommands.cs @@ -55,7 +55,7 @@ public partial class Gambling foreach (var i in images) i.Dispose(); - var eb = new EmbedBuilder() + var eb = _sender.CreateEmbed() .WithOkColor(); var toSend = string.Empty; @@ -160,7 +160,7 @@ public partial class Gambling return; } - var eb = new EmbedBuilder() + var eb = _sender.CreateEmbed() .WithOkColor() .WithAuthor(ctx.User) .WithDescription(result.Card.GetEmoji()) diff --git a/src/NadekoBot/Modules/Gambling/Events/CurrencyEventsCommands.cs b/src/NadekoBot/Modules/Gambling/Events/CurrencyEventsCommands.cs index 141658b5f..cb140673f 100644 --- a/src/NadekoBot/Modules/Gambling/Events/CurrencyEventsCommands.cs +++ b/src/NadekoBot/Modules/Gambling/Events/CurrencyEventsCommands.cs @@ -30,12 +30,12 @@ public partial class Gambling private EmbedBuilder GetEmbed(CurrencyEvent.Type type, EventOptions opts, long currentPot) => type switch { - CurrencyEvent.Type.Reaction => new EmbedBuilder() + CurrencyEvent.Type.Reaction => _sender.CreateEmbed() .WithOkColor() .WithTitle(GetText(strs.event_title(type.ToString()))) .WithDescription(GetReactionDescription(opts.Amount, currentPot)) .WithFooter(GetText(strs.event_duration_footer(opts.Hours))), - CurrencyEvent.Type.GameStatus => new EmbedBuilder() + CurrencyEvent.Type.GameStatus => _sender.CreateEmbed() .WithOkColor() .WithTitle(GetText(strs.event_title(type.ToString()))) .WithDescription(GetGameStatusDescription(opts.Amount, currentPot)) diff --git a/src/NadekoBot/Modules/Gambling/FlipCoin/FlipCoinCommands.cs b/src/NadekoBot/Modules/Gambling/FlipCoin/FlipCoinCommands.cs index 32d98d508..a0d1962f5 100644 --- a/src/NadekoBot/Modules/Gambling/FlipCoin/FlipCoinCommands.cs +++ b/src/NadekoBot/Modules/Gambling/FlipCoin/FlipCoinCommands.cs @@ -84,7 +84,7 @@ public partial class Gambling ? Format.Bold(GetText(strs.heads)) : Format.Bold(GetText(strs.tails)))); - var eb = new EmbedBuilder() + var eb = _sender.CreateEmbed() .WithOkColor() .WithAuthor(ctx.User) .WithDescription(msg) @@ -130,7 +130,7 @@ public partial class Gambling str = Format.Bold(GetText(strs.better_luck)); } - await Response().Embed(new EmbedBuilder() + await Response().Embed(_sender.CreateEmbed() .WithAuthor(ctx.User) .WithDescription(str) .WithOkColor() diff --git a/src/NadekoBot/Modules/Gambling/Gambling.cs b/src/NadekoBot/Modules/Gambling/Gambling.cs index b582565b2..54de7a1bb 100644 --- a/src/NadekoBot/Modules/Gambling/Gambling.cs +++ b/src/NadekoBot/Modules/Gambling/Gambling.cs @@ -73,7 +73,7 @@ public partial class Gambling : GamblingModule { var stats = await _gamblingTxTracker.GetAllAsync(); - var eb = new EmbedBuilder() + var eb = _sender.CreateEmbed() .WithOkColor(); var str = "` Feature `|`   Bet  `|`Paid Out`|`  RoI  `\n"; @@ -118,7 +118,7 @@ public partial class Gambling : GamblingModule } // [21:03] Bob Page: Kinda remids me of US economy - var embed = new EmbedBuilder() + var embed = _sender.CreateEmbed() .WithTitle(GetText(strs.economy_state)) .AddField(GetText(strs.currency_owned), N(ec.Cash - ec.Bot)) .AddField(GetText(strs.currency_one_percent), (onePercent * 100).ToString("F2") + "%") @@ -310,7 +310,7 @@ public partial class Gambling : GamblingModule trs = await uow.Set().GetPageFor(userId, page); } - var embed = new EmbedBuilder() + var embed = _sender.CreateEmbed() .WithTitle(GetText(strs.transactions(((SocketGuild)ctx.Guild)?.GetUser(userId)?.ToString() ?? $"{userId}"))) .WithOkColor(); @@ -360,7 +360,7 @@ public partial class Gambling : GamblingModule return; } - var eb = new EmbedBuilder().WithOkColor(); + var eb = _sender.CreateEmbed().WithOkColor(); eb.WithAuthor(ctx.User); eb.WithTitle(GetText(strs.transaction)); @@ -624,7 +624,7 @@ public partial class Gambling : GamblingModule return; } - var embed = new EmbedBuilder().WithOkColor().WithTitle(GetText(strs.roll_duel)); + var embed = _sender.CreateEmbed().WithOkColor().WithTitle(GetText(strs.roll_duel)); var description = string.Empty; @@ -731,7 +731,7 @@ public partial class Gambling : GamblingModule str = GetText(strs.better_luck); } - var eb = new EmbedBuilder() + var eb = _sender.CreateEmbed() .WithAuthor(ctx.User) .WithDescription(Format.Bold(str)) .AddField(GetText(strs.roll2), result.Roll.ToString(CultureInfo.InvariantCulture)) @@ -758,68 +758,64 @@ public partial class Gambling : GamblingModule var (opts, _) = OptionsParser.ParseFrom(new LbOpts(), args); - List cleanRichest; + // List cleanRichest; // it's pointless to have clean on dm context if (ctx.Guild is null) { opts.Clean = false; } - if (opts.Clean) + + async Task> GetTopRichest(int curPage) { - await using (var uow = _db.GetDbContext()) + if (opts.Clean) { - cleanRichest = await uow.Set().GetTopRichest(_client.CurrentUser.Id, 0, 10_000); + await ctx.Channel.TriggerTypingAsync(); + await _tracker.EnsureUsersDownloadedAsync(ctx.Guild); + + await using var uow = _db.GetDbContext(); + + var cleanRichest = await uow.Set() + .GetTopRichest(_client.CurrentUser.Id, 0, 10_000); + + var sg = (SocketGuild)ctx.Guild!; + return cleanRichest.Where(x => sg.GetUser(x.UserId) is not null).ToList(); } - - await ctx.Channel.TriggerTypingAsync(); - await _tracker.EnsureUsersDownloadedAsync(ctx.Guild); - - var sg = (SocketGuild)ctx.Guild!; - cleanRichest = cleanRichest.Where(x => sg.GetUser(x.UserId) is not null).ToList(); - } - else - { - await using var uow = _db.GetDbContext(); - cleanRichest = await uow.Set().GetTopRichest(_client.CurrentUser.Id, page); - } - - await ctx.SendPaginatedConfirmAsync(page, - async curPage => + else { - var embed = new EmbedBuilder().WithOkColor().WithTitle(CurrencySign + " " + GetText(strs.leaderboard)); + await using var uow = _db.GetDbContext(); + return await uow.Set().GetTopRichest(_client.CurrentUser.Id, curPage); + } + } - List toSend; - if (!opts.Clean) - { - await using var uow = _db.GetDbContext(); - toSend = await uow.Set().GetTopRichest(_client.CurrentUser.Id, curPage); - } - else - { - toSend = cleanRichest.Skip(curPage * 9).Take(9).ToList(); - } + await Response() + .Paginated() + .PageItems(GetTopRichest) + .PageSize(9) + .CurrentPage(page) + .Page((toSend, curPage) => + { + var embed = _sender.CreateEmbed().WithOkColor() + .WithTitle(CurrencySign + " " + GetText(strs.leaderboard)); - if (!toSend.Any()) - { - embed.WithDescription(GetText(strs.no_user_on_this_page)); - return embed; - } + if (!toSend.Any()) + { + embed.WithDescription(GetText(strs.no_user_on_this_page)); + return Task.FromResult(embed); + } - for (var i = 0; i < toSend.Count; i++) - { - var x = toSend[i]; - var usrStr = x.ToString().TrimTo(20, true); + for (var i = 0; i < toSend.Count; i++) + { + var x = toSend[i]; + var usrStr = x.ToString().TrimTo(20, true); - var j = i; - embed.AddField("#" + ((9 * curPage) + j + 1) + " " + usrStr, N(x.CurrencyAmount), true); - } + var j = i; + embed.AddField("#" + ((9 * curPage) + j + 1) + " " + usrStr, N(x.CurrencyAmount), true); + } - return embed; - }, - opts.Clean ? cleanRichest.Count() : 9000, - 9, - opts.Clean); + return Task.FromResult(embed); + }) + .SendAsync(); } public enum InputRpsPick : byte @@ -861,7 +857,7 @@ public partial class Gambling : GamblingModule return; } - var embed = new EmbedBuilder(); + var embed = _sender.CreateEmbed(); string msg; if (result.Result == RpsResultType.Draw) @@ -922,7 +918,7 @@ public partial class Gambling : GamblingModule sb.AppendLine(); } - var eb = new EmbedBuilder() + var eb = _sender.CreateEmbed() .WithOkColor() .WithDescription(sb.ToString()) .AddField(GetText(strs.multiplier), $"{result.Multiplier:0.##}x", true) diff --git a/src/NadekoBot/Modules/Gambling/PlantPick/PlantAndPickCommands.cs b/src/NadekoBot/Modules/Gambling/PlantPick/PlantAndPickCommands.cs index fc8a5e505..3297ed2f8 100644 --- a/src/NadekoBot/Modules/Gambling/PlantPick/PlantAndPickCommands.cs +++ b/src/NadekoBot/Modules/Gambling/PlantPick/PlantAndPickCommands.cs @@ -92,21 +92,23 @@ public partial class Gambling { if (--page < 0) return Task.CompletedTask; + var enabledIn = _service.GetAllGeneratingChannels(); - return ctx.SendPaginatedConfirmAsync(page, - _ => - { - var items = enabledIn.Skip(page * 9).Take(9).ToList(); + return Response() + .Paginated() + .Items(enabledIn.ToList()) + .PageSize(9) + .CurrentPage(page) + .Page((items, _) => + { + if (!items.Any()) + return _sender.CreateEmbed().WithErrorColor().WithDescription("-"); - if (!items.Any()) - return new EmbedBuilder().WithErrorColor().WithDescription("-"); - - return items.Aggregate(new EmbedBuilder().WithOkColor(), - (eb, i) => eb.AddField(i.GuildId.ToString(), i.ChannelId)); - }, - enabledIn.Count(), - 9); + return items.Aggregate(_sender.CreateEmbed().WithOkColor(), + (eb, i) => eb.AddField(i.GuildId.ToString(), i.ChannelId)); + }) + .SendAsync(); } } } \ No newline at end of file diff --git a/src/NadekoBot/Modules/Gambling/Shop/ShopCommands.cs b/src/NadekoBot/Modules/Gambling/Shop/ShopCommands.cs index 201985e4e..7d7bd23cd 100644 --- a/src/NadekoBot/Modules/Gambling/Shop/ShopCommands.cs +++ b/src/NadekoBot/Modules/Gambling/Shop/ShopCommands.cs @@ -48,27 +48,29 @@ public partial class Gambling var entries = uow.GuildConfigsForId(ctx.Guild.Id, set => set.Include(x => x.ShopEntries).ThenInclude(x => x.Items)) .ShopEntries.ToIndexed(); - return ctx.SendPaginatedConfirmAsync(page, - curPage => - { - var theseEntries = entries.Skip(curPage * 9).Take(9).ToArray(); - if (!theseEntries.Any()) - return new EmbedBuilder().WithErrorColor().WithDescription(GetText(strs.shop_none)); - var embed = new EmbedBuilder().WithOkColor().WithTitle(GetText(strs.shop)); + return Response() + .Paginated() + .Items(entries.ToList()) + .PageSize(9) + .CurrentPage(page) + .Page((items, curPage) => + { + if (!items.Any()) + return _sender.CreateEmbed().WithErrorColor().WithDescription(GetText(strs.shop_none)); + var embed = _sender.CreateEmbed().WithOkColor().WithTitle(GetText(strs.shop)); - for (var i = 0; i < theseEntries.Length; i++) - { - var entry = theseEntries[i]; - embed.AddField($"#{(curPage * 9) + i + 1} - {N(entry.Price)}", - EntryToString(entry), - true); - } + for (var i = 0; i < items.Count; i++) + { + var entry = items[i]; + embed.AddField($"#{(curPage * 9) + i + 1} - {N(entry.Price)}", + EntryToString(entry), + true); + } - return embed; - }, - entries.Count, - 9); + return embed; + }) + .SendAsync(); } [Cmd] @@ -187,7 +189,7 @@ public partial class Gambling { await Response() .User(ctx.User) - .Embed(new EmbedBuilder() + .Embed(_sender.CreateEmbed() .WithOkColor() .WithTitle(GetText(strs.shop_purchase(ctx.Guild.Name))) .AddField(GetText(strs.item), item.Text) @@ -246,7 +248,7 @@ public partial class Gambling else { var cmd = entry.Command.Replace("%you%", ctx.User.Id.ToString()); - var eb = new EmbedBuilder() + var eb = _sender.CreateEmbed() .WithPendingColor() .WithTitle("Executing shop command") .WithDescription(cmd); @@ -268,10 +270,11 @@ public partial class Gambling try { var pendingMsg = await msgTask; - await pendingMsg.EditAsync(SmartEmbedText.FromEmbed(eb - .WithOkColor() - .WithTitle("Shop command executed") - .Build())); + await pendingMsg.EditAsync( + SmartEmbedText.FromEmbed(eb + .WithOkColor() + .WithTitle("Shop command executed") + .Build())); } catch { @@ -531,7 +534,7 @@ public partial class Gambling public EmbedBuilder EntryToEmbed(ShopEntry entry) { - var embed = new EmbedBuilder().WithOkColor(); + var embed = _sender.CreateEmbed().WithOkColor(); if (entry.Type == ShopEntryType.Role) { diff --git a/src/NadekoBot/Modules/Gambling/Slot/SlotCommands.cs b/src/NadekoBot/Modules/Gambling/Slot/SlotCommands.cs index 8ca24fbc6..4fa4481f1 100644 --- a/src/NadekoBot/Modules/Gambling/Slot/SlotCommands.cs +++ b/src/NadekoBot/Modules/Gambling/Slot/SlotCommands.cs @@ -69,7 +69,7 @@ public partial class Gambling await using var imgStream = await image.ToStreamAsync(); - var eb = new EmbedBuilder() + var eb = _sender.CreateEmbed() .WithAuthor(ctx.User) .WithDescription(Format.Bold(text)) .WithImageUrl($"attachment://result.png") diff --git a/src/NadekoBot/Modules/Gambling/Waifus/WaifuClaimCommands.cs b/src/NadekoBot/Modules/Gambling/Waifus/WaifuClaimCommands.cs index 146c3327c..214e512a6 100644 --- a/src/NadekoBot/Modules/Gambling/Waifus/WaifuClaimCommands.cs +++ b/src/NadekoBot/Modules/Gambling/Waifus/WaifuClaimCommands.cs @@ -20,9 +20,9 @@ public partial class Gambling public async Task WaifuReset() { var price = _service.GetResetPrice(ctx.User); - var embed = new EmbedBuilder() - .WithTitle(GetText(strs.waifu_reset_confirm)) - .WithDescription(GetText(strs.waifu_reset_price(Format.Bold(N(price))))); + var embed = _sender.CreateEmbed() + .WithTitle(GetText(strs.waifu_reset_confirm)) + .WithDescription(GetText(strs.waifu_reset_price(Format.Bold(N(price))))); if (!await PromptUserConfirmAsync(embed)) return; @@ -222,7 +222,7 @@ public partial class Gambling return; } - var embed = new EmbedBuilder().WithTitle(GetText(strs.waifus_top_waifus)).WithOkColor(); + var embed = _sender.CreateEmbed().WithTitle(GetText(strs.waifus_top_waifus)).WithOkColor(); var i = 0; foreach (var w in waifus) @@ -306,25 +306,25 @@ public partial class Gambling if (string.IsNullOrWhiteSpace(fansStr)) fansStr = "-"; - var embed = new EmbedBuilder() - .WithOkColor() - .WithTitle(GetText(strs.waifu) - + " " - + (wi.FullName ?? name ?? targetId.ToString()) - + " - \"the " - + _service.GetClaimTitle(wi.ClaimCount) - + "\"") - .AddField(GetText(strs.price), N(wi.Price), true) - .AddField(GetText(strs.claimed_by), wi.ClaimerName ?? nobody, true) - .AddField(GetText(strs.likes), wi.AffinityName ?? nobody, true) - .AddField(GetText(strs.changes_of_heart), $"{wi.AffinityCount} - \"the {affInfo}\"", true) - .AddField(GetText(strs.divorces), wi.DivorceCount.ToString(), true) - .AddField("\u200B", "\u200B", true) - .AddField(GetText(strs.fans(fansList.Count)), fansStr, true) - .AddField($"Waifus ({wi.ClaimCount})", - wi.ClaimCount == 0 ? nobody : claimsStr, - true) - .AddField(GetText(strs.gifts), itemsStr, true); + var embed = _sender.CreateEmbed() + .WithOkColor() + .WithTitle(GetText(strs.waifu) + + " " + + (wi.FullName ?? name ?? targetId.ToString()) + + " - \"the " + + _service.GetClaimTitle(wi.ClaimCount) + + "\"") + .AddField(GetText(strs.price), N(wi.Price), true) + .AddField(GetText(strs.claimed_by), wi.ClaimerName ?? nobody, true) + .AddField(GetText(strs.likes), wi.AffinityName ?? nobody, true) + .AddField(GetText(strs.changes_of_heart), $"{wi.AffinityCount} - \"the {affInfo}\"", true) + .AddField(GetText(strs.divorces), wi.DivorceCount.ToString(), true) + .AddField("\u200B", "\u200B", true) + .AddField(GetText(strs.fans(fansList.Count)), fansStr, true) + .AddField($"Waifus ({wi.ClaimCount})", + wi.ClaimCount == 0 ? nobody : claimsStr, + true) + .AddField(GetText(strs.gifts), itemsStr, true); await Response().Embed(embed).SendAsync(); } @@ -338,25 +338,27 @@ public partial class Gambling return; var waifuItems = _service.GetWaifuItems(); - await ctx.SendPaginatedConfirmAsync(page, - cur => - { - var embed = new EmbedBuilder().WithTitle(GetText(strs.waifu_gift_shop)).WithOkColor(); + await Response() + .Paginated() + .Items(waifuItems.OrderBy(x => x.Negative) + .ThenBy(x => x.Price) + .ToList()) + .PageSize(9) + .CurrentPage(page) + .Page((items, _) => + { + var embed = _sender.CreateEmbed().WithTitle(GetText(strs.waifu_gift_shop)).WithOkColor(); + + items + .ToList() + .ForEach(x => embed.AddField( + $"{(!x.Negative ? string.Empty : "\\💔")} {x.ItemEmoji} {x.Name}", + Format.Bold(N(x.Price)), + true)); - waifuItems.OrderBy(x => x.Negative) - .ThenBy(x => x.Price) - .Skip(9 * cur) - .Take(9) - .ToList() - .ForEach(x => embed.AddField( - $"{(!x.Negative ? string.Empty : "\\💔")} {x.ItemEmoji} {x.Name}", - Format.Bold(N(x.Price)), - true)); - - return embed; - }, - waifuItems.Count, - 9); + return embed; + }) + .SendAsync(); } [Cmd] diff --git a/src/NadekoBot/Modules/Games/Acrophobia/AcropobiaCommands.cs b/src/NadekoBot/Modules/Games/Acrophobia/AcropobiaCommands.cs index dbb28b101..96ef4993d 100644 --- a/src/NadekoBot/Modules/Games/Acrophobia/AcropobiaCommands.cs +++ b/src/NadekoBot/Modules/Games/Acrophobia/AcropobiaCommands.cs @@ -67,7 +67,7 @@ public partial class Games private Task Game_OnStarted(AcrophobiaGame game) { - var embed = new EmbedBuilder() + var embed = _sender.CreateEmbed() .WithOkColor() .WithTitle(GetText(strs.acrophobia)) .WithDescription( @@ -92,7 +92,7 @@ public partial class Games if (submissions.Length == 1) { - await Response().Embed(new EmbedBuilder() + await Response().Embed(_sender.CreateEmbed() .WithOkColor() .WithDescription(GetText( strs.acro_winner_only( @@ -103,7 +103,7 @@ public partial class Games var i = 0; - var embed = new EmbedBuilder() + var embed = _sender.CreateEmbed() .WithOkColor() .WithTitle(GetText(strs.acrophobia) + " - " + GetText(strs.submissions_closed)) .WithDescription(GetText(strs.acro_nym_was( @@ -127,7 +127,7 @@ public partial class Games var table = votes.OrderByDescending(v => v.Value); var winner = table.First(); - var embed = new EmbedBuilder() + var embed = _sender.CreateEmbed() .WithOkColor() .WithTitle(GetText(strs.acrophobia)) .WithDescription(GetText(strs.acro_winner(Format.Bold(winner.Key.UserName), diff --git a/src/NadekoBot/Modules/Games/Games.cs b/src/NadekoBot/Modules/Games/Games.cs index becfa2eeb..02a355252 100644 --- a/src/NadekoBot/Modules/Games/Games.cs +++ b/src/NadekoBot/Modules/Games/Games.cs @@ -38,7 +38,7 @@ public partial class Games : NadekoModule return; var res = _service.GetEightballResponse(ctx.User.Id, question); - await Response().Embed(new EmbedBuilder() + await Response().Embed(_sender.CreateEmbed() .WithOkColor() .WithDescription(ctx.User.ToString()) .AddField("❓ " + GetText(strs.question), question) diff --git a/src/NadekoBot/Modules/Games/Hangman/HangmanCommands.cs b/src/NadekoBot/Modules/Games/Hangman/HangmanCommands.cs index b5324cb30..417f05e9e 100644 --- a/src/NadekoBot/Modules/Games/Hangman/HangmanCommands.cs +++ b/src/NadekoBot/Modules/Games/Hangman/HangmanCommands.cs @@ -23,11 +23,11 @@ public partial class Games /-\ """; - public static EmbedBuilder GetEmbed(HangmanGame.State state) + public static EmbedBuilder GetEmbed(IMessageSenderService sender, HangmanGame.State state) { if (state.Phase == HangmanGame.Phase.Running) { - return new EmbedBuilder() + return sender.CreateEmbed() .WithOkColor() .AddField("Hangman", Draw(state)) .AddField("Guess", Format.Code(state.Word)) @@ -36,14 +36,14 @@ public partial class Games if (state.Phase == HangmanGame.Phase.Ended && state.Failed) { - return new EmbedBuilder() + return sender.CreateEmbed() .WithErrorColor() .AddField("Hangman", Draw(state)) .AddField("Guess", Format.Code(state.Word)) .WithFooter(state.MissedLetters.Join(' ')); } - return new EmbedBuilder() + return sender.CreateEmbed() .WithOkColor() .AddField("Hangman", Draw(state)) .AddField("Guess", Format.Code(state.Word)) @@ -60,7 +60,7 @@ public partial class Games return; } - var eb = GetEmbed(hangman); + var eb = GetEmbed(_sender, hangman); eb.WithDescription(GetText(strs.hangman_game_started)); await Response().Embed(eb).SendAsync(); } diff --git a/src/NadekoBot/Modules/Games/Hangman/HangmanService.cs b/src/NadekoBot/Modules/Games/Hangman/HangmanService.cs index 6f580db20..1f5efcfc7 100644 --- a/src/NadekoBot/Modules/Games/Hangman/HangmanService.cs +++ b/src/NadekoBot/Modules/Games/Hangman/HangmanService.cs @@ -116,7 +116,7 @@ public sealed class HangmanService : IHangmanService, IExecNoCommand string content, HangmanGame.State state) { - var embed = Games.HangmanCommands.GetEmbed(state); + var embed = Games.HangmanCommands.GetEmbed(_sender, state); if (state.GuessResult == HangmanGame.GuessResult.Guess) embed.WithDescription($"{user} guessed the letter {content}!").WithOkColor(); else if (state.GuessResult == HangmanGame.GuessResult.Incorrect && state.Failed) diff --git a/src/NadekoBot/Modules/Games/SpeedTyping/SpeedTypingCommands.cs b/src/NadekoBot/Modules/Games/SpeedTyping/SpeedTypingCommands.cs index 0e7bc5234..cc6d302a6 100644 --- a/src/NadekoBot/Modules/Games/SpeedTyping/SpeedTypingCommands.cs +++ b/src/NadekoBot/Modules/Games/SpeedTyping/SpeedTypingCommands.cs @@ -94,7 +94,7 @@ public partial class Games if (removed is null) return; - var embed = new EmbedBuilder() + var embed = _sender.CreateEmbed() .WithTitle($"Removed typing article #{index + 1}") .WithDescription(removed.Text.TrimTo(50)) .WithOkColor(); diff --git a/src/NadekoBot/Modules/Games/SpeedTyping/TypingGame.cs b/src/NadekoBot/Modules/Games/SpeedTyping/TypingGame.cs index 297b4ceb5..8a22954ac 100644 --- a/src/NadekoBot/Modules/Games/SpeedTyping/TypingGame.cs +++ b/src/NadekoBot/Modules/Games/SpeedTyping/TypingGame.cs @@ -82,7 +82,6 @@ public class TypingGame do { - // todo fix all modifies await Task.Delay(2000); time -= 2; try { await msg.ModifyAsync(m => m.Content = $"Starting new typing contest in **{time}**.."); } @@ -145,7 +144,7 @@ public class TypingGame var wpm = CurrentSentence.Length / WORD_VALUE / elapsed.TotalSeconds * 60; _finishedUserIds.Add(msg.Author.Id); - var embed = new EmbedBuilder() + var embed = _sender.CreateEmbed() .WithOkColor() .WithTitle($"{msg.Author} finished the race!") .AddField("Place", $"#{_finishedUserIds.Count}", true) diff --git a/src/NadekoBot/Modules/Games/TicTacToe/TicTacToe.cs b/src/NadekoBot/Modules/Games/TicTacToe/TicTacToe.cs index 279afc9f9..e73f708c8 100644 --- a/src/NadekoBot/Modules/Games/TicTacToe/TicTacToe.cs +++ b/src/NadekoBot/Modules/Games/TicTacToe/TicTacToe.cs @@ -73,7 +73,7 @@ public class TicTacToe public EmbedBuilder GetEmbed(string title = null) { - var embed = new EmbedBuilder() + var embed = _sender.CreateEmbed() .WithOkColor() .WithDescription(Environment.NewLine + GetState()) .WithAuthor(GetText(strs.vs(_users[0], _users[1]))); diff --git a/src/NadekoBot/Modules/Games/Trivia/Games.cs b/src/NadekoBot/Modules/Games/Trivia/Games.cs index 031dedd11..92714a2ac 100644 --- a/src/NadekoBot/Modules/Games/Trivia/Games.cs +++ b/src/NadekoBot/Modules/Games/Trivia/Games.cs @@ -160,7 +160,7 @@ public partial class Games { try { - questionEmbed = new EmbedBuilder() + questionEmbed = _sender.CreateEmbed() .WithOkColor() .WithTitle(GetText(strs.trivia_game)) .AddField(GetText(strs.category), question.Category) @@ -189,7 +189,7 @@ public partial class Games { try { - var embed = new EmbedBuilder() + var embed = _sender.CreateEmbed() .WithErrorColor() .WithTitle(GetText(strs.trivia_game)) .WithDescription(GetText(strs.trivia_times_up(Format.Bold(question.Answer)))); @@ -221,7 +221,7 @@ public partial class Games { try { - await Response().Embed(new EmbedBuilder() + await Response().Embed(_sender.CreateEmbed() .WithOkColor() .WithAuthor(GetText(strs.trivia_ended)) .WithTitle(GetText(strs.leaderboard)) @@ -247,7 +247,7 @@ public partial class Games { try { - var embed = new EmbedBuilder() + var embed = _sender.CreateEmbed() .WithOkColor() .WithTitle(GetText(strs.trivia_game)) .WithDescription(GetText(strs.trivia_win(user.Name, diff --git a/src/NadekoBot/Modules/Help/Help.cs b/src/NadekoBot/Modules/Help/Help.cs index 90db86781..e0bc21bb6 100644 --- a/src/NadekoBot/Modules/Help/Help.cs +++ b/src/NadekoBot/Modules/Help/Help.cs @@ -84,32 +84,32 @@ public sealed class Help : NadekoModule topLevelModules.Add(m); } - await ctx.SendPaginatedConfirmAsync(page, - cur => - { - var embed = new EmbedBuilder().WithOkColor().WithTitle(GetText(strs.list_of_modules)); + await Response() + .Paginated() + .Items(topLevelModules) + .CurrentPage(page) + .AddFooter(false) + .Page((items, _) => + { + var embed = _sender.CreateEmbed().WithOkColor().WithTitle(GetText(strs.list_of_modules)); - var localModules = topLevelModules.Skip(12 * cur).Take(12).ToList(); + if (!items.Any()) + { + embed = embed.WithOkColor().WithDescription(GetText(strs.module_page_empty)); + return embed; + } - if (!localModules.Any()) - { - embed = embed.WithOkColor().WithDescription(GetText(strs.module_page_empty)); - return embed; - } + items.OrderBy(module => module.Name) + .ToList() + .ForEach(module => embed.AddField($"{GetModuleEmoji(module.Name)} {module.Name}", + GetModuleDescription(module.Name) + + "\n" + + Format.Code(GetText(strs.module_footer(prefix, module.Name.ToLowerInvariant()))), + true)); - localModules.OrderBy(module => module.Name) - .ToList() - .ForEach(module => embed.AddField($"{GetModuleEmoji(module.Name)} {module.Name}", - GetModuleDescription(module.Name) - + "\n" - + Format.Code(GetText(strs.module_footer(prefix, module.Name.ToLowerInvariant()))), - true)); - - return embed; - }, - topLevelModules.Count(), - 12, - false); + return embed; + }) + .SendAsync(); } private string GetModuleDescription(string moduleName) @@ -271,7 +271,7 @@ public sealed class Help : NadekoModule var cnt = 0; var groups = cmdsWithGroup.GroupBy(_ => cnt++ / 48).ToArray(); - var embed = new EmbedBuilder().WithOkColor(); + var embed = _sender.CreateEmbed().WithOkColor(); foreach (var g in groups) { var last = g.Count(); @@ -303,9 +303,9 @@ public sealed class Help : NadekoModule private async Task Group(ModuleInfo group) { - var eb = new EmbedBuilder() - .WithTitle(GetText(strs.cmd_group_commands(group.Name))) - .WithOkColor(); + var eb = _sender.CreateEmbed() + .WithTitle(GetText(strs.cmd_group_commands(group.Name))) + .WithOkColor(); foreach (var cmd in group.Commands.DistinctBy(x => x.Aliases[0])) { @@ -358,7 +358,8 @@ public sealed class Help : NadekoModule var data = await GetHelpString(); if (data == default) return; - await ch.SendAsync(data); + + await Response().Text(data).SendAsync(); try { await ctx.OkAsync(); @@ -534,9 +535,9 @@ public sealed class Help : NadekoModule label: "Selfhosting"), SelfhostAction)); - var eb = new EmbedBuilder() - .WithOkColor() - .WithTitle("Thank you for considering to donate to the NadekoBot project!"); + var eb = _sender.CreateEmbed() + .WithOkColor() + .WithTitle("Thank you for considering to donate to the NadekoBot project!"); eb .WithDescription("NadekoBot relies on donations to keep the servers, services and APIs running.\n" @@ -575,7 +576,12 @@ Nadeko will DM you the welcome instructions, and you may start using the patron- try { - await (await ctx.User.CreateDMChannelAsync()).EmbedAsync(eb, inter: selfhostInter); + await Response() + .Channel(await ctx.User.CreateDMChannelAsync()) + .Embed(eb) + .Interaction(selfhostInter) + .SendAsync(); + _ = ctx.OkAsync(); } catch diff --git a/src/NadekoBot/Modules/Help/HelpService.cs b/src/NadekoBot/Modules/Help/HelpService.cs index c58cb4bff..ba8452eb1 100644 --- a/src/NadekoBot/Modules/Help/HelpService.cs +++ b/src/NadekoBot/Modules/Help/HelpService.cs @@ -2,11 +2,22 @@ using NadekoBot.Common.ModuleBehaviors; namespace NadekoBot.Modules.Help.Services; -public class HelpService(BotConfigService bss, IReplacementService repSvc) : IExecNoCommand, INService +public class HelpService : IExecNoCommand, INService { + private readonly BotConfigService _bss; + private readonly IReplacementService _rs; + private readonly IMessageSenderService _sender; + + public HelpService(BotConfigService bss, IReplacementService repSvc, IMessageSenderService sender) + { + _bss = bss; + _rs = repSvc; + _sender = sender; + } + public async Task ExecOnNoCommandAsync(IGuild? guild, IUserMessage msg) { - var settings = bss.Data; + var settings = _bss.Data; if (guild is null) { if (string.IsNullOrWhiteSpace(settings.DmHelpText) || settings.DmHelpText == "-") @@ -14,20 +25,20 @@ public class HelpService(BotConfigService bss, IReplacementService repSvc) : IEx // only send dm help text if it contains one of the keywords, if they're specified // if they're not, then reply to every DM - if (settings.DmHelpTextKeywords is not null && - !settings.DmHelpTextKeywords.Any(k => msg.Content.Contains(k))) + if (settings.DmHelpTextKeywords is not null + && !settings.DmHelpTextKeywords.Any(k => msg.Content.Contains(k))) { return; } var repCtx = new ReplacementContext(guild: guild, channel: msg.Channel, users: msg.Author) - .WithOverride("%prefix%", () => bss.Data.Prefix) - .WithOverride("%bot.prefix%", () => bss.Data.Prefix); + .WithOverride("%prefix%", () => _bss.Data.Prefix) + .WithOverride("%bot.prefix%", () => _bss.Data.Prefix); var text = SmartText.CreateFrom(settings.DmHelpText); - text = await repSvc.ReplaceAsync(text, repCtx); + text = await _rs.ReplaceAsync(text, repCtx); - await msg.Channel.SendAsync(text); + await _sender.Response(msg.Channel).Text(text).SendAsync(); } } } \ No newline at end of file diff --git a/src/NadekoBot/Modules/Medusae/Medusa.cs b/src/NadekoBot/Modules/Medusae/Medusa.cs index 66437a476..859c308f3 100644 --- a/src/NadekoBot/Modules/Medusae/Medusa.cs +++ b/src/NadekoBot/Modules/Medusae/Medusa.cs @@ -11,7 +11,7 @@ public partial class Medusa : NadekoModule { _repo = repo; } - + [Cmd] [OwnerOnly] public async Task MedusaLoad(string? name = null) @@ -21,11 +21,11 @@ public partial class Medusa : NadekoModule var loaded = _service.GetLoadedMedusae() .Select(x => x.Name) .ToHashSet(); - + var unloaded = _service.GetAllMedusae() - .Where(x => !loaded.Contains(x)) - .Select(x => Format.Code(x.ToString())) - .ToArray(); + .Where(x => !loaded.Contains(x)) + .Select(x => Format.Code(x.ToString())) + .ToArray(); if (unloaded.Length == 0) { @@ -33,16 +33,18 @@ public partial class Medusa : NadekoModule return; } - await ctx.SendPaginatedConfirmAsync(0, - page => - { - return new EmbedBuilder() - .WithOkColor() - .WithTitle(GetText(strs.list_of_unloaded)) - .WithDescription(unloaded.Skip(10 * page).Take(10).Join('\n')); - }, - unloaded.Length, - 10); + await Response() + .Paginated() + .Items(unloaded) + .PageSize(10) + .Page((items, _) => + { + return _sender.CreateEmbed() + .WithOkColor() + .WithTitle(GetText(strs.list_of_unloaded)) + .WithDescription(items.Join('\n')); + }) + .SendAsync(); return; } @@ -63,7 +65,7 @@ public partial class Medusa : NadekoModule await Response().Error(locStr).SendAsync(); } } - + [Cmd] [OwnerOnly] public async Task MedusaUnload(string? name = null) @@ -77,15 +79,17 @@ public partial class Medusa : NadekoModule return; } - await Response().Embed(new EmbedBuilder() - .WithOkColor() - .WithTitle(GetText(strs.loaded_medusae)) - .WithDescription(loaded.Select(x => x.Name) - .Join("\n"))).SendAsync(); - + await Response() + .Embed(_sender.CreateEmbed() + .WithOkColor() + .WithTitle(GetText(strs.loaded_medusae)) + .WithDescription(loaded.Select(x => x.Name) + .Join("\n"))) + .SendAsync(); + return; } - + var res = await _service.UnloadMedusaAsync(name); if (res == MedusaUnloadResult.Success) await Response().Confirm(strs.medusa_unloaded(Format.Code(name))).SendAsync(); @@ -113,27 +117,29 @@ public partial class Medusa : NadekoModule await Response().Pending(strs.no_medusa_available).SendAsync(); return; } - + var loaded = _service.GetLoadedMedusae() .Select(x => x.Name) .ToHashSet(); var output = all - .Select(m => - { - var emoji = loaded.Contains(m) ? "`✅`" : "`🔴`"; - return $"{emoji} `{m}`"; - }) - .ToArray(); + .Select(m => + { + var emoji = loaded.Contains(m) ? "`✅`" : "`🔴`"; + return $"{emoji} `{m}`"; + }) + .ToArray(); - await ctx.SendPaginatedConfirmAsync(0, - page => new EmbedBuilder() - .WithOkColor() - .WithTitle(GetText(strs.list_of_medusae)) - .WithDescription(output.Skip(page * 10).Take(10).Join('\n')), - output.Length, - 10); + await Response() + .Paginated() + .Items(output) + .PageSize(10) + .Page((items, _) => _sender.CreateEmbed() + .WithOkColor() + .WithTitle(GetText(strs.list_of_medusae)) + .WithDescription(items.Join('\n'))) + .SendAsync(); } [Cmd] @@ -147,7 +153,7 @@ public partial class Medusa : NadekoModule var found = medusae.FirstOrDefault(x => string.Equals(x.Name, name, StringComparison.InvariantCultureIgnoreCase)); - + if (found is null) { await Response().Error(strs.medusa_name_not_found).SendAsync(); @@ -156,26 +162,26 @@ public partial class Medusa : NadekoModule var cmdCount = found.Sneks.Sum(x => x.Commands.Count); var cmdNames = found.Sneks - .SelectMany(x => Format.Code(string.IsNullOrWhiteSpace(x.Prefix) - ? x.Name - : $"{x.Prefix} {x.Name}")) - .Join("\n"); + .SelectMany(x => Format.Code(string.IsNullOrWhiteSpace(x.Prefix) + ? x.Name + : $"{x.Prefix} {x.Name}")) + .Join("\n"); - var eb = new EmbedBuilder() - .WithOkColor() - .WithAuthor(GetText(strs.medusa_info)) - .WithTitle(found.Name) - .WithDescription(found.Description) - .AddField(GetText(strs.sneks_count(found.Sneks.Count)), - found.Sneks.Count == 0 - ? "-" - : found.Sneks.Select(x => x.Name).Join('\n'), - true) - .AddField(GetText(strs.commands_count(cmdCount)), - string.IsNullOrWhiteSpace(cmdNames) - ? "-" - : cmdNames, - true); + var eb = _sender.CreateEmbed() + .WithOkColor() + .WithAuthor(GetText(strs.medusa_info)) + .WithTitle(found.Name) + .WithDescription(found.Description) + .AddField(GetText(strs.sneks_count(found.Sneks.Count)), + found.Sneks.Count == 0 + ? "-" + : found.Sneks.Select(x => x.Name).Join('\n'), + true) + .AddField(GetText(strs.commands_count(cmdCount)), + string.IsNullOrWhiteSpace(cmdNames) + ? "-" + : cmdNames, + true); await Response().Embed(eb).SendAsync(); return; @@ -186,42 +192,49 @@ public partial class Medusa : NadekoModule await Response().Pending(strs.no_medusa_loaded).SendAsync(); return; } - - await ctx.SendPaginatedConfirmAsync(0, - page => - { - var eb = new EmbedBuilder() - .WithOkColor(); - foreach (var medusa in medusae.Skip(page * 9).Take(9)) - { - eb.AddField(medusa.Name, - $""" - `Sneks:` {medusa.Sneks.Count} - `Commands:` {medusa.Sneks.Sum(x => x.Commands.Count)} - -- - {medusa.Description} - """); - } + await Response() + .Paginated() + .Items(medusae) + .PageSize(9) + .CurrentPage(0) + .Page((items, _) => + { + var eb = _sender.CreateEmbed() + .WithOkColor(); - return eb; - }, medusae.Count, 9); + foreach (var medusa in items) + { + eb.AddField(medusa.Name, + $""" + `Sneks:` {medusa.Sneks.Count} + `Commands:` {medusa.Sneks.Sum(x => x.Commands.Count)} + -- + {medusa.Description} + """); + } + + return eb; + }) + .SendAsync(); } [Cmd] [OwnerOnly] public async Task MedusaSearch() { - var eb = new EmbedBuilder() - .WithTitle(GetText(strs.list_of_medusae)) - .WithOkColor(); - + var eb = _sender.CreateEmbed() + .WithTitle(GetText(strs.list_of_medusae)) + .WithOkColor(); + foreach (var item in await _repo.GetModuleItemsAsync()) { - eb.AddField(item.Name, $""" - {item.Description} - `{item.Command}` - """, true); + eb.AddField(item.Name, + $""" + {item.Description} + `{item.Command}` + """, + true); } await Response().Embed(eb).SendAsync(); diff --git a/src/NadekoBot/Modules/Music/Music.cs b/src/NadekoBot/Modules/Music/Music.cs index 5c8d18fb8..354b86db2 100644 --- a/src/NadekoBot/Modules/Music/Music.cs +++ b/src/NadekoBot/Modules/Music/Music.cs @@ -109,11 +109,11 @@ public sealed partial class Music : NadekoModule try { - var embed = new EmbedBuilder() - .WithOkColor() - .WithAuthor(GetText(strs.queued_track) + " #" + (index + 1), MUSIC_ICON_URL) - .WithDescription($"{trackInfo.PrettyName()}\n{GetText(strs.queue)} ") - .WithFooter(trackInfo.Platform.ToString()); + var embed = _sender.CreateEmbed() + .WithOkColor() + .WithAuthor(GetText(strs.queued_track) + " #" + (index + 1), MUSIC_ICON_URL) + .WithDescription($"{trackInfo.PrettyName()}\n{GetText(strs.queue)} ") + .WithFooter(trackInfo.Platform.ToString()); if (!string.IsNullOrWhiteSpace(trackInfo.Thumbnail)) embed.WithThumbnailUrl(trackInfo.Thumbnail); @@ -273,7 +273,7 @@ public sealed partial class Music : NadekoModule return; } - EmbedBuilder PrintAction(int curPage) + EmbedBuilder PrintAction(IReadOnlyList tracks, int curPage) { var desc = string.Empty; var current = mp.GetCurrentTrack(out var currentIndex); @@ -300,32 +300,38 @@ public sealed partial class Music : NadekoModule } - desc += tracks.Skip(LQ_ITEMS_PER_PAGE * curPage) - .Take(LQ_ITEMS_PER_PAGE) - .Select((v, index) => - { - index += LQ_ITEMS_PER_PAGE * curPage; - if (index == currentIndex) - return $"**⇒**`{index + 1}.` {v.PrettyFullName()}"; + desc += tracks + .Select((v, index) => + { + index += LQ_ITEMS_PER_PAGE * curPage; + if (index == currentIndex) + return $"**⇒**`{index + 1}.` {v.PrettyFullName()}"; - return $"`{index + 1}.` {v.PrettyFullName()}"; - }) - .Join('\n'); + return $"`{index + 1}.` {v.PrettyFullName()}"; + }) + .Join('\n'); if (!string.IsNullOrWhiteSpace(add)) desc = add + "\n" + desc; - var embed = new EmbedBuilder() - .WithAuthor(GetText(strs.player_queue(curPage + 1, (tracks.Count / LQ_ITEMS_PER_PAGE) + 1)), - MUSIC_ICON_URL) - .WithDescription(desc) - .WithFooter($" {mp.PrettyVolume()} | 🎶 {tracks.Count} | ⌛ {mp.PrettyTotalTime()} ") - .WithOkColor(); + var embed = _sender.CreateEmbed() + .WithAuthor(GetText(strs.player_queue(curPage + 1, (tracks.Count / LQ_ITEMS_PER_PAGE) + 1)), + MUSIC_ICON_URL) + .WithDescription(desc) + .WithFooter($" {mp.PrettyVolume()} | 🎶 {tracks.Count} | ⌛ {mp.PrettyTotalTime()} ") + .WithOkColor(); return embed; } - await ctx.SendPaginatedConfirmAsync(page, PrintAction, tracks.Count, LQ_ITEMS_PER_PAGE, false); + await Response() + .Paginated() + .Items(tracks) + .PageSize(LQ_ITEMS_PER_PAGE) + .CurrentPage(page) + .AddFooter(false) + .Page(PrintAction) + .SendAsync(); } // search @@ -408,11 +414,11 @@ public sealed partial class Music : NadekoModule return; } - var embed = new EmbedBuilder() - .WithAuthor(GetText(strs.removed_track) + " #" + index, MUSIC_ICON_URL) - .WithDescription(track.PrettyName()) - .WithFooter(track.PrettyInfo()) - .WithErrorColor(); + var embed = _sender.CreateEmbed() + .WithAuthor(GetText(strs.removed_track) + " #" + index, MUSIC_ICON_URL) + .WithDescription(track.PrettyName()) + .WithFooter(track.PrettyInfo()) + .WithErrorColor(); await _service.SendToOutputAsync(ctx.Guild.Id, embed); } @@ -576,12 +582,12 @@ public sealed partial class Music : NadekoModule return; } - var embed = new EmbedBuilder() - .WithTitle(track.Title.TrimTo(65)) - .WithAuthor(GetText(strs.track_moved), MUSIC_ICON_URL) - .AddField(GetText(strs.from_position), $"#{from + 1}", true) - .AddField(GetText(strs.to_position), $"#{to + 1}", true) - .WithOkColor(); + var embed = _sender.CreateEmbed() + .WithTitle(track.Title.TrimTo(65)) + .WithAuthor(GetText(strs.track_moved), MUSIC_ICON_URL) + .AddField(GetText(strs.from_position), $"#{from + 1}", true) + .AddField(GetText(strs.to_position), $"#{to + 1}", true) + .WithOkColor(); if (Uri.IsWellFormedUriString(track.Url, UriKind.Absolute)) embed.WithUrl(track.Url); @@ -635,13 +641,13 @@ public sealed partial class Music : NadekoModule if (currentTrack is null) return; - var embed = new EmbedBuilder() - .WithOkColor() - .WithAuthor(GetText(strs.now_playing), MUSIC_ICON_URL) - .WithDescription(currentTrack.PrettyName()) - .WithThumbnailUrl(currentTrack.Thumbnail) - .WithFooter( - $"{mp.PrettyVolume()} | {mp.PrettyTotalTime()} | {currentTrack.Platform} | {currentTrack.Queuer}"); + var embed = _sender.CreateEmbed() + .WithOkColor() + .WithAuthor(GetText(strs.now_playing), MUSIC_ICON_URL) + .WithDescription(currentTrack.PrettyName()) + .WithThumbnailUrl(currentTrack.Thumbnail) + .WithFooter( + $"{mp.PrettyVolume()} | {mp.PrettyTotalTime()} | {currentTrack.Platform} | {currentTrack.Queuer}"); await Response().Embed(embed).SendAsync(); } diff --git a/src/NadekoBot/Modules/Music/PlaylistCommands.cs b/src/NadekoBot/Modules/Music/PlaylistCommands.cs index 3309a0cb3..691062c37 100644 --- a/src/NadekoBot/Modules/Music/PlaylistCommands.cs +++ b/src/NadekoBot/Modules/Music/PlaylistCommands.cs @@ -50,7 +50,7 @@ public sealed partial class Music playlists = uow.Set().GetPlaylistsOnPage(num); } - var embed = new EmbedBuilder() + var embed = _sender.CreateEmbed() .WithAuthor(GetText(strs.playlists_page(num)), MUSIC_ICON_URL) .WithDescription(string.Join("\n", playlists.Select(r => GetText(strs.playlists(r.Id, r.Name, r.Author, r.Songs.Count))))) @@ -103,20 +103,22 @@ public sealed partial class Music mpl = uow.Set().GetWithSongs(id); } - await ctx.SendPaginatedConfirmAsync(page, - cur => - { - var i = 0; - var str = string.Join("\n", - mpl.Songs.Skip(cur * 20) - .Take(20) - .Select(x => $"`{++i}.` [{x.Title.TrimTo(45)}]({x.Query}) `{x.Provider}`")); - return new EmbedBuilder().WithTitle($"\"{mpl.Name}\" by {mpl.Author}") - .WithOkColor() - .WithDescription(str); - }, - mpl.Songs.Count, - 20); + await Response() + .Paginated() + .Items(mpl.Songs) + .PageSize(20) + .CurrentPage(page) + .Page((items, _) => + { + var i = 0; + var str = string.Join("\n", + items + .Select(x => $"`{++i}.` [{x.Title.TrimTo(45)}]({x.Query}) `{x.Provider}`")); + return _sender.CreateEmbed().WithTitle($"\"{mpl.Name}\" by {mpl.Author}") + .WithOkColor() + .WithDescription(str); + }) + .SendAsync(); } [Cmd] @@ -154,7 +156,7 @@ public sealed partial class Music } await Response() - .Embed(new EmbedBuilder() + .Embed(_sender.CreateEmbed() .WithOkColor() .WithTitle(GetText(strs.playlist_saved)) .AddField(GetText(strs.name), name) diff --git a/src/NadekoBot/Modules/Music/Services/MusicService.cs b/src/NadekoBot/Modules/Music/Services/MusicService.cs index 9ca232447..ad4ff5b9a 100644 --- a/src/NadekoBot/Modules/Music/Services/MusicService.cs +++ b/src/NadekoBot/Modules/Music/Services/MusicService.cs @@ -163,7 +163,9 @@ public sealed class MusicService : IMusicService { if (_outputChannels.TryGetValue(guildId, out var chan)) { - var msg = await (chan.Override ?? chan.Default).EmbedAsync(embed); + var msg = await _sender.Response(chan.Override ?? chan.Default) + .Embed(embed) + .SendAsync(); return msg; } @@ -176,11 +178,11 @@ public sealed class MusicService : IMusicService return async (mp, trackInfo) => { _ = lastFinishedMessage?.DeleteAsync(); - var embed = new EmbedBuilder() - .WithOkColor() - .WithAuthor(GetText(guildId, strs.finished_track), Music.MUSIC_ICON_URL) - .WithDescription(trackInfo.PrettyName()) - .WithFooter(trackInfo.PrettyTotalTime()); + var embed = _sender.CreateEmbed() + .WithOkColor() + .WithAuthor(GetText(guildId, strs.finished_track), Music.MUSIC_ICON_URL) + .WithDescription(trackInfo.PrettyName()) + .WithFooter(trackInfo.PrettyTotalTime()); lastFinishedMessage = await SendToOutputAsync(guildId, embed); }; @@ -192,11 +194,11 @@ public sealed class MusicService : IMusicService return async (mp, trackInfo, index) => { _ = lastPlayingMessage?.DeleteAsync(); - var embed = new EmbedBuilder() - .WithOkColor() - .WithAuthor(GetText(guildId, strs.playing_track(index + 1)), Music.MUSIC_ICON_URL) - .WithDescription(trackInfo.PrettyName()) - .WithFooter($"{mp.PrettyVolume()} | {trackInfo.PrettyInfo()}"); + var embed = _sender.CreateEmbed() + .WithOkColor() + .WithAuthor(GetText(guildId, strs.playing_track(index + 1)), Music.MUSIC_ICON_URL) + .WithDescription(trackInfo.PrettyName()) + .WithFooter($"{mp.PrettyVolume()} | {trackInfo.PrettyInfo()}"); lastPlayingMessage = await SendToOutputAsync(guildId, embed); }; @@ -279,9 +281,9 @@ public sealed class MusicService : IMusicService yield return ("%music.playing%", () => { var randomPlayingTrack = _players.Select(x => x.Value.GetCurrentTrack(out _)) - .Where(x => x is not null) - .Shuffle() - .FirstOrDefault(); + .Where(x => x is not null) + .Shuffle() + .FirstOrDefault(); if (randomPlayingTrack is null) return "-"; diff --git a/src/NadekoBot/Modules/Patronage/CurrencyRewardService.cs b/src/NadekoBot/Modules/Patronage/CurrencyRewardService.cs index 9e90c37f9..854303136 100644 --- a/src/NadekoBot/Modules/Patronage/CurrencyRewardService.cs +++ b/src/NadekoBot/Modules/Patronage/CurrencyRewardService.cs @@ -171,7 +171,7 @@ public sealed class CurrencyRewardService : INService, IDisposable if (user is null) return; - var eb = new EmbedBuilder() + var eb = _sender.CreateEmbed() .WithOkColor() .WithDescription(message); diff --git a/src/NadekoBot/Modules/Patronage/PatronageCommands.cs b/src/NadekoBot/Modules/Patronage/PatronageCommands.cs index c4401f202..11c14fe9f 100644 --- a/src/NadekoBot/Modules/Patronage/PatronageCommands.cs +++ b/src/NadekoBot/Modules/Patronage/PatronageCommands.cs @@ -49,7 +49,7 @@ public partial class Patronage : NadekoModule // // var patron = _service.GiftPatronAsync(user, amount); // - // var eb = new EmbedBuilder(); + // var eb = _sender.CreateEmbed(); // // await Response().Embed(eb.WithDescription($"Added **{days}** days of Patron benefits to {user.Mention}!") // .AddField("Tier", Format.Bold(patron.Tier.ToString()), true) @@ -70,7 +70,7 @@ public partial class Patronage : NadekoModule var patron = await _service.GetPatronAsync(user.Id); var quotaStats = await _service.GetUserQuotaStatistic(user.Id); - var eb = new EmbedBuilder() + var eb = _sender.CreateEmbed() .WithAuthor(user) .WithTitle(GetText(strs.patron_info)) .WithOkColor(); diff --git a/src/NadekoBot/Modules/Patronage/PatronageService.cs b/src/NadekoBot/Modules/Patronage/PatronageService.cs index 9af8d6f47..f0798a4f6 100644 --- a/src/NadekoBot/Modules/Patronage/PatronageService.cs +++ b/src/NadekoBot/Modules/Patronage/PatronageService.cs @@ -306,7 +306,7 @@ public sealed class PatronageService _ => false, ins => { - var eb = new EmbedBuilder() + var eb = _sender.CreateEmbed() .WithPendingColor() .WithTitle("Insufficient Patron Tier") .AddField("For", $"{ins.FeatureType}: `{ins.Feature}`", true) @@ -336,7 +336,7 @@ public sealed class PatronageService }, quota => { - var eb = new EmbedBuilder() + var eb = _sender.CreateEmbed() .WithPendingColor() .WithTitle("Quota Limit Reached"); @@ -778,7 +778,7 @@ public sealed class PatronageService if (user is null) return; - var eb = new EmbedBuilder() + var eb = _sender.CreateEmbed() .WithOkColor() .WithTitle("❤️ Thank you for supporting NadekoBot! ❤️") .WithDescription( diff --git a/src/NadekoBot/Modules/Permissions/Blacklist/BlacklistCommands.cs b/src/NadekoBot/Modules/Permissions/Blacklist/BlacklistCommands.cs index a35ad60b3..6d269fefd 100644 --- a/src/NadekoBot/Modules/Permissions/Blacklist/BlacklistCommands.cs +++ b/src/NadekoBot/Modules/Permissions/Blacklist/BlacklistCommands.cs @@ -60,12 +60,12 @@ public partial class Permissions .Page((pageItems, _) => { if (pageItems.Count == 0) - return new EmbedBuilder() + return _sender.CreateEmbed() .WithOkColor() .WithTitle(title) .WithDescription(GetText(strs.empty_page)); - return new EmbedBuilder() + return _sender.CreateEmbed() .WithTitle(title) .WithDescription(allItems.Join('\n')) .WithOkColor(); diff --git a/src/NadekoBot/Modules/Permissions/CommandCooldown/CmdCdsCommands.cs b/src/NadekoBot/Modules/Permissions/CommandCooldown/CmdCdsCommands.cs index a8cf4e8bd..d045ca647 100644 --- a/src/NadekoBot/Modules/Permissions/CommandCooldown/CmdCdsCommands.cs +++ b/src/NadekoBot/Modules/Permissions/CommandCooldown/CmdCdsCommands.cs @@ -61,7 +61,7 @@ public partial class Permissions else await Response().Confirm(strs.cmdcd_add(Format.Bold(name), Format.Bold(secs.ToString()))).SendAsync(); } - + [Cmd] [RequireContext(ContextType.Guild)] [Priority(0)] @@ -80,7 +80,7 @@ public partial class Permissions { if (--page < 0) return; - + var channel = (ITextChannel)ctx.Channel; var localSet = _service.GetCommandCooldowns(ctx.Guild.Id); @@ -88,17 +88,21 @@ public partial class Permissions await Response().Confirm(strs.cmdcd_none).SendAsync(); else { - await ctx.SendPaginatedConfirmAsync(page, curPage => - { - var items = localSet.Skip(curPage * 15) - .Take(15) - .Select(x => $"{Format.Code(x.CommandName)}: {x.Seconds.Seconds().Humanize(maxUnit: TimeUnit.Second, culture: Culture)}"); + await Response() + .Paginated() + .Items(localSet) + .PageSize(15) + .CurrentPage(page) + .Page((items, _) => + { + var output = items.Select(x => + $"{Format.Code(x.CommandName)}: {x.Seconds.Seconds().Humanize(maxUnit: TimeUnit.Second, culture: Culture)}"); - return new EmbedBuilder() - .WithOkColor() - .WithDescription(items.Join("\n")); - - }, localSet.Count, 15); + return _sender.CreateEmbed() + .WithOkColor() + .WithDescription(output.Join("\n")); + }) + .SendAsync(); } } } diff --git a/src/NadekoBot/Modules/Permissions/Filter/FilterCommands.cs b/src/NadekoBot/Modules/Permissions/Filter/FilterCommands.cs index 0da25e953..83f6d1f8c 100644 --- a/src/NadekoBot/Modules/Permissions/Filter/FilterCommands.cs +++ b/src/NadekoBot/Modules/Permissions/Filter/FilterCommands.cs @@ -29,9 +29,9 @@ public partial class Permissions [RequireContext(ContextType.Guild)] public async Task FilterList() { - var embed = new EmbedBuilder() - .WithOkColor() - .WithTitle("Server filter settings"); + var embed = _sender.CreateEmbed() + .WithOkColor() + .WithTitle("Server filter settings"); var config = await _service.GetFilterSettings(ctx.Guild.Id); @@ -41,14 +41,14 @@ public partial class Permissions async Task GetChannelListAsync(IReadOnlyCollection channels) { var toReturn = (await channels - .Select(async cid => - { - var ch = await ctx.Guild.GetChannelAsync(cid); - return ch is null - ? $"{cid} *missing*" - : $"<#{cid}>"; - }) - .WhenAll()) + .Select(async cid => + { + var ch = await ctx.Guild.GetChannelAsync(cid); + return ch is null + ? $"{cid} *missing*" + : $"<#{cid}>"; + }) + .WhenAll()) .Join('\n'); if (string.IsNullOrWhiteSpace(toReturn)) @@ -312,13 +312,16 @@ public partial class Permissions var fws = fwHash.ToArray(); - await ctx.SendPaginatedConfirmAsync(page, - curPage => new EmbedBuilder() - .WithTitle(GetText(strs.filter_word_list)) - .WithDescription(string.Join("\n", fws.Skip(curPage * 10).Take(10))) - .WithOkColor(), - fws.Length, - 10); + await Response() + .Paginated() + .Items(fws) + .PageSize(10) + .CurrentPage(page) + .Page((items, _) => _sender.CreateEmbed() + .WithTitle(GetText(strs.filter_word_list)) + .WithDescription(string.Join("\n", items)) + .WithOkColor()) + .SendAsync(); } } } \ No newline at end of file diff --git a/src/NadekoBot/Modules/Permissions/GlobalPermissions/GlobalPermissionCommands.cs b/src/NadekoBot/Modules/Permissions/GlobalPermissions/GlobalPermissionCommands.cs index faa159728..f75c6a99a 100644 --- a/src/NadekoBot/Modules/Permissions/GlobalPermissions/GlobalPermissionCommands.cs +++ b/src/NadekoBot/Modules/Permissions/GlobalPermissions/GlobalPermissionCommands.cs @@ -30,7 +30,7 @@ public partial class Permissions return; } - var embed = new EmbedBuilder().WithOkColor(); + var embed = _sender.CreateEmbed().WithOkColor(); if (blockedModule.Any()) embed.AddField(GetText(strs.blocked_modules), string.Join("\n", _service.BlockedModules)); diff --git a/src/NadekoBot/Modules/Searches/Anime/AnimeSearchCommands.cs b/src/NadekoBot/Modules/Searches/Anime/AnimeSearchCommands.cs index fb5582bb9..c9338091c 100644 --- a/src/NadekoBot/Modules/Searches/Anime/AnimeSearchCommands.cs +++ b/src/NadekoBot/Modules/Searches/Anime/AnimeSearchCommands.cs @@ -24,7 +24,7 @@ public partial class Searches // return; // } // - // var embed = new EmbedBuilder() + // var embed = _sender.CreateEmbed() // .WithOkColor() // .WithDescription(novelData.Description.Replace("
", Environment.NewLine, StringComparison.InvariantCulture)) // .WithTitle(novelData.Title) @@ -86,7 +86,7 @@ public partial class Searches .Select(x => x.TextContent.Split(':').Select(y => y.Trim()).ToArray()) .ToArray(); - var embed = new EmbedBuilder() + var embed = _sender.CreateEmbed() .WithOkColor() .WithTitle(GetText(strs.mal_profile(name))) .AddField("💚 " + GetText(strs.watching), stats[0], true) @@ -151,7 +151,7 @@ public partial class Searches return; } - var embed = new EmbedBuilder() + var embed = _sender.CreateEmbed() .WithOkColor() .WithDescription(animeData.Synopsis.Replace("
", Environment.NewLine, @@ -183,7 +183,7 @@ public partial class Searches return; } - var embed = new EmbedBuilder() + var embed = _sender.CreateEmbed() .WithOkColor() .WithDescription(mangaData.Synopsis.Replace("
", Environment.NewLine, diff --git a/src/NadekoBot/Modules/Searches/Crypto/CryptoCommands.cs b/src/NadekoBot/Modules/Searches/Crypto/CryptoCommands.cs index d6a50f09c..81c7e156b 100644 --- a/src/NadekoBot/Modules/Searches/Crypto/CryptoCommands.cs +++ b/src/NadekoBot/Modules/Searches/Crypto/CryptoCommands.cs @@ -35,7 +35,7 @@ public partial class Searches } var symbol = symbols.First(); - var promptEmbed = new EmbedBuilder() + var promptEmbed = _sender.CreateEmbed() .WithDescription(symbol.Description) .WithTitle(GetText(strs.did_you_mean(symbol.Symbol))); @@ -79,7 +79,7 @@ public partial class Searches var price = stock.Price.ToString("C2", localCulture); - var eb = new EmbedBuilder() + var eb = _sender.CreateEmbed() .WithOkColor() .WithAuthor(stock.Symbol) .WithUrl($"https://www.tradingview.com/chart/?symbol={stock.Symbol}") @@ -127,7 +127,7 @@ public partial class Searches if (nearest is not null) { - var embed = new EmbedBuilder() + var embed = _sender.CreateEmbed() .WithTitle(GetText(strs.crypto_not_found)) .WithDescription( GetText(strs.did_you_mean(Format.Bold($"{nearest.Name} ({nearest.Symbol})")))); @@ -160,7 +160,7 @@ public partial class Searches await using var sparkline = await _service.GetSparklineAsync(crypto.Id, usd.PercentChange7d >= 0); var fileName = $"{crypto.Slug}_7d.png"; - var toSend = new EmbedBuilder() + var toSend = _sender.CreateEmbed() .WithOkColor() .WithAuthor($"#{crypto.CmcRank}") .WithTitle($"{crypto.Name} ({crypto.Symbol})") diff --git a/src/NadekoBot/Modules/Searches/Feeds/FeedCommands.cs b/src/NadekoBot/Modules/Searches/Feeds/FeedCommands.cs index 04fe223ae..2826a876d 100644 --- a/src/NadekoBot/Modules/Searches/Feeds/FeedCommands.cs +++ b/src/NadekoBot/Modules/Searches/Feeds/FeedCommands.cs @@ -111,28 +111,36 @@ public partial class Searches [Cmd] [RequireContext(ContextType.Guild)] [UserPerm(GuildPerm.ManageMessages)] - public async Task FeedList() + public async Task FeedList(int page = 1) { + if (--page < 0) + return; + var feeds = _service.GetFeeds(ctx.Guild.Id); if (!feeds.Any()) { - await Response().Embed(new EmbedBuilder().WithOkColor().WithDescription(GetText(strs.feed_no_feed))).SendAsync(); + await Response() + .Embed(_sender.CreateEmbed().WithOkColor().WithDescription(GetText(strs.feed_no_feed))) + .SendAsync(); return; } - - await ctx.SendPaginatedConfirmAsync(0, - cur => - { - var embed = new EmbedBuilder().WithOkColor(); - var i = 0; - var fs = string.Join("\n", - feeds.Skip(cur * 10).Take(10).Select(x => $"`{(cur * 10) + ++i}.` <#{x.ChannelId}> {x.Url}")); - return embed.WithDescription(fs); - }, - feeds.Count, - 10); + await Response() + .Paginated() + .Items(feeds) + .PageSize(10) + .CurrentPage(page) + .Page((items, cur) => + { + var embed = _sender.CreateEmbed().WithOkColor(); + var i = 0; + var fs = string.Join("\n", + items.Select(x => $"`{(cur * 10) + ++i}.` <#{x.ChannelId}> {x.Url}")); + + return embed.WithDescription(fs); + }) + .SendAsync(); } } } \ No newline at end of file diff --git a/src/NadekoBot/Modules/Searches/Feeds/FeedsService.cs b/src/NadekoBot/Modules/Searches/Feeds/FeedsService.cs index 09f53783a..d934dc3c9 100644 --- a/src/NadekoBot/Modules/Searches/Feeds/FeedsService.cs +++ b/src/NadekoBot/Modules/Searches/Feeds/FeedsService.cs @@ -31,14 +31,14 @@ public class FeedsService : INService { var guildConfigIds = bot.AllGuildConfigs.Select(x => x.Id).ToList(); _subs = uow.Set() - .AsQueryable() - .Where(x => guildConfigIds.Contains(x.Id)) - .Include(x => x.FeedSubs) - .ToList() - .SelectMany(x => x.FeedSubs) - .GroupBy(x => x.Url.ToLower()) - .ToDictionary(x => x.Key, x => x.ToList()) - .ToConcurrent(); + .AsQueryable() + .Where(x => guildConfigIds.Contains(x.Id)) + .Include(x => x.FeedSubs) + .ToList() + .SelectMany(x => x.FeedSubs) + .GroupBy(x => x.Url.ToLower()) + .ToDictionary(x => x.Key, x => x.ToList()) + .ToConcurrent(); } _client = client; @@ -61,7 +61,7 @@ public class FeedsService : INService // remove from db await using var ctx = _db.GetDbContext(); await ctx.GetTable() - .DeleteAsync(x => ids.Contains(x.Id)); + .DeleteAsync(x => ids.Contains(x.Id)); // remove from the local cache _subs.TryRemove(url, out _); @@ -95,14 +95,14 @@ public class FeedsService : INService var feed = await FeedReader.ReadAsync(rssUrl); var items = feed - .Items.Select(item => (Item: item, - LastUpdate: item.PublishingDate?.ToUniversalTime() - ?? (item.SpecificItem as AtomFeedItem)?.UpdatedDate?.ToUniversalTime())) - .Where(data => data.LastUpdate is not null) - .Select(data => (data.Item, LastUpdate: (DateTime)data.LastUpdate)) - .OrderByDescending(data => data.LastUpdate) - .Reverse() // start from the oldest - .ToList(); + .Items.Select(item => (Item: item, + LastUpdate: item.PublishingDate?.ToUniversalTime() + ?? (item.SpecificItem as AtomFeedItem)?.UpdatedDate?.ToUniversalTime())) + .Where(data => data.LastUpdate is not null) + .Select(data => (data.Item, LastUpdate: (DateTime)data.LastUpdate)) + .OrderByDescending(data => data.LastUpdate) + .Reverse() // start from the oldest + .ToList(); if (!_lastPosts.TryGetValue(kvp.Key, out var lastFeedUpdate)) { @@ -115,7 +115,7 @@ public class FeedsService : INService if (itemUpdateDate <= lastFeedUpdate) continue; - var embed = new EmbedBuilder().WithFooter(rssUrl); + var embed = _sender.CreateEmbed().WithFooter(rssUrl); _lastPosts[kvp.Key] = itemUpdateDate; @@ -141,12 +141,12 @@ public class FeedsService : INService if (!gotImage && feedItem.SpecificItem is AtomFeedItem afi) { var previewElement = afi.Element.Elements() - .FirstOrDefault(x => x.Name.LocalName == "preview"); + .FirstOrDefault(x => x.Name.LocalName == "preview"); if (previewElement is null) { previewElement = afi.Element.Elements() - .FirstOrDefault(x => x.Name.LocalName == "thumbnail"); + .FirstOrDefault(x => x.Name.LocalName == "thumbnail"); } if (previewElement is not null) @@ -170,11 +170,23 @@ public class FeedsService : INService //send the created embed to all subscribed channels var feedSendTasks = kvp.Value - .Where(x => x.GuildConfig is not null) - .Select(x => _client.GetGuild(x.GuildConfig.GuildId) - ?.GetTextChannel(x.ChannelId) - ?.EmbedAsync(embed, string.IsNullOrWhiteSpace(x.Message) ? "" : x.Message)) - .Where(x => x is not null); + .Where(x => x.GuildConfig is not null) + .Select(x => + { + var ch = _client.GetGuild(x.GuildConfig.GuildId) + ?.GetTextChannel(x.ChannelId); + + if (ch is null) + return null; + + return _sender.Response(ch) + .Embed(embed) + .Text(string.IsNullOrWhiteSpace(x.Message) + ? string.Empty + : x.Message) + .SendAsync(); + }) + .Where(x => x is not null); allSendTasks.Add(feedSendTasks.WhenAll()); @@ -202,11 +214,15 @@ public class FeedsService : INService { using var uow = _db.GetDbContext(); return uow.GuildConfigsForId(guildId, set => set.Include(x => x.FeedSubs)) - .FeedSubs.OrderBy(x => x.Id) - .ToList(); + .FeedSubs.OrderBy(x => x.Id) + .ToList(); } - public FeedAddResult AddFeed(ulong guildId, ulong channelId, string rssFeed, string message) + public FeedAddResult AddFeed( + ulong guildId, + ulong channelId, + string rssFeed, + string message) { ArgumentNullException.ThrowIfNull(rssFeed, nameof(rssFeed)); @@ -252,8 +268,8 @@ public class FeedsService : INService using var uow = _db.GetDbContext(); var items = uow.GuildConfigsForId(guildId, set => set.Include(x => x.FeedSubs)) - .FeedSubs.OrderBy(x => x.Id) - .ToList(); + .FeedSubs.OrderBy(x => x.Id) + .ToList(); if (items.Count <= index) return false; diff --git a/src/NadekoBot/Modules/Searches/MemegenCommands.cs b/src/NadekoBot/Modules/Searches/MemegenCommands.cs index b4682b7dc..9fbd12820 100644 --- a/src/NadekoBot/Modules/Searches/MemegenCommands.cs +++ b/src/NadekoBot/Modules/Searches/MemegenCommands.cs @@ -40,18 +40,21 @@ public partial class Searches var data = JsonConvert.DeserializeObject>(rawJson)!; - await ctx.SendPaginatedConfirmAsync(page, - curPage => - { - var templates = string.Empty; - foreach (var template in data.Skip(curPage * 15).Take(15)) - templates += $"**{template.Name}:**\n key: `{template.Id}`\n"; - var embed = new EmbedBuilder().WithOkColor().WithDescription(templates); + await Response() + .Paginated() + .Items(data) + .PageSize(15) + .CurrentPage(page) + .Page((items, curPage) => + { + var templates = string.Empty; + foreach (var template in items) + templates += $"**{template.Name}:**\n key: `{template.Id}`\n"; + var embed = _sender.CreateEmbed().WithOkColor().WithDescription(templates); - return embed; - }, - data.Count, - 15); + return embed; + }) + .SendAsync(); } [Cmd] diff --git a/src/NadekoBot/Modules/Searches/OsuCommands.cs b/src/NadekoBot/Modules/Searches/OsuCommands.cs index 7acd254cb..3658e38bb 100644 --- a/src/NadekoBot/Modules/Searches/OsuCommands.cs +++ b/src/NadekoBot/Modules/Searches/OsuCommands.cs @@ -49,7 +49,7 @@ public partial class Searches var obj = objs[0]; var userId = obj.UserId; - await Response().Embed(new EmbedBuilder() + await Response().Embed(_sender.CreateEmbed() .WithOkColor() .WithTitle($"osu! {smode} profile for {user}") .WithThumbnailUrl($"https://a.ppy.sh/{userId}") @@ -95,7 +95,7 @@ public partial class Searches var userData = JsonConvert.DeserializeObject(usrResString).Users[0]; var userStats = statsResponse.Stats; - var embed = new EmbedBuilder() + var embed = _sender.CreateEmbed() .WithOkColor() .WithTitle($"osu!Gatari {modeStr} profile for {user}") .WithThumbnailUrl($"https://a.gatari.pw/{userStats.Id}") @@ -166,7 +166,7 @@ public partial class Searches return (title, desc); }); - var eb = new EmbedBuilder().WithOkColor().WithTitle($"Top 5 plays for {user}"); + var eb = _sender.CreateEmbed().WithOkColor().WithTitle($"Top 5 plays for {user}"); var mapData = await mapTasks.WhenAll(); foreach (var (title, desc) in mapData.Where(x => x != default)) diff --git a/src/NadekoBot/Modules/Searches/PathOfExileCommands.cs b/src/NadekoBot/Modules/Searches/PathOfExileCommands.cs index cdb07f32a..ddc271c38 100644 --- a/src/NadekoBot/Modules/Searches/PathOfExileCommands.cs +++ b/src/NadekoBot/Modules/Searches/PathOfExileCommands.cs @@ -135,7 +135,7 @@ public partial class Searches } catch { - var embed = new EmbedBuilder().WithDescription(GetText(strs.account_not_found)).WithErrorColor(); + var embed = _sender.CreateEmbed().WithDescription(GetText(strs.account_not_found)).WithErrorColor(); await Response().Embed(embed).SendAsync(); return; @@ -144,37 +144,38 @@ public partial class Searches if (!string.IsNullOrWhiteSpace(league)) characters.RemoveAll(c => c.League != league); - await ctx.SendPaginatedConfirmAsync(page, - curPage => - { - var embed = new EmbedBuilder() - .WithAuthor($"Characters on {usr}'s account", - "https://web.poecdn.com/image/favicon/ogimage.png", - $"{PROFILE_URL}{usr}") - .WithOkColor(); + await Response() + .Paginated() + .Items(characters) + .PageSize(9) + .CurrentPage(page) + .Page((items, curPage) => + { + var embed = _sender.CreateEmbed() + .WithAuthor($"Characters on {usr}'s account", + "https://web.poecdn.com/image/favicon/ogimage.png", + $"{PROFILE_URL}{usr}") + .WithOkColor(); - var tempList = characters.Skip(curPage * 9).Take(9).ToList(); + if (characters.Count == 0) + return embed.WithDescription("This account has no characters."); - if (characters.Count == 0) - return embed.WithDescription("This account has no characters."); + var sb = new StringBuilder(); + sb.AppendLine($"```{"#",-5}{"Character Name",-23}{"League",-10}{"Class",-13}{"Level",-3}"); + for (var i = 0; i < items.Count; i++) + { + var character = items[i]; - var sb = new StringBuilder(); - sb.AppendLine($"```{"#",-5}{"Character Name",-23}{"League",-10}{"Class",-13}{"Level",-3}"); - for (var i = 0; i < tempList.Count; i++) - { - var character = tempList[i]; + sb.AppendLine( + $"#{i + 1 + (curPage * 9),-4}{character.Name,-23}{ShortLeagueName(character.League),-10}{character.Class,-13}{character.Level,-3}"); + } - sb.AppendLine( - $"#{i + 1 + (curPage * 9),-4}{character.Name,-23}{ShortLeagueName(character.League),-10}{character.Class,-13}{character.Level,-3}"); - } + sb.AppendLine("```"); + embed.WithDescription(sb.ToString()); - sb.AppendLine("```"); - embed.WithDescription(sb.ToString()); - - return embed; - }, - characters.Count, - 9); + return embed; + }) + .SendAsync(); } [Cmd] @@ -190,17 +191,17 @@ public partial class Searches } catch { - var eembed = new EmbedBuilder().WithDescription(GetText(strs.leagues_not_found)).WithErrorColor(); + var eembed = _sender.CreateEmbed().WithDescription(GetText(strs.leagues_not_found)).WithErrorColor(); await Response().Embed(eembed).SendAsync(); return; } - var embed = new EmbedBuilder() - .WithAuthor("Path of Exile Leagues", - "https://web.poecdn.com/image/favicon/ogimage.png", - "https://www.pathofexile.com") - .WithOkColor(); + var embed = _sender.CreateEmbed() + .WithAuthor("Path of Exile Leagues", + "https://web.poecdn.com/image/favicon/ogimage.png", + "https://www.pathofexile.com") + .WithOkColor(); var sb = new StringBuilder(); sb.AppendLine($"```{"#",-5}{"League Name",-23}"); @@ -273,19 +274,19 @@ public partial class Searches CultureInfo.InvariantCulture); } - var embed = new EmbedBuilder() - .WithAuthor($"{leagueName} Currency Exchange", - "https://web.poecdn.com/image/favicon/ogimage.png", - "http://poe.ninja") - .AddField("Currency Type", cleanCurrency, true) - .AddField($"{cleanConvert} Equivalent", chaosEquivalent / conversionEquivalent, true) - .WithOkColor(); + var embed = _sender.CreateEmbed() + .WithAuthor($"{leagueName} Currency Exchange", + "https://web.poecdn.com/image/favicon/ogimage.png", + "http://poe.ninja") + .AddField("Currency Type", cleanCurrency, true) + .AddField($"{cleanConvert} Equivalent", chaosEquivalent / conversionEquivalent, true) + .WithOkColor(); await Response().Embed(embed).SendAsync(); } catch { - var embed = new EmbedBuilder().WithDescription(GetText(strs.ninja_not_found)).WithErrorColor(); + var embed = _sender.CreateEmbed().WithDescription(GetText(strs.ninja_not_found)).WithErrorColor(); await Response().Embed(embed).SendAsync(); } diff --git a/src/NadekoBot/Modules/Searches/PokemonSearchCommands.cs b/src/NadekoBot/Modules/Searches/PokemonSearchCommands.cs index f51486900..15c6e41cf 100644 --- a/src/NadekoBot/Modules/Searches/PokemonSearchCommands.cs +++ b/src/NadekoBot/Modules/Searches/PokemonSearchCommands.cs @@ -25,7 +25,7 @@ public partial class Searches if (kvp.Key.ToUpperInvariant() == pokemon.ToUpperInvariant()) { var p = kvp.Value; - await Response().Embed(new EmbedBuilder() + await Response().Embed(_sender.CreateEmbed() .WithOkColor() .WithTitle(kvp.Key.ToTitleCase()) .WithDescription(p.BaseStats.ToString()) @@ -55,7 +55,7 @@ public partial class Searches { if (kvp.Key.ToUpperInvariant() == ability) { - await Response().Embed(new EmbedBuilder() + await Response().Embed(_sender.CreateEmbed() .WithOkColor() .WithTitle(kvp.Value.Name) .WithDescription(string.IsNullOrWhiteSpace(kvp.Value.Desc) diff --git a/src/NadekoBot/Modules/Searches/Search/SearchCommands.cs b/src/NadekoBot/Modules/Searches/Search/SearchCommands.cs index 22e4fe975..f5ec21fea 100644 --- a/src/NadekoBot/Modules/Searches/Search/SearchCommands.cs +++ b/src/NadekoBot/Modules/Searches/Search/SearchCommands.cs @@ -59,7 +59,7 @@ public partial class Searches descStr = descStr.TrimTo(4096); - var embed = new EmbedBuilder() + var embed = _sender.CreateEmbed() .WithOkColor() .WithAuthor(ctx.User) .WithTitle(query.TrimTo(64)!) @@ -98,7 +98,7 @@ public partial class Searches EmbedBuilder CreateEmbed(IImageSearchResultEntry entry) { - return new EmbedBuilder() + return _sender.CreateEmbed() .WithOkColor() .WithAuthor(ctx.User) .WithTitle(query) @@ -190,7 +190,7 @@ public partial class Searches // // var descStr = string.Join("\n\n", desc); // -// var embed = new EmbedBuilder() +// var embed = _sender.CreateEmbed() // .WithAuthor(ctx.User.ToString(), // "https://upload.wikimedia.org/wikipedia/en/9/90/The_DuckDuckGo_Duck.png") // .WithDescription($"{GetText(strs.search_for)} **{query}**\n\n" + descStr) diff --git a/src/NadekoBot/Modules/Searches/Searches.cs b/src/NadekoBot/Modules/Searches/Searches.cs index ad9085fe5..995f94c90 100644 --- a/src/NadekoBot/Modules/Searches/Searches.cs +++ b/src/NadekoBot/Modules/Searches/Searches.cs @@ -54,7 +54,7 @@ public partial class Searches : NadekoModule if (!await ValidateQuery(query)) return; - var embed = new EmbedBuilder(); + var embed = _sender.CreateEmbed(); var data = await _service.GetWeatherDataAsync(query); if (data is null) @@ -134,7 +134,7 @@ public partial class Searches : NadekoModule return; } - var eb = new EmbedBuilder() + var eb = _sender.CreateEmbed() .WithOkColor() .WithTitle(GetText(strs.time_new)) .WithDescription(Format.Code(data.Time.ToString(Culture))) @@ -160,7 +160,7 @@ public partial class Searches : NadekoModule } await Response() - .Embed(new EmbedBuilder() + .Embed(_sender.CreateEmbed() .WithOkColor() .WithTitle(movie.Title) .WithUrl($"https://www.imdb.com/title/{movie.ImdbId}/") @@ -191,7 +191,7 @@ public partial class Searches : NadekoModule private Task InternalRandomImage(SearchesService.ImageTag tag) { var url = _service.GetRandomImageUrl(tag); - return Response().Embed(new EmbedBuilder().WithOkColor().WithImageUrl(url)).SendAsync(); + return Response().Embed(_sender.CreateEmbed().WithOkColor().WithImageUrl(url)).SendAsync(); } [Cmd] @@ -242,7 +242,7 @@ public partial class Searches : NadekoModule } await Response() - .Embed(new EmbedBuilder() + .Embed(_sender.CreateEmbed() .WithOkColor() .AddField(GetText(strs.original_url), $"<{query}>") .AddField(GetText(strs.short_url), $"<{shortLink}>")) @@ -264,7 +264,7 @@ public partial class Searches : NadekoModule return; } - var embed = new EmbedBuilder() + var embed = _sender.CreateEmbed() .WithOkColor() .WithTitle(card.Name) .WithDescription(card.Description) @@ -297,7 +297,7 @@ public partial class Searches : NadekoModule return; } - var embed = new EmbedBuilder().WithOkColor().WithImageUrl(card.Img); + var embed = _sender.CreateEmbed().WithOkColor().WithImageUrl(card.Img); if (!string.IsNullOrWhiteSpace(card.Flavor)) embed.WithDescription(card.Flavor); @@ -318,21 +318,24 @@ public partial class Searches : NadekoModule $"https://api.urbandictionary.com/v0/define?term={Uri.EscapeDataString(query)}"); try { - var items = JsonConvert.DeserializeObject(res).List; - if (items.Any()) + var allItems = JsonConvert.DeserializeObject(res).List; + if (allItems.Any()) { - await ctx.SendPaginatedConfirmAsync(0, - p => - { - var item = items[p]; - return new EmbedBuilder() - .WithOkColor() - .WithUrl(item.Permalink) - .WithTitle(item.Word) - .WithDescription(item.Definition); - }, - items.Length, - 1); + await Response() + .Paginated() + .Items(allItems) + .PageSize(1) + .CurrentPage(0) + .Page((items, _) => + { + var item = items[0]; + return _sender.CreateEmbed() + .WithOkColor() + .WithUrl(item.Permalink) + .WithTitle(item.Word) + .WithDescription(item.Definition); + }) + .SendAsync(); return; } } @@ -362,52 +365,54 @@ public partial class Searches : NadekoModule + WebUtility.UrlEncode(word)); }); - var data = JsonConvert.DeserializeObject(res); + var responseModel = JsonConvert.DeserializeObject(res); - var datas = data.Results - .Where(x => x.Senses is not null - && x.Senses.Count > 0 - && x.Senses[0].Definition is not null) - .Select(x => (Sense: x.Senses[0], x.PartOfSpeech)) - .ToList(); + var data = responseModel.Results + .Where(x => x.Senses is not null + && x.Senses.Count > 0 + && x.Senses[0].Definition is not null) + .Select(x => (Sense: x.Senses[0], x.PartOfSpeech)) + .ToList(); - if (!datas.Any()) + if (!data.Any()) { Log.Warning("Definition not found: {Word}", word); await Response().Error(strs.define_unknown).SendAsync(); } - var col = datas.Select(x => ( - Definition: x.Sense.Definition is string - ? x.Sense.Definition.ToString() - : ((JArray)JToken.Parse(x.Sense.Definition.ToString())).First.ToString(), - Example: x.Sense.Examples is null || x.Sense.Examples.Count == 0 - ? string.Empty - : x.Sense.Examples[0].Text, Word: word, - WordType: string.IsNullOrWhiteSpace(x.PartOfSpeech) ? "-" : x.PartOfSpeech)) - .ToList(); + var col = data.Select(x => ( + Definition: x.Sense.Definition is string + ? x.Sense.Definition.ToString() + : ((JArray)JToken.Parse(x.Sense.Definition.ToString())).First.ToString(), + Example: x.Sense.Examples is null || x.Sense.Examples.Count == 0 + ? string.Empty + : x.Sense.Examples[0].Text, Word: word, + WordType: string.IsNullOrWhiteSpace(x.PartOfSpeech) ? "-" : x.PartOfSpeech)) + .ToList(); Log.Information("Sending {Count} definition for: {Word}", col.Count, word); - await ctx.SendPaginatedConfirmAsync(0, - page => - { - var model = col.Skip(page).First(); - var embed = new EmbedBuilder() - .WithDescription(ctx.User.Mention) - .AddField(GetText(strs.word), model.Word, true) - .AddField(GetText(strs._class), model.WordType, true) - .AddField(GetText(strs.definition), model.Definition) - .WithOkColor(); + await Response() + .Paginated() + .Items(col) + .PageSize(1) + .Page((items, _) => + { + var model = items.First(); + var embed = _sender.CreateEmbed() + .WithDescription(ctx.User.Mention) + .AddField(GetText(strs.word), model.Word, true) + .AddField(GetText(strs._class), model.WordType, true) + .AddField(GetText(strs.definition), model.Definition) + .WithOkColor(); - if (!string.IsNullOrWhiteSpace(model.Example)) - embed.AddField(GetText(strs.example), model.Example); + if (!string.IsNullOrWhiteSpace(model.Example)) + embed.AddField(GetText(strs.example), model.Example); - return embed; - }, - col.Count, - 1); + return embed; + }) + .SendAsync(); } catch (Exception ex) { @@ -474,7 +479,7 @@ public partial class Searches : NadekoModule await Response() .Embed( - new EmbedBuilder() + _sender.CreateEmbed() .WithOkColor() .AddField("Username", usr.ToString()) .AddField("Avatar Url", avatarUrl) @@ -542,7 +547,7 @@ public partial class Searches : NadekoModule { var v = obj.Verses[0]; await Response() - .Embed(new EmbedBuilder() + .Embed(_sender.CreateEmbed() .WithOkColor() .WithTitle($"{v.BookName} {v.Chapter}:{v.Verse}") .WithDescription(v.Text)) @@ -565,7 +570,7 @@ public partial class Searches : NadekoModule return; } - //var embed = new EmbedBuilder() + //var embed = _sender.CreateEmbed() // .WithOkColor() // .WithDescription(gameData.ShortDescription) // .WithTitle(gameData.Name) diff --git a/src/NadekoBot/Modules/Searches/StreamNotification/StreamNotificationCommands.cs b/src/NadekoBot/Modules/Searches/StreamNotification/StreamNotificationCommands.cs index 2eeca41f9..98c8e2ede 100644 --- a/src/NadekoBot/Modules/Searches/StreamNotification/StreamNotificationCommands.cs +++ b/src/NadekoBot/Modules/Searches/StreamNotification/StreamNotificationCommands.cs @@ -95,9 +95,9 @@ public partial class Searches .Page((elements, cur) => { if (elements.Count == 0) - return new EmbedBuilder().WithDescription(GetText(strs.streams_none)).WithErrorColor(); + return _sender.CreateEmbed().WithDescription(GetText(strs.streams_none)).WithErrorColor(); - var eb = new EmbedBuilder().WithTitle(GetText(strs.streams_follow_title)).WithOkColor(); + var eb = _sender.CreateEmbed().WithTitle(GetText(strs.streams_follow_title)).WithOkColor(); for (var index = 0; index < elements.Count; index++) { var elem = elements[index]; diff --git a/src/NadekoBot/Modules/Searches/StreamNotification/StreamNotificationService.cs b/src/NadekoBot/Modules/Searches/StreamNotification/StreamNotificationService.cs index 8b5080b44..3671ae45f 100644 --- a/src/NadekoBot/Modules/Searches/StreamNotification/StreamNotificationService.cs +++ b/src/NadekoBot/Modules/Searches/StreamNotification/StreamNotificationService.cs @@ -73,34 +73,34 @@ public sealed class StreamNotificationService : INService, IReadyExecutor { var ids = client.GetGuildIds(); var guildConfigs = uow.Set() - .AsQueryable() - .Include(x => x.FollowedStreams) - .Where(x => ids.Contains(x.GuildId)) - .ToList(); + .AsQueryable() + .Include(x => x.FollowedStreams) + .Where(x => ids.Contains(x.GuildId)) + .ToList(); _offlineNotificationServers = new(guildConfigs - .Where(gc => gc.NotifyStreamOffline) - .Select(x => x.GuildId) - .ToList()); + .Where(gc => gc.NotifyStreamOffline) + .Select(x => x.GuildId) + .ToList()); _deleteOnOfflineServers = new(guildConfigs - .Where(gc => gc.DeleteStreamOnlineMessage) - .Select(x => x.GuildId) - .ToList()); + .Where(gc => gc.DeleteStreamOnlineMessage) + .Select(x => x.GuildId) + .ToList()); var followedStreams = guildConfigs.SelectMany(x => x.FollowedStreams).ToList(); _shardTrackedStreams = followedStreams.GroupBy(x => new - { - x.Type, - Name = x.Username.ToLower() - }) - .ToList() - .ToDictionary( - x => new StreamDataKey(x.Key.Type, x.Key.Name.ToLower()), - x => x.GroupBy(y => y.GuildId) - .ToDictionary(y => y.Key, - y => y.AsEnumerable().ToHashSet())); + { + x.Type, + Name = x.Username.ToLower() + }) + .ToList() + .ToDictionary( + x => new StreamDataKey(x.Key.Type, x.Key.Name.ToLower()), + x => x.GroupBy(y => y.GuildId) + .ToDictionary(y => y.Key, + y => y.AsEnumerable().ToHashSet())); // shard 0 will keep track of when there are no more guilds which track a stream if (client.ShardId == 0) @@ -111,12 +111,12 @@ public sealed class StreamNotificationService : INService, IReadyExecutor _streamTracker.AddLastData(fs.CreateKey(), null, false); _trackCounter = allFollowedStreams.GroupBy(x => new - { - x.Type, - Name = x.Username.ToLower() - }) - .ToDictionary(x => new StreamDataKey(x.Key.Type, x.Key.Name), - x => x.Select(fs => fs.GuildId).ToHashSet()); + { + x.Type, + Name = x.Username.ToLower() + }) + .ToDictionary(x => new StreamDataKey(x.Key.Type, x.Key.Name), + x => x.Select(fs => fs.GuildId).ToHashSet()); } } @@ -156,7 +156,7 @@ public sealed class StreamNotificationService : INService, IReadyExecutor continue; var deleteGroups = failingStreams.GroupBy(x => x.Type) - .ToDictionary(x => x.Key, x => x.Select(y => y.Name).ToList()); + .ToDictionary(x => x.Key, x => x.Select(y => y.Name).ToList()); await using var uow = _db.GetDbContext(); foreach (var kvp in deleteGroups) @@ -169,9 +169,9 @@ public sealed class StreamNotificationService : INService, IReadyExecutor string.Join(", ", kvp.Value)); var toDelete = uow.Set() - .AsQueryable() - .Where(x => x.Type == kvp.Key && kvp.Value.Contains(x.Username)) - .ToList(); + .AsQueryable() + .Where(x => x.Type == kvp.Key && kvp.Value.Contains(x.Username)) + .ToList(); uow.RemoveRange(toDelete); await uow.SaveChangesAsync(); @@ -250,13 +250,20 @@ public sealed class StreamNotificationService : INService, IReadyExecutor if (_shardTrackedStreams.TryGetValue(key, out var fss)) { await fss - // send offline stream notifications only to guilds which enable it with .stoff - .SelectMany(x => x.Value) - .Where(x => _offlineNotificationServers.Contains(x.GuildId)) - .Select(fs => _client.GetGuild(fs.GuildId) - ?.GetTextChannel(fs.ChannelId) - ?.EmbedAsync(GetEmbed(fs.GuildId, stream))) - .WhenAll(); + // send offline stream notifications only to guilds which enable it with .stoff + .SelectMany(x => x.Value) + .Where(x => _offlineNotificationServers.Contains(x.GuildId)) + .Select(fs => + { + var ch = _client.GetGuild(fs.GuildId) + ?.GetTextChannel(fs.ChannelId); + + if (ch is null) + return Task.CompletedTask; + + return _sender.Response(ch).Embed(GetEmbed(fs.GuildId, stream)).SendAsync(); + }) + .WhenAll(); } } } @@ -270,33 +277,35 @@ public sealed class StreamNotificationService : INService, IReadyExecutor if (_shardTrackedStreams.TryGetValue(key, out var fss)) { var messages = await fss.SelectMany(x => x.Value) - .Select(async fs => - { - var textChannel = _client.GetGuild(fs.GuildId)?.GetTextChannel(fs.ChannelId); + .Select(async fs => + { + var textChannel = _client.GetGuild(fs.GuildId) + ?.GetTextChannel(fs.ChannelId); - if (textChannel is null) - return default; + if (textChannel is null) + return default; - var repCtx = new ReplacementContext(guild: textChannel.Guild, client: _client) - .WithOverride("%platform%", () => fs.Type.ToString()); + var repCtx = new ReplacementContext(guild: textChannel.Guild, + client: _client) + .WithOverride("%platform%", () => fs.Type.ToString()); - var message = string.IsNullOrWhiteSpace(fs.Message) - ? "" - : await _repSvc.ReplaceAsync(fs.Message, repCtx); + var message = string.IsNullOrWhiteSpace(fs.Message) + ? "" + : await _repSvc.ReplaceAsync(fs.Message, repCtx); - var msg = await _sender.Response(textChannel) - .Embed(GetEmbed(fs.GuildId, stream, false)) - .Text(message) - .SendAsync(); + var msg = await _sender.Response(textChannel) + .Embed(GetEmbed(fs.GuildId, stream, false)) + .Text(message) + .SendAsync(); - // only cache the ids of channel/message pairs - if (_deleteOnOfflineServers.Contains(fs.GuildId)) - return (textChannel.Id, msg.Id); - else - return default; - }) - .WhenAll(); + // only cache the ids of channel/message pairs + if (_deleteOnOfflineServers.Contains(fs.GuildId)) + return (textChannel.Id, msg.Id); + else + return default; + }) + .WhenAll(); // push online stream messages to redis @@ -306,9 +315,9 @@ public sealed class StreamNotificationService : INService, IReadyExecutor try { var pairs = messages - .Where(x => x != default) - .Select(x => (x.Item1, x.Item2)) - .ToList(); + .Where(x => x != default) + .Select(x => (x.Item1, x.Item2)) + .ToList(); if (pairs.Count > 0) await OnlineMessagesSent(key.Type, key.Name, pairs); @@ -330,9 +339,10 @@ public sealed class StreamNotificationService : INService, IReadyExecutor { using (var uow = _db.GetDbContext()) { - var gc = uow.Set().AsQueryable() - .Include(x => x.FollowedStreams) - .FirstOrDefault(x => x.GuildId == guildConfig.GuildId); + var gc = uow.Set() + .AsQueryable() + .Include(x => x.FollowedStreams) + .FirstOrDefault(x => x.GuildId == guildConfig.GuildId); if (gc is null) return Task.CompletedTask; @@ -392,10 +402,10 @@ public sealed class StreamNotificationService : INService, IReadyExecutor await using (var uow = _db.GetDbContext()) { var fss = uow.Set() - .AsQueryable() - .Where(x => x.GuildId == guildId) - .OrderBy(x => x.Id) - .ToList(); + .AsQueryable() + .Where(x => x.GuildId == guildId) + .OrderBy(x => x.Id) + .ToList(); // out of range if (fss.Count <= index) @@ -484,11 +494,11 @@ public sealed class StreamNotificationService : INService, IReadyExecutor public EmbedBuilder GetEmbed(ulong guildId, StreamData status, bool showViewers = true) { - var embed = new EmbedBuilder() - .WithTitle(status.Name) - .WithUrl(status.StreamUrl) - .WithDescription(status.StreamUrl) - .AddField(GetText(guildId, strs.status), status.IsLive ? "🟢 Online" : "🔴 Offline", true); + var embed = _sender.CreateEmbed() + .WithTitle(status.Name) + .WithUrl(status.StreamUrl) + .WithDescription(status.StreamUrl) + .AddField(GetText(guildId, strs.status), status.IsLive ? "🟢 Online" : "🔴 Offline", true); if (showViewers) { diff --git a/src/NadekoBot/Modules/Searches/Translate/TranslateService.cs b/src/NadekoBot/Modules/Searches/Translate/TranslateService.cs index b3553e07b..57dc8fe03 100644 --- a/src/NadekoBot/Modules/Searches/Translate/TranslateService.cs +++ b/src/NadekoBot/Modules/Searches/Translate/TranslateService.cs @@ -69,7 +69,7 @@ public sealed class TranslateService : ITranslateService, IExecNoCommand, IReady || msg.Content.Equals(output, StringComparison.InvariantCultureIgnoreCase)) return; - var embed = new EmbedBuilder().WithOkColor(); + var embed = _sender.CreateEmbed().WithOkColor(); if (autoDelete) { diff --git a/src/NadekoBot/Modules/Searches/Translate/TranslatorCommands.cs b/src/NadekoBot/Modules/Searches/Translate/TranslatorCommands.cs index 818676f40..8466fe159 100644 --- a/src/NadekoBot/Modules/Searches/Translate/TranslatorCommands.cs +++ b/src/NadekoBot/Modules/Searches/Translate/TranslatorCommands.cs @@ -20,7 +20,7 @@ public partial class Searches await ctx.Channel.TriggerTypingAsync(); var translation = await _service.Translate(from, to, text); - var embed = new EmbedBuilder().WithOkColor().AddField(from, text).AddField(to, translation); + var embed = _sender.CreateEmbed().WithOkColor().AddField(from, text).AddField(to, translation); await Response().Embed(embed).SendAsync(); } @@ -80,7 +80,7 @@ public partial class Searches { var langs = _service.GetLanguages().ToList(); - var eb = new EmbedBuilder() + var eb = _sender.CreateEmbed() .WithTitle(GetText(strs.supported_languages)) .WithOkColor(); diff --git a/src/NadekoBot/Modules/Searches/XkcdCommands.cs b/src/NadekoBot/Modules/Searches/XkcdCommands.cs index bc19ebb60..7aba4813c 100644 --- a/src/NadekoBot/Modules/Searches/XkcdCommands.cs +++ b/src/NadekoBot/Modules/Searches/XkcdCommands.cs @@ -25,7 +25,7 @@ public partial class Searches using var http = _httpFactory.CreateClient(); var res = await http.GetStringAsync($"{XKCD_URL}/info.0.json"); var comic = JsonConvert.DeserializeObject(res); - var embed = new EmbedBuilder() + var embed = _sender.CreateEmbed() .WithOkColor() .WithImageUrl(comic.ImageLink) .WithAuthor(comic.Title, "https://xkcd.com/s/919f27.ico", $"{XKCD_URL}/{comic.Num}") @@ -60,7 +60,7 @@ public partial class Searches var res = await http.GetStringAsync($"{XKCD_URL}/{num}/info.0.json"); var comic = JsonConvert.DeserializeObject(res); - var embed = new EmbedBuilder() + var embed = _sender.CreateEmbed() .WithOkColor() .WithImageUrl(comic.ImageLink) .WithAuthor(comic.Title, "https://xkcd.com/s/919f27.ico", $"{XKCD_URL}/{num}") diff --git a/src/NadekoBot/Modules/Utility/Alias/AliasCommands.cs b/src/NadekoBot/Modules/Utility/Alias/AliasCommands.cs index d6c67f9cc..cd4e658a8 100644 --- a/src/NadekoBot/Modules/Utility/Alias/AliasCommands.cs +++ b/src/NadekoBot/Modules/Utility/Alias/AliasCommands.cs @@ -121,17 +121,19 @@ public partial class Utility var arr = maps.ToArray(); - await ctx.SendPaginatedConfirmAsync(page, - curPage => - { - return new EmbedBuilder() - .WithOkColor() - .WithTitle(GetText(strs.alias_list)) - .WithDescription(string.Join("\n", - arr.Skip(curPage * 10).Take(10).Select(x => $"`{x.Key}` => `{x.Value}`"))); - }, - arr.Length, - 10); + await Response() + .Paginated() + .Items(arr) + .PageSize(10) + .CurrentPage(page) + .Page((items, _) => + { + return _sender.CreateEmbed() + .WithOkColor() + .WithTitle(GetText(strs.alias_list)) + .WithDescription(string.Join("\n", items.Select(x => $"`{x.Key}` => `{x.Value}`"))); + }) + .SendAsync(); } } } \ No newline at end of file diff --git a/src/NadekoBot/Modules/Utility/ConfigCommands.cs b/src/NadekoBot/Modules/Utility/ConfigCommands.cs index cf409cd3d..1d4378ef0 100644 --- a/src/NadekoBot/Modules/Utility/ConfigCommands.cs +++ b/src/NadekoBot/Modules/Utility/ConfigCommands.cs @@ -20,7 +20,7 @@ public partial class Utility if (setting is null) { var configNames = _settingServices.Select(x => x.Name); - var embed = new EmbedBuilder() + var embed = _sender.CreateEmbed() .WithErrorColor() .WithDescription(GetText(strs.config_not_found(Format.Code(name)))) .AddField(GetText(strs.config_list), string.Join("\n", configNames)); @@ -43,7 +43,7 @@ public partial class Utility name = name?.ToLowerInvariant(); if (string.IsNullOrWhiteSpace(name)) { - var embed = new EmbedBuilder() + var embed = _sender.CreateEmbed() .WithOkColor() .WithTitle(GetText(strs.config_list)) .WithDescription(string.Join("\n", configNames)); @@ -58,7 +58,7 @@ public partial class Utility // if config name is not found, print error and the list of configs if (setting is null) { - var embed = new EmbedBuilder() + var embed = _sender.CreateEmbed() .WithErrorColor() .WithDescription(GetText(strs.config_not_found(Format.Code(name)))) .AddField(GetText(strs.config_list), string.Join("\n", configNames)); @@ -75,7 +75,7 @@ public partial class Utility if (string.IsNullOrWhiteSpace(prop)) { var propStrings = GetPropsAndValuesString(setting, propNames); - var embed = new EmbedBuilder().WithOkColor().WithTitle($"⚙️ {setting.Name}").WithDescription(propStrings); + var embed = _sender.CreateEmbed().WithOkColor().WithTitle($"⚙️ {setting.Name}").WithDescription(propStrings); await Response().Embed(embed).SendAsync(); @@ -88,7 +88,7 @@ public partial class Utility if (!exists) { var propStrings = GetPropsAndValuesString(setting, propNames); - var propErrorEmbed = new EmbedBuilder() + var propErrorEmbed = _sender.CreateEmbed() .WithErrorColor() .WithDescription(GetText( strs.config_prop_not_found(Format.Code(prop), Format.Code(name)))) @@ -110,7 +110,7 @@ public partial class Utility if (prop != "currency.sign") value = Format.Code(Format.Sanitize(value.TrimTo(1000)), "json"); - var embed = new EmbedBuilder() + var embed = _sender.CreateEmbed() .WithOkColor() .AddField("Config", Format.Code(setting.Name), true) .AddField("Prop", Format.Code(prop), true) diff --git a/src/NadekoBot/Modules/Utility/Giveaway/GiveawayCommands.cs b/src/NadekoBot/Modules/Utility/Giveaway/GiveawayCommands.cs index 929716e4d..c5f2702c5 100644 --- a/src/NadekoBot/Modules/Utility/Giveaway/GiveawayCommands.cs +++ b/src/NadekoBot/Modules/Utility/Giveaway/GiveawayCommands.cs @@ -17,7 +17,7 @@ public partial class Utility return; } - var eb = new EmbedBuilder() + var eb = _sender.CreateEmbed() .WithPendingColor() .WithTitle(GetText(strs.giveaway_starting)) .WithDescription(message); @@ -103,7 +103,7 @@ public partial class Utility return; } - var eb = new EmbedBuilder() + var eb = _sender.CreateEmbed() .WithTitle(GetText(strs.giveaway_list)) .WithOkColor(); diff --git a/src/NadekoBot/Modules/Utility/Giveaway/GiveawayService.cs b/src/NadekoBot/Modules/Utility/Giveaway/GiveawayService.cs index ea9af2889..631b2540e 100644 --- a/src/NadekoBot/Modules/Utility/Giveaway/GiveawayService.cs +++ b/src/NadekoBot/Modules/Utility/Giveaway/GiveawayService.cs @@ -317,7 +317,7 @@ public sealed class GiveawayService : INService, IReadyExecutor {Format.Code(winner.UserId.ToString())} """; - var eb = new EmbedBuilder() + var eb = _sender.CreateEmbed() .WithOkColor() .WithTitle(GetText(strs.giveaway_ended)) .WithDescription(ga.Message) diff --git a/src/NadekoBot/Modules/Utility/Info/InfoCommands.cs b/src/NadekoBot/Modules/Utility/Info/InfoCommands.cs index 4767c923b..a7dcef1a0 100644 --- a/src/NadekoBot/Modules/Utility/Info/InfoCommands.cs +++ b/src/NadekoBot/Modules/Utility/Info/InfoCommands.cs @@ -54,7 +54,7 @@ public partial class Utility if (string.IsNullOrWhiteSpace(features)) features = "-"; - var embed = new EmbedBuilder() + var embed = _sender.CreateEmbed() .WithAuthor(GetText(strs.server_info)) .WithTitle(guild.Name) .AddField(GetText(strs.id), guild.Id.ToString(), true) @@ -87,7 +87,7 @@ public partial class Utility return; var createdAt = new DateTime(2015, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).AddMilliseconds(ch.Id >> 22); var usercount = (await ch.GetUsersAsync().FlattenAsync()).Count(); - var embed = new EmbedBuilder() + var embed = _sender.CreateEmbed() .WithTitle(ch.Name) .WithDescription(ch.Topic?.SanitizeMentions(true)) .AddField(GetText(strs.id), ch.Id.ToString(), true) @@ -107,7 +107,7 @@ public partial class Utility var createdAt = new DateTime(2015, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) .AddMilliseconds(role.Id >> 22); var usercount = role.Members.LongCount(); - var embed = new EmbedBuilder() + var embed = _sender.CreateEmbed() .WithTitle(role.Name.TrimTo(128)) .WithDescription(role.Permissions.ToList().Join(" | ")) .AddField(GetText(strs.id), role.Id.ToString(), true) @@ -133,7 +133,7 @@ public partial class Utility if (user is null) return; - var embed = new EmbedBuilder().AddField(GetText(strs.name), $"**{user.Username}**#{user.Discriminator}", true); + var embed = _sender.CreateEmbed().AddField(GetText(strs.name), $"**{user.Username}**#{user.Discriminator}", true); if (!string.IsNullOrWhiteSpace(user.Nickname)) embed.AddField(GetText(strs.nickname), user.Nickname, true); @@ -204,7 +204,7 @@ public partial class Utility kvp.Value))); } - await Response().Embed(new EmbedBuilder() + await Response().Embed(_sender.CreateEmbed() .WithTitle(GetText(strs.activity_page(page + 1))) .WithOkColor() .WithFooter(GetText( diff --git a/src/NadekoBot/Modules/Utility/Info/InviteCommands.cs b/src/NadekoBot/Modules/Utility/Info/InviteCommands.cs index bab37298d..eb47202d5 100644 --- a/src/NadekoBot/Modules/Utility/Info/InviteCommands.cs +++ b/src/NadekoBot/Modules/Utility/Info/InviteCommands.cs @@ -47,9 +47,9 @@ public partial class Utility var i = 1; if (!invs.Any()) - return new EmbedBuilder().WithErrorColor().WithDescription(GetText(strs.no_invites)); + return _sender.CreateEmbed().WithErrorColor().WithDescription(GetText(strs.no_invites)); - var embed = new EmbedBuilder().WithOkColor(); + var embed = _sender.CreateEmbed().WithOkColor(); foreach (var inv in invs) { var expiryString = inv.MaxAge is null or 0 || inv.CreatedAt is null diff --git a/src/NadekoBot/Modules/Utility/Quote/QuoteCommands.cs b/src/NadekoBot/Modules/Utility/Quote/QuoteCommands.cs index dc96e8ba9..fbc4b5323 100644 --- a/src/NadekoBot/Modules/Utility/Quote/QuoteCommands.cs +++ b/src/NadekoBot/Modules/Utility/Quote/QuoteCommands.cs @@ -106,7 +106,10 @@ public partial class Utility var text = SmartText.CreateFrom(quote.Text); text = await repSvc.ReplaceAsync(text, repCtx); - await ctx.Channel.SendAsync($"`#{quote.Id}` 📣 " + text, true, replyTo: ctx.Message); + await Response() + .Text($"`#{quote.Id}` 📣 " + text) + .Sanitize() + .SendAsync(); } [Cmd] @@ -132,13 +135,13 @@ public partial class Utility private async Task ShowQuoteData(Quote data) { - var eb = new EmbedBuilder() - .WithOkColor() - .WithTitle($"{GetText(strs.quote_id($"#{data.Id}"))} | {GetText(strs.response)}:") - .WithDescription(Format.Sanitize(data.Text).Replace("](", "]\\(").TrimTo(4096)) - .AddField(GetText(strs.trigger), data.Keyword) - .WithFooter( - GetText(strs.created_by($"{data.AuthorName} ({data.AuthorId})"))); + var eb = _sender.CreateEmbed() + .WithOkColor() + .WithTitle($"{GetText(strs.quote_id($"#{data.Id}"))} | {GetText(strs.response)}:") + .WithDescription(Format.Sanitize(data.Text).Replace("](", "]\\(").TrimTo(4096)) + .AddField(GetText(strs.trigger), data.Keyword) + .WithFooter( + GetText(strs.created_by($"{data.AuthorName} ({data.AuthorId})"))); if (!(data.Text.Length > 4096)) { @@ -146,10 +149,12 @@ public partial class Utility return; } - // todo all send files should go through response system too - await ctx.Channel.SendFileAsync( - attachment: new FileAttachment(await data.Text.ToStream(), "quote.txt"), - embed: eb.Build()); + await using var textStream = await data.Text.ToStream(); + + await Response() + .Embed(eb) + .File(textStream, "quote.txt") + .SendAsync(); } private async Task QuoteSearchinternalAsync(string? keyword, string textOrAuthor) @@ -217,7 +222,10 @@ public partial class Utility var text = SmartText.CreateFrom(quote.Text); text = await repSvc.ReplaceAsync(text, repCtx); - await ctx.Channel.SendAsync(infoText + text, true, replyTo: ctx.Message); + await Response() + .Text(infoText + text) + .Sanitize() + .SendAsync(); } [Cmd] diff --git a/src/NadekoBot/Modules/Utility/Remind/RemindCommands.cs b/src/NadekoBot/Modules/Utility/Remind/RemindCommands.cs index 1b1239bde..a520fc6e4 100644 --- a/src/NadekoBot/Modules/Utility/Remind/RemindCommands.cs +++ b/src/NadekoBot/Modules/Utility/Remind/RemindCommands.cs @@ -96,7 +96,7 @@ public partial class Utility if (--page < 0) return; - var embed = new EmbedBuilder() + var embed = _sender.CreateEmbed() .WithOkColor() .WithTitle(GetText(isServer ? strs.reminder_server_list : strs.reminder_list)); diff --git a/src/NadekoBot/Modules/Utility/Remind/RemindService.cs b/src/NadekoBot/Modules/Utility/Remind/RemindService.cs index 824fd36ec..c7510f350 100644 --- a/src/NadekoBot/Modules/Utility/Remind/RemindService.cs +++ b/src/NadekoBot/Modules/Utility/Remind/RemindService.cs @@ -208,7 +208,7 @@ public class RemindService : INService, IReadyExecutor, IRemindService else { await _sender.Response(ch) - .Embed(new EmbedBuilder() + .Embed(_sender.CreateEmbed() .WithOkColor() .WithTitle("Reminder") .AddField("Created At", diff --git a/src/NadekoBot/Modules/Utility/Repeater/RepeatCommands.cs b/src/NadekoBot/Modules/Utility/Repeater/RepeatCommands.cs index f3e9485c8..83fdd188c 100644 --- a/src/NadekoBot/Modules/Utility/Repeater/RepeatCommands.cs +++ b/src/NadekoBot/Modules/Utility/Repeater/RepeatCommands.cs @@ -64,7 +64,7 @@ public partial class Utility } var description = GetRepeaterInfoString(removed); - await Response().Embed(new EmbedBuilder() + await Response().Embed(_sender.CreateEmbed() .WithOkColor() .WithTitle(GetText(strs.repeater_removed(index + 1))) .WithDescription(description)).SendAsync(); @@ -187,7 +187,7 @@ public partial class Utility } var description = GetRepeaterInfoString(runner); - await Response().Embed(new EmbedBuilder() + await Response().Embed(_sender.CreateEmbed() .WithOkColor() .WithTitle(GetText(strs.repeater_created)) .WithDescription(description)).SendAsync(); @@ -205,7 +205,7 @@ public partial class Utility return; } - var embed = new EmbedBuilder().WithTitle(GetText(strs.list_of_repeaters)).WithOkColor(); + var embed = _sender.CreateEmbed().WithTitle(GetText(strs.list_of_repeaters)).WithOkColor(); var i = 0; foreach (var runner in repeaters.OrderBy(r => r.Repeater.Id)) diff --git a/src/NadekoBot/Modules/Utility/Repeater/RepeaterService.cs b/src/NadekoBot/Modules/Utility/Repeater/RepeaterService.cs index 411642df1..414244fc9 100644 --- a/src/NadekoBot/Modules/Utility/Repeater/RepeaterService.cs +++ b/src/NadekoBot/Modules/Utility/Repeater/RepeaterService.cs @@ -19,24 +19,27 @@ public sealed class RepeaterService : IReadyExecutor, INService private readonly ConcurrentHashSet _skipNext = new(); private readonly object _queueLocker = new(); + private readonly IMessageSenderService _sender; public RepeaterService( DiscordSocketClient client, DbService db, IReplacementService repSvc, - IBotCredentials creds) + IBotCredentials creds, + IMessageSenderService sender) { _db = db; _repSvc = repSvc; _creds = creds; _client = client; + _sender = sender; using var uow = _db.GetDbContext(); var shardRepeaters = uow.Set() - .Where(x => (int)(x.GuildId / Math.Pow(2, 22)) % _creds.TotalShards - == _client.ShardId) - .AsNoTracking() - .ToList(); + .Where(x => (int)(x.GuildId / Math.Pow(2, 22)) % _creds.TotalShards + == _client.ShardId) + .AsNoTracking() + .ToList(); _noRedundant = new(shardRepeaters.Where(x => x.NoRedundant).Select(x => x.Id)); @@ -125,10 +128,11 @@ public sealed class RepeaterService : IReadyExecutor, INService { await using var uow = _db.GetDbContext(); - var toTrigger = await uow.Set().AsNoTracking() - .Where(x => x.GuildId == guildId) - .Skip(index) - .FirstOrDefaultAsyncEF(); + var toTrigger = await uow.Set() + .AsNoTracking() + .Where(x => x.GuildId == guildId) + .Skip(index) + .FirstOrDefaultAsyncEF(); if (toTrigger is null) return false; @@ -265,7 +269,7 @@ public sealed class RepeaterService : IReadyExecutor, INService var text = SmartText.CreateFrom(repeater.Message); text = await _repSvc.ReplaceAsync(text, repCtx); - var newMsg = await channel.SendAsync(text); + var newMsg = await _sender.Response(channel).Text(text).SendAsync(); _ = newMsg.AddReactionAsync(new Emoji("🔄")); if (_noRedundant.Contains(repeater.Id)) @@ -308,12 +312,13 @@ public sealed class RepeaterService : IReadyExecutor, INService private async Task SetRepeaterLastMessageInternal(int repeaterId, ulong lastMsgId) { await using var uow = _db.GetDbContext(); - await uow.Set().AsQueryable() - .Where(x => x.Id == repeaterId) - .UpdateAsync(rep => new() - { - LastMessageId = lastMsgId - }); + await uow.Set() + .AsQueryable() + .Where(x => x.Id == repeaterId) + .UpdateAsync(rep => new() + { + LastMessageId = lastMsgId + }); } public async Task AddRepeaterAsync( @@ -358,10 +363,11 @@ public sealed class RepeaterService : IReadyExecutor, INService throw new ArgumentOutOfRangeException(nameof(index)); await using var uow = _db.GetDbContext(); - var toRemove = await uow.Set().AsNoTracking() - .Where(x => x.GuildId == guildId) - .Skip(index) - .FirstOrDefaultAsyncEF(); + var toRemove = await uow.Set() + .AsNoTracking() + .Where(x => x.GuildId == guildId) + .Skip(index) + .FirstOrDefaultAsyncEF(); if (toRemove is null) return null; @@ -389,10 +395,11 @@ public sealed class RepeaterService : IReadyExecutor, INService public async Task ToggleRedundantAsync(ulong guildId, int index) { await using var uow = _db.GetDbContext(); - var toToggle = await uow.Set().AsQueryable() - .Where(x => x.GuildId == guildId) - .Skip(index) - .FirstOrDefaultAsyncEF(); + var toToggle = await uow.Set() + .AsQueryable() + .Where(x => x.GuildId == guildId) + .Skip(index) + .FirstOrDefaultAsyncEF(); if (toToggle is null) return null; @@ -411,9 +418,9 @@ public sealed class RepeaterService : IReadyExecutor, INService { await using var ctx = _db.GetDbContext(); var toSkip = await ctx.Set() - .Where(x => x.GuildId == guildId) - .Skip(index) - .FirstOrDefaultAsyncEF(); + .Where(x => x.GuildId == guildId) + .Skip(index) + .FirstOrDefaultAsyncEF(); if (toSkip is null) return null; diff --git a/src/NadekoBot/Modules/Utility/Todo/TodoCommands.cs b/src/NadekoBot/Modules/Utility/Todo/TodoCommands.cs index e89ddeffc..f1445fdfb 100644 --- a/src/NadekoBot/Modules/Utility/Todo/TodoCommands.cs +++ b/src/NadekoBot/Modules/Utility/Todo/TodoCommands.cs @@ -81,27 +81,27 @@ public partial class Utility } - private async Task ShowTodosAsync(TodoModel[] todos) - { - await ctx.SendPaginatedConfirmAsync(0, - (curPage) => - { - var eb = new EmbedBuilder() - .WithOkColor() - .WithTitle(GetText(strs.todo_list)); + private Task ShowTodosAsync(TodoModel[] todos) + => Response() + .Paginated() + .Items(todos) + .PageSize(9) + .Page((items, _) => + { + var eb = _sender.CreateEmbed() + .WithOkColor() + .WithTitle(GetText(strs.todo_list)); - ShowTodoItem(todos, curPage, eb); + ShowTodoItem(items, eb); - return eb; - }, - todos.Length, - 9); - } + return eb; + }) + .SendAsync(); - private static void ShowTodoItem(IReadOnlyCollection todos, int curPage, EmbedBuilder eb) + private static void ShowTodoItem(IReadOnlyCollection todos, EmbedBuilder eb) { var sb = new StringBuilder(); - foreach (var todo in todos.Skip(curPage * 9).Take(9)) + foreach (var todo in todos) { sb.AppendLine($"{(todo.IsDone ? "✔" : "□")} {Format.Code(new kwum(todo.Id).ToString())} {todo.Todo}"); @@ -147,23 +147,25 @@ public partial class Utility return; } - await ctx.SendPaginatedConfirmAsync(page, - (curPage) => - { - var eb = new EmbedBuilder() - .WithTitle(GetText(strs.todo_archive_list)) - .WithOkColor(); + await Response() + .Paginated() + .Items(archivedTodoLists) + .PageSize(9) + .CurrentPage(page) + .Page((items, _) => + { + var eb = _sender.CreateEmbed() + .WithTitle(GetText(strs.todo_archive_list)) + .WithOkColor(); - foreach (var archivedList in archivedTodoLists.Skip(curPage * 9).Take(9)) - { - eb.AddField($"id: {archivedList.Id.ToString()}", archivedList.Name, true); - } + foreach (var archivedList in items) + { + eb.AddField($"id: {archivedList.Id.ToString()}", archivedList.Name, true); + } - return eb; - }, - archivedTodoLists.Count, - 9, - true); + return eb; + }) + .SendAsync(); } [Cmd] @@ -176,19 +178,21 @@ public partial class Utility return; } - await ctx.SendPaginatedConfirmAsync(0, - (curPage) => - { - var eb = new EmbedBuilder() - .WithOkColor() - .WithTitle(GetText(strs.todo_list)); + await Response() + .Paginated() + .Items(list.Items) + .PageSize(9) + .Page((items, _) => + { + var eb = _sender.CreateEmbed() + .WithOkColor() + .WithTitle(GetText(strs.todo_list)); - ShowTodoItem(list.Items, curPage, eb); + ShowTodoItem(items, eb); - return eb; - }, - list.Items.Count, - 9); + return eb; + }) + .SendAsync(); } [Cmd] diff --git a/src/NadekoBot/Modules/Utility/UnitConversion/UnitConversionCommands.cs b/src/NadekoBot/Modules/Utility/UnitConversion/UnitConversionCommands.cs index e6d7abf13..6fd573190 100644 --- a/src/NadekoBot/Modules/Utility/UnitConversion/UnitConversionCommands.cs +++ b/src/NadekoBot/Modules/Utility/UnitConversion/UnitConversionCommands.cs @@ -13,7 +13,7 @@ public partial class Utility { var units = await _service.GetUnitsAsync(); - var embed = new EmbedBuilder().WithTitle(GetText(strs.convertlist)).WithOkColor(); + var embed = _sender.CreateEmbed().WithTitle(GetText(strs.convertlist)).WithOkColor(); foreach (var g in units.GroupBy(x => x.UnitType)) diff --git a/src/NadekoBot/Modules/Utility/Utility.cs b/src/NadekoBot/Modules/Utility/Utility.cs index 1143fcdc1..df12bb63b 100644 --- a/src/NadekoBot/Modules/Utility/Utility.cs +++ b/src/NadekoBot/Modules/Utility/Utility.cs @@ -83,9 +83,10 @@ public partial class Utility : NadekoModule var repCtx = new ReplacementContext(Context); message = await repSvc.ReplaceAsync(message, repCtx); - await channel.SendAsync(message, - !((IGuildUser)ctx.User).GuildPermissions.MentionEveryone, - replyTo: ctx.Message); + await Response() + .Text(message) + .UserBasedMentions() + .SendAsync(); } [Cmd] @@ -154,21 +155,22 @@ public partial class Utility : NadekoModule .Select(u => $"`{u.Id,18}` {u}") .ToArray(); - await ctx.SendPaginatedConfirmAsync(page, - cur => - { - var pageUsers = roleUsers.Skip(cur * 20).Take(20).ToList(); + await Response() + .Paginated() + .Items(roleUsers) + .PageSize(20) + .CurrentPage(page) + .Page((pageUsers, _) => + { + if (pageUsers.Count == 0) + return _sender.CreateEmbed().WithOkColor().WithDescription(GetText(strs.no_user_on_this_page)); - if (pageUsers.Count == 0) - return new EmbedBuilder().WithOkColor().WithDescription(GetText(strs.no_user_on_this_page)); - - return new EmbedBuilder() - .WithOkColor() - .WithTitle(GetText(strs.inrole_list(Format.Bold(role?.Name ?? "No Role"), roleUsers.Length))) - .WithDescription(string.Join("\n", pageUsers)); - }, - roleUsers.Length, - 20); + return _sender.CreateEmbed() + .WithOkColor() + .WithTitle(GetText(strs.inrole_list(Format.Bold(role?.Name ?? "No Role"), roleUsers.Length))) + .WithDescription(string.Join("\n", pageUsers)); + }) + .SendAsync(); } [Cmd] @@ -301,30 +303,32 @@ public partial class Utility : NadekoModule if (string.IsNullOrWhiteSpace(ownerIds)) ownerIds = "-"; - await Response().Embed(new EmbedBuilder() - .WithOkColor() - .WithAuthor($"NadekoBot v{StatsService.BotVersion}", - "https://nadeko-pictures.nyc3.digitaloceanspaces.com/other/avatar.png", - "https://nadekobot.readthedocs.io/en/latest/") - .AddField(GetText(strs.author), _stats.Author, true) - .AddField(GetText(strs.botid), _client.CurrentUser.Id.ToString(), true) - .AddField(GetText(strs.shard), - $"#{_client.ShardId} / {_creds.TotalShards}", - true) - .AddField(GetText(strs.commands_ran), _stats.CommandsRan.ToString(), true) - .AddField(GetText(strs.messages), - $"{_stats.MessageCounter} ({_stats.MessagesPerSecond:F2}/sec)", - true) - .AddField(GetText(strs.memory), - FormattableString.Invariant($"{_stats.GetPrivateMemoryMegabytes():F2} MB"), - true) - .AddField(GetText(strs.owner_ids), ownerIds, true) - .AddField(GetText(strs.uptime), _stats.GetUptimeString("\n"), true) - .AddField(GetText(strs.presence), - GetText(strs.presence_txt(_coord.GetGuildCount(), - _stats.TextChannels, - _stats.VoiceChannels)), - true)).SendAsync(); + await Response() + .Embed(_sender.CreateEmbed() + .WithOkColor() + .WithAuthor($"NadekoBot v{StatsService.BotVersion}", + "https://nadeko-pictures.nyc3.digitaloceanspaces.com/other/avatar.png", + "https://nadekobot.readthedocs.io/en/latest/") + .AddField(GetText(strs.author), _stats.Author, true) + .AddField(GetText(strs.botid), _client.CurrentUser.Id.ToString(), true) + .AddField(GetText(strs.shard), + $"#{_client.ShardId} / {_creds.TotalShards}", + true) + .AddField(GetText(strs.commands_ran), _stats.CommandsRan.ToString(), true) + .AddField(GetText(strs.messages), + $"{_stats.MessageCounter} ({_stats.MessagesPerSecond:F2}/sec)", + true) + .AddField(GetText(strs.memory), + FormattableString.Invariant($"{_stats.GetPrivateMemoryMegabytes():F2} MB"), + true) + .AddField(GetText(strs.owner_ids), ownerIds, true) + .AddField(GetText(strs.uptime), _stats.GetUptimeString("\n"), true) + .AddField(GetText(strs.presence), + GetText(strs.presence_txt(_coord.GetGuildCount(), + _stats.TextChannels, + _stats.VoiceChannels)), + true)) + .SendAsync(); } [Cmd] @@ -517,7 +521,7 @@ public partial class Utility : NadekoModule return; } - var embed = new EmbedBuilder().WithOkColor(); + var embed = _sender.CreateEmbed().WithOkColor(); foreach (var guild in guilds) embed.AddField(guild.Name, GetText(strs.listservers(guild.Id, guild.MemberCount, guild.OwnerId))); @@ -660,6 +664,7 @@ public partial class Utility : NadekoModule .WithReferences(this.GetType().Assembly) .WithImports( "System", + "System.Linq", "NadekoBot", "NadekoBot.Extensions", "Microsoft.Extensions.DependencyInjection", @@ -683,10 +688,10 @@ public partial class Utility : NadekoModule var output = result.ReturnValue?.ToString(); if (!string.IsNullOrWhiteSpace(output)) { - var eb = new EmbedBuilder() - .WithOkColor() - .AddField("Code", scriptText) - .AddField("Output", output.TrimTo(512)!); + var eb = _sender.CreateEmbed() + .WithOkColor() + .AddField("Code", scriptText) + .AddField("Output", output.TrimTo(512)!); _ = Response().Embed(eb).SendAsync(); } diff --git a/src/NadekoBot/Modules/Xp/Club/Club.cs b/src/NadekoBot/Modules/Xp/Club/Club.cs index 4e50f1a2d..6a7ebd4e7 100644 --- a/src/NadekoBot/Modules/Xp/Club/Club.cs +++ b/src/NadekoBot/Modules/Xp/Club/Club.cs @@ -127,10 +127,9 @@ public partial class Xp .Paginated() .Items(allUsers) .PageSize(10) - .CurrentPage(0) .Page((users, _) => { - var embed = new EmbedBuilder() + var embed = _sender.CreateEmbed() .WithOkColor() .WithTitle($"{club}") .WithDescription(GetText(strs.level_x(lvl.Level + $" ({club.Xp} xp)"))) @@ -206,22 +205,21 @@ public partial class Xp var bans = club.Bans.Select(x => x.User).ToArray(); - return ctx.SendPaginatedConfirmAsync(page, - _ => - { - var toShow = string.Join("\n", - bans - .Skip(page * 10) - .Take(10) - .Select(x => x.ToString())); + return Response() + .Paginated() + .Items(bans) + .PageSize(10) + .CurrentPage(page) + .Page((items, _) => + { + var toShow = string.Join("\n", items.Select(x => x.ToString())); - return new EmbedBuilder() - .WithTitle(GetText(strs.club_bans_for(club.ToString()))) - .WithDescription(toShow) - .WithOkColor(); - }, - bans.Length, - 10); + return _sender.CreateEmbed() + .WithTitle(GetText(strs.club_bans_for(club.ToString()))) + .WithDescription(toShow) + .WithOkColor(); + }) + .SendAsync(); } [Cmd] @@ -236,18 +234,21 @@ public partial class Xp var apps = club.Applicants.Select(x => x.User).ToArray(); - return ctx.SendPaginatedConfirmAsync(page, - _ => - { - var toShow = string.Join("\n", apps.Skip(page * 10).Take(10).Select(x => x.ToString())); + return Response() + .Paginated() + .Items(apps) + .PageSize(10) + .CurrentPage(page) + .Page((items, _) => + { + var toShow = string.Join("\n", items.Select(x => x.ToString())); - return new EmbedBuilder() - .WithTitle(GetText(strs.club_apps_for(club.ToString()))) - .WithDescription(toShow) - .WithOkColor(); - }, - apps.Length, - 10); + return _sender.CreateEmbed() + .WithTitle(GetText(strs.club_apps_for(club.ToString()))) + .WithDescription(toShow) + .WithOkColor(); + }) + .SendAsync(); } [Cmd] @@ -412,7 +413,7 @@ public partial class Xp ? "-" : desc; - var eb = new EmbedBuilder() + var eb = _sender.CreateEmbed() .WithAuthor(ctx.User) .WithTitle(GetText(strs.club_desc_update)) .WithOkColor() @@ -443,7 +444,7 @@ public partial class Xp var clubs = _service.GetClubLeaderboardPage(page); - var embed = new EmbedBuilder().WithTitle(GetText(strs.club_leaderboard(page + 1))).WithOkColor(); + var embed = _sender.CreateEmbed().WithTitle(GetText(strs.club_leaderboard(page + 1))).WithOkColor(); var i = page * 9; foreach (var club in clubs) @@ -464,7 +465,7 @@ public partial class Xp return; case ClubRenameResult.Success: { - var embed = new EmbedBuilder().WithTitle(GetText(strs.club_renamed(clubName))).WithOkColor(); + var embed = _sender.CreateEmbed().WithTitle(GetText(strs.club_renamed(clubName))).WithOkColor(); await Response().Embed(embed).SendAsync(); return; } diff --git a/src/NadekoBot/Modules/Xp/Xp.cs b/src/NadekoBot/Modules/Xp/Xp.cs index 9eed1ba5a..4dd1de798 100644 --- a/src/NadekoBot/Modules/Xp/Xp.cs +++ b/src/NadekoBot/Modules/Xp/Xp.cs @@ -59,10 +59,10 @@ public partial class Xp : NadekoModule var globalSetting = _service.GetNotificationType(ctx.User); var serverSetting = _service.GetNotificationType(ctx.User.Id, ctx.Guild.Id); - var embed = new EmbedBuilder() - .WithOkColor() - .AddField(GetText(strs.xpn_setting_global), GetNotifLocationString(globalSetting)) - .AddField(GetText(strs.xpn_setting_server), GetNotifLocationString(serverSetting)); + var embed = _sender.CreateEmbed() + .WithOkColor() + .AddField(GetText(strs.xpn_setting_global), GetNotifLocationString(globalSetting)) + .AddField(GetText(strs.xpn_setting_server), GetNotifLocationString(serverSetting)); await Response().Embed(embed).SendAsync(); } @@ -147,18 +147,21 @@ public partial class Xp : NadekoModule desc += "\n\n" + rolesStr + chansStr; var lines = desc.Split('\n'); - await ctx.SendPaginatedConfirmAsync(0, - curpage => - { - var embed = new EmbedBuilder() - .WithTitle(GetText(strs.exclusion_list)) - .WithDescription(string.Join('\n', lines.Skip(15 * curpage).Take(15))) - .WithOkColor(); + await Response() + .Paginated() + .Items(lines) + .PageSize(15) + .CurrentPage(0) + .Page((items, _) => + { + var embed = _sender.CreateEmbed() + .WithTitle(GetText(strs.exclusion_list)) + .WithDescription(string.Join('\n', items)) + .WithOkColor(); - return embed; - }, - lines.Length, - 15); + return embed; + }) + .SendAsync(); } [Cmd] @@ -182,53 +185,54 @@ public partial class Xp : NadekoModule await ctx.Channel.TriggerTypingAsync(); var socketGuild = (SocketGuild)ctx.Guild; - var allUsers = new List(); + var allCleanUsers = new List(); if (opts.Clean) { await ctx.Channel.TriggerTypingAsync(); await _tracker.EnsureUsersDownloadedAsync(ctx.Guild); - allUsers = _service.GetTopUserXps(ctx.Guild.Id, 1000) - .Where(user => socketGuild.GetUser(user.UserId) is not null) - .ToList(); + allCleanUsers = _service.GetTopUserXps(ctx.Guild.Id, 1000) + .Where(user => socketGuild.GetUser(user.UserId) is not null) + .ToList(); } - await ctx.SendPaginatedConfirmAsync(page, - curPage => - { - var embed = new EmbedBuilder().WithTitle(GetText(strs.server_leaderboard)).WithOkColor(); + await Response() + .Paginated() + .PageItems(opts.Clean + ? (curPage) => Task.FromResult>(allCleanUsers.Skip(curPage * 9) + .Take(9) + .ToList()) + : (curPage) => Task.FromResult>(_service.GetUserXps(ctx.Guild.Id, curPage))) + .PageSize(9) + .CurrentPage(page) + .AddFooter(false) + .Page((users, curPage) => + { + var embed = _sender.CreateEmbed().WithTitle(GetText(strs.server_leaderboard)).WithOkColor(); - List users; - if (opts.Clean) - users = allUsers.Skip(curPage * 9).Take(9).ToList(); - else - users = _service.GetUserXps(ctx.Guild.Id, curPage); + if (!users.Any()) + return embed.WithDescription("-"); - if (!users.Any()) - return embed.WithDescription("-"); + for (var i = 0; i < users.Count; i++) + { + var levelStats = new LevelStats(users[i].Xp + users[i].AwardedXp); + var user = ((SocketGuild)ctx.Guild).GetUser(users[i].UserId); - for (var i = 0; i < users.Count; i++) - { - var levelStats = new LevelStats(users[i].Xp + users[i].AwardedXp); - var user = ((SocketGuild)ctx.Guild).GetUser(users[i].UserId); + var userXpData = users[i]; - var userXpData = users[i]; + var awardStr = string.Empty; + if (userXpData.AwardedXp > 0) + awardStr = $"(+{userXpData.AwardedXp})"; + else if (userXpData.AwardedXp < 0) + awardStr = $"({userXpData.AwardedXp})"; - var awardStr = string.Empty; - if (userXpData.AwardedXp > 0) - awardStr = $"(+{userXpData.AwardedXp})"; - else if (userXpData.AwardedXp < 0) - awardStr = $"({userXpData.AwardedXp})"; + embed.AddField($"#{i + 1 + (curPage * 9)} {user?.ToString() ?? users[i].UserId.ToString()}", + $"{GetText(strs.level_x(levelStats.Level))} - {levelStats.TotalXp}xp {awardStr}"); + } - embed.AddField($"#{i + 1 + (curPage * 9)} {user?.ToString() ?? users[i].UserId.ToString()}", - $"{GetText(strs.level_x(levelStats.Level))} - {levelStats.TotalXp}xp {awardStr}"); - } - - return embed; - }, - 900, - 9, - false); + return embed; + }) + .SendAsync(); } [Cmd] @@ -239,7 +243,7 @@ public partial class Xp : NadekoModule return; var users = _service.GetUserXps(page); - var embed = new EmbedBuilder().WithTitle(GetText(strs.global_leaderboard)).WithOkColor(); + var embed = _sender.CreateEmbed().WithTitle(GetText(strs.global_leaderboard)).WithOkColor(); if (!users.Any()) embed.WithDescription("-"); @@ -317,7 +321,9 @@ public partial class Xp : NadekoModule [UserPerm(GuildPerm.Administrator)] public async Task XpReset(ulong userId) { - var embed = new EmbedBuilder().WithTitle(GetText(strs.reset)).WithDescription(GetText(strs.reset_user_confirm)); + var embed = _sender.CreateEmbed() + .WithTitle(GetText(strs.reset)) + .WithDescription(GetText(strs.reset_user_confirm)); if (!await PromptUserConfirmAsync(embed)) return; @@ -332,7 +338,9 @@ public partial class Xp : NadekoModule [UserPerm(GuildPerm.Administrator)] public async Task XpReset() { - var embed = new EmbedBuilder().WithTitle(GetText(strs.reset)).WithDescription(GetText(strs.reset_server_confirm)); + var embed = _sender.CreateEmbed() + .WithTitle(GetText(strs.reset)) + .WithDescription(GetText(strs.reset_server_confirm)); if (!await PromptUserConfirmAsync(embed)) return; @@ -383,94 +391,102 @@ public partial class Xp : NadekoModule if (page < 0) return; - var items = type == XpShopInputType.Backgrounds + var allItems = type == XpShopInputType.Backgrounds ? await _service.GetShopBgs() : await _service.GetShopFrames(); - if (items is null) + if (allItems is null) { await Response().Error(strs.xp_shop_disabled).SendAsync(); return; } - if (items.Count == 0) + if (allItems.Count == 0) { await Response().Error(strs.not_found).SendAsync(); return; } - await ctx.SendPaginatedConfirmAsync<(string, XpShopItemType)?>(page, - current => - { - var (key, item) = items.Skip(current).First(); + await Response() + .Paginated() + .Items(allItems) + .PageSize(1) + .CurrentPage(page) + .AddFooter(false) + .Page((items, _) => + { + if (!items.Any()) + return _sender.CreateEmbed() + .WithDescription(GetText(strs.not_found)) + .WithErrorColor(); - var eb = new EmbedBuilder() - .WithOkColor() - .WithTitle(item.Name) - .AddField(GetText(strs.price), - CurrencyHelper.N(item.Price, Culture, _gss.GetCurrencySign()), - true) - .WithImageUrl(string.IsNullOrWhiteSpace(item.Preview) - ? item.Url - : item.Preview); + var (key, item) = items.FirstOrDefault(); - if (!string.IsNullOrWhiteSpace(item.Desc)) - eb.AddField(GetText(strs.desc), item.Desc); + var eb = _sender.CreateEmbed() + .WithOkColor() + .WithTitle(item.Name) + .AddField(GetText(strs.price), + CurrencyHelper.N(item.Price, Culture, _gss.GetCurrencySign()), + true) + .WithImageUrl(string.IsNullOrWhiteSpace(item.Preview) + ? item.Url + : item.Preview); - if (key == "default") - eb.WithDescription(GetText(strs.xpshop_website)); + if (!string.IsNullOrWhiteSpace(item.Desc)) + eb.AddField(GetText(strs.desc), item.Desc); + + if (key == "default") + eb.WithDescription(GetText(strs.xpshop_website)); - var tier = _service.GetXpShopTierRequirement(type); - if (tier != PatronTier.None) - { - eb.WithFooter(GetText(strs.xp_shop_buy_required_tier(tier.ToString()))); - } + var tier = _service.GetXpShopTierRequirement(type); + if (tier != PatronTier.None) + { + eb.WithFooter(GetText(strs.xp_shop_buy_required_tier(tier.ToString()))); + } - return Task.FromResult(eb); - }, - async current => - { - var (key, _) = items.Skip(current).First(); + return eb; + }) + .Interaction(async current => + { + var (key, _) = allItems.Skip(current).First(); - var itemType = type == XpShopInputType.Backgrounds - ? XpShopItemType.Background - : XpShopItemType.Frame; + var itemType = type == XpShopInputType.Backgrounds + ? XpShopItemType.Background + : XpShopItemType.Frame; - var ownedItem = await _service.GetUserItemAsync(ctx.User.Id, itemType, key); - if (ownedItem is not null) - { - var button = new ButtonBuilder(ownedItem.IsUsing - ? GetText(strs.in_use) - : GetText(strs.use), - "xpshop:use", - emote: Emoji.Parse("👐"), - isDisabled: ownedItem.IsUsing); + var ownedItem = await _service.GetUserItemAsync(ctx.User.Id, itemType, key); + if (ownedItem is not null) + { + var button = new ButtonBuilder(ownedItem.IsUsing + ? GetText(strs.in_use) + : GetText(strs.use), + "xpshop:use", + emote: Emoji.Parse("👐"), + isDisabled: ownedItem.IsUsing); - var inter = new SimpleInteraction<(string key, XpShopItemType type)?>( - button, - OnShopUse, - (key, itemType)); + var inter = new SimpleInteraction<(string key, XpShopItemType type)?>( + button, + OnShopUse, + (key, itemType)); - return inter; - } - else - { - var button = new ButtonBuilder(GetText(strs.buy), - "xpshop:buy", - emote: Emoji.Parse("💰")); + return inter; + } + else + { + var button = new ButtonBuilder(GetText(strs.buy), + "xpshop:buy", + emote: Emoji.Parse("💰")); - var inter = new SimpleInteraction<(string key, XpShopItemType type)?>( - button, - OnShopBuy, - (key, itemType)); + var inter = new SimpleInteraction<(string key, XpShopItemType type)?>( + button, + OnShopBuy, + (key, itemType)); - return inter; - } - }, - items.Count, - 1, - addPaginatedFooter: false); + return inter; + } + }) + .SendAsync(); } [Cmd] diff --git a/src/NadekoBot/Modules/Xp/XpRewards.cs b/src/NadekoBot/Modules/Xp/XpRewards.cs index bc0cfc43f..ab06aacdc 100644 --- a/src/NadekoBot/Modules/Xp/XpRewards.cs +++ b/src/NadekoBot/Modules/Xp/XpRewards.cs @@ -16,10 +16,10 @@ public partial class Xp [UserPerm(GuildPerm.Administrator)] public async Task XpRewsReset() { - var promptEmbed = new EmbedBuilder() - .WithPendingColor() - .WithDescription(GetText(strs.xprewsreset_confirm)); - + var promptEmbed = _sender.CreateEmbed() + .WithPendingColor() + .WithDescription(GetText(strs.xprewsreset_confirm)); + var reply = await PromptUserConfirmAsync(promptEmbed); if (!reply) @@ -66,24 +66,25 @@ public partial class Xp .OrderBy(x => x.Key) .ToList(); - return Context.SendPaginatedConfirmAsync(page, - cur => - { - var embed = new EmbedBuilder().WithTitle(GetText(strs.level_up_rewards)).WithOkColor(); + return Response() + .Paginated() + .Items(allRewards) + .PageSize(9) + .CurrentPage(page) + .Page((items, _) => + { + var embed = _sender.CreateEmbed().WithTitle(GetText(strs.level_up_rewards)).WithOkColor(); - var localRewards = allRewards.Skip(cur * 9).Take(9).ToList(); + if (!items.Any()) + return embed.WithDescription(GetText(strs.no_level_up_rewards)); - if (!localRewards.Any()) - return embed.WithDescription(GetText(strs.no_level_up_rewards)); + foreach (var reward in items) + embed.AddField(GetText(strs.level_x(reward.Key)), + string.Join("\n", reward.Select(y => y.Item2))); - foreach (var reward in localRewards) - embed.AddField(GetText(strs.level_x(reward.Key)), - string.Join("\n", reward.Select(y => y.Item2))); - - return embed; - }, - allRewards.Count, - 9); + return embed; + }) + .SendAsync(); } [Cmd] @@ -112,8 +113,10 @@ public partial class Xp await Response().Confirm(strs.xp_role_reward_add_role(level, Format.Bold(role.ToString()))).SendAsync(); else { - await Response().Confirm(strs.xp_role_reward_remove_role(Format.Bold(level.ToString()), - Format.Bold(role.ToString()))).SendAsync(); + await Response() + .Confirm(strs.xp_role_reward_remove_role(Format.Bold(level.ToString()), + Format.Bold(role.ToString()))) + .SendAsync(); } } @@ -129,8 +132,10 @@ public partial class Xp if (amount == 0) await Response().Confirm(strs.cur_reward_cleared(level, _cp.GetCurrencySign())).SendAsync(); else - await Response().Confirm(strs.cur_reward_added(level, - Format.Bold(amount + _cp.GetCurrencySign()))).SendAsync(); + await Response() + .Confirm(strs.cur_reward_added(level, + Format.Bold(amount + _cp.GetCurrencySign()))) + .SendAsync(); } } } \ No newline at end of file diff --git a/src/NadekoBot/_common/CleanupModuleBase.cs b/src/NadekoBot/_common/CleanupModuleBase.cs index b45daa024..1ea038b88 100644 --- a/src/NadekoBot/_common/CleanupModuleBase.cs +++ b/src/NadekoBot/_common/CleanupModuleBase.cs @@ -7,7 +7,7 @@ public abstract class CleanupModuleBase : NadekoModule { try { - var embed = new EmbedBuilder() + var embed = _sender.CreateEmbed() .WithTitle(GetText(strs.sql_confirm_exec)) .WithDescription(name); diff --git a/src/NadekoBot/_common/Interaction/SimpleInteraction.cs b/src/NadekoBot/_common/Interaction/SimpleInteraction.cs index 4a54d1232..1360ef7eb 100644 --- a/src/NadekoBot/_common/Interaction/SimpleInteraction.cs +++ b/src/NadekoBot/_common/Interaction/SimpleInteraction.cs @@ -1,8 +1,20 @@ namespace NadekoBot; -public class SimpleInteraction +public static class InteractionHelpers { - public ButtonBuilder Button { get; } + public static readonly IEmote ArrowLeft = Emote.Parse("<:x:1232256519844790302>"); + public static readonly IEmote ArrowRight = Emote.Parse("<:x:1232256515298295838>"); +} + +public abstract class SimpleInteractionBase +{ + public abstract Task TriggerAsync(SocketMessageComponent smc); + public abstract ButtonBuilder Button { get; } +} + +public class SimpleInteraction : SimpleInteractionBase +{ + public override ButtonBuilder Button { get; } private readonly Func _onClick; private readonly T? _state; @@ -13,7 +25,7 @@ public class SimpleInteraction _state = state; } - public async Task TriggerAsync(SocketMessageComponent smc) + public override async Task TriggerAsync(SocketMessageComponent smc) { await _onClick(smc, _state!); } diff --git a/src/NadekoBot/_common/NadekoModule.cs b/src/NadekoBot/_common/NadekoModule.cs index f36b01164..77a2cd4d3 100644 --- a/src/NadekoBot/_common/NadekoModule.cs +++ b/src/NadekoBot/_common/NadekoModule.cs @@ -19,6 +19,7 @@ public abstract class NadekoModule : ModuleBase public INadekoInteractionService _inter { get; set; } public IReplacementService repSvc { get; set; } public IMessageSenderService _sender { get; set; } + public BotConfigService _bcs { get; set; } protected string prefix => _cmdHandler.GetPrefix(ctx.Guild); @@ -27,7 +28,7 @@ public abstract class NadekoModule : ModuleBase => Context; public ResponseBuilder Response() - => new ResponseBuilder(Strings) + => new ResponseBuilder(Strings, _bcs, (DiscordSocketClient)ctx.Client) .Context(ctx); protected override void BeforeExecute(CommandInfo command) diff --git a/src/NadekoBot/_common/Sender/IMessageSenderService.cs b/src/NadekoBot/_common/Sender/IMessageSenderService.cs index 81ccf8edc..efb1b1452 100644 --- a/src/NadekoBot/_common/Sender/IMessageSenderService.cs +++ b/src/NadekoBot/_common/Sender/IMessageSenderService.cs @@ -7,4 +7,6 @@ public interface IMessageSenderService ResponseBuilder Response(IUser user); ResponseBuilder Response(SocketMessageComponent smc); + + NadekoEmbedBuilder CreateEmbed(); } \ No newline at end of file diff --git a/src/NadekoBot/_common/Sender/MessageChannelExtensions.cs b/src/NadekoBot/_common/Sender/MessageChannelExtensions.cs deleted file mode 100644 index 41467af14..000000000 --- a/src/NadekoBot/_common/Sender/MessageChannelExtensions.cs +++ /dev/null @@ -1,280 +0,0 @@ -namespace NadekoBot.Extensions; - -public static class MessageChannelExtensions -{ - // main overload that all other send methods reduce to - public static Task SendAsync( - this IMessageChannel channel, - string? plainText, - Embed? embed = null, - IReadOnlyCollection? embeds = null, - bool sanitizeAll = false, - MessageComponent? components = null, - IUserMessage? replyTo = null) - { - plainText = sanitizeAll - ? plainText?.SanitizeAllMentions() ?? "" - : plainText?.SanitizeMentions() ?? ""; - - var msgReference = CreateMessageReference(channel, replyTo); - return channel.SendMessageAsync(plainText, - embed: embed, - embeds: embeds is null - ? null - : embeds as Embed[] ?? embeds.ToArray(), - components: components, - messageReference: msgReference); - } - - private static MessageReference? CreateMessageReference(IChannel source, IMessage? replyTo) - { - if (replyTo is null) - return null; - - if (replyTo.Channel.Id != source.Id) - return null; - - return new(replyTo.Id, - replyTo.Channel.Id, - (replyTo.Channel as ITextChannel)?.GuildId, - failIfNotExists: false); - } - - public static async Task SendAsync( - this IMessageChannel channel, - string? plainText, - NadekoInteraction? inter, - Embed? embed = null, - IReadOnlyCollection? embeds = null, - bool sanitizeAll = false, - IUserMessage? replyTo = null) - { - var msg = await channel.SendAsync(plainText, - embed, - embeds, - sanitizeAll, - inter?.CreateComponent(), - replyTo); - - if (inter is not null) - await inter.RunAsync(msg); - - return msg; - } - - public static Task SendAsync( - this IMessageChannel channel, - SmartText text, - bool sanitizeAll = false, - IUserMessage? replyTo = null) - => text switch - { - SmartEmbedText set => channel.SendAsync(set.PlainText, - set.IsValid ? set.GetEmbed().Build() : null, - sanitizeAll: sanitizeAll, - replyTo: replyTo), - SmartPlainText st => channel.SendAsync(st.Text, - default(Embed), - sanitizeAll: sanitizeAll, - replyTo: replyTo), - SmartEmbedTextArray arr => channel.SendAsync(arr.Content, - embeds: arr.GetEmbedBuilders().Map(e => e.Build()), - sanitizeAll: sanitizeAll, - replyTo: replyTo), - _ => throw new ArgumentOutOfRangeException(nameof(text)) - }; - - public static Task EmbedAsync( - this IMessageChannel ch, - EmbedBuilder? embed, - string plainText = "", - IReadOnlyCollection? embeds = null, - NadekoInteraction? inter = null, - IUserMessage? replyTo = null) - => ch.SendAsync(plainText, - inter, - embed: embed?.Build(), - embeds: embeds?.Map(x => x.Build()), - replyTo: replyTo); - - // embed title and optional footer overloads - - 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); - - private const string BUTTON_LEFT = "BUTTON_LEFT"; - private const string BUTTON_RIGHT = "BUTTON_RIGHT"; - - private static readonly IEmote _arrowLeft = Emote.Parse("<:x:1232256519844790302>"); - private static readonly IEmote _arrowRight = Emote.Parse("<:x:1232256515298295838>"); - - public static Task SendPaginatedConfirmAsync( - this ICommandContext ctx, - int currentPage, - Func> pageFunc, - int totalElements, - int itemsPerPage, - bool addPaginatedFooter = true) - => ctx.SendPaginatedConfirmAsync(currentPage, - pageFunc, - default(Func?>>), - totalElements, - itemsPerPage, - addPaginatedFooter); - - public static async Task SendPaginatedConfirmAsync( - this ICommandContext ctx, - int currentPage, - Func> pageFunc, - Func?>>? interFactory, - int totalElements, - int itemsPerPage, - bool addPaginatedFooter = true) - { - var lastPage = (totalElements - 1) / itemsPerPage; - - var embed = await pageFunc(currentPage); - - if (addPaginatedFooter) - embed.AddPaginatedFooter(currentPage, lastPage); - - SimpleInteraction? maybeInter = null; - - async Task GetComponentBuilder() - { - var cb = new ComponentBuilder(); - - cb.WithButton(new ButtonBuilder() - .WithStyle(ButtonStyle.Primary) - .WithCustomId(BUTTON_LEFT) - .WithDisabled(lastPage == 0) - .WithEmote(_arrowLeft) - .WithDisabled(currentPage <= 0)); - - if (interFactory is not null) - { - maybeInter = await interFactory(currentPage); - - if (maybeInter is not null) - cb.WithButton(maybeInter.Button); - } - - cb.WithButton(new ButtonBuilder() - .WithStyle(ButtonStyle.Primary) - .WithCustomId(BUTTON_RIGHT) - .WithDisabled(lastPage == 0 || currentPage >= lastPage) - .WithEmote(_arrowRight)); - - return cb; - } - - async Task UpdatePageAsync(SocketMessageComponent smc) - { - var toSend = await pageFunc(currentPage); - if (addPaginatedFooter) - toSend.AddPaginatedFooter(currentPage, lastPage); - - var component = (await GetComponentBuilder()).Build(); - - await smc.ModifyOriginalResponseAsync(x => - { - x.Embed = toSend.Build(); - x.Components = component; - }); - } - - var component = (await GetComponentBuilder()).Build(); - var msg = await ctx.Channel.SendAsync(null, embed: embed.Build(), components: component, replyTo: ctx.Message); - - async Task OnInteractionAsync(SocketInteraction si) - { - try - { - if (si is not SocketMessageComponent smc) - return; - - if (smc.Message.Id != msg.Id) - return; - - await si.DeferAsync(); - if (smc.User.Id != ctx.User.Id) - return; - - if (smc.Data.CustomId == BUTTON_LEFT) - { - if (currentPage == 0) - return; - - --currentPage; - _ = UpdatePageAsync(smc); - } - else if (smc.Data.CustomId == BUTTON_RIGHT) - { - if (currentPage >= lastPage) - return; - - ++currentPage; - _ = UpdatePageAsync(smc); - } - else if (maybeInter is { } inter && inter.Button.CustomId == smc.Data.CustomId) - { - await inter.TriggerAsync(smc); - _ = UpdatePageAsync(smc); - } - } - catch (Exception ex) - { - Log.Error(ex, "Error in pagination: {ErrorMessage}", ex.Message); - } - } - - if (lastPage == 0 && interFactory is null) - return; - - var client = (DiscordSocketClient)ctx.Client; - - client.InteractionCreated += OnInteractionAsync; - - await Task.Delay(30_000); - - client.InteractionCreated -= OnInteractionAsync; - - await msg.ModifyAsync(mp => mp.Components = new ComponentBuilder().Build()); - } - - private static readonly Emoji _okEmoji = new Emoji("✅"); - private static readonly Emoji _warnEmoji = new Emoji("⚠️"); - private static readonly Emoji _errorEmoji = new Emoji("❌"); - - public static Task ReactAsync(this ICommandContext ctx, MsgType type) - { - var emoji = type switch - { - MsgType.Error => _errorEmoji, - MsgType.Pending => _warnEmoji, - MsgType.Ok => _okEmoji, - _ => throw new ArgumentOutOfRangeException(nameof(type)), - }; - - return ctx.Message.AddReactionAsync(emoji); - } - - public static Task OkAsync(this ICommandContext ctx) - => ctx.ReactAsync(MsgType.Ok); - - public static Task ErrorAsync(this ICommandContext ctx) - => ctx.ReactAsync(MsgType.Error); - - public static Task WarningAsync(this ICommandContext ctx) - => ctx.ReactAsync(MsgType.Pending); -} \ No newline at end of file diff --git a/src/NadekoBot/_common/Sender/MessageSenderService.cs b/src/NadekoBot/_common/Sender/MessageSenderService.cs index fb296af8c..d25a7b1ed 100644 --- a/src/NadekoBot/_common/Sender/MessageSenderService.cs +++ b/src/NadekoBot/_common/Sender/MessageSenderService.cs @@ -1,3 +1,4 @@ +using NadekoBot.Common.Configs; using System.Diagnostics.CodeAnalysis; namespace NadekoBot.Extensions; @@ -5,27 +6,52 @@ namespace NadekoBot.Extensions; public sealed class MessageSenderService : IMessageSenderService, INService { private readonly IBotStrings _bs; + private readonly BotConfigService _bcs; + private readonly DiscordSocketClient _client; - public MessageSenderService(IBotStrings bs) + public MessageSenderService(IBotStrings bs, BotConfigService bcs, DiscordSocketClient client) { _bs = bs; + _bcs = bcs; + _client = client; } public ResponseBuilder Response(IMessageChannel channel) - => new ResponseBuilder(_bs) + => new ResponseBuilder(_bs, _bcs, _client) .Channel(channel); public ResponseBuilder Response(ICommandContext ctx) - => new ResponseBuilder(_bs) + => new ResponseBuilder(_bs, _bcs, _client) .Context(ctx); public ResponseBuilder Response(IUser user) - => new ResponseBuilder(_bs) + => new ResponseBuilder(_bs, _bcs, _client) .User(user); - - // todo fix interactions + public ResponseBuilder Response(SocketMessageComponent smc) - => new ResponseBuilder(_bs) + => new ResponseBuilder(_bs, _bcs, _client) .Channel(smc.Channel); + + public NadekoEmbedBuilder CreateEmbed() + => new NadekoEmbedBuilder(_bcs); +} + +public class NadekoEmbedBuilder : EmbedBuilder +{ + private readonly BotConfig _bc; + + public NadekoEmbedBuilder(BotConfigService bcs) + { + _bc = bcs.Data; + } + + public EmbedBuilder WithOkColor() + => WithColor(_bc.Color.Ok.ToDiscordColor()); + + public EmbedBuilder WithErrorColor() + => WithColor(_bc.Color.Error.ToDiscordColor()); + + public EmbedBuilder WithPendingColor() + => WithColor(_bc.Color.Pending.ToDiscordColor()); } \ No newline at end of file diff --git a/src/NadekoBot/_common/Sender/ResponseBuilder.PaginationSender.cs b/src/NadekoBot/_common/Sender/ResponseBuilder.PaginationSender.cs index df979d2a0..495c88b33 100644 --- a/src/NadekoBot/_common/Sender/ResponseBuilder.PaginationSender.cs +++ b/src/NadekoBot/_common/Sender/ResponseBuilder.PaginationSender.cs @@ -7,24 +7,20 @@ public partial class ResponseBuilder private const string BUTTON_LEFT = "BUTTON_LEFT"; private const string BUTTON_RIGHT = "BUTTON_RIGHT"; - private static readonly IEmote _arrowLeft = Emote.Parse("<:x:1232256519844790302>"); - private static readonly IEmote _arrowRight = Emote.Parse("<:x:1232256515298295838>"); - private readonly SourcedPaginatedResponseBuilder _paginationBuilder; - private readonly ResponseBuilder builder; - private readonly DiscordSocketClient client; + private readonly ResponseBuilder _builder; + private readonly DiscordSocketClient _client; private int currentPage; public PaginationSender( SourcedPaginatedResponseBuilder paginationBuilder, - ResponseBuilder builder - ) + ResponseBuilder builder) { - this._paginationBuilder = paginationBuilder; - this.builder = builder; + _paginationBuilder = paginationBuilder; + _builder = builder; - client = (DiscordSocketClient)builder.ctx.Client; - currentPage = 0; + _client = builder.Client; + currentPage = paginationBuilder.InitialPage; } public async Task SendAsync(bool ephemeral = false) @@ -38,7 +34,7 @@ public partial class ResponseBuilder if (_paginationBuilder.AddPaginatedFooter) embed.AddPaginatedFooter(currentPage, lastPage); - SimpleInteraction? maybeInter = null; + SimpleInteractionBase? maybeInter = null; async Task GetComponentBuilder() { @@ -48,22 +44,22 @@ public partial class ResponseBuilder .WithStyle(ButtonStyle.Primary) .WithCustomId(BUTTON_LEFT) .WithDisabled(lastPage == 0) - .WithEmote(_arrowLeft) + .WithEmote(InteractionHelpers.ArrowLeft) .WithDisabled(currentPage <= 0)); - // todo - // if (interFactory is not null) - // { - // maybeInter = await interFactory(currentPage); - // - // if (maybeInter is not null) - // cb.WithButton(maybeInter.Button); - // } + + if (_paginationBuilder.InteractionFunc is not null) + { + maybeInter = await _paginationBuilder.InteractionFunc(currentPage); + + if (maybeInter is not null) + cb.WithButton(maybeInter.Button); + } cb.WithButton(new ButtonBuilder() .WithStyle(ButtonStyle.Primary) .WithCustomId(BUTTON_RIGHT) .WithDisabled(lastPage == 0 || currentPage >= lastPage) - .WithEmote(_arrowRight)); + .WithEmote(InteractionHelpers.ArrowRight)); return cb; } @@ -84,7 +80,7 @@ public partial class ResponseBuilder }); } - var model = builder.Build(ephemeral); + var model = await _builder.BuildAsync(ephemeral); var component = (await GetComponentBuilder()).Build(); var msg = await model.TargetChannel @@ -104,7 +100,8 @@ public partial class ResponseBuilder return; await si.DeferAsync(); - if (smc.User.Id != model.User.Id) + + if (smc.User.Id != model.User?.Id) return; if (smc.Data.CustomId == BUTTON_LEFT) @@ -134,20 +131,15 @@ public partial class ResponseBuilder Log.Error(ex, "Error in pagination: {ErrorMessage}", ex.Message); } } - // todo re-add - // if (lastPage == 0 && interFactory is null) - // return; - if (lastPage == 0) + if (lastPage == 0 && _paginationBuilder.InteractionFunc is null) return; - var client = this.client; - - client.InteractionCreated += OnInteractionAsync; + _client.InteractionCreated += OnInteractionAsync; await Task.Delay(30_000); - client.InteractionCreated -= OnInteractionAsync; + _client.InteractionCreated -= OnInteractionAsync; await msg.ModifyAsync(mp => mp.Components = new ComponentBuilder().Build()); } diff --git a/src/NadekoBot/_common/Sender/ResponseBuilder.cs b/src/NadekoBot/_common/Sender/ResponseBuilder.cs index a3bb5aed4..ef37fcc93 100644 --- a/src/NadekoBot/_common/Sender/ResponseBuilder.cs +++ b/src/NadekoBot/_common/Sender/ResponseBuilder.cs @@ -1,29 +1,39 @@ -namespace NadekoBot.Extensions; +using NadekoBot.Common.Configs; +using NadekoBot.Db.Models; + +namespace NadekoBot.Extensions; public sealed partial class ResponseBuilder { - private ICommandContext? ctx = null; - private IMessageChannel? channel = null; - private Embed? embed = null; - private string? plainText = null; - private IReadOnlyCollection? embeds = null; - private IUserMessage? msg = null; - private IUser? user = null; + private ICommandContext? ctx; + private IMessageChannel? channel; + private string? plainText; + private IReadOnlyCollection? embeds; + private IUserMessage? msg; + private IUser? user; private bool sanitizeMentions = true; private LocStr? locTxt; private object[] locParams = []; private bool shouldReply = true; private readonly IBotStrings _bs; - private EmbedBuilder? embedBuilder = null; + private readonly BotConfigService _bcs; + private EmbedBuilder? embedBuilder; private NadekoInteraction? inter; - private Stream? fileStream = null; - private string? fileName = null; + private Stream? fileStream; + private string? fileName; + private EmbedColor color = EmbedColor.Ok; + private LocStr? embedLocDesc; - public ResponseBuilder(IBotStrings bs) + public DiscordSocketClient Client { get; set; } + + public ResponseBuilder(IBotStrings bs, BotConfigService bcs, DiscordSocketClient client) { _bs = bs; + _bcs = bcs; + Client = client; } + private MessageReference? CreateMessageReference(IMessageChannel targetChannel) { if (!shouldReply) @@ -44,72 +54,116 @@ public sealed partial class ResponseBuilder failIfNotExists: false); } - public ResponseMessageModel Build(bool ephemeral = false) + public async Task BuildAsync(bool ephemeral) { - // todo use ephemeral in interactions - var targetChannel = InternalResolveChannel() ?? throw new ArgumentNullException(nameof(channel)); + var targetChannel = await InternalResolveChannel() ?? throw new ArgumentNullException(nameof(channel)); var msgReference = CreateMessageReference(targetChannel); - var txt = GetText(locTxt); - // todo check message sanitization + var txt = GetText(locTxt, targetChannel); + + if (embedLocDesc is LocStr ls) + { + InternalCreateEmbed(null, GetText(ls, targetChannel)); + } + + if (embedBuilder is not null) + PaintEmbedInternal(embedBuilder); + + var finalEmbed = embedBuilder?.Build(); + var buildModel = new ResponseMessageModel() { TargetChannel = targetChannel, MessageReference = msgReference, Text = txt, - User = ctx?.User, - Embed = embed ?? embedBuilder?.Build(), + User = user ?? ctx?.User, + Embed = finalEmbed, Embeds = embeds?.Map(x => x.Build()), - SanitizeMentions = sanitizeMentions ? new(AllowedMentionTypes.Users) : AllowedMentions.All + SanitizeMentions = sanitizeMentions ? new(AllowedMentionTypes.Users) : AllowedMentions.All, + Ephemeral = ephemeral, + Interaction = inter }; return buildModel; } - public Task SendAsync(bool ephemeral = false) + public async Task SendAsync(bool ephemeral = false) { - var model = Build(ephemeral); - return SendAsync(model); + var model = await BuildAsync(ephemeral); + var sentMsg = await SendAsync(model); + + + return sentMsg; } public async Task SendAsync(ResponseMessageModel model) { - if (this.fileStream is Stream stream) - return await model.TargetChannel.SendFileAsync(stream, + IUserMessage sentMsg; + if (fileStream is Stream stream) + { + sentMsg = await model.TargetChannel.SendFileAsync(stream, filename: fileName, model.Text, embed: model.Embed, - components: null, + components: inter?.CreateComponent(), allowedMentions: model.SanitizeMentions, messageReference: model.MessageReference); + } + else + { + sentMsg = await model.TargetChannel.SendMessageAsync( + model.Text, + embed: model.Embed, + embeds: model.Embeds, + components: inter?.CreateComponent(), + allowedMentions: model.SanitizeMentions, + messageReference: model.MessageReference); + } - return await model.TargetChannel.SendMessageAsync( - model.Text, - embed: model.Embed, - embeds: model.Embeds, - components: null, - allowedMentions: model.SanitizeMentions, - messageReference: model.MessageReference); + if (model.Interaction is not null) + { + await model.Interaction.RunAsync(sentMsg); + } + + return sentMsg; } + private EmbedBuilder PaintEmbedInternal(EmbedBuilder eb) + => color switch + { + EmbedColor.Ok => eb.WithOkColor(), + EmbedColor.Pending => eb.WithPendingColor(), + EmbedColor.Error => eb.WithErrorColor(), + _ => throw new NotSupportedException() + }; + private ulong? InternalResolveGuildId(IMessageChannel? targetChannel) => ctx?.Guild?.Id ?? (targetChannel as ITextChannel)?.GuildId; - // todo not good, has to go to the user - private IMessageChannel? InternalResolveChannel() - => channel ?? ctx?.Channel ?? msg?.Channel; - - private string? GetText(LocStr? locStr) + private async Task InternalResolveChannel() + { + if (user is not null) + { + var ch = await user.CreateDMChannelAsync(); + + if (ch is not null) + { + return ch; + } + } + + return channel ?? ctx?.Channel ?? msg?.Channel; + } + + private string? GetText(LocStr? locStr, IMessageChannel targetChannel) { - var targetChannel = InternalResolveChannel(); var guildId = InternalResolveGuildId(targetChannel); return locStr is LocStr ls ? _bs.GetText(ls.Key, guildId, locParams) : plainText; } - private string GetText(LocStr locStr) + private string GetText(LocStr locStr, IMessageChannel targetChannel) { - var targetChannel = InternalResolveChannel(); var guildId = InternalResolveGuildId(targetChannel); return _bs.GetText(locStr.Key, guildId, locStr.Params); } @@ -125,91 +179,108 @@ public sealed partial class ResponseBuilder if (text is SmartPlainText spt) plainText = spt.Text; else if (text is SmartEmbedText set) - embed = set.GetEmbed().Build(); + embedBuilder = set.GetEmbed(); else if (text is SmartEmbedTextArray ser) embeds = ser.GetEmbedBuilders(); return this; } - private ResponseBuilder InternalColoredText(string text, EmbedColor color) - { - embed = new EmbedBuilder() - .WithColor(color) - .WithDescription(text) - .Build(); - - return this; - } - - private EmbedBuilder CreateEmbedInternal( + private void InternalCreateEmbed( string? title, - string? text, - string? url, - string? footer = null) - { - var embed = new EmbedBuilder() - .WithTitle(title) - .WithDescription(text); - - if (!string.IsNullOrWhiteSpace(url)) - embed = embed.WithUrl(url); - - if (!string.IsNullOrWhiteSpace(footer)) - embed = embed.WithFooter(footer); - - return embed; - } - - private EmbedBuilder PaintEmbedInternal(EmbedBuilder eb, EmbedColor color) - => color switch - { - EmbedColor.Ok => eb.WithOkColor(), - EmbedColor.Pending => eb.WithPendingColor(), - EmbedColor.Error => eb.WithErrorColor(), - }; - - public ResponseBuilder Error( - string? title, - string? text, + string text, string? url = null, string? footer = null) { - var eb = CreateEmbedInternal(title, text, url, footer); - embed = PaintEmbedInternal(eb, EmbedColor.Error).Build(); - return this; - } + var eb = new NadekoEmbedBuilder(_bcs) + .WithDescription(text); + if (!string.IsNullOrWhiteSpace(title)) + eb.WithTitle(title); + + if (!string.IsNullOrWhiteSpace(url)) + eb = eb.WithUrl(url); + + if (!string.IsNullOrWhiteSpace(footer)) + eb = eb.WithFooter(footer); + + embedBuilder = eb; + } public ResponseBuilder Confirm( string? title, - string? text, + string text, string? url = null, string? footer = null) { - var eb = CreateEmbedInternal(title, text, url, footer); - embed = PaintEmbedInternal(eb, EmbedColor.Error).Build(); + InternalCreateEmbed(title, text, url, footer); + color = EmbedColor.Ok; + return this; + } + + public ResponseBuilder Error( + string? title, + string text, + string? url = null, + string? footer = null) + { + InternalCreateEmbed(title, text, url, footer); + color = EmbedColor.Error; + return this; + } + + public ResponseBuilder Pending( + string? title, + string text, + string? url = null, + string? footer = null) + { + InternalCreateEmbed(title, text, url, footer); + color = EmbedColor.Pending; return this; } public ResponseBuilder Confirm(string text) - => InternalColoredText(text, EmbedColor.Ok); + { + InternalCreateEmbed(null, text); + color = EmbedColor.Ok; + return this; + } public ResponseBuilder Confirm(LocStr str) - => Confirm(GetText(str)); + { + embedLocDesc = str; + color = EmbedColor.Ok; + return this; + } public ResponseBuilder Pending(string text) - => InternalColoredText(text, EmbedColor.Ok); + { + InternalCreateEmbed(null, text); + color = EmbedColor.Pending; + return this; + } public ResponseBuilder Pending(LocStr str) - => Pending(GetText(str)); + { + embedLocDesc = str; + color = EmbedColor.Pending; + return this; + } public ResponseBuilder Error(string text) - => InternalColoredText(text, EmbedColor.Error); + { + InternalCreateEmbed(null, text); + color = EmbedColor.Error; + return this; + } public ResponseBuilder Error(LocStr str) - => Error(GetText(str)); - + { + embedLocDesc = str; + color = EmbedColor.Error; + return this; + } public ResponseBuilder UserBasedMentions() { @@ -220,17 +291,15 @@ public sealed partial class ResponseBuilder private IUser? InternalResolveUser() => ctx?.User ?? user ?? msg?.Author; - // todo embed colors - public ResponseBuilder Embed(EmbedBuilder eb) { embedBuilder = eb; return this; } - public ResponseBuilder Channel(IMessageChannel channel) + public ResponseBuilder Channel(IMessageChannel ch) { - this.channel = channel; + channel = ch; return this; } @@ -240,21 +309,21 @@ public sealed partial class ResponseBuilder return this; } - public ResponseBuilder Context(ICommandContext ctx) + public ResponseBuilder Context(ICommandContext context) { - this.ctx = ctx; + ctx = context; return this; } - public ResponseBuilder Message(IUserMessage msg) + public ResponseBuilder Message(IUserMessage message) { - this.msg = msg; + msg = message; return this; } - public ResponseBuilder User(IUser user) + public ResponseBuilder User(IUser usr) { - this.user = user; + user = usr; return this; } @@ -266,7 +335,6 @@ public sealed partial class ResponseBuilder public ResponseBuilder Interaction(NadekoInteraction? interaction) { - // todo implement inter = interaction; return this; } @@ -277,10 +345,10 @@ public sealed partial class ResponseBuilder return this; } - public ResponseBuilder FileName(Stream fileStream, string fileName) + public ResponseBuilder File(Stream stream, string name) { - this.fileStream = fileStream; - this.fileName = fileName; + fileStream = stream; + fileName = name; return this; } @@ -300,27 +368,51 @@ public class PaginatedResponseBuilder public SourcedPaginatedResponseBuilder Items(IReadOnlyCollection items) => new SourcedPaginatedResponseBuilder(_builder) .Items(items); + + public SourcedPaginatedResponseBuilder PageItems(Func>> items) + => new SourcedPaginatedResponseBuilder(_builder) + .PageItems(items); } public sealed class SourcedPaginatedResponseBuilder : PaginatedResponseBuilder { private IReadOnlyCollection? items; - public Func, int, Task> PageFunc { get; private set; } - public Func>> ItemsFunc { get; set; } + + public Func, int, Task> PageFunc { get; private set; } = static delegate + { + return Task.FromResult(new()); + }; + + public Func>> ItemsFunc { get; set; } = static delegate + { + return Task.FromResult(Enumerable.Empty()); + }; + + public Func>? InteractionFunc { get; private set; } + public int TotalElements { get; private set; } = 1; public int ItemsPerPage { get; private set; } = 9; public bool AddPaginatedFooter { get; private set; } = true; public bool IsEphemeral { get; private set; } + public int InitialPage { get; set; } + public SourcedPaginatedResponseBuilder(ResponseBuilder builder) : base(builder) { } - public SourcedPaginatedResponseBuilder Items(IReadOnlyCollection items) + public SourcedPaginatedResponseBuilder Items(IReadOnlyCollection col) { - this.items = items; - ItemsFunc = (i) => Task.FromResult(this.items.Skip(i * ItemsPerPage).Take(ItemsPerPage)); + items = col; + TotalElements = col.Count; + ItemsFunc = (i) => Task.FromResult(items.Skip(i * ItemsPerPage).Take(ItemsPerPage)); + return this; + } + + public SourcedPaginatedResponseBuilder PageItems(Func>> func) + { + ItemsFunc = func; return this; } @@ -337,24 +429,22 @@ public sealed class SourcedPaginatedResponseBuilder : PaginatedResponseBuilde return this; } - // todo use it - public int InitialPage { get; set; } public SourcedPaginatedResponseBuilder Page(Func, int, EmbedBuilder> pageFunc) { - this.PageFunc = (xs, x) => Task.FromResult(pageFunc(xs, x)); + PageFunc = (xs, x) => Task.FromResult(pageFunc(xs, x)); return this; } public SourcedPaginatedResponseBuilder Page(Func, int, Task> pageFunc) { - this.PageFunc = pageFunc; + PageFunc = pageFunc; return this; } - public SourcedPaginatedResponseBuilder AddFooter() + public SourcedPaginatedResponseBuilder AddFooter(bool addFooter = true) { - AddPaginatedFooter = true; + AddPaginatedFooter = addFooter; return this; } @@ -373,4 +463,10 @@ public sealed class SourcedPaginatedResponseBuilder : PaginatedResponseBuilde return paginationSender.SendAsync(IsEphemeral); } + + public SourcedPaginatedResponseBuilder Interaction(Func> func) + { + InteractionFunc = async (i) => await func(i); + return this; + } } \ No newline at end of file diff --git a/src/NadekoBot/_common/Sender/ResponseBuilderExtensions.cs b/src/NadekoBot/_common/Sender/ResponseBuilderExtensions.cs index f49a863c3..a0b896d3a 100644 --- a/src/NadekoBot/_common/Sender/ResponseBuilderExtensions.cs +++ b/src/NadekoBot/_common/Sender/ResponseBuilderExtensions.cs @@ -2,17 +2,27 @@ public static class ResponseBuilderExtensions { - // todo delete this - - public static EmbedBuilder WithColor(this EmbedBuilder eb, EmbedColor color) - => eb; - public static EmbedBuilder WithPendingColor(this EmbedBuilder eb) - => eb.WithColor(EmbedColor.Error); + { + if (eb is NadekoEmbedBuilder neb) + return neb.WithPendingColor(); + + return eb; + } public static EmbedBuilder WithOkColor(this EmbedBuilder eb) - => eb.WithColor(EmbedColor.Ok); + { + if (eb is NadekoEmbedBuilder neb) + return neb.WithOkColor(); + + return eb; + } public static EmbedBuilder WithErrorColor(this EmbedBuilder eb) - => eb.WithColor(EmbedColor.Error); + { + if (eb is NadekoEmbedBuilder neb) + return neb.WithErrorColor(); + + return eb; + } } \ No newline at end of file diff --git a/src/NadekoBot/_common/Sender/ResponseMessageModel.cs b/src/NadekoBot/_common/Sender/ResponseMessageModel.cs index cf34c9cbc..592b18e9d 100644 --- a/src/NadekoBot/_common/Sender/ResponseMessageModel.cs +++ b/src/NadekoBot/_common/Sender/ResponseMessageModel.cs @@ -1,10 +1,12 @@ public class ResponseMessageModel { - public IMessageChannel TargetChannel { get; set; } - public MessageReference MessageReference { get; set; } - public string Text { get; set; } - public Embed Embed { get; set; } - public Embed[] Embeds { get; set; } - public AllowedMentions SanitizeMentions { get; set; } - public IUser User { get; set; } + public required IMessageChannel TargetChannel { get; set; } + public MessageReference? MessageReference { get; set; } + public string? Text { get; set; } + public Embed? Embed { get; set; } + public Embed[]? Embeds { get; set; } + public required AllowedMentions SanitizeMentions { get; set; } + public IUser? User { get; set; } + public bool Ephemeral { get; set; } + public NadekoInteraction? Interaction { get; set; } } \ No newline at end of file diff --git a/src/NadekoBot/_common/Services/IEmbedBuilderService.cs b/src/NadekoBot/_common/Services/IEmbedBuilderService.cs deleted file mode 100644 index 19b6a7f85..000000000 --- a/src/NadekoBot/_common/Services/IEmbedBuilderService.cs +++ /dev/null @@ -1,17 +0,0 @@ -#nullable disable - -namespace NadekoBot.Services; - -// todo remove -public sealed class DiscordEmbedBuilderWrapper -{ - // public EmbedBuilder WithColor(EmbedColor color) - // => color switch - // { - // EmbedColor.Ok => Wrap(embed.WithColor(_botConfig.Color.Ok.ToDiscordColor())), - // EmbedColor.Pending => Wrap(embed.WithColor(_botConfig.Color.Pending.ToDiscordColor())), - // EmbedColor.Error => Wrap(embed.WithColor(_botConfig.Color.Error.ToDiscordColor())), - // _ => throw new ArgumentOutOfRangeException(nameof(color), "Unsupported EmbedColor type") - // }; - -} \ No newline at end of file diff --git a/src/NadekoBot/_common/Services/Impl/CommandsUtilityService.cs b/src/NadekoBot/_common/Services/Impl/CommandsUtilityService.cs index 8229eb960..42de90f41 100644 --- a/src/NadekoBot/_common/Services/Impl/CommandsUtilityService.cs +++ b/src/NadekoBot/_common/Services/Impl/CommandsUtilityService.cs @@ -39,7 +39,7 @@ public sealed class CommandsUtilityService : ICommandsUtilityService, INService var culture = _loc.GetCultureInfo(guild); - var em = new EmbedBuilder() + var em = _sender.CreateEmbed() .AddField(str, $"{com.RealSummary(_strings, _medusae, culture, prefix)}", true); _dpos.TryGetOverrides(guild?.Id ?? 0, com.Name, out var overrides); diff --git a/src/NadekoBot/_common/_Extensions/CommandContextExtensions.cs b/src/NadekoBot/_common/_Extensions/CommandContextExtensions.cs new file mode 100644 index 000000000..5db6ae628 --- /dev/null +++ b/src/NadekoBot/_common/_Extensions/CommandContextExtensions.cs @@ -0,0 +1,30 @@ +namespace NadekoBot.Extensions; + +public static class CommandContextExtensions +{ + private static readonly Emoji _okEmoji = new Emoji("✅"); + private static readonly Emoji _warnEmoji = new Emoji("⚠️"); + private static readonly Emoji _errorEmoji = new Emoji("❌"); + + public static Task ReactAsync(this ICommandContext ctx, MsgType type) + { + var emoji = type switch + { + MsgType.Error => _errorEmoji, + MsgType.Pending => _warnEmoji, + MsgType.Ok => _okEmoji, + _ => throw new ArgumentOutOfRangeException(nameof(type)), + }; + + return ctx.Message.AddReactionAsync(emoji); + } + + public static Task OkAsync(this ICommandContext ctx) + => ctx.ReactAsync(MsgType.Ok); + + public static Task ErrorAsync(this ICommandContext ctx) + => ctx.ReactAsync(MsgType.Error); + + public static Task WarningAsync(this ICommandContext ctx) + => ctx.ReactAsync(MsgType.Pending); +} \ No newline at end of file diff --git a/src/NadekoBot/_common/_Extensions/Extensions.cs b/src/NadekoBot/_common/_Extensions/Extensions.cs index a0f7fd2cd..2d3dc1e04 100644 --- a/src/NadekoBot/_common/_Extensions/Extensions.cs +++ b/src/NadekoBot/_common/_Extensions/Extensions.cs @@ -9,18 +9,25 @@ namespace NadekoBot.Extensions; public static class Extensions { + private static readonly Regex _urlRegex = + new(@"^(https?|ftp)://(?[^\s/$.?#].[^\s]*)$", RegexOptions.Compiled); + + /// + /// Converts to + /// + /// The to convert. + /// The . public static DateOnly ToDateOnly(this DateTime dateTime) => DateOnly.FromDateTime(dateTime); + /// + /// Determines if is before today + /// + /// The to check. + /// True if is before today. public static bool IsBeforeToday(this DateTime date) => date < DateTime.UtcNow.Date; - private static readonly Regex _urlRegex = - new(@"^(https?|ftp)://(?[^\s/$.?#].[^\s]*)$", RegexOptions.Compiled); - - // public static EmbedBuilder WithAuthor(this EmbedBuilder eb, IUser author) - // => eb.WithAuthor(author.ToString()!, author.RealAvatarUrl().ToString()); - public static Task EditAsync(this IUserMessage msg, SmartText text) => text switch { diff --git a/src/NadekoBot/_common/_Extensions/SocketMessageComponentExtensions.cs b/src/NadekoBot/_common/_Extensions/SocketMessageComponentExtensions.cs index 6ea0d99a1..da53513a7 100644 --- a/src/NadekoBot/_common/_Extensions/SocketMessageComponentExtensions.cs +++ b/src/NadekoBot/_common/_Extensions/SocketMessageComponentExtensions.cs @@ -1,72 +1,15 @@ - -namespace NadekoBot.Extensions; +namespace NadekoBot.Extensions; public static class SocketMessageComponentExtensions { - public static Task RespondAsync( - this SocketMessageComponent smc, - string? plainText, - Embed? embed = null, - IReadOnlyCollection? embeds = null, - bool sanitizeAll = false, - MessageComponent? components = null, - bool ephemeral = true) - { - plainText = sanitizeAll - ? plainText?.SanitizeAllMentions() ?? "" - : plainText?.SanitizeMentions() ?? ""; - - return smc.RespondAsync(plainText, - embed: embed, - embeds: embeds is null - ? null - : embeds as Embed[] ?? embeds.ToArray(), - components: components, - ephemeral: ephemeral); - } - - public static Task RespondAsync( - this SocketMessageComponent smc, - SmartText text, - bool sanitizeAll = false, - bool ephemeral = true) - => text switch - { - SmartEmbedText set => smc.RespondAsync(set.PlainText, - set.IsValid ? set.GetEmbed().Build() : null, - sanitizeAll: sanitizeAll, - ephemeral: ephemeral), - SmartPlainText st => smc.RespondAsync(st.Text, - default(Embed), - sanitizeAll: sanitizeAll, - ephemeral: ephemeral), - SmartEmbedTextArray arr => smc.RespondAsync(arr.Content, - embeds: arr.GetEmbedBuilders().Map(e => e.Build()), - ephemeral: ephemeral), - _ => throw new ArgumentOutOfRangeException(nameof(text)) - }; - - public static Task EmbedAsync( - this SocketMessageComponent smc, - EmbedBuilder? embed, - string plainText = "", - IReadOnlyCollection? embeds = null, - NadekoInteraction? inter = null, - bool ephemeral = false) - => smc.RespondAsync(plainText, - embed: embed?.Build(), - embeds: embeds?.Map(x => x.Build()), - ephemeral: ephemeral); - - public static Task RespondAsync( + public static async Task RespondAsync( this SocketMessageComponent ch, IMessageSenderService sender, string text, MsgType type, - bool ephemeral = false, - NadekoInteraction? inter = null) + bool ephemeral = false) { - var embed = new EmbedBuilder().WithDescription(text); + var embed = sender.CreateEmbed().WithDescription(text); embed = (type switch { @@ -76,12 +19,9 @@ public static class SocketMessageComponentExtensions _ => throw new ArgumentOutOfRangeException(nameof(type)) }); - return sender.Response(ch) - .Embed(embed) - .Interaction(inter) - .SendAsync(ephemeral: ephemeral); + await ch.RespondAsync(embeds: [embed.Build()], ephemeral: ephemeral); } - + // embed title and optional footer overloads public static Task RespondConfirmAsync(