using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Telegram.Bot; using Telegram.Bot.Args; using Telegram.Bot.Types; using Telegram.Bot.Types.Enums; using Telegram.Bot.Types.ReplyMarkups; using Newtonsoft.Json; using Telegram.Bot.Exceptions; namespace TelegramRemindMe { public static class ReminderBot { private static List _chats = new List(); private static readonly TelegramBotClient Bot = new TelegramBotClient("bot token here"); public static void Main() { Bot.OnMessage += BotOnMessageReceived; Bot.OnMessageEdited += BotOnMessageReceived; Bot.OnCallbackQuery += BotOnCallbackQueryReceived; //Bot.OnInlineQuery += BotOnInlineQueryReceived; //Bot.OnInlineResultChosen += BotOnChosenInlineResultReceived; Bot.OnReceiveError += BotOnReceiveError; if(!System.IO.File.Exists("config.json")) SaveToJson(_chats); _chats = ReadJson(); var me = Bot.GetMeAsync().Result; Console.Title = me.Username; Bot.StartReceiving(); Console.WriteLine($"Start listening for @{me.Username}"); Console.ReadLine(); Bot.StopReceiving(); } private static async void BotOnMessageReceived(object sender, MessageEventArgs messageEventArgs) { var message = messageEventArgs.Message; if (message == null || message.Type != MessageType.Text) return; if (_chats.Find(e => e.ChatId == messageEventArgs.Message.Chat.Id) == null) _chats.Add(new ChatEntry(messageEventArgs.Message.Chat.Id)); var currentChat = _chats.Find(e => e.ChatId == messageEventArgs.Message.Chat.Id); if (message.Text.Equals("/cancel")) { SendOverview(currentChat, "Action canceled."); return; } switch (currentChat.status) { case ChatStatusEnum.WaitingTaskTitle: currentChat._tasklist.Add(new TaskEntry(message.Text)); //await Bot.SendChatActionAsync(message.Chat.Id, ChatAction.Typing); SendOverview(currentChat, "Task added successfully!"); return; case ChatStatusEnum.WaitingTaskComplete: try { var completedItem = int.Parse(message.Text); if (completedItem < 1 || completedItem > currentChat._tasklist.Count(p => !p.Completed)) throw new ArgumentOutOfRangeException(); currentChat._tasklist.FindAll(p => !p.Completed)[completedItem - 1].Completed = true; SendOverview(currentChat, "Task has been set as completed."); } catch (Exception e) { SendOverview(currentChat, $"🛑 Invalid input! [{e.Message}]"); } return; case ChatStatusEnum.Idle: break; } switch (message.Text.Split(' ').First()) { default: SendOverview(currentChat); break; case "/echo": await Bot.SendChatActionAsync(message.Chat.Id, ChatAction.RecordVideoNote); await Task.Delay(500); await Bot.SendChatActionAsync(message.Chat.Id, ChatAction.UploadDocument); await Task.Delay(500); await Bot.SendChatActionAsync(message.Chat.Id, ChatAction.RecordAudio); await Task.Delay(500); await Bot.SendChatActionAsync(message.Chat.Id, ChatAction.Typing); await Task.Delay(500); await Bot.SendTextMessageAsync( message.Chat.Id, "MEOW, you woke me up!" + message.Text.Substring(5)); break; } } private static async void BotOnCallbackQueryReceived(object sender, CallbackQueryEventArgs callbackQueryEventArgs) { Console.WriteLine( $"Received action request from @{callbackQueryEventArgs.CallbackQuery.Message.Chat.Username}: {callbackQueryEventArgs.CallbackQuery.Data}"); if (_chats.Find(e => e.ChatId == callbackQueryEventArgs.CallbackQuery.Message.Chat.Id) == null) _chats.Add(new ChatEntry(callbackQueryEventArgs.CallbackQuery.Message.Chat.Id)); var currentChat = _chats.Find(e => e.ChatId == callbackQueryEventArgs.CallbackQuery.Message.Chat.Id); switch (callbackQueryEventArgs.CallbackQuery.Data) { case "Add a new task": currentChat.IsWorkingMessage = true; //TODO: fix try { currentChat.WorkingMsg = Bot.EditMessageTextAsync( new ChatId(currentChat.ChatId), callbackQueryEventArgs.CallbackQuery.Message.MessageId, "How should your new task be called?" ).Result.MessageId; } catch (ApiRequestException) {} currentChat.status = ChatStatusEnum.WaitingTaskTitle; break; case "Set a task as completed": var sb = new StringBuilder(); var i = 0; foreach (var entry in currentChat._tasklist.Where(p => !p.Completed)) { sb.AppendLine($"{++i}) {entry.Title}"); } sb.AppendLine(); sb.AppendLine("Send me the number of the task you want to complete."); currentChat.IsWorkingMessage = true; try { currentChat.WorkingMsg = Bot.EditMessageTextAsync(currentChat.ChatId, callbackQueryEventArgs.CallbackQuery.Message.MessageId, sb.ToString()).Result.MessageId; } catch (ApiRequestException) {} currentChat.status = ChatStatusEnum.WaitingTaskComplete; break; case "Show all tasks": currentChat.AllTasksShown = true; currentChat.IsWorkingMessage = true; currentChat.WorkingMsg = callbackQueryEventArgs.CallbackQuery.Message.MessageId; SendOverview(currentChat); currentChat.WorkingMsg = callbackQueryEventArgs.CallbackQuery.Message.MessageId; await Bot.AnswerCallbackQueryAsync(callbackQueryEventArgs.CallbackQuery.Id, "Showing all tasks"); break; case "Hide completed tasks": currentChat.AllTasksShown = false; currentChat.IsWorkingMessage = true; currentChat.WorkingMsg = callbackQueryEventArgs.CallbackQuery.Message.MessageId; SendOverview(currentChat); await Bot.AnswerCallbackQueryAsync(callbackQueryEventArgs.CallbackQuery.Id, "Showing only uncompleted tasks"); break; default: Console.WriteLine("Wat (Unknown callback action)"); await Bot.AnswerCallbackQueryAsync( callbackQueryEventArgs.CallbackQuery.Id, "Wat"); break; } } private static async void SendOverview(ChatEntry chat, string prefixLine = "") { SaveToJson(_chats); var actionKeyboard = new InlineKeyboardMarkup(new[] { new[] { InlineKeyboardButton.WithCallbackData("Add a new task"), InlineKeyboardButton.WithCallbackData("Set a task as completed"), }, new[] { InlineKeyboardButton.WithCallbackData( chat.AllTasksShown ? "Hide completed tasks" : "Show all tasks") } }); //await Bot.SendChatActionAsync(chat.ChatId, ChatAction.Typing); //TODO: why is this firing when workingmsg already deleted? try { if (chat.IsWorkingMessage) await Bot.DeleteMessageAsync(chat.ChatId, chat.WorkingMsg); } catch (ApiRequestException){} chat.IsWorkingMessage = false; chat.status = ChatStatusEnum.Idle; var sb = new StringBuilder(); sb.AppendLine("Your tasks:"); if (chat.AllTasksShown) { foreach (var task in chat._tasklist) { sb.Append(task.Completed ? "✅ " : "🔶 "); sb.AppendLine(task.Title); } } else { foreach (var task in chat._tasklist.Where(p => !p.Completed)) { sb.Append("🔶 "); sb.AppendLine(task.Title); } } sb.AppendLine(); sb.AppendLine("What do you want me to do?"); if (prefixLine != "") { var msgid = Bot.SendTextMessageAsync( chat.ChatId, prefixLine) .Result.MessageId; //await Bot.SendChatActionAsync(chat.ChatId, ChatAction.Typing); //await Task.Delay(1500); await Bot.EditMessageTextAsync(chat.ChatId, msgid, sb.ToString(), replyMarkup: actionKeyboard); } else { //await Bot.SendChatActionAsync(chat.ChatId, ChatAction.Typing); await Bot.SendTextMessageAsync(chat.ChatId, sb.ToString(), replyMarkup: actionKeyboard); } } private static void BotOnReceiveError(object sender, ReceiveErrorEventArgs receiveErrorEventArgs) { Console.WriteLine("Received error: {0} — {1}", receiveErrorEventArgs.ApiRequestException.ErrorCode, receiveErrorEventArgs.ApiRequestException.Message); } private static void SaveToJson(List chats) { var str = JsonConvert.SerializeObject(chats); while (true) { try { System.IO.File.WriteAllText("config.json", str); break; } catch { Console.WriteLine("Unable to write to config.json, retrying..."); } } } private static List ReadJson() { while (true) { try { var str = System.IO.File.ReadAllText("config.json"); return JsonConvert.DeserializeObject>(str); } catch { Console.WriteLine("Unable to read from config.json, retrying..."); } } } } }