Files
BotPages/BotPages.Core/Messaging/MessageBuilder.cs
FrigaT 0ed47b2b90
All checks were successful
CI / build-test (push) Successful in 38s
Release / pack-and-publish (release) Successful in 43s
Исправлен возврат messageId при отправке сообщения
2026-01-13 21:22:06 +03:00

206 lines
6.9 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using BotPages.Core.Abstractions;
namespace BotPages.Core.Messaging;
/// <summary>
/// Fluentбилдер для отправки сообщений (текст, кнопки, файлы, альбомы, прогресс).
/// Поддерживает указание адаптер-специфичных опций через `WithAdapterOption`.
/// </summary>
public sealed class MessageBuilder
{
private readonly PageContext _ctx;
private string? _text = null;
private MessageFormat _format = MessageFormat.Plain;
private readonly List<List<InlineButton>> _inline = new();
private readonly List<List<ReplyButton>> _reply = new();
private readonly List<(FileDescriptor file, string? caption, MessageFormat? captionFormat)> _files = new();
private readonly List<(FileDescriptor file, string? caption, MessageFormat? captionFormat)> _album = new();
private bool _disableReplyKeyboard;
private AdapterOptionsBag? _adapterOptions = null;
private string? _chatId = null;
/// <summary>Создать билдер сообщений.</summary>
public MessageBuilder(PageContext ctx) => _ctx = ctx;
/// <summary>
/// Установить опции для конкретного адаптера. Ключ адаптера определяется адаптером (напр., "telegram").
/// </summary>
public MessageBuilder WithAdapterOption<T>(string adapterType, T options)
{
if (_adapterOptions is null) _adapterOptions = new AdapterOptionsBag();
_adapterOptions.Set(adapterType, options);
return this;
}
/// <summary>ID чата куда отрпавить сообщение.</summary>
public MessageBuilder ChatId(string chatId)
{
_chatId = chatId;
return this;
}
/// <summary>Текст сообщения.</summary>
public MessageBuilder Text(string text, MessageFormat format = MessageFormat.Plain)
{
_text = text;
_format = format;
return this;
}
/// <summary>Добавить inlineкнопку.</summary>
public MessageBuilder Inline(string label, string value)
{
_inline.Add(new() { new(label, value) });
return this;
}
/// <summary>Добавить inlineкнопку.</summary>
public MessageBuilder Inline(InlineButton button)
{
_inline.Add(new() { button });
return this;
}
/// <summary>Добавить inlineкнопку.</summary>
public MessageBuilder Inline(params InlineButton[] buttons)
{
_inline.Add(buttons.ToList());
return this;
}
/// <summary>Добавить строку inlineкнопок.</summary>
public MessageBuilder Inline(IEnumerable<InlineButton> row)
{
_inline.Add(row.ToList());
return this;
}
/// <summary>Добавить строки inlineкнопок.</summary>
public MessageBuilder Inline(IEnumerable<IEnumerable<InlineButton>> row)
{
_inline.AddRange(row.Select(t => t.ToList()).ToList());
return this;
}
/// <summary>
/// Отключение Reply клавиатуры.
/// </summary>
public MessageBuilder DisableReply()
{
_disableReplyKeyboard = true;
return this;
}
/// <summary>Добавить replyкнопку.</summary>
public MessageBuilder Reply(params ReplyButton[] label)
{
_disableReplyKeyboard = false;
_reply.Add(label.ToList());
return this;
}
/// <summary>Добавить строку replyкнопок.</summary>
public MessageBuilder Reply(IEnumerable<ReplyButton> row)
{
_disableReplyKeyboard = false;
_reply.Add(row.ToList());
return this;
}
/// <summary>Добавить строки replyкнопок.</summary>
public MessageBuilder Reply(IEnumerable<IEnumerable<ReplyButton>> row)
{
_disableReplyKeyboard = false;
_reply.AddRange(row.Select(t => t.ToList()).ToList());
return this;
}
/// <summary>Добавить файл для отправки.</summary>
public MessageBuilder File(FileDescriptor file, string? caption = null, MessageFormat? captionFormat = null)
{
_files.Add((file, caption, captionFormat));
return this;
}
/// <summary>Добавить файл в альбом.</summary>
public MessageBuilder Album(FileDescriptor file, string? caption = null, MessageFormat? captionFormat = null)
{
_album.Add((file, caption, captionFormat));
return this;
}
/// <summary>Удалить сообщение.</summary>
public async Task DeleteAsync(string messageId, CancellationToken ct = default)
{
await _ctx.DeleteAsync(this._chatId ?? _ctx.Update.Chat.Id, messageId, ct);
}
/// <summary>Отправить собранное сообщение.</summary>
public async Task<string?> SendAsync(CancellationToken ct = default)
=> await SendAsync(string.Empty, ct);
/// <summary>Редактировать сообщение.</summary>
public async Task<string?> SendAsync(string messageId, CancellationToken ct = default)
{
string? outMessageId = null;
List<List<ReplyButton>>? reply = null;
if (_disableReplyKeyboard) reply = new();
else if (_reply.Any()) reply = _reply;
// Текст
if (!string.IsNullOrWhiteSpace(_text))
{
var req = new SendRequest
{
ChatId = _chatId ?? _ctx.Update.Chat.Id,
Text = _text,
TextFormat = _format,
Inline = _inline,
Reply = reply,
MessageId = string.IsNullOrWhiteSpace(messageId) ? null : messageId,
AdapterOptions = _adapterOptions
};
outMessageId = await _ctx.SendAsync(req, ct);
}
// Файлы
foreach (var (file, caption, captionFormat) in _files)
{
var req = new SendRequest
{
ChatId = _chatId ?? _ctx.Update.Chat.Id,
File = file,
Caption = caption,
CaptionFormat = captionFormat,
Inline = _inline,
Reply = reply,
AdapterOptions = _adapterOptions
};
var res = await _ctx.SendAsync(req, ct);
// сохранить первый возвращённый id сообщения
if (outMessageId is null && res is not null) outMessageId = res;
}
// Альбом
if (_album.Count > 0)
{
var builder = _ctx.Albums;
foreach (var (file, caption, captionFormat) in _album)
builder.Add(file, caption, captionFormat);
await builder.SendAsync(ct);
}
_text = null;
_files.Clear();
_album.Clear();
_adapterOptions = null;
_chatId = null;
return outMessageId;
}
}