From be19bbec5d354aff495b2180493eb6dc8dcfc9da Mon Sep 17 00:00:00 2001 From: FlorianDahn Date: Sun, 14 Oct 2018 02:26:50 +0200 Subject: [PATCH] - Adding a progress bar control - Adding a control base class - Adding an option to log all incomming messages with an event handler - Some necessary added try/catch stuff to catch exceptions for "blocked" Bots, to prevent crashing - Added some progress bar Test to Testproject --- TelegramBaseTest/Program.cs | 2 +- TelegramBaseTest/TelegramBaseTest.csproj | 1 + TelegramBaseTest/Tests/ProgressTest.cs | 183 ++++++++++++ TelegramBaseTest/Tests/Start.cs | 11 + TelegramBotBase/Base/ControlBase.cs | 24 ++ TelegramBotBase/Base/MessageIncomeResult.cs | 30 ++ TelegramBotBase/BotBase.cs | 44 ++- TelegramBotBase/Controls/ProgressBar.cs | 292 ++++++++++++++++++++ TelegramBotBase/Form/FormBase.cs | 11 +- TelegramBotBase/Sessions/DeviceSession.cs | 46 ++- TelegramBotBase/TelegramBotBase.csproj | 3 + 11 files changed, 627 insertions(+), 20 deletions(-) create mode 100644 TelegramBaseTest/Tests/ProgressTest.cs create mode 100644 TelegramBotBase/Base/ControlBase.cs create mode 100644 TelegramBotBase/Base/MessageIncomeResult.cs create mode 100644 TelegramBotBase/Controls/ProgressBar.cs diff --git a/TelegramBaseTest/Program.cs b/TelegramBaseTest/Program.cs index 9eec2b4..06804a4 100644 --- a/TelegramBaseTest/Program.cs +++ b/TelegramBaseTest/Program.cs @@ -14,7 +14,7 @@ namespace TelegramBaseTest static void Main(string[] args) { - String APIKey = ""; + String APIKey = "480896099:AAEtq_owUqRH62DR0gYc-ZWRI_TWl8El1YQ"; BotBase bb = new BotBase(APIKey); diff --git a/TelegramBaseTest/TelegramBaseTest.csproj b/TelegramBaseTest/TelegramBaseTest.csproj index 1ce6b58..5b75454 100644 --- a/TelegramBaseTest/TelegramBaseTest.csproj +++ b/TelegramBaseTest/TelegramBaseTest.csproj @@ -55,6 +55,7 @@ + diff --git a/TelegramBaseTest/Tests/ProgressTest.cs b/TelegramBaseTest/Tests/ProgressTest.cs new file mode 100644 index 0000000..0dd9965 --- /dev/null +++ b/TelegramBaseTest/Tests/ProgressTest.cs @@ -0,0 +1,183 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using TelegramBotBase.Base; +using TelegramBotBase.Form; + +namespace TelegramBaseTest.Tests +{ + public class ProgressTest : AutoCleanForm + { + + public ProgressTest() + { + this.DeleteMode = eDeleteMode.OnLeavingForm; + } + + public override async Task Opened() + { + await this.Device.Send("Welcome to ProgressTest"); + } + + public override async Task Action(MessageResult message) + { + var call = message.GetData(); + + await message.ConfirmAction(); + + + if (call == null) + return; + + TelegramBotBase.Controls.ProgressBar Bar = null; + + switch (call.Value) + { + case "standard": + + Bar = new TelegramBotBase.Controls.ProgressBar(0, 100, TelegramBotBase.Controls.ProgressBar.eProgressStyle.standard); + Bar.Device = this.Device; + + await Bar.Render(); + + this.Controls.Add(Bar); + + for (int i = 0; i <= 100; i++) + { + Bar.Value++; + await Bar.Render(); + + Thread.Sleep(250); + } + + break; + + case "squares": + + Bar = new TelegramBotBase.Controls.ProgressBar(0, 100, TelegramBotBase.Controls.ProgressBar.eProgressStyle.squares); + Bar.Device = this.Device; + + await Bar.Render(); + + this.Controls.Add(Bar); + + for (int i = 0; i <= 100; i++) + { + Bar.Value++; + await Bar.Render(); + + Thread.Sleep(250); + } + + break; + + case "circles": + + Bar = new TelegramBotBase.Controls.ProgressBar(0, 100, TelegramBotBase.Controls.ProgressBar.eProgressStyle.circles); + Bar.Device = this.Device; + + await Bar.Render(); + + this.Controls.Add(Bar); + + for (int i = 0; i <= 100; i++) + { + Bar.Value++; + await Bar.Render(); + + Thread.Sleep(250); + } + + break; + + case "lines": + + Bar = new TelegramBotBase.Controls.ProgressBar(0, 100, TelegramBotBase.Controls.ProgressBar.eProgressStyle.lines); + Bar.Device = this.Device; + + await Bar.Render(); + + this.Controls.Add(Bar); + + for (int i = 0; i <= 100; i++) + { + Bar.Value++; + await Bar.Render(); + + Thread.Sleep(250); + } + + break; + + case "squaredlines": + + Bar = new TelegramBotBase.Controls.ProgressBar(0, 100, TelegramBotBase.Controls.ProgressBar.eProgressStyle.squaredLines); + Bar.Device = this.Device; + + await Bar.Render(); + + this.Controls.Add(Bar); + + for (int i = 0; i <= 100; i++) + { + Bar.Value++; + await Bar.Render(); + + Thread.Sleep(250); + } + + + break; + + case "start": + + var sf = new Start(); + + await sf.Init(); + + await this.NavigateTo(sf); + + break; + + default: + + + + break; + } + + + } + + + public override async Task Render(MessageResult message) + { + ButtonForm btn = new ButtonForm(); + btn.AddButtonRow(new ButtonBase("Standard", new CallbackData("a", "standard").Serialize()), new ButtonBase("Squares", new CallbackData("a", "squares").Serialize())); + + btn.AddButtonRow(new ButtonBase("Circles", new CallbackData("a", "circles").Serialize()), new ButtonBase("Lines", new CallbackData("a", "lines").Serialize())); + + btn.AddButtonRow(new ButtonBase("Squared Line", new CallbackData("a", "squaredlines").Serialize())); + + btn.AddButtonRow(new ButtonBase("Back to start", new CallbackData("a", "start").Serialize())); + + await this.Device.Send("Choose your progress bar:", btn); + } + + public override async Task Closed() + { + foreach(var b in this.Controls) + { + await b.Cleanup(); + } + + await this.Device.Send("Ciao from ProgressTest"); + } + + + + } +} diff --git a/TelegramBaseTest/Tests/Start.cs b/TelegramBaseTest/Tests/Start.cs index d9882af..3c6fdfe 100644 --- a/TelegramBaseTest/Tests/Start.cs +++ b/TelegramBaseTest/Tests/Start.cs @@ -41,6 +41,16 @@ namespace TelegramBaseTest.Tests await this.NavigateTo(bf); + break; + + case "progress": + + var pf = new ProgressTest(); + + await pf.Init(); + + await this.NavigateTo(pf); + break; } @@ -53,6 +63,7 @@ namespace TelegramBaseTest.Tests ButtonForm btn = new ButtonForm(); btn.AddButtonRow(new ButtonBase("#1 Simple Text", new CallbackData("a", "text").Serialize()), new ButtonBase("#2 Button Test", new CallbackData("a", "buttons").Serialize())); + btn.AddButtonRow(new ButtonBase("#3 Progress Bar", new CallbackData("a", "progress").Serialize())); await this.Device.Send("Choose your test:", btn); diff --git a/TelegramBotBase/Base/ControlBase.cs b/TelegramBotBase/Base/ControlBase.cs new file mode 100644 index 0000000..707ad27 --- /dev/null +++ b/TelegramBotBase/Base/ControlBase.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TelegramBotBase.Base +{ + public class ControlBase + { + public Sessions.DeviceSession Device { get; set; } + + public virtual async Task Render() + { + + } + + public virtual async Task Cleanup() + { + + } + + } +} diff --git a/TelegramBotBase/Base/MessageIncomeResult.cs b/TelegramBotBase/Base/MessageIncomeResult.cs new file mode 100644 index 0000000..58df0c7 --- /dev/null +++ b/TelegramBotBase/Base/MessageIncomeResult.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using TelegramBotBase.Sessions; + +namespace TelegramBotBase.Base +{ + public class MessageIncomeResult : EventArgs + { + + public long DeviceId { get; set; } + + public DeviceSession Device { get; set; } + + public MessageResult Message { get; set; } + + public MessageIncomeResult(long DeviceId, DeviceSession Device, MessageResult message) + { + this.DeviceId = DeviceId; + this.Device = Device; + this.Message = message; + } + + + + + } +} diff --git a/TelegramBotBase/BotBase.cs b/TelegramBotBase/BotBase.cs index 9a5731b..0b38963 100644 --- a/TelegramBotBase/BotBase.cs +++ b/TelegramBotBase/BotBase.cs @@ -21,7 +21,7 @@ namespace TelegramBotBase public SessionBase Sessions { get; set; } /// - /// Beinhaltet Systembefehle die immer erreichbar sind und nicht an die Formulare weitergereicht werden. z.b. /start + /// Contains System commands which will be available at everytime and didnt get passed to forms, i.e. /start /// public List SystemCalls { get; set; } @@ -29,12 +29,26 @@ namespace TelegramBotBase private static object __evSessionBegins = new object(); + private static object __evMessage = new object(); + private static object __evSystemCall = new object(); private static object __evException = new object(); private static object __evUnhandledCall = new object(); + + /// + /// SKips all messages during running (good for big delay updates) + /// + public bool SkipAllMessages { get; set; } = false; + + /// + /// Loggs all messages and sent them to the event handler + /// + public bool LogAllMessages { get; set; } = false; + + public BotBase(String apiKey) { this.APIKey = apiKey; @@ -82,8 +96,18 @@ namespace TelegramBotBase private void Client_Message(object sender, MessageResult e) { + if (this.SkipAllMessages) + return; + try { + if (LogAllMessages) + { + DeviceSession ds2 = this.Sessions.GetSession(e.DeviceId); + OnMessage(new MessageIncomeResult(e.DeviceId, ds2, e)); + } + + Client_TryMessage(sender, e); } catch (Telegram.Bot.Exceptions.ApiRequestException ex) @@ -255,6 +279,24 @@ namespace TelegramBotBase } + public event EventHandler Message + { + add + { + this.__Events.AddHandler(__evMessage, value); + } + remove + { + this.__Events.RemoveHandler(__evMessage, value); + } + } + + public void OnMessage(MessageIncomeResult e) + { + (this.__Events[__evMessage] as EventHandler)?.Invoke(this, e); + + } + public event EventHandler SystemCall { add diff --git a/TelegramBotBase/Controls/ProgressBar.cs b/TelegramBotBase/Controls/ProgressBar.cs new file mode 100644 index 0000000..63a032a --- /dev/null +++ b/TelegramBotBase/Controls/ProgressBar.cs @@ -0,0 +1,292 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TelegramBotBase.Controls +{ + public class ProgressBar : Base.ControlBase + { + public enum eProgressStyle + { + standard = 0, + squares = 1, + circles = 2, + lines = 3, + squaredLines = 4, + custom = 10 + } + + public eProgressStyle ProgressStyle + { + get + { + return m_eStyle; + } + set + { + m_eStyle = value; + LoadStyle(); + } + } + + private eProgressStyle m_eStyle = eProgressStyle.standard; + + + public int Value + { + get + { + return this.m_iValue; + } + set + { + if (value > this.Max) + { + return; + } + + if (this.m_iValue != value) + { + this.RenderNecessary = true; + } + this.m_iValue = value; + } + } + + private int m_iValue = 0; + + public int Max + { + get + { + return this.m_iMax; + } + set + { + if (this.m_iMax != value) + { + this.RenderNecessary = true; + } + this.m_iMax = value; + } + } + + private int m_iMax = 100; + + public int? MessageId { get; set; } + + private bool RenderNecessary { get; set; } = false; + + public int Steps + { + get + { + switch (this.ProgressStyle) + { + case eProgressStyle.standard: + + return 1; + + case eProgressStyle.squares: + + return 10; + + case eProgressStyle.circles: + + return 10; + + case eProgressStyle.lines: + + return 5; + + case eProgressStyle.squaredLines: + + return 5; + + default: + + return 1; + } + } + } + + /// + /// Filled block (reached percentage) + /// + public String BlockChar + { + get; set; + } + + /// + /// Unfilled block (not reached yet) + /// + public String EmptyBlockChar + { + get; set; + } + + /// + /// String at the beginning of the progress bar + /// + public String StartChar + { + get; set; + } + + /// + /// String at the end of the progress bar + /// + public String EndChar + { + get; set; + } + + public ProgressBar() + { + this.ProgressStyle = eProgressStyle.standard; + + this.Value = 0; + this.Max = 100; + + this.RenderNecessary = true; + } + + public ProgressBar(int Value, int Max, eProgressStyle Style) + { + this.Value = Value; + this.Max = Max; + this.ProgressStyle = Style; + + this.RenderNecessary = true; + } + + public override async Task Cleanup() + { + if (this.MessageId == null || this.MessageId == -1) + return; + + + await this.Device.DeleteMessage(this.MessageId.Value); + } + + public void LoadStyle() + { + this.StartChar = ""; + this.EndChar = ""; + + switch (this.ProgressStyle) + { + case eProgressStyle.circles: + + this.BlockChar = "⚫️ "; + this.EmptyBlockChar = "⚪️ "; + + break; + case eProgressStyle.squares: + + this.BlockChar = "⬛️ "; + this.EmptyBlockChar = "⬜️ "; + + break; + case eProgressStyle.lines: + + this.BlockChar = "█"; + this.EmptyBlockChar = "▁"; + + break; + case eProgressStyle.squaredLines: + + this.BlockChar = "▇"; + this.EmptyBlockChar = "—"; + + this.StartChar = "["; + this.EndChar = "]"; + + break; + case eProgressStyle.standard: + case eProgressStyle.custom: + + this.BlockChar = ""; + this.EmptyBlockChar = ""; + + break; + } + + } + + public async override Task Render() + { + if (!this.RenderNecessary) + { + return; + } + + if (this.Device == null) + { + return; + } + + String message = ""; + int blocks = 0; + int maxBlocks = 0; + + switch (this.ProgressStyle) + { + case eProgressStyle.standard: + + message = this.Value.ToString("0") + "%"; + + break; + + case eProgressStyle.squares: + case eProgressStyle.circles: + case eProgressStyle.lines: + case eProgressStyle.squaredLines: + case eProgressStyle.custom: + + blocks = (int)Math.Floor((decimal)this.Value / this.Steps); + + maxBlocks = (this.Max / this.Steps); + + message += this.StartChar; + + for (int i = 0; i < blocks; i++) + { + message += this.BlockChar; + } + + for (int i = 0; i < (maxBlocks - blocks); i++) + { + message += this.EmptyBlockChar; + } + + message += this.EndChar; + + message += " " + this.Value.ToString("0") + "%"; + + break; + + default: + + return; + } + + if (this.MessageId == null) + { + var m = await this.Device.Send(message); + + this.MessageId = m.MessageId; + } + else + { + await this.Device.Edit(this.MessageId.Value, message); + } + + this.RenderNecessary = false; + } + + } +} diff --git a/TelegramBotBase/Form/FormBase.cs b/TelegramBotBase/Form/FormBase.cs index c7103a9..0dc8e2b 100644 --- a/TelegramBotBase/Form/FormBase.cs +++ b/TelegramBotBase/Form/FormBase.cs @@ -21,12 +21,14 @@ namespace TelegramBotBase.Form /// public bool FormSwitched { get; set; } = false; + public List Controls { get; set; } + public FormBase() { - + this.Controls = new List(); } - public FormBase(MessageClient Client) + public FormBase(MessageClient Client): this() { this.Client = Client; } @@ -46,7 +48,10 @@ namespace TelegramBotBase.Form public virtual async Task Closed() { - + foreach (var b in this.Controls) + { + await b.Cleanup(); + } } public virtual async Task PreLoad(MessageResult message) diff --git a/TelegramBotBase/Sessions/DeviceSession.cs b/TelegramBotBase/Sessions/DeviceSession.cs index 2376bfd..37c11f3 100644 --- a/TelegramBotBase/Sessions/DeviceSession.cs +++ b/TelegramBotBase/Sessions/DeviceSession.cs @@ -62,10 +62,10 @@ namespace TelegramBotBase.Sessions /// /// /// - public async Task Edit(int messageId, String text, ButtonForm buttons = null) + public async Task Edit(int messageId, String text, ButtonForm buttons = null) { if (this.ActiveForm == null) - return; + return null; InlineKeyboardMarkup markup = null; if (buttons != null) @@ -73,8 +73,18 @@ namespace TelegramBotBase.Sessions markup = buttons; } - var message = await this.Client.TelegramClient.EditMessageTextAsync(this.DeviceId, messageId, text, replyMarkup: markup); + try + { + var m = await this.Client.TelegramClient.EditMessageTextAsync(this.DeviceId, messageId, text, replyMarkup: markup); + return m; + } + catch + { + + } + + return null; } /// @@ -84,10 +94,10 @@ namespace TelegramBotBase.Sessions /// /// /// - public async Task Send(String text, ButtonForm buttons = null, int replyTo = 0, bool disableNotification = false) + public async Task Send(String text, ButtonForm buttons = null, int replyTo = 0, bool disableNotification = false) { if (this.ActiveForm == null) - return; + return null; InlineKeyboardMarkup markup = null; if (buttons != null) @@ -103,15 +113,17 @@ namespace TelegramBotBase.Sessions } catch (Telegram.Bot.Exceptions.ApiRequestException ex) { - return; + return null; } catch { - return; + return null; } OnMessageSent(new MessageSentEventArgs(m.MessageId, m)); + + return m; } /// @@ -121,10 +133,10 @@ namespace TelegramBotBase.Sessions /// /// /// - public async Task Send(String text, InlineKeyboardMarkup markup, int replyTo = 0, bool disableNotification = false) + public async Task Send(String text, InlineKeyboardMarkup markup, int replyTo = 0, bool disableNotification = false) { if (this.ActiveForm == null) - return; + return null; Message m = null; @@ -134,14 +146,16 @@ namespace TelegramBotBase.Sessions } catch (Telegram.Bot.Exceptions.ApiRequestException ex) { - return; + return null; } catch { - return; + return null; } OnMessageSent(new MessageSentEventArgs(m.MessageId, m)); + + return m; } /// @@ -151,10 +165,10 @@ namespace TelegramBotBase.Sessions /// /// /// - public async Task SendPhoto(InputOnlineFile file, ButtonForm buttons = null, int replyTo = 0, bool disableNotification = false) + public async Task SendPhoto(InputOnlineFile file, ButtonForm buttons = null, int replyTo = 0, bool disableNotification = false) { if (this.ActiveForm == null) - return; + return null; InlineKeyboardMarkup markup = null; if (buttons != null) @@ -170,14 +184,16 @@ namespace TelegramBotBase.Sessions } catch (Telegram.Bot.Exceptions.ApiRequestException ex) { - return; + return null; } catch { - return; + return null; } OnMessageSent(new MessageSentEventArgs(m.MessageId, m)); + + return m; } /// diff --git a/TelegramBotBase/TelegramBotBase.csproj b/TelegramBotBase/TelegramBotBase.csproj index 148d417..d0cc597 100644 --- a/TelegramBotBase/TelegramBotBase.csproj +++ b/TelegramBotBase/TelegramBotBase.csproj @@ -58,7 +58,9 @@ + + @@ -67,6 +69,7 @@ +