From b4dd14ed2b7242c76ef319b2770991fd139aa9c2 Mon Sep 17 00:00:00 2001 From: Slavasil Date: Sun, 20 Apr 2025 18:42:08 +0300 Subject: [PATCH] complete the basic dialog flow --- SimpleTGBot/DialogData.cs | 1 + SimpleTGBot/Interactions.cs | 10 ++++ SimpleTGBot/TelegramBot.cs | 112 +++++++++++++++++++++++++++++++++++- 3 files changed, 121 insertions(+), 2 deletions(-) diff --git a/SimpleTGBot/DialogData.cs b/SimpleTGBot/DialogData.cs index ecdf46f..cbede51 100644 --- a/SimpleTGBot/DialogData.cs +++ b/SimpleTGBot/DialogData.cs @@ -4,6 +4,7 @@ internal class DialogData { public DialogState state; public string? inputPictureFilename; + public string? inputTitle; } enum DialogState diff --git a/SimpleTGBot/Interactions.cs b/SimpleTGBot/Interactions.cs index f4d3e90..103d5f0 100644 --- a/SimpleTGBot/Interactions.cs +++ b/SimpleTGBot/Interactions.cs @@ -7,6 +7,10 @@ internal static class Interactions public const string awaitingPictureMessage = "Привет. Я - бот, который умеет делать демотиваторы. Присылай картинку, а я скажу, что делать дальше. Или можешь нажать на кнопку в меню."; public const string sayHelloMessage = "Напиши \"привет\" или нажми на кнопку в меню, чтобы начать."; public const string sendPictureOrQuitMessage = "Пришли мне картинку для демотиватора, чтобы продолжить. Чтобы отменить, напиши \"назад\" или \"\""; + public const string sendTitleOrQuitMessage = "Пришли мне текст для демотиватора, чтобы продолжить. Чтобы отменить, нажми на кнопку в меню."; + public const string awaitingTitleMessage = "Шикарная картинка. Давай сделаем из неё крутой интернет-мэм для скуфов. Какой текст ты бы хотел видеть на нём? Можно написать две строки, тогда первая строка будет заголовком, а вторая под ним."; + public const string showingResultMessage = "Вот такой демотиватор получился. Можно поменять цветовую схему, добавить водяной знак или оставить как есть."; + public const string awaitingSubtitleMessage = "Найс. Напиши текст, который будет под заголовком, или точку (.), чтобы не добавлять его."; public static readonly IReplyMarkup initialReplyMarkup = new ReplyKeyboardMarkup([[new KeyboardButton("▶️Начать")]]); public static readonly IReplyMarkup backButtonReplyMarkup = new ReplyKeyboardMarkup(new KeyboardButton("↩️Назад")); @@ -14,6 +18,7 @@ internal static class Interactions static readonly string[] helloWords = ["прив","привет","▶️начать","ку","хай","приветик","превед","привки","хаюхай","здравствуй","здравствуйте","здорово","дарова","дороу","здарова","здорова"]; static readonly string[] cancelWords = ["↩️назад", "назад", "выйти", "отмена", "отменить", "отменяй", "галя", "галина", "стоп"]; + static readonly string cancelButtonText = "↩️Назад"; public static bool IsStartCommand(string message) { @@ -31,4 +36,9 @@ internal static class Interactions string[] messageWords = message.ToLower().Split(new char[] { ' ', ',', '.', ';', '(', ')' }); return cancelWords.Any(word => messageWords.Contains(word)); } + + public static bool IsCancelButton(string message) + { + return message == cancelButtonText; + } } diff --git a/SimpleTGBot/TelegramBot.cs b/SimpleTGBot/TelegramBot.cs index ff33220..54d8536 100644 --- a/SimpleTGBot/TelegramBot.cs +++ b/SimpleTGBot/TelegramBot.cs @@ -131,6 +131,49 @@ internal class TelegramBot } break; } + case DialogState.AwaitingTitle: + { + if (message.Text is { } messageText) + { + if (!Interactions.IsCancelButton(messageText)) + { + await DialogHandleDemotivatorText(botClient, dialogData, message, messageText, cancellationToken); + } else + { + DialogCancelDemotivatorCreation(dialogData); + await botClient.SendTextMessageAsync(message.Chat.Id, Interactions.awaitingPictureMessage, replyMarkup: Interactions.quickActionReplyMarkup); + } + } else + { + await botClient.SendTextMessageAsync(message.Chat.Id, Interactions.sendTitleOrQuitMessage, replyMarkup: Interactions.backButtonReplyMarkup); + } + break; + } + case DialogState.AwaitingSubtitle: + { + if (message.Text is { } messageText) + { + if (!Interactions.IsCancelButton(messageText)) + { + await DialogHandleDemotivatorSubtitle(botClient, dialogData, message, messageText, cancellationToken); + } + else + { + DialogCancelDemotivatorCreation(dialogData); + await botClient.SendTextMessageAsync(message.Chat.Id, Interactions.awaitingPictureMessage, replyMarkup: Interactions.quickActionReplyMarkup); + } + } + break; + } + case DialogState.ShowingResult: + { + bool replied = false; + if (message.Text is { } messageText) + { + + } + break; + } } } @@ -146,20 +189,85 @@ internal class TelegramBot response.EnsureSuccessStatusCode(); (string tempFileName, FileStream tempFile) = temp.newTemporaryFile("pic", pictureExtension); await response.Content.CopyToAsync(tempFile); - tempFile.Close(); + tempFile.Dispose(); logger.Info($"Файл картинки {tempFileName} загружен от пользователя {message.From.FirstName}[{message.From.Id}]"); dialogData.inputPictureFilename = tempFileName; + dialogData.state = DialogState.AwaitingTitle; + await botClient.SendTextMessageAsync(message.Chat.Id, Interactions.awaitingTitleMessage, replyMarkup: Interactions.backButtonReplyMarkup); } } catch (Exception e) { logger.Error("Ошибка при скачивании картинки от пользователя: " + e.GetType().Name + ": " + e.Message); logger.Error(e.StackTrace ?? ""); - _ = botClient.SendTextMessageAsync(message.Chat.Id, "Ошибка :("); dialogData.state = DialogState.Initial; + await botClient.SendTextMessageAsync(message.Chat.Id, "Ошибка :("); + await botClient.SendTextMessageAsync(message.Chat.Id, Interactions.awaitingPictureMessage, replyMarkup: Interactions.quickActionReplyMarkup); } } + async Task DialogHandleDemotivatorText(ITelegramBotClient botClient, DialogData dialogData, Message message, string text, CancellationToken cancellationToken) + { + string[] lines = text.Split('\n'); + string title; + string? subtitle = null; + if (lines.Length > 1) + { + title = lines[0]; + subtitle = string.Join(' ', lines.Skip(1)); + } else + { + title = lines.First(); + } + + if (subtitle != null) + { + logger.Info($"Генерирую простой демотиватор: [\"{title}\", \"{subtitle}\"]"); + MemoryStream demotivator = DemotivatorGen.MakePictureDemotivator( + dialogData.inputPictureFilename!, + [new DemotivatorText() { Title = title, Subtitle = subtitle }], + DemotivatorGen.DefaultStyle()); + DialogFinishDemotivatorCreation(dialogData); + await botClient.SendPhotoAsync(message.Chat.Id, new InputFile(demotivator, "dem.png"), caption: Interactions.showingResultMessage, cancellationToken: cancellationToken); + demotivator.Dispose(); + } else + { + logger.Info($"Пользователь ввёл заголовок: \"{title}\""); + dialogData.inputTitle = title; + dialogData.state = DialogState.AwaitingSubtitle; + await botClient.SendTextMessageAsync(message.Chat.Id, Interactions.awaitingSubtitleMessage, replyMarkup: Interactions.backButtonReplyMarkup, cancellationToken: cancellationToken); + } + } + + async Task DialogHandleDemotivatorSubtitle(ITelegramBotClient botClient, DialogData dialogData, Message message, string subtitle, CancellationToken cancellationToken) + { + subtitle = subtitle != "." ? subtitle.Replace('\n', ' ') : ""; + string title = dialogData.inputTitle!; + + logger.Info($"Генерирую простой демотиватор: [\"{title}\", \"{subtitle}\"]"); + MemoryStream demotivator = DemotivatorGen.MakePictureDemotivator( + dialogData.inputPictureFilename!, + [new DemotivatorText() { Title = title, Subtitle = subtitle }], + DemotivatorGen.DefaultStyle()); + DialogFinishDemotivatorCreation(dialogData); + await botClient.SendPhotoAsync(message.Chat.Id, new InputFile(demotivator, "dem.png"), caption: Interactions.showingResultMessage, cancellationToken: cancellationToken); + demotivator.Dispose(); + } + + void DialogCancelDemotivatorCreation(DialogData dialogData) + { + dialogData.state = DialogState.AwaitingPicture; + if (dialogData.inputPictureFilename != null) + temp.deleteTemporaryFile(dialogData.inputPictureFilename); + } + + void DialogFinishDemotivatorCreation(DialogData dialogData) + { + dialogData.state = DialogState.ShowingResult; + if (dialogData.inputPictureFilename != null) + temp.deleteTemporaryFile(dialogData.inputPictureFilename); + } + /// /// Обработчик исключений, возникших при работе бота ///