- 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
This commit is contained in:
FlorianDahn 2018-10-14 02:26:50 +02:00
parent f431a4afc2
commit be19bbec5d
11 changed files with 627 additions and 20 deletions

View File

@ -14,7 +14,7 @@ namespace TelegramBaseTest
static void Main(string[] args)
{
String APIKey = "";
String APIKey = "480896099:AAEtq_owUqRH62DR0gYc-ZWRI_TWl8El1YQ";
BotBase<Start> bb = new BotBase<Start>(APIKey);

View File

@ -55,6 +55,7 @@
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Tests\ButtonTestForm.cs" />
<Compile Include="Tests\ProgressTest.cs" />
<Compile Include="Tests\SimpleForm.cs" />
<Compile Include="Tests\Start.cs" />
<Compile Include="Tests\TestForm.cs" />

View File

@ -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<CallbackData>();
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");
}
}
}

View File

@ -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);

View File

@ -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()
{
}
}
}

View File

@ -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;
}
}
}

View File

@ -21,7 +21,7 @@ namespace TelegramBotBase
public SessionBase Sessions { get; set; }
/// <summary>
/// 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
/// </summary>
public List<String> 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();
/// <summary>
/// SKips all messages during running (good for big delay updates)
/// </summary>
public bool SkipAllMessages { get; set; } = false;
/// <summary>
/// Loggs all messages and sent them to the event handler
/// </summary>
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<MessageIncomeResult> Message
{
add
{
this.__Events.AddHandler(__evMessage, value);
}
remove
{
this.__Events.RemoveHandler(__evMessage, value);
}
}
public void OnMessage(MessageIncomeResult e)
{
(this.__Events[__evMessage] as EventHandler<MessageIncomeResult>)?.Invoke(this, e);
}
public event EventHandler<SystemCallEventArgs> SystemCall
{
add

View File

@ -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;
}
}
}
/// <summary>
/// Filled block (reached percentage)
/// </summary>
public String BlockChar
{
get; set;
}
/// <summary>
/// Unfilled block (not reached yet)
/// </summary>
public String EmptyBlockChar
{
get; set;
}
/// <summary>
/// String at the beginning of the progress bar
/// </summary>
public String StartChar
{
get; set;
}
/// <summary>
/// String at the end of the progress bar
/// </summary>
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;
}
}
}

View File

@ -21,12 +21,14 @@ namespace TelegramBotBase.Form
/// </summary>
public bool FormSwitched { get; set; } = false;
public List<ControlBase> Controls { get; set; }
public FormBase()
{
this.Controls = new List<Base.ControlBase>();
}
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)

View File

@ -62,10 +62,10 @@ namespace TelegramBotBase.Sessions
/// <param name="text"></param>
/// <param name="buttons"></param>
/// <returns></returns>
public async Task Edit(int messageId, String text, ButtonForm buttons = null)
public async Task<Message> 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;
}
/// <summary>
@ -84,10 +94,10 @@ namespace TelegramBotBase.Sessions
/// <param name="replyTo"></param>
/// <param name="disableNotification"></param>
/// <returns></returns>
public async Task Send(String text, ButtonForm buttons = null, int replyTo = 0, bool disableNotification = false)
public async Task<Message> 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;
}
/// <summary>
@ -121,10 +133,10 @@ namespace TelegramBotBase.Sessions
/// <param name="replyTo"></param>
/// <param name="disableNotification"></param>
/// <returns></returns>
public async Task Send(String text, InlineKeyboardMarkup markup, int replyTo = 0, bool disableNotification = false)
public async Task<Message> 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;
}
/// <summary>
@ -151,10 +165,10 @@ namespace TelegramBotBase.Sessions
/// <param name="replyTo"></param>
/// <param name="disableNotification"></param>
/// <returns></returns>
public async Task SendPhoto(InputOnlineFile file, ButtonForm buttons = null, int replyTo = 0, bool disableNotification = false)
public async Task<Message> 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;
}
/// <summary>

View File

@ -58,7 +58,9 @@
<ItemGroup>
<Compile Include="Base\ActionResult.cs" />
<Compile Include="Base\ButtonClickedEventArgs.cs" />
<Compile Include="Base\ControlBase.cs" />
<Compile Include="Base\MessageClient.cs" />
<Compile Include="Base\MessageIncomeResult.cs" />
<Compile Include="Base\MessageResult.cs" />
<Compile Include="Base\MessageSentEventArgs.cs" />
<Compile Include="Base\ResultBase.cs" />
@ -67,6 +69,7 @@
<Compile Include="Base\UnhandledCallEventArgs.cs" />
<Compile Include="Base\SystemCallEventArgs.cs" />
<Compile Include="BotBase.cs" />
<Compile Include="Controls\ProgressBar.cs" />
<Compile Include="Form\AlertDialog.cs" />
<Compile Include="Form\ArrayPromptDialog.cs" />
<Compile Include="Form\AutoCleanForm.cs" />