diff --git a/Examples/AsyncFormUpdates/App.config b/Examples/AsyncFormUpdates/App.config
new file mode 100644
index 0000000..56efbc7
--- /dev/null
+++ b/Examples/AsyncFormUpdates/App.config
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Examples/AsyncFormUpdates/AsyncFormUpdates.csproj b/Examples/AsyncFormUpdates/AsyncFormUpdates.csproj
new file mode 100644
index 0000000..212f87e
--- /dev/null
+++ b/Examples/AsyncFormUpdates/AsyncFormUpdates.csproj
@@ -0,0 +1,69 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {673A56F5-6110-4AED-A68D-562FD6ED3EA6}
+ Exe
+ AsyncFormUpdates
+ AsyncFormUpdates
+ v4.7.2
+ 512
+ true
+ true
+
+
+ AnyCPU
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ AnyCPU
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+ ..\..\packages\Newtonsoft.Json.11.0.2\lib\net45\Newtonsoft.Json.dll
+
+
+
+
+
+
+
+
+
+
+ ..\..\packages\Telegram.Bot.15.7.1\lib\net45\Telegram.Bot.dll
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {0bd16fb9-7ed4-4ccb-83eb-5cee538e1b6c}
+ TelegramBotBase
+
+
+
+
\ No newline at end of file
diff --git a/Examples/AsyncFormUpdates/Program.cs b/Examples/AsyncFormUpdates/Program.cs
new file mode 100644
index 0000000..f249391
--- /dev/null
+++ b/Examples/AsyncFormUpdates/Program.cs
@@ -0,0 +1,48 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Timers;
+
+namespace AsyncFormUpdates
+{
+ class Program
+ {
+ static TelegramBotBase.BotBase bot = null;
+
+ static void Main(string[] args)
+ {
+ String apiKey = "APIKey";
+
+ bot = new TelegramBotBase.BotBase(apiKey);
+
+ bot.Start();
+
+ var timer = new Timer(5000);
+
+ timer.Elapsed += Timer_Elapsed;
+ timer.Start();
+
+ Console.ReadLine();
+
+ timer.Stop();
+ bot.Stop();
+ }
+
+ private static async void Timer_Elapsed(object sender, ElapsedEventArgs e)
+ {
+
+ foreach(var s in bot.Sessions.SessionList)
+ {
+ //Only for AsyncUpdateForm
+ if (s.Value.ActiveForm.GetType() != typeof(forms.AsyncFormUpdate) && s.Value.ActiveForm.GetType() != typeof(forms.AsyncFormEdit))
+ continue;
+
+ await bot.InvokeMessageLoop(s.Key);
+ }
+
+
+ }
+ }
+}
diff --git a/Examples/AsyncFormUpdates/Properties/AssemblyInfo.cs b/Examples/AsyncFormUpdates/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..216bef4
--- /dev/null
+++ b/Examples/AsyncFormUpdates/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// Allgemeine Informationen über eine Assembly werden über die folgenden
+// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern,
+// die einer Assembly zugeordnet sind.
+[assembly: AssemblyTitle("AsyncFormUpdates")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("AsyncFormUpdates")]
+[assembly: AssemblyCopyright("Copyright © 2021")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Durch Festlegen von ComVisible auf FALSE werden die Typen in dieser Assembly
+// für COM-Komponenten unsichtbar. Wenn Sie auf einen Typ in dieser Assembly von
+// COM aus zugreifen müssen, sollten Sie das ComVisible-Attribut für diesen Typ auf "True" festlegen.
+[assembly: ComVisible(false)]
+
+// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird
+[assembly: Guid("673a56f5-6110-4aed-a68d-562fd6ed3ea6")]
+
+// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten:
+//
+// Hauptversion
+// Nebenversion
+// Buildnummer
+// Revision
+//
+// Sie können alle Werte angeben oder Standardwerte für die Build- und Revisionsnummern verwenden,
+// indem Sie "*" wie unten gezeigt eingeben:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/Examples/AsyncFormUpdates/forms/AsyncFormEdit.cs b/Examples/AsyncFormUpdates/forms/AsyncFormEdit.cs
new file mode 100644
index 0000000..1e176d7
--- /dev/null
+++ b/Examples/AsyncFormUpdates/forms/AsyncFormEdit.cs
@@ -0,0 +1,57 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using TelegramBotBase.Attributes;
+using TelegramBotBase.Base;
+using TelegramBotBase.Form;
+
+namespace AsyncFormUpdates.forms
+{
+ public class AsyncFormEdit : FormBase
+ {
+ [SaveState]
+ int counter = 0;
+
+ int MessageId = 0;
+
+ public override async Task Load(MessageResult message)
+ {
+ counter++;
+ }
+
+ public override async Task Action(MessageResult message)
+ {
+ await message.ConfirmAction("");
+
+ switch (message.RawData ?? "")
+ {
+ case "back":
+
+ var st = new Start();
+ await NavigateTo(st);
+
+ break;
+ }
+ }
+
+ public override async Task Render(MessageResult message)
+ {
+ var bf = new ButtonForm();
+ bf.AddButtonRow("Back", "back");
+
+ if (MessageId != 0)
+ {
+ await Device.Edit(MessageId, $"Your current count is at: {counter}", bf);
+ }
+ else
+ {
+ var m = await Device.Send($"Your current count is at: {counter}", bf, disableNotification: true);
+ MessageId = m.MessageId;
+ }
+
+ }
+
+ }
+}
diff --git a/Examples/AsyncFormUpdates/forms/AsyncFormUpdate.cs b/Examples/AsyncFormUpdates/forms/AsyncFormUpdate.cs
new file mode 100644
index 0000000..4a4b4c7
--- /dev/null
+++ b/Examples/AsyncFormUpdates/forms/AsyncFormUpdate.cs
@@ -0,0 +1,48 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using TelegramBotBase.Attributes;
+using TelegramBotBase.Base;
+using TelegramBotBase.Form;
+
+namespace AsyncFormUpdates.forms
+{
+ public class AsyncFormUpdate : AutoCleanForm
+ {
+ [SaveState]
+ int counter = 0;
+
+
+ public override async Task Load(MessageResult message)
+ {
+ counter++;
+ }
+
+ public override async Task Action(MessageResult message)
+ {
+ await message.ConfirmAction("");
+
+ switch (message.RawData ?? "")
+ {
+ case "back":
+
+ var st = new Start();
+ await NavigateTo(st);
+
+ break;
+ }
+ }
+
+ public override async Task Render(MessageResult message)
+ {
+ var bf = new ButtonForm();
+ bf.AddButtonRow("Back", "back");
+
+ await Device.Send($"Your current count is at: {counter}", bf, disableNotification: true);
+ }
+
+
+ }
+}
diff --git a/Examples/AsyncFormUpdates/forms/Start.cs b/Examples/AsyncFormUpdates/forms/Start.cs
new file mode 100644
index 0000000..c69fa4a
--- /dev/null
+++ b/Examples/AsyncFormUpdates/forms/Start.cs
@@ -0,0 +1,52 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using TelegramBotBase.Base;
+using TelegramBotBase.Form;
+
+namespace AsyncFormUpdates.forms
+{
+ public class Start : AutoCleanForm
+ {
+
+
+ public override async Task Action(MessageResult message)
+ {
+ await message.ConfirmAction("");
+
+ switch (message.RawData ?? "")
+ {
+ case "async":
+
+ var afe = new AsyncFormEdit();
+ await NavigateTo(afe);
+
+
+ break;
+
+ case "async_del":
+
+ var afu = new AsyncFormUpdate();
+ await NavigateTo(afu);
+
+
+ break;
+ }
+
+ }
+
+ public override async Task Render(MessageResult message)
+ {
+ var bf = new ButtonForm();
+
+ bf.AddButtonRow("Open Async Form with AutoCleanupForm", "async_del");
+
+ bf.AddButtonRow("Open Async Form with Edit", "async");
+
+ await Device.Send("Choose your option", bf);
+ }
+
+ }
+}
diff --git a/Examples/AsyncFormUpdates/packages.config b/Examples/AsyncFormUpdates/packages.config
new file mode 100644
index 0000000..e25dbb0
--- /dev/null
+++ b/Examples/AsyncFormUpdates/packages.config
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
index 069cbec..11e605d 100644
--- a/README.md
+++ b/README.md
@@ -77,6 +77,8 @@ Thanks !
* [CheckedButtonList](#checked-button-list)
+ * [MultiToggleButton](#multi-toggle-button)
+
- [Groups](#groups)
* [SplitterForm](#splitter-form)
@@ -814,6 +816,8 @@ await this.NavigateTo(cd);
### Checked Button List
+### Multi Toggle Button
+
## Groups
@@ -896,6 +900,7 @@ public class GroupForm : FormBase
case Telegram.Bot.Types.Enums.MessageType.MessagePinned:
case Telegram.Bot.Types.Enums.MessageType.GroupCreated:
case Telegram.Bot.Types.Enums.MessageType.SupergroupCreated:
+ case Telegram.Bot.Types.Enums.MessageType.ChannelCreated:
await OnGroupChanged(new GroupChangedEventArgs(message.MessageType, message));
@@ -1081,6 +1086,9 @@ Will allow you to run specific system commands or run/kill processes via Bot. Ha
Will delete Join and Leave messages automatically in groups.
+- [Examples/AsyncFormUpdates/](Examples/AsyncFormUpdates/)
+
+When you want to update forms async without any user interaction (message/action) before. Use the new InvokeMessageLoop method of BotBase.
---
diff --git a/TelegramBotBase/Args/ButtonClickedEventArgs.cs b/TelegramBotBase/Args/ButtonClickedEventArgs.cs
index c3fe2db..a99b9f8 100644
--- a/TelegramBotBase/Args/ButtonClickedEventArgs.cs
+++ b/TelegramBotBase/Args/ButtonClickedEventArgs.cs
@@ -16,6 +16,8 @@ namespace TelegramBotBase.Args
public int Index { get; set; }
+ public object Tag { get; set; }
+
public ButtonClickedEventArgs()
{
diff --git a/TelegramBotBase/Args/MessageDeletedEventArgs.cs b/TelegramBotBase/Args/MessageDeletedEventArgs.cs
new file mode 100644
index 0000000..69d262b
--- /dev/null
+++ b/TelegramBotBase/Args/MessageDeletedEventArgs.cs
@@ -0,0 +1,23 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Telegram.Bot.Types;
+
+namespace TelegramBotBase.Args
+{
+ public class MessageDeletedEventArgs
+ {
+ public int MessageId
+ {
+ get;set;
+ }
+
+ public MessageDeletedEventArgs(int messageId)
+ {
+ this.MessageId = messageId;
+ }
+
+ }
+}
diff --git a/TelegramBotBase/Args/PromptDialogCompletedEventArgs.cs b/TelegramBotBase/Args/PromptDialogCompletedEventArgs.cs
new file mode 100644
index 0000000..14f9cf8
--- /dev/null
+++ b/TelegramBotBase/Args/PromptDialogCompletedEventArgs.cs
@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace TelegramBotBase.Args
+{
+ public class PromptDialogCompletedEventArgs
+ {
+ public object Tag { get; set; }
+
+ public String Value { get; set; }
+
+ }
+}
diff --git a/TelegramBotBase/Base/MessageResult.cs b/TelegramBotBase/Base/MessageResult.cs
index b7099c7..7da2bdd 100644
--- a/TelegramBotBase/Base/MessageResult.cs
+++ b/TelegramBotBase/Base/MessageResult.cs
@@ -20,12 +20,18 @@ namespace TelegramBotBase.Base
{
get
{
- return this.RawMessageData?.Message?.Chat.Id ?? this.RawCallbackData?.CallbackQuery.Message?.Chat.Id ?? 0;
+ return this.RawMessageData?.Message?.Chat.Id
+ ?? this.RawCallbackData?.CallbackQuery.Message?.Chat.Id
+ ?? Device?.DeviceId
+ ?? 0;
}
}
public DeviceSession Device
- { get; set; }
+ {
+ get;
+ set;
+ }
///
/// The message id
@@ -34,7 +40,9 @@ namespace TelegramBotBase.Base
{
get
{
- return this.Message?.MessageId ?? this.RawCallbackData?.CallbackQuery?.Message?.MessageId ?? 0;
+ return this.Message?.MessageId
+ ?? this.RawCallbackData?.CallbackQuery?.Message?.MessageId
+ ?? 0;
}
}
@@ -58,7 +66,8 @@ namespace TelegramBotBase.Base
{
get
{
- return this.RawMessageData?.Message?.Type ?? Telegram.Bot.Types.Enums.MessageType.Unknown;
+ return this.RawMessageData?.Message?.Type
+ ?? Telegram.Bot.Types.Enums.MessageType.Unknown;
}
}
@@ -175,6 +184,10 @@ namespace TelegramBotBase.Base
}
}
+ internal MessageResult()
+ {
+
+ }
public MessageResult(Telegram.Bot.Args.MessageEventArgs rawdata)
{
diff --git a/TelegramBotBase/BotBase.cs b/TelegramBotBase/BotBase.cs
index 8176234..9d9c354 100644
--- a/TelegramBotBase/BotBase.cs
+++ b/TelegramBotBase/BotBase.cs
@@ -72,6 +72,7 @@ namespace TelegramBotBase
{
this.SystemSettings = new Dictionary();
+ SetSetting(eSettings.MaxNumberOfRetries, 5);
SetSetting(eSettings.NavigationMaximum, 10);
SetSetting(eSettings.LogAllMessages, false);
SetSetting(eSettings.SkipAllMessages, false);
@@ -177,6 +178,8 @@ namespace TelegramBotBase
});
}
+ DeviceSession.MaxNumberOfRetries = this.GetSetting(eSettings.MaxNumberOfRetries, 5);
+
this.Client.TelegramClient.StartReceiving();
}
@@ -230,7 +233,7 @@ namespace TelegramBotBase
ds?.OnMessageReceived(new MessageReceivedEventArgs(e.Message));
- await Client_TryMessage(sender, e);
+ await Client_Loop(sender, e);
}
catch (Telegram.Bot.Exceptions.ApiRequestException ex)
{
@@ -243,14 +246,86 @@ namespace TelegramBotBase
}
}
- private async Task Client_TryMessage(object sender, MessageResult e)
+
+
+ //private async Task Client_TryMessage(object sender, MessageResult e)
+ //{
+ // DeviceSession ds = e.Device;
+ // if (ds == null)
+ // {
+ // ds = await this.Sessions.StartSession(e.DeviceId);
+ // e.Device = ds;
+
+ // ds.LastMessage = e.Message;
+
+ // OnSessionBegins(new SessionBeginEventArgs(e.DeviceId, ds));
+ // }
+
+ // ds.LastAction = DateTime.Now;
+ // ds.LastMessage = e.Message;
+
+ // //Is this a bot command ?
+ // if (e.IsBotCommand && this.BotCommands.Count(a => "/" + a.Command == e.BotCommand) > 0)
+ // {
+ // var sce = new BotCommandEventArgs(e.BotCommand, e.BotCommandParameters, e.Message, ds.DeviceId, ds);
+ // await OnBotCommand(sce);
+
+ // if (sce.Handled)
+ // return;
+ // }
+
+ // FormBase activeForm = null;
+
+ // int i = 0;
+
+ // //Should formulars get navigated (allow maximum of 10, to dont get loops)
+ // do
+ // {
+ // i++;
+
+ // //Reset navigation
+ // ds.FormSwitched = false;
+
+ // activeForm = ds.ActiveForm;
+
+ // //Pre Loading Event
+ // await activeForm.PreLoad(e);
+
+ // //Send Load event to controls
+ // await activeForm.LoadControls(e);
+
+ // //Loading Event
+ // await activeForm.Load(e);
+
+ // //Is Attachment ? (Photo, Audio, Video, Contact, Location, Document)
+ // if (e.Message.Type == Telegram.Bot.Types.Enums.MessageType.Contact | e.Message.Type == Telegram.Bot.Types.Enums.MessageType.Document | e.Message.Type == Telegram.Bot.Types.Enums.MessageType.Location |
+ // e.Message.Type == Telegram.Bot.Types.Enums.MessageType.Photo | e.Message.Type == Telegram.Bot.Types.Enums.MessageType.Video | e.Message.Type == Telegram.Bot.Types.Enums.MessageType.Audio)
+ // {
+ // await activeForm.SentData(new DataResult(e));
+ // }
+
+ // //Render Event
+ // if (!ds.FormSwitched)
+ // {
+ // await activeForm.RenderControls(e);
+
+ // await activeForm.Render(e);
+ // }
+
+ // e.IsFirstHandler = false;
+
+ // } while (ds.FormSwitched && i < this.GetSetting(eSettings.NavigationMaximum, 10));
+
+
+ //}
+
+ private async Task Client_Loop(object sender, MessageResult e)
{
DeviceSession ds = e.Device;
if (ds == null)
{
ds = await this.Sessions.StartSession(e.DeviceId);
e.Device = ds;
-
ds.LastMessage = e.Message;
OnSessionBegins(new SessionBeginEventArgs(e.DeviceId, ds));
@@ -293,15 +368,41 @@ namespace TelegramBotBase
await activeForm.Load(e);
//Is Attachment ? (Photo, Audio, Video, Contact, Location, Document)
- if (e.Message.Type == Telegram.Bot.Types.Enums.MessageType.Contact | e.Message.Type == Telegram.Bot.Types.Enums.MessageType.Document | e.Message.Type == Telegram.Bot.Types.Enums.MessageType.Location |
- e.Message.Type == Telegram.Bot.Types.Enums.MessageType.Photo | e.Message.Type == Telegram.Bot.Types.Enums.MessageType.Video | e.Message.Type == Telegram.Bot.Types.Enums.MessageType.Audio)
+ if (e.MessageType == Telegram.Bot.Types.Enums.MessageType.Contact | e.MessageType == Telegram.Bot.Types.Enums.MessageType.Document | e.MessageType == Telegram.Bot.Types.Enums.MessageType.Location |
+ e.MessageType == Telegram.Bot.Types.Enums.MessageType.Photo | e.MessageType == Telegram.Bot.Types.Enums.MessageType.Video | e.MessageType == Telegram.Bot.Types.Enums.MessageType.Audio)
{
await activeForm.SentData(new DataResult(e));
}
- //Render Event
+ //Action Event
+ if (!ds.FormSwitched && e.IsAction)
+ {
+ //Send Action event to controls
+ await activeForm.ActionControls(e);
+
+ //Send Action event to form itself
+ await activeForm.Action(e);
+
+ if (!e.Handled)
+ {
+ var uhc = new UnhandledCallEventArgs(e.Message.Text, e.RawData, ds.DeviceId, e.MessageId, e.Message, ds);
+ OnUnhandledCall(uhc);
+
+ if (uhc.Handled)
+ {
+ e.Handled = true;
+ if (!ds.FormSwitched)
+ {
+ break;
+ }
+ }
+ }
+
+ }
+
if (!ds.FormSwitched)
{
+ //Render Event
await activeForm.RenderControls(e);
await activeForm.Render(e);
@@ -314,6 +415,38 @@ namespace TelegramBotBase
}
+ ///
+ /// This will invoke the full message loop for the device even when no "userevent" like message or action has been raised.
+ ///
+ /// Contains the device/chat id of the device to update.
+ public async Task InvokeMessageLoop(long DeviceId)
+ {
+ var mr = new MessageResult();
+
+ await InvokeMessageLoop(DeviceId, mr);
+ }
+
+ ///
+ /// This will invoke the full message loop for the device even when no "userevent" like message or action has been raised.
+ ///
+ /// Contains the device/chat id of the device to update.
+ ///
+ public async Task InvokeMessageLoop(long DeviceId, MessageResult e)
+ {
+ try
+ {
+ DeviceSession ds = this.Sessions.GetSession(DeviceId);
+ e.Device = ds;
+
+ await Client_Loop(this, e);
+ }
+ catch (Exception ex)
+ {
+ DeviceSession ds = this.Sessions.GetSession(DeviceId);
+ OnException(new SystemExceptionEventArgs(e.Message.Text, DeviceId, ds, ex));
+ }
+ }
+
private async void Client_MessageEdit(object sender, MessageResult e)
{
if (this.GetSetting(eSettings.SkipAllMessages, false))
@@ -363,12 +496,12 @@ namespace TelegramBotBase
//When form has been switched due navigation within the edit method, reopen Client_Message
if (ds.FormSwitched)
{
- await Client_TryMessage(sender, e);
+ await Client_Loop(sender, e);
}
}
- private void Client_Action(object sender, MessageResult e)
+ private async void Client_Action(object sender, MessageResult e)
{
try
{
@@ -380,7 +513,7 @@ namespace TelegramBotBase
OnMessage(new MessageIncomeEventArgs(e.DeviceId, ds, e));
}
- Client_TryAction(sender, e);
+ await Client_Loop(sender, e);
}
catch (Exception ex)
{
@@ -389,80 +522,80 @@ namespace TelegramBotBase
}
}
- private async void Client_TryAction(object sender, MessageResult e)
- {
- DeviceSession ds = e.Device;
- if (ds == null)
- {
- ds = await this.Sessions.StartSession(e.DeviceId);
- e.Device = ds;
- }
+ //private async void Client_TryAction(object sender, MessageResult e)
+ //{
+ // DeviceSession ds = e.Device;
+ // if (ds == null)
+ // {
+ // ds = await this.Sessions.StartSession(e.DeviceId);
+ // e.Device = ds;
+ // }
- ds.LastAction = DateTime.Now;
- ds.LastMessage = e.Message;
+ // ds.LastAction = DateTime.Now;
+ // ds.LastMessage = e.Message;
- FormBase activeForm = null;
+ // FormBase activeForm = null;
- int i = 0;
+ // int i = 0;
- //Should formulars get navigated (allow maximum of 10, to dont get loops)
- do
- {
- i++;
+ // //Should formulars get navigated (allow maximum of 10, to dont get loops)
+ // do
+ // {
+ // i++;
- //Reset navigation
- ds.FormSwitched = false;
+ // //Reset navigation
+ // ds.FormSwitched = false;
- activeForm = ds.ActiveForm;
+ // activeForm = ds.ActiveForm;
- //Pre Loading Event
- await activeForm.PreLoad(e);
+ // //Pre Loading Event
+ // await activeForm.PreLoad(e);
- //Send Load event to controls
- await activeForm.LoadControls(e);
+ // //Send Load event to controls
+ // await activeForm.LoadControls(e);
- //Loading Event
- await activeForm.Load(e);
+ // //Loading Event
+ // await activeForm.Load(e);
- //Action Event
- if (!ds.FormSwitched)
- {
- //Send Action event to controls
- await activeForm.ActionControls(e);
+ // //Action Event
+ // if (!ds.FormSwitched)
+ // {
+ // //Send Action event to controls
+ // await activeForm.ActionControls(e);
- //Send Action event to form itself
- await activeForm.Action(e);
+ // //Send Action event to form itself
+ // await activeForm.Action(e);
- if (!e.Handled)
- {
- var uhc = new UnhandledCallEventArgs(e.Message.Text, e.RawData, ds.DeviceId, e.MessageId, e.Message, ds);
- OnUnhandledCall(uhc);
+ // if (!e.Handled)
+ // {
+ // var uhc = new UnhandledCallEventArgs(e.Message.Text, e.RawData, ds.DeviceId, e.MessageId, e.Message, ds);
+ // OnUnhandledCall(uhc);
- if (uhc.Handled)
- {
- e.Handled = true;
- if (!ds.FormSwitched)
- {
- break;
- }
- }
- }
+ // if (uhc.Handled)
+ // {
+ // e.Handled = true;
+ // if (!ds.FormSwitched)
+ // {
+ // break;
+ // }
+ // }
+ // }
- }
+ // }
- //Render Event
- if (!ds.FormSwitched)
- {
- await activeForm.RenderControls(e);
+ // //Render Event
+ // if (!ds.FormSwitched)
+ // {
+ // await activeForm.RenderControls(e);
- await activeForm.Render(e);
- }
+ // await activeForm.Render(e);
+ // }
- e.IsFirstHandler = false;
+ // e.IsFirstHandler = false;
- } while (ds.FormSwitched && i < this.GetSetting(eSettings.NavigationMaximum, 10));
+ // } while (ds.FormSwitched && i < this.GetSetting(eSettings.NavigationMaximum, 10));
- }
+ //}
///
/// This method will update all local created bot commands to the botfather.
diff --git a/TelegramBotBase/Commands/Extensions.cs b/TelegramBotBase/Commands/Extensions.cs
new file mode 100644
index 0000000..b866439
--- /dev/null
+++ b/TelegramBotBase/Commands/Extensions.cs
@@ -0,0 +1,40 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Telegram.Bot.Types;
+
+namespace TelegramBotBase.Commands
+{
+ public static class Extensions
+ {
+ ///
+ /// Adding the default /start command with a description.
+ ///
+ ///
+ ///
+ public static void AddStartCommand(this List cmds, String description)
+ {
+ cmds.Add(new BotCommand() { Command = "start", Description = description });
+ }
+
+ ///
+ /// Adding the default /help command with a description.
+ ///
+ ///
+ ///
+ public static void AddHelpCommand(this List cmds, String description)
+ {
+ cmds.Add(new BotCommand() { Command = "help", Description = description });
+ }
+
+ ///
+ /// Adding the default /settings command with a description.
+ ///
+ ///
+ ///
+ public static void AddSettingsCommand(this List cmds, String description)
+ {
+ cmds.Add(new BotCommand() { Command = "settings", Description = description });
+ }
+ }
+}
diff --git a/TelegramBotBase/Constants/Telegram.cs b/TelegramBotBase/Constants/Telegram.cs
index b7392ee..d203123 100644
--- a/TelegramBotBase/Constants/Telegram.cs
+++ b/TelegramBotBase/Constants/Telegram.cs
@@ -21,5 +21,7 @@ namespace TelegramBotBase.Constants
public const int MaxReplyKeyboardCols = 12;
+ public const int MessageDeletionsPerSecond = 30;
+
}
}
diff --git a/TelegramBotBase/Controls/Hybrid/ButtonGrid.cs b/TelegramBotBase/Controls/Hybrid/ButtonGrid.cs
index 99c96b4..7a1318b 100644
--- a/TelegramBotBase/Controls/Hybrid/ButtonGrid.cs
+++ b/TelegramBotBase/Controls/Hybrid/ButtonGrid.cs
@@ -159,6 +159,22 @@ namespace TelegramBotBase.Controls.Hybrid
}
}
+ public override void Init()
+ {
+ this.Device.MessageDeleted += Device_MessageDeleted;
+ }
+
+ private void Device_MessageDeleted(object sender, MessageDeletedEventArgs e)
+ {
+ if (this.MessageId == null)
+ return;
+
+ if (e.MessageId != this.MessageId)
+ return;
+
+ this.MessageId = null;
+ }
+
public async override Task Load(MessageResult result)
{
if (this.KeyboardType != eKeyboardType.ReplyKeyboard)
@@ -396,14 +412,20 @@ namespace TelegramBotBase.Controls.Hybrid
case eKeyboardType.InlineKeyBoard:
+ //Try to edit message if message id is available
+ //When the returned message is null then the message has been already deleted, resend it
if (this.MessageId != null)
{
m = await this.Device.Edit(this.MessageId.Value, this.Title, (InlineKeyboardMarkup)form);
+ if (m != null)
+ {
+ this.MessageId = m.MessageId;
+ return;
+ }
}
- else
- {
- m = await this.Device.Send(this.Title, (InlineKeyboardMarkup)form, disableNotification: true, parseMode: MessageParseMode, MarkdownV2AutoEscape: false);
- }
+
+ //When no message id is available or it has been deleted due the use of AutoCleanForm re-render automatically
+ m = await this.Device.Send(this.Title, (InlineKeyboardMarkup)form, disableNotification: true, parseMode: MessageParseMode, MarkdownV2AutoEscape: false);
break;
}
@@ -573,6 +595,11 @@ namespace TelegramBotBase.Controls.Hybrid
{
this.Updated();
}
+ else
+ {
+ //Remove event handler
+ this.Device.MessageDeleted -= Device_MessageDeleted;
+ }
}
///
diff --git a/TelegramBotBase/Controls/Hybrid/TaggedButtonGrid.cs b/TelegramBotBase/Controls/Hybrid/TaggedButtonGrid.cs
index 9fb8d5f..31028e9 100644
--- a/TelegramBotBase/Controls/Hybrid/TaggedButtonGrid.cs
+++ b/TelegramBotBase/Controls/Hybrid/TaggedButtonGrid.cs
@@ -170,6 +170,22 @@ namespace TelegramBotBase.Controls.Hybrid
}
}
+ public override void Init()
+ {
+ this.Device.MessageDeleted += Device_MessageDeleted;
+ }
+
+ private void Device_MessageDeleted(object sender, MessageDeletedEventArgs e)
+ {
+ if (this.MessageId == null)
+ return;
+
+ if (e.MessageId != this.MessageId)
+ return;
+
+ this.MessageId = null;
+ }
+
public async override Task Load(MessageResult result)
{
if (this.KeyboardType != eKeyboardType.ReplyKeyboard)
@@ -185,10 +201,7 @@ namespace TelegramBotBase.Controls.Hybrid
?? SubHeadLayoutButtonRow?.FirstOrDefault(a => a.Text.Trim() == result.MessageText)
?? ButtonsForm.ToList().FirstOrDefault(a => a.Text.Trim() == result.MessageText);
- var index = HeadLayoutButtonRow?.IndexOf(button)
- ?? SubHeadLayoutButtonRow?.IndexOf(button)
- ?? ButtonsForm.ToList().IndexOf(button);
-
+ var index = ButtonsForm.FindRowByButton(button);
switch (this.SelectedViewIndex)
@@ -326,9 +339,7 @@ namespace TelegramBotBase.Controls.Hybrid
?? SubHeadLayoutButtonRow?.FirstOrDefault(a => a.Value == result.RawData)
?? ButtonsForm.ToList().FirstOrDefault(a => a.Value == result.RawData);
- var index = HeadLayoutButtonRow?.IndexOf(button)
- ?? SubHeadLayoutButtonRow?.IndexOf(button)
- ?? ButtonsForm.ToList().IndexOf(button);
+ var index = ButtonsForm.FindRowByButton(button);
if (button != null)
{
@@ -521,15 +532,21 @@ namespace TelegramBotBase.Controls.Hybrid
case eKeyboardType.InlineKeyBoard:
+
+ //Try to edit message if message id is available
+ //When the returned message is null then the message has been already deleted, resend it
if (this.MessageId != null)
{
m = await this.Device.Edit(this.MessageId.Value, this.Title, (InlineKeyboardMarkup)form);
- }
- else
- {
- m = await this.Device.Send(this.Title, (InlineKeyboardMarkup)form, disableNotification: true, parseMode: MessageParseMode, MarkdownV2AutoEscape: false);
+ if (m != null)
+ {
+ this.MessageId = m.MessageId;
+ return;
+ }
}
+ //When no message id is available or it has been deleted due the use of AutoCleanForm re-render automatically
+ m = await this.Device.Send(this.Title, (InlineKeyboardMarkup)form, disableNotification: true, parseMode: MessageParseMode, MarkdownV2AutoEscape: false);
break;
}
@@ -782,6 +799,11 @@ namespace TelegramBotBase.Controls.Hybrid
{
this.Updated();
}
+ else
+ {
+ //Remove event handler
+ this.Device.MessageDeleted -= Device_MessageDeleted;
+ }
}
///
diff --git a/TelegramBotBase/Controls/Inline/MultiToggleButton.cs b/TelegramBotBase/Controls/Inline/MultiToggleButton.cs
new file mode 100644
index 0000000..1828f2b
--- /dev/null
+++ b/TelegramBotBase/Controls/Inline/MultiToggleButton.cs
@@ -0,0 +1,164 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using TelegramBotBase.Base;
+using TelegramBotBase.Form;
+
+namespace TelegramBotBase.Controls.Inline
+{
+ public class MultiToggleButton : ControlBase
+ {
+ ///
+ /// This contains the selected icon.
+ ///
+ public String SelectedIcon { get; set; } = Localizations.Default.Language["MultiToggleButton_SelectedIcon"];
+
+ ///
+ /// This will appear on the ConfirmAction message (if not empty)
+ ///
+ public String ChangedString { get; set; } = Localizations.Default.Language["MultiToggleButton_Changed"];
+
+ ///
+ /// This holds the title of the control.
+ ///
+ public String Title { get; set; } = Localizations.Default.Language["MultiToggleButton_Title"];
+
+ public int? MessageId { get; set; }
+
+ private bool RenderNecessary = true;
+
+ private static readonly object __evToggled = new object();
+
+ private readonly EventHandlerList Events = new EventHandlerList();
+
+ ///
+ /// This will hold all options available.
+ ///
+ public List Options { get; set; }
+
+ ///
+ /// This will set if an empty selection (null) is allowed.
+ ///
+ public bool AllowEmptySelection { get; set; } = true;
+
+
+ public MultiToggleButton()
+ {
+ Options = new List();
+ }
+
+ public event EventHandler Toggled
+ {
+ add
+ {
+ this.Events.AddHandler(__evToggled, value);
+ }
+ remove
+ {
+ this.Events.RemoveHandler(__evToggled, value);
+ }
+ }
+
+ public void OnToggled(EventArgs e)
+ {
+ (this.Events[__evToggled] as EventHandler)?.Invoke(this, e);
+ }
+
+ public override async Task Action(MessageResult result, String value = null)
+ {
+ if (result.Handled)
+ return;
+
+ await result.ConfirmAction(this.ChangedString);
+
+ switch (value ?? "unknown")
+ {
+ default:
+
+ var s = value.Split('$');
+
+ if (s[0] == "check" && s.Length > 1)
+ {
+ int index = 0;
+ if (!int.TryParse(s[1], out index))
+ {
+ return;
+ }
+
+ if(SelectedOption== null || SelectedOption != this.Options[index])
+ {
+ this.SelectedOption = this.Options[index];
+ OnToggled(new EventArgs());
+ }
+ else if(this.AllowEmptySelection)
+ {
+ this.SelectedOption = null;
+ OnToggled(new EventArgs());
+ }
+
+ RenderNecessary = true;
+
+ return;
+ }
+
+
+ RenderNecessary = false;
+
+ break;
+
+ }
+
+ result.Handled = true;
+
+ }
+
+ public override async Task Render(MessageResult result)
+ {
+ if (!RenderNecessary)
+ return;
+
+ var bf = new ButtonForm(this);
+
+ var lst = new List();
+ foreach (var o in this.Options)
+ {
+ var index = this.Options.IndexOf(o);
+ if (o == this.SelectedOption)
+ {
+ lst.Add(new ButtonBase(SelectedIcon + " " + o.Text, "check$" + index));
+ continue;
+ }
+
+ lst.Add(new ButtonBase(o.Text, "check$" + index));
+ }
+
+ bf.AddButtonRow(lst);
+
+ if (this.MessageId != null)
+ {
+ var m = await this.Device.Edit(this.MessageId.Value, this.Title, bf);
+ }
+ else
+ {
+ var m = await this.Device.Send(this.Title, bf, disableNotification: true);
+ if (m != null)
+ {
+ this.MessageId = m.MessageId;
+ }
+ }
+
+ this.RenderNecessary = false;
+
+
+ }
+
+ public ButtonBase SelectedOption
+ {
+ get; set;
+ }
+
+ }
+}
diff --git a/TelegramBotBase/Enums/eSettings.cs b/TelegramBotBase/Enums/eSettings.cs
index e425650..7e55710 100644
--- a/TelegramBotBase/Enums/eSettings.cs
+++ b/TelegramBotBase/Enums/eSettings.cs
@@ -27,9 +27,14 @@ namespace TelegramBotBase.Enums
///
/// Does stick to the console event handler and saves all sessions on exit.
///
- SaveSessionsOnConsoleExit = 4
+ SaveSessionsOnConsoleExit = 4,
+ ///
+ /// Indicates the maximum number of times a request that received error
+ /// 429 will be sent again after a timeout until it receives code 200 or an error code not equal to 429.
+ ///
+ MaxNumberOfRetries = 5,
}
}
diff --git a/TelegramBotBase/Form/ArrayPromptDialog.cs b/TelegramBotBase/Form/ArrayPromptDialog.cs
index 0812b25..42749fe 100644
--- a/TelegramBotBase/Form/ArrayPromptDialog.cs
+++ b/TelegramBotBase/Form/ArrayPromptDialog.cs
@@ -16,8 +16,16 @@ namespace TelegramBotBase.Form
[IgnoreState]
public class ArrayPromptDialog : FormBase
{
+ ///
+ /// The message the users sees.
+ ///
public String Message { get; set; }
+ ///
+ /// An additional optional value.
+ ///
+ public object Tag { get; set; }
+
public ButtonBase[][] Buttons { get; set; }
[Obsolete]
@@ -70,7 +78,7 @@ namespace TelegramBotBase.Form
return;
}
- OnButtonClicked(new ButtonClickedEventArgs(button));
+ OnButtonClicked(new ButtonClickedEventArgs(button) { Tag = this.Tag });
FormBase fb = ButtonForms.ContainsKey(call.Value) ? ButtonForms[call.Value] : null;
diff --git a/TelegramBotBase/Form/AutoCleanForm.cs b/TelegramBotBase/Form/AutoCleanForm.cs
index 20aa644..4a7c6c5 100644
--- a/TelegramBotBase/Form/AutoCleanForm.cs
+++ b/TelegramBotBase/Form/AutoCleanForm.cs
@@ -25,7 +25,7 @@ namespace TelegramBotBase.Form
[SaveState]
public eDeleteSide DeleteSide { get; set; }
-
+
public AutoCleanForm()
{
@@ -33,13 +33,12 @@ namespace TelegramBotBase.Form
this.DeleteMode = eDeleteMode.OnEveryCall;
this.DeleteSide = eDeleteSide.BotOnly;
- this.Init += AutoCleanForm_Init;
+ this.Init += AutoCleanForm_Init;
this.Closed += AutoCleanForm_Closed;
}
-
private async Task AutoCleanForm_Init(object sender, InitEventArgs e)
{
if (this.Device == null)
@@ -130,13 +129,23 @@ namespace TelegramBotBase.Form
{
while (this.OldMessages.Count > 0)
{
- if (!await this.Device.DeleteMessage(this.OldMessages[0]))
+ var tasks = new List();
+ var msgs = this.OldMessages.Take(Constants.Telegram.MessageDeletionsPerSecond);
+
+ foreach (var msg in msgs)
{
- //Message can't be deleted cause it seems not to exist anymore
- if (this.OldMessages.Count > 0)
- this.OldMessages.RemoveAt(0);
+ tasks.Add(this.Device.DeleteMessage(msg));
}
- }
+
+ await Task.WhenAll(tasks);
+
+ foreach(var m in msgs)
+ {
+ Device.OnMessageDeleted(new MessageDeletedEventArgs(m));
+ }
+
+ this.OldMessages.RemoveRange(0, msgs.Count());
+ }
}
}
}
diff --git a/TelegramBotBase/Form/ConfirmDialog.cs b/TelegramBotBase/Form/ConfirmDialog.cs
index a5ce824..dc791db 100644
--- a/TelegramBotBase/Form/ConfirmDialog.cs
+++ b/TelegramBotBase/Form/ConfirmDialog.cs
@@ -13,8 +13,16 @@ namespace TelegramBotBase.Form
[IgnoreState]
public class ConfirmDialog : ModalDialog
{
+ ///
+ /// The message the users sees.
+ ///
public String Message { get; set; }
+ ///
+ /// An additional optional value.
+ ///
+ public object Tag { get; set; }
+
///
/// Automatically close form on button click
///
@@ -77,7 +85,7 @@ namespace TelegramBotBase.Form
return;
}
- OnButtonClicked(new ButtonClickedEventArgs(button));
+ OnButtonClicked(new ButtonClickedEventArgs(button) { Tag = this.Tag });
if (AutoCloseOnClick)
await CloseForm();
diff --git a/TelegramBotBase/Form/GroupForm.cs b/TelegramBotBase/Form/GroupForm.cs
index 3cfc949..6b460cf 100644
--- a/TelegramBotBase/Form/GroupForm.cs
+++ b/TelegramBotBase/Form/GroupForm.cs
@@ -41,6 +41,7 @@ namespace TelegramBotBase.Form
case Telegram.Bot.Types.Enums.MessageType.MessagePinned:
case Telegram.Bot.Types.Enums.MessageType.GroupCreated:
case Telegram.Bot.Types.Enums.MessageType.SupergroupCreated:
+ case Telegram.Bot.Types.Enums.MessageType.ChannelCreated:
await OnGroupChanged(new GroupChangedEventArgs(message.MessageType, message));
diff --git a/TelegramBotBase/Form/PromptDialog.cs b/TelegramBotBase/Form/PromptDialog.cs
index f2a26cd..ec9e61c 100644
--- a/TelegramBotBase/Form/PromptDialog.cs
+++ b/TelegramBotBase/Form/PromptDialog.cs
@@ -6,6 +6,7 @@ using System.Text;
using System.Threading.Tasks;
using Telegram.Bot.Types;
using Telegram.Bot.Types.ReplyMarkups;
+using TelegramBotBase.Args;
using TelegramBotBase.Attributes;
using TelegramBotBase.Base;
@@ -14,10 +15,21 @@ namespace TelegramBotBase.Form
[IgnoreState]
public class PromptDialog : ModalDialog
{
+ ///
+ /// The message the users sees.
+ ///
public String Message { get; set; }
+ ///
+ /// The returned text value by the user.
+ ///
public String Value { get; set; }
+ ///
+ /// An additional optional value.
+ ///
+ public object Tag { get; set; }
+
private EventHandlerList __Events { get; set; } = new EventHandlerList();
private static object __evCompleted { get; } = new object();
@@ -86,13 +98,13 @@ namespace TelegramBotBase.Form
message.Handled = true;
- OnCompleted(new EventArgs());
+ OnCompleted(new PromptDialogCompletedEventArgs() { Tag = this.Tag, Value = this.Value });
await this.CloseForm();
}
- public event EventHandler Completed
+ public event EventHandler Completed
{
add
{
@@ -104,9 +116,9 @@ namespace TelegramBotBase.Form
}
}
- public void OnCompleted(EventArgs e)
+ public void OnCompleted(PromptDialogCompletedEventArgs e)
{
- (this.__Events[__evCompleted] as EventHandler)?.Invoke(this, e);
+ (this.__Events[__evCompleted] as EventHandler)?.Invoke(this, e);
}
}
diff --git a/TelegramBotBase/Localizations/English.cs b/TelegramBotBase/Localizations/English.cs
index ed97089..1082c21 100644
--- a/TelegramBotBase/Localizations/English.cs
+++ b/TelegramBotBase/Localizations/English.cs
@@ -26,6 +26,10 @@ namespace TelegramBotBase.Localizations
Values["ToggleButton_OnIcon"] = "⚫";
Values["ToggleButton_OffIcon"] = "⚪";
Values["ToggleButton_Title"] = "Toggle";
+ Values["ToggleButton_Changed"] = "Choosen";
+ Values["MultiToggleButton_SelectedIcon"] = "✅";
+ Values["MultiToggleButton_Title"] = "Multi-Toggle";
+ Values["MultiToggleButton_Changed"] = "Choosen";
Values["PromptDialog_Back"] = "Back";
Values["ToggleButton_Changed"] = "Setting changed";
}
diff --git a/TelegramBotBase/Localizations/Localization.cs b/TelegramBotBase/Localizations/Localization.cs
index e00c25c..7f60247 100644
--- a/TelegramBotBase/Localizations/Localization.cs
+++ b/TelegramBotBase/Localizations/Localization.cs
@@ -36,6 +36,10 @@ namespace TelegramBotBase.Localizations
Values["ToggleButton_OnIcon"] = "⚫";
Values["ToggleButton_OffIcon"] = "⚪";
Values["ToggleButton_Title"] = "Schalter";
+ Values["ToggleButton_Changed"] = "Ausgewählt";
+ Values["MultiToggleButton_SelectedIcon"] = "✅";
+ Values["MultiToggleButton_Title"] = "Mehrfach-Schalter";
+ Values["MultiToggleButton_Changed"] = "Ausgewählt";
Values["PromptDialog_Back"] = "Zurück";
Values["ToggleButton_Changed"] = "Einstellung geändert";
diff --git a/TelegramBotBase/SessionBase.cs b/TelegramBotBase/SessionBase.cs
index 67e309d..7096000 100644
--- a/TelegramBotBase/SessionBase.cs
+++ b/TelegramBotBase/SessionBase.cs
@@ -198,6 +198,8 @@ namespace TelegramBotBase
catch (ArgumentException ex)
{
+ CustomConversionChecks(form, p, f);
+
}
catch
{
@@ -238,6 +240,35 @@ namespace TelegramBotBase
}
+ private static void CustomConversionChecks(FormBase form, KeyValuePair p, System.Reflection.PropertyInfo f)
+ {
+ //Newtonsoft Int64/Int32 converter issue
+ if (f.PropertyType == typeof(Int32))
+ {
+ int i = 0;
+ if(int.TryParse(p.Value.ToString(), out i))
+ {
+ f.SetValue(form, i);
+ }
+ return;
+ }
+
+ //Newtonsoft Double/Decimal converter issue
+ if(f.PropertyType == typeof(Decimal) | f.PropertyType == typeof(Nullable))
+ {
+ decimal d = 0;
+ if(decimal.TryParse(p.Value.ToString(), out d))
+ {
+ f.SetValue(form, d);
+ }
+ return;
+ }
+
+
+ }
+
+
+
///
/// Saves all open states into the machine.
///
diff --git a/TelegramBotBase/Sessions/DeviceSession.cs b/TelegramBotBase/Sessions/DeviceSession.cs
index 12d57d4..7ce93c1 100644
--- a/TelegramBotBase/Sessions/DeviceSession.cs
+++ b/TelegramBotBase/Sessions/DeviceSession.cs
@@ -119,6 +119,7 @@ namespace TelegramBotBase.Sessions
private static object __evMessageSent = new object();
private static object __evMessageReceived = new object();
+ private static object __evMessageDeleted = new object();
public DeviceSession()
{
@@ -769,20 +770,24 @@ namespace TelegramBotBase.Sessions
///
public async Task API(Func> call)
{
- try
+ var numberOfTries = 0;
+ while (numberOfTries < DeviceSession.MaxNumberOfRetries)
{
- return await call(this.Client.TelegramClient);
- }
- catch (ApiRequestException ex)
- {
- if (ex.Parameters != null)
+ try
{
- await Task.Delay(ex.Parameters.RetryAfter);
+ return await call(Client.TelegramClient);
+ }
+ catch (ApiRequestException ex)
+ {
+ if (ex.ErrorCode != 429)
+ throw;
- return await call(this.Client.TelegramClient);
+ if (ex.Parameters != null)
+ await Task.Delay(ex.Parameters.RetryAfter * 1000);
+
+ numberOfTries++;
}
}
-
return default(T);
}
@@ -793,17 +798,23 @@ namespace TelegramBotBase.Sessions
///
public async Task API(Func call)
{
- try
+ var numberOfTries = 0;
+ while (numberOfTries < DeviceSession.MaxNumberOfRetries)
{
- await call(this.Client.TelegramClient);
- }
- catch (ApiRequestException ex)
- {
- if (ex.Parameters != null)
+ try
{
- await Task.Delay(ex.Parameters.RetryAfter);
+ await call(Client.TelegramClient);
+ return;
+ }
+ catch (ApiRequestException ex)
+ {
+ if (ex.ErrorCode != 429)
+ throw;
- await call(this.Client.TelegramClient);
+ if (ex.Parameters != null)
+ await Task.Delay(ex.Parameters.RetryAfter * 1000);
+
+ numberOfTries++;
}
}
}
@@ -853,6 +864,37 @@ namespace TelegramBotBase.Sessions
(this.__Events[__evMessageReceived] as EventHandler)?.Invoke(this, e);
}
+ ///
+ /// Eventhandler for deleting messages
+ ///
+ public event EventHandler MessageDeleted
+ {
+ add
+ {
+ this.__Events.AddHandler(__evMessageDeleted, value);
+ }
+ remove
+ {
+ this.__Events.RemoveHandler(__evMessageDeleted, value);
+ }
+ }
+
+
+ public void OnMessageDeleted(MessageDeletedEventArgs e)
+ {
+ (this.__Events[__evMessageDeleted] as EventHandler)?.Invoke(this, e);
+ }
+
#endregion
+
+ #region "Static"
+
+ ///
+ /// Indicates the maximum number of times a request that received error
+ /// 429 will be sent again after a timeout until it receives code 200 or an error code not equal to 429.
+ ///
+ public static uint MaxNumberOfRetries { get; set; }
+
+ #endregion "Static"
}
}
diff --git a/TelegramBotBaseTest/Tests/Controls/MultiToggleButtons.cs b/TelegramBotBaseTest/Tests/Controls/MultiToggleButtons.cs
new file mode 100644
index 0000000..b38abb4
--- /dev/null
+++ b/TelegramBotBaseTest/Tests/Controls/MultiToggleButtons.cs
@@ -0,0 +1,53 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using TelegramBotBase.Args;
+using TelegramBotBase.Controls;
+using TelegramBotBase.Controls.Inline;
+using TelegramBotBase.Form;
+
+namespace TelegramBotBaseTest.Tests.Controls
+{
+ public class MultiToggleButtons : AutoCleanForm
+ {
+ public MultiToggleButtons()
+ {
+ this.DeleteMode = TelegramBotBase.Enums.eDeleteMode.OnLeavingForm;
+
+ this.Init += ToggleButtons_Init;
+ }
+
+ private async Task ToggleButtons_Init(object sender, InitEventArgs e)
+ {
+
+ var mtb = new MultiToggleButton();
+
+ mtb.Options = new List() { new ButtonBase("Option 1", "1"), new ButtonBase("Option 2", "2"), new ButtonBase("Option 3", "3") };
+ mtb.SelectedOption = mtb.Options.FirstOrDefault();
+ mtb.Toggled += Tb_Toggled;
+ this.AddControl(mtb);
+
+ mtb = new MultiToggleButton();
+
+ mtb.Options = new List() { new ButtonBase("Option 4", "4"), new ButtonBase("Option 5", "5"), new ButtonBase("Option 6", "6") };
+ mtb.SelectedOption = mtb.Options.FirstOrDefault();
+ mtb.AllowEmptySelection = false;
+ mtb.Toggled += Tb_Toggled;
+ this.AddControl(mtb);
+ }
+
+ private void Tb_Toggled(object sender, EventArgs e)
+ {
+ var tb = sender as MultiToggleButton;
+ if (tb.SelectedOption != null)
+ {
+ Console.WriteLine(tb.ID.ToString() + " was pressed, and toggled to " + tb.SelectedOption.Value);
+ return;
+ }
+
+ Console.WriteLine("Selection for " + tb.ID.ToString() + " has been removed.");
+ }
+ }
+}
diff --git a/TelegramBotBaseTest/Tests/Menu.cs b/TelegramBotBaseTest/Tests/Menu.cs
index d72d04f..57cf9fb 100644
--- a/TelegramBotBaseTest/Tests/Menu.cs
+++ b/TelegramBotBaseTest/Tests/Menu.cs
@@ -140,6 +140,17 @@ namespace TelegramBotBaseTest.Tests
await this.NavigateTo(tb);
break;
+
+ case "multitogglebuttons":
+
+ message.Handled = true;
+
+ var mtb = new Controls.MultiToggleButtons();
+
+ await this.NavigateTo(mtb);
+
+ break;
+
case "buttongrid":
message.Handled = true;
@@ -217,6 +228,8 @@ namespace TelegramBotBaseTest.Tests
btn.AddButtonRow(new ButtonBase("#11 ToggleButtons", new CallbackData("a", "togglebuttons").Serialize()));
+ btn.AddButtonRow(new ButtonBase("#11.2 MultiToggleButtons", new CallbackData("a", "multitogglebuttons").Serialize()));
+
btn.AddButtonRow(new ButtonBase("#12 ButtonGrid", new CallbackData("a", "buttongrid").Serialize()));
btn.AddButtonRow(new ButtonBase("#13 ButtonGrid Paging & Filter", new CallbackData("a", "buttongridfilter").Serialize()));
diff --git a/images/multitogglebutton.gif b/images/multitogglebutton.gif
new file mode 100644
index 0000000..b399eae
Binary files /dev/null and b/images/multitogglebutton.gif differ