Files
nadekobot/src/NadekoBot/_Extensions/IMessageChannelExtensions.cs
2021-12-29 06:07:16 +01:00

211 lines
7.6 KiB
C#

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