Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
567a9f937f | ||
|
|
95b4ff77c5 | ||
|
|
ba82c11d66 | ||
|
|
c2e33da277 | ||
|
|
259fa54236 | ||
|
|
f790a16e85 | ||
|
|
97fea333f7 | ||
|
|
e1b31b0b9a | ||
|
|
7aca5a648f | ||
|
|
f24c309f63 | ||
|
|
ba9fd8062c | ||
|
|
b37c31f2bd | ||
|
|
2c34a178ee | ||
|
|
2f030f3c12 | ||
|
|
a364562fd3 | ||
|
|
8ef8733a2b | ||
|
|
049b2081ec | ||
|
|
48b76a84be | ||
|
|
31c8231b2d | ||
|
|
e9504f3b36 | ||
|
|
8592f4279d | ||
|
|
2457773a12 | ||
|
|
46e65faf31 | ||
|
|
193a4811bf | ||
|
|
08a0de8087 | ||
|
|
82469cff70 | ||
|
|
81eafe1219 | ||
|
|
183e89c36f | ||
|
|
ad6cf9539c | ||
|
|
46576eb819 | ||
|
|
cf9e2285f1 | ||
|
|
ecfacdadbb | ||
|
|
c00c2e8d8f | ||
|
|
bfd905d590 | ||
|
|
7b1bf75dde | ||
|
|
7a7a65c3a7 | ||
|
|
8a42a861cf | ||
|
|
47876681e0 | ||
|
|
9314b4c0e5 | ||
|
|
01c19b9900 | ||
|
|
0af587d27f | ||
|
|
97b9176c3a | ||
|
|
dfa479d409 | ||
|
|
07dec0dc9d | ||
|
|
2fc16b18da | ||
|
|
11eeb0dcab | ||
|
|
fbfcbe99fb | ||
|
|
948c1368d7 | ||
|
|
d66df4978d | ||
|
|
7d8895850a | ||
|
|
5e87d00c58 | ||
|
|
efe5fef7d0 | ||
|
|
eebb5cb6f5 | ||
|
|
992065d289 | ||
|
|
1acfeb873f | ||
|
|
de35ebb66e | ||
|
|
2c3e707673 | ||
|
|
6d39d2fb73 | ||
|
|
ef667d12d8 | ||
|
|
d24f8e7ac5 | ||
|
|
e5dc3fd2bc | ||
|
|
6ebb96bd93 | ||
|
|
a1b3b9246b | ||
|
|
25a0ff2e3e | ||
|
|
b74233d66d | ||
|
|
fb7b624ad8 | ||
|
|
965e6e18b9 | ||
|
|
b1c518cbd3 | ||
|
|
ab0ae5cda4 | ||
|
|
b850330f65 | ||
|
|
317dad7d24 |
@@ -0,0 +1,12 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="TelegramBotBase" Version="3.1.1" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace JoinHiderBot
|
||||||
|
{
|
||||||
|
class Program
|
||||||
|
{
|
||||||
|
static void Main(string[] args)
|
||||||
|
{
|
||||||
|
|
||||||
|
String apiKey = "";
|
||||||
|
|
||||||
|
var bot = new TelegramBotBase.BotBase<forms.Start>(apiKey);
|
||||||
|
|
||||||
|
bot.Start();
|
||||||
|
|
||||||
|
Console.ReadLine();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using TelegramBotBase.Args;
|
||||||
|
using TelegramBotBase.Form;
|
||||||
|
|
||||||
|
namespace JoinHiderBot.forms
|
||||||
|
{
|
||||||
|
public class GroupManageForm : GroupForm
|
||||||
|
{
|
||||||
|
|
||||||
|
public override async Task OnMemberChanges(MemberChangeEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.Type != Telegram.Bot.Types.Enums.MessageType.ChatMembersAdded && e.Type != Telegram.Bot.Types.Enums.MessageType.ChatMemberLeft)
|
||||||
|
return;
|
||||||
|
|
||||||
|
|
||||||
|
var m = e.Result.Message;
|
||||||
|
|
||||||
|
await this.Device.DeleteMessage(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using TelegramBotBase.Base;
|
||||||
|
using TelegramBotBase.Form;
|
||||||
|
|
||||||
|
namespace JoinHiderBot.forms
|
||||||
|
{
|
||||||
|
public class Start : SplitterForm
|
||||||
|
{
|
||||||
|
public override async Task<bool> Open(MessageResult e)
|
||||||
|
{
|
||||||
|
await this.Device.Send("This bot works only in groups.");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<bool> OpenGroup(MessageResult e)
|
||||||
|
{
|
||||||
|
var gmf = new GroupManageForm();
|
||||||
|
|
||||||
|
await this.NavigateTo(gmf);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace SystemCommandsBot
|
||||||
|
{
|
||||||
|
class Program
|
||||||
|
{
|
||||||
|
public static config.Config BotConfig { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
static void Main(string[] args)
|
||||||
|
{
|
||||||
|
|
||||||
|
BotConfig = config.Config.load();
|
||||||
|
|
||||||
|
if (BotConfig.ApiKey == null || BotConfig.ApiKey.Trim() == "")
|
||||||
|
{
|
||||||
|
Console.WriteLine("Config created...");
|
||||||
|
Console.ReadLine();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var bot = new TelegramBotBase.BotBase<forms.StartForm>(BotConfig.ApiKey);
|
||||||
|
|
||||||
|
bot.Start();
|
||||||
|
|
||||||
|
Console.WriteLine("Bot started");
|
||||||
|
|
||||||
|
Console.ReadLine();
|
||||||
|
|
||||||
|
|
||||||
|
bot.Stop();
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,10 +7,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||||
</ItemGroup>
|
<PackageReference Include="TelegramBotBase" Version="3.1.1" />
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\..\TelegramBotBase\TelegramBotBase.csproj" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -71,15 +71,36 @@ Thanks !
|
|||||||
|
|
||||||
* [ButtonGrid](#button-grid)
|
* [ButtonGrid](#button-grid)
|
||||||
|
|
||||||
|
* [Paging and Searching](#paging--searching)
|
||||||
|
|
||||||
- [Groups](#groups)
|
- [Groups](#groups)
|
||||||
* [SplitterForm](#splitter-form)
|
* [SplitterForm](#splitter-form)
|
||||||
|
|
||||||
* [GroupForm](#group-form)
|
* [GroupForm](#group-form)
|
||||||
|
|
||||||
- [State Machine and Session Serialization](#statemachine)
|
- [State Machine and Session Serialization (v3.0.0)](#statemachine-and-sessions)
|
||||||
|
|
||||||
* In the making, is comming soon.
|
* [StateMachines](#statemachines)
|
||||||
|
|
||||||
|
* [SimpleJSONStateMachine](#simplejsonstatemachine)
|
||||||
|
|
||||||
|
* [JSONStateMachine](#jsonstatemachine)
|
||||||
|
|
||||||
|
* [XMLStateMachine](#xmlstatemachine)
|
||||||
|
|
||||||
|
* [Interfaces](#interfaces)
|
||||||
|
|
||||||
|
* [IStateMachine](#istatemachine)
|
||||||
|
|
||||||
|
* [IStateForm](#istateform)
|
||||||
|
|
||||||
|
* [Attributes](#attributes)
|
||||||
|
|
||||||
|
* [SaveState](#savestate)
|
||||||
|
|
||||||
|
* [IgnoreState](#ignorestate)
|
||||||
|
|
||||||
|
- [Examples](#examples)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -99,7 +120,7 @@ It gives you features which will look/feel like WinForms or have a good way to c
|
|||||||
## How to start:
|
## How to start:
|
||||||
|
|
||||||
Within your empty App your need to put some initial lines including your APIKey to get things started.
|
Within your empty App your need to put some initial lines including your APIKey to get things started.
|
||||||
The "BotBase" Class will manage a lot of things for you, like system calls, action events and so on.
|
The "BotBase" Class will manage a lot of things for you, like bot commands, action events and so on.
|
||||||
"StartForm" is your first Formular which every user will get internally redirected to, like a start page, you could redirect from there later in code, so users won't recognize it.
|
"StartForm" is your first Formular which every user will get internally redirected to, like a start page, you could redirect from there later in code, so users won't recognize it.
|
||||||
It needs to be a subclass of "FormBase" you will find in Namespace TelegramBotBase.Base
|
It needs to be a subclass of "FormBase" you will find in Namespace TelegramBotBase.Base
|
||||||
|
|
||||||
@@ -110,7 +131,10 @@ It needs to be a subclass of "FormBase" you will find in Namespace TelegramBotBa
|
|||||||
BotBase<StartForm> bb = new BotBase<StartForm>("{YOUR API KEY}");
|
BotBase<StartForm> bb = new BotBase<StartForm>("{YOUR API KEY}");
|
||||||
|
|
||||||
//Add Systemcommands if you like, you could catch them later
|
//Add Systemcommands if you like, you could catch them later
|
||||||
bb.SystemCalls.Add("/start");
|
bb.BotCommands.Add(new BotCommand() { Command = "start", Description = "Starts the bot" });
|
||||||
|
|
||||||
|
//Update bot commands to botfather
|
||||||
|
bb.UploadBotCommands().Wait();
|
||||||
|
|
||||||
//Start your Bot
|
//Start your Bot
|
||||||
bb.Start();
|
bb.Start();
|
||||||
@@ -135,17 +159,10 @@ public class StartForm : FormBase
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Gets invoked if the form gets opened (with Form.NavigateTo(NewForm))
|
//Opened() got replaced with event handler
|
||||||
public override async Task Opened()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
//Closed() got replaced with event handler
|
||||||
|
|
||||||
//Gets invoked if the form gets leaved
|
|
||||||
public override async Task Closed()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//Gets invoked on every Message/Action/Data in this context
|
//Gets invoked on every Message/Action/Data in this context
|
||||||
public override async Task Load(MessageResult message)
|
public override async Task Load(MessageResult message)
|
||||||
@@ -153,6 +170,12 @@ public class StartForm : FormBase
|
|||||||
await this.Device.Send("Hello world!");
|
await this.Device.Send("Hello world!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Gets invoked on edited messages
|
||||||
|
public override async Task Edited(MessageResult message)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
//Gets invoked on Button clicks
|
//Gets invoked on Button clicks
|
||||||
public override async Task Action(MessageResult message)
|
public override async Task Action(MessageResult message)
|
||||||
{
|
{
|
||||||
@@ -196,10 +219,10 @@ await this.NavigateTo(tf);
|
|||||||
|
|
||||||
All examples are within the test project, so just try it out on your own.
|
All examples are within the test project, so just try it out on your own.
|
||||||
|
|
||||||
### Add some system calls (Example #0 - System Calls)
|
### Add some system calls (Example #0 - Bot Commands)
|
||||||
|
|
||||||
Inside of the BotFather you are able to add "Commands" to your TelegramBot. The user will see them, depending on the application as options he could choose.
|
Inside of the BotFather you are able to add "Commands" to your TelegramBot. The user will see them, depending on the application as options he could choose.
|
||||||
I'm calling them Systemcalls. Before start (and later for sure) you could add them to your BotBase. Every time a message comes in they will get checked if they are one of them.
|
Before start (and later for sure) you could add them to your BotBase. Every time a message comes in they will get checked if they are one of them.
|
||||||
If so, a special event Handler will get raised where you are easier able to manage the action behind.
|
If so, a special event Handler will get raised where you are easier able to manage the action behind.
|
||||||
|
|
||||||
Below we have 4 options.
|
Below we have 4 options.
|
||||||
@@ -217,13 +240,12 @@ Below we have 4 options.
|
|||||||
```
|
```
|
||||||
BotBase<Start> bb = new BotBase<Start>("{YOUR API KEY}");
|
BotBase<Start> bb = new BotBase<Start>("{YOUR API KEY}");
|
||||||
|
|
||||||
bb.SystemCalls.Add("/start");
|
bb.BotCommands.Add(new BotCommand() { Command = "start", Description = "Starts the bot" });
|
||||||
bb.SystemCalls.Add("/form1");
|
bb.BotCommands.Add(new BotCommand() { Command = "form1", Description = "Opens test form 1" });
|
||||||
bb.SystemCalls.Add("/form2");
|
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." });
|
||||||
|
|
||||||
bb.SystemCalls.Add("/params");
|
bb.BotCommand += async (s, en) =>
|
||||||
|
|
||||||
bb.SystemCall += async (s, en) =>
|
|
||||||
{
|
{
|
||||||
switch (en.Command)
|
switch (en.Command)
|
||||||
{
|
{
|
||||||
@@ -254,6 +276,9 @@ bb.SystemCall += async (s, en) =>
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//Update Bot commands to botfather
|
||||||
|
bb.UploadBotCommands().Wait();
|
||||||
|
|
||||||
bb.Start();
|
bb.Start();
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -270,11 +295,13 @@ public class SimpleForm : AutoCleanForm
|
|||||||
{
|
{
|
||||||
public SimpleForm()
|
public SimpleForm()
|
||||||
{
|
{
|
||||||
this.DeleteSide = eSide.Both;
|
this.DeleteSide = TelegramBotBase.Enums.eDeleteSide.Both;
|
||||||
this.DeleteMode = eDeleteMode.OnLeavingForm;
|
this.DeleteMode = TelegramBotBase.Enums.eDeleteMode.OnLeavingForm;
|
||||||
|
|
||||||
|
this.Opened += SimpleForm_Opened;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task Opened()
|
private async Task SimpleForm_Opened(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
await this.Device.Send("Hello world! (send 'back' to get back to Start)\r\nOr\r\nhi, hello, maybe, bye and ciao");
|
await this.Device.Send("Hello world! (send 'back' to get back to Start)\r\nOr\r\nhi, hello, maybe, bye and ciao");
|
||||||
}
|
}
|
||||||
@@ -655,7 +682,7 @@ public async override Task Render(MessageResult message)
|
|||||||
```
|
```
|
||||||
|
|
||||||
There is also a second example, where every of these 3 inputs gets requested by a different formular (class). Just for imagination of the possiblites.
|
There is also a second example, where every of these 3 inputs gets requested by a different formular (class). Just for imagination of the possiblites.
|
||||||
Cause its to much Text, i didnt have added it here. You will find it under [TelegramBaseTest/Tests/Register/PerStep.cs](TelegramBaseTest/Tests/Register/PerStep.cs)
|
Cause its to much Text, i didnt have added it here. You will find it under [TelegramBotBaseTest/Tests/Register/PerStep.cs](TelegramBotBaseTest/Tests/Register/PerStep.cs)
|
||||||
Beginn there and navigate your way through these Steps in the subfolder.
|
Beginn there and navigate your way through these Steps in the subfolder.
|
||||||
|
|
||||||
|
|
||||||
@@ -774,6 +801,8 @@ await this.NavigateTo(cd);
|
|||||||
### Button Grid
|
### Button Grid
|
||||||
<img src="images/buttongrid.gif?raw=true" />
|
<img src="images/buttongrid.gif?raw=true" />
|
||||||
|
|
||||||
|
#### Paging & Searching
|
||||||
|
<img src="images/buttongrid_pagingfilter.gif?raw=true" />
|
||||||
|
|
||||||
## Groups
|
## Groups
|
||||||
|
|
||||||
@@ -891,7 +920,155 @@ public class GroupForm : FormBase
|
|||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Statemachine and Sessions
|
||||||
|
|
||||||
|
Depending on the usecases and the overall structure of a Telegram Bot it is essential to have some kind of session serialization or state machine to keep the user context after restarts of the bot (ie. due to updates) or crashes.
|
||||||
|
For this I have created some easy to implement structures which fits into the current environment.
|
||||||
|
|
||||||
|
Below you find all possiblities.
|
||||||
|
|
||||||
|
### Statemachines
|
||||||
|
|
||||||
|
There are actually 3 types of example state machines you could use. A state machine is a kind of serializer which saves the important session data in a reusable structure like JSON or XML.
|
||||||
|
|
||||||
|
You could use one of the following state machines:
|
||||||
|
|
||||||
|
#### SimpleJSONStateMachine
|
||||||
|
Is easy to use and useful for simple structures like basic datatypes. Did not work for complex ones like generics. Use the JSONStateMachine for them.
|
||||||
|
In general you didn't need to do more then, to keep the actual form:
|
||||||
|
|
||||||
|
```
|
||||||
|
//Prepare the System
|
||||||
|
BotBase<StartForm> bb = new BotBase<StartForm>("{YOUR API KEY}");
|
||||||
|
|
||||||
|
//Add Systemcommands if you like, you could catch them later
|
||||||
|
bb.SystemCalls.Add("/start");
|
||||||
|
|
||||||
|
//Set the statemachine and enable it
|
||||||
|
bb.StateMachine = new TelegramBotBase.States.SimpleJSONStateMachine(AppContext.BaseDirectory + "config\\states.json");
|
||||||
|
|
||||||
|
//Start your Bot
|
||||||
|
bb.Start();
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
#### JSONStateMachine
|
||||||
|
Is easy to use too, but works for complex datatypes cause it saves there namespaces and additional type informations into the JSON file too.
|
||||||
|
In general you didn't need to do more then, to keep the actual form:
|
||||||
|
|
||||||
|
```
|
||||||
|
//Prepare the System
|
||||||
|
BotBase<StartForm> bb = new BotBase<StartForm>("{YOUR API KEY}");
|
||||||
|
|
||||||
|
//Add Systemcommands if you like, you could catch them later
|
||||||
|
bb.SystemCalls.Add("/start");
|
||||||
|
|
||||||
|
//Set the statemachine and enable it
|
||||||
|
bb.StateMachine = new TelegramBotBase.States.JSONStateMachine(AppContext.BaseDirectory + "config\\states.json");
|
||||||
|
|
||||||
|
//Start your Bot
|
||||||
|
bb.Start();
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
#### XMLStateMachine
|
||||||
|
|
||||||
|
The last one, should work like the others.
|
||||||
|
In general you didn't need to do more then, to keep the actual form:
|
||||||
|
|
||||||
|
```
|
||||||
|
//Prepare the System
|
||||||
|
BotBase<StartForm> bb = new BotBase<StartForm>("{YOUR API KEY}");
|
||||||
|
|
||||||
|
//Add Systemcommands if you like, you could catch them later
|
||||||
|
bb.SystemCalls.Add("/start");
|
||||||
|
|
||||||
|
//Set the statemachine and enable it
|
||||||
|
bb.StateMachine = new TelegramBotBase.States.XMLStateMachine(AppContext.BaseDirectory + "config\\states.xml");
|
||||||
|
|
||||||
|
//Start your Bot
|
||||||
|
bb.Start();
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### Interfaces
|
||||||
|
|
||||||
|
There are two interfaces, one for the StateMachine itself, which is useful to build a custom one for a different datatype and one for implementing into a form which should be invoked with events.
|
||||||
|
|
||||||
|
#### IStateMachine
|
||||||
|
|
||||||
|
Is the basic StateMachine interface, it has two methods SaveFormStates(SaveStatesEventArgs e) and StateContainer LoadFormStates(), nothing fancy, just simple calls. Implement into both methods your own serialization process.
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
public interface IStateMachine
|
||||||
|
{
|
||||||
|
void SaveFormStates(SaveStatesEventArgs e);
|
||||||
|
|
||||||
|
StateContainer LoadFormStates();
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
#### IStateForm
|
||||||
|
|
||||||
|
When implemented, this will invoke one of these two methods: LoadState(LoadStateEventArgs e) or SaveState(SaveStateEventArgs e).
|
||||||
|
They have methods to load or save data from the statemachine of the current form.
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
public interface IStateForm
|
||||||
|
{
|
||||||
|
void LoadState(LoadStateEventArgs e);
|
||||||
|
|
||||||
|
void SaveState(SaveStateEventArgs e);
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### Attributes
|
||||||
|
|
||||||
|
If you don't want to implement the IStateForm interface, cause there are maybe "just" one or two properties you want to keep and restore, use the following attribute:
|
||||||
|
|
||||||
|
#### SaveState
|
||||||
|
|
||||||
|
This will let the engine know, that you want too keep and restore this field automatically. Unlike the IStateForm methods, you have no option to manipulate data.
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
[SaveState]
|
||||||
|
public long UserId { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
#### IgnoreState
|
||||||
|
|
||||||
|
Due to the fact that Attribute implementation and interaction is optional, you want to let the engine maybe know, that you don't want to keep a specific form. So it should get "lost". This attribute will help you here, add it to the form class and it will not get serialized, even if it implements IStateForm or the SaveState attributes.
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
[IgnoreState]
|
||||||
|
public class Registration : STForm
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
You find all example projects in the "Examples" subfolder.
|
||||||
|
|
||||||
|
- [Examples/SystemCommandsBot/](Examples/SystemCommandsBot/)
|
||||||
|
|
||||||
|
Will allow you to run specific system commands or run/kill processes via Bot. Has also a simple authentication mechanism with one password.
|
||||||
|
|
||||||
|
- [Examples/JoinHiderBot/](Examples/JoinHiderBot/)
|
||||||
|
|
||||||
|
Will delete Join and Leave messages automatically in groups.
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
+4
-4
@@ -9,9 +9,9 @@ using TelegramBotBase.Sessions;
|
|||||||
namespace TelegramBotBase.Args
|
namespace TelegramBotBase.Args
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Base class for given system call results
|
/// Base class for given bot command results
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class SystemCallEventArgs : EventArgs
|
public class BotCommandEventArgs : EventArgs
|
||||||
{
|
{
|
||||||
public String Command { get; set; }
|
public String Command { get; set; }
|
||||||
|
|
||||||
@@ -26,13 +26,13 @@ namespace TelegramBotBase.Args
|
|||||||
public Message OriginalMessage { get; set; }
|
public Message OriginalMessage { get; set; }
|
||||||
|
|
||||||
|
|
||||||
public SystemCallEventArgs()
|
public BotCommandEventArgs()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public SystemCallEventArgs(String Command, List<String> Parameters, Message Message, long DeviceId, DeviceSession Device)
|
public BotCommandEventArgs(String Command, List<String> Parameters, Message Message, long DeviceId, DeviceSession Device)
|
||||||
{
|
{
|
||||||
this.Command = Command;
|
this.Command = Command;
|
||||||
this.Parameters = Parameters;
|
this.Parameters = Parameters;
|
||||||
@@ -410,6 +410,19 @@ namespace TelegramBotBase.Form
|
|||||||
this.Controls.Remove(control);
|
this.Controls.Remove(control);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes all controls.
|
||||||
|
/// </summary>
|
||||||
|
public void RemoveAllControls()
|
||||||
|
{
|
||||||
|
foreach(var c in this.Controls)
|
||||||
|
{
|
||||||
|
c.Cleanup().Wait();
|
||||||
|
|
||||||
|
this.Controls.Remove(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Cleanup
|
/// Cleanup
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ using System.Net;
|
|||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Telegram.Bot.Types;
|
||||||
|
|
||||||
namespace TelegramBotBase.Base
|
namespace TelegramBotBase.Base
|
||||||
{
|
{
|
||||||
@@ -15,6 +16,7 @@ namespace TelegramBotBase.Base
|
|||||||
public class MessageClient
|
public class MessageClient
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
public String APIKey { get; set; }
|
public String APIKey { get; set; }
|
||||||
|
|
||||||
public Telegram.Bot.TelegramBotClient TelegramClient { get; set; }
|
public Telegram.Bot.TelegramBotClient TelegramClient { get; set; }
|
||||||
@@ -142,6 +144,27 @@ namespace TelegramBotBase.Base
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This will return the current list of bot commands.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task<BotCommand[]> GetBotCommands()
|
||||||
|
{
|
||||||
|
return await this.TelegramClient.GetMyCommandsAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This will set your bot commands to the given list.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="botcommands"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task SetBotCommands(List<BotCommand> botcommands)
|
||||||
|
{
|
||||||
|
await this.TelegramClient.SetMyCommandsAsync(botcommands);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#region "Events"
|
#region "Events"
|
||||||
|
|
||||||
|
|||||||
@@ -74,9 +74,9 @@ namespace TelegramBotBase.Base
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Is this a system call ? Starts with a slash '/' and a command
|
/// Is this a command ? Starts with a slash '/' and a command
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsSystemCall
|
public bool IsBotCommand
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
@@ -87,11 +87,11 @@ namespace TelegramBotBase.Base
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns a List of all parameters which has been sent with the command itself (i.e. /start 123 456 789 => 123,456,789)
|
/// Returns a List of all parameters which has been sent with the command itself (i.e. /start 123 456 789 => 123,456,789)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public List<String> SystemCallParameters
|
public List<String> BotCommandParameters
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (!IsSystemCall)
|
if (!IsBotCommand)
|
||||||
return new List<string>();
|
return new List<string>();
|
||||||
|
|
||||||
//Split by empty space and skip first entry (command itself), return as list
|
//Split by empty space and skip first entry (command itself), return as list
|
||||||
@@ -100,13 +100,13 @@ namespace TelegramBotBase.Base
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns just the System call command (i.e. /start 1 2 3 => /start)
|
/// Returns just the command (i.e. /start 1 2 3 => /start)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public String SystemCommand
|
public String BotCommand
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (!IsSystemCall)
|
if (!IsBotCommand)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
return this.MessageText.Split(' ')[0];
|
return this.MessageText.Split(' ')[0];
|
||||||
|
|||||||
+123
-72
@@ -5,9 +5,11 @@ using System.Linq;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Telegram.Bot;
|
using Telegram.Bot;
|
||||||
|
using Telegram.Bot.Types;
|
||||||
using TelegramBotBase.Args;
|
using TelegramBotBase.Args;
|
||||||
using TelegramBotBase.Attributes;
|
using TelegramBotBase.Attributes;
|
||||||
using TelegramBotBase.Base;
|
using TelegramBotBase.Base;
|
||||||
|
using TelegramBotBase.Enums;
|
||||||
using TelegramBotBase.Form;
|
using TelegramBotBase.Form;
|
||||||
using TelegramBotBase.Interfaces;
|
using TelegramBotBase.Interfaces;
|
||||||
using TelegramBotBase.Sessions;
|
using TelegramBotBase.Sessions;
|
||||||
@@ -31,12 +33,15 @@ namespace TelegramBotBase
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// List of all running/active sessions
|
/// List of all running/active sessions
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public SessionBase Sessions { get; set; }
|
public SessionBase<T> Sessions { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Contains System commands which will be available at everytime and didnt get passed to forms, i.e. /start
|
/// Contains System commands which will be available at everytime and didnt get passed to forms, i.e. /start
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public List<String> SystemCalls { get; set; }
|
public List<BotCommand> BotCommands { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
#region "Events"
|
||||||
|
|
||||||
private EventHandlerList __Events = new EventHandlerList();
|
private EventHandlerList __Events = new EventHandlerList();
|
||||||
|
|
||||||
@@ -46,47 +51,52 @@ namespace TelegramBotBase
|
|||||||
|
|
||||||
private static object __evSystemCall = new object();
|
private static object __evSystemCall = new object();
|
||||||
|
|
||||||
public delegate Task SystemCallEventHandler(object sender, SystemCallEventArgs e);
|
public delegate Task BotCommandEventHandler(object sender, BotCommandEventArgs e);
|
||||||
|
|
||||||
private static object __evException = new object();
|
private static object __evException = new object();
|
||||||
|
|
||||||
private static object __evUnhandledCall = new object();
|
private static object __evUnhandledCall = new object();
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Skips all messages during running (good for big delay updates)
|
|
||||||
/// </summary>
|
|
||||||
public bool SkipAllMessages { get; set; } = false;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Loggs all messages and sent them to the event handler
|
|
||||||
/// </summary>
|
|
||||||
public bool LogAllMessages { get; set; } = false;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Enable the SessionState (you need to implement on call forms the IStateForm interface)
|
/// Enable the SessionState (you need to implement on call forms the IStateForm interface)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IStateMachine StateMachine { get; set; }
|
public IStateMachine StateMachine { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// How often could a form navigate to another (within one user action/call/message)
|
public Dictionary<eSettings, uint> SystemSettings { get; private set; }
|
||||||
/// </summary>
|
|
||||||
private const int NavigationMaximum = 10;
|
private BotBase()
|
||||||
|
{
|
||||||
|
this.SystemSettings = new Dictionary<eSettings, uint>();
|
||||||
|
|
||||||
|
SetSetting(eSettings.NavigationMaximum, 10);
|
||||||
|
SetSetting(eSettings.LogAllMessages, false);
|
||||||
|
SetSetting(eSettings.SkipAllMessages, false);
|
||||||
|
SetSetting(eSettings.SaveSessionsOnConsoleExit, false);
|
||||||
|
|
||||||
|
this.BotCommands = new List<BotCommand>();
|
||||||
|
|
||||||
|
this.Sessions = new SessionBase<T>();
|
||||||
|
this.Sessions.BotBase = this;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Simple start of your Bot with the APIKey
|
/// Simple start of your Bot with the APIKey
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="apiKey"></param>
|
/// <param name="apiKey"></param>
|
||||||
public BotBase(String apiKey)
|
public BotBase(String apiKey, bool initClient = true) : this()
|
||||||
{
|
{
|
||||||
this.APIKey = apiKey;
|
this.APIKey = apiKey;
|
||||||
|
|
||||||
|
if (!initClient)
|
||||||
|
return;
|
||||||
|
|
||||||
this.Client = new Base.MessageClient(this.APIKey);
|
this.Client = new Base.MessageClient(this.APIKey);
|
||||||
this.Client.TelegramClient.Timeout = new TimeSpan(0, 1, 0);
|
this.Client.TelegramClient.Timeout = new TimeSpan(0, 1, 0);
|
||||||
|
|
||||||
this.SystemCalls = new List<string>();
|
|
||||||
|
|
||||||
this.Sessions = new SessionBase();
|
|
||||||
this.Sessions.Client = this.Client;
|
this.Sessions.Client = this.Client;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,15 +105,10 @@ namespace TelegramBotBase
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="apiKey"></param>
|
/// <param name="apiKey"></param>
|
||||||
/// <param name="proxyBaseAddress">i.e. https://127.0.0.1:10000</param>
|
/// <param name="proxyBaseAddress">i.e. https://127.0.0.1:10000</param>
|
||||||
public BotBase(String apiKey, System.Net.Http.HttpClient proxy)
|
public BotBase(String apiKey, System.Net.Http.HttpClient proxy) : this(apiKey, false)
|
||||||
{
|
{
|
||||||
this.APIKey = apiKey;
|
|
||||||
|
|
||||||
this.Client = new Base.MessageClient(this.APIKey, proxy);
|
this.Client = new Base.MessageClient(this.APIKey, proxy);
|
||||||
|
|
||||||
this.SystemCalls = new List<string>();
|
|
||||||
|
|
||||||
this.Sessions = new SessionBase();
|
|
||||||
this.Sessions.Client = this.Client;
|
this.Sessions.Client = this.Client;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,15 +117,10 @@ namespace TelegramBotBase
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="apiKey"></param>
|
/// <param name="apiKey"></param>
|
||||||
/// <param name="client"></param>
|
/// <param name="client"></param>
|
||||||
public BotBase(String apiKey, TelegramBotClient client)
|
public BotBase(String apiKey, TelegramBotClient client) : this(apiKey, false)
|
||||||
{
|
{
|
||||||
this.APIKey = apiKey;
|
|
||||||
|
|
||||||
this.Client = new Base.MessageClient(this.APIKey, client);
|
this.Client = new Base.MessageClient(this.APIKey, client);
|
||||||
|
|
||||||
this.SystemCalls = new List<string>();
|
|
||||||
|
|
||||||
this.Sessions = new SessionBase();
|
|
||||||
this.Sessions.Client = this.Client;
|
this.Sessions.Client = this.Client;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,17 +129,12 @@ namespace TelegramBotBase
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="apiKey"></param>
|
/// <param name="apiKey"></param>
|
||||||
/// <param name="proxyBaseAddress">i.e. https://127.0.0.1:10000</param>
|
/// <param name="proxyBaseAddress">i.e. https://127.0.0.1:10000</param>
|
||||||
public BotBase(String apiKey, String proxyBaseAddress)
|
public BotBase(String apiKey, String proxyBaseAddress) : this(apiKey, false)
|
||||||
{
|
{
|
||||||
this.APIKey = apiKey;
|
|
||||||
|
|
||||||
var url = new Uri(proxyBaseAddress);
|
var url = new Uri(proxyBaseAddress);
|
||||||
|
|
||||||
this.Client = new Base.MessageClient(this.APIKey, url);
|
this.Client = new Base.MessageClient(this.APIKey, url);
|
||||||
|
|
||||||
this.SystemCalls = new List<string>();
|
|
||||||
|
|
||||||
this.Sessions = new SessionBase();
|
|
||||||
this.Sessions.Client = this.Client;
|
this.Sessions.Client = this.Client;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,15 +144,10 @@ namespace TelegramBotBase
|
|||||||
/// <param name="apiKey"></param>
|
/// <param name="apiKey"></param>
|
||||||
/// <param name="proxyHost">i.e. 127.0.0.1</param>
|
/// <param name="proxyHost">i.e. 127.0.0.1</param>
|
||||||
/// <param name="proxyPort">i.e. 10000</param>
|
/// <param name="proxyPort">i.e. 10000</param>
|
||||||
public BotBase(String apiKey, String proxyHost, int proxyPort)
|
public BotBase(String apiKey, String proxyHost, int proxyPort) : this(apiKey, false)
|
||||||
{
|
{
|
||||||
this.APIKey = apiKey;
|
|
||||||
|
|
||||||
this.Client = new Base.MessageClient(this.APIKey, proxyHost, proxyPort);
|
this.Client = new Base.MessageClient(this.APIKey, proxyHost, proxyPort);
|
||||||
|
|
||||||
this.SystemCalls = new List<string>();
|
|
||||||
|
|
||||||
this.Sessions = new SessionBase();
|
|
||||||
this.Sessions.Client = this.Client;
|
this.Sessions.Client = this.Client;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -178,6 +168,15 @@ namespace TelegramBotBase
|
|||||||
this.Sessions.LoadSessionStates(this.StateMachine);
|
this.Sessions.LoadSessionStates(this.StateMachine);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Enable auto session saving
|
||||||
|
if (this.GetSetting(eSettings.SaveSessionsOnConsoleExit, false))
|
||||||
|
{
|
||||||
|
TelegramBotBase.Tools.Console.SetHandler(() =>
|
||||||
|
{
|
||||||
|
this.Sessions.SaveSessionStates(this.StateMachine);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
this.Client.TelegramClient.StartReceiving();
|
this.Client.TelegramClient.StartReceiving();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,10 +194,7 @@ namespace TelegramBotBase
|
|||||||
|
|
||||||
this.Client.TelegramClient.StopReceiving();
|
this.Client.TelegramClient.StopReceiving();
|
||||||
|
|
||||||
if (this.StateMachine != null)
|
this.Sessions.SaveSessionStates();
|
||||||
{
|
|
||||||
this.Sessions.SaveSessionStates(this.StateMachine);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -219,7 +215,7 @@ namespace TelegramBotBase
|
|||||||
|
|
||||||
private async void Client_Message(object sender, MessageResult e)
|
private async void Client_Message(object sender, MessageResult e)
|
||||||
{
|
{
|
||||||
if (this.SkipAllMessages)
|
if (this.GetSetting(eSettings.SkipAllMessages, false))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
try
|
try
|
||||||
@@ -227,7 +223,7 @@ namespace TelegramBotBase
|
|||||||
DeviceSession ds = this.Sessions.GetSession(e.DeviceId);
|
DeviceSession ds = this.Sessions.GetSession(e.DeviceId);
|
||||||
e.Device = ds;
|
e.Device = ds;
|
||||||
|
|
||||||
if (LogAllMessages)
|
if (this.GetSetting(eSettings.LogAllMessages, false))
|
||||||
{
|
{
|
||||||
OnMessage(new MessageIncomeEventArgs(e.DeviceId, ds, e));
|
OnMessage(new MessageIncomeEventArgs(e.DeviceId, ds, e));
|
||||||
}
|
}
|
||||||
@@ -260,15 +256,14 @@ namespace TelegramBotBase
|
|||||||
OnSessionBegins(new SessionBeginEventArgs(e.DeviceId, ds));
|
OnSessionBegins(new SessionBeginEventArgs(e.DeviceId, ds));
|
||||||
}
|
}
|
||||||
|
|
||||||
ds.ChatTitle = e.Message.Chat.Username ?? e.Message.Chat.Title;
|
|
||||||
ds.LastAction = DateTime.Now;
|
ds.LastAction = DateTime.Now;
|
||||||
ds.LastMessage = e.Message;
|
ds.LastMessage = e.Message;
|
||||||
|
|
||||||
//Is this a systemcall ?
|
//Is this a bot command ?
|
||||||
if (e.IsSystemCall && this.SystemCalls.Contains(e.SystemCommand))
|
if (e.IsBotCommand && this.BotCommands.Count(a => "/" + a.Command == e.BotCommand) > 0)
|
||||||
{
|
{
|
||||||
var sce = new SystemCallEventArgs(e.SystemCommand, e.SystemCallParameters, e.Message, ds.DeviceId, ds);
|
var sce = new BotCommandEventArgs(e.BotCommand, e.BotCommandParameters, e.Message, ds.DeviceId, ds);
|
||||||
await OnSystemCall(sce);
|
await OnBotCommand(sce);
|
||||||
|
|
||||||
if (sce.Handled)
|
if (sce.Handled)
|
||||||
return;
|
return;
|
||||||
@@ -314,14 +309,14 @@ namespace TelegramBotBase
|
|||||||
|
|
||||||
e.IsFirstHandler = false;
|
e.IsFirstHandler = false;
|
||||||
|
|
||||||
} while (ds.FormSwitched && i < NavigationMaximum);
|
} while (ds.FormSwitched && i < this.GetSetting(eSettings.NavigationMaximum, 10));
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void Client_MessageEdit(object sender, MessageResult e)
|
private async void Client_MessageEdit(object sender, MessageResult e)
|
||||||
{
|
{
|
||||||
if (this.SkipAllMessages)
|
if (this.GetSetting(eSettings.SkipAllMessages, false))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
try
|
try
|
||||||
@@ -329,7 +324,7 @@ namespace TelegramBotBase
|
|||||||
DeviceSession ds = this.Sessions.GetSession(e.DeviceId);
|
DeviceSession ds = this.Sessions.GetSession(e.DeviceId);
|
||||||
e.Device = ds;
|
e.Device = ds;
|
||||||
|
|
||||||
if (LogAllMessages)
|
if (this.GetSetting(eSettings.LogAllMessages, false))
|
||||||
{
|
{
|
||||||
OnMessage(new MessageIncomeEventArgs(e.DeviceId, ds, e));
|
OnMessage(new MessageIncomeEventArgs(e.DeviceId, ds, e));
|
||||||
}
|
}
|
||||||
@@ -359,7 +354,6 @@ namespace TelegramBotBase
|
|||||||
e.Device = ds;
|
e.Device = ds;
|
||||||
}
|
}
|
||||||
|
|
||||||
ds.ChatTitle = e.Message.Chat.Username ?? e.Message.Chat.Title;
|
|
||||||
ds.LastAction = DateTime.Now;
|
ds.LastAction = DateTime.Now;
|
||||||
ds.LastMessage = e.Message;
|
ds.LastMessage = e.Message;
|
||||||
|
|
||||||
@@ -381,7 +375,7 @@ namespace TelegramBotBase
|
|||||||
DeviceSession ds = this.Sessions.GetSession(e.DeviceId);
|
DeviceSession ds = this.Sessions.GetSession(e.DeviceId);
|
||||||
e.Device = ds;
|
e.Device = ds;
|
||||||
|
|
||||||
if (LogAllMessages)
|
if (this.GetSetting(eSettings.LogAllMessages, false))
|
||||||
{
|
{
|
||||||
OnMessage(new MessageIncomeEventArgs(e.DeviceId, ds, e));
|
OnMessage(new MessageIncomeEventArgs(e.DeviceId, ds, e));
|
||||||
}
|
}
|
||||||
@@ -404,7 +398,6 @@ namespace TelegramBotBase
|
|||||||
e.Device = ds;
|
e.Device = ds;
|
||||||
}
|
}
|
||||||
|
|
||||||
ds.ChatTitle = e.Message.Chat.Username ?? e.Message.Chat.Title;
|
|
||||||
ds.LastAction = DateTime.Now;
|
ds.LastAction = DateTime.Now;
|
||||||
ds.LastMessage = e.Message;
|
ds.LastMessage = e.Message;
|
||||||
|
|
||||||
@@ -447,11 +440,8 @@ namespace TelegramBotBase
|
|||||||
|
|
||||||
if (uhc.Handled)
|
if (uhc.Handled)
|
||||||
{
|
{
|
||||||
if (ds.FormSwitched)
|
e.Handled = true;
|
||||||
{
|
if (!ds.FormSwitched)
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -470,10 +460,68 @@ namespace TelegramBotBase
|
|||||||
|
|
||||||
e.IsFirstHandler = false;
|
e.IsFirstHandler = false;
|
||||||
|
|
||||||
} while (ds.FormSwitched && i < NavigationMaximum);
|
} while (ds.FormSwitched && i < this.GetSetting(eSettings.NavigationMaximum, 10));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This method will update all local created bot commands to the botfather.
|
||||||
|
/// </summary>
|
||||||
|
public async Task UploadBotCommands()
|
||||||
|
{
|
||||||
|
await this.Client.SetBotCommands(this.BotCommands);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Could set a variety of settings to improve the bot handling.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="set"></param>
|
||||||
|
/// <param name="Value"></param>
|
||||||
|
public void SetSetting(eSettings set, uint Value)
|
||||||
|
{
|
||||||
|
this.SystemSettings[set] = Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Could set a variety of settings to improve the bot handling.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="set"></param>
|
||||||
|
/// <param name="Value"></param>
|
||||||
|
public void SetSetting(eSettings set, bool Value)
|
||||||
|
{
|
||||||
|
this.SystemSettings[set] = (Value ? 1u : 0u);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Could get the current value of a setting
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="set"></param>
|
||||||
|
/// <param name="defaultValue"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public uint GetSetting(eSettings set, uint defaultValue)
|
||||||
|
{
|
||||||
|
if (!this.SystemSettings.ContainsKey(set))
|
||||||
|
return defaultValue;
|
||||||
|
|
||||||
|
return this.SystemSettings[set];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Could get the current value of a setting
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="set"></param>
|
||||||
|
/// <param name="defaultValue"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public bool GetSetting(eSettings set, bool defaultValue)
|
||||||
|
{
|
||||||
|
if (!this.SystemSettings.ContainsKey(set))
|
||||||
|
return defaultValue;
|
||||||
|
|
||||||
|
return this.SystemSettings[set] == 0u ? false : true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#region "Events"
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Will be called if a session/context gets started
|
/// Will be called if a session/context gets started
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -518,15 +566,15 @@ namespace TelegramBotBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Will be called if a system call gets raised
|
/// Will be called if a bot command gets raised
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public event SystemCallEventHandler SystemCall;
|
public event BotCommandEventHandler BotCommand;
|
||||||
|
|
||||||
|
|
||||||
public async Task OnSystemCall(SystemCallEventArgs e)
|
public async Task OnBotCommand(BotCommandEventArgs e)
|
||||||
{
|
{
|
||||||
if (this.SystemCall != null)
|
if (this.BotCommand != null)
|
||||||
await SystemCall(this, e);
|
await BotCommand(this, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -570,5 +618,8 @@ namespace TelegramBotBase
|
|||||||
(this.__Events[__evUnhandledCall] as EventHandler<UnhandledCallEventArgs>)?.Invoke(this, e);
|
(this.__Events[__evUnhandledCall] as EventHandler<UnhandledCallEventArgs>)?.Invoke(this, e);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
|
using System.Diagnostics.SymbolStore;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@@ -12,13 +13,14 @@ using TelegramBotBase.Base;
|
|||||||
using TelegramBotBase.Enums;
|
using TelegramBotBase.Enums;
|
||||||
using TelegramBotBase.Exceptions;
|
using TelegramBotBase.Exceptions;
|
||||||
using TelegramBotBase.Form;
|
using TelegramBotBase.Form;
|
||||||
|
using static TelegramBotBase.Base.Async;
|
||||||
|
|
||||||
namespace TelegramBotBase.Controls
|
namespace TelegramBotBase.Controls
|
||||||
{
|
{
|
||||||
public class ButtonGrid : Base.ControlBase
|
public class ButtonGrid : Base.ControlBase
|
||||||
{
|
{
|
||||||
|
|
||||||
public String Title { get; set; } = "Toggle";
|
public String Title { get; set; } = Localizations.Default.Language["ButtonGrid_Title"];
|
||||||
|
|
||||||
public String ConfirmationText { get; set; } = "";
|
public String ConfirmationText { get; set; } = "";
|
||||||
|
|
||||||
@@ -45,8 +47,50 @@ namespace TelegramBotBase.Controls
|
|||||||
|
|
||||||
public bool DeletePreviousMessage { get; set; } = true;
|
public bool DeletePreviousMessage { get; set; } = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Parsemode of the message.
|
||||||
|
/// </summary>
|
||||||
public ParseMode MessageParseMode { get; set; } = ParseMode.Default;
|
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"];
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Layout of the buttons which should be displayed always on top.
|
||||||
|
/// </summary>
|
||||||
|
public List<ButtonBase> HeadLayoutButtonRow { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Layout of columns which should be displayed below the header
|
||||||
|
/// </summary>
|
||||||
|
public List<ButtonBase> SubHeadLayoutButtonRow { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Defines which type of Button Keyboard should be rendered.
|
/// Defines which type of Button Keyboard should be rendered.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -91,7 +135,7 @@ namespace TelegramBotBase.Controls
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public event EventHandler<ButtonClickedEventArgs> ButtonClicked
|
public event AsyncEventHandler<ButtonClickedEventArgs> ButtonClicked
|
||||||
{
|
{
|
||||||
add
|
add
|
||||||
{
|
{
|
||||||
@@ -103,9 +147,13 @@ namespace TelegramBotBase.Controls
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnButtonClicked(ButtonClickedEventArgs e)
|
public async Task OnButtonClicked(ButtonClickedEventArgs e)
|
||||||
{
|
{
|
||||||
(this.Events[__evButtonClicked] as EventHandler<ButtonClickedEventArgs>)?.Invoke(this, e);
|
var handler = this.Events[__evButtonClicked].GetInvocationList().Cast<AsyncEventHandler<ButtonClickedEventArgs>>();
|
||||||
|
foreach (var h in handler)
|
||||||
|
{
|
||||||
|
await Async.InvokeAllAsync<ButtonClickedEventArgs>(h, this, e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async override Task Load(MessageResult result)
|
public async override Task Load(MessageResult result)
|
||||||
@@ -116,12 +164,61 @@ namespace TelegramBotBase.Controls
|
|||||||
if (!result.IsFirstHandler)
|
if (!result.IsFirstHandler)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var button = ButtonsForm.ToList().FirstOrDefault(a => a.Text.Trim() == result.MessageText);
|
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 (button == null)
|
if (button == null)
|
||||||
|
{
|
||||||
|
if (result.MessageText == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
await OnButtonClicked(new ButtonClickedEventArgs(button));
|
||||||
|
|
||||||
//Remove button click message
|
//Remove button click message
|
||||||
if (this.DeletePreviousMessage)
|
if (this.DeletePreviousMessage)
|
||||||
@@ -146,12 +243,37 @@ namespace TelegramBotBase.Controls
|
|||||||
{
|
{
|
||||||
case eKeyboardType.InlineKeyBoard:
|
case eKeyboardType.InlineKeyBoard:
|
||||||
|
|
||||||
var button = ButtonsForm.ToList().FirstOrDefault(a => a.Value == result.RawData);
|
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 (button == null)
|
if (button == null)
|
||||||
return;
|
{
|
||||||
|
switch (result.RawData)
|
||||||
|
{
|
||||||
|
case "$previous$":
|
||||||
|
|
||||||
OnButtonClicked(new ButtonClickedEventArgs(button));
|
if (this.CurrentPageIndex > 0)
|
||||||
|
this.CurrentPageIndex--;
|
||||||
|
|
||||||
|
this.Updated();
|
||||||
|
|
||||||
|
break;
|
||||||
|
case "$next$":
|
||||||
|
|
||||||
|
if (this.CurrentPageIndex < this.PageCount - 1)
|
||||||
|
this.CurrentPageIndex++;
|
||||||
|
|
||||||
|
this.Updated();
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await OnButtonClicked(new ButtonClickedEventArgs(button));
|
||||||
|
|
||||||
result.Handled = true;
|
result.Handled = true;
|
||||||
|
|
||||||
@@ -160,17 +282,16 @@ namespace TelegramBotBase.Controls
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async override Task Render(MessageResult result)
|
/// <summary>
|
||||||
|
/// This method checks of the amount of buttons
|
||||||
|
/// </summary>
|
||||||
|
private void CheckGrid()
|
||||||
{
|
{
|
||||||
if (!this.RenderNecessary)
|
|
||||||
return;
|
|
||||||
|
|
||||||
|
|
||||||
switch (m_eKeyboardType)
|
switch (m_eKeyboardType)
|
||||||
{
|
{
|
||||||
case eKeyboardType.InlineKeyBoard:
|
case eKeyboardType.InlineKeyBoard:
|
||||||
|
|
||||||
if (ButtonsForm.Rows > Constants.Telegram.MaxInlineKeyBoardRows)
|
if (ButtonsForm.Rows > Constants.Telegram.MaxInlineKeyBoardRows && !this.EnablePaging)
|
||||||
{
|
{
|
||||||
throw new MaximumRowsReachedException() { Value = ButtonsForm.Rows, Maximum = Constants.Telegram.MaxInlineKeyBoardRows };
|
throw new MaximumRowsReachedException() { Value = ButtonsForm.Rows, Maximum = Constants.Telegram.MaxInlineKeyBoardRows };
|
||||||
}
|
}
|
||||||
@@ -181,9 +302,10 @@ namespace TelegramBotBase.Controls
|
|||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case eKeyboardType.ReplyKeyboard:
|
case eKeyboardType.ReplyKeyboard:
|
||||||
|
|
||||||
if (ButtonsForm.Rows > Constants.Telegram.MaxReplyKeyboardRows)
|
if (ButtonsForm.Rows > Constants.Telegram.MaxReplyKeyboardRows && !this.EnablePaging)
|
||||||
{
|
{
|
||||||
throw new MaximumRowsReachedException() { Value = ButtonsForm.Rows, Maximum = Constants.Telegram.MaxReplyKeyboardRows };
|
throw new MaximumRowsReachedException() { Value = ButtonsForm.Rows, Maximum = Constants.Telegram.MaxReplyKeyboardRows };
|
||||||
}
|
}
|
||||||
@@ -195,52 +317,93 @@ namespace TelegramBotBase.Controls
|
|||||||
|
|
||||||
break;
|
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;
|
Message m = null;
|
||||||
if (this.MessageId != 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.EnablePaging)
|
||||||
|
{
|
||||||
|
form = GeneratePagingView(form);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.HeadLayoutButtonRow != null && HeadLayoutButtonRow.Count > 0)
|
||||||
|
{
|
||||||
|
form.InsertButtonRow(0, this.HeadLayoutButtonRow);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.SubHeadLayoutButtonRow != null && SubHeadLayoutButtonRow.Count > 0)
|
||||||
|
{
|
||||||
|
if (this.IsNavigationBarVisible)
|
||||||
|
{
|
||||||
|
form.InsertButtonRow(2, this.SubHeadLayoutButtonRow);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
form.InsertButtonRow(1, this.SubHeadLayoutButtonRow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch (this.KeyboardType)
|
switch (this.KeyboardType)
|
||||||
{
|
{
|
||||||
//Reply Keyboard could only be updated with a new keyboard.
|
//Reply Keyboard could only be updated with a new keyboard.
|
||||||
case eKeyboardType.ReplyKeyboard:
|
case eKeyboardType.ReplyKeyboard:
|
||||||
if (this.ButtonsForm.Count == 0)
|
|
||||||
|
if (this.MessageId != null)
|
||||||
|
{
|
||||||
|
if (form.Count == 0)
|
||||||
{
|
{
|
||||||
await this.Device.HideReplyKeyboard();
|
await this.Device.HideReplyKeyboard();
|
||||||
this.MessageId = null;
|
this.MessageId = null;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
if (this.DeletePreviousMessage)
|
if (this.DeletePreviousMessage)
|
||||||
await this.Device.DeleteMessage(this.MessageId.Value);
|
await this.Device.DeleteMessage(this.MessageId.Value);
|
||||||
|
}
|
||||||
|
|
||||||
var rkm = (ReplyKeyboardMarkup)this.ButtonsForm;
|
if (form.Count == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
|
||||||
|
var rkm = (ReplyKeyboardMarkup)form;
|
||||||
rkm.ResizeKeyboard = this.ResizeKeyboard;
|
rkm.ResizeKeyboard = this.ResizeKeyboard;
|
||||||
rkm.OneTimeKeyboard = this.OneTimeKeyboard;
|
rkm.OneTimeKeyboard = this.OneTimeKeyboard;
|
||||||
m = await this.Device.Send(this.Title, rkm, disableNotification: true, parseMode: MessageParseMode);
|
m = await this.Device.Send(this.Title, rkm, disableNotification: true, parseMode: MessageParseMode, MarkdownV2AutoEscape: false);
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case eKeyboardType.InlineKeyBoard:
|
case eKeyboardType.InlineKeyBoard:
|
||||||
m = await this.Device.Edit(this.MessageId.Value, this.Title, (InlineKeyboardMarkup)this.ButtonsForm);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
if (this.MessageId != null)
|
||||||
|
{
|
||||||
|
m = await this.Device.Edit(this.MessageId.Value, this.Title, (InlineKeyboardMarkup)form);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
switch (this.KeyboardType)
|
m = await this.Device.Send(this.Title, (InlineKeyboardMarkup)form, disableNotification: true, parseMode: MessageParseMode, MarkdownV2AutoEscape: false);
|
||||||
{
|
}
|
||||||
case eKeyboardType.ReplyKeyboard:
|
|
||||||
var rkm = (ReplyKeyboardMarkup)this.ButtonsForm;
|
|
||||||
rkm.ResizeKeyboard = this.ResizeKeyboard;
|
|
||||||
rkm.OneTimeKeyboard = this.OneTimeKeyboard;
|
|
||||||
m = await this.Device.Send(this.Title, rkm, disableNotification: true, parseMode: MessageParseMode);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case eKeyboardType.InlineKeyBoard:
|
|
||||||
m = await this.Device.Send(this.Title, (InlineKeyboardMarkup)this.ButtonsForm, disableNotification: true, parseMode: MessageParseMode);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -248,10 +411,158 @@ namespace TelegramBotBase.Controls
|
|||||||
{
|
{
|
||||||
this.MessageId = m.MessageId;
|
this.MessageId = m.MessageId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.RenderNecessary = false;
|
private ButtonForm GeneratePagingView(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)
|
||||||
|
{
|
||||||
|
bf.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$"));
|
||||||
|
|
||||||
|
if (this.EnableSearch)
|
||||||
|
{
|
||||||
|
lst.Insert(2, new ButtonBase("🔍 " + (this.SearchQuery ?? ""), "$search$"));
|
||||||
|
}
|
||||||
|
|
||||||
|
bf.InsertButtonRow(0, lst);
|
||||||
|
|
||||||
|
bf.AddButtonRow(lst);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 + ButtonsForm.Rows;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int PageCount
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (this.ButtonsForm.Count == 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
var bf = this.ButtonsForm;
|
||||||
|
|
||||||
|
if (this.EnableSearch && this.SearchQuery != null && this.SearchQuery != "")
|
||||||
|
{
|
||||||
|
bf = bf.FilterDuplicate(this.SearchQuery);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bf.Rows == 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return (int)Math.Ceiling((decimal)(bf.Rows / (decimal)(MaximumRow - 3)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task Hidden(bool FormClose)
|
public override async Task Hidden(bool FormClose)
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ namespace TelegramBotBase.Controls
|
|||||||
|
|
||||||
private int? MessageId { get; set; }
|
private int? MessageId { get; set; }
|
||||||
|
|
||||||
public String Title { get; set; } = "Pick Date";
|
public String Title { get; set; } = Localizations.Default.Language["CalendarPicker_Title"];
|
||||||
|
|
||||||
public eMonthPickerMode PickerMode { get; set; }
|
public eMonthPickerMode PickerMode { get; set; }
|
||||||
|
|
||||||
@@ -55,7 +55,7 @@ namespace TelegramBotBase.Controls
|
|||||||
|
|
||||||
switch (result.RawData)
|
switch (result.RawData)
|
||||||
{
|
{
|
||||||
case "next":
|
case "$next$":
|
||||||
|
|
||||||
switch (this.PickerMode)
|
switch (this.PickerMode)
|
||||||
{
|
{
|
||||||
@@ -74,7 +74,7 @@ namespace TelegramBotBase.Controls
|
|||||||
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case "prev":
|
case "$prev$":
|
||||||
|
|
||||||
switch (this.PickerMode)
|
switch (this.PickerMode)
|
||||||
{
|
{
|
||||||
@@ -93,7 +93,7 @@ namespace TelegramBotBase.Controls
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "monthtitle":
|
case "$monthtitle$":
|
||||||
|
|
||||||
if (this.EnableMonthView)
|
if (this.EnableMonthView)
|
||||||
{
|
{
|
||||||
@@ -102,7 +102,7 @@ namespace TelegramBotBase.Controls
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "yeartitle":
|
case "$yeartitle$":
|
||||||
|
|
||||||
if (this.EnableYearView)
|
if (this.EnableYearView)
|
||||||
{
|
{
|
||||||
@@ -110,7 +110,7 @@ namespace TelegramBotBase.Controls
|
|||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case "yearstitle":
|
case "$yearstitle$":
|
||||||
|
|
||||||
if (this.EnableMonthView)
|
if (this.EnableMonthView)
|
||||||
{
|
{
|
||||||
@@ -179,7 +179,7 @@ namespace TelegramBotBase.Controls
|
|||||||
string[] dayNamesNormal = this.Culture.DateTimeFormat.ShortestDayNames;
|
string[] dayNamesNormal = this.Culture.DateTimeFormat.ShortestDayNames;
|
||||||
string[] dayNamesShifted = Shift(dayNamesNormal, (int)this.FirstDayOfWeek);
|
string[] dayNamesShifted = Shift(dayNamesNormal, (int)this.FirstDayOfWeek);
|
||||||
|
|
||||||
bf.AddButtonRow(new ButtonBase("<<", "prev"), new ButtonBase(this.Culture.DateTimeFormat.MonthNames[month.Month - 1] + " " + month.Year.ToString(), "monthtitle"), new ButtonBase(">>", "next"));
|
bf.AddButtonRow(new ButtonBase(Localizations.Default.Language["CalendarPicker_PreviousPage"], "$prev$"), new ButtonBase(this.Culture.DateTimeFormat.MonthNames[month.Month - 1] + " " + month.Year.ToString(), "$monthtitle$"), new ButtonBase(Localizations.Default.Language["CalendarPicker_NextPage"], "$next$"));
|
||||||
|
|
||||||
bf.AddButtonRow(dayNamesShifted.Select(a => new ButtonBase(a, a)).ToList());
|
bf.AddButtonRow(dayNamesShifted.Select(a => new ButtonBase(a, a)).ToList());
|
||||||
|
|
||||||
@@ -223,7 +223,7 @@ namespace TelegramBotBase.Controls
|
|||||||
|
|
||||||
case eMonthPickerMode.month:
|
case eMonthPickerMode.month:
|
||||||
|
|
||||||
bf.AddButtonRow(new ButtonBase("<<", "prev"), new ButtonBase(this.VisibleMonth.Year.ToString("0000"), "yeartitle"), new ButtonBase(">>", "next"));
|
bf.AddButtonRow(new ButtonBase(Localizations.Default.Language["CalendarPicker_PreviousPage"], "$prev$"), new ButtonBase(this.VisibleMonth.Year.ToString("0000"), "$yeartitle$"), new ButtonBase(Localizations.Default.Language["CalendarPicker_NextPage"], "$next$"));
|
||||||
|
|
||||||
var months = this.Culture.DateTimeFormat.MonthNames;
|
var months = this.Culture.DateTimeFormat.MonthNames;
|
||||||
|
|
||||||
@@ -235,7 +235,7 @@ namespace TelegramBotBase.Controls
|
|||||||
|
|
||||||
case eMonthPickerMode.year:
|
case eMonthPickerMode.year:
|
||||||
|
|
||||||
bf.AddButtonRow(new ButtonBase("<<", "prev"), new ButtonBase("Year", "yearstitle"), new ButtonBase(">>", "next"));
|
bf.AddButtonRow(new ButtonBase(Localizations.Default.Language["CalendarPicker_PreviousPage"], "$prev$"), new ButtonBase("Year", "$yearstitle$"), new ButtonBase(Localizations.Default.Language["CalendarPicker_NextPage"], "$next$"));
|
||||||
|
|
||||||
var starti = Math.Floor(this.VisibleMonth.Year / 10f) * 10;
|
var starti = Math.Floor(this.VisibleMonth.Year / 10f) * 10;
|
||||||
|
|
||||||
|
|||||||
@@ -12,15 +12,17 @@ namespace TelegramBotBase.Controls
|
|||||||
public class ToggleButton : ControlBase
|
public class ToggleButton : ControlBase
|
||||||
{
|
{
|
||||||
|
|
||||||
public String UncheckedIcon { get; set; } = "⚪";
|
public String UncheckedIcon { get; set; } = Localizations.Default.Language["ToggleButton_OffIcon"];
|
||||||
|
|
||||||
public String CheckedIcon { get; set; } = "⚫";
|
public String CheckedIcon { get; set; } = Localizations.Default.Language["ToggleButton_OnIcon"];
|
||||||
|
|
||||||
public String CheckedString { get; set; } = "On";
|
public String CheckedString { get; set; } = Localizations.Default.Language["ToggleButton_On"];
|
||||||
|
|
||||||
public String UncheckedString { get; set; } = "Off";
|
public String UncheckedString { get; set; } = Localizations.Default.Language["ToggleButton_Off"];
|
||||||
|
|
||||||
public String Title { get; set; } = "Toggle";
|
public String ChangedString { get; set; } = Localizations.Default.Language["ToggleButton_Changed"];
|
||||||
|
|
||||||
|
public String Title { get; set; } = Localizations.Default.Language["ToggleButton_Title"];
|
||||||
|
|
||||||
public int? MessageId { get; set; }
|
public int? MessageId { get; set; }
|
||||||
|
|
||||||
@@ -68,7 +70,7 @@ namespace TelegramBotBase.Controls
|
|||||||
if (result.Handled)
|
if (result.Handled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
await result.ConfirmAction();
|
await result.ConfirmAction(this.ChangedString);
|
||||||
|
|
||||||
switch (value ?? "unknown")
|
switch (value ?? "unknown")
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -20,12 +20,12 @@ namespace TelegramBotBase.Controls
|
|||||||
|
|
||||||
private int? MessageId { get; set; }
|
private int? MessageId { get; set; }
|
||||||
|
|
||||||
public String MoveUpIcon { get; set; } = "🔼 up";
|
public String MoveUpIcon { get; set; } = Localizations.Default.Language["TreeView_LevelUp"];
|
||||||
|
|
||||||
public TreeView()
|
public TreeView()
|
||||||
{
|
{
|
||||||
this.Nodes = new List<TreeViewNode>();
|
this.Nodes = new List<TreeViewNode>();
|
||||||
this.Title = "Select node";
|
this.Title = Localizations.Default.Language["TreeView_Title"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -52,8 +52,10 @@ namespace TelegramBotBase.Controls
|
|||||||
|
|
||||||
var n = (this.VisibleNode != null ? this.VisibleNode.FindNodeByValue(val) : this.Nodes.FirstOrDefault(a => a.Value == val));
|
var n = (this.VisibleNode != null ? this.VisibleNode.FindNodeByValue(val) : this.Nodes.FirstOrDefault(a => a.Value == val));
|
||||||
|
|
||||||
if (n != null)
|
if (n == null)
|
||||||
{
|
return;
|
||||||
|
|
||||||
|
|
||||||
if (n.ChildNodes.Count > 0)
|
if (n.ChildNodes.Count > 0)
|
||||||
{
|
{
|
||||||
this.VisibleNode = n;
|
this.VisibleNode = n;
|
||||||
@@ -64,7 +66,7 @@ namespace TelegramBotBase.Controls
|
|||||||
}
|
}
|
||||||
|
|
||||||
result.Handled = true;
|
result.Handled = true;
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace TelegramBotBase.Enums
|
||||||
|
{
|
||||||
|
public enum eNavigationBarVisibility
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Shows it depending on the amount of items.
|
||||||
|
/// </summary>
|
||||||
|
auto = 0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Will not show it at any time.
|
||||||
|
/// </summary>
|
||||||
|
never = 1,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Will show it at any time.
|
||||||
|
/// </summary>
|
||||||
|
always = 2
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace TelegramBotBase.Enums
|
||||||
|
{
|
||||||
|
public enum eSettings
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// How often could a form navigate to another (within one user action/call/message)
|
||||||
|
/// </summary>
|
||||||
|
NavigationMaximum = 1,
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Loggs all messages and sent them to the event handler
|
||||||
|
/// </summary>
|
||||||
|
LogAllMessages = 2,
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Skips all messages during running (good for big delay updates)
|
||||||
|
/// </summary>
|
||||||
|
SkipAllMessages = 3,
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Does stick to the console event handler and saves all sessions on exit.
|
||||||
|
/// </summary>
|
||||||
|
SaveSessionsOnConsoleExit = 4
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ using System.ComponentModel;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using TelegramBotBase.Attributes;
|
||||||
using TelegramBotBase.Base;
|
using TelegramBotBase.Base;
|
||||||
|
|
||||||
namespace TelegramBotBase.Form
|
namespace TelegramBotBase.Form
|
||||||
@@ -11,6 +12,7 @@ namespace TelegramBotBase.Form
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// A simple prompt dialog with one ok Button
|
/// A simple prompt dialog with one ok Button
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[IgnoreState]
|
||||||
public class AlertDialog : ConfirmDialog
|
public class AlertDialog : ConfirmDialog
|
||||||
{
|
{
|
||||||
public String ButtonText { get; set; }
|
public String ButtonText { get; set; }
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using System.Linq;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using TelegramBotBase.Args;
|
using TelegramBotBase.Args;
|
||||||
|
using TelegramBotBase.Attributes;
|
||||||
using TelegramBotBase.Base;
|
using TelegramBotBase.Base;
|
||||||
|
|
||||||
namespace TelegramBotBase.Form
|
namespace TelegramBotBase.Form
|
||||||
@@ -12,11 +13,11 @@ namespace TelegramBotBase.Form
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// A prompt with a lot of buttons
|
/// A prompt with a lot of buttons
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[IgnoreState]
|
||||||
public class ArrayPromptDialog : FormBase
|
public class ArrayPromptDialog : FormBase
|
||||||
{
|
{
|
||||||
public String Message { get; set; }
|
public String Message { get; set; }
|
||||||
|
|
||||||
|
|
||||||
public ButtonBase[][] Buttons { get; set; }
|
public ButtonBase[][] Buttons { get; set; }
|
||||||
|
|
||||||
[Obsolete]
|
[Obsolete]
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using System.Text;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Telegram.Bot.Types;
|
using Telegram.Bot.Types;
|
||||||
using TelegramBotBase.Args;
|
using TelegramBotBase.Args;
|
||||||
|
using TelegramBotBase.Attributes;
|
||||||
using TelegramBotBase.Base;
|
using TelegramBotBase.Base;
|
||||||
using TelegramBotBase.Enums;
|
using TelegramBotBase.Enums;
|
||||||
|
|
||||||
@@ -15,17 +16,20 @@ namespace TelegramBotBase.Form
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class AutoCleanForm : FormBase
|
public class AutoCleanForm : FormBase
|
||||||
{
|
{
|
||||||
List<Message> OldMessages { get; set; }
|
[SaveState]
|
||||||
|
public List<int> OldMessages { get; set; }
|
||||||
|
|
||||||
|
[SaveState]
|
||||||
public eDeleteMode DeleteMode { get; set; }
|
public eDeleteMode DeleteMode { get; set; }
|
||||||
|
|
||||||
|
[SaveState]
|
||||||
public eDeleteSide DeleteSide { get; set; }
|
public eDeleteSide DeleteSide { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public AutoCleanForm()
|
public AutoCleanForm()
|
||||||
{
|
{
|
||||||
this.OldMessages = new List<Message>();
|
this.OldMessages = new List<int>();
|
||||||
this.DeleteMode = eDeleteMode.OnEveryCall;
|
this.DeleteMode = eDeleteMode.OnEveryCall;
|
||||||
this.DeleteSide = eDeleteSide.BotOnly;
|
this.DeleteSide = eDeleteSide.BotOnly;
|
||||||
|
|
||||||
@@ -52,7 +56,7 @@ namespace TelegramBotBase.Form
|
|||||||
if (this.DeleteSide == eDeleteSide.BotOnly)
|
if (this.DeleteSide == eDeleteSide.BotOnly)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this.OldMessages.Add(e.Message);
|
this.OldMessages.Add(e.Message.MessageId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Device_MessageSent(object sender, MessageSentEventArgs e)
|
private void Device_MessageSent(object sender, MessageSentEventArgs e)
|
||||||
@@ -60,7 +64,7 @@ namespace TelegramBotBase.Form
|
|||||||
if (this.DeleteSide == eDeleteSide.UserOnly)
|
if (this.DeleteSide == eDeleteSide.UserOnly)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this.OldMessages.Add(e.Message);
|
this.OldMessages.Add(e.Message.MessageId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task PreLoad(MessageResult message)
|
public override async Task PreLoad(MessageResult message)
|
||||||
@@ -77,7 +81,17 @@ namespace TelegramBotBase.Form
|
|||||||
/// <param name="Id"></param>
|
/// <param name="Id"></param>
|
||||||
public void AddMessage(Message m)
|
public void AddMessage(Message m)
|
||||||
{
|
{
|
||||||
this.OldMessages.Add(m);
|
this.OldMessages.Add(m.MessageId);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a message to this of removable ones
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="Id"></param>
|
||||||
|
public void AddMessage(int messageId)
|
||||||
|
{
|
||||||
|
this.OldMessages.Add(messageId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -86,11 +100,7 @@ namespace TelegramBotBase.Form
|
|||||||
/// <param name="Id"></param>
|
/// <param name="Id"></param>
|
||||||
public void LeaveMessage(int Id)
|
public void LeaveMessage(int Id)
|
||||||
{
|
{
|
||||||
var m = this.OldMessages.FirstOrDefault(a => a.MessageId == Id);
|
this.OldMessages.Remove(Id);
|
||||||
if (m == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
this.OldMessages.Remove(m);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -120,7 +130,7 @@ namespace TelegramBotBase.Form
|
|||||||
{
|
{
|
||||||
while (this.OldMessages.Count > 0)
|
while (this.OldMessages.Count > 0)
|
||||||
{
|
{
|
||||||
if (!await this.Device.DeleteMessage(this.OldMessages[0].MessageId))
|
if (!await this.Device.DeleteMessage(this.OldMessages[0]))
|
||||||
{
|
{
|
||||||
//Message can't be deleted cause it seems not to exist anymore
|
//Message can't be deleted cause it seems not to exist anymore
|
||||||
if (this.OldMessages.Count > 0)
|
if (this.OldMessages.Count > 0)
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ namespace TelegramBotBase.Form
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class ButtonBase
|
public class ButtonBase
|
||||||
{
|
{
|
||||||
public String Text { get; set; }
|
public virtual String Text { get; set; }
|
||||||
|
|
||||||
public String Value { get; set; }
|
public String Value { get; set; }
|
||||||
|
|
||||||
|
|||||||
@@ -42,6 +42,15 @@ namespace TelegramBotBase.Form
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public List<ButtonBase> this[int row]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return Buttons[row];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public ButtonForm()
|
public ButtonForm()
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -52,6 +61,11 @@ namespace TelegramBotBase.Form
|
|||||||
this.DependencyControl = control;
|
this.DependencyControl = control;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void AddButtonRow(String Text, String Value, String Url = null)
|
||||||
|
{
|
||||||
|
Buttons.Add(new List<ButtonBase>() { new ButtonBase(Text, Value, Url) });
|
||||||
|
}
|
||||||
|
|
||||||
public void AddButtonRow(IEnumerable<ButtonBase> row)
|
public void AddButtonRow(IEnumerable<ButtonBase> row)
|
||||||
{
|
{
|
||||||
Buttons.Add(row.ToList());
|
Buttons.Add(row.ToList());
|
||||||
@@ -62,6 +76,16 @@ namespace TelegramBotBase.Form
|
|||||||
AddButtonRow(row.ToList());
|
AddButtonRow(row.ToList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void InsertButtonRow(int index, IEnumerable<ButtonBase> row)
|
||||||
|
{
|
||||||
|
Buttons.Insert(index, row.ToList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void InsertButtonRow(int index, params ButtonBase[] row)
|
||||||
|
{
|
||||||
|
InsertButtonRow(index, row.ToList());
|
||||||
|
}
|
||||||
|
|
||||||
public static T[][] SplitTo<T>(IEnumerable<T> items, int itemsPerRow = 2)
|
public static T[][] SplitTo<T>(IEnumerable<T> items, int itemsPerRow = 2)
|
||||||
{
|
{
|
||||||
T[][] splitted = default(T[][]);
|
T[][] splitted = default(T[][]);
|
||||||
@@ -86,7 +110,10 @@ namespace TelegramBotBase.Form
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return this.Buttons.Select(a => a.ToArray()).Aggregate((a, b) => a.Union(b).ToArray()).Length;
|
if (this.Buttons.Count == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return this.Buttons.Select(a => a.ToArray()).ToList().Aggregate((a, b) => a.Union(b).ToArray()).Length;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,7 +134,7 @@ namespace TelegramBotBase.Form
|
|||||||
|
|
||||||
public List<ButtonBase> ToList()
|
public List<ButtonBase> ToList()
|
||||||
{
|
{
|
||||||
return this.Buttons.Aggregate((a, b) => a.Union(b).ToList());
|
return this.Buttons.DefaultIfEmpty(new List<ButtonBase>()).Aggregate((a, b) => a.Union(b).ToList());
|
||||||
}
|
}
|
||||||
|
|
||||||
public InlineKeyboardButton[][] ToInlineButtonArray()
|
public InlineKeyboardButton[][] ToInlineButtonArray()
|
||||||
@@ -153,5 +180,69 @@ namespace TelegramBotBase.Form
|
|||||||
|
|
||||||
return ikm;
|
return ikm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a copy of this form.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public ButtonForm Duplicate()
|
||||||
|
{
|
||||||
|
var bf = new ButtonForm()
|
||||||
|
{
|
||||||
|
Markup = this.Markup,
|
||||||
|
DependencyControl = this.DependencyControl
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (var b in Buttons)
|
||||||
|
{
|
||||||
|
var lst = new List<ButtonBase>();
|
||||||
|
foreach (var b2 in b)
|
||||||
|
{
|
||||||
|
lst.Add(b2);
|
||||||
|
}
|
||||||
|
bf.Buttons.Add(lst);
|
||||||
|
}
|
||||||
|
|
||||||
|
return bf;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a copy of this form and filters by the parameter.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public ButtonForm FilterDuplicate(String filter, bool ByRow = false)
|
||||||
|
{
|
||||||
|
var bf = new ButtonForm()
|
||||||
|
{
|
||||||
|
Markup = this.Markup,
|
||||||
|
DependencyControl = this.DependencyControl
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (var b in Buttons)
|
||||||
|
{
|
||||||
|
var lst = new List<ButtonBase>();
|
||||||
|
foreach (var b2 in b)
|
||||||
|
{
|
||||||
|
if (b2.Text.IndexOf(filter, StringComparison.InvariantCultureIgnoreCase) == -1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
//Copy full row, when at least one match has found.
|
||||||
|
if (ByRow)
|
||||||
|
{
|
||||||
|
lst.AddRange(b);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lst.Add(b2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lst.Count > 0)
|
||||||
|
bf.Buttons.Add(lst);
|
||||||
|
}
|
||||||
|
|
||||||
|
return bf;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,14 +5,20 @@ using System.Linq;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using TelegramBotBase.Args;
|
using TelegramBotBase.Args;
|
||||||
|
using TelegramBotBase.Attributes;
|
||||||
using TelegramBotBase.Base;
|
using TelegramBotBase.Base;
|
||||||
|
|
||||||
namespace TelegramBotBase.Form
|
namespace TelegramBotBase.Form
|
||||||
{
|
{
|
||||||
|
[IgnoreState]
|
||||||
public class ConfirmDialog : ModalDialog
|
public class ConfirmDialog : ModalDialog
|
||||||
{
|
{
|
||||||
public String Message { get; set; }
|
public String Message { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Automatically close form on button click
|
||||||
|
/// </summary>
|
||||||
|
public bool AutoCloseOnClick { get; set; } = true;
|
||||||
|
|
||||||
public List<ButtonBase> Buttons { get; set; }
|
public List<ButtonBase> Buttons { get; set; }
|
||||||
|
|
||||||
@@ -48,6 +54,12 @@ namespace TelegramBotBase.Form
|
|||||||
|
|
||||||
public override async Task Action(MessageResult message)
|
public override async Task Action(MessageResult message)
|
||||||
{
|
{
|
||||||
|
if (message.Handled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!message.IsFirstHandler)
|
||||||
|
return;
|
||||||
|
|
||||||
var call = message.GetData<CallbackData>();
|
var call = message.GetData<CallbackData>();
|
||||||
if (call == null)
|
if (call == null)
|
||||||
return;
|
return;
|
||||||
@@ -66,6 +78,9 @@ namespace TelegramBotBase.Form
|
|||||||
}
|
}
|
||||||
|
|
||||||
OnButtonClicked(new ButtonClickedEventArgs(button));
|
OnButtonClicked(new ButtonClickedEventArgs(button));
|
||||||
|
|
||||||
|
if (AutoCloseOnClick)
|
||||||
|
await CloseForm();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace TelegramBotBase.Form
|
||||||
|
{
|
||||||
|
public class DynamicButton : ButtonBase
|
||||||
|
{
|
||||||
|
public override string Text
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return GetText?.Invoke() ?? m_text;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
m_text = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String m_text = "";
|
||||||
|
|
||||||
|
private Func<String> GetText;
|
||||||
|
|
||||||
|
public DynamicButton(String Text, String Value, String Url = null)
|
||||||
|
{
|
||||||
|
this.Text = Text;
|
||||||
|
this.Value = Value;
|
||||||
|
this.Url = Url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DynamicButton(Func<String> GetText, String Value, String Url = null)
|
||||||
|
{
|
||||||
|
this.GetText = GetText;
|
||||||
|
this.Value = Value;
|
||||||
|
this.Url = Url;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -22,7 +22,7 @@ namespace TelegramBotBase.Form
|
|||||||
await this.OnClosed(new EventArgs());
|
await this.OnClosed(new EventArgs());
|
||||||
|
|
||||||
|
|
||||||
this.ParentForm?.ReturnFromModal(this);
|
await this.ParentForm?.ReturnFromModal(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,11 +4,14 @@ using System.ComponentModel;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Telegram.Bot.Types;
|
||||||
using Telegram.Bot.Types.ReplyMarkups;
|
using Telegram.Bot.Types.ReplyMarkups;
|
||||||
|
using TelegramBotBase.Attributes;
|
||||||
using TelegramBotBase.Base;
|
using TelegramBotBase.Base;
|
||||||
|
|
||||||
namespace TelegramBotBase.Form
|
namespace TelegramBotBase.Form
|
||||||
{
|
{
|
||||||
|
[IgnoreState]
|
||||||
public class PromptDialog : ModalDialog
|
public class PromptDialog : ModalDialog
|
||||||
{
|
{
|
||||||
public String Message { get; set; }
|
public String Message { get; set; }
|
||||||
@@ -21,7 +24,12 @@ namespace TelegramBotBase.Form
|
|||||||
|
|
||||||
public bool ShowBackButton { get; set; } = false;
|
public bool ShowBackButton { get; set; } = false;
|
||||||
|
|
||||||
public String BackLabel { get; set; } = "Zurück";
|
public String BackLabel { get; set; } = Localizations.Default.Language["PromptDialog_Back"];
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Contains the RAW received message.
|
||||||
|
/// </summary>
|
||||||
|
public Message ReceivedMessage { get; set; }
|
||||||
|
|
||||||
public PromptDialog()
|
public PromptDialog()
|
||||||
{
|
{
|
||||||
@@ -38,6 +46,9 @@ namespace TelegramBotBase.Form
|
|||||||
if (message.Handled)
|
if (message.Handled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (!message.IsFirstHandler)
|
||||||
|
return;
|
||||||
|
|
||||||
if (this.ShowBackButton && message.MessageText == BackLabel)
|
if (this.ShowBackButton && message.MessageText == BackLabel)
|
||||||
{
|
{
|
||||||
await this.CloseForm();
|
await this.CloseForm();
|
||||||
@@ -48,6 +59,8 @@ namespace TelegramBotBase.Form
|
|||||||
if (this.Value == null)
|
if (this.Value == null)
|
||||||
{
|
{
|
||||||
this.Value = message.MessageText;
|
this.Value = message.MessageText;
|
||||||
|
|
||||||
|
ReceivedMessage = message.Message;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -71,6 +84,8 @@ namespace TelegramBotBase.Form
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
message.Handled = true;
|
||||||
|
|
||||||
OnCompleted(new EventArgs());
|
OnCompleted(new EventArgs());
|
||||||
|
|
||||||
await this.CloseForm();
|
await this.CloseForm();
|
||||||
|
|||||||
@@ -3,11 +3,14 @@ using System.Collections.Generic;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using TelegramBotBase.Args;
|
using TelegramBotBase.Args;
|
||||||
using TelegramBotBase.Base;
|
using TelegramBotBase.Base;
|
||||||
|
using TelegramBotBase.Form;
|
||||||
|
|
||||||
namespace TelegramBotBase.Interfaces
|
namespace TelegramBotBase.Interfaces
|
||||||
{
|
{
|
||||||
public interface IStateMachine
|
public interface IStateMachine
|
||||||
{
|
{
|
||||||
|
Type FallbackStateForm { get; }
|
||||||
|
|
||||||
void SaveFormStates(SaveStatesEventArgs e);
|
void SaveFormStates(SaveStatesEventArgs e);
|
||||||
|
|
||||||
StateContainer LoadFormStates();
|
StateContainer LoadFormStates();
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace TelegramBotBase.Localizations
|
||||||
|
{
|
||||||
|
public static class Default
|
||||||
|
{
|
||||||
|
|
||||||
|
public static Localization Language = new English();
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace TelegramBotBase.Localizations
|
||||||
|
{
|
||||||
|
public class English : Localization
|
||||||
|
{
|
||||||
|
public English() : base()
|
||||||
|
{
|
||||||
|
Values["Language"] = "English";
|
||||||
|
Values["ButtonGrid_Title"] = "Menu";
|
||||||
|
Values["ButtonGrid_NoItems"] = "There are no items.";
|
||||||
|
Values["ButtonGrid_PreviousPage"] = "◀️";
|
||||||
|
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["CalendarPicker_Title"] = "Pick date";
|
||||||
|
Values["CalendarPicker_PreviousPage"] = "◀️";
|
||||||
|
Values["CalendarPicker_NextPage"] = "▶️";
|
||||||
|
Values["TreeView_Title"] = "Select node";
|
||||||
|
Values["TreeView_LevelUp"] = "🔼 level up";
|
||||||
|
Values["ToggleButton_On"] = "On";
|
||||||
|
Values["ToggleButton_Off"] = "Off";
|
||||||
|
Values["ToggleButton_OnIcon"] = "⚫";
|
||||||
|
Values["ToggleButton_OffIcon"] = "⚪";
|
||||||
|
Values["ToggleButton_Title"] = "Toggle";
|
||||||
|
Values["PromptDialog_Back"] = "Back";
|
||||||
|
Values["ToggleButton_Changed"] = "Setting changed";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace TelegramBotBase.Localizations
|
||||||
|
{
|
||||||
|
public class German : Localization
|
||||||
|
{
|
||||||
|
public German() : base()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace TelegramBotBase.Localizations
|
||||||
|
{
|
||||||
|
public class Localization
|
||||||
|
{
|
||||||
|
public Dictionary<String, String> Values = new Dictionary<string, string>();
|
||||||
|
|
||||||
|
public String this[String key]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return Values[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -10,7 +10,7 @@ using System.Runtime.InteropServices;
|
|||||||
[assembly: AssemblyConfiguration("")]
|
[assembly: AssemblyConfiguration("")]
|
||||||
[assembly: AssemblyCompany("Florian Dahn")]
|
[assembly: AssemblyCompany("Florian Dahn")]
|
||||||
[assembly: AssemblyProduct("TelegramBotBase Framework")]
|
[assembly: AssemblyProduct("TelegramBotBase Framework")]
|
||||||
[assembly: AssemblyCopyright("Copyright © Florian Dahn 2019")]
|
[assembly: AssemblyCopyright("Copyright © Florian Dahn 2020")]
|
||||||
[assembly: AssemblyTrademark("")]
|
[assembly: AssemblyTrademark("")]
|
||||||
[assembly: AssemblyCulture("")]
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
||||||
@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
|
|||||||
// Sie können alle Werte angeben oder die standardmäßigen Build- und Revisionsnummern
|
// Sie können alle Werte angeben oder die standardmäßigen Build- und Revisionsnummern
|
||||||
// übernehmen, indem Sie "*" eingeben:
|
// übernehmen, indem Sie "*" eingeben:
|
||||||
// [assembly: AssemblyVersion("1.0.*")]
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
[assembly: AssemblyVersion("2.1.0.0")]
|
[assembly: AssemblyVersion("3.1.0.0")]
|
||||||
[assembly: AssemblyFileVersion("2.1.0.0")]
|
[assembly: AssemblyFileVersion("3.1.0.0")]
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Runtime.Serialization;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using TelegramBotBase.Args;
|
using TelegramBotBase.Args;
|
||||||
@@ -14,12 +16,15 @@ namespace TelegramBotBase
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Base class for managing all active sessions
|
/// Base class for managing all active sessions
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class SessionBase
|
public class SessionBase<T>
|
||||||
|
where T : FormBase
|
||||||
{
|
{
|
||||||
public MessageClient Client { get; set; }
|
public MessageClient Client { get; set; }
|
||||||
|
|
||||||
public Dictionary<long, DeviceSession> SessionList { get; set; }
|
public Dictionary<long, DeviceSession> SessionList { get; set; }
|
||||||
|
|
||||||
|
public BotBase<T> BotBase { get; set; }
|
||||||
|
|
||||||
|
|
||||||
public SessionBase()
|
public SessionBase()
|
||||||
{
|
{
|
||||||
@@ -130,7 +135,22 @@ namespace TelegramBotBase
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var form = t.GetConstructor(new Type[] { }).Invoke(new object[] { }) as FormBase;
|
var form = t.GetConstructor(new Type[] { })?.Invoke(new object[] { }) as FormBase;
|
||||||
|
|
||||||
|
//No default constructor, fallback
|
||||||
|
if (form == null)
|
||||||
|
{
|
||||||
|
if (!statemachine.FallbackStateForm.IsSubclassOf(typeof(FormBase)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
form = statemachine.FallbackStateForm.GetConstructor(new Type[] { })?.Invoke(new object[] { }) as FormBase;
|
||||||
|
|
||||||
|
//Fallback failed, due missing default constructor
|
||||||
|
if (form == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (s.Values != null && s.Values.Count > 0)
|
if (s.Values != null && s.Values.Count > 0)
|
||||||
{
|
{
|
||||||
@@ -145,6 +165,16 @@ namespace TelegramBotBase
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
if (f.PropertyType.IsEnum)
|
||||||
|
{
|
||||||
|
var ent = Enum.Parse(f.PropertyType, p.Value.ToString());
|
||||||
|
|
||||||
|
f.SetValue(form, ent);
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
f.SetValue(form, p.Value);
|
f.SetValue(form, p.Value);
|
||||||
}
|
}
|
||||||
catch (ArgumentException ex)
|
catch (ArgumentException ex)
|
||||||
@@ -211,21 +241,28 @@ namespace TelegramBotBase
|
|||||||
|
|
||||||
var form = s.Value.ActiveForm;
|
var form = s.Value.ActiveForm;
|
||||||
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var se = new StateEntry();
|
var se = new StateEntry();
|
||||||
se.DeviceId = s.Key;
|
se.DeviceId = s.Key;
|
||||||
se.ChatTitle = s.Value.ChatTitle;
|
se.ChatTitle = s.Value.GetChatTitle();
|
||||||
se.FormUri = form.GetType().FullName;
|
se.FormUri = form.GetType().FullName;
|
||||||
se.QualifiedName = form.GetType().AssemblyQualifiedName;
|
se.QualifiedName = form.GetType().AssemblyQualifiedName;
|
||||||
|
|
||||||
//Skip classes where IgnoreState attribute is existing
|
//Skip classes where IgnoreState attribute is existing
|
||||||
if (form.GetType().GetCustomAttributes(typeof(IgnoreState), true).Length != 0)
|
if (form.GetType().GetCustomAttributes(typeof(IgnoreState), true).Length != 0)
|
||||||
|
{
|
||||||
|
//Skip this form, when there is no fallback state form
|
||||||
|
if (statemachine.FallbackStateForm == null)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Replace form by default State one.
|
||||||
|
se.FormUri = statemachine.FallbackStateForm.FullName;
|
||||||
|
se.QualifiedName = statemachine.FallbackStateForm.AssemblyQualifiedName;
|
||||||
|
}
|
||||||
|
|
||||||
//Is Subclass of IStateForm
|
//Is Subclass of IStateForm
|
||||||
var iform = form as IStateForm;
|
var iform = form as IStateForm;
|
||||||
if (iform != null)
|
if (iform != null)
|
||||||
@@ -261,5 +298,17 @@ namespace TelegramBotBase
|
|||||||
|
|
||||||
statemachine.SaveFormStates(new SaveStatesEventArgs(sc));
|
statemachine.SaveFormStates(new SaveStatesEventArgs(sc));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Saves all open states into the machine.
|
||||||
|
/// </summary>
|
||||||
|
public void SaveSessionStates()
|
||||||
|
{
|
||||||
|
if (this.BotBase.StateMachine == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
|
||||||
|
this.SaveSessionStates(this.BotBase.StateMachine);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,18 @@ namespace TelegramBotBase.Sessions
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public String ChatTitle { get; set; }
|
public String ChatTitle { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the ChatTitle depending on groups/channels or users
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public String GetChatTitle()
|
||||||
|
{
|
||||||
|
return LastMessage?.Chat.Title
|
||||||
|
?? LastMessage?.Chat.Username
|
||||||
|
?? LastMessage?.Chat.FirstName
|
||||||
|
?? ChatTitle;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// When did any last action happend (message received or button clicked)
|
/// When did any last action happend (message received or button clicked)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -123,6 +135,7 @@ namespace TelegramBotBase.Sessions
|
|||||||
this.ActiveForm.Device = this;
|
this.ActiveForm.Device = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Edits the text message
|
/// Edits the text message
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -130,11 +143,8 @@ namespace TelegramBotBase.Sessions
|
|||||||
/// <param name="text"></param>
|
/// <param name="text"></param>
|
||||||
/// <param name="buttons"></param>
|
/// <param name="buttons"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task<Message> Edit(int messageId, String text, ButtonForm buttons = null)
|
public async Task<Message> Edit(int messageId, String text, ButtonForm buttons = null, ParseMode parseMode = ParseMode.Default)
|
||||||
{
|
{
|
||||||
if (this.ActiveForm == null)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
InlineKeyboardMarkup markup = buttons;
|
InlineKeyboardMarkup markup = buttons;
|
||||||
|
|
||||||
if (text.Length > Constants.Telegram.MaxMessageLength)
|
if (text.Length > Constants.Telegram.MaxMessageLength)
|
||||||
@@ -144,7 +154,7 @@ namespace TelegramBotBase.Sessions
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return await this.Client.TelegramClient.EditMessageTextAsync(this.DeviceId, messageId, text, replyMarkup: markup);
|
return await this.Client.TelegramClient.EditMessageTextAsync(this.DeviceId, messageId, text, parseMode, replyMarkup: markup);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
@@ -162,11 +172,8 @@ namespace TelegramBotBase.Sessions
|
|||||||
/// <param name="text"></param>
|
/// <param name="text"></param>
|
||||||
/// <param name="buttons"></param>
|
/// <param name="buttons"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task<Message> Edit(int messageId, String text, InlineKeyboardMarkup markup)
|
public async Task<Message> Edit(int messageId, String text, InlineKeyboardMarkup markup, ParseMode parseMode = ParseMode.Default)
|
||||||
{
|
{
|
||||||
if (this.ActiveForm == null)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
if (text.Length > Constants.Telegram.MaxMessageLength)
|
if (text.Length > Constants.Telegram.MaxMessageLength)
|
||||||
{
|
{
|
||||||
throw new MaxLengthException(text.Length);
|
throw new MaxLengthException(text.Length);
|
||||||
@@ -174,7 +181,7 @@ namespace TelegramBotBase.Sessions
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return await this.Client.TelegramClient.EditMessageTextAsync(this.DeviceId, messageId, text, replyMarkup: markup);
|
return await this.Client.TelegramClient.EditMessageTextAsync(this.DeviceId, messageId, text, parseMode, replyMarkup: markup);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
@@ -192,11 +199,8 @@ namespace TelegramBotBase.Sessions
|
|||||||
/// <param name="text"></param>
|
/// <param name="text"></param>
|
||||||
/// <param name="buttons"></param>
|
/// <param name="buttons"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task<Message> Edit(Message message, ButtonForm buttons = null)
|
public async Task<Message> Edit(Message message, ButtonForm buttons = null, ParseMode parseMode = ParseMode.Default)
|
||||||
{
|
{
|
||||||
if (this.ActiveForm == null)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
InlineKeyboardMarkup markup = buttons;
|
InlineKeyboardMarkup markup = buttons;
|
||||||
|
|
||||||
if (message.Text.Length > Constants.Telegram.MaxMessageLength)
|
if (message.Text.Length > Constants.Telegram.MaxMessageLength)
|
||||||
@@ -206,7 +210,7 @@ namespace TelegramBotBase.Sessions
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return await this.Client.TelegramClient.EditMessageTextAsync(this.DeviceId, message.MessageId, message.Text, replyMarkup: markup);
|
return await this.Client.TelegramClient.EditMessageTextAsync(this.DeviceId, message.MessageId, message.Text, parseMode, replyMarkup: markup);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
@@ -217,6 +221,27 @@ namespace TelegramBotBase.Sessions
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Edits the reply keyboard markup (buttons)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="messageId"></param>
|
||||||
|
/// <param name="bf"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task<Message> EditReplyMarkup(int messageId, ButtonForm bf)
|
||||||
|
{
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return await this.Client.TelegramClient.EditMessageReplyMarkupAsync(this.DeviceId, messageId, bf);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sends a simple text message
|
/// Sends a simple text message
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -225,7 +250,7 @@ namespace TelegramBotBase.Sessions
|
|||||||
/// <param name="replyTo"></param>
|
/// <param name="replyTo"></param>
|
||||||
/// <param name="disableNotification"></param>
|
/// <param name="disableNotification"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task<Message> Send(String text, ButtonForm buttons = null, int replyTo = 0, bool disableNotification = false, ParseMode parseMode = ParseMode.Default, bool MarkdownV2AutoEscape = true)
|
public async Task<Message> Send(long deviceId, String text, ButtonForm buttons = null, int replyTo = 0, bool disableNotification = false, ParseMode parseMode = ParseMode.Default, bool MarkdownV2AutoEscape = true)
|
||||||
{
|
{
|
||||||
if (this.ActiveForm == null)
|
if (this.ActiveForm == null)
|
||||||
return null;
|
return null;
|
||||||
@@ -246,7 +271,7 @@ namespace TelegramBotBase.Sessions
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
m = await (this.Client.TelegramClient.SendTextMessageAsync(this.DeviceId, text, parseMode, replyToMessageId: replyTo, replyMarkup: markup, disableNotification: disableNotification));
|
m = await (this.Client.TelegramClient.SendTextMessageAsync(deviceId, text, parseMode, replyToMessageId: replyTo, replyMarkup: markup, disableNotification: disableNotification));
|
||||||
|
|
||||||
OnMessageSent(new MessageSentEventArgs(m));
|
OnMessageSent(new MessageSentEventArgs(m));
|
||||||
}
|
}
|
||||||
@@ -262,6 +287,19 @@ namespace TelegramBotBase.Sessions
|
|||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sends a simple text message
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="text"></param>
|
||||||
|
/// <param name="buttons"></param>
|
||||||
|
/// <param name="replyTo"></param>
|
||||||
|
/// <param name="disableNotification"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task<Message> Send(String text, ButtonForm buttons = null, int replyTo = 0, bool disableNotification = false, ParseMode parseMode = ParseMode.Default, bool MarkdownV2AutoEscape = true)
|
||||||
|
{
|
||||||
|
return await Send(this.DeviceId, text, buttons, replyTo, disableNotification, parseMode, MarkdownV2AutoEscape);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sends a simple text message
|
/// Sends a simple text message
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -356,7 +394,7 @@ namespace TelegramBotBase.Sessions
|
|||||||
/// <param name="replyTo"></param>
|
/// <param name="replyTo"></param>
|
||||||
/// <param name="disableNotification"></param>
|
/// <param name="disableNotification"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task<Message> SendPhoto(InputOnlineFile file, ButtonForm buttons = null, int replyTo = 0, bool disableNotification = false, ParseMode parseMode = ParseMode.Default)
|
public async Task<Message> SendPhoto(InputOnlineFile file, String caption = null, ButtonForm buttons = null, int replyTo = 0, bool disableNotification = false, ParseMode parseMode = ParseMode.Default)
|
||||||
{
|
{
|
||||||
if (this.ActiveForm == null)
|
if (this.ActiveForm == null)
|
||||||
return null;
|
return null;
|
||||||
@@ -367,7 +405,7 @@ namespace TelegramBotBase.Sessions
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
m = await this.Client.TelegramClient.SendPhotoAsync(this.DeviceId, file, parseMode: parseMode, replyToMessageId: replyTo, replyMarkup: markup, disableNotification: disableNotification);
|
m = await this.Client.TelegramClient.SendPhotoAsync(this.DeviceId, file, caption: caption, parseMode: parseMode, replyToMessageId: replyTo, replyMarkup: markup, disableNotification: disableNotification);
|
||||||
|
|
||||||
OnMessageSent(new MessageSentEventArgs(m));
|
OnMessageSent(new MessageSentEventArgs(m));
|
||||||
}
|
}
|
||||||
@@ -392,13 +430,13 @@ namespace TelegramBotBase.Sessions
|
|||||||
/// <param name="replyTo"></param>
|
/// <param name="replyTo"></param>
|
||||||
/// <param name="disableNotification"></param>
|
/// <param name="disableNotification"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task<Message> SendPhoto(Image image, String name, ButtonForm buttons = null, int replyTo = 0, bool disableNotification = false)
|
public async Task<Message> SendPhoto(Image image, String name, String caption, ButtonForm buttons = null, int replyTo = 0, bool disableNotification = false)
|
||||||
{
|
{
|
||||||
using (var fileStream = Tools.Images.ToStream(image, ImageFormat.Png))
|
using (var fileStream = Tools.Images.ToStream(image, ImageFormat.Png))
|
||||||
{
|
{
|
||||||
InputOnlineFile fts = new InputOnlineFile(fileStream, name);
|
InputOnlineFile fts = new InputOnlineFile(fileStream, name);
|
||||||
|
|
||||||
return await SendPhoto(fts, buttons, replyTo, disableNotification);
|
return await SendPhoto(fts, caption: caption, buttons, replyTo, disableNotification);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -411,13 +449,13 @@ namespace TelegramBotBase.Sessions
|
|||||||
/// <param name="replyTo"></param>
|
/// <param name="replyTo"></param>
|
||||||
/// <param name="disableNotification"></param>
|
/// <param name="disableNotification"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task<Message> SendPhoto(Bitmap image, String name, ButtonForm buttons = null, int replyTo = 0, bool disableNotification = false)
|
public async Task<Message> SendPhoto(Bitmap image, String name, String caption, ButtonForm buttons = null, int replyTo = 0, bool disableNotification = false)
|
||||||
{
|
{
|
||||||
using (var fileStream = Tools.Images.ToStream(image, ImageFormat.Png))
|
using (var fileStream = Tools.Images.ToStream(image, ImageFormat.Png))
|
||||||
{
|
{
|
||||||
InputOnlineFile fts = new InputOnlineFile(fileStream, name);
|
InputOnlineFile fts = new InputOnlineFile(fileStream, name);
|
||||||
|
|
||||||
return await SendPhoto(fts, buttons, replyTo, disableNotification);
|
return await SendPhoto(fts, caption: caption, buttons, replyTo, disableNotification);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -429,7 +467,7 @@ namespace TelegramBotBase.Sessions
|
|||||||
/// <param name="replyTo"></param>
|
/// <param name="replyTo"></param>
|
||||||
/// <param name="disableNotification"></param>
|
/// <param name="disableNotification"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task<Message> SendVideo(InputOnlineFile file, ButtonForm buttons = null, int replyTo = 0, bool disableNotification = false, ParseMode parseMode = ParseMode.Default)
|
public async Task<Message> SendVideo(InputOnlineFile file, String caption = null, ButtonForm buttons = null, int replyTo = 0, bool disableNotification = false, ParseMode parseMode = ParseMode.Default)
|
||||||
{
|
{
|
||||||
if (this.ActiveForm == null)
|
if (this.ActiveForm == null)
|
||||||
return null;
|
return null;
|
||||||
@@ -440,7 +478,7 @@ namespace TelegramBotBase.Sessions
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
m = await this.Client.TelegramClient.SendVideoAsync(this.DeviceId, file, parseMode: parseMode, replyToMessageId: replyTo, replyMarkup: markup, disableNotification: disableNotification);
|
m = await this.Client.TelegramClient.SendVideoAsync(this.DeviceId, file, caption: caption, parseMode: parseMode, replyToMessageId: replyTo, replyMarkup: markup, disableNotification: disableNotification);
|
||||||
|
|
||||||
OnMessageSent(new MessageSentEventArgs(m));
|
OnMessageSent(new MessageSentEventArgs(m));
|
||||||
}
|
}
|
||||||
@@ -699,6 +737,19 @@ namespace TelegramBotBase.Sessions
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public virtual async Task UnbanUser(int userId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await this.Client.TelegramClient.UnbanChatMemberAsync(this.DeviceId, userId);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Eventhandler for sent messages
|
/// Eventhandler for sent messages
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using System.Runtime.Serialization.Formatters;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using TelegramBotBase.Args;
|
using TelegramBotBase.Args;
|
||||||
using TelegramBotBase.Base;
|
using TelegramBotBase.Base;
|
||||||
|
using TelegramBotBase.Form;
|
||||||
using TelegramBotBase.Interfaces;
|
using TelegramBotBase.Interfaces;
|
||||||
|
|
||||||
namespace TelegramBotBase.States
|
namespace TelegramBotBase.States
|
||||||
@@ -18,13 +19,28 @@ namespace TelegramBotBase.States
|
|||||||
|
|
||||||
public bool Overwrite { get; set; }
|
public bool Overwrite { get; set; }
|
||||||
|
|
||||||
public JSONStateMachine(String file, bool overwrite = true)
|
public Type FallbackStateForm { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Will initialize the state machine.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="file">Path of the file and name where to save the session details.</param>
|
||||||
|
/// <param name="fallbackStateForm">Type of Form which will be saved instead of Form which has <seealso cref="Attributes.IgnoreState"/> attribute declared. Needs to be subclass of <seealso cref="Form.FormBase"/>.</param>
|
||||||
|
/// <param name="overwrite">Declares of the file could be overwritten.</param>
|
||||||
|
public JSONStateMachine(String file, Type fallbackStateForm = null, bool overwrite = true)
|
||||||
{
|
{
|
||||||
if (file is null)
|
if (file is null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(file));
|
throw new ArgumentNullException(nameof(file));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.FallbackStateForm = fallbackStateForm;
|
||||||
|
|
||||||
|
if (this.FallbackStateForm != null && !this.FallbackStateForm.IsSubclassOf(typeof(FormBase)))
|
||||||
|
{
|
||||||
|
throw new ArgumentException("FallbackStateForm is not a subclass of FormBase");
|
||||||
|
}
|
||||||
|
|
||||||
this.FilePath = file;
|
this.FilePath = file;
|
||||||
this.Overwrite = overwrite;
|
this.Overwrite = overwrite;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using System.Runtime.Serialization.Formatters;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using TelegramBotBase.Args;
|
using TelegramBotBase.Args;
|
||||||
using TelegramBotBase.Base;
|
using TelegramBotBase.Base;
|
||||||
|
using TelegramBotBase.Form;
|
||||||
using TelegramBotBase.Interfaces;
|
using TelegramBotBase.Interfaces;
|
||||||
|
|
||||||
namespace TelegramBotBase.States
|
namespace TelegramBotBase.States
|
||||||
@@ -18,13 +19,28 @@ namespace TelegramBotBase.States
|
|||||||
|
|
||||||
public bool Overwrite { get; set; }
|
public bool Overwrite { get; set; }
|
||||||
|
|
||||||
public SimpleJSONStateMachine(String file, bool overwrite = true)
|
public Type FallbackStateForm { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Will initialize the state machine.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="file">Path of the file and name where to save the session details.</param>
|
||||||
|
/// <param name="fallbackStateForm">Type of Form which will be saved instead of Form which has <seealso cref="Attributes.IgnoreState"/> attribute declared. Needs to be subclass of <seealso cref="Form.FormBase"/>.</param>
|
||||||
|
/// <param name="overwrite">Declares of the file could be overwritten.</param>
|
||||||
|
public SimpleJSONStateMachine(String file, Type fallbackStateForm = null, bool overwrite = true)
|
||||||
{
|
{
|
||||||
if (file is null)
|
if (file is null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(file));
|
throw new ArgumentNullException(nameof(file));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.FallbackStateForm = fallbackStateForm;
|
||||||
|
|
||||||
|
if (this.FallbackStateForm != null && !this.FallbackStateForm.IsSubclassOf(typeof(FormBase)))
|
||||||
|
{
|
||||||
|
throw new ArgumentException("FallbackStateForm is not a subclass of FormBase");
|
||||||
|
}
|
||||||
|
|
||||||
this.FilePath = file;
|
this.FilePath = file;
|
||||||
this.Overwrite = overwrite;
|
this.Overwrite = overwrite;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ using System.Xml;
|
|||||||
using System.Xml.Serialization;
|
using System.Xml.Serialization;
|
||||||
using TelegramBotBase.Args;
|
using TelegramBotBase.Args;
|
||||||
using TelegramBotBase.Base;
|
using TelegramBotBase.Base;
|
||||||
|
using TelegramBotBase.Form;
|
||||||
using TelegramBotBase.Interfaces;
|
using TelegramBotBase.Interfaces;
|
||||||
|
|
||||||
namespace TelegramBotBase.States
|
namespace TelegramBotBase.States
|
||||||
@@ -17,13 +18,28 @@ namespace TelegramBotBase.States
|
|||||||
|
|
||||||
public bool Overwrite { get; set; }
|
public bool Overwrite { get; set; }
|
||||||
|
|
||||||
public XMLStateMachine(String file, bool overwrite = true)
|
public Type FallbackStateForm { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Will initialize the state machine.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="file">Path of the file and name where to save the session details.</param>
|
||||||
|
/// <param name="fallbackStateForm">Type of Form which will be saved instead of Form which has <seealso cref="Attributes.IgnoreState"/> attribute declared. Needs to be subclass of <seealso cref="Form.FormBase"/>.</param>
|
||||||
|
/// <param name="overwrite">Declares of the file could be overwritten.</param>
|
||||||
|
public XMLStateMachine(String file, Type fallbackStateForm = null, bool overwrite = true)
|
||||||
{
|
{
|
||||||
if (file is null)
|
if (file is null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(file));
|
throw new ArgumentNullException(nameof(file));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.FallbackStateForm = fallbackStateForm;
|
||||||
|
|
||||||
|
if (this.FallbackStateForm != null && !this.FallbackStateForm.IsSubclassOf(typeof(FormBase)))
|
||||||
|
{
|
||||||
|
throw new ArgumentException("FallbackStateForm is not a subclass of FormBase");
|
||||||
|
}
|
||||||
|
|
||||||
this.FilePath = file;
|
this.FilePath = file;
|
||||||
this.Overwrite = overwrite;
|
this.Overwrite = overwrite;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,28 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFrameworks>netstandard2.0;net461;netcoreapp3.1</TargetFrameworks>
|
<TargetFrameworks>netstandard2.1;net461;netcoreapp3.1</TargetFrameworks>
|
||||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||||
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
|
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
|
||||||
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
|
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
|
||||||
<PackageProjectUrl>https://github.com/MajMcCloud/TelegramBotFramework</PackageProjectUrl>
|
<PackageProjectUrl>https://github.com/MajMcCloud/TelegramBotFramework</PackageProjectUrl>
|
||||||
<RepositoryUrl>https://github.com/MajMcCloud/TelegramBotFramework</RepositoryUrl>
|
<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.0 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>
|
<Configurations>Debug;Release;</Configurations>
|
||||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||||
<RunAnalyzersDuringBuild>false</RunAnalyzersDuringBuild>
|
<RunAnalyzersDuringBuild>false</RunAnalyzersDuringBuild>
|
||||||
<RunAnalyzersDuringLiveAnalysis>false</RunAnalyzersDuringLiveAnalysis>
|
<RunAnalyzersDuringLiveAnalysis>false</RunAnalyzersDuringLiveAnalysis>
|
||||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||||
|
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
||||||
|
<IncludeSymbols>true</IncludeSymbols>
|
||||||
|
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
<DebugSymbols>true</DebugSymbols>
|
<DebugSymbols>true</DebugSymbols>
|
||||||
<DebugType>full</DebugType>
|
<DebugType>full</DebugType>
|
||||||
@@ -56,6 +64,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Remove="cpack.ps1" />
|
<None Remove="cpack.ps1" />
|
||||||
|
<None Remove="cpack_bak.ps1" />
|
||||||
<None Remove="cpush.ps1" />
|
<None Remove="cpush.ps1" />
|
||||||
<None Remove="nuget.exe" />
|
<None Remove="nuget.exe" />
|
||||||
<None Remove="TelegramBotBase.1.5.0.nupkg" />
|
<None Remove="TelegramBotBase.1.5.0.nupkg" />
|
||||||
@@ -64,6 +73,11 @@
|
|||||||
<None Remove="TelegramBotBase.1.5.1.zip" />
|
<None Remove="TelegramBotBase.1.5.1.zip" />
|
||||||
<None Remove="TelegramBotBase.1.5.2.nupkg" />
|
<None Remove="TelegramBotBase.1.5.2.nupkg" />
|
||||||
<None Remove="TelegramBotBase.1.5.2.zip" />
|
<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" />
|
<None Remove="TelegramBotBase.nuspec" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,65 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace TelegramBotBase.Tools
|
||||||
|
{
|
||||||
|
public static class Console
|
||||||
|
{
|
||||||
|
[DllImport("Kernel32")]
|
||||||
|
private static extern bool SetConsoleCtrlHandler(EventHandler handler, bool add);
|
||||||
|
|
||||||
|
private delegate bool EventHandler(CtrlType sig);
|
||||||
|
static EventHandler _handler;
|
||||||
|
|
||||||
|
static List<Action> Actions = new List<Action>();
|
||||||
|
|
||||||
|
enum CtrlType
|
||||||
|
{
|
||||||
|
CTRL_C_EVENT = 0,
|
||||||
|
CTRL_BREAK_EVENT = 1,
|
||||||
|
CTRL_CLOSE_EVENT = 2,
|
||||||
|
CTRL_LOGOFF_EVENT = 5,
|
||||||
|
CTRL_SHUTDOWN_EVENT = 6
|
||||||
|
}
|
||||||
|
|
||||||
|
static Console()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SetHandler(Action action)
|
||||||
|
{
|
||||||
|
Actions.Add(action);
|
||||||
|
|
||||||
|
if (_handler != null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_handler += new EventHandler(Handler);
|
||||||
|
SetConsoleCtrlHandler(_handler, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool Handler(CtrlType sig)
|
||||||
|
{
|
||||||
|
switch (sig)
|
||||||
|
{
|
||||||
|
case CtrlType.CTRL_C_EVENT:
|
||||||
|
case CtrlType.CTRL_LOGOFF_EVENT:
|
||||||
|
case CtrlType.CTRL_SHUTDOWN_EVENT:
|
||||||
|
case CtrlType.CTRL_CLOSE_EVENT:
|
||||||
|
|
||||||
|
foreach (var a in Actions)
|
||||||
|
{
|
||||||
|
a();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Telegram.Bot.Types;
|
||||||
|
using TelegramBotBase;
|
||||||
|
using TelegramBotBase.Form;
|
||||||
|
using TelegramBotBaseTest.Tests;
|
||||||
|
|
||||||
|
namespace TelegramBotBaseTest
|
||||||
|
{
|
||||||
|
class Program
|
||||||
|
{
|
||||||
|
static void Main(string[] args)
|
||||||
|
{
|
||||||
|
|
||||||
|
BotBase<Start> bb = new BotBase<Start>(APIKey);
|
||||||
|
|
||||||
|
bb.BotCommands.Add(new BotCommand() { Command = "start", Description = "Starts the bot" });
|
||||||
|
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." });
|
||||||
|
|
||||||
|
bb.BotCommand += async (s, en) =>
|
||||||
|
{
|
||||||
|
switch (en.Command)
|
||||||
|
{
|
||||||
|
case "/start":
|
||||||
|
|
||||||
|
var start = new Menu();
|
||||||
|
|
||||||
|
await en.Device.ActiveForm.NavigateTo(start);
|
||||||
|
|
||||||
|
break;
|
||||||
|
case "/form1":
|
||||||
|
|
||||||
|
var form1 = new TestForm();
|
||||||
|
|
||||||
|
await en.Device.ActiveForm.NavigateTo(form1);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "/form2":
|
||||||
|
|
||||||
|
var form2 = new TestForm2();
|
||||||
|
|
||||||
|
await en.Device.ActiveForm.NavigateTo(form2);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "/params":
|
||||||
|
|
||||||
|
String m = en.Parameters.DefaultIfEmpty("").Aggregate((a, b) => a + " and " + b);
|
||||||
|
|
||||||
|
await en.Device.Send("Your parameters are: " + m, replyTo: en.Device.LastMessageId);
|
||||||
|
|
||||||
|
en.Handled = true;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
//Update Bot commands to botfather
|
||||||
|
bb.UploadBotCommands().Wait();
|
||||||
|
|
||||||
|
bb.SetSetting(TelegramBotBase.Enums.eSettings.LogAllMessages, true);
|
||||||
|
|
||||||
|
bb.Message += (s,en) =>
|
||||||
|
{
|
||||||
|
Console.WriteLine(en.DeviceId + " " + en.Message.MessageText + " " + (en.Message.RawData ?? ""));
|
||||||
|
};
|
||||||
|
|
||||||
|
bb.Start();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Console.WriteLine("Telegram Bot started...");
|
||||||
|
|
||||||
|
Console.WriteLine("Press q to quit application.");
|
||||||
|
|
||||||
|
|
||||||
|
Console.ReadLine();
|
||||||
|
|
||||||
|
bb.Stop();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -44,7 +44,7 @@ namespace TelegramBotBaseTest.Tests.Controls
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void Bg_ButtonClicked(object sender, ButtonClickedEventArgs e)
|
private async Task Bg_ButtonClicked(object sender, ButtonClickedEventArgs e)
|
||||||
{
|
{
|
||||||
if (e.Button == null)
|
if (e.Button == null)
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -0,0 +1,73 @@
|
|||||||
|
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.Form;
|
||||||
|
|
||||||
|
namespace TelegramBotBaseTest.Tests.Controls
|
||||||
|
{
|
||||||
|
public class ButtonGridPagingForm : AutoCleanForm
|
||||||
|
{
|
||||||
|
|
||||||
|
ButtonGrid m_Buttons = null;
|
||||||
|
|
||||||
|
public ButtonGridPagingForm()
|
||||||
|
{
|
||||||
|
this.DeleteMode = TelegramBotBase.Enums.eDeleteMode.OnLeavingForm;
|
||||||
|
|
||||||
|
this.Init += ButtonGridForm_Init;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ButtonGridForm_Init(object sender, InitEventArgs e)
|
||||||
|
{
|
||||||
|
m_Buttons = new ButtonGrid();
|
||||||
|
|
||||||
|
m_Buttons.KeyboardType = TelegramBotBase.Enums.eKeyboardType.ReplyKeyboard;
|
||||||
|
|
||||||
|
m_Buttons.EnablePaging = true;
|
||||||
|
m_Buttons.EnableSearch = 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 ButtonBase(c.EnglishName, c.EnglishName));
|
||||||
|
}
|
||||||
|
|
||||||
|
m_Buttons.ButtonsForm = bf;
|
||||||
|
|
||||||
|
m_Buttons.ButtonClicked += Bg_ButtonClicked;
|
||||||
|
|
||||||
|
this.AddControl(m_Buttons);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task Bg_ButtonClicked(object sender, ButtonClickedEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.Button == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (e.Button.Value == "back")
|
||||||
|
{
|
||||||
|
var start = new Menu();
|
||||||
|
await this.NavigateTo(start);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
await this.Device.Send($"Button clicked with Text: {e.Button.Text} and Value {e.Button.Value}");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -146,6 +146,16 @@ namespace TelegramBotBaseTest.Tests
|
|||||||
|
|
||||||
await this.NavigateTo(bg);
|
await this.NavigateTo(bg);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "buttongridfilter":
|
||||||
|
|
||||||
|
message.Handled = true;
|
||||||
|
|
||||||
|
var bg2 = new Controls.ButtonGridPagingForm();
|
||||||
|
|
||||||
|
await this.NavigateTo(bg2);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,6 +185,8 @@ namespace TelegramBotBaseTest.Tests
|
|||||||
|
|
||||||
btn.AddButtonRow(new ButtonBase("#12 ButtonGrid", new CallbackData("a", "buttongrid").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()));
|
||||||
|
|
||||||
await this.Device.Send("Choose your test:", btn);
|
await this.Device.Send("Choose your test:", btn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Examples", "Examples", "{BF
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SystemCommandsBot", "Examples\SystemCommandsBot\SystemCommandsBot.csproj", "{FC484952-3060-4F87-9809-4CD66D6961C0}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SystemCommandsBot", "Examples\SystemCommandsBot\SystemCommandsBot.csproj", "{FC484952-3060-4F87-9809-4CD66D6961C0}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JoinHiderBot", "Examples\JoinHiderBot\JoinHiderBot.csproj", "{E804B9E5-7ACC-49D3-9253-806766C1D9A5}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@@ -34,12 +36,17 @@ Global
|
|||||||
{FC484952-3060-4F87-9809-4CD66D6961C0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{FC484952-3060-4F87-9809-4CD66D6961C0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{FC484952-3060-4F87-9809-4CD66D6961C0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{FC484952-3060-4F87-9809-4CD66D6961C0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{FC484952-3060-4F87-9809-4CD66D6961C0}.Release|Any CPU.Build.0 = Release|Any CPU
|
{FC484952-3060-4F87-9809-4CD66D6961C0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{E804B9E5-7ACC-49D3-9253-806766C1D9A5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{E804B9E5-7ACC-49D3-9253-806766C1D9A5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{E804B9E5-7ACC-49D3-9253-806766C1D9A5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{E804B9E5-7ACC-49D3-9253-806766C1D9A5}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(NestedProjects) = preSolution
|
GlobalSection(NestedProjects) = preSolution
|
||||||
{FC484952-3060-4F87-9809-4CD66D6961C0} = {BFA71E3F-31C0-4FC1-A320-4DCF704768C5}
|
{FC484952-3060-4F87-9809-4CD66D6961C0} = {BFA71E3F-31C0-4FC1-A320-4DCF704768C5}
|
||||||
|
{E804B9E5-7ACC-49D3-9253-806766C1D9A5} = {BFA71E3F-31C0-4FC1-A320-4DCF704768C5}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
SolutionGuid = {59CB40E1-9FA7-4867-A56F-4F418286F057}
|
SolutionGuid = {59CB40E1-9FA7-4867-A56F-4F418286F057}
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 1.0 MiB |
Reference in New Issue
Block a user