Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8e29652148 | ||
|
|
5bb316d874 | ||
|
|
d2ae08771e | ||
|
|
9162c0894c | ||
|
|
e0ec133209 | ||
|
|
7004ee5963 | ||
|
|
ef8ca3c988 | ||
|
|
f021f12486 | ||
|
|
d06e1eaa52 | ||
|
|
23969881c1 | ||
|
|
9fa3df2889 | ||
|
|
6ed91224eb | ||
|
|
aabc7f04b7 | ||
|
|
71433c0e4e | ||
|
|
894d0799c8 | ||
|
|
6c2543630d | ||
|
|
84d18f6f45 | ||
|
|
5f49e25458 | ||
|
|
f28c9b1e22 | ||
|
|
0db0c00cd0 | ||
|
|
2158f53cde | ||
|
|
fd7d72b986 | ||
|
|
47a5b502b9 | ||
|
|
ce4c7b6f1c | ||
|
|
5bae650edc | ||
|
|
9eae63dae6 | ||
|
|
6f005114bc | ||
|
|
00440a50e8 | ||
|
|
ae9dd17ae3 | ||
|
|
be2660239a | ||
|
|
e88114049e | ||
|
|
177c198916 | ||
|
|
1f7a9900c4 | ||
|
|
d6051ce607 | ||
|
|
5613e84bc3 | ||
|
|
d52fd41467 | ||
|
|
8df6e4ce55 | ||
|
|
9012ec76b1 | ||
|
|
36fb40b6bd | ||
|
|
47aa8c2aaa | ||
|
|
1709631965 | ||
|
|
264a998052 | ||
|
|
a00aaacbfb | ||
|
|
bd908db867 | ||
|
|
e2c485aede | ||
|
|
c8936d0748 | ||
|
|
92f12735c8 | ||
|
|
8142b626b2 | ||
|
|
5dcbe04a73 | ||
|
|
e742ded371 | ||
|
|
706b0f522a | ||
|
|
61e3652edf | ||
|
|
c484edd427 | ||
|
|
181902336c | ||
|
|
dc364b5fd3 | ||
|
|
1fd4752c0e | ||
|
|
d84be50243 | ||
|
|
1caa71cd25 | ||
|
|
e81e5f1854 | ||
|
|
399e056a8f | ||
|
|
26c4f479fa | ||
|
|
72d94df907 | ||
|
|
31e0683699 | ||
|
|
676be49a62 | ||
|
|
5b67f334ff | ||
|
|
6a556af070 | ||
|
|
4910a04923 | ||
|
|
10f4e1b745 | ||
|
|
42b624c28f | ||
|
|
75013d51bd | ||
|
|
7f3bcfe418 | ||
|
|
f5e26924d8 | ||
|
|
884aa60fac | ||
|
|
adc18891e0 | ||
|
|
07eb4bef75 | ||
|
|
dfe64b22ab | ||
|
|
15a8b8897f | ||
|
|
91048b4f7c | ||
|
|
426bb078af | ||
|
|
63deb978a4 | ||
|
|
1a2b5818aa | ||
|
|
fc44b7d38c | ||
|
|
dc8cb81284 | ||
|
|
0202fc29a8 | ||
|
|
7e51126fd3 | ||
|
|
67e82acf20 | ||
|
|
c32fc2c3da | ||
|
|
4351fc7c68 | ||
|
|
80d43ac369 | ||
|
|
376ba68e8e | ||
|
|
6b404545df | ||
|
|
a524fef0d5 | ||
|
|
73ba36ea2b | ||
|
|
46160b54ae | ||
|
|
87690a3630 | ||
|
|
975a942993 | ||
|
|
4336ff1681 |
@@ -0,0 +1,2 @@
|
||||
github: #[MajMcCloud]
|
||||
custom: ["https://paypal.me/majmccloud", dahn.partners]
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<configuration>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
|
||||
</startup>
|
||||
</configuration>
|
||||
@@ -0,0 +1,69 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{673A56F5-6110-4AED-A68D-562FD6ED3EA6}</ProjectGuid>
|
||||
<OutputType>Exe</OutputType>
|
||||
<RootNamespace>AsyncFormUpdates</RootNamespace>
|
||||
<AssemblyName>AsyncFormUpdates</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
<Deterministic>true</Deterministic>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Newtonsoft.Json, Version=11.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Newtonsoft.Json.11.0.2\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="Telegram.Bot, Version=15.7.1.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Telegram.Bot.15.7.1\lib\net45\Telegram.Bot.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="forms\AsyncFormEdit.cs" />
|
||||
<Compile Include="forms\AsyncFormUpdate.cs" />
|
||||
<Compile Include="forms\Start.cs" />
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="App.config" />
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\TelegramBotBase\TelegramBotBase.csproj">
|
||||
<Project>{0bd16fb9-7ed4-4ccb-83eb-5cee538e1b6c}</Project>
|
||||
<Name>TelegramBotBase</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
||||
@@ -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<forms.Start> bot = null;
|
||||
|
||||
static void Main(string[] args)
|
||||
{
|
||||
String apiKey = "APIKey";
|
||||
|
||||
bot = new TelegramBotBase.BotBase<forms.Start>(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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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")]
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Newtonsoft.Json" version="11.0.2" targetFramework="net472" />
|
||||
<package id="System.Net.Requests" version="4.3.0" targetFramework="net472" />
|
||||
<package id="Telegram.Bot" version="15.7.1" targetFramework="net472" />
|
||||
</packages>
|
||||
@@ -73,6 +73,12 @@ Thanks !
|
||||
|
||||
* [Paging and Searching](#paging--searching)
|
||||
|
||||
* [TaggedButtonGrid](#tagged-button-grid)
|
||||
|
||||
* [CheckedButtonList](#checked-button-list)
|
||||
|
||||
* [MultiToggleButton](#multi-toggle-button)
|
||||
|
||||
- [Groups](#groups)
|
||||
* [SplitterForm](#splitter-form)
|
||||
|
||||
@@ -100,6 +106,16 @@ Thanks !
|
||||
|
||||
* [IgnoreState](#ignorestate)
|
||||
|
||||
|
||||
- [Navigation and NavigationController (v4.0.0)](#navigation-and-navigationcontroller)
|
||||
|
||||
* [As of Now](#as-of-now)
|
||||
|
||||
* [How to use](#how-to-use-)
|
||||
|
||||
|
||||
|
||||
|
||||
- [Examples](#examples)
|
||||
|
||||
---
|
||||
@@ -153,11 +169,9 @@ public class StartForm : FormBase
|
||||
|
||||
}
|
||||
|
||||
//Gets invoked during Navigation to this form
|
||||
public override async Task Init(params object[] param)
|
||||
{
|
||||
//Gets invoked during Navigation to this form
|
||||
|
||||
}
|
||||
//Init() got replaced with event handler
|
||||
|
||||
//Opened() got replaced with event handler
|
||||
|
||||
@@ -804,6 +818,15 @@ await this.NavigateTo(cd);
|
||||
#### Paging & Searching
|
||||
<img src="images/buttongrid_pagingfilter.gif?raw=true" />
|
||||
|
||||
### Tagged Button Grid
|
||||
<img src="images/taggedbuttongrid.gif?raw=true" />
|
||||
|
||||
### Checked Button List
|
||||
<img src="images/checkedbuttonlist.gif?raw=true" />
|
||||
|
||||
### Multi Toggle Button
|
||||
<img src="images/multitogglebutton.gif?raw=true" />
|
||||
|
||||
## Groups
|
||||
|
||||
For working with groups, there are multiple different tools which helps to work with and allows bot also to manage "Single-User" chats and group chats.
|
||||
@@ -885,6 +908,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));
|
||||
|
||||
@@ -1057,6 +1081,81 @@ public class Registration : STForm
|
||||
|
||||
```
|
||||
|
||||
## Navigation and NavigationController
|
||||
|
||||
### As of now
|
||||
|
||||
As from earlier topics on this readme you already know the default way for (cross) navigation between Forms.
|
||||
It will look something like this:
|
||||
|
||||
```
|
||||
|
||||
var f = new FormBase();
|
||||
await this.NavigateTo(f);
|
||||
|
||||
```
|
||||
|
||||
Depending on the model and structure of your bot it can make sense, to have more linear navigation instead of "cross" navigation.
|
||||
|
||||
In example you have a bot which shows a list of football teams. And when clicking on it you want to open the team details and latest matches.
|
||||
|
||||
After the matches you want to maybe switch to a different teams and take a look at their statistics and matches.
|
||||
|
||||
At some point, you "just" want to get back to the first team so like on Android your clicking the "back" button multiple times.
|
||||
|
||||
This can become really complicated, when not having some controller below which handle these "Push/Pop" calls.
|
||||
|
||||
Thats why I introduced a NavigationController class which manages these situations and the stack.
|
||||
|
||||
|
||||
### How to use ?
|
||||
|
||||
First you need to create a NavigationController instance at the same position in code, where you want to start the navigation.
|
||||
|
||||
You will use the current FormBase instance as a root class within the constructor. So you can later come back to this one.
|
||||
|
||||
**Tip**: *You can add also a completely new instance of i.e. a main menu form here to get back to it then. So you are free to choose.*
|
||||
|
||||
We are using the same FormBase instance as above.
|
||||
|
||||
|
||||
```
|
||||
|
||||
var nc = new NavigationController(this);
|
||||
|
||||
var f = new FormBase();
|
||||
|
||||
//Replace the current form in the context with the controller.
|
||||
await this.NavigateTo(nc);
|
||||
|
||||
//Push the new from onto the stack to render it
|
||||
nc.PushAsync(f);
|
||||
|
||||
```
|
||||
|
||||
|
||||
Later to open a new form use PushAsync again:
|
||||
|
||||
```
|
||||
|
||||
await this.NavigationController.PushAsync(newForm);
|
||||
|
||||
```
|
||||
|
||||
When you want to go back one Form on the stack use PopAsync:
|
||||
|
||||
|
||||
```
|
||||
|
||||
await this.NavigationController.PopAsync();
|
||||
|
||||
```
|
||||
|
||||
**Notice**: *By default the NavigationController has ForceCleanupOnLastPop enabled, which means that when the stack is again at 1 (due to PopAsync or PopToRootAsync calls) it will replace the controller automatically with the root form you have given to the constructor at the beginning.*
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## Examples
|
||||
|
||||
@@ -1070,6 +1169,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.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using TelegramBotBase.Controls.Hybrid;
|
||||
using TelegramBotBase.Form;
|
||||
|
||||
namespace TelegramBotBase.Args
|
||||
@@ -14,6 +15,12 @@ namespace TelegramBotBase.Args
|
||||
{
|
||||
public ButtonBase Button { get; set; }
|
||||
|
||||
public int Index { get; set; }
|
||||
|
||||
public object Tag { get; set; }
|
||||
|
||||
public ButtonRow Row { get; set; }
|
||||
|
||||
|
||||
public ButtonClickedEventArgs()
|
||||
{
|
||||
@@ -23,7 +30,20 @@ namespace TelegramBotBase.Args
|
||||
public ButtonClickedEventArgs(ButtonBase button)
|
||||
{
|
||||
this.Button = button;
|
||||
this.Index = -1;
|
||||
}
|
||||
|
||||
public ButtonClickedEventArgs(ButtonBase button, int Index)
|
||||
{
|
||||
this.Button = button;
|
||||
this.Index = Index;
|
||||
}
|
||||
|
||||
public ButtonClickedEventArgs(ButtonBase button, int Index, ButtonRow row)
|
||||
{
|
||||
this.Button = button;
|
||||
this.Index = Index;
|
||||
this.Row = row;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using TelegramBotBase.Controls.Hybrid;
|
||||
using TelegramBotBase.Form;
|
||||
|
||||
namespace TelegramBotBase.Args
|
||||
{
|
||||
public class CheckedChangedEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains the index of the row where the button is inside.
|
||||
/// Contains -1 when it is a layout button or not found.
|
||||
/// </summary>
|
||||
public int Index { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Contains all buttons within this row, excluding the checkbox.
|
||||
/// </summary>
|
||||
public ButtonRow Row { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Contains the new checked status of the row.
|
||||
/// </summary>
|
||||
public bool Checked { get; set; }
|
||||
|
||||
|
||||
public CheckedChangedEventArgs()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public CheckedChangedEventArgs(ButtonRow row, int Index, bool Checked)
|
||||
{
|
||||
this.Row = row;
|
||||
this.Index = Index;
|
||||
this.Checked = Checked;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -54,5 +54,10 @@ namespace TelegramBotBase.Args
|
||||
return false;
|
||||
}
|
||||
|
||||
public object GetObject(String key)
|
||||
{
|
||||
return Values[key];
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -19,9 +19,16 @@ namespace TelegramBotBase.Args
|
||||
|
||||
public Message Message { get; set; }
|
||||
|
||||
public MessageSentEventArgs(Message message)
|
||||
/// <summary>
|
||||
/// Contains the element, which has called the method.
|
||||
/// </summary>
|
||||
public Type Origin { get; set; }
|
||||
|
||||
|
||||
public MessageSentEventArgs(Message message, Type Origin)
|
||||
{
|
||||
this.Message = message;
|
||||
this.Origin = Origin;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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; }
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace TelegramBotBase.Args
|
||||
{
|
||||
public class RenderViewEventArgs : EventArgs
|
||||
{
|
||||
public int CurrentView { get; set; }
|
||||
|
||||
|
||||
public RenderViewEventArgs(int ViewIndex)
|
||||
{
|
||||
|
||||
CurrentView = ViewIndex;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -32,6 +32,10 @@ namespace TelegramBotBase.Args
|
||||
{
|
||||
Values[key] = value;
|
||||
}
|
||||
public void SetObject(String key, object value)
|
||||
{
|
||||
Values[key] = value;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,14 @@ namespace TelegramBotBase.Base
|
||||
/// </summary>
|
||||
public bool Enabled { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Get invoked when control will be added to a form and invoked.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public virtual void Init()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public virtual async Task Load(MessageResult result)
|
||||
{
|
||||
@@ -59,6 +67,10 @@ namespace TelegramBotBase.Base
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Will be called on a cleanup.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public virtual async Task Cleanup()
|
||||
{
|
||||
|
||||
|
||||
@@ -109,6 +109,12 @@ namespace TelegramBotBase.Base
|
||||
return new InputOnlineFile(encryptedContent, this.Document.FileName);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Downloads a file and saves it to the given path.
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
/// <returns></returns>
|
||||
public async Task DownloadDocument(String path)
|
||||
{
|
||||
var file = await this.Client.TelegramClient.GetFileAsync(this.Document.FileId);
|
||||
@@ -118,6 +124,42 @@ namespace TelegramBotBase.Base
|
||||
fs.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Downloads the document and returns an byte array.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<byte[]> DownloadRawDocument()
|
||||
{
|
||||
MemoryStream ms = new MemoryStream();
|
||||
await this.Client.TelegramClient.GetInfoAndDownloadFileAsync(this.Document.FileId, ms);
|
||||
return ms.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Downloads a document and returns it as string. (txt,csv,etc) Default encoding ist UTF8.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<String> DownloadRawTextDocument()
|
||||
{
|
||||
return await DownloadRawTextDocument(Encoding.UTF8);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Downloads a document and returns it as string. (txt,csv,etc)
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<String> DownloadRawTextDocument(Encoding encoding)
|
||||
{
|
||||
MemoryStream ms = new MemoryStream();
|
||||
await this.Client.TelegramClient.GetInfoAndDownloadFileAsync(this.Document.FileId, ms);
|
||||
|
||||
ms.Position = 0;
|
||||
|
||||
var sr = new StreamReader(ms, encoding);
|
||||
|
||||
return sr.ReadToEnd();
|
||||
}
|
||||
|
||||
public async Task<InputOnlineFile> DownloadVideo()
|
||||
{
|
||||
var encryptedContent = new System.IO.MemoryStream(this.Video.FileSize);
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using TelegramBotBase.Args;
|
||||
using TelegramBotBase.Base;
|
||||
using TelegramBotBase.Form.Navigation;
|
||||
using TelegramBotBase.Sessions;
|
||||
using static TelegramBotBase.Base.Async;
|
||||
|
||||
@@ -17,6 +18,8 @@ namespace TelegramBotBase.Form
|
||||
public class FormBase : IDisposable
|
||||
{
|
||||
|
||||
public NavigationController NavigationController { get; set; }
|
||||
|
||||
public DeviceSession Device { get; set; }
|
||||
|
||||
public MessageClient Client { get; set; }
|
||||
@@ -55,7 +58,10 @@ namespace TelegramBotBase.Form
|
||||
if (this.Events[__evInit] == null)
|
||||
return;
|
||||
|
||||
var handler = this.Events[__evInit].GetInvocationList().Cast<AsyncEventHandler<InitEventArgs>>();
|
||||
var handler = this.Events[__evInit]?.GetInvocationList().Cast<AsyncEventHandler<InitEventArgs>>();
|
||||
if (handler == null)
|
||||
return;
|
||||
|
||||
foreach (var h in handler)
|
||||
{
|
||||
await Async.InvokeAllAsync<InitEventArgs>(h, this, e);
|
||||
@@ -84,7 +90,10 @@ namespace TelegramBotBase.Form
|
||||
if (this.Events[__evOpened] == null)
|
||||
return;
|
||||
|
||||
var handler = this.Events[__evOpened].GetInvocationList().Cast<AsyncEventHandler<EventArgs>>();
|
||||
var handler = this.Events[__evOpened]?.GetInvocationList().Cast<AsyncEventHandler<EventArgs>>();
|
||||
if (handler == null)
|
||||
return;
|
||||
|
||||
foreach (var h in handler)
|
||||
{
|
||||
await Async.InvokeAllAsync<EventArgs>(h, this, e);
|
||||
@@ -114,7 +123,10 @@ namespace TelegramBotBase.Form
|
||||
if (this.Events[__evClosed] == null)
|
||||
return;
|
||||
|
||||
var handler = this.Events[__evClosed].GetInvocationList().Cast<AsyncEventHandler<EventArgs>>();
|
||||
var handler = this.Events[__evClosed]?.GetInvocationList().Cast<AsyncEventHandler<EventArgs>>();
|
||||
if (handler == null)
|
||||
return;
|
||||
|
||||
foreach (var h in handler)
|
||||
{
|
||||
await Async.InvokeAllAsync<EventArgs>(h, this, e);
|
||||
@@ -171,7 +183,7 @@ namespace TelegramBotBase.Form
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <returns></returns>
|
||||
public async Task LoadControls(MessageResult message)
|
||||
public virtual async Task LoadControls(MessageResult message)
|
||||
{
|
||||
//Looking for the control by id, if not listened, raise event for all
|
||||
if (message.RawData?.StartsWith("#c") ?? false)
|
||||
@@ -219,7 +231,7 @@ namespace TelegramBotBase.Form
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <returns></returns>
|
||||
public async Task ActionControls(MessageResult message)
|
||||
public virtual async Task ActionControls(MessageResult message)
|
||||
{
|
||||
//Looking for the control by id, if not listened, raise event for all
|
||||
if (message.RawData.StartsWith("#c"))
|
||||
@@ -269,7 +281,7 @@ namespace TelegramBotBase.Form
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <returns></returns>
|
||||
public async Task RenderControls(MessageResult message)
|
||||
public virtual async Task RenderControls(MessageResult message)
|
||||
{
|
||||
foreach (var b in this.Controls)
|
||||
{
|
||||
@@ -391,9 +403,15 @@ namespace TelegramBotBase.Form
|
||||
/// <param name="control"></param>
|
||||
public void AddControl(ControlBase control)
|
||||
{
|
||||
//Duplicate check
|
||||
if (this.Controls.Contains(control))
|
||||
throw new ArgumentException("Control has been already added.");
|
||||
|
||||
control.ID = this.Controls.Count + 1;
|
||||
control.Device = this.Device;
|
||||
this.Controls.Add(control);
|
||||
|
||||
control.Init();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,11 +160,11 @@ namespace TelegramBotBase.Base
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <returns></returns>
|
||||
public async Task ConfirmAction(String message = "")
|
||||
public async Task ConfirmAction(String message = "", bool showAlert = false, String urlToOpen = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
await this.Client.TelegramClient.AnswerCallbackQueryAsync(this.RawCallbackData.CallbackQuery.Id, message);
|
||||
await this.Client.TelegramClient.AnswerCallbackQueryAsync(this.RawCallbackData.CallbackQuery.Id, message, showAlert, urlToOpen);
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -175,6 +184,10 @@ namespace TelegramBotBase.Base
|
||||
}
|
||||
}
|
||||
|
||||
internal MessageResult()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public MessageResult(Telegram.Bot.Args.MessageEventArgs rawdata)
|
||||
{
|
||||
|
||||
+198
-65
@@ -72,6 +72,7 @@ namespace TelegramBotBase
|
||||
{
|
||||
this.SystemSettings = new Dictionary<eSettings, uint>();
|
||||
|
||||
SetSetting(eSettings.MaxNumberOfRetries, 5);
|
||||
SetSetting(eSettings.NavigationMaximum, 10);
|
||||
SetSetting(eSettings.LogAllMessages, false);
|
||||
SetSetting(eSettings.SkipAllMessages, false);
|
||||
@@ -173,10 +174,12 @@ namespace TelegramBotBase
|
||||
{
|
||||
TelegramBotBase.Tools.Console.SetHandler(() =>
|
||||
{
|
||||
this.Sessions.SaveSessionStates(this.StateMachine);
|
||||
this.Sessions.SaveSessionStates();
|
||||
});
|
||||
}
|
||||
|
||||
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<T>(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<T>(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
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This will invoke the full message loop for the device even when no "userevent" like message or action has been raised.
|
||||
/// </summary>
|
||||
/// <param name="DeviceId">Contains the device/chat id of the device to update.</param>
|
||||
public async Task InvokeMessageLoop(long DeviceId)
|
||||
{
|
||||
var mr = new MessageResult();
|
||||
|
||||
await InvokeMessageLoop(DeviceId, mr);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This will invoke the full message loop for the device even when no "userevent" like message or action has been raised.
|
||||
/// </summary>
|
||||
/// <param name="DeviceId">Contains the device/chat id of the device to update.</param>
|
||||
/// <param name="e"></param>
|
||||
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<T>(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<T>(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));
|
||||
|
||||
}
|
||||
//}
|
||||
|
||||
/// <summary>
|
||||
/// This method will update all local created bot commands to the botfather.
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Telegram.Bot.Types;
|
||||
|
||||
namespace TelegramBotBase.Commands
|
||||
{
|
||||
public static class Extensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Adding the default /start command with a description.
|
||||
/// </summary>
|
||||
/// <param name="cmds"></param>
|
||||
/// <param name="description"></param>
|
||||
public static void AddStartCommand(this List<BotCommand> cmds, String description)
|
||||
{
|
||||
cmds.Add(new BotCommand() { Command = "start", Description = description });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adding the default /help command with a description.
|
||||
/// </summary>
|
||||
/// <param name="cmds"></param>
|
||||
/// <param name="description"></param>
|
||||
public static void AddHelpCommand(this List<BotCommand> cmds, String description)
|
||||
{
|
||||
cmds.Add(new BotCommand() { Command = "help", Description = description });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adding the default /settings command with a description.
|
||||
/// </summary>
|
||||
/// <param name="cmds"></param>
|
||||
/// <param name="description"></param>
|
||||
public static void AddSettingsCommand(this List<BotCommand> cmds, String description)
|
||||
{
|
||||
cmds.Add(new BotCommand() { Command = "settings", Description = description });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,5 +21,7 @@ namespace TelegramBotBase.Constants
|
||||
|
||||
public const int MaxReplyKeyboardCols = 12;
|
||||
|
||||
public const int MessageDeletionsPerSecond = 30;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+271
-152
@@ -10,12 +10,13 @@ using Telegram.Bot.Types.Enums;
|
||||
using Telegram.Bot.Types.ReplyMarkups;
|
||||
using TelegramBotBase.Args;
|
||||
using TelegramBotBase.Base;
|
||||
using TelegramBotBase.Datasources;
|
||||
using TelegramBotBase.Enums;
|
||||
using TelegramBotBase.Exceptions;
|
||||
using TelegramBotBase.Form;
|
||||
using static TelegramBotBase.Base.Async;
|
||||
|
||||
namespace TelegramBotBase.Controls
|
||||
namespace TelegramBotBase.Controls.Hybrid
|
||||
{
|
||||
public class ButtonGrid : Base.ControlBase
|
||||
{
|
||||
@@ -30,7 +31,26 @@ namespace TelegramBotBase.Controls
|
||||
|
||||
private readonly EventHandlerList Events = new EventHandlerList();
|
||||
|
||||
public ButtonForm ButtonsForm { get; set; }
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Obsolete("This property is obsolete. Please use the DataSource property instead.")]
|
||||
public ButtonForm ButtonsForm
|
||||
{
|
||||
get
|
||||
{
|
||||
return DataSource.ButtonForm;
|
||||
}
|
||||
set
|
||||
{
|
||||
DataSource = new ButtonFormDataSource(value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Data source of the items.
|
||||
/// </summary>
|
||||
public ButtonFormDataSource DataSource { get; set; }
|
||||
|
||||
public int? MessageId { get; set; }
|
||||
|
||||
@@ -47,6 +67,11 @@ namespace TelegramBotBase.Controls
|
||||
|
||||
public bool DeletePreviousMessage { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Removes the reply message from a user.
|
||||
/// </summary>
|
||||
public bool DeleteReplyMessage { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Parsemode of the message.
|
||||
/// </summary>
|
||||
@@ -84,12 +109,12 @@ namespace TelegramBotBase.Controls
|
||||
/// <summary>
|
||||
/// Layout of the buttons which should be displayed always on top.
|
||||
/// </summary>
|
||||
public List<ButtonBase> HeadLayoutButtonRow { get; set; }
|
||||
public ButtonRow HeadLayoutButtonRow { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Layout of columns which should be displayed below the header
|
||||
/// </summary>
|
||||
public List<ButtonBase> SubHeadLayoutButtonRow { get; set; }
|
||||
public ButtonRow SubHeadLayoutButtonRow { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Defines which type of Button Keyboard should be rendered.
|
||||
@@ -118,8 +143,7 @@ namespace TelegramBotBase.Controls
|
||||
|
||||
public ButtonGrid()
|
||||
{
|
||||
this.ButtonsForm = new ButtonForm();
|
||||
|
||||
this.DataSource = new ButtonFormDataSource();
|
||||
|
||||
}
|
||||
|
||||
@@ -131,7 +155,7 @@ namespace TelegramBotBase.Controls
|
||||
|
||||
public ButtonGrid(ButtonForm form)
|
||||
{
|
||||
this.ButtonsForm = form;
|
||||
this.DataSource = new ButtonFormDataSource(form);
|
||||
}
|
||||
|
||||
|
||||
@@ -149,13 +173,32 @@ namespace TelegramBotBase.Controls
|
||||
|
||||
public async Task OnButtonClicked(ButtonClickedEventArgs e)
|
||||
{
|
||||
var handler = this.Events[__evButtonClicked].GetInvocationList().Cast<AsyncEventHandler<ButtonClickedEventArgs>>();
|
||||
var handler = this.Events[__evButtonClicked]?.GetInvocationList().Cast<AsyncEventHandler<ButtonClickedEventArgs>>();
|
||||
if (handler == null)
|
||||
return;
|
||||
|
||||
foreach (var h in handler)
|
||||
{
|
||||
await Async.InvokeAllAsync<ButtonClickedEventArgs>(h, this, e);
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
@@ -164,67 +207,95 @@ namespace TelegramBotBase.Controls
|
||||
if (!result.IsFirstHandler)
|
||||
return;
|
||||
|
||||
var button = HeadLayoutButtonRow?.FirstOrDefault(a => a.Text.Trim() == result.MessageText)
|
||||
?? SubHeadLayoutButtonRow?.FirstOrDefault(a => a.Text.Trim() == result.MessageText)
|
||||
?? ButtonsForm.ToList().FirstOrDefault(a => a.Text.Trim() == result.MessageText);
|
||||
if (result.MessageText == null || result.MessageText == "")
|
||||
return;
|
||||
|
||||
if (button == null)
|
||||
var matches = new List<ButtonRow>();
|
||||
ButtonRow match = null;
|
||||
int index = -1;
|
||||
|
||||
if (HeadLayoutButtonRow?.Matches(result.MessageText) ?? false)
|
||||
{
|
||||
if (result.MessageText == null)
|
||||
return;
|
||||
match = HeadLayoutButtonRow;
|
||||
goto check;
|
||||
}
|
||||
|
||||
if (result.MessageText == PreviousPageLabel)
|
||||
{
|
||||
if (this.CurrentPageIndex > 0)
|
||||
this.CurrentPageIndex--;
|
||||
if (SubHeadLayoutButtonRow?.Matches(result.MessageText) ?? false)
|
||||
{
|
||||
match = SubHeadLayoutButtonRow;
|
||||
goto check;
|
||||
}
|
||||
|
||||
this.Updated();
|
||||
}
|
||||
else if (result.MessageText == NextPageLabel)
|
||||
{
|
||||
if (this.CurrentPageIndex < this.PageCount - 1)
|
||||
this.CurrentPageIndex++;
|
||||
|
||||
this.Updated();
|
||||
}
|
||||
else if (this.EnableSearch)
|
||||
{
|
||||
if (result.MessageText.StartsWith("🔍"))
|
||||
{
|
||||
//Sent note about searching
|
||||
if (this.SearchQuery == null)
|
||||
{
|
||||
await this.Device.Send(this.SearchLabel);
|
||||
}
|
||||
|
||||
this.SearchQuery = null;
|
||||
this.Updated();
|
||||
return;
|
||||
}
|
||||
|
||||
this.SearchQuery = result.MessageText;
|
||||
|
||||
if (this.SearchQuery != null && this.SearchQuery != "")
|
||||
{
|
||||
this.CurrentPageIndex = 0;
|
||||
this.Updated();
|
||||
}
|
||||
|
||||
}
|
||||
var br = DataSource.FindRow(result.MessageText);
|
||||
if (br != null)
|
||||
{
|
||||
match = br.Item1;
|
||||
index = br.Item2;
|
||||
}
|
||||
|
||||
|
||||
//var button = HeadLayoutButtonRow?. .FirstOrDefault(a => a.Text.Trim() == result.MessageText)
|
||||
// ?? SubHeadLayoutButtonRow?.FirstOrDefault(a => a.Text.Trim() == result.MessageText);
|
||||
|
||||
// bf.ToList().FirstOrDefault(a => a.Text.Trim() == result.MessageText)
|
||||
|
||||
//var index = bf.FindRowByButton(button);
|
||||
|
||||
check:
|
||||
|
||||
//Remove button click message
|
||||
if (this.DeleteReplyMessage)
|
||||
await Device.DeleteMessage(result.MessageId);
|
||||
|
||||
if (match != null)
|
||||
{
|
||||
await OnButtonClicked(new ButtonClickedEventArgs(match.GetButtonMatch(result.MessageText), index, match));
|
||||
|
||||
result.Handled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
await OnButtonClicked(new ButtonClickedEventArgs(button));
|
||||
if (result.MessageText == PreviousPageLabel)
|
||||
{
|
||||
if (this.CurrentPageIndex > 0)
|
||||
this.CurrentPageIndex--;
|
||||
|
||||
this.Updated();
|
||||
}
|
||||
else if (result.MessageText == NextPageLabel)
|
||||
{
|
||||
if (this.CurrentPageIndex < this.PageCount - 1)
|
||||
this.CurrentPageIndex++;
|
||||
|
||||
this.Updated();
|
||||
}
|
||||
else if (this.EnableSearch)
|
||||
{
|
||||
if (result.MessageText.StartsWith("🔍"))
|
||||
{
|
||||
//Sent note about searching
|
||||
if (this.SearchQuery == null)
|
||||
{
|
||||
await this.Device.Send(this.SearchLabel);
|
||||
}
|
||||
|
||||
this.SearchQuery = null;
|
||||
this.Updated();
|
||||
return;
|
||||
}
|
||||
|
||||
this.SearchQuery = result.MessageText;
|
||||
|
||||
if (this.SearchQuery != null && this.SearchQuery != "")
|
||||
{
|
||||
this.CurrentPageIndex = 0;
|
||||
this.Updated();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//Remove button click message
|
||||
if (this.DeletePreviousMessage)
|
||||
await Device.DeleteMessage(result.MessageId);
|
||||
|
||||
result.Handled = true;
|
||||
|
||||
}
|
||||
|
||||
@@ -236,46 +307,69 @@ namespace TelegramBotBase.Controls
|
||||
if (!result.IsFirstHandler)
|
||||
return;
|
||||
|
||||
//Find clicked button depending on Text or Value (depending on markup type)
|
||||
if (this.KeyboardType != eKeyboardType.InlineKeyBoard)
|
||||
return;
|
||||
|
||||
await result.ConfirmAction(this.ConfirmationText ?? "");
|
||||
|
||||
//Find clicked button depending on Text or Value (depending on markup type)
|
||||
switch (this.KeyboardType)
|
||||
ButtonRow match = null;
|
||||
int index = -1;
|
||||
|
||||
if (HeadLayoutButtonRow?.Matches(result.RawData, false) ?? false)
|
||||
{
|
||||
case eKeyboardType.InlineKeyBoard:
|
||||
match = HeadLayoutButtonRow;
|
||||
goto check;
|
||||
}
|
||||
|
||||
var button = HeadLayoutButtonRow?.FirstOrDefault(a => a.Value == result.RawData)
|
||||
?? SubHeadLayoutButtonRow?.FirstOrDefault(a => a.Value == result.RawData)
|
||||
?? ButtonsForm.ToList().FirstOrDefault(a => a.Value == result.RawData);
|
||||
if (SubHeadLayoutButtonRow?.Matches(result.RawData, false) ?? false)
|
||||
{
|
||||
match = SubHeadLayoutButtonRow;
|
||||
goto check;
|
||||
}
|
||||
|
||||
if (button == null)
|
||||
{
|
||||
switch (result.RawData)
|
||||
{
|
||||
case "$previous$":
|
||||
|
||||
if (this.CurrentPageIndex > 0)
|
||||
this.CurrentPageIndex--;
|
||||
|
||||
this.Updated();
|
||||
|
||||
break;
|
||||
case "$next$":
|
||||
|
||||
if (this.CurrentPageIndex < this.PageCount - 1)
|
||||
this.CurrentPageIndex++;
|
||||
|
||||
this.Updated();
|
||||
|
||||
break;
|
||||
}
|
||||
var br = DataSource.FindRow(result.RawData, false);
|
||||
if (br != null)
|
||||
{
|
||||
match = br.Item1;
|
||||
index = br.Item2;
|
||||
}
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
await OnButtonClicked(new ButtonClickedEventArgs(button));
|
||||
//var bf = DataSource.ButtonForm;
|
||||
|
||||
result.Handled = true;
|
||||
//var button = HeadLayoutButtonRow?.FirstOrDefault(a => a.Value == result.RawData)
|
||||
// ?? SubHeadLayoutButtonRow?.FirstOrDefault(a => a.Value == result.RawData)
|
||||
// ?? bf.ToList().FirstOrDefault(a => a.Value == result.RawData);
|
||||
|
||||
//var index = bf.FindRowByButton(button);
|
||||
|
||||
check:
|
||||
if (match != null)
|
||||
{
|
||||
await OnButtonClicked(new ButtonClickedEventArgs(match.GetButtonMatch(result.RawData, false), index, match));
|
||||
|
||||
result.Handled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
switch (result.RawData)
|
||||
{
|
||||
case "$previous$":
|
||||
|
||||
if (this.CurrentPageIndex > 0)
|
||||
this.CurrentPageIndex--;
|
||||
|
||||
this.Updated();
|
||||
|
||||
break;
|
||||
case "$next$":
|
||||
|
||||
if (this.CurrentPageIndex < this.PageCount - 1)
|
||||
this.CurrentPageIndex++;
|
||||
|
||||
this.Updated();
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -291,28 +385,28 @@ namespace TelegramBotBase.Controls
|
||||
{
|
||||
case eKeyboardType.InlineKeyBoard:
|
||||
|
||||
if (ButtonsForm.Rows > Constants.Telegram.MaxInlineKeyBoardRows && !this.EnablePaging)
|
||||
if (DataSource.RowCount > Constants.Telegram.MaxInlineKeyBoardRows && !this.EnablePaging)
|
||||
{
|
||||
throw new MaximumRowsReachedException() { Value = ButtonsForm.Rows, Maximum = Constants.Telegram.MaxInlineKeyBoardRows };
|
||||
throw new MaximumRowsReachedException() { Value = DataSource.RowCount, Maximum = Constants.Telegram.MaxInlineKeyBoardRows };
|
||||
}
|
||||
|
||||
if (ButtonsForm.Cols > Constants.Telegram.MaxInlineKeyBoardCols)
|
||||
if (DataSource.ColumnCount > Constants.Telegram.MaxInlineKeyBoardCols)
|
||||
{
|
||||
throw new MaximumColsException() { Value = ButtonsForm.Rows, Maximum = Constants.Telegram.MaxInlineKeyBoardCols };
|
||||
throw new MaximumColsException() { Value = DataSource.ColumnCount, Maximum = Constants.Telegram.MaxInlineKeyBoardCols };
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case eKeyboardType.ReplyKeyboard:
|
||||
|
||||
if (ButtonsForm.Rows > Constants.Telegram.MaxReplyKeyboardRows && !this.EnablePaging)
|
||||
if (DataSource.RowCount > Constants.Telegram.MaxReplyKeyboardRows && !this.EnablePaging)
|
||||
{
|
||||
throw new MaximumRowsReachedException() { Value = ButtonsForm.Rows, Maximum = Constants.Telegram.MaxReplyKeyboardRows };
|
||||
throw new MaximumRowsReachedException() { Value = DataSource.RowCount, Maximum = Constants.Telegram.MaxReplyKeyboardRows };
|
||||
}
|
||||
|
||||
if (ButtonsForm.Cols > Constants.Telegram.MaxReplyKeyboardCols)
|
||||
if (DataSource.ColumnCount > Constants.Telegram.MaxReplyKeyboardCols)
|
||||
{
|
||||
throw new MaximumColsException() { Value = ButtonsForm.Rows, Maximum = Constants.Telegram.MaxReplyKeyboardCols };
|
||||
throw new MaximumColsException() { Value = DataSource.ColumnCount, Maximum = Constants.Telegram.MaxReplyKeyboardCols };
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -329,22 +423,21 @@ namespace TelegramBotBase.Controls
|
||||
|
||||
this.RenderNecessary = false;
|
||||
|
||||
Message m = null;
|
||||
ButtonForm form = this.DataSource.PickItems(CurrentPageIndex * ItemRowsPerPage, ItemRowsPerPage, (this.EnableSearch ? this.SearchQuery : null));
|
||||
|
||||
ButtonForm form = this.ButtonsForm;
|
||||
|
||||
if (this.EnableSearch && this.SearchQuery != null && this.SearchQuery != "")
|
||||
{
|
||||
form = form.FilterDuplicate(this.SearchQuery, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
form = form.Duplicate();
|
||||
}
|
||||
//if (this.EnableSearch && this.SearchQuery != null && this.SearchQuery != "")
|
||||
//{
|
||||
// form = form.FilterDuplicate(this.SearchQuery, true);
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// form = form.Duplicate();
|
||||
//}
|
||||
|
||||
if (this.EnablePaging)
|
||||
{
|
||||
form = GeneratePagingView(form);
|
||||
IntegratePagingView(form);
|
||||
}
|
||||
|
||||
if (this.HeadLayoutButtonRow != null && HeadLayoutButtonRow.Count > 0)
|
||||
@@ -364,26 +457,37 @@ namespace TelegramBotBase.Controls
|
||||
}
|
||||
}
|
||||
|
||||
Message m = null;
|
||||
|
||||
switch (this.KeyboardType)
|
||||
{
|
||||
//Reply Keyboard could only be updated with a new keyboard.
|
||||
case eKeyboardType.ReplyKeyboard:
|
||||
|
||||
if (this.MessageId != null)
|
||||
|
||||
if (form.Count == 0)
|
||||
{
|
||||
if (form.Count == 0)
|
||||
if (this.MessageId != null)
|
||||
{
|
||||
await this.Device.HideReplyKeyboard();
|
||||
this.MessageId = null;
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.DeletePreviousMessage)
|
||||
await this.Device.DeleteMessage(this.MessageId.Value);
|
||||
return;
|
||||
}
|
||||
|
||||
if (form.Count == 0)
|
||||
return;
|
||||
//if (this.MessageId != null)
|
||||
//{
|
||||
// if (form.Count == 0)
|
||||
// {
|
||||
// await this.Device.HideReplyKeyboard();
|
||||
// this.MessageId = null;
|
||||
// return;
|
||||
// }
|
||||
//}
|
||||
|
||||
//if (form.Count == 0)
|
||||
// return;
|
||||
|
||||
|
||||
var rkm = (ReplyKeyboardMarkup)form;
|
||||
@@ -391,18 +495,28 @@ namespace TelegramBotBase.Controls
|
||||
rkm.OneTimeKeyboard = this.OneTimeKeyboard;
|
||||
m = await this.Device.Send(this.Title, rkm, disableNotification: true, parseMode: MessageParseMode, MarkdownV2AutoEscape: false);
|
||||
|
||||
//Prevent flicker of keyboard
|
||||
if (this.DeletePreviousMessage && this.MessageId != null)
|
||||
await this.Device.DeleteMessage(this.MessageId.Value);
|
||||
|
||||
break;
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -415,47 +529,31 @@ namespace TelegramBotBase.Controls
|
||||
|
||||
}
|
||||
|
||||
private ButtonForm GeneratePagingView(ButtonForm dataForm)
|
||||
private void IntegratePagingView(ButtonForm dataForm)
|
||||
{
|
||||
|
||||
ButtonForm bf = new ButtonForm();
|
||||
|
||||
|
||||
for (int i = 0; i < this.MaximumRow - LayoutRows; i++)
|
||||
{
|
||||
int it = (this.CurrentPageIndex * (this.MaximumRow - LayoutRows)) + i;
|
||||
|
||||
if (it > dataForm.Rows - 1)
|
||||
break;
|
||||
|
||||
bf.AddButtonRow(dataForm[it]);
|
||||
}
|
||||
|
||||
//No Items
|
||||
if (this.ButtonsForm.Count == 0)
|
||||
if (dataForm.Rows == 0)
|
||||
{
|
||||
bf.AddButtonRow(new ButtonBase(NoItemsLabel, "$"));
|
||||
dataForm.AddButtonRow(new ButtonBase(NoItemsLabel, "$"));
|
||||
}
|
||||
|
||||
if (this.IsNavigationBarVisible)
|
||||
{
|
||||
//🔍
|
||||
List<ButtonBase> lst = new List<ButtonBase>();
|
||||
lst.Add(new ButtonBase(PreviousPageLabel, "$previous$"));
|
||||
lst.Add(new ButtonBase(String.Format(Localizations.Default.Language["ButtonGrid_CurrentPage"], this.CurrentPageIndex + 1, this.PageCount), "$site$"));
|
||||
lst.Add(new ButtonBase(NextPageLabel, "$next$"));
|
||||
ButtonRow row = new ButtonRow();
|
||||
row.Add(new ButtonBase(PreviousPageLabel, "$previous$"));
|
||||
row.Add(new ButtonBase(String.Format(Localizations.Default.Language["ButtonGrid_CurrentPage"], this.CurrentPageIndex + 1, this.PageCount), "$site$"));
|
||||
row.Add(new ButtonBase(NextPageLabel, "$next$"));
|
||||
|
||||
if (this.EnableSearch)
|
||||
{
|
||||
lst.Insert(2, new ButtonBase("🔍 " + (this.SearchQuery ?? ""), "$search$"));
|
||||
row.Insert(2, new ButtonBase("🔍 " + (this.SearchQuery ?? ""), "$search$"));
|
||||
}
|
||||
|
||||
bf.InsertButtonRow(0, lst);
|
||||
dataForm.InsertButtonRow(0, row);
|
||||
|
||||
bf.AddButtonRow(lst);
|
||||
dataForm.AddButtonRow(row);
|
||||
}
|
||||
|
||||
return bf;
|
||||
}
|
||||
|
||||
public bool PagingNecessary
|
||||
@@ -517,7 +615,7 @@ namespace TelegramBotBase.Controls
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.LayoutRows + ButtonsForm.Rows;
|
||||
return this.LayoutRows + DataSource.RowCount;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -544,24 +642,40 @@ namespace TelegramBotBase.Controls
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the number of item rows per page.
|
||||
/// </summary>
|
||||
public int ItemRowsPerPage
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.MaximumRow - this.LayoutRows;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the number of pages.
|
||||
/// </summary>
|
||||
public int PageCount
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.ButtonsForm.Count == 0)
|
||||
if (DataSource.RowCount == 0)
|
||||
return 1;
|
||||
|
||||
var bf = this.ButtonsForm;
|
||||
//var bf = this.DataSource.PickAllItems(this.EnableSearch ? this.SearchQuery : null);
|
||||
|
||||
if (this.EnableSearch && this.SearchQuery != null && this.SearchQuery != "")
|
||||
{
|
||||
bf = bf.FilterDuplicate(this.SearchQuery);
|
||||
}
|
||||
var max = this.DataSource.CalculateMax(this.EnableSearch ? this.SearchQuery : null);
|
||||
|
||||
if (bf.Rows == 0)
|
||||
//if (this.EnableSearch && this.SearchQuery != null && this.SearchQuery != "")
|
||||
//{
|
||||
// bf = bf.FilterDuplicate(this.SearchQuery);
|
||||
//}
|
||||
|
||||
if (max == 0)
|
||||
return 1;
|
||||
|
||||
return (int)Math.Ceiling((decimal)(bf.Rows / (decimal)(MaximumRow - 3)));
|
||||
return (int)Math.Ceiling((decimal)((decimal)max / (decimal)ItemRowsPerPage));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -572,6 +686,11 @@ namespace TelegramBotBase.Controls
|
||||
{
|
||||
this.Updated();
|
||||
}
|
||||
else
|
||||
{
|
||||
//Remove event handler
|
||||
this.Device.MessageDeleted -= Device_MessageDeleted;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -0,0 +1,112 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using TelegramBotBase.Form;
|
||||
|
||||
namespace TelegramBotBase.Controls.Hybrid
|
||||
{
|
||||
[DebuggerDisplay("{Count} columns")]
|
||||
public class ButtonRow
|
||||
{
|
||||
|
||||
List<ButtonBase> __buttons = new List<ButtonBase>();
|
||||
|
||||
public ButtonRow()
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
public ButtonRow(params ButtonBase[] buttons)
|
||||
{
|
||||
__buttons = buttons.ToList();
|
||||
}
|
||||
|
||||
|
||||
public ButtonBase this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
return __buttons[index];
|
||||
}
|
||||
}
|
||||
|
||||
public int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
return __buttons.Count;
|
||||
}
|
||||
}
|
||||
|
||||
public void Add(ButtonBase button)
|
||||
{
|
||||
__buttons.Add(button);
|
||||
}
|
||||
|
||||
public void AddRange(ButtonBase button)
|
||||
{
|
||||
__buttons.Add(button);
|
||||
}
|
||||
|
||||
public void Insert(int index, ButtonBase button)
|
||||
{
|
||||
__buttons.Insert(index, button);
|
||||
}
|
||||
|
||||
public IEnumerator<ButtonBase> GetEnumerator()
|
||||
{
|
||||
return __buttons.GetEnumerator();
|
||||
}
|
||||
|
||||
public ButtonBase[] ToArray()
|
||||
{
|
||||
return __buttons.ToArray();
|
||||
}
|
||||
|
||||
public List<ButtonBase> ToList()
|
||||
{
|
||||
return __buttons.ToList();
|
||||
}
|
||||
|
||||
public bool Matches(String text, bool useText = true)
|
||||
{
|
||||
foreach (var b in __buttons)
|
||||
{
|
||||
if (useText && b.Text.Trim().Equals(text, StringComparison.InvariantCultureIgnoreCase))
|
||||
return true;
|
||||
|
||||
if (!useText && b.Value.Equals(text, StringComparison.InvariantCultureIgnoreCase))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the button inside of the row which matches.
|
||||
/// </summary>
|
||||
/// <param name="text"></param>
|
||||
/// <param name="useText"></param>
|
||||
/// <returns></returns>
|
||||
public ButtonBase GetButtonMatch(String text, bool useText = true)
|
||||
{
|
||||
foreach (var b in __buttons)
|
||||
{
|
||||
if (useText && b.Text.Trim().Equals(text, StringComparison.InvariantCultureIgnoreCase))
|
||||
return b;
|
||||
if (!useText && b.Value.Equals(text, StringComparison.InvariantCultureIgnoreCase))
|
||||
return b;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static implicit operator ButtonRow(List<ButtonBase> list)
|
||||
{
|
||||
return new ButtonRow() { __buttons = list };
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,874 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics.SymbolStore;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Telegram.Bot.Types;
|
||||
using Telegram.Bot.Types.Enums;
|
||||
using Telegram.Bot.Types.ReplyMarkups;
|
||||
using TelegramBotBase.Args;
|
||||
using TelegramBotBase.Base;
|
||||
using TelegramBotBase.Datasources;
|
||||
using TelegramBotBase.Enums;
|
||||
using TelegramBotBase.Exceptions;
|
||||
using TelegramBotBase.Form;
|
||||
using static TelegramBotBase.Base.Async;
|
||||
|
||||
namespace TelegramBotBase.Controls.Hybrid
|
||||
{
|
||||
public class CheckedButtonList : Base.ControlBase
|
||||
{
|
||||
|
||||
public String Title { get; set; } = Localizations.Default.Language["ButtonGrid_Title"];
|
||||
|
||||
public String ConfirmationText { get; set; } = "";
|
||||
|
||||
private bool RenderNecessary = true;
|
||||
|
||||
private static readonly object __evButtonClicked = new object();
|
||||
|
||||
private static readonly object __evCheckedChanged = new object();
|
||||
|
||||
private readonly EventHandlerList Events = new EventHandlerList();
|
||||
|
||||
[Obsolete("This property is obsolete. Please use the DataSource property instead.")]
|
||||
public ButtonForm ButtonsForm
|
||||
{
|
||||
get
|
||||
{
|
||||
return DataSource.ButtonForm;
|
||||
}
|
||||
set
|
||||
{
|
||||
DataSource = new ButtonFormDataSource(value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Data source of the items.
|
||||
/// </summary>
|
||||
public ButtonFormDataSource DataSource { get; set; }
|
||||
|
||||
List<int> CheckedRows { get; set; } = new List<int>();
|
||||
|
||||
public int? MessageId { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Optional. Requests clients to resize the keyboard vertically for optimal fit (e.g., make the keyboard smaller if there are just two rows of buttons). Defaults to false, in which case the custom keyboard is always of the same height as the app's standard keyboard.
|
||||
/// Source: https://core.telegram.org/bots/api#replykeyboardmarkup
|
||||
/// </summary>
|
||||
public bool ResizeKeyboard { get; set; } = false;
|
||||
|
||||
public bool OneTimeKeyboard { get; set; } = false;
|
||||
|
||||
public bool HideKeyboardOnCleanup { get; set; } = true;
|
||||
|
||||
public bool DeletePreviousMessage { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Removes the reply message from a user.
|
||||
/// </summary>
|
||||
public bool DeleteReplyMessage { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Parsemode of the message.
|
||||
/// </summary>
|
||||
public ParseMode MessageParseMode { get; set; } = ParseMode.Default;
|
||||
|
||||
/// <summary>
|
||||
/// Enables automatic paging of buttons when the amount of rows is exceeding the limits.
|
||||
/// </summary>
|
||||
public bool EnablePaging { get; set; } = false;
|
||||
|
||||
|
||||
///// <summary>
|
||||
///// Enabled a search function.
|
||||
///// </summary>
|
||||
//public bool EnableSearch { get; set; } = false;
|
||||
|
||||
//public String SearchQuery { get; set; }
|
||||
|
||||
public eNavigationBarVisibility NavigationBarVisibility { get; set; } = eNavigationBarVisibility.always;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Index of the current page
|
||||
/// </summary>
|
||||
public int CurrentPageIndex { get; set; } = 0;
|
||||
|
||||
public String PreviousPageLabel = Localizations.Default.Language["ButtonGrid_PreviousPage"];
|
||||
|
||||
public String NextPageLabel = Localizations.Default.Language["ButtonGrid_NextPage"];
|
||||
|
||||
public String NoItemsLabel = Localizations.Default.Language["ButtonGrid_NoItems"];
|
||||
|
||||
//public String SearchLabel = Localizations.Default.Language["ButtonGrid_SearchFeature"];
|
||||
|
||||
public String CheckedIconLabel { get; set; } = "✅";
|
||||
|
||||
public String UncheckedIconLabel { get; set; } = "◻️";
|
||||
|
||||
/// <summary>
|
||||
/// Layout of the buttons which should be displayed always on top.
|
||||
/// </summary>
|
||||
public ButtonRow HeadLayoutButtonRow { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Layout of columns which should be displayed below the header
|
||||
/// </summary>
|
||||
public ButtonRow SubHeadLayoutButtonRow { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Defines which type of Button Keyboard should be rendered.
|
||||
/// </summary>
|
||||
public eKeyboardType KeyboardType
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_eKeyboardType;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (m_eKeyboardType != value)
|
||||
{
|
||||
this.RenderNecessary = true;
|
||||
|
||||
Cleanup().Wait();
|
||||
|
||||
m_eKeyboardType = value;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private eKeyboardType m_eKeyboardType = eKeyboardType.ReplyKeyboard;
|
||||
|
||||
public CheckedButtonList()
|
||||
{
|
||||
this.DataSource = new ButtonFormDataSource();
|
||||
|
||||
|
||||
}
|
||||
|
||||
public CheckedButtonList(eKeyboardType type) : this()
|
||||
{
|
||||
m_eKeyboardType = type;
|
||||
}
|
||||
|
||||
|
||||
public CheckedButtonList(ButtonForm form)
|
||||
{
|
||||
this.DataSource = new ButtonFormDataSource(form);
|
||||
}
|
||||
|
||||
public event AsyncEventHandler<ButtonClickedEventArgs> ButtonClicked
|
||||
{
|
||||
add
|
||||
{
|
||||
this.Events.AddHandler(__evButtonClicked, value);
|
||||
}
|
||||
remove
|
||||
{
|
||||
this.Events.RemoveHandler(__evButtonClicked, value);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task OnButtonClicked(ButtonClickedEventArgs e)
|
||||
{
|
||||
var handler = this.Events[__evButtonClicked]?.GetInvocationList().Cast<AsyncEventHandler<ButtonClickedEventArgs>>();
|
||||
if (handler == null)
|
||||
return;
|
||||
|
||||
foreach (var h in handler)
|
||||
{
|
||||
await Async.InvokeAllAsync<ButtonClickedEventArgs>(h, this, e);
|
||||
}
|
||||
}
|
||||
|
||||
public event AsyncEventHandler<CheckedChangedEventArgs> CheckedChanged
|
||||
{
|
||||
add
|
||||
{
|
||||
this.Events.AddHandler(__evCheckedChanged, value);
|
||||
}
|
||||
remove
|
||||
{
|
||||
this.Events.RemoveHandler(__evCheckedChanged, value);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task OnCheckedChanged(CheckedChangedEventArgs e)
|
||||
{
|
||||
var handler = this.Events[__evCheckedChanged]?.GetInvocationList().Cast<AsyncEventHandler<CheckedChangedEventArgs>>();
|
||||
if (handler == null)
|
||||
return;
|
||||
|
||||
foreach (var h in handler)
|
||||
{
|
||||
await Async.InvokeAllAsync<CheckedChangedEventArgs>(h, this, e);
|
||||
}
|
||||
}
|
||||
|
||||
public async override Task Load(MessageResult result)
|
||||
{
|
||||
if (this.KeyboardType != eKeyboardType.ReplyKeyboard)
|
||||
return;
|
||||
|
||||
if (!result.IsFirstHandler)
|
||||
return;
|
||||
|
||||
if (result.MessageText == null || result.MessageText == "")
|
||||
return;
|
||||
|
||||
var matches = new List<ButtonRow>();
|
||||
ButtonRow match = null;
|
||||
int index = -1;
|
||||
|
||||
if (HeadLayoutButtonRow?.Matches(result.MessageText) ?? false)
|
||||
{
|
||||
match = HeadLayoutButtonRow;
|
||||
goto check;
|
||||
}
|
||||
|
||||
if (SubHeadLayoutButtonRow?.Matches(result.MessageText) ?? false)
|
||||
{
|
||||
match = SubHeadLayoutButtonRow;
|
||||
goto check;
|
||||
}
|
||||
|
||||
var br = DataSource.FindRow(result.MessageText);
|
||||
if (br != null)
|
||||
{
|
||||
match = br.Item1;
|
||||
index = br.Item2;
|
||||
}
|
||||
|
||||
|
||||
//var button = HeadLayoutButtonRow?. .FirstOrDefault(a => a.Text.Trim() == result.MessageText)
|
||||
// ?? SubHeadLayoutButtonRow?.FirstOrDefault(a => a.Text.Trim() == result.MessageText);
|
||||
|
||||
// bf.ToList().FirstOrDefault(a => a.Text.Trim() == result.MessageText)
|
||||
|
||||
//var index = bf.FindRowByButton(button);
|
||||
|
||||
|
||||
|
||||
check:
|
||||
|
||||
|
||||
//Remove button click message
|
||||
if (this.DeleteReplyMessage)
|
||||
await Device.DeleteMessage(result.MessageId);
|
||||
|
||||
if (match == null)
|
||||
{
|
||||
if (result.MessageText == PreviousPageLabel)
|
||||
{
|
||||
if (this.CurrentPageIndex > 0)
|
||||
this.CurrentPageIndex--;
|
||||
|
||||
this.Updated();
|
||||
}
|
||||
else if (result.MessageText == NextPageLabel)
|
||||
{
|
||||
if (this.CurrentPageIndex < this.PageCount - 1)
|
||||
this.CurrentPageIndex++;
|
||||
|
||||
this.Updated();
|
||||
}
|
||||
else if (result.MessageText.EndsWith(CheckedIconLabel))
|
||||
{
|
||||
var s = result.MessageText.Split(' ', '.');
|
||||
index = int.Parse(s[0]) - 1;
|
||||
|
||||
if (!this.CheckedRows.Contains(index))
|
||||
return;
|
||||
|
||||
this.CheckedRows.Remove(index);
|
||||
|
||||
this.Updated();
|
||||
|
||||
await OnCheckedChanged(new CheckedChangedEventArgs(ButtonsForm[index], index, false));
|
||||
|
||||
}
|
||||
else if (result.MessageText.EndsWith(UncheckedIconLabel))
|
||||
{
|
||||
var s = result.MessageText.Split(' ', '.');
|
||||
index = int.Parse(s[0]) - 1;
|
||||
|
||||
if (this.CheckedRows.Contains(index))
|
||||
return;
|
||||
|
||||
|
||||
this.CheckedRows.Add(index);
|
||||
|
||||
this.Updated();
|
||||
|
||||
await OnCheckedChanged(new CheckedChangedEventArgs(ButtonsForm[index], index, true));
|
||||
|
||||
}
|
||||
//else if (this.EnableSearch)
|
||||
//{
|
||||
// if (result.MessageText.StartsWith("🔍"))
|
||||
// {
|
||||
// //Sent note about searching
|
||||
// if (this.SearchQuery == null)
|
||||
// {
|
||||
// await this.Device.Send(this.SearchLabel);
|
||||
// }
|
||||
|
||||
// this.SearchQuery = null;
|
||||
// this.Updated();
|
||||
// return;
|
||||
// }
|
||||
|
||||
// this.SearchQuery = result.MessageText;
|
||||
|
||||
// if (this.SearchQuery != null && this.SearchQuery != "")
|
||||
// {
|
||||
// this.CurrentPageIndex = 0;
|
||||
// this.Updated();
|
||||
// }
|
||||
|
||||
//}
|
||||
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
await OnButtonClicked(new ButtonClickedEventArgs(match.GetButtonMatch(result.MessageText), index, match));
|
||||
|
||||
result.Handled = true;
|
||||
|
||||
//await OnButtonClicked(new ButtonClickedEventArgs(button, index));
|
||||
|
||||
////Remove button click message
|
||||
//if (this.DeletePreviousMessage)
|
||||
// await Device.DeleteMessage(result.MessageId);
|
||||
|
||||
//result.Handled = true;
|
||||
|
||||
}
|
||||
|
||||
public async override Task Action(MessageResult result, string value = null)
|
||||
{
|
||||
if (result.Handled)
|
||||
return;
|
||||
|
||||
if (!result.IsFirstHandler)
|
||||
return;
|
||||
|
||||
//Find clicked button depending on Text or Value (depending on markup type)
|
||||
if (this.KeyboardType != eKeyboardType.InlineKeyBoard)
|
||||
return;
|
||||
|
||||
await result.ConfirmAction(this.ConfirmationText ?? "");
|
||||
|
||||
ButtonRow match = null;
|
||||
int index = -1;
|
||||
|
||||
if (HeadLayoutButtonRow?.Matches(result.RawData, false) ?? false)
|
||||
{
|
||||
match = HeadLayoutButtonRow;
|
||||
goto check;
|
||||
}
|
||||
|
||||
if (SubHeadLayoutButtonRow?.Matches(result.RawData, false) ?? false)
|
||||
{
|
||||
match = SubHeadLayoutButtonRow;
|
||||
goto check;
|
||||
}
|
||||
|
||||
var br = DataSource.FindRow(result.RawData, false);
|
||||
if (br != null)
|
||||
{
|
||||
match = br.Item1;
|
||||
index = br.Item2;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//var bf = DataSource.ButtonForm;
|
||||
|
||||
//var button = HeadLayoutButtonRow?.FirstOrDefault(a => a.Value == result.RawData)
|
||||
// ?? SubHeadLayoutButtonRow?.FirstOrDefault(a => a.Value == result.RawData)
|
||||
// ?? bf.ToList().FirstOrDefault(a => a.Value == result.RawData);
|
||||
|
||||
//var index = bf.FindRowByButton(button);
|
||||
|
||||
check:
|
||||
if (match != null)
|
||||
{
|
||||
await OnButtonClicked(new ButtonClickedEventArgs(match.GetButtonMatch(result.RawData, false), index, match));
|
||||
|
||||
result.Handled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
//if (button != null)
|
||||
//{
|
||||
// await OnButtonClicked(new ButtonClickedEventArgs(button, index));
|
||||
|
||||
// result.Handled = true;
|
||||
// return;
|
||||
//}
|
||||
|
||||
switch (result.RawData)
|
||||
{
|
||||
case "$previous$":
|
||||
|
||||
if (this.CurrentPageIndex > 0)
|
||||
this.CurrentPageIndex--;
|
||||
|
||||
this.Updated();
|
||||
|
||||
break;
|
||||
case "$next$":
|
||||
|
||||
if (this.CurrentPageIndex < this.PageCount - 1)
|
||||
this.CurrentPageIndex++;
|
||||
|
||||
this.Updated();
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
var s = result.RawData.Split('$');
|
||||
|
||||
|
||||
switch (s[0])
|
||||
{
|
||||
case "check":
|
||||
|
||||
index = int.Parse(s[1]);
|
||||
|
||||
if (!this.CheckedRows.Contains(index))
|
||||
{
|
||||
this.CheckedRows.Add(index);
|
||||
|
||||
this.Updated();
|
||||
|
||||
await OnCheckedChanged(new CheckedChangedEventArgs(ButtonsForm[index], index, true));
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case "uncheck":
|
||||
|
||||
index = int.Parse(s[1]);
|
||||
|
||||
if (this.CheckedRows.Contains(index))
|
||||
{
|
||||
this.CheckedRows.Remove(index);
|
||||
|
||||
this.Updated();
|
||||
|
||||
await OnCheckedChanged(new CheckedChangedEventArgs(ButtonsForm[index], index, false));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method checks of the amount of buttons
|
||||
/// </summary>
|
||||
private void CheckGrid()
|
||||
{
|
||||
switch (m_eKeyboardType)
|
||||
{
|
||||
case eKeyboardType.InlineKeyBoard:
|
||||
|
||||
if (DataSource.RowCount > Constants.Telegram.MaxInlineKeyBoardRows && !this.EnablePaging)
|
||||
{
|
||||
throw new MaximumRowsReachedException() { Value = DataSource.RowCount, Maximum = Constants.Telegram.MaxInlineKeyBoardRows };
|
||||
}
|
||||
|
||||
if (DataSource.ColumnCount > Constants.Telegram.MaxInlineKeyBoardCols)
|
||||
{
|
||||
throw new MaximumColsException() { Value = DataSource.ColumnCount, Maximum = Constants.Telegram.MaxInlineKeyBoardCols };
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case eKeyboardType.ReplyKeyboard:
|
||||
|
||||
if (DataSource.RowCount > Constants.Telegram.MaxReplyKeyboardRows && !this.EnablePaging)
|
||||
{
|
||||
throw new MaximumRowsReachedException() { Value = DataSource.RowCount, Maximum = Constants.Telegram.MaxReplyKeyboardRows };
|
||||
}
|
||||
|
||||
if (DataSource.ColumnCount > Constants.Telegram.MaxReplyKeyboardCols)
|
||||
{
|
||||
throw new MaximumColsException() { Value = DataSource.ColumnCount, Maximum = Constants.Telegram.MaxReplyKeyboardCols };
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public async override Task Render(MessageResult result)
|
||||
{
|
||||
if (!this.RenderNecessary)
|
||||
return;
|
||||
|
||||
//Check for rows and column limits
|
||||
CheckGrid();
|
||||
|
||||
this.RenderNecessary = false;
|
||||
|
||||
Message m = null;
|
||||
|
||||
ButtonForm form = this.DataSource.PickItems(CurrentPageIndex * ItemRowsPerPage, ItemRowsPerPage, null);
|
||||
|
||||
//if (this.EnableSearch && this.SearchQuery != null && this.SearchQuery != "")
|
||||
//{
|
||||
// form = form.FilterDuplicate(this.SearchQuery, true);
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
//form = form.Duplicate();
|
||||
//}
|
||||
|
||||
if (this.EnablePaging)
|
||||
{
|
||||
IntegratePagingView(form);
|
||||
}
|
||||
else
|
||||
{
|
||||
form = PrepareCheckableLayout(form);
|
||||
}
|
||||
|
||||
if (this.HeadLayoutButtonRow != null && HeadLayoutButtonRow.Count > 0)
|
||||
{
|
||||
form.InsertButtonRow(0, this.HeadLayoutButtonRow.ToArray());
|
||||
}
|
||||
|
||||
if (this.SubHeadLayoutButtonRow != null && SubHeadLayoutButtonRow.Count > 0)
|
||||
{
|
||||
if (this.IsNavigationBarVisible)
|
||||
{
|
||||
form.InsertButtonRow(2, this.SubHeadLayoutButtonRow.ToArray());
|
||||
}
|
||||
else
|
||||
{
|
||||
form.InsertButtonRow(1, this.SubHeadLayoutButtonRow.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
switch (this.KeyboardType)
|
||||
{
|
||||
//Reply Keyboard could only be updated with a new keyboard.
|
||||
case eKeyboardType.ReplyKeyboard:
|
||||
|
||||
if (form.Count == 0)
|
||||
{
|
||||
if (this.MessageId != null)
|
||||
{
|
||||
await this.Device.HideReplyKeyboard();
|
||||
this.MessageId = null;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//if (form.Count == 0)
|
||||
// return;
|
||||
|
||||
|
||||
var rkm = (ReplyKeyboardMarkup)form;
|
||||
rkm.ResizeKeyboard = this.ResizeKeyboard;
|
||||
rkm.OneTimeKeyboard = this.OneTimeKeyboard;
|
||||
m = await this.Device.Send(this.Title, rkm, disableNotification: true, parseMode: MessageParseMode, MarkdownV2AutoEscape: false);
|
||||
|
||||
//Prevent flicker of keyboard
|
||||
if (this.DeletePreviousMessage && this.MessageId != null)
|
||||
await this.Device.DeleteMessage(this.MessageId.Value);
|
||||
|
||||
break;
|
||||
|
||||
case eKeyboardType.InlineKeyBoard:
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (m != null)
|
||||
{
|
||||
this.MessageId = m.MessageId;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private void IntegratePagingView(ButtonForm dataForm)
|
||||
{
|
||||
//No Items
|
||||
if (dataForm.Rows == 0)
|
||||
{
|
||||
dataForm.AddButtonRow(new ButtonBase(NoItemsLabel, "$"));
|
||||
}
|
||||
|
||||
ButtonForm bf = new ButtonForm();
|
||||
|
||||
bf = PrepareCheckableLayout(dataForm);
|
||||
|
||||
|
||||
if (this.IsNavigationBarVisible)
|
||||
{
|
||||
//🔍
|
||||
ButtonRow row = new ButtonRow();
|
||||
row.Add(new ButtonBase(PreviousPageLabel, "$previous$"));
|
||||
row.Add(new ButtonBase(String.Format(Localizations.Default.Language["ButtonGrid_CurrentPage"], this.CurrentPageIndex + 1, this.PageCount), "$site$"));
|
||||
row.Add(new ButtonBase(NextPageLabel, "$next$"));
|
||||
|
||||
|
||||
dataForm.InsertButtonRow(0, row);
|
||||
|
||||
dataForm.AddButtonRow(row);
|
||||
}
|
||||
}
|
||||
|
||||
private ButtonForm PrepareCheckableLayout(ButtonForm dataForm)
|
||||
{
|
||||
var bf = new ButtonForm();
|
||||
for (int i = 0; i < dataForm.Rows; i++)
|
||||
{
|
||||
int it = (this.CurrentPageIndex * (this.MaximumRow - LayoutRows)) + i;
|
||||
|
||||
//if (it > dataForm.Rows - 1)
|
||||
// break;
|
||||
|
||||
var r = dataForm[i];
|
||||
|
||||
String s = CheckedRows.Contains(it) ? this.CheckedIconLabel : this.UncheckedIconLabel;
|
||||
|
||||
//On reply keyboards we need a unique text.
|
||||
if (this.KeyboardType == eKeyboardType.ReplyKeyboard)
|
||||
{
|
||||
s = $"{it + 1}. " + s;
|
||||
}
|
||||
|
||||
if (CheckedRows.Contains(it))
|
||||
{
|
||||
r.Insert(0, new ButtonBase(s, "uncheck$" + it.ToString()));
|
||||
}
|
||||
else
|
||||
{
|
||||
r.Insert(0, new ButtonBase(s, "check$" + it.ToString()));
|
||||
}
|
||||
|
||||
bf.AddButtonRow(r);
|
||||
}
|
||||
|
||||
return bf;
|
||||
}
|
||||
|
||||
public bool PagingNecessary
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.KeyboardType == eKeyboardType.InlineKeyBoard && TotalRows > Constants.Telegram.MaxInlineKeyBoardRows)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this.KeyboardType == eKeyboardType.ReplyKeyboard && TotalRows > Constants.Telegram.MaxReplyKeyboardRows)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsNavigationBarVisible
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.NavigationBarVisibility == eNavigationBarVisibility.always | (this.NavigationBarVisibility == eNavigationBarVisibility.auto && PagingNecessary))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the maximum number of rows
|
||||
/// </summary>
|
||||
public int MaximumRow
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (this.KeyboardType)
|
||||
{
|
||||
case eKeyboardType.InlineKeyBoard:
|
||||
return Constants.Telegram.MaxInlineKeyBoardRows;
|
||||
|
||||
case eKeyboardType.ReplyKeyboard:
|
||||
return Constants.Telegram.MaxReplyKeyboardRows;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the number of all rows (layout + navigation + content);
|
||||
/// </summary>
|
||||
public int TotalRows
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.LayoutRows + DataSource.RowCount;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Contains the Number of Rows which are used by the layout.
|
||||
/// </summary>
|
||||
private int LayoutRows
|
||||
{
|
||||
get
|
||||
{
|
||||
int layoutRows = 0;
|
||||
|
||||
if (this.NavigationBarVisibility == eNavigationBarVisibility.always | this.NavigationBarVisibility == eNavigationBarVisibility.auto)
|
||||
layoutRows += 2;
|
||||
|
||||
if (this.HeadLayoutButtonRow != null && this.HeadLayoutButtonRow.Count > 0)
|
||||
layoutRows++;
|
||||
|
||||
if (this.SubHeadLayoutButtonRow != null && this.SubHeadLayoutButtonRow.Count > 0)
|
||||
layoutRows++;
|
||||
|
||||
return layoutRows;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the number of item rows per page.
|
||||
/// </summary>
|
||||
public int ItemRowsPerPage
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.MaximumRow - this.LayoutRows;
|
||||
}
|
||||
}
|
||||
|
||||
public int PageCount
|
||||
{
|
||||
get
|
||||
{
|
||||
if (DataSource.RowCount == 0)
|
||||
return 1;
|
||||
|
||||
//var bf = this.DataSource.PickAllItems(this.EnableSearch ? this.SearchQuery : null);
|
||||
|
||||
var max = this.DataSource.RowCount;
|
||||
|
||||
//if (this.EnableSearch && this.SearchQuery != null && this.SearchQuery != "")
|
||||
//{
|
||||
// bf = bf.FilterDuplicate(this.SearchQuery);
|
||||
//}
|
||||
|
||||
if (max == 0)
|
||||
return 1;
|
||||
|
||||
return (int)Math.Ceiling((decimal)((decimal)max / (decimal)ItemRowsPerPage));
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task Hidden(bool FormClose)
|
||||
{
|
||||
//Prepare for opening Modal, and comming back
|
||||
if (!FormClose)
|
||||
{
|
||||
this.Updated();
|
||||
}
|
||||
}
|
||||
|
||||
public List<ButtonBase> CheckedItems
|
||||
{
|
||||
get
|
||||
{
|
||||
List<ButtonBase> lst = new List<ButtonBase>();
|
||||
|
||||
foreach (var c in CheckedRows)
|
||||
{
|
||||
lst.Add(this.ButtonsForm[c][0]);
|
||||
}
|
||||
|
||||
return lst;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Tells the control that it has been updated.
|
||||
/// </summary>
|
||||
public void Updated()
|
||||
{
|
||||
this.RenderNecessary = true;
|
||||
}
|
||||
|
||||
public async override Task Cleanup()
|
||||
{
|
||||
if (this.MessageId == null)
|
||||
return;
|
||||
|
||||
switch (this.KeyboardType)
|
||||
{
|
||||
case eKeyboardType.InlineKeyBoard:
|
||||
|
||||
await this.Device.DeleteMessage(this.MessageId.Value);
|
||||
|
||||
this.MessageId = null;
|
||||
|
||||
break;
|
||||
case eKeyboardType.ReplyKeyboard:
|
||||
|
||||
if (this.HideKeyboardOnCleanup)
|
||||
{
|
||||
await this.Device.HideReplyKeyboard();
|
||||
}
|
||||
|
||||
this.MessageId = null;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using TelegramBotBase.Args;
|
||||
using TelegramBotBase.Base;
|
||||
|
||||
namespace TelegramBotBase.Controls.Hybrid
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// This Control is for having a basic form content switching control.
|
||||
/// </summary>
|
||||
public abstract class MultiView : Base.ControlBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Index of the current View.
|
||||
/// </summary>
|
||||
public int SelectedViewIndex
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_iSelectedViewIndex;
|
||||
}
|
||||
set
|
||||
{
|
||||
m_iSelectedViewIndex = value;
|
||||
|
||||
//Already rendered? Re-Render
|
||||
if (_Rendered)
|
||||
ForceRender().Wait();
|
||||
}
|
||||
}
|
||||
|
||||
private int m_iSelectedViewIndex = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Hold if the View has been rendered already.
|
||||
/// </summary>
|
||||
private bool _Rendered = false;
|
||||
|
||||
private List<int> Messages { get; set; }
|
||||
|
||||
|
||||
public MultiView()
|
||||
{
|
||||
Messages = new List<int>();
|
||||
}
|
||||
|
||||
|
||||
private void Device_MessageSent(object sender, MessageSentEventArgs e)
|
||||
{
|
||||
if (e.Origin == null || !e.Origin.IsSubclassOf(typeof(MultiView)))
|
||||
return;
|
||||
|
||||
this.Messages.Add(e.MessageId);
|
||||
}
|
||||
|
||||
public override void Init()
|
||||
{
|
||||
Device.MessageSent += Device_MessageSent;
|
||||
}
|
||||
|
||||
public override async Task Load(MessageResult result)
|
||||
{
|
||||
_Rendered = false;
|
||||
}
|
||||
|
||||
|
||||
public override async Task Render(MessageResult result)
|
||||
{
|
||||
//When already rendered, skip rendering
|
||||
if (_Rendered)
|
||||
return;
|
||||
|
||||
await CleanUpView();
|
||||
|
||||
await RenderView(new RenderViewEventArgs(this.SelectedViewIndex));
|
||||
|
||||
_Rendered = true;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Will get invoked on rendering the current controls view.
|
||||
/// </summary>
|
||||
/// <param name="e"></param>
|
||||
public virtual async Task RenderView(RenderViewEventArgs e)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
async Task CleanUpView()
|
||||
{
|
||||
|
||||
var tasks = new List<Task>();
|
||||
|
||||
foreach (var msg in this.Messages)
|
||||
{
|
||||
tasks.Add(this.Device.DeleteMessage(msg));
|
||||
}
|
||||
|
||||
await Task.WhenAll(tasks);
|
||||
|
||||
this.Messages.Clear();
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Forces render of control contents.
|
||||
/// </summary>
|
||||
public async Task ForceRender()
|
||||
{
|
||||
await CleanUpView();
|
||||
|
||||
await RenderView(new RenderViewEventArgs(this.SelectedViewIndex));
|
||||
|
||||
_Rendered = true;
|
||||
}
|
||||
|
||||
public override async Task Cleanup()
|
||||
{
|
||||
Device.MessageSent -= Device_MessageSent;
|
||||
|
||||
await CleanUpView();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
+9
-7
@@ -7,11 +7,11 @@ using System.Threading.Tasks;
|
||||
using TelegramBotBase.Base;
|
||||
using TelegramBotBase.Enums;
|
||||
using TelegramBotBase.Form;
|
||||
|
||||
using TelegramBotBase.Tools;
|
||||
using static TelegramBotBase.Tools.Arrays;
|
||||
using static TelegramBotBase.Tools.Time;
|
||||
|
||||
namespace TelegramBotBase.Controls
|
||||
namespace TelegramBotBase.Controls.Inline
|
||||
{
|
||||
public class CalendarPicker : Base.ControlBase
|
||||
{
|
||||
@@ -37,15 +37,17 @@ namespace TelegramBotBase.Controls
|
||||
|
||||
public bool EnableYearView { get; set; } = true;
|
||||
|
||||
public CalendarPicker()
|
||||
public CalendarPicker(CultureInfo culture)
|
||||
{
|
||||
this.SelectedDate = DateTime.Today;
|
||||
this.VisibleMonth = DateTime.Today;
|
||||
this.FirstDayOfWeek = DayOfWeek.Monday;
|
||||
this.Culture = new CultureInfo("de-de");
|
||||
this.Culture = culture;
|
||||
this.PickerMode = eMonthPickerMode.day;
|
||||
}
|
||||
|
||||
public CalendarPicker() : this(new CultureInfo("en-en")) { }
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -124,13 +126,13 @@ namespace TelegramBotBase.Controls
|
||||
default:
|
||||
|
||||
int day = 0;
|
||||
if (result.RawData.StartsWith("d-") && int.TryParse(result.RawData.Split('-')[1], out day))
|
||||
if (result.RawData.StartsWith("d-") && TryParseDay(result.RawData.Split('-')[1], this.SelectedDate, out day))
|
||||
{
|
||||
this.SelectedDate = new DateTime(this.VisibleMonth.Year, this.VisibleMonth.Month, day);
|
||||
}
|
||||
|
||||
int month = 0;
|
||||
if (result.RawData.StartsWith("m-") && int.TryParse(result.RawData.Split('-')[1], out month))
|
||||
if (result.RawData.StartsWith("m-") && TryParseMonth(result.RawData.Split('-')[1], out month))
|
||||
{
|
||||
this.SelectedDate = new DateTime(this.VisibleMonth.Year, month, 1);
|
||||
this.VisibleMonth = this.SelectedDate;
|
||||
@@ -142,7 +144,7 @@ namespace TelegramBotBase.Controls
|
||||
}
|
||||
|
||||
int year = 0;
|
||||
if (result.RawData.StartsWith("y-") && int.TryParse(result.RawData.Split('-')[1], out year))
|
||||
if (result.RawData.StartsWith("y-") && TryParseYear(result.RawData.Split('-')[1], out year))
|
||||
{
|
||||
this.SelectedDate = new DateTime(year, SelectedDate.Month, SelectedDate.Day);
|
||||
this.VisibleMonth = this.SelectedDate;
|
||||
+1
-1
@@ -8,7 +8,7 @@ using TelegramBotBase.Base;
|
||||
using TelegramBotBase.Enums;
|
||||
using TelegramBotBase.Form;
|
||||
|
||||
namespace TelegramBotBase.Controls
|
||||
namespace TelegramBotBase.Controls.Inline
|
||||
{
|
||||
public class MonthPicker : CalendarPicker
|
||||
{
|
||||
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// This contains the selected icon.
|
||||
/// </summary>
|
||||
public String SelectedIcon { get; set; } = Localizations.Default.Language["MultiToggleButton_SelectedIcon"];
|
||||
|
||||
/// <summary>
|
||||
/// This will appear on the ConfirmAction message (if not empty)
|
||||
/// </summary>
|
||||
public String ChangedString { get; set; } = Localizations.Default.Language["MultiToggleButton_Changed"];
|
||||
|
||||
/// <summary>
|
||||
/// This holds the title of the control.
|
||||
/// </summary>
|
||||
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();
|
||||
|
||||
/// <summary>
|
||||
/// This will hold all options available.
|
||||
/// </summary>
|
||||
public List<ButtonBase> Options { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// This will set if an empty selection (null) is allowed.
|
||||
/// </summary>
|
||||
public bool AllowEmptySelection { get; set; } = true;
|
||||
|
||||
|
||||
public MultiToggleButton()
|
||||
{
|
||||
Options = new List<ButtonBase>();
|
||||
}
|
||||
|
||||
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<ButtonBase>();
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -5,7 +5,7 @@ using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using TelegramBotBase.Base;
|
||||
|
||||
namespace TelegramBotBase.Controls
|
||||
namespace TelegramBotBase.Controls.Inline
|
||||
{
|
||||
/// <summary>
|
||||
/// A simple control for show and managing progress.
|
||||
+1
-1
@@ -7,7 +7,7 @@ using System.Threading.Tasks;
|
||||
using TelegramBotBase.Base;
|
||||
using TelegramBotBase.Form;
|
||||
|
||||
namespace TelegramBotBase.Controls
|
||||
namespace TelegramBotBase.Controls.Inline
|
||||
{
|
||||
public class ToggleButton : ControlBase
|
||||
{
|
||||
@@ -6,7 +6,7 @@ using System.Threading.Tasks;
|
||||
using TelegramBotBase.Base;
|
||||
using TelegramBotBase.Form;
|
||||
|
||||
namespace TelegramBotBase.Controls
|
||||
namespace TelegramBotBase.Controls.Inline
|
||||
{
|
||||
public class TreeView : ControlBase
|
||||
{
|
||||
+1
-1
@@ -4,7 +4,7 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace TelegramBotBase.Controls
|
||||
namespace TelegramBotBase.Controls.Inline
|
||||
{
|
||||
public class TreeViewNode
|
||||
{
|
||||
@@ -0,0 +1,142 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using TelegramBotBase.Controls.Hybrid;
|
||||
using TelegramBotBase.Form;
|
||||
using TelegramBotBase.Interfaces;
|
||||
|
||||
namespace TelegramBotBase.Datasources
|
||||
{
|
||||
public class ButtonFormDataSource : Interfaces.IDataSource<ButtonRow>
|
||||
{
|
||||
public virtual ButtonForm ButtonForm
|
||||
{
|
||||
get
|
||||
{
|
||||
return __buttonform;
|
||||
}
|
||||
set
|
||||
{
|
||||
__buttonform = value;
|
||||
}
|
||||
}
|
||||
|
||||
private ButtonForm __buttonform = null;
|
||||
|
||||
public ButtonFormDataSource()
|
||||
{
|
||||
__buttonform = new ButtonForm();
|
||||
}
|
||||
|
||||
public ButtonFormDataSource(ButtonForm bf)
|
||||
{
|
||||
__buttonform = bf;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns the amount of rows exisiting.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public virtual int Count => ButtonForm.Count;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns the amount of rows.
|
||||
/// </summary>
|
||||
public virtual int RowCount => ButtonForm.Rows;
|
||||
|
||||
/// <summary>
|
||||
/// Returns the maximum amount of columns.
|
||||
/// </summary>
|
||||
public virtual int ColumnCount => ButtonForm.Cols;
|
||||
|
||||
/// <summary>
|
||||
/// Returns the row with the specific index.
|
||||
/// </summary>
|
||||
/// <param name="index"></param>
|
||||
/// <returns></returns>
|
||||
public virtual ButtonRow ItemAt(int index)
|
||||
{
|
||||
return ButtonForm[index];
|
||||
}
|
||||
|
||||
public virtual List<ButtonRow> ItemRange(int start, int count)
|
||||
{
|
||||
return ButtonForm.GetRange(start, count);
|
||||
}
|
||||
|
||||
public virtual List<ButtonRow> AllItems()
|
||||
{
|
||||
return ButtonForm.ToArray();
|
||||
}
|
||||
|
||||
public virtual ButtonForm PickItems(int start, int count, String filter = null)
|
||||
{
|
||||
ButtonForm bf = new ButtonForm();
|
||||
ButtonForm dataForm = null;
|
||||
|
||||
if (filter == null)
|
||||
{
|
||||
dataForm = ButtonForm.Duplicate();
|
||||
}
|
||||
else
|
||||
{
|
||||
dataForm = ButtonForm.FilterDuplicate(filter, true);
|
||||
}
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
int it = start + i;
|
||||
|
||||
if (it > dataForm.Rows - 1)
|
||||
break;
|
||||
|
||||
bf.AddButtonRow(dataForm[it]);
|
||||
}
|
||||
|
||||
return bf;
|
||||
}
|
||||
|
||||
public virtual ButtonForm PickAllItems(String filter = null)
|
||||
{
|
||||
if (filter == null)
|
||||
return ButtonForm.Duplicate();
|
||||
|
||||
|
||||
return ButtonForm.FilterDuplicate(filter, true);
|
||||
}
|
||||
|
||||
public virtual Tuple<ButtonRow, int> FindRow(String text, bool useText = true)
|
||||
{
|
||||
return ButtonForm.FindRow(text, useText);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the maximum items of this data source.
|
||||
/// </summary>
|
||||
/// <param name="filter"></param>
|
||||
/// <returns></returns>
|
||||
public virtual int CalculateMax(String filter = null)
|
||||
{
|
||||
return PickAllItems(filter).Rows;
|
||||
}
|
||||
|
||||
public virtual ButtonRow Render(object data)
|
||||
{
|
||||
return data as ButtonRow;
|
||||
}
|
||||
|
||||
|
||||
public static implicit operator ButtonFormDataSource(ButtonForm bf)
|
||||
{
|
||||
return new ButtonFormDataSource(bf);
|
||||
}
|
||||
|
||||
public static implicit operator ButtonForm(ButtonFormDataSource ds)
|
||||
{
|
||||
return ds.ButtonForm;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace TelegramBotBase.Datasources
|
||||
{
|
||||
public class StaticDataSource<T> : Interfaces.IDataSource<T>
|
||||
{
|
||||
List<T> Data { get; set; }
|
||||
|
||||
public StaticDataSource()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public StaticDataSource(List<T> data)
|
||||
{
|
||||
this.Data = data;
|
||||
}
|
||||
|
||||
|
||||
public int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
return Data.Count;
|
||||
}
|
||||
}
|
||||
|
||||
public T ItemAt(int index)
|
||||
{
|
||||
return Data[index];
|
||||
}
|
||||
|
||||
public List<T> ItemRange(int start, int count)
|
||||
{
|
||||
return Data.Skip(start).Take(count).ToList();
|
||||
}
|
||||
|
||||
public List<T> AllItems()
|
||||
{
|
||||
return Data;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,9 +27,14 @@ namespace TelegramBotBase.Enums
|
||||
/// <summary>
|
||||
/// Does stick to the console event handler and saves all sessions on exit.
|
||||
/// </summary>
|
||||
SaveSessionsOnConsoleExit = 4
|
||||
SaveSessionsOnConsoleExit = 4,
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
MaxNumberOfRetries = 5,
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,8 +16,16 @@ namespace TelegramBotBase.Form
|
||||
[IgnoreState]
|
||||
public class ArrayPromptDialog : FormBase
|
||||
{
|
||||
/// <summary>
|
||||
/// The message the users sees.
|
||||
/// </summary>
|
||||
public String Message { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// An additional optional value.
|
||||
/// </summary>
|
||||
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;
|
||||
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Telegram.Bot.Exceptions;
|
||||
using Telegram.Bot.Types;
|
||||
using TelegramBotBase.Args;
|
||||
using TelegramBotBase.Attributes;
|
||||
@@ -33,13 +35,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)
|
||||
@@ -48,8 +49,15 @@ namespace TelegramBotBase.Form
|
||||
this.Device.MessageSent += Device_MessageSent;
|
||||
|
||||
this.Device.MessageReceived += Device_MessageReceived;
|
||||
|
||||
this.Device.MessageDeleted += Device_MessageDeleted;
|
||||
}
|
||||
|
||||
private void Device_MessageDeleted(object sender, MessageDeletedEventArgs e)
|
||||
{
|
||||
if (OldMessages.Contains(e.MessageId))
|
||||
OldMessages.Remove(e.MessageId);
|
||||
}
|
||||
|
||||
private void Device_MessageReceived(object sender, MessageReceivedEventArgs e)
|
||||
{
|
||||
@@ -128,15 +136,93 @@ namespace TelegramBotBase.Form
|
||||
/// <returns></returns>
|
||||
public async Task MessageCleanup()
|
||||
{
|
||||
while (this.OldMessages.Count > 0)
|
||||
var oldMessages = OldMessages.AsEnumerable();
|
||||
|
||||
#if !NET472
|
||||
while (oldMessages.Any())
|
||||
{
|
||||
if (!await this.Device.DeleteMessage(this.OldMessages[0]))
|
||||
using var cts = new CancellationTokenSource();
|
||||
var deletedMessages = new ConcurrentBag<int>();
|
||||
var parallelQuery = OldMessages.AsParallel()
|
||||
.WithCancellation(cts.Token);
|
||||
Task retryAfterTask = null;
|
||||
try
|
||||
{
|
||||
//Message can't be deleted cause it seems not to exist anymore
|
||||
if (this.OldMessages.Count > 0)
|
||||
this.OldMessages.RemoveAt(0);
|
||||
parallelQuery.ForAll(i =>
|
||||
{
|
||||
try
|
||||
{
|
||||
Device.DeleteMessage(i).GetAwaiter().GetResult();
|
||||
deletedMessages.Add(i);
|
||||
}
|
||||
catch (ApiRequestException req) when (req.ErrorCode == 400)
|
||||
{
|
||||
deletedMessages.Add(i);
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (AggregateException ex)
|
||||
{
|
||||
cts.Cancel();
|
||||
|
||||
var retryAfterSeconds = ex.InnerExceptions
|
||||
.Where(e => e is ApiRequestException apiEx && apiEx.ErrorCode == 429)
|
||||
.Max(e => (int?)((ApiRequestException)e).Parameters.RetryAfter) ?? 0;
|
||||
retryAfterTask = Task.Delay(retryAfterSeconds * 1000);
|
||||
}
|
||||
|
||||
//deletedMessages.AsParallel().ForAll(i => Device.OnMessageDeleted(new MessageDeletedEventArgs(i)));
|
||||
|
||||
oldMessages = oldMessages.Where(x => !deletedMessages.Contains(x));
|
||||
if (retryAfterTask != null)
|
||||
await retryAfterTask;
|
||||
}
|
||||
#else
|
||||
while (oldMessages.Any())
|
||||
{
|
||||
using (var cts = new CancellationTokenSource())
|
||||
{
|
||||
var deletedMessages = new ConcurrentBag<int>();
|
||||
var parallelQuery = OldMessages.AsParallel()
|
||||
.WithCancellation(cts.Token);
|
||||
Task retryAfterTask = null;
|
||||
try
|
||||
{
|
||||
parallelQuery.ForAll(i =>
|
||||
{
|
||||
try
|
||||
{
|
||||
Device.DeleteMessage(i).GetAwaiter().GetResult();
|
||||
deletedMessages.Add(i);
|
||||
}
|
||||
catch (ApiRequestException req) when (req.ErrorCode == 400)
|
||||
{
|
||||
deletedMessages.Add(i);
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (AggregateException ex)
|
||||
{
|
||||
cts.Cancel();
|
||||
|
||||
var retryAfterSeconds = ex.InnerExceptions
|
||||
.Where(e => e is ApiRequestException apiEx && apiEx.ErrorCode == 429)
|
||||
.Max(e => (int?)((ApiRequestException)e).Parameters.RetryAfter) ?? 0;
|
||||
retryAfterTask = Task.Delay(retryAfterSeconds * 1000);
|
||||
}
|
||||
|
||||
//deletedMessages.AsParallel().ForAll(i => Device.OnMessageDeleted(new MessageDeletedEventArgs(i)));
|
||||
|
||||
oldMessages = oldMessages.Where(x => !deletedMessages.Contains(x));
|
||||
if (retryAfterTask != null)
|
||||
await retryAfterTask;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
OldMessages.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
@@ -7,6 +8,7 @@ using Telegram.Bot.Types.ReplyMarkups;
|
||||
|
||||
namespace TelegramBotBase.Form
|
||||
{
|
||||
[DebuggerDisplay("{Text}, {Value}")]
|
||||
/// <summary>
|
||||
/// Base class for button handling
|
||||
/// </summary>
|
||||
@@ -36,7 +38,7 @@ namespace TelegramBotBase.Form
|
||||
/// </summary>
|
||||
/// <param name="form"></param>
|
||||
/// <returns></returns>
|
||||
public InlineKeyboardButton ToInlineButton(ButtonForm form)
|
||||
public virtual InlineKeyboardButton ToInlineButton(ButtonForm form)
|
||||
{
|
||||
String id = (form.DependencyControl != null ? form.DependencyControl.ControlID + "_" : "");
|
||||
if (this.Url == null)
|
||||
@@ -59,7 +61,7 @@ namespace TelegramBotBase.Form
|
||||
/// </summary>
|
||||
/// <param name="form"></param>
|
||||
/// <returns></returns>
|
||||
public KeyboardButton ToKeyboardButton(ButtonForm form)
|
||||
public virtual KeyboardButton ToKeyboardButton(ButtonForm form)
|
||||
{
|
||||
return new KeyboardButton(this.Text);
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Telegram.Bot.Types.ReplyMarkups;
|
||||
using TelegramBotBase.Base;
|
||||
using TelegramBotBase.Controls.Hybrid;
|
||||
|
||||
namespace TelegramBotBase.Form
|
||||
{
|
||||
@@ -13,7 +14,7 @@ namespace TelegramBotBase.Form
|
||||
/// </summary>
|
||||
public class ButtonForm
|
||||
{
|
||||
List<List<ButtonBase>> Buttons = new List<List<ButtonBase>>();
|
||||
List<ButtonRow> Buttons = new List<ButtonRow>();
|
||||
|
||||
|
||||
public IReplyMarkup Markup { get; set; }
|
||||
@@ -43,7 +44,7 @@ namespace TelegramBotBase.Form
|
||||
}
|
||||
|
||||
|
||||
public List<ButtonBase> this[int row]
|
||||
public ButtonRow this[int row]
|
||||
{
|
||||
get
|
||||
{
|
||||
@@ -66,9 +67,14 @@ namespace TelegramBotBase.Form
|
||||
Buttons.Add(new List<ButtonBase>() { new ButtonBase(Text, Value, Url) });
|
||||
}
|
||||
|
||||
public void AddButtonRow(IEnumerable<ButtonBase> row)
|
||||
//public void AddButtonRow(ButtonRow row)
|
||||
//{
|
||||
// Buttons.Add(row.ToList());
|
||||
//}
|
||||
|
||||
public void AddButtonRow(ButtonRow row)
|
||||
{
|
||||
Buttons.Add(row.ToList());
|
||||
Buttons.Add(row);
|
||||
}
|
||||
|
||||
public void AddButtonRow(params ButtonBase[] row)
|
||||
@@ -76,16 +82,26 @@ namespace TelegramBotBase.Form
|
||||
AddButtonRow(row.ToList());
|
||||
}
|
||||
|
||||
public void AddButtonRows(IEnumerable<ButtonRow> rows)
|
||||
{
|
||||
Buttons.AddRange(rows);
|
||||
}
|
||||
|
||||
public void InsertButtonRow(int index, IEnumerable<ButtonBase> row)
|
||||
{
|
||||
Buttons.Insert(index, row.ToList());
|
||||
}
|
||||
|
||||
public void InsertButtonRow(int index, params ButtonBase[] row)
|
||||
public void InsertButtonRow(int index, ButtonRow row)
|
||||
{
|
||||
InsertButtonRow(index, row.ToList());
|
||||
Buttons.Insert(index, row);
|
||||
}
|
||||
|
||||
//public void InsertButtonRow(int index, params ButtonBase[] row)
|
||||
//{
|
||||
// InsertButtonRow(index, row.ToList());
|
||||
//}
|
||||
|
||||
public static T[][] SplitTo<T>(IEnumerable<T> items, int itemsPerRow = 2)
|
||||
{
|
||||
T[][] splitted = default(T[][]);
|
||||
@@ -132,25 +148,62 @@ namespace TelegramBotBase.Form
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a range of rows from the buttons.
|
||||
/// </summary>
|
||||
/// <param name="start"></param>
|
||||
/// <param name="count"></param>
|
||||
/// <returns></returns>
|
||||
public List<ButtonRow> GetRange(int start, int count)
|
||||
{
|
||||
return Buttons.Skip(start).Take(count).ToList();
|
||||
}
|
||||
|
||||
|
||||
public List<ButtonBase> ToList()
|
||||
{
|
||||
return this.Buttons.DefaultIfEmpty(new List<ButtonBase>()).Aggregate((a, b) => a.Union(b).ToList());
|
||||
return this.Buttons.DefaultIfEmpty(new List<ButtonBase>()).Select(a => a.ToList()).Aggregate((a, b) => a.Union(b).ToList());
|
||||
}
|
||||
|
||||
public InlineKeyboardButton[][] ToInlineButtonArray()
|
||||
{
|
||||
var ikb = this.Buttons.Select(a => a.Select(b => b.ToInlineButton(this)).ToArray()).ToArray();
|
||||
var ikb = this.Buttons.Select(a => a.ToArray().Select(b => b.ToInlineButton(this)).ToArray()).ToArray();
|
||||
|
||||
return ikb;
|
||||
}
|
||||
|
||||
public KeyboardButton[][] ToReplyButtonArray()
|
||||
{
|
||||
var ikb = this.Buttons.Select(a => a.Select(b => b.ToKeyboardButton(this)).ToArray()).ToArray();
|
||||
var ikb = this.Buttons.Select(a => a.ToArray().Select(b => b.ToKeyboardButton(this)).ToArray()).ToArray();
|
||||
|
||||
return ikb;
|
||||
}
|
||||
|
||||
public List<ButtonRow> ToArray()
|
||||
{
|
||||
return Buttons;
|
||||
}
|
||||
|
||||
public int FindRowByButton(ButtonBase button)
|
||||
{
|
||||
var row = this.Buttons.FirstOrDefault(a => a.ToArray().Count(b => b == button) > 0);
|
||||
if (row == null)
|
||||
return -1;
|
||||
|
||||
return this.Buttons.IndexOf(row);
|
||||
}
|
||||
|
||||
public Tuple<ButtonRow, int> FindRow(String text, bool useText = true)
|
||||
{
|
||||
var r = this.Buttons.FirstOrDefault(a => a.Matches(text, useText));
|
||||
if (r == null)
|
||||
return null;
|
||||
|
||||
var i = this.Buttons.IndexOf(r);
|
||||
return new Tuple<ButtonRow, int>(r, i);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns the first Button with the given value.
|
||||
/// </summary>
|
||||
@@ -195,7 +248,7 @@ namespace TelegramBotBase.Form
|
||||
|
||||
foreach (var b in Buttons)
|
||||
{
|
||||
var lst = new List<ButtonBase>();
|
||||
var lst = new ButtonRow();
|
||||
foreach (var b2 in b)
|
||||
{
|
||||
lst.Add(b2);
|
||||
@@ -220,7 +273,7 @@ namespace TelegramBotBase.Form
|
||||
|
||||
foreach (var b in Buttons)
|
||||
{
|
||||
var lst = new List<ButtonBase>();
|
||||
var lst = new ButtonRow();
|
||||
foreach (var b2 in b)
|
||||
{
|
||||
if (b2.Text.IndexOf(filter, StringComparison.InvariantCultureIgnoreCase) == -1)
|
||||
@@ -229,7 +282,49 @@ namespace TelegramBotBase.Form
|
||||
//Copy full row, when at least one match has found.
|
||||
if (ByRow)
|
||||
{
|
||||
lst.AddRange(b);
|
||||
lst = b;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
lst.Add(b2);
|
||||
}
|
||||
}
|
||||
|
||||
if (lst.Count > 0)
|
||||
bf.Buttons.Add(lst);
|
||||
}
|
||||
|
||||
return bf;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a copy of this form and filters by the parameter.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public ButtonForm TagDuplicate(List<String> tags, bool ByRow = false)
|
||||
{
|
||||
var bf = new ButtonForm()
|
||||
{
|
||||
Markup = this.Markup,
|
||||
DependencyControl = this.DependencyControl
|
||||
};
|
||||
|
||||
foreach (var b in Buttons)
|
||||
{
|
||||
var lst = new ButtonRow();
|
||||
foreach (var b2 in b)
|
||||
{
|
||||
if (!(b2 is TagButtonBase tb))
|
||||
continue;
|
||||
|
||||
if (!tags.Contains(tb.Tag))
|
||||
continue;
|
||||
|
||||
//Copy full row, when at least one match has found.
|
||||
if (ByRow)
|
||||
{
|
||||
lst = b;
|
||||
break;
|
||||
}
|
||||
else
|
||||
|
||||
@@ -13,8 +13,16 @@ namespace TelegramBotBase.Form
|
||||
[IgnoreState]
|
||||
public class ConfirmDialog : ModalDialog
|
||||
{
|
||||
/// <summary>
|
||||
/// The message the users sees.
|
||||
/// </summary>
|
||||
public String Message { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// An additional optional value.
|
||||
/// </summary>
|
||||
public object Tag { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Automatically close form on button click
|
||||
/// </summary>
|
||||
@@ -77,7 +85,7 @@ namespace TelegramBotBase.Form
|
||||
return;
|
||||
}
|
||||
|
||||
OnButtonClicked(new ButtonClickedEventArgs(button));
|
||||
OnButtonClicked(new ButtonClickedEventArgs(button) { Tag = this.Tag });
|
||||
|
||||
if (AutoCloseOnClick)
|
||||
await CloseForm();
|
||||
|
||||
@@ -5,7 +5,6 @@ using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using TelegramBotBase.Args;
|
||||
using TelegramBotBase.Base;
|
||||
using static TelegramBotBase.Base.Async;
|
||||
|
||||
namespace TelegramBotBase.Form
|
||||
{
|
||||
@@ -42,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));
|
||||
|
||||
|
||||
@@ -0,0 +1,358 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using TelegramBotBase.Args;
|
||||
using TelegramBotBase.Attributes;
|
||||
using TelegramBotBase.Base;
|
||||
using TelegramBotBase.Interfaces;
|
||||
|
||||
namespace TelegramBotBase.Form.Navigation
|
||||
{
|
||||
[DebuggerDisplay("{Index+1} Forms")]
|
||||
public class NavigationController : FormBase, IStateForm
|
||||
{
|
||||
|
||||
[SaveState]
|
||||
private List<FormBase> History { get; set; }
|
||||
|
||||
[SaveState]
|
||||
public int Index { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Will replace the controller when poping a form to the root form.
|
||||
/// </summary>
|
||||
[SaveState]
|
||||
public bool ForceCleanupOnLastPop { get; set; }
|
||||
|
||||
public NavigationController()
|
||||
{
|
||||
History = new List<FormBase>();
|
||||
Index = -1;
|
||||
ForceCleanupOnLastPop = true;
|
||||
|
||||
this.Init += NavigationController_Init;
|
||||
this.Opened += NavigationController_Opened;
|
||||
this.Closed += NavigationController_Closed;
|
||||
}
|
||||
|
||||
public NavigationController(FormBase startForm, params FormBase[] forms) : this()
|
||||
{
|
||||
this.Client = startForm.Client;
|
||||
this.Device = startForm.Device;
|
||||
startForm.NavigationController = this;
|
||||
|
||||
History.Add(startForm);
|
||||
Index = 0;
|
||||
|
||||
if (forms.Length > 0)
|
||||
{
|
||||
History.AddRange(forms);
|
||||
Index = History.Count - 1;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task NavigationController_Init(object sender, Args.InitEventArgs e)
|
||||
{
|
||||
if (CurrentForm == null)
|
||||
return;
|
||||
|
||||
await CurrentForm.OnInit(e);
|
||||
}
|
||||
|
||||
private async Task NavigationController_Opened(object sender, EventArgs e)
|
||||
{
|
||||
if (CurrentForm == null)
|
||||
return;
|
||||
|
||||
await CurrentForm.OnOpened(e);
|
||||
}
|
||||
|
||||
private async Task NavigationController_Closed(object sender, EventArgs e)
|
||||
{
|
||||
if (CurrentForm == null)
|
||||
return;
|
||||
|
||||
await CurrentForm.OnClosed(e);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Remove the current active form on the stack.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public virtual async Task PopAsync()
|
||||
{
|
||||
if (History.Count == 0)
|
||||
return;
|
||||
|
||||
var form = History[Index];
|
||||
|
||||
form.NavigationController = null;
|
||||
History.Remove(form);
|
||||
Index--;
|
||||
|
||||
Device.FormSwitched = true;
|
||||
|
||||
await form.OnClosed(new EventArgs());
|
||||
|
||||
//Leave NavigationController and move to the last one
|
||||
if (ForceCleanupOnLastPop && History.Count == 1)
|
||||
{
|
||||
var last_form = History[0];
|
||||
last_form.NavigationController = null;
|
||||
await this.NavigateTo(last_form);
|
||||
return;
|
||||
}
|
||||
|
||||
if (History.Count > 0)
|
||||
{
|
||||
form = History[Index];
|
||||
await form.OnOpened(new EventArgs());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pop's through all forms back to the root form.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public virtual async Task PopToRootAsync()
|
||||
{
|
||||
while (Index > 0)
|
||||
{
|
||||
await PopAsync();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pushing the given form to the stack and renders it.
|
||||
/// </summary>
|
||||
/// <param name="form"></param>
|
||||
/// <returns></returns>
|
||||
public virtual async Task PushAsync(FormBase form, params object[] args)
|
||||
{
|
||||
form.Client = this.Client;
|
||||
form.Device = this.Device;
|
||||
form.NavigationController = this;
|
||||
|
||||
this.History.Add(form);
|
||||
Index++;
|
||||
|
||||
Device.FormSwitched = true;
|
||||
|
||||
if (Index < 2)
|
||||
return;
|
||||
|
||||
await form.OnInit(new InitEventArgs(args));
|
||||
|
||||
await form.OnOpened(new EventArgs());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pops the current form and pushes a new one.
|
||||
/// Will help to remove forms so you can not navigate back to them.
|
||||
/// </summary>
|
||||
/// <param name="form"></param>
|
||||
/// <param name="args"></param>
|
||||
/// <returns></returns>
|
||||
public virtual async Task PushAndReplaceAsync(FormBase form, params object[] args)
|
||||
{
|
||||
await PopAsync();
|
||||
|
||||
await PushAsync(form, args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the current form from the stack.
|
||||
/// </summary>
|
||||
public FormBase CurrentForm
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.History.Count == 0)
|
||||
return null;
|
||||
|
||||
return this.History[Index];
|
||||
}
|
||||
}
|
||||
|
||||
public List<FormBase> GetAllForms()
|
||||
{
|
||||
return History.ToList();
|
||||
}
|
||||
|
||||
|
||||
public void LoadState(LoadStateEventArgs e)
|
||||
{
|
||||
if (e.Get("$controller.history.count") == null)
|
||||
return;
|
||||
|
||||
|
||||
int historyCount = e.GetInt("$controller.history.count");
|
||||
|
||||
for (int i = 0; i < historyCount; i++)
|
||||
{
|
||||
|
||||
var c = e.GetObject($"$controller.history[{i}]") as Dictionary<String, object>;
|
||||
|
||||
|
||||
|
||||
var qname = e.Get($"$controller.history[{i}].type");
|
||||
|
||||
if (qname == null)
|
||||
continue;
|
||||
|
||||
Type t = Type.GetType(qname.ToString());
|
||||
if (t == null || !t.IsSubclassOf(typeof(FormBase)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var form = t.GetConstructor(new Type[] { })?.Invoke(new object[] { }) as FormBase;
|
||||
|
||||
//No default constructor, fallback
|
||||
if (form == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var properties = c.Where(a => a.Key.StartsWith("$"));
|
||||
|
||||
var fields = form.GetType().GetProperties(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic).Where(a => a.GetCustomAttributes(typeof(SaveState), true).Length != 0).ToList();
|
||||
|
||||
foreach (var p in properties)
|
||||
{
|
||||
var f = fields.FirstOrDefault(a => a.Name == p.Key.Substring(1));
|
||||
if (f == null)
|
||||
continue;
|
||||
|
||||
try
|
||||
{
|
||||
if (f.PropertyType.IsEnum)
|
||||
{
|
||||
var ent = Enum.Parse(f.PropertyType, p.Value.ToString());
|
||||
|
||||
f.SetValue(form, ent);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
f.SetValue(form, p.Value);
|
||||
}
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
|
||||
Tools.Conversion.CustomConversionChecks(form, p, f);
|
||||
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
form.Device = this.Device;
|
||||
form.Client = this.Client;
|
||||
form.NavigationController = this;
|
||||
|
||||
form.OnInit(new InitEventArgs());
|
||||
|
||||
this.History.Add(form);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void SaveState(SaveStateEventArgs e)
|
||||
{
|
||||
e.Set("$controller.history.count", History.Count.ToString());
|
||||
|
||||
int i = 0;
|
||||
foreach (var form in History)
|
||||
{
|
||||
var fields = form.GetType().GetProperties(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic).Where(a => a.GetCustomAttributes(typeof(SaveState), true).Length != 0).ToList();
|
||||
|
||||
var dt = new Dictionary<String, object>();
|
||||
foreach (var f in fields)
|
||||
{
|
||||
var val = f.GetValue(form);
|
||||
|
||||
dt.Add("$" + f.Name, val);
|
||||
}
|
||||
|
||||
e.Set($"$controller.history[{i}].type", form.GetType().AssemblyQualifiedName);
|
||||
|
||||
e.SetObject($"$controller.history[{i}]", dt);
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#region "Methods passthrough"
|
||||
|
||||
public override async Task NavigateTo(FormBase newForm, params object[] args)
|
||||
{
|
||||
await CurrentForm.NavigateTo(newForm, args);
|
||||
}
|
||||
|
||||
public override async Task LoadControls(MessageResult message)
|
||||
{
|
||||
await CurrentForm.LoadControls(message);
|
||||
}
|
||||
|
||||
public override async Task Load(MessageResult message)
|
||||
{
|
||||
await CurrentForm.Load(message);
|
||||
}
|
||||
|
||||
public override async Task ActionControls(MessageResult message)
|
||||
{
|
||||
await CurrentForm.ActionControls(message);
|
||||
}
|
||||
|
||||
public override async Task Action(MessageResult message)
|
||||
{
|
||||
await CurrentForm.Action(message);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public override async Task Edited(MessageResult message)
|
||||
{
|
||||
await CurrentForm.Edited(message);
|
||||
}
|
||||
|
||||
public override async Task Render(MessageResult message)
|
||||
{
|
||||
await CurrentForm.Render(message);
|
||||
}
|
||||
|
||||
public override async Task RenderControls(MessageResult message)
|
||||
{
|
||||
await CurrentForm.RenderControls(message);
|
||||
}
|
||||
|
||||
public override async Task PreLoad(MessageResult message)
|
||||
{
|
||||
await CurrentForm.PreLoad(message);
|
||||
}
|
||||
|
||||
public override async Task ReturnFromModal(ModalDialog modal)
|
||||
{
|
||||
await CurrentForm.ReturnFromModal(modal);
|
||||
}
|
||||
|
||||
public override async Task SentData(DataResult message)
|
||||
{
|
||||
await CurrentForm.SentData(message);
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// The message the users sees.
|
||||
/// </summary>
|
||||
public String Message { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The returned text value by the user.
|
||||
/// </summary>
|
||||
public String Value { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// An additional optional value.
|
||||
/// </summary>
|
||||
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<EventArgs> Completed
|
||||
public event EventHandler<PromptDialogCompletedEventArgs> Completed
|
||||
{
|
||||
add
|
||||
{
|
||||
@@ -104,9 +116,9 @@ namespace TelegramBotBase.Form
|
||||
}
|
||||
}
|
||||
|
||||
public void OnCompleted(EventArgs e)
|
||||
public void OnCompleted(PromptDialogCompletedEventArgs e)
|
||||
{
|
||||
(this.__Events[__evCompleted] as EventHandler<EventArgs>)?.Invoke(this, e);
|
||||
(this.__Events[__evCompleted] as EventHandler<PromptDialogCompletedEventArgs>)?.Invoke(this, e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using TelegramBotBase.Base;
|
||||
using static TelegramBotBase.Base.Async;
|
||||
|
||||
|
||||
namespace TelegramBotBase.Form
|
||||
{
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Telegram.Bot.Types.ReplyMarkups;
|
||||
|
||||
namespace TelegramBotBase.Form
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for button handling
|
||||
/// </summary>
|
||||
public class TagButtonBase : ButtonBase
|
||||
{
|
||||
public String Tag { get; set; }
|
||||
|
||||
public TagButtonBase()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public TagButtonBase(String Text, String Value, String Tag)
|
||||
{
|
||||
this.Text = Text;
|
||||
this.Value = Value;
|
||||
this.Tag = Tag;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns an inline Button
|
||||
/// </summary>
|
||||
/// <param name="form"></param>
|
||||
/// <returns></returns>
|
||||
public override InlineKeyboardButton ToInlineButton(ButtonForm form)
|
||||
{
|
||||
String id = (form.DependencyControl != null ? form.DependencyControl.ControlID + "_" : "");
|
||||
|
||||
return InlineKeyboardButton.WithCallbackData(this.Text, id + this.Value);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns a KeyBoardButton
|
||||
/// </summary>
|
||||
/// <param name="form"></param>
|
||||
/// <returns></returns>
|
||||
public override KeyboardButton ToKeyboardButton(ButtonForm form)
|
||||
{
|
||||
return new KeyboardButton(this.Text);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using TelegramBotBase.Controls.Hybrid;
|
||||
|
||||
namespace TelegramBotBase.Interfaces
|
||||
{
|
||||
public interface IDataSource<T>
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Returns the amount of items within this source.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
int Count { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns the item at the specific index.
|
||||
/// </summary>
|
||||
/// <param name="index"></param>
|
||||
/// <returns></returns>
|
||||
T ItemAt(int index);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get all items from this source within this range.
|
||||
/// </summary>
|
||||
/// <param name="start"></param>
|
||||
/// <param name="count"></param>
|
||||
/// <returns></returns>
|
||||
List<T> ItemRange(int start, int count);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of all items of this datasource.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
List<T> AllItems();
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using TelegramBotBase.Form;
|
||||
|
||||
namespace TelegramBotBase.Interfaces
|
||||
{
|
||||
interface IDeviceSession
|
||||
{
|
||||
/// <summary>
|
||||
/// Device or chat id
|
||||
/// </summary>
|
||||
long DeviceId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Username of user or group
|
||||
/// </summary>
|
||||
String ChatTitle { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// When did any last action happend (message received or button clicked)
|
||||
/// </summary>
|
||||
DateTime LastAction { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the form where the user/group is at the moment.
|
||||
/// </summary>
|
||||
FormBase ActiveForm { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the previous shown form
|
||||
/// </summary>
|
||||
FormBase PreviousForm { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// contains if the form has been switched (navigated)
|
||||
/// </summary>
|
||||
bool FormSwitched { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,9 @@ namespace TelegramBotBase.Localizations
|
||||
Values["ButtonGrid_NextPage"] = "▶️";
|
||||
Values["ButtonGrid_CurrentPage"] = "Page {0} of {1}";
|
||||
Values["ButtonGrid_SearchFeature"] = "💡 Send a message to filter the list. Click the 🔍 to reset the filter.";
|
||||
Values["ButtonGrid_Back"] = "Back";
|
||||
Values["ButtonGrid_CheckAll"] = "Check all";
|
||||
Values["ButtonGrid_UncheckAll"] = "Uncheck all";
|
||||
Values["CalendarPicker_Title"] = "Pick date";
|
||||
Values["CalendarPicker_PreviousPage"] = "◀️";
|
||||
Values["CalendarPicker_NextPage"] = "▶️";
|
||||
@@ -25,6 +28,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";
|
||||
}
|
||||
|
||||
@@ -8,7 +8,32 @@ namespace TelegramBotBase.Localizations
|
||||
{
|
||||
public German() : base()
|
||||
{
|
||||
|
||||
Values["Language"] = "Deutsch (German)";
|
||||
Values["ButtonGrid_Title"] = "Menü";
|
||||
Values["ButtonGrid_NoItems"] = "Es sind keine Einträge vorhanden.";
|
||||
Values["ButtonGrid_PreviousPage"] = "◀️";
|
||||
Values["ButtonGrid_NextPage"] = "▶️";
|
||||
Values["ButtonGrid_CurrentPage"] = "Seite {0} von {1}";
|
||||
Values["ButtonGrid_SearchFeature"] = "💡 Sende eine Nachricht um die Liste zu filtern. Klicke die 🔍 um den Filter zurückzusetzen.";
|
||||
Values["ButtonGrid_Back"] = "Zurück";
|
||||
Values["ButtonGrid_CheckAll"] = "Alle auswählen";
|
||||
Values["ButtonGrid_UncheckAll"] = "Keine auswählen";
|
||||
Values["CalendarPicker_Title"] = "Datum auswählen";
|
||||
Values["CalendarPicker_PreviousPage"] = "◀️";
|
||||
Values["CalendarPicker_NextPage"] = "▶️";
|
||||
Values["TreeView_Title"] = "Knoten auswählen";
|
||||
Values["TreeView_LevelUp"] = "🔼 Stufe hoch";
|
||||
Values["ToggleButton_On"] = "An";
|
||||
Values["ToggleButton_Off"] = "Aus";
|
||||
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";
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ using System.Text;
|
||||
|
||||
namespace TelegramBotBase.Localizations
|
||||
{
|
||||
public class Localization
|
||||
public abstract class Localization
|
||||
{
|
||||
public Dictionary<String, String> Values = new Dictionary<string, string>();
|
||||
|
||||
@@ -18,25 +18,7 @@ namespace TelegramBotBase.Localizations
|
||||
|
||||
public Localization()
|
||||
{
|
||||
Values["Language"] = "Deutsch (German)";
|
||||
Values["ButtonGrid_Title"] = "Menü";
|
||||
Values["ButtonGrid_NoItems"] = "Es sind keine Einträge vorhanden.";
|
||||
Values["ButtonGrid_PreviousPage"] = "◀️";
|
||||
Values["ButtonGrid_NextPage"] = "▶️";
|
||||
Values["ButtonGrid_CurrentPage"] = "Seite {0} von {1}";
|
||||
Values["ButtonGrid_SearchFeature"] = "💡 Sende eine Nachricht um die Liste zu filtern. Klicke die 🔍 um den Filter zurückzusetzen.";
|
||||
Values["CalendarPicker_Title"] = "Datum auswählen";
|
||||
Values["CalendarPicker_PreviousPage"] = "◀️";
|
||||
Values["CalendarPicker_NextPage"] = "▶️";
|
||||
Values["TreeView_Title"] = "Knoten auswählen";
|
||||
Values["TreeView_LevelUp"] = "🔼 Stufe hoch";
|
||||
Values["ToggleButton_On"] = "An";
|
||||
Values["ToggleButton_Off"] = "Aus";
|
||||
Values["ToggleButton_OnIcon"] = "⚫";
|
||||
Values["ToggleButton_OffIcon"] = "⚪";
|
||||
Values["ToggleButton_Title"] = "Schalter";
|
||||
Values["PromptDialog_Back"] = "Zurück";
|
||||
Values["ToggleButton_Changed"] = "Einstellung geändert";
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -115,6 +115,20 @@ namespace TelegramBotBase
|
||||
return this.SessionList.Where(a => a.Key < 0).Select(a => a.Value).ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads the previously saved states from the machine.
|
||||
/// </summary>
|
||||
public async void LoadSessionStates()
|
||||
{
|
||||
if (BotBase.StateMachine == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
LoadSessionStates(BotBase.StateMachine);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Loads the previously saved states from the machine.
|
||||
/// </summary>
|
||||
@@ -135,6 +149,10 @@ namespace TelegramBotBase
|
||||
continue;
|
||||
}
|
||||
|
||||
//Key already existing
|
||||
if (this.SessionList.ContainsKey(s.DeviceId))
|
||||
continue;
|
||||
|
||||
var form = t.GetConstructor(new Type[] { })?.Invoke(new object[] { }) as FormBase;
|
||||
|
||||
//No default constructor, fallback
|
||||
@@ -180,6 +198,8 @@ namespace TelegramBotBase
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
|
||||
Tools.Conversion.CustomConversionChecks(form, p, f);
|
||||
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -188,6 +208,13 @@ namespace TelegramBotBase
|
||||
}
|
||||
}
|
||||
|
||||
form.Client = Client;
|
||||
var device = new DeviceSession(s.DeviceId, form);
|
||||
|
||||
device.ChatTitle = s.ChatTitle;
|
||||
|
||||
this.SessionList.Add(s.DeviceId, device);
|
||||
|
||||
//Is Subclass of IStateForm
|
||||
var iform = form as IStateForm;
|
||||
if (iform != null)
|
||||
@@ -197,14 +224,6 @@ namespace TelegramBotBase
|
||||
iform.LoadState(ls);
|
||||
}
|
||||
|
||||
|
||||
form.Client = Client;
|
||||
var device = new DeviceSession(s.DeviceId, form);
|
||||
|
||||
device.ChatTitle = s.ChatTitle;
|
||||
|
||||
this.SessionList.Add(s.DeviceId, device);
|
||||
|
||||
try
|
||||
{
|
||||
await form.OnInit(new InitEventArgs());
|
||||
@@ -220,6 +239,9 @@ namespace TelegramBotBase
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Saves all open states into the machine.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
@@ -16,6 +17,7 @@ using TelegramBotBase.Args;
|
||||
using TelegramBotBase.Base;
|
||||
using TelegramBotBase.Exceptions;
|
||||
using TelegramBotBase.Form;
|
||||
using TelegramBotBase.Interfaces;
|
||||
using TelegramBotBase.Markdown;
|
||||
|
||||
namespace TelegramBotBase.Sessions
|
||||
@@ -23,7 +25,7 @@ namespace TelegramBotBase.Sessions
|
||||
/// <summary>
|
||||
/// Base class for a device/chat session
|
||||
/// </summary>
|
||||
public class DeviceSession
|
||||
public class DeviceSession : IDeviceSession
|
||||
{
|
||||
/// <summary>
|
||||
/// Device or chat id
|
||||
@@ -117,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()
|
||||
{
|
||||
@@ -154,7 +157,7 @@ namespace TelegramBotBase.Sessions
|
||||
|
||||
try
|
||||
{
|
||||
return await this.Client.TelegramClient.EditMessageTextAsync(this.DeviceId, messageId, text, parseMode, replyMarkup: markup);
|
||||
return await API(a => a.EditMessageTextAsync(this.DeviceId, messageId, text, parseMode, replyMarkup: markup));
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -181,7 +184,7 @@ namespace TelegramBotBase.Sessions
|
||||
|
||||
try
|
||||
{
|
||||
return await this.Client.TelegramClient.EditMessageTextAsync(this.DeviceId, messageId, text, parseMode, replyMarkup: markup);
|
||||
return await API(a => a.EditMessageTextAsync(this.DeviceId, messageId, text, parseMode, replyMarkup: markup));
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -210,7 +213,7 @@ namespace TelegramBotBase.Sessions
|
||||
|
||||
try
|
||||
{
|
||||
return await this.Client.TelegramClient.EditMessageTextAsync(this.DeviceId, message.MessageId, message.Text, parseMode, replyMarkup: markup);
|
||||
return await API(a => a.EditMessageTextAsync(this.DeviceId, message.MessageId, message.Text, parseMode, replyMarkup: markup));
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -232,7 +235,7 @@ namespace TelegramBotBase.Sessions
|
||||
|
||||
try
|
||||
{
|
||||
return await this.Client.TelegramClient.EditMessageReplyMarkupAsync(this.DeviceId, messageId, bf);
|
||||
return await API(a => a.EditMessageReplyMarkupAsync(this.DeviceId, messageId, bf));
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -257,8 +260,6 @@ namespace TelegramBotBase.Sessions
|
||||
|
||||
InlineKeyboardMarkup markup = buttons;
|
||||
|
||||
Message m = null;
|
||||
|
||||
if (text.Length > Constants.Telegram.MaxMessageLength)
|
||||
{
|
||||
throw new MaxLengthException(text.Length);
|
||||
@@ -271,20 +272,17 @@ namespace TelegramBotBase.Sessions
|
||||
|
||||
try
|
||||
{
|
||||
m = await (this.Client.TelegramClient.SendTextMessageAsync(deviceId, text, parseMode, replyToMessageId: replyTo, replyMarkup: markup, disableNotification: disableNotification));
|
||||
var t = API(a => a.SendTextMessageAsync(deviceId, text, parseMode, replyToMessageId: replyTo, replyMarkup: markup, disableNotification: disableNotification));
|
||||
|
||||
OnMessageSent(new MessageSentEventArgs(m));
|
||||
}
|
||||
catch (ApiRequestException)
|
||||
{
|
||||
return null;
|
||||
var o = GetOrigin(new StackTrace());
|
||||
OnMessageSent(new MessageSentEventArgs(await t, o));
|
||||
|
||||
return await t;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -313,8 +311,6 @@ namespace TelegramBotBase.Sessions
|
||||
if (this.ActiveForm == null)
|
||||
return null;
|
||||
|
||||
Message m = null;
|
||||
|
||||
if (text.Length > Constants.Telegram.MaxMessageLength)
|
||||
{
|
||||
throw new MaxLengthException(text.Length);
|
||||
@@ -327,20 +323,17 @@ namespace TelegramBotBase.Sessions
|
||||
|
||||
try
|
||||
{
|
||||
m = await (this.Client.TelegramClient.SendTextMessageAsync(this.DeviceId, text, parseMode, replyToMessageId: replyTo, replyMarkup: markup, disableNotification: disableNotification));
|
||||
var t = API(a => a.SendTextMessageAsync(this.DeviceId, text, parseMode, replyToMessageId: replyTo, replyMarkup: markup, disableNotification: disableNotification));
|
||||
|
||||
OnMessageSent(new MessageSentEventArgs(m));
|
||||
}
|
||||
catch (ApiRequestException)
|
||||
{
|
||||
return null;
|
||||
var o = GetOrigin(new StackTrace());
|
||||
OnMessageSent(new MessageSentEventArgs(await t, o));
|
||||
|
||||
return await t;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -356,8 +349,6 @@ namespace TelegramBotBase.Sessions
|
||||
if (this.ActiveForm == null)
|
||||
return null;
|
||||
|
||||
Message m = null;
|
||||
|
||||
if (text.Length > Constants.Telegram.MaxMessageLength)
|
||||
{
|
||||
throw new MaxLengthException(text.Length);
|
||||
@@ -370,20 +361,17 @@ namespace TelegramBotBase.Sessions
|
||||
|
||||
try
|
||||
{
|
||||
m = await (this.Client.TelegramClient.SendTextMessageAsync(this.DeviceId, text, parseMode, replyToMessageId: replyTo, replyMarkup: markup, disableNotification: disableNotification));
|
||||
var t = API(a => a.SendTextMessageAsync(this.DeviceId, text, parseMode, replyToMessageId: replyTo, replyMarkup: markup, disableNotification: disableNotification));
|
||||
|
||||
OnMessageSent(new MessageSentEventArgs(m));
|
||||
}
|
||||
catch (ApiRequestException)
|
||||
{
|
||||
return null;
|
||||
var o = GetOrigin(new StackTrace());
|
||||
OnMessageSent(new MessageSentEventArgs(await t, o));
|
||||
|
||||
return await t;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -401,24 +389,19 @@ namespace TelegramBotBase.Sessions
|
||||
|
||||
InlineKeyboardMarkup markup = buttons;
|
||||
|
||||
Message m = null;
|
||||
|
||||
try
|
||||
{
|
||||
m = await this.Client.TelegramClient.SendPhotoAsync(this.DeviceId, file, caption: caption, parseMode: parseMode, replyToMessageId: replyTo, replyMarkup: markup, disableNotification: disableNotification);
|
||||
var t = API(a => a.SendPhotoAsync(this.DeviceId, file, caption: caption, parseMode: parseMode, replyToMessageId: replyTo, replyMarkup: markup, disableNotification: disableNotification));
|
||||
|
||||
OnMessageSent(new MessageSentEventArgs(m));
|
||||
}
|
||||
catch (ApiRequestException)
|
||||
{
|
||||
return null;
|
||||
var o = GetOrigin(new StackTrace());
|
||||
OnMessageSent(new MessageSentEventArgs(await t, o));
|
||||
|
||||
return await t;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -474,24 +457,19 @@ namespace TelegramBotBase.Sessions
|
||||
|
||||
InlineKeyboardMarkup markup = buttons;
|
||||
|
||||
Message m = null;
|
||||
|
||||
try
|
||||
{
|
||||
m = await this.Client.TelegramClient.SendVideoAsync(this.DeviceId, file, caption: caption, parseMode: parseMode, replyToMessageId: replyTo, replyMarkup: markup, disableNotification: disableNotification);
|
||||
var t = API(a => a.SendVideoAsync(this.DeviceId, file, caption: caption, parseMode: parseMode, replyToMessageId: replyTo, replyMarkup: markup, disableNotification: disableNotification));
|
||||
|
||||
OnMessageSent(new MessageSentEventArgs(m));
|
||||
}
|
||||
catch (ApiRequestException)
|
||||
{
|
||||
return null;
|
||||
var o = GetOrigin(new StackTrace());
|
||||
OnMessageSent(new MessageSentEventArgs(await t, o));
|
||||
|
||||
return await t;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -509,24 +487,19 @@ namespace TelegramBotBase.Sessions
|
||||
|
||||
InlineKeyboardMarkup markup = buttons;
|
||||
|
||||
Message m = null;
|
||||
|
||||
try
|
||||
{
|
||||
m = await this.Client.TelegramClient.SendVideoAsync(this.DeviceId, new InputOnlineFile(url), parseMode: parseMode, replyToMessageId: replyTo, replyMarkup: markup, disableNotification: disableNotification);
|
||||
var t = API(a => a.SendVideoAsync(this.DeviceId, new InputOnlineFile(url), parseMode: parseMode, replyToMessageId: replyTo, replyMarkup: markup, disableNotification: disableNotification));
|
||||
|
||||
OnMessageSent(new MessageSentEventArgs(m));
|
||||
}
|
||||
catch (ApiRequestException)
|
||||
{
|
||||
return null;
|
||||
var o = GetOrigin(new StackTrace());
|
||||
OnMessageSent(new MessageSentEventArgs(await t, o));
|
||||
|
||||
return await t;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -591,11 +564,19 @@ namespace TelegramBotBase.Sessions
|
||||
markup = buttons;
|
||||
}
|
||||
|
||||
var m = await this.Client.TelegramClient.SendDocumentAsync(this.DeviceId, document, caption, replyMarkup: markup, disableNotification: disableNotification, replyToMessageId: replyTo);
|
||||
try
|
||||
{
|
||||
var t = API(a => a.SendDocumentAsync(this.DeviceId, document, caption, replyMarkup: markup, disableNotification: disableNotification, replyToMessageId: replyTo));
|
||||
|
||||
OnMessageSent(new MessageSentEventArgs(m));
|
||||
var o = GetOrigin(new StackTrace());
|
||||
OnMessageSent(new MessageSentEventArgs(await t, o));
|
||||
|
||||
return m;
|
||||
return await t;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -605,7 +586,7 @@ namespace TelegramBotBase.Sessions
|
||||
/// <returns></returns>
|
||||
public async Task SetAction(ChatAction action)
|
||||
{
|
||||
await this.Client.TelegramClient.SendChatActionAsync(this.DeviceId, action);
|
||||
await API(a => a.SendChatActionAsync(this.DeviceId, action));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -619,7 +600,7 @@ namespace TelegramBotBase.Sessions
|
||||
{
|
||||
var rck = new ReplyKeyboardMarkup(KeyboardButton.WithRequestContact(buttonText));
|
||||
rck.OneTimeKeyboard = OneTimeOnly;
|
||||
return await this.Client.TelegramClient.SendTextMessageAsync(this.DeviceId, requestMessage, replyMarkup: rck);
|
||||
return await API(a => a.SendTextMessageAsync(this.DeviceId, requestMessage, replyMarkup: rck));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -633,7 +614,7 @@ namespace TelegramBotBase.Sessions
|
||||
{
|
||||
var rcl = new ReplyKeyboardMarkup(KeyboardButton.WithRequestLocation(buttonText));
|
||||
rcl.OneTimeKeyboard = OneTimeOnly;
|
||||
return await this.Client.TelegramClient.SendTextMessageAsync(this.DeviceId, requestMessage, replyMarkup: rcl);
|
||||
return await API(a => a.SendTextMessageAsync(this.DeviceId, requestMessage, replyMarkup: rcl));
|
||||
}
|
||||
|
||||
public async Task<Message> HideReplyKeyboard(String closedMsg = "Closed", bool autoDeleteResponse = true)
|
||||
@@ -663,18 +644,12 @@ namespace TelegramBotBase.Sessions
|
||||
/// <returns></returns>
|
||||
public virtual async Task<bool> DeleteMessage(int messageId = -1)
|
||||
{
|
||||
try
|
||||
{
|
||||
await this.Client.TelegramClient.DeleteMessageAsync(this.DeviceId, messageId);
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (ApiRequestException)
|
||||
{
|
||||
await RAW(a => a.DeleteMessageAsync(this.DeviceId, messageId));
|
||||
|
||||
}
|
||||
OnMessageDeleted(new MessageDeletedEventArgs(messageId));
|
||||
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -692,7 +667,7 @@ namespace TelegramBotBase.Sessions
|
||||
{
|
||||
try
|
||||
{
|
||||
await this.Client.TelegramClient.SetChatPermissionsAsync(this.DeviceId, permissions);
|
||||
await API(a => a.SetChatPermissionsAsync(this.DeviceId, permissions));
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -700,11 +675,30 @@ namespace TelegramBotBase.Sessions
|
||||
}
|
||||
}
|
||||
|
||||
public virtual async Task RestrictUser(int userId, ChatPermissions permissions, DateTime until = default(DateTime))
|
||||
private Type GetOrigin(StackTrace stackTrace)
|
||||
{
|
||||
for (int i = 0; i < stackTrace.FrameCount; i++)
|
||||
{
|
||||
var methodBase = stackTrace.GetFrame(i).GetMethod();
|
||||
|
||||
//Debug.WriteLine(methodBase.Name);
|
||||
|
||||
if (methodBase.DeclaringType.IsSubclassOf(typeof(FormBase)) | methodBase.DeclaringType.IsSubclassOf(typeof(ControlBase)))
|
||||
{
|
||||
return methodBase.DeclaringType;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
#region "Users"
|
||||
|
||||
public virtual async Task RestrictUser(long userId, ChatPermissions permissions, DateTime until = default(DateTime))
|
||||
{
|
||||
try
|
||||
{
|
||||
await this.Client.TelegramClient.RestrictChatMemberAsync(this.DeviceId, userId, permissions, until);
|
||||
await API(a => a.RestrictChatMemberAsync(this.DeviceId, userId, permissions, until));
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -712,11 +706,11 @@ namespace TelegramBotBase.Sessions
|
||||
}
|
||||
}
|
||||
|
||||
public virtual async Task<ChatMember> GetChatUser(int userId)
|
||||
public virtual async Task<ChatMember> GetChatUser(long userId)
|
||||
{
|
||||
try
|
||||
{
|
||||
return await this.Client.TelegramClient.GetChatMemberAsync(this.DeviceId, userId);
|
||||
return await API(a => a.GetChatMemberAsync(this.DeviceId, userId));
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -725,11 +719,11 @@ namespace TelegramBotBase.Sessions
|
||||
return null;
|
||||
}
|
||||
|
||||
public virtual async Task KickUser(int userId, DateTime until = default(DateTime))
|
||||
public virtual async Task KickUser(long userId, DateTime until = default(DateTime))
|
||||
{
|
||||
try
|
||||
{
|
||||
await this.Client.TelegramClient.KickChatMemberAsync(this.DeviceId, userId, until);
|
||||
await API(a => a.KickChatMemberAsync(this.DeviceId, userId, until));
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -737,11 +731,11 @@ namespace TelegramBotBase.Sessions
|
||||
}
|
||||
}
|
||||
|
||||
public virtual async Task UnbanUser(int userId)
|
||||
public virtual async Task UnbanUser(long userId)
|
||||
{
|
||||
try
|
||||
{
|
||||
await this.Client.TelegramClient.UnbanChatMemberAsync(this.DeviceId, userId);
|
||||
await API(a => a.UnbanChatMemberAsync(this.DeviceId, userId));
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -749,7 +743,78 @@ namespace TelegramBotBase.Sessions
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Gives access to the original TelegramClient without any Exception catchings.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="call"></param>
|
||||
/// <returns></returns>
|
||||
public T RAW<T>(Func<Telegram.Bot.TelegramBotClient, T> call)
|
||||
{
|
||||
return call(this.Client.TelegramClient);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This will call a function on the TelegramClient and automatically Retry if an limit has been exceeded.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="call"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<T> API<T>(Func<Telegram.Bot.TelegramBotClient, Task<T>> call)
|
||||
{
|
||||
var numberOfTries = 0;
|
||||
while (numberOfTries < DeviceSession.MaxNumberOfRetries)
|
||||
{
|
||||
try
|
||||
{
|
||||
return await call(Client.TelegramClient);
|
||||
}
|
||||
catch (ApiRequestException ex)
|
||||
{
|
||||
if (ex.ErrorCode != 429)
|
||||
throw;
|
||||
|
||||
if (ex.Parameters != null)
|
||||
await Task.Delay(ex.Parameters.RetryAfter * 1000);
|
||||
|
||||
numberOfTries++;
|
||||
}
|
||||
}
|
||||
return default(T);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This will call a function on the TelegramClient and automatically Retry if an limit has been exceeded.
|
||||
/// </summary>
|
||||
/// <param name="call"></param>
|
||||
/// <returns></returns>
|
||||
public async Task API(Func<Telegram.Bot.TelegramBotClient, Task> call)
|
||||
{
|
||||
var numberOfTries = 0;
|
||||
while (numberOfTries < DeviceSession.MaxNumberOfRetries)
|
||||
{
|
||||
try
|
||||
{
|
||||
await call(Client.TelegramClient);
|
||||
return;
|
||||
}
|
||||
catch (ApiRequestException ex)
|
||||
{
|
||||
if (ex.ErrorCode != 429)
|
||||
throw;
|
||||
|
||||
if (ex.Parameters != null)
|
||||
await Task.Delay(ex.Parameters.RetryAfter * 1000);
|
||||
|
||||
numberOfTries++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#region "Events"
|
||||
|
||||
/// <summary>
|
||||
/// Eventhandler for sent messages
|
||||
@@ -792,5 +857,38 @@ namespace TelegramBotBase.Sessions
|
||||
{
|
||||
(this.__Events[__evMessageReceived] as EventHandler<MessageReceivedEventArgs>)?.Invoke(this, e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Eventhandler for deleting messages
|
||||
/// </summary>
|
||||
public event EventHandler<MessageDeletedEventArgs> MessageDeleted
|
||||
{
|
||||
add
|
||||
{
|
||||
this.__Events.AddHandler(__evMessageDeleted, value);
|
||||
}
|
||||
remove
|
||||
{
|
||||
this.__Events.RemoveHandler(__evMessageDeleted, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void OnMessageDeleted(MessageDeletedEventArgs e)
|
||||
{
|
||||
(this.__Events[__evMessageDeleted] as EventHandler<MessageDeletedEventArgs>)?.Invoke(this, e);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region "Static"
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public static uint MaxNumberOfRetries { get; set; }
|
||||
|
||||
#endregion "Static"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>netstandard2.1;net461;netcoreapp3.1</TargetFrameworks>
|
||||
<TargetFrameworks>netstandard2.1;net472;net5;netcoreapp3.1</TargetFrameworks>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
|
||||
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
|
||||
<PackageProjectUrl>https://github.com/MajMcCloud/TelegramBotFramework</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/MajMcCloud/TelegramBotFramework</RepositoryUrl>
|
||||
<PackageReleaseNotes>- moving from .Net Framework 4.7.2 to .Net Standard 2.1 for the Library and .Net Core 3.1 for the test project!</PackageReleaseNotes>
|
||||
<PackageReleaseNotes>- moving from .Net Framework 4.7.2 to .Net Standard 2.1 for the Library and .Net Core 3.1 for the test project!</PackageReleaseNotes>
|
||||
<Configurations>Debug;Release;</Configurations>
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
<RunAnalyzersDuringBuild>false</RunAnalyzersDuringBuild>
|
||||
@@ -62,29 +62,16 @@
|
||||
<None Remove="Archive\**" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="cpack.ps1" />
|
||||
<None Remove="cpack_bak.ps1" />
|
||||
<None Remove="cpush.ps1" />
|
||||
<None Remove="nuget.exe" />
|
||||
<None Remove="TelegramBotBase.1.5.0.nupkg" />
|
||||
<None Remove="TelegramBotBase.1.5.0.zip" />
|
||||
<None Remove="TelegramBotBase.1.5.1.nupkg" />
|
||||
<None Remove="TelegramBotBase.1.5.1.zip" />
|
||||
<None Remove="TelegramBotBase.1.5.2.nupkg" />
|
||||
<None Remove="TelegramBotBase.1.5.2.zip" />
|
||||
<None Remove="TelegramBotBase.2.0.0.nupkg" />
|
||||
<None Remove="TelegramBotBase.2.1.0.nupkg" />
|
||||
<None Remove="TelegramBotBase.2.1.0.zip" />
|
||||
<None Remove="TelegramBotBase.3.0.0.nupkg" />
|
||||
<None Remove="TelegramBotBase.3.0.0.zip" />
|
||||
<None Remove="TelegramBotBase.nuspec" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||
<PackageReference Include="System.Drawing.Common" Version="4.7.0" />
|
||||
<PackageReference Include="Telegram.Bot" Version="15.5.1" />
|
||||
<PackageReference Include="System.ComponentModel" Version="4.3.0" />
|
||||
<PackageReference Include="System.Drawing.Common" Version="5.0.2" />
|
||||
<PackageReference Include="Telegram.Bot" Version="16.0.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Controls\Reply\" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using TelegramBotBase.Form;
|
||||
|
||||
namespace TelegramBotBase.Tools
|
||||
{
|
||||
public static class Conversion
|
||||
{
|
||||
public static void CustomConversionChecks(FormBase form, KeyValuePair<string, object> 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>))
|
||||
{
|
||||
decimal d = 0;
|
||||
if (decimal.TryParse(p.Value.ToString(), out d))
|
||||
{
|
||||
f.SetValue(form, d);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,21 @@ namespace TelegramBotBase.Tools
|
||||
{
|
||||
public static class Time
|
||||
{
|
||||
public static bool TryParseDay(string src, DateTime currentDate, out int resultDay)
|
||||
{
|
||||
return int.TryParse(src, out resultDay) && resultDay >= 1 && resultDay <= DateTime.DaysInMonth(currentDate.Year, currentDate.Month);
|
||||
}
|
||||
|
||||
public static bool TryParseMonth(string src, out int resultMonth)
|
||||
{
|
||||
return int.TryParse(src, out resultMonth) && resultMonth >= 1 && resultMonth <= 12;
|
||||
}
|
||||
|
||||
public static bool TryParseYear(string src, out int resultYear)
|
||||
{
|
||||
return int.TryParse(src, out resultYear) && resultYear >= 0 && resultYear <= DateTime.MaxValue.Year;
|
||||
}
|
||||
|
||||
public static DateTime StartOfWeek(this DateTime dt, DayOfWeek startOfWeek)
|
||||
{
|
||||
int diff = dt.DayOfWeek - startOfWeek;
|
||||
|
||||
@@ -7,7 +7,7 @@ using Telegram.Bot.Types;
|
||||
using TelegramBotBase;
|
||||
using TelegramBotBase.Form;
|
||||
using TelegramBotBaseTest.Tests;
|
||||
|
||||
using TelegramBotBase.Commands;
|
||||
namespace TelegramBotBaseTest
|
||||
{
|
||||
class Program
|
||||
@@ -17,7 +17,9 @@ namespace TelegramBotBaseTest
|
||||
|
||||
BotBase<Start> bb = new BotBase<Start>(APIKey);
|
||||
|
||||
bb.BotCommands.Add(new BotCommand() { Command = "start", Description = "Starts the bot" });
|
||||
bb.BotCommands.AddStartCommand("Starts the bot");
|
||||
bb.BotCommands.AddHelpCommand("Should show you some help");
|
||||
bb.BotCommands.AddSettingsCommand("Should show you some settings");
|
||||
bb.BotCommands.Add(new BotCommand() { Command = "form1", Description = "Opens test form 1" });
|
||||
bb.BotCommands.Add(new BotCommand() { Command = "form2", Description = "Opens test form 2" });
|
||||
bb.BotCommands.Add(new BotCommand() { Command = "params", Description = "Returns all send parameters as a message." });
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFrameworks>netcoreapp3.0;net461</TargetFrameworks>
|
||||
<TargetFrameworks>netcoreapp3.1;net5</TargetFrameworks>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<Configurations>Debug;Release</Configurations>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using TelegramBotBase.Args;
|
||||
using TelegramBotBase.Controls;
|
||||
using TelegramBotBase.Controls.Hybrid;
|
||||
using TelegramBotBase.Form;
|
||||
|
||||
namespace TelegramBotBaseTest.Tests.Controls
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using TelegramBotBase.Args;
|
||||
using TelegramBotBase.Controls;
|
||||
using TelegramBotBase.Controls.Hybrid;
|
||||
using TelegramBotBase.Form;
|
||||
|
||||
namespace TelegramBotBaseTest.Tests.Controls
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using TelegramBotBase.Args;
|
||||
using TelegramBotBase.Controls;
|
||||
using TelegramBotBase.Controls.Hybrid;
|
||||
using TelegramBotBase.Form;
|
||||
|
||||
namespace TelegramBotBaseTest.Tests.Controls
|
||||
{
|
||||
public class ButtonGridTagForm : AutoCleanForm
|
||||
{
|
||||
|
||||
TaggedButtonGrid m_Buttons = null;
|
||||
|
||||
public ButtonGridTagForm()
|
||||
{
|
||||
this.DeleteMode = TelegramBotBase.Enums.eDeleteMode.OnLeavingForm;
|
||||
|
||||
this.Init += ButtonGridTagForm_Init;
|
||||
}
|
||||
|
||||
private async Task ButtonGridTagForm_Init(object sender, InitEventArgs e)
|
||||
{
|
||||
m_Buttons = new TaggedButtonGrid();
|
||||
|
||||
m_Buttons.KeyboardType = TelegramBotBase.Enums.eKeyboardType.ReplyKeyboard;
|
||||
|
||||
m_Buttons.EnablePaging = true;
|
||||
|
||||
m_Buttons.HeadLayoutButtonRow = new List<ButtonBase>() { new ButtonBase("Back", "back") };
|
||||
|
||||
|
||||
var countries = CultureInfo.GetCultures(CultureTypes.SpecificCultures);
|
||||
|
||||
ButtonForm bf = new ButtonForm();
|
||||
|
||||
foreach (var c in countries)
|
||||
{
|
||||
bf.AddButtonRow(new TagButtonBase(c.EnglishName, c.EnglishName, c.Parent.EnglishName));
|
||||
}
|
||||
|
||||
m_Buttons.Tags = countries.Select(a => a.Parent.EnglishName).Distinct().OrderBy(a => a).ToList();
|
||||
m_Buttons.SelectedTags = countries.Select(a => a.Parent.EnglishName).Distinct().OrderBy(a => a).ToList();
|
||||
|
||||
m_Buttons.EnableCheckAllTools = true;
|
||||
|
||||
m_Buttons.DataSource = new TelegramBotBase.Datasources.ButtonFormDataSource(bf);
|
||||
|
||||
m_Buttons.ButtonClicked += Bg_ButtonClicked;
|
||||
|
||||
this.AddControl(m_Buttons);
|
||||
}
|
||||
|
||||
private async Task Bg_ButtonClicked(object sender, ButtonClickedEventArgs e)
|
||||
{
|
||||
if (e.Button == null)
|
||||
return;
|
||||
|
||||
switch (e.Button.Value)
|
||||
{
|
||||
|
||||
case "back":
|
||||
var start = new Menu();
|
||||
await this.NavigateTo(start);
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
|
||||
await this.Device.Send($"Button clicked with Text: {e.Button.Text} and Value {e.Button.Value}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ using TelegramBotBase.Base;
|
||||
using TelegramBotBase.Form;
|
||||
using TelegramBotBase.Controls;
|
||||
using TelegramBotBase.Args;
|
||||
using TelegramBotBase.Controls.Inline;
|
||||
|
||||
namespace TelegramBotBaseTest.Tests.Controls
|
||||
{
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
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.Hybrid;
|
||||
using TelegramBotBase.Form;
|
||||
|
||||
namespace TelegramBotBaseTest.Tests.Controls
|
||||
{
|
||||
public class CheckedButtonListForm : AutoCleanForm
|
||||
{
|
||||
|
||||
CheckedButtonList m_Buttons = null;
|
||||
|
||||
public CheckedButtonListForm()
|
||||
{
|
||||
this.DeleteMode = TelegramBotBase.Enums.eDeleteMode.OnLeavingForm;
|
||||
|
||||
this.Init += CheckedButtonListForm_Init;
|
||||
}
|
||||
|
||||
private async Task CheckedButtonListForm_Init(object sender, InitEventArgs e)
|
||||
{
|
||||
m_Buttons = new CheckedButtonList();
|
||||
|
||||
m_Buttons.KeyboardType = TelegramBotBase.Enums.eKeyboardType.InlineKeyBoard;
|
||||
m_Buttons.EnablePaging = true;
|
||||
|
||||
m_Buttons.HeadLayoutButtonRow = new List<ButtonBase>() { new ButtonBase("Back", "back"), new ButtonBase("Switch Keyboard", "switch") };
|
||||
|
||||
m_Buttons.SubHeadLayoutButtonRow = new List<ButtonBase>() { new ButtonBase("No checked items", "$") };
|
||||
|
||||
ButtonForm bf = new ButtonForm();
|
||||
|
||||
for (int i = 0; i < 30; i++)
|
||||
{
|
||||
bf.AddButtonRow($"{i + 1}. Item", i.ToString());
|
||||
}
|
||||
|
||||
m_Buttons.DataSource = new TelegramBotBase.Datasources.ButtonFormDataSource(bf);
|
||||
|
||||
m_Buttons.ButtonClicked += Bg_ButtonClicked;
|
||||
m_Buttons.CheckedChanged += M_Buttons_CheckedChanged;
|
||||
|
||||
this.AddControl(m_Buttons);
|
||||
}
|
||||
|
||||
private async Task M_Buttons_CheckedChanged(object sender, CheckedChangedEventArgs e)
|
||||
{
|
||||
m_Buttons.SubHeadLayoutButtonRow = new List<ButtonBase>() { new ButtonBase($"{m_Buttons.CheckedItems.Count} checked items", "$") };
|
||||
}
|
||||
|
||||
private async Task Bg_ButtonClicked(object sender, ButtonClickedEventArgs e)
|
||||
{
|
||||
if (e.Button == null)
|
||||
return;
|
||||
|
||||
switch (e.Button.Value)
|
||||
{
|
||||
case "back":
|
||||
|
||||
var start = new Menu();
|
||||
await NavigateTo(start);
|
||||
break;
|
||||
|
||||
|
||||
case "switch":
|
||||
switch (m_Buttons.KeyboardType)
|
||||
{
|
||||
case TelegramBotBase.Enums.eKeyboardType.ReplyKeyboard:
|
||||
m_Buttons.KeyboardType = TelegramBotBase.Enums.eKeyboardType.InlineKeyBoard;
|
||||
break;
|
||||
case TelegramBotBase.Enums.eKeyboardType.InlineKeyBoard:
|
||||
m_Buttons.KeyboardType = TelegramBotBase.Enums.eKeyboardType.ReplyKeyboard;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
await Device.Send($"Button clicked with Text: {e.Button.Text} and Value {e.Button.Value}");
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ using TelegramBotBase.Base;
|
||||
using TelegramBotBase.Form;
|
||||
using TelegramBotBase.Controls;
|
||||
using TelegramBotBase.Args;
|
||||
using TelegramBotBase.Controls.Inline;
|
||||
|
||||
namespace TelegramBotBaseTest.Tests.Controls
|
||||
{
|
||||
|
||||
@@ -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<ButtonBase>() { 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<ButtonBase>() { 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.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using TelegramBotBase.Base;
|
||||
using TelegramBotBase.Controls.Hybrid;
|
||||
using TelegramBotBase.Form;
|
||||
|
||||
namespace TelegramBotBaseTest.Tests.Controls
|
||||
{
|
||||
public class MultiViewForm : AutoCleanForm
|
||||
{
|
||||
|
||||
Subclass.MultiViewTest mvt = null;
|
||||
|
||||
ButtonGrid bg = null;
|
||||
|
||||
public MultiViewForm()
|
||||
{
|
||||
this.DeleteMode = TelegramBotBase.Enums.eDeleteMode.OnLeavingForm;
|
||||
this.Init += MultiViewForm_Init;
|
||||
}
|
||||
|
||||
private async Task MultiViewForm_Init(object sender, TelegramBotBase.Args.InitEventArgs e)
|
||||
{
|
||||
mvt = new Subclass.MultiViewTest();
|
||||
|
||||
AddControl(mvt);
|
||||
|
||||
bg = new ButtonGrid();
|
||||
bg.ButtonsForm = new ButtonForm();
|
||||
bg.ButtonsForm.AddButtonRow("Back", "$back$");
|
||||
bg.ButtonClicked += Bg_ButtonClicked;
|
||||
bg.KeyboardType = TelegramBotBase.Enums.eKeyboardType.ReplyKeyboard;
|
||||
AddControl(bg);
|
||||
}
|
||||
|
||||
private async Task Bg_ButtonClicked(object sender, TelegramBotBase.Args.ButtonClickedEventArgs e)
|
||||
{
|
||||
switch(e.Button.Value)
|
||||
{
|
||||
case "$back$":
|
||||
|
||||
var mn = new Menu();
|
||||
await NavigateTo(mn);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task Load(MessageResult message)
|
||||
{
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
public override async Task Action(MessageResult message)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
public override async Task Render(MessageResult message)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using TelegramBotBase.Args;
|
||||
using TelegramBotBase.Base;
|
||||
using TelegramBotBase.Form;
|
||||
|
||||
namespace TelegramBotBaseTest.Tests.Controls.Subclass
|
||||
{
|
||||
public class MultiViewTest : TelegramBotBase.Controls.Hybrid.MultiView
|
||||
{
|
||||
|
||||
|
||||
public override async Task Action(MessageResult result, string value = null)
|
||||
{
|
||||
|
||||
switch (result.RawData)
|
||||
{
|
||||
case "back":
|
||||
|
||||
this.SelectedViewIndex--;
|
||||
|
||||
break;
|
||||
case "next":
|
||||
|
||||
this.SelectedViewIndex++;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public override async Task RenderView(RenderViewEventArgs e)
|
||||
{
|
||||
|
||||
ButtonForm bf = new ButtonForm();
|
||||
bf.AddButtonRow(new ButtonBase("Back", "back"), new ButtonBase("Next", "next"));
|
||||
|
||||
switch (e.CurrentView)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
|
||||
await Device.Send($"Page {e.CurrentView + 1}", bf);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
await Device.Send("Unknown Page", bf);
|
||||
|
||||
break;
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using TelegramBotBase.Args;
|
||||
using TelegramBotBase.Controls;
|
||||
using TelegramBotBase.Controls.Inline;
|
||||
using TelegramBotBase.Form;
|
||||
|
||||
namespace TelegramBotBaseTest.Tests.Controls
|
||||
|
||||
@@ -7,6 +7,7 @@ using TelegramBotBase.Form;
|
||||
using TelegramBotBase.Controls;
|
||||
using TelegramBotBase.Base;
|
||||
using TelegramBotBase.Args;
|
||||
using TelegramBotBase.Controls.Inline;
|
||||
|
||||
namespace TelegramBotBaseTest.Tests.Controls
|
||||
{
|
||||
|
||||
@@ -0,0 +1,163 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using TelegramBotBase.Controls.Hybrid;
|
||||
using TelegramBotBase.Datasources;
|
||||
using TelegramBotBase.Form;
|
||||
|
||||
namespace TelegramBotBaseTest.Tests.Datasources
|
||||
{
|
||||
public class CustomDataSource : ButtonFormDataSource
|
||||
{
|
||||
|
||||
public List<String> Countries = new List<string>() { "Country 1", "Country 2", "Country 3" };
|
||||
|
||||
public CustomDataSource()
|
||||
{
|
||||
loadData();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method has the example purpose of creating and loading some example data.
|
||||
/// When using a database you do not need this kind of method.
|
||||
/// </summary>
|
||||
private void loadData()
|
||||
{
|
||||
//Exists data source? Read it
|
||||
if (File.Exists(AppContext.BaseDirectory + "countries.json"))
|
||||
{
|
||||
try
|
||||
{
|
||||
var List = Newtonsoft.Json.JsonConvert.DeserializeObject<List<String>>(File.ReadAllText("countries.json"));
|
||||
|
||||
|
||||
Countries = List;
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//If not, create it
|
||||
try
|
||||
{
|
||||
var countries = CultureInfo.GetCultures(CultureTypes.SpecificCultures).Select(a => a.DisplayName).ToList();
|
||||
|
||||
Countries = countries;
|
||||
|
||||
var tmp = Newtonsoft.Json.JsonConvert.SerializeObject(countries);
|
||||
|
||||
File.WriteAllText( AppContext.BaseDirectory + "countries.json", tmp);
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public override ButtonRow ItemAt(int index)
|
||||
{
|
||||
var item = Countries.ElementAt(index);
|
||||
if (item == null)
|
||||
return new ButtonRow();
|
||||
|
||||
return Render(item);
|
||||
}
|
||||
|
||||
public override List<ButtonRow> ItemRange(int start, int count)
|
||||
{
|
||||
var items = Countries.Skip(start).Take(count);
|
||||
|
||||
List<ButtonRow> lst = new List<ButtonRow>();
|
||||
foreach (var c in items)
|
||||
{
|
||||
lst.Add(Render(c));
|
||||
}
|
||||
|
||||
return lst;
|
||||
}
|
||||
|
||||
public override List<ButtonRow> AllItems()
|
||||
{
|
||||
List<ButtonRow> lst = new List<ButtonRow>();
|
||||
foreach (var c in Countries)
|
||||
{
|
||||
lst.Add(Render(c));
|
||||
}
|
||||
return lst;
|
||||
}
|
||||
|
||||
public override ButtonForm PickItems(int start, int count, string filter = null)
|
||||
{
|
||||
List<ButtonRow> rows = ItemRange(start, count);
|
||||
|
||||
ButtonForm lst = new ButtonForm();
|
||||
foreach (var c in rows)
|
||||
{
|
||||
lst.AddButtonRow(c);
|
||||
}
|
||||
return lst;
|
||||
}
|
||||
|
||||
public override ButtonForm PickAllItems(string filter = null)
|
||||
{
|
||||
List<ButtonRow> rows = AllItems();
|
||||
|
||||
ButtonForm bf = new ButtonForm();
|
||||
|
||||
bf.AddButtonRows(rows);
|
||||
|
||||
return bf;
|
||||
}
|
||||
|
||||
public override int CalculateMax(string filter = null)
|
||||
{
|
||||
if (filter == null)
|
||||
return Countries.Count;
|
||||
|
||||
return Countries.Where(a => a.IndexOf(filter, StringComparison.InvariantCultureIgnoreCase) != -1).Count();
|
||||
}
|
||||
|
||||
public override ButtonRow Render(object data)
|
||||
{
|
||||
var s = data as String;
|
||||
if (s == null)
|
||||
return new ButtonRow(new ButtonBase("Empty", "zero"));
|
||||
|
||||
return new ButtonRow(new ButtonBase(s, s));
|
||||
}
|
||||
|
||||
public override int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
return Countries.Count;
|
||||
}
|
||||
}
|
||||
|
||||
public override int ColumnCount
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
public override int RowCount
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.Count;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using TelegramBotBase.Base;
|
||||
using TelegramBotBase.Controls.Hybrid;
|
||||
using TelegramBotBase.Form;
|
||||
|
||||
namespace TelegramBotBaseTest.Tests.Datasources
|
||||
{
|
||||
public class List : FormBase
|
||||
{
|
||||
ButtonGrid __buttons = null;
|
||||
|
||||
public List()
|
||||
{
|
||||
this.Init += List_Init;
|
||||
}
|
||||
|
||||
private async Task List_Init(object sender, TelegramBotBase.Args.InitEventArgs e)
|
||||
{
|
||||
|
||||
__buttons = new ButtonGrid();
|
||||
|
||||
__buttons.EnablePaging = true;
|
||||
__buttons.EnableSearch = false;
|
||||
__buttons.ButtonClicked += __buttons_ButtonClicked;
|
||||
__buttons.KeyboardType = TelegramBotBase.Enums.eKeyboardType.ReplyKeyboard;
|
||||
__buttons.DeleteReplyMessage = true;
|
||||
|
||||
__buttons.HeadLayoutButtonRow = new ButtonRow(new ButtonBase("Back", "back"));
|
||||
|
||||
var cds = new CustomDataSource();
|
||||
__buttons.DataSource = cds;
|
||||
|
||||
AddControl(__buttons);
|
||||
}
|
||||
|
||||
private async Task __buttons_ButtonClicked(object sender, TelegramBotBase.Args.ButtonClickedEventArgs e)
|
||||
{
|
||||
switch(e.Button.Value)
|
||||
{
|
||||
case "back":
|
||||
|
||||
var mn = new Menu();
|
||||
await NavigateTo(mn);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task Load(MessageResult message)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
public override async Task Render(MessageResult message)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@ namespace TelegramBotBaseTest.Tests.Groups
|
||||
public class LinkReplaceTest : TelegramBotBase.Form.GroupForm
|
||||
{
|
||||
|
||||
Dictionary<int, int> Counter { get; set; } = new Dictionary<int, int>();
|
||||
Dictionary<long, int> Counter { get; set; } = new Dictionary<long, int>();
|
||||
|
||||
private const int Maximum = 3;
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using TelegramBotBase.Base;
|
||||
using TelegramBotBase.Form;
|
||||
using TelegramBotBaseTest.Tests.Controls;
|
||||
|
||||
namespace TelegramBotBaseTest.Tests
|
||||
{
|
||||
@@ -27,6 +28,7 @@ namespace TelegramBotBaseTest.Tests
|
||||
}
|
||||
|
||||
|
||||
await Device.HideReplyKeyboard();
|
||||
}
|
||||
|
||||
public override async Task Action(MessageResult message)
|
||||
@@ -39,7 +41,9 @@ namespace TelegramBotBaseTest.Tests
|
||||
if (call == null)
|
||||
return;
|
||||
|
||||
switch(call.Value)
|
||||
message.Handled = true;
|
||||
|
||||
switch (call.Value)
|
||||
{
|
||||
case "text":
|
||||
|
||||
@@ -91,8 +95,6 @@ namespace TelegramBotBaseTest.Tests
|
||||
|
||||
case "data":
|
||||
|
||||
message.Handled = true;
|
||||
|
||||
var data = new DataForm();
|
||||
|
||||
await this.NavigateTo(data);
|
||||
@@ -101,8 +103,6 @@ namespace TelegramBotBaseTest.Tests
|
||||
|
||||
case "calendar":
|
||||
|
||||
message.Handled = true;
|
||||
|
||||
var calendar = new Controls.CalendarPickerForm();
|
||||
|
||||
await this.NavigateTo(calendar);
|
||||
@@ -111,8 +111,6 @@ namespace TelegramBotBaseTest.Tests
|
||||
|
||||
case "month":
|
||||
|
||||
message.Handled = true;
|
||||
|
||||
var month = new Controls.MonthPickerForm();
|
||||
|
||||
await this.NavigateTo(month);
|
||||
@@ -121,8 +119,6 @@ namespace TelegramBotBaseTest.Tests
|
||||
|
||||
case "treeview":
|
||||
|
||||
message.Handled = true;
|
||||
|
||||
var tree = new Controls.TreeViewForms();
|
||||
|
||||
await this.NavigateTo(tree);
|
||||
@@ -131,16 +127,21 @@ namespace TelegramBotBaseTest.Tests
|
||||
|
||||
case "togglebuttons":
|
||||
|
||||
message.Handled = true;
|
||||
|
||||
var tb = new Controls.ToggleButtons();
|
||||
|
||||
await this.NavigateTo(tb);
|
||||
|
||||
break;
|
||||
case "buttongrid":
|
||||
|
||||
message.Handled = true;
|
||||
case "multitogglebuttons":
|
||||
|
||||
var mtb = new Controls.MultiToggleButtons();
|
||||
|
||||
await this.NavigateTo(mtb);
|
||||
|
||||
break;
|
||||
|
||||
case "buttongrid":
|
||||
|
||||
var bg = new Controls.ButtonGridForm();
|
||||
|
||||
@@ -150,12 +151,66 @@ namespace TelegramBotBaseTest.Tests
|
||||
|
||||
case "buttongridfilter":
|
||||
|
||||
message.Handled = true;
|
||||
|
||||
var bg2 = new Controls.ButtonGridPagingForm();
|
||||
|
||||
await this.NavigateTo(bg2);
|
||||
|
||||
break;
|
||||
|
||||
case "buttongridtags":
|
||||
|
||||
var bg3 = new Controls.ButtonGridTagForm();
|
||||
|
||||
await this.NavigateTo(bg3);
|
||||
|
||||
break;
|
||||
|
||||
case "multiview":
|
||||
|
||||
var mvf = new MultiViewForm();
|
||||
|
||||
await NavigateTo(mvf);
|
||||
|
||||
|
||||
break;
|
||||
|
||||
case "checkedbuttonlist":
|
||||
|
||||
var cbl = new CheckedButtonListForm();
|
||||
|
||||
await NavigateTo(cbl);
|
||||
|
||||
|
||||
break;
|
||||
|
||||
case "navigationcontroller":
|
||||
|
||||
var nc = new Navigation.Start();
|
||||
|
||||
await NavigateTo(nc);
|
||||
|
||||
|
||||
break;
|
||||
|
||||
case "dynamicbuttongrid":
|
||||
|
||||
var dg = new Datasources.List();
|
||||
|
||||
await NavigateTo(dg);
|
||||
|
||||
break;
|
||||
|
||||
case "notifications":
|
||||
|
||||
var not = new Notifications.Start();
|
||||
await NavigateTo(not);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
message.Handled = false;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -183,10 +238,24 @@ 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()));
|
||||
|
||||
btn.AddButtonRow(new ButtonBase("#14 ButtonGrid Tags (Filter)", new CallbackData("a", "buttongridtags").Serialize()));
|
||||
|
||||
btn.AddButtonRow(new ButtonBase("#15 MultiView", new CallbackData("a", "multiview").Serialize()));
|
||||
|
||||
btn.AddButtonRow(new ButtonBase("#16 CheckedButtonList", new CallbackData("a", "checkedbuttonlist").Serialize()));
|
||||
|
||||
btn.AddButtonRow(new ButtonBase("#17 NavigationController (Push/Pop)", new CallbackData("a", "navigationcontroller").Serialize()));
|
||||
|
||||
btn.AddButtonRow(new ButtonBase("#18 Dynamic ButtonGrid (DataSources)", new CallbackData("a", "dynamicbuttongrid").Serialize()));
|
||||
|
||||
btn.AddButtonRow(new ButtonBase("#19 Notifications", new CallbackData("a", "notifications").Serialize()));
|
||||
|
||||
await this.Device.Send("Choose your test:", btn);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using TelegramBotBase.Form;
|
||||
using TelegramBotBase.Form.Navigation;
|
||||
|
||||
namespace TelegramBotBaseTest.Tests.Navigation
|
||||
{
|
||||
class CustomController : NavigationController
|
||||
{
|
||||
public CustomController(FormBase form) : base(form)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
public override Task PushAsync(FormBase form, params object[] args)
|
||||
{
|
||||
Console.WriteLine($"Pushes form (Count on stack {this.Index + 1})");
|
||||
//Device.Send($"Pushes form (Count on stack {this.Index + 1})");
|
||||
|
||||
return base.PushAsync(form, args);
|
||||
}
|
||||
|
||||
|
||||
public override Task PopAsync()
|
||||
{
|
||||
Console.WriteLine($"Pops one form (Count on stack {this.Index + 1})");
|
||||
//Device.Send($"Pops one form (Count on stack {this.Index + 1})");
|
||||
|
||||
return base.PopAsync();
|
||||
}
|
||||
|
||||
public override Task PopToRootAsync()
|
||||
{
|
||||
Console.WriteLine($"Moved back to root (Count on stack {this.Index + 1})");
|
||||
//Device.Send($"Moved back to root (Count on stack {this.Index + 1})");
|
||||
|
||||
return base.PopToRootAsync();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Telegram.Bot.Types;
|
||||
using TelegramBotBase.Base;
|
||||
using TelegramBotBase.Form;
|
||||
|
||||
namespace TelegramBotBaseTest.Tests.Navigation
|
||||
{
|
||||
public class Form1 : FormBase
|
||||
{
|
||||
Message msg = null;
|
||||
|
||||
public Form1()
|
||||
{
|
||||
this.Closed += Form1_Closed;
|
||||
}
|
||||
|
||||
private async Task Form1_Closed(object sender, EventArgs e)
|
||||
{
|
||||
if (msg == null)
|
||||
return;
|
||||
|
||||
await Device.DeleteMessage(msg);
|
||||
}
|
||||
|
||||
public override async Task Action(MessageResult message)
|
||||
{
|
||||
if (message.Handled)
|
||||
return;
|
||||
|
||||
await message.ConfirmAction();
|
||||
|
||||
switch (message.RawData)
|
||||
{
|
||||
case "next":
|
||||
|
||||
message.Handled = true;
|
||||
|
||||
var f1 = new Form1();
|
||||
|
||||
await NavigationController.PushAsync(f1);
|
||||
|
||||
|
||||
break;
|
||||
|
||||
case "previous":
|
||||
|
||||
message.Handled = true;
|
||||
|
||||
//Pop's the current form and move the previous one. The root form will be the Start class.
|
||||
await NavigationController.PopAsync();
|
||||
|
||||
break;
|
||||
|
||||
case "root":
|
||||
|
||||
message.Handled = true;
|
||||
|
||||
await NavigationController.PopToRootAsync();
|
||||
|
||||
break;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
public override async Task Render(MessageResult message)
|
||||
{
|
||||
if (msg != null)
|
||||
return;
|
||||
|
||||
var bf = new ButtonForm();
|
||||
bf.AddButtonRow("Next page", "next");
|
||||
bf.AddButtonRow("Previous page", "previous");
|
||||
bf.AddButtonRow("Back to root", "root");
|
||||
|
||||
msg = await Device.Send($"Choose your options (Count on stack {NavigationController.Index + 1})", bf);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Telegram.Bot.Types;
|
||||
using TelegramBotBase.Base;
|
||||
using TelegramBotBase.Form;
|
||||
using TelegramBotBase.Form.Navigation;
|
||||
|
||||
namespace TelegramBotBaseTest.Tests.Navigation
|
||||
{
|
||||
public class Start : FormBase
|
||||
{
|
||||
|
||||
Message msg = null;
|
||||
|
||||
public Start()
|
||||
{
|
||||
this.Closed += Start_Closed;
|
||||
}
|
||||
|
||||
private async Task Start_Closed(object sender, EventArgs e)
|
||||
{
|
||||
if (msg == null)
|
||||
return;
|
||||
|
||||
await Device.DeleteMessage(msg);
|
||||
}
|
||||
|
||||
public override async Task Load(MessageResult message)
|
||||
{
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
public override async Task Action(MessageResult message)
|
||||
{
|
||||
if (message.Handled)
|
||||
return;
|
||||
|
||||
await message.ConfirmAction();
|
||||
|
||||
switch (message.RawData)
|
||||
{
|
||||
case "yes":
|
||||
|
||||
message.Handled = true;
|
||||
|
||||
//Create navigation controller and navigate to it, keep the current form as root form so we can get back to here later
|
||||
var nc = new CustomController(this);
|
||||
|
||||
var f1 = new Form1();
|
||||
|
||||
await NavigateTo(nc);
|
||||
|
||||
await nc.PushAsync(f1);
|
||||
|
||||
|
||||
break;
|
||||
case "no":
|
||||
|
||||
message.Handled = true;
|
||||
|
||||
var mn = new Menu();
|
||||
|
||||
await NavigateTo(mn);
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public override async Task Render(MessageResult message)
|
||||
{
|
||||
var bf = new ButtonForm();
|
||||
|
||||
bf.AddButtonRow("Yes", "yes");
|
||||
bf.AddButtonRow("No", "no");
|
||||
|
||||
msg = await Device.Send("Open controller?", bf);
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using TelegramBotBase.Base;
|
||||
using TelegramBotBase.Form;
|
||||
|
||||
namespace TelegramBotBaseTest.Tests.Notifications
|
||||
{
|
||||
public class Start : AutoCleanForm
|
||||
{
|
||||
bool sent = false;
|
||||
|
||||
public Start()
|
||||
{
|
||||
this.DeleteMode = TelegramBotBase.Enums.eDeleteMode.OnLeavingForm;
|
||||
}
|
||||
|
||||
public override async Task Action(MessageResult message)
|
||||
{
|
||||
if (message.Handled)
|
||||
return;
|
||||
|
||||
switch (message.RawData)
|
||||
{
|
||||
case "alert":
|
||||
|
||||
await message.ConfirmAction("This is an alert.", true);
|
||||
|
||||
break;
|
||||
case "back":
|
||||
|
||||
var mn = new Menu();
|
||||
await NavigateTo(mn);
|
||||
|
||||
break;
|
||||
default:
|
||||
|
||||
await message.ConfirmAction("This is feedback");
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public override async Task Render(MessageResult message)
|
||||
{
|
||||
if (sent)
|
||||
return;
|
||||
|
||||
var bf = new ButtonForm();
|
||||
bf.AddButtonRow("Normal feeback", "normal");
|
||||
bf.AddButtonRow("Alert Box", "alert");
|
||||
bf.AddButtonRow("Back", "back");
|
||||
|
||||
await Device.Send("Choose your test", bf);
|
||||
|
||||
sent = true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using TelegramBotBase.Base;
|
||||
using TelegramBotBase.Controls.Inline;
|
||||
using TelegramBotBase.Form;
|
||||
|
||||
namespace TelegramBotBaseTest.Tests
|
||||
@@ -35,41 +36,41 @@ namespace TelegramBotBaseTest.Tests
|
||||
if (call == null)
|
||||
return;
|
||||
|
||||
TelegramBotBase.Controls.ProgressBar Bar = null;
|
||||
ProgressBar Bar = null;
|
||||
|
||||
switch (call.Value)
|
||||
{
|
||||
case "standard":
|
||||
|
||||
Bar = new TelegramBotBase.Controls.ProgressBar(0, 100, TelegramBotBase.Controls.ProgressBar.eProgressStyle.standard);
|
||||
Bar = new ProgressBar(0, 100, ProgressBar.eProgressStyle.standard);
|
||||
Bar.Device = this.Device;
|
||||
|
||||
break;
|
||||
|
||||
case "squares":
|
||||
|
||||
Bar = new TelegramBotBase.Controls.ProgressBar(0, 100, TelegramBotBase.Controls.ProgressBar.eProgressStyle.squares);
|
||||
Bar = new ProgressBar(0, 100, ProgressBar.eProgressStyle.squares);
|
||||
Bar.Device = this.Device;
|
||||
|
||||
break;
|
||||
|
||||
case "circles":
|
||||
|
||||
Bar = new TelegramBotBase.Controls.ProgressBar(0, 100, TelegramBotBase.Controls.ProgressBar.eProgressStyle.circles);
|
||||
Bar = new ProgressBar(0, 100, ProgressBar.eProgressStyle.circles);
|
||||
Bar.Device = this.Device;
|
||||
|
||||
break;
|
||||
|
||||
case "lines":
|
||||
|
||||
Bar = new TelegramBotBase.Controls.ProgressBar(0, 100, TelegramBotBase.Controls.ProgressBar.eProgressStyle.lines);
|
||||
Bar = new ProgressBar(0, 100, ProgressBar.eProgressStyle.lines);
|
||||
Bar.Device = this.Device;
|
||||
|
||||
break;
|
||||
|
||||
case "squaredlines":
|
||||
|
||||
Bar = new TelegramBotBase.Controls.ProgressBar(0, 100, TelegramBotBase.Controls.ProgressBar.eProgressStyle.squaredLines);
|
||||
Bar = new ProgressBar(0, 100, ProgressBar.eProgressStyle.squaredLines);
|
||||
Bar.Device = this.Device;
|
||||
|
||||
break;
|
||||
|
||||
@@ -39,7 +39,6 @@ namespace TelegramBotBaseTest.Tests
|
||||
case "reply":
|
||||
|
||||
|
||||
|
||||
break;
|
||||
|
||||
case "navigate":
|
||||
|
||||
@@ -118,7 +118,7 @@ namespace TelegramBotBaseTest.Tests
|
||||
btn.AddButtonRow(new ButtonBase("Request Prompt", CallbackData.Create("navigate", "prompt")));
|
||||
|
||||
|
||||
await this.Device.SendPhoto(bmp, "Test", btn);
|
||||
await this.Device.SendPhoto(bmp, "Test", "", btn);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Newtonsoft.Json" version="12.0.2" targetFramework="net452" />
|
||||
<package id="System.Net.Requests" version="4.3.0" targetFramework="net452" />
|
||||
<package id="Telegram.Bot" version="14.12.0" targetFramework="net452" />
|
||||
<package id="Newtonsoft.Json" version="12.0.2" targetFramework="net5" />
|
||||
<package id="System.Net.Requests" version="4.3.0" targetFramework="net5" />
|
||||
<package id="Telegram.Bot" version="14.12.0" targetFramework="net5" />
|
||||
</packages>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.0 MiB |
Binary file not shown.
|
After Width: | Height: | Size: 328 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 756 KiB |
Reference in New Issue
Block a user