using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using BotFramework.Attributes; using BotFramework.Enums; using Kruzya.TelegramBot.Core.Data; using Kruzya.TelegramBot.Core.Extensions; using Kruzya.TelegramBot.Core.Options; using Microsoft.Extensions.DependencyInjection; using Telegram.Bot; using Telegram.Bot.Types; using Telegram.Bot.Types.ReplyMarkups; namespace Kruzya.TelegramBot.Core.Handler; public class SettingsHandler : CommonHandler { private readonly IEnumerable _options; public SettingsHandler(CoreContext db, IServiceProvider serviceProvider) : base(db) { _options = serviceProvider.GetServices(); } [Command(InChat.Public, "settings", CommandParseMode.WithUsername)] public async Task HandleSettings() { if (!await Bot.IsUserAdminAsync(Chat, From)) { return; } await Bot.SendTextMessageAsync( Chat.Id, "What do you want to change?", replyMarkup: GetSettingsMarkup() ); } [Update(InChat.Public, UpdateFlag.CallbackQuery)] public async Task HandleCallback() { var query = CallbackQuery; var queryData = query.Data; if (queryData == null || !queryData.StartsWith("option") || !await Bot.IsUserAdminAsync(Chat, From)) { return; } var paramList = queryData.Split('|'); if (!long.TryParse(paramList[1], out var senderId)) { return; } if (senderId != From.Id) { await AnswerQuery(query.Id, "Keyboard called by another user"); return; } if (paramList[2] == "main_menu") { await AnswerQuery(query.Id); await Bot.EditMessageTextAsync(Chat.Id, query.Message!.MessageId, "What do you want to change?", replyMarkup: GetSettingsMarkup()); return; } if (paramList[2] == "edit" || paramList[2] == "select") { var option = GetOptionById(paramList[3]); if (option == null) { await AnswerQuery(query.Id, "Invalid option ID"); return; } switch (paramList[2]) { case "edit": await HandleOptionEdit(option, paramList, query); break; case "select": await HandleOptionSelect(option, paramList, query); break; } } } private async Task HandleOptionEdit(IOption option, string[] paramList, CallbackQuery query) { var chatId = Chat.Id; var messageId = query.Message!.MessageId; switch (option.OptionType) { case OptionType.OnOff: var onOffOpt = (IOption) option; await onOffOpt.SetValueAsync(chatId, !await onOffOpt.GetValueAsync(chatId)); await AnswerQuery(query.Id); await Bot.EditMessageReplyMarkupAsync(chatId, messageId, GetSettingsMarkup()); break; case OptionType.Select: var selectOpt = (IOption) option; await AnswerQuery(query.Id); await Bot.EditMessageTextAsync(Chat.Id, messageId, "Here's what you can choose:", replyMarkup: await GetChoiceSelectKeyboard(selectOpt)); break; default: await AnswerQuery(query.Id, "Not implemented"); break; } } private async Task HandleOptionSelect(IOption option, string[] paramList, CallbackQuery query) { var choice = option.ChoiceList.SingleOrDefault(x => x.Id == paramList[4]); if (choice == null) { await AnswerQuery(query.Id, "Invalid option choice"); return; } var selectOption = (IOption) option; await selectOption.SetValueAsync(Chat.Id, choice.Id); await AnswerQuery(query.Id); await Bot.EditMessageReplyMarkupAsync(Chat.Id, query.Message!.MessageId, await GetChoiceSelectKeyboard(selectOption)); } private async Task GetKeyboardButton(IOption option) { var button = new InlineKeyboardButton(option.OptionName) { CallbackData = $"option|{From.Id}|edit|{option.OptionId}" }; switch (option.OptionType) { case OptionType.OnOff: { var isEnabled = await ((IOption) option).GetValueAsync(Chat.Id); button.Text += isEnabled ? " 🟢" : " 🔴"; break; } case OptionType.Select: { var value = await ((IOption) option).GetValueAsync(Chat.Id); var currentChoice = option.ChoiceList.Single(x => x.Id == value); button.Text += $" ({currentChoice.ShortName})"; break; } } return button; } private async Task GetChoiceSelectKeyboard(IOption option) { var value = await option.GetValueAsync(Chat.Id); var choices = option.ChoiceList.Select(x => x.ToButton(From.Id, option.OptionId, x.Id == value)) .ToList(); choices.Add(new [] { new InlineKeyboardButton("Main menu") { CallbackData = $"option|{From.Id}|main_menu" } }); return new InlineKeyboardMarkup(choices); } private InlineKeyboardMarkup GetSettingsMarkup() { var keyboardLayout = _options.ToAsyncEnumerable() .SelectAwait(async x => await GetKeyboardButton(x)) .ToEnumerable() .Chunk(2); return new InlineKeyboardMarkup(keyboardLayout); } private IOption GetOptionById(string optionId) { return _options.SingleOrDefault(x => x.OptionId == optionId); } }