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 | ||
|
|
eb61d40a38 | ||
|
|
2ed030b2fb | ||
|
|
fd6f6fef34 | ||
|
|
54176f9136 | ||
|
|
f80fda8ff9 | ||
|
|
8b66842d34 | ||
|
|
0cdb8c3a1a | ||
|
|
8b9929198a | ||
|
|
7a3e4721bd | ||
|
|
f914920919 | ||
|
|
0435c68281 | ||
|
|
5a1e050aec | ||
|
|
6a62d73fe0 | ||
|
|
519a6fe41c | ||
|
|
201dfd10dd | ||
|
|
78a412c630 | ||
|
|
7a7014cec3 | ||
|
|
64311d0cd9 | ||
|
|
762fb27294 | ||
|
|
164194ac66 | ||
|
|
321bd7c0ff | ||
|
|
37ef30ebee | ||
|
|
9b1461ad78 | ||
|
|
38fa0a4e99 | ||
|
|
fba922049f | ||
|
|
d5a9a5f7a4 | ||
|
|
5126074419 | ||
|
|
aa38492bde | ||
|
|
9c68914e9d | ||
|
|
3fe2779b1e | ||
|
|
8e6de4a0e1 | ||
|
|
382ae2de2d | ||
|
|
77fd3393de | ||
|
|
0f1da77aca | ||
|
|
1561c1dd08 | ||
|
|
5b38f2e1e2 | ||
|
|
2989456fe5 | ||
|
|
7e4174a3be | ||
|
|
73f81cc8a2 | ||
|
|
2071ba2eeb | ||
|
|
a08ba8f512 | ||
|
|
649b94dafe |
@@ -1,17 +0,0 @@
|
||||
name: .NET Core
|
||||
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Setup .NET Core
|
||||
uses: actions/setup-dotnet@v1
|
||||
with:
|
||||
dotnet-version: 2.2.108
|
||||
- name: Build with dotnet
|
||||
run: dotnet build --configuration Release
|
||||
+12
@@ -240,3 +240,15 @@ ModelManifest.xml
|
||||
|
||||
# FAKE - F# Make
|
||||
.fake/
|
||||
MigrationBackup
|
||||
TelegramBotBase/nuget.exe
|
||||
Material
|
||||
TelegramBotBase/cp.ps1
|
||||
TelegramBotBase/TelegramBotBase.nuspec
|
||||
Program.cs
|
||||
TelegramBotBase/Archive
|
||||
/TelegramBotBase/TelegramBotBase.1.5.0.zip
|
||||
/TelegramBotBase/TelegramBotBase.1.5.1.zip
|
||||
/TelegramBotBase/TelegramBotBase.1.5.2.zip
|
||||
/TelegramBotBase/cpush.ps1
|
||||
/TelegramBotBase/cpack.ps1
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||
<PackageReference Include="TelegramBotBase" Version="3.1.1" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,30 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace SystemCommandsBot.commands
|
||||
{
|
||||
public class Commando
|
||||
{
|
||||
public int ID { get; set; }
|
||||
|
||||
public String Title { get; set; }
|
||||
|
||||
public String ShellCmd { get; set; }
|
||||
|
||||
public bool Enabled { get; set; } = true;
|
||||
|
||||
public String Action { get; set; }
|
||||
|
||||
public bool UseShell { get; set; } = true;
|
||||
|
||||
|
||||
public int? MaxInstances { get; set; }
|
||||
|
||||
public String ProcName
|
||||
{
|
||||
get;set;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace SystemCommandsBot.config
|
||||
{
|
||||
public class Config
|
||||
{
|
||||
public String Password { get; set; }
|
||||
|
||||
public String ApiKey { get; set; }
|
||||
|
||||
public List<commands.Commando> Commandos { get; set; }
|
||||
|
||||
|
||||
public Config()
|
||||
{
|
||||
this.Commandos = new List<commands.Commando>();
|
||||
}
|
||||
|
||||
public void loadDefaultValues()
|
||||
{
|
||||
this.ApiKey = "";
|
||||
this.Commandos.Add(new commands.Commando() { ID = 0, Enabled = true, Title = "Test Befehl", ShellCmd = "explorer.exe", Action = "start", MaxInstances = 2 });
|
||||
}
|
||||
|
||||
|
||||
public static Config load()
|
||||
{
|
||||
try
|
||||
{
|
||||
return load(AppContext.BaseDirectory + "config\\default.cfg");
|
||||
|
||||
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex.Message);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public static Config load(String path)
|
||||
{
|
||||
try
|
||||
{
|
||||
var cfg = Newtonsoft.Json.JsonConvert.DeserializeObject<Config>(File.ReadAllText(path)) as Config;
|
||||
return cfg;
|
||||
}
|
||||
catch (DirectoryNotFoundException ex)
|
||||
{
|
||||
DirectoryInfo di = new DirectoryInfo(path);
|
||||
|
||||
if (!Directory.Exists(di.Parent.FullName))
|
||||
{
|
||||
Directory.CreateDirectory(di.Parent.FullName);
|
||||
}
|
||||
|
||||
var cfg = new Config();
|
||||
cfg.loadDefaultValues();
|
||||
cfg.save(path);
|
||||
return cfg;
|
||||
}
|
||||
catch (FileNotFoundException ex)
|
||||
{
|
||||
var cfg = new Config();
|
||||
cfg.loadDefaultValues();
|
||||
cfg.save(path);
|
||||
return cfg;
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex.Message);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void save(String path)
|
||||
{
|
||||
try
|
||||
{
|
||||
File.WriteAllText(path, Newtonsoft.Json.JsonConvert.SerializeObject(this));
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using TelegramBotBase.Base;
|
||||
using TelegramBotBase.Form;
|
||||
|
||||
namespace SystemCommandsBot.forms
|
||||
{
|
||||
public class CmdForm : TelegramBotBase.Form.AutoCleanForm
|
||||
{
|
||||
public DateTime ExpiresAt { get; set; }
|
||||
|
||||
public int? MessageId { get; set; }
|
||||
|
||||
public override async Task Load(MessageResult message)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override async Task Action(MessageResult message)
|
||||
{
|
||||
var btn = message.RawData;
|
||||
|
||||
int id = -1;
|
||||
|
||||
if (!int.TryParse(btn, out id))
|
||||
{
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var cmd = Program.BotConfig.Commandos.Where(a => a.Enabled && a.ID == id).FirstOrDefault();
|
||||
if (cmd == null)
|
||||
{
|
||||
await this.Device.Send("Cmd nicht verfügbar.");
|
||||
return;
|
||||
}
|
||||
|
||||
message.Handled = true;
|
||||
|
||||
switch (cmd.Action)
|
||||
{
|
||||
case "start":
|
||||
|
||||
FileInfo fi = new FileInfo(cmd.ShellCmd);
|
||||
|
||||
if (cmd.MaxInstances != null && cmd.MaxInstances >= 0)
|
||||
{
|
||||
|
||||
if (Process.GetProcessesByName(cmd.ProcName).Count() >= cmd.MaxInstances)
|
||||
{
|
||||
await this.Device.Send("Anwendung läuft bereits.");
|
||||
await message.ConfirmAction("Anwendung läuft bereits.");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ProcessStartInfo psi = new ProcessStartInfo();
|
||||
psi.FileName = cmd.ShellCmd;
|
||||
psi.WorkingDirectory = fi.DirectoryName;
|
||||
psi.UseShellExecute = cmd.UseShell;
|
||||
|
||||
Process.Start(psi);
|
||||
|
||||
await this.Device.Send(fi.Name + " wurde gestarted.");
|
||||
|
||||
await message.ConfirmAction(fi.Name + " wurde gestarted.");
|
||||
|
||||
break;
|
||||
|
||||
case "kill":
|
||||
|
||||
FileInfo fi2 = new FileInfo(cmd.ShellCmd);
|
||||
|
||||
String pros = fi2.Name.Replace(fi2.Extension, "");
|
||||
|
||||
var proc = Process.GetProcessesByName(pros).ToList();
|
||||
|
||||
foreach (var p in proc)
|
||||
{
|
||||
try
|
||||
{
|
||||
p.Kill();
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
await this.Device.Send(fi2.Name + " wurde beendet.");
|
||||
|
||||
await message.ConfirmAction(fi2.Name + " wurde beendet.");
|
||||
|
||||
break;
|
||||
|
||||
case "restart":
|
||||
|
||||
FileInfo fi3 = new FileInfo(cmd.ShellCmd);
|
||||
|
||||
String pros2 = fi3.Name.Replace(fi3.Extension, "");
|
||||
|
||||
var proc2 = Process.GetProcessesByName(pros2).ToList();
|
||||
|
||||
foreach (var p in proc2)
|
||||
{
|
||||
try
|
||||
{
|
||||
p.Kill();
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
FileInfo fi4 = new FileInfo(cmd.ShellCmd);
|
||||
|
||||
ProcessStartInfo psi2 = new ProcessStartInfo();
|
||||
psi2.FileName = cmd.ShellCmd;
|
||||
psi2.WorkingDirectory = fi4.DirectoryName;
|
||||
psi2.FileName = cmd.ShellCmd;
|
||||
psi2.UseShellExecute = cmd.UseShell;
|
||||
|
||||
Process.Start(psi2);
|
||||
|
||||
await this.Device.Send(fi3.Name + " wurde neugestarted.");
|
||||
await message.ConfirmAction(fi3.Name + " wurde neugestarted.");
|
||||
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
await message.ConfirmAction();
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
public override async Task Render(MessageResult message)
|
||||
{
|
||||
if (this.MessageId == null)
|
||||
{
|
||||
var buttons = Program.BotConfig.Commandos.Where(a => a.Enabled).Select(a => new ButtonBase(a.Title, a.ID.ToString()));
|
||||
|
||||
ButtonForm bf = new ButtonForm();
|
||||
bf.AddSplitted(buttons, 1);
|
||||
await this.Device.Send("Deine Optionen", bf);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using TelegramBotBase.Base;
|
||||
|
||||
namespace SystemCommandsBot.forms
|
||||
{
|
||||
public class StartForm : TelegramBotBase.Form.FormBase
|
||||
{
|
||||
public String Password { get; set; }
|
||||
|
||||
public override async Task Load(MessageResult message)
|
||||
{
|
||||
var inp = message.MessageText;
|
||||
if (Program.BotConfig.Password == inp)
|
||||
{
|
||||
this.Password = inp;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
public override async Task Render(MessageResult message)
|
||||
{
|
||||
if (this.Password == null || this.Password.Trim() == "")
|
||||
{
|
||||
await this.Device.Send("Bitte gib dein Passwort an.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
var cmd = new forms.CmdForm();
|
||||
cmd.ExpiresAt = DateTime.Now.AddDays(14);
|
||||
|
||||
await this.NavigateTo(cmd);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -71,11 +71,36 @@ Thanks !
|
||||
|
||||
* [ButtonGrid](#button-grid)
|
||||
|
||||
* [Paging and Searching](#paging--searching)
|
||||
|
||||
- [Groups](#groups)
|
||||
* [SplitterForm](#splitter-form)
|
||||
|
||||
* [GroupForm](#group-form)
|
||||
|
||||
- [State Machine and Session Serialization (v3.0.0)](#statemachine-and-sessions)
|
||||
|
||||
* [StateMachines](#statemachines)
|
||||
|
||||
* [SimpleJSONStateMachine](#simplejsonstatemachine)
|
||||
|
||||
* [JSONStateMachine](#jsonstatemachine)
|
||||
|
||||
* [XMLStateMachine](#xmlstatemachine)
|
||||
|
||||
* [Interfaces](#interfaces)
|
||||
|
||||
* [IStateMachine](#istatemachine)
|
||||
|
||||
* [IStateForm](#istateform)
|
||||
|
||||
* [Attributes](#attributes)
|
||||
|
||||
* [SaveState](#savestate)
|
||||
|
||||
* [IgnoreState](#ignorestate)
|
||||
|
||||
- [Examples](#examples)
|
||||
|
||||
---
|
||||
|
||||
@@ -95,7 +120,7 @@ It gives you features which will look/feel like WinForms or have a good way to c
|
||||
## How to start:
|
||||
|
||||
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.
|
||||
It needs to be a subclass of "FormBase" you will find in Namespace TelegramBotBase.Base
|
||||
|
||||
@@ -106,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}");
|
||||
|
||||
//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
|
||||
bb.Start();
|
||||
@@ -131,17 +159,10 @@ public class StartForm : FormBase
|
||||
|
||||
}
|
||||
|
||||
//Gets invoked if the form gets opened (with Form.NavigateTo(NewForm))
|
||||
public override async Task Opened()
|
||||
{
|
||||
//Opened() got replaced with event handler
|
||||
|
||||
}
|
||||
//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
|
||||
public override async Task Load(MessageResult message)
|
||||
@@ -149,6 +170,12 @@ public class StartForm : FormBase
|
||||
await this.Device.Send("Hello world!");
|
||||
}
|
||||
|
||||
//Gets invoked on edited messages
|
||||
public override async Task Edited(MessageResult message)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//Gets invoked on Button clicks
|
||||
public override async Task Action(MessageResult message)
|
||||
{
|
||||
@@ -192,10 +219,10 @@ await this.NavigateTo(tf);
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
Below we have 4 options.
|
||||
@@ -213,13 +240,12 @@ Below we have 4 options.
|
||||
```
|
||||
BotBase<Start> bb = new BotBase<Start>("{YOUR API KEY}");
|
||||
|
||||
bb.SystemCalls.Add("/start");
|
||||
bb.SystemCalls.Add("/form1");
|
||||
bb.SystemCalls.Add("/form2");
|
||||
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.SystemCalls.Add("/params");
|
||||
|
||||
bb.SystemCall += async (s, en) =>
|
||||
bb.BotCommand += async (s, en) =>
|
||||
{
|
||||
switch (en.Command)
|
||||
{
|
||||
@@ -250,6 +276,9 @@ bb.SystemCall += async (s, en) =>
|
||||
|
||||
};
|
||||
|
||||
//Update Bot commands to botfather
|
||||
bb.UploadBotCommands().Wait();
|
||||
|
||||
bb.Start();
|
||||
|
||||
```
|
||||
@@ -266,11 +295,13 @@ public class SimpleForm : AutoCleanForm
|
||||
{
|
||||
public SimpleForm()
|
||||
{
|
||||
this.DeleteSide = eSide.Both;
|
||||
this.DeleteMode = eDeleteMode.OnLeavingForm;
|
||||
this.DeleteSide = TelegramBotBase.Enums.eDeleteSide.Both;
|
||||
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");
|
||||
}
|
||||
@@ -651,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.
|
||||
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.
|
||||
|
||||
|
||||
@@ -770,6 +801,8 @@ await this.NavigateTo(cd);
|
||||
### Button Grid
|
||||
<img src="images/buttongrid.gif?raw=true" />
|
||||
|
||||
#### Paging & Searching
|
||||
<img src="images/buttongrid_pagingfilter.gif?raw=true" />
|
||||
|
||||
## Groups
|
||||
|
||||
@@ -887,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.
|
||||
|
||||
|
||||
---
|
||||
|
||||
+5
-5
@@ -6,12 +6,12 @@ using System.Threading.Tasks;
|
||||
using Telegram.Bot.Types;
|
||||
using TelegramBotBase.Sessions;
|
||||
|
||||
namespace TelegramBotBase.Base
|
||||
namespace TelegramBotBase.Args
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for given system call results
|
||||
/// Base class for given bot command results
|
||||
/// </summary>
|
||||
public class SystemCallEventArgs : EventArgs
|
||||
public class BotCommandEventArgs : EventArgs
|
||||
{
|
||||
public String Command { get; set; }
|
||||
|
||||
@@ -26,13 +26,13 @@ namespace TelegramBotBase.Base
|
||||
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.Parameters = Parameters;
|
||||
+1
-1
@@ -5,7 +5,7 @@ using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using TelegramBotBase.Form;
|
||||
|
||||
namespace TelegramBotBase.Base
|
||||
namespace TelegramBotBase.Args
|
||||
{
|
||||
/// <summary>
|
||||
/// Button get clicked event
|
||||
+2
-1
@@ -2,8 +2,9 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Telegram.Bot.Types.Enums;
|
||||
using TelegramBotBase.Base;
|
||||
|
||||
namespace TelegramBotBase.Base
|
||||
namespace TelegramBotBase.Args
|
||||
{
|
||||
public class GroupChangedEventArgs : EventArgs
|
||||
{
|
||||
@@ -4,7 +4,7 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace TelegramBotBase.Base
|
||||
namespace TelegramBotBase.Args
|
||||
{
|
||||
public class InitEventArgs : EventArgs
|
||||
{
|
||||
@@ -0,0 +1,58 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace TelegramBotBase.Args
|
||||
{
|
||||
public class LoadStateEventArgs
|
||||
{
|
||||
public Dictionary<String,object> Values { get; set; }
|
||||
|
||||
public LoadStateEventArgs()
|
||||
{
|
||||
Values = new Dictionary<string, object>();
|
||||
}
|
||||
|
||||
public List<String> Keys
|
||||
{
|
||||
get
|
||||
{
|
||||
return Values.Keys.ToList();
|
||||
}
|
||||
}
|
||||
|
||||
public String Get(String key)
|
||||
{
|
||||
return Values[key].ToString();
|
||||
}
|
||||
|
||||
public int GetInt(String key)
|
||||
{
|
||||
int i = 0;
|
||||
if (int.TryParse(Values[key].ToString(), out i))
|
||||
return i;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public double GetDouble(String key)
|
||||
{
|
||||
double d = 0;
|
||||
if (double.TryParse(Values[key].ToString(), out d))
|
||||
return d;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public bool GetBool(String key)
|
||||
{
|
||||
bool b = false;
|
||||
if (bool.TryParse(Values[key].ToString(), out b))
|
||||
return b;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
+2
-1
@@ -4,8 +4,9 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using Telegram.Bot.Types;
|
||||
using Telegram.Bot.Types.Enums;
|
||||
using TelegramBotBase.Base;
|
||||
|
||||
namespace TelegramBotBase.Base
|
||||
namespace TelegramBotBase.Args
|
||||
{
|
||||
public class MemberChangeEventArgs : EventArgs
|
||||
{
|
||||
+2
-2
@@ -7,7 +7,7 @@ using TelegramBotBase.Sessions;
|
||||
|
||||
namespace TelegramBotBase.Base
|
||||
{
|
||||
public class MessageIncomeResult : EventArgs
|
||||
public class MessageIncomeEventArgs : EventArgs
|
||||
{
|
||||
|
||||
public long DeviceId { get; set; }
|
||||
@@ -16,7 +16,7 @@ namespace TelegramBotBase.Base
|
||||
|
||||
public MessageResult Message { get; set; }
|
||||
|
||||
public MessageIncomeResult(long DeviceId, DeviceSession Device, MessageResult message)
|
||||
public MessageIncomeEventArgs(long DeviceId, DeviceSession Device, MessageResult message)
|
||||
{
|
||||
this.DeviceId = DeviceId;
|
||||
this.Device = Device;
|
||||
+1
-1
@@ -5,7 +5,7 @@ using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Telegram.Bot.Types;
|
||||
|
||||
namespace TelegramBotBase.Base
|
||||
namespace TelegramBotBase.Args
|
||||
{
|
||||
public class MessageReceivedEventArgs
|
||||
{
|
||||
+1
-1
@@ -5,7 +5,7 @@ using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Telegram.Bot.Types;
|
||||
|
||||
namespace TelegramBotBase.Base
|
||||
namespace TelegramBotBase.Args
|
||||
{
|
||||
public class MessageSentEventArgs
|
||||
{
|
||||
@@ -0,0 +1,37 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace TelegramBotBase.Args
|
||||
{
|
||||
public class SaveStateEventArgs
|
||||
{
|
||||
public Dictionary<String, object> Values { get; set; }
|
||||
|
||||
public SaveStateEventArgs()
|
||||
{
|
||||
Values = new Dictionary<string, object>();
|
||||
}
|
||||
|
||||
public void Set(String key, String value)
|
||||
{
|
||||
Values[key] = value;
|
||||
}
|
||||
|
||||
public void SetInt(String key, int value)
|
||||
{
|
||||
Values[key] = value;
|
||||
}
|
||||
|
||||
public void SetBool(String key, bool value)
|
||||
{
|
||||
Values[key] = value;
|
||||
}
|
||||
|
||||
public void SetDouble(String key, double value)
|
||||
{
|
||||
Values[key] = value;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using TelegramBotBase.Base;
|
||||
using TelegramBotBase.Sessions;
|
||||
|
||||
namespace TelegramBotBase.Args
|
||||
{
|
||||
public class SaveStatesEventArgs
|
||||
{
|
||||
public StateContainer States { get; set; }
|
||||
|
||||
|
||||
public SaveStatesEventArgs(StateContainer states)
|
||||
{
|
||||
this.States = states;
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -7,13 +7,13 @@ using TelegramBotBase.Sessions;
|
||||
|
||||
namespace TelegramBotBase.Base
|
||||
{
|
||||
public class SessionBeginResult : EventArgs
|
||||
public class SessionBeginEventArgs : EventArgs
|
||||
{
|
||||
public long DeviceId { get; set; }
|
||||
|
||||
public DeviceSession Device { get; set; }
|
||||
|
||||
public SessionBeginResult(long DeviceId, DeviceSession Device)
|
||||
public SessionBeginEventArgs(long DeviceId, DeviceSession Device)
|
||||
{
|
||||
this.DeviceId = DeviceId;
|
||||
this.Device = Device;
|
||||
+1
-1
@@ -5,7 +5,7 @@ using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using TelegramBotBase.Sessions;
|
||||
|
||||
namespace TelegramBotBase.Base
|
||||
namespace TelegramBotBase.Args
|
||||
{
|
||||
public class SystemExceptionEventArgs : EventArgs
|
||||
{
|
||||
+1
-1
@@ -6,7 +6,7 @@ using System.Threading.Tasks;
|
||||
using Telegram.Bot.Types;
|
||||
using TelegramBotBase.Sessions;
|
||||
|
||||
namespace TelegramBotBase.Base
|
||||
namespace TelegramBotBase.Args
|
||||
{
|
||||
public class UnhandledCallEventArgs : EventArgs
|
||||
{
|
||||
@@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace TelegramBotBase.Attributes
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Declares that this class should not be getting serialized
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class IgnoreState : Attribute
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace TelegramBotBase.Attributes
|
||||
{
|
||||
/// <summary>
|
||||
/// Declares that the field or property should be save and recovered an restart.
|
||||
/// </summary>
|
||||
public class SaveState : Attribute
|
||||
{
|
||||
public String Key { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
@@ -51,6 +51,12 @@ namespace TelegramBotBase.Base
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
public virtual async Task Hidden(bool FormClose)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
public virtual async Task Cleanup()
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
@@ -97,7 +98,7 @@ namespace TelegramBotBase.Base
|
||||
this.RawMessageData = message.RawMessageData;
|
||||
this.Message = message.Message;
|
||||
|
||||
|
||||
this.Client = message.Client;
|
||||
}
|
||||
|
||||
public async Task<InputOnlineFile> DownloadDocument()
|
||||
@@ -108,6 +109,15 @@ namespace TelegramBotBase.Base
|
||||
return new InputOnlineFile(encryptedContent, this.Document.FileName);
|
||||
}
|
||||
|
||||
public async Task DownloadDocument(String path)
|
||||
{
|
||||
var file = await this.Client.TelegramClient.GetFileAsync(this.Document.FileId);
|
||||
FileStream fs = new FileStream(path, FileMode.Create);
|
||||
await this.Client.TelegramClient.DownloadFileAsync(file.FilePath, fs);
|
||||
fs.Close();
|
||||
fs.Dispose();
|
||||
}
|
||||
|
||||
public async Task<InputOnlineFile> DownloadVideo()
|
||||
{
|
||||
var encryptedContent = new System.IO.MemoryStream(this.Video.FileSize);
|
||||
@@ -116,6 +126,32 @@ namespace TelegramBotBase.Base
|
||||
return new InputOnlineFile(encryptedContent, "");
|
||||
}
|
||||
|
||||
public async Task DownloadVideo(String path)
|
||||
{
|
||||
var file = await this.Client.TelegramClient.GetFileAsync(this.Video.FileId);
|
||||
FileStream fs = new FileStream(path, FileMode.Create);
|
||||
await this.Client.TelegramClient.DownloadFileAsync(file.FilePath, fs);
|
||||
fs.Close();
|
||||
fs.Dispose();
|
||||
}
|
||||
|
||||
public async Task<InputOnlineFile> DownloadAudio()
|
||||
{
|
||||
var encryptedContent = new System.IO.MemoryStream(this.Audio.FileSize);
|
||||
var file = await this.Client.TelegramClient.GetInfoAndDownloadFileAsync(this.Audio.FileId, encryptedContent);
|
||||
|
||||
return new InputOnlineFile(encryptedContent, "");
|
||||
}
|
||||
|
||||
public async Task DownloadAudio(String path)
|
||||
{
|
||||
var file = await this.Client.TelegramClient.GetFileAsync(this.Audio.FileId);
|
||||
FileStream fs = new FileStream(path, FileMode.Create);
|
||||
await this.Client.TelegramClient.DownloadFileAsync(file.FilePath, fs);
|
||||
fs.Close();
|
||||
fs.Dispose();
|
||||
}
|
||||
|
||||
public async Task<InputOnlineFile> DownloadPhoto(int index)
|
||||
{
|
||||
var photo = this.Photos[index];
|
||||
@@ -125,5 +161,15 @@ namespace TelegramBotBase.Base
|
||||
return new InputOnlineFile(encryptedContent, "");
|
||||
}
|
||||
|
||||
public async Task DownloadPhoto(int index, String path)
|
||||
{
|
||||
var photo = this.Photos[index];
|
||||
var file = await this.Client.TelegramClient.GetFileAsync(photo.FileId);
|
||||
FileStream fs = new FileStream(path, FileMode.Create);
|
||||
await this.Client.TelegramClient.DownloadFileAsync(file.FilePath, fs);
|
||||
fs.Close();
|
||||
fs.Dispose();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using TelegramBotBase.Args;
|
||||
using TelegramBotBase.Base;
|
||||
using TelegramBotBase.Sessions;
|
||||
using static TelegramBotBase.Base.Async;
|
||||
@@ -106,6 +107,8 @@ namespace TelegramBotBase.Form
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public async Task OnClosed(EventArgs e)
|
||||
{
|
||||
if (this.Events[__evClosed] == null)
|
||||
@@ -135,6 +138,16 @@ namespace TelegramBotBase.Form
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get invoked when a modal child from has been closed.
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <returns></returns>
|
||||
public virtual async Task ReturnFromModal(ModalDialog modal)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Pre to form close, cleanup all controls
|
||||
@@ -144,7 +157,7 @@ namespace TelegramBotBase.Form
|
||||
{
|
||||
foreach (var b in this.Controls)
|
||||
{
|
||||
await b.Cleanup();
|
||||
b.Cleanup().Wait();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,6 +203,15 @@ namespace TelegramBotBase.Form
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets invoked, when a messages has been edited.
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <returns></returns>
|
||||
public virtual async Task Edited(MessageResult message)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
@@ -275,7 +297,7 @@ namespace TelegramBotBase.Form
|
||||
/// </summary>
|
||||
/// <param name="newForm"></param>
|
||||
/// <returns></returns>
|
||||
public async Task NavigateTo(FormBase newForm, params object[] args)
|
||||
public virtual async Task NavigateTo(FormBase newForm, params object[] args)
|
||||
{
|
||||
DeviceSession ds = this.Device;
|
||||
if (ds == null)
|
||||
@@ -289,12 +311,21 @@ namespace TelegramBotBase.Form
|
||||
newForm.Client = this.Client;
|
||||
newForm.Device = ds;
|
||||
|
||||
await newForm.OnInit(new InitEventArgs(args));
|
||||
//Notify prior to close
|
||||
foreach (var b in this.Controls)
|
||||
{
|
||||
if (!b.Enabled)
|
||||
continue;
|
||||
|
||||
await this.CloseControls();
|
||||
await b.Hidden(true);
|
||||
}
|
||||
|
||||
this.CloseControls().Wait();
|
||||
|
||||
await this.OnClosed(new EventArgs());
|
||||
|
||||
await newForm.OnInit(new InitEventArgs(args));
|
||||
|
||||
await newForm.OnOpened(new EventArgs());
|
||||
}
|
||||
|
||||
@@ -303,7 +334,7 @@ namespace TelegramBotBase.Form
|
||||
/// </summary>
|
||||
/// <param name="newForm"></param>
|
||||
/// <returns></returns>
|
||||
public async Task OpenModal(ModalDialog newForm, params object[] args)
|
||||
public virtual async Task OpenModal(ModalDialog newForm, params object[] args)
|
||||
{
|
||||
DeviceSession ds = this.Device;
|
||||
if (ds == null)
|
||||
@@ -318,12 +349,21 @@ namespace TelegramBotBase.Form
|
||||
ds.ActiveForm = newForm;
|
||||
newForm.Client = parentForm.Client;
|
||||
newForm.Device = ds;
|
||||
newForm.ParentForm = parentForm;
|
||||
|
||||
newForm.Closed += async (s, en) =>
|
||||
{
|
||||
await CloseModal(newForm, parentForm);
|
||||
};
|
||||
|
||||
foreach (var b in this.Controls)
|
||||
{
|
||||
if (!b.Enabled)
|
||||
continue;
|
||||
|
||||
await b.Hidden(false);
|
||||
}
|
||||
|
||||
await newForm.OnInit(new InitEventArgs(args));
|
||||
|
||||
await newForm.OnOpened(new EventArgs());
|
||||
@@ -370,6 +410,19 @@ namespace TelegramBotBase.Form
|
||||
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>
|
||||
/// Cleanup
|
||||
/// </summary>
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Telegram.Bot.Types;
|
||||
|
||||
namespace TelegramBotBase.Base
|
||||
{
|
||||
@@ -15,6 +16,7 @@ namespace TelegramBotBase.Base
|
||||
public class MessageClient
|
||||
{
|
||||
|
||||
|
||||
public String APIKey { get; set; }
|
||||
|
||||
public Telegram.Bot.TelegramBotClient TelegramClient { get; set; }
|
||||
@@ -23,6 +25,8 @@ namespace TelegramBotBase.Base
|
||||
|
||||
private static object __evOnMessage = new object();
|
||||
|
||||
private static object __evOnMessageEdit = new object();
|
||||
|
||||
private static object __evCallbackQuery = new object();
|
||||
|
||||
|
||||
@@ -84,13 +88,11 @@ namespace TelegramBotBase.Base
|
||||
{
|
||||
this.TelegramClient.Timeout = new TimeSpan(0, 0, 30);
|
||||
|
||||
|
||||
this.TelegramClient.OnMessage += TelegramClient_OnMessage;
|
||||
this.TelegramClient.OnMessageEdited += TelegramClient_OnMessageEdited;
|
||||
this.TelegramClient.OnCallbackQuery += TelegramClient_OnCallbackQuery;
|
||||
|
||||
}
|
||||
|
||||
|
||||
private async void TelegramClient_OnMessage(object sender, Telegram.Bot.Args.MessageEventArgs e)
|
||||
{
|
||||
//Skip empty messages by default
|
||||
@@ -109,6 +111,25 @@ namespace TelegramBotBase.Base
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private async void TelegramClient_OnMessageEdited(object sender, Telegram.Bot.Args.MessageEventArgs e)
|
||||
{
|
||||
//Skip empty messages by default
|
||||
if (e.Message == null)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
var mr = new MessageResult(e);
|
||||
mr.Client = this;
|
||||
OnMessageEdit(mr);
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private async void TelegramClient_OnCallbackQuery(object sender, Telegram.Bot.Args.CallbackQueryEventArgs e)
|
||||
{
|
||||
try
|
||||
@@ -123,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"
|
||||
|
||||
@@ -143,6 +185,23 @@ namespace TelegramBotBase.Base
|
||||
(this.__Events[__evOnMessage] as EventHandler<MessageResult>)?.Invoke(this, result);
|
||||
}
|
||||
|
||||
public event EventHandler<MessageResult> MessageEdit
|
||||
{
|
||||
add
|
||||
{
|
||||
this.__Events.AddHandler(__evOnMessageEdit, value);
|
||||
}
|
||||
remove
|
||||
{
|
||||
this.__Events.RemoveHandler(__evOnMessageEdit, value);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnMessageEdit(MessageResult result)
|
||||
{
|
||||
(this.__Events[__evOnMessageEdit] as EventHandler<MessageResult>)?.Invoke(this, result);
|
||||
}
|
||||
|
||||
public event EventHandler<MessageResult> Action
|
||||
{
|
||||
add
|
||||
|
||||
@@ -74,9 +74,9 @@ namespace TelegramBotBase.Base
|
||||
}
|
||||
|
||||
/// <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>
|
||||
public bool IsSystemCall
|
||||
public bool IsBotCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
@@ -87,11 +87,11 @@ namespace TelegramBotBase.Base
|
||||
/// <summary>
|
||||
/// Returns a List of all parameters which has been sent with the command itself (i.e. /start 123 456 789 => 123,456,789)
|
||||
/// </summary>
|
||||
public List<String> SystemCallParameters
|
||||
public List<String> BotCommandParameters
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!IsSystemCall)
|
||||
if (!IsBotCommand)
|
||||
return new List<string>();
|
||||
|
||||
//Split by empty space and skip first entry (command itself), return as list
|
||||
@@ -100,19 +100,24 @@ namespace TelegramBotBase.Base
|
||||
}
|
||||
|
||||
/// <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>
|
||||
public String SystemCommand
|
||||
public String BotCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!IsSystemCall)
|
||||
if (!IsBotCommand)
|
||||
return null;
|
||||
|
||||
return this.MessageText.Split(' ')[0];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns if this message will be used on the first form or not.
|
||||
/// </summary>
|
||||
public bool IsFirstHandler { get; set; } = true;
|
||||
|
||||
public bool Handled { get; set; } = false;
|
||||
|
||||
public String RawData
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace TelegramBotBase.Base
|
||||
{
|
||||
public partial class StateContainer
|
||||
{
|
||||
public List<StateEntry> States { get; set; }
|
||||
|
||||
public List<long> ChatIds
|
||||
{
|
||||
get
|
||||
{
|
||||
return States.Where(a => a.DeviceId > 0).Select(a => a.DeviceId).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
public List<long> GroupIds
|
||||
{
|
||||
get
|
||||
{
|
||||
return States.Where(a => a.DeviceId < 0).Select(a => a.DeviceId).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
public StateContainer()
|
||||
{
|
||||
this.States = new List<StateEntry>();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Text;
|
||||
|
||||
namespace TelegramBotBase.Base
|
||||
{
|
||||
|
||||
[DebuggerDisplay("Device: {DeviceId}, {FormUri}")]
|
||||
public class StateEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains the DeviceId of the entry.
|
||||
/// </summary>
|
||||
public long DeviceId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Contains the Username (on privat chats) or Group title on groups/channels.
|
||||
/// </summary>
|
||||
public String ChatTitle { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Contains additional values to save.
|
||||
/// </summary>
|
||||
public Dictionary<String, object> Values { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Contains the full qualified namespace of the form to used for reload it via reflection.
|
||||
/// </summary>
|
||||
public String FormUri {get;set;}
|
||||
|
||||
/// <summary>
|
||||
/// Contains the assembly, where to find that form.
|
||||
/// </summary>
|
||||
public String QualifiedName { get; set; }
|
||||
|
||||
public StateEntry()
|
||||
{
|
||||
this.Values = new Dictionary<string, object>();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
+204
-74
@@ -5,8 +5,13 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Telegram.Bot;
|
||||
using Telegram.Bot.Types;
|
||||
using TelegramBotBase.Args;
|
||||
using TelegramBotBase.Attributes;
|
||||
using TelegramBotBase.Base;
|
||||
using TelegramBotBase.Enums;
|
||||
using TelegramBotBase.Form;
|
||||
using TelegramBotBase.Interfaces;
|
||||
using TelegramBotBase.Sessions;
|
||||
|
||||
namespace TelegramBotBase
|
||||
@@ -28,12 +33,15 @@ namespace TelegramBotBase
|
||||
/// <summary>
|
||||
/// List of all running/active sessions
|
||||
/// </summary>
|
||||
public SessionBase Sessions { get; set; }
|
||||
public SessionBase<T> Sessions { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Contains System commands which will be available at everytime and didnt get passed to forms, i.e. /start
|
||||
/// </summary>
|
||||
public List<String> SystemCalls { get; set; }
|
||||
public List<BotCommand> BotCommands { get; set; }
|
||||
|
||||
|
||||
#region "Events"
|
||||
|
||||
private EventHandlerList __Events = new EventHandlerList();
|
||||
|
||||
@@ -43,41 +51,52 @@ namespace TelegramBotBase
|
||||
|
||||
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 __evUnhandledCall = new object();
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Skips all messages during running (good for big delay updates)
|
||||
/// Enable the SessionState (you need to implement on call forms the IStateForm interface)
|
||||
/// </summary>
|
||||
public bool SkipAllMessages { get; set; } = false;
|
||||
public IStateMachine StateMachine { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Loggs all messages and sent them to the event handler
|
||||
/// </summary>
|
||||
public bool LogAllMessages { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// How often could a form navigate to another (within one user action/call/message)
|
||||
/// </summary>
|
||||
private const int NavigationMaximum = 10;
|
||||
public Dictionary<eSettings, uint> SystemSettings { get; private set; }
|
||||
|
||||
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>
|
||||
/// Simple start of your Bot with the APIKey
|
||||
/// </summary>
|
||||
/// <param name="apiKey"></param>
|
||||
public BotBase(String apiKey)
|
||||
public BotBase(String apiKey, bool initClient = true) : this()
|
||||
{
|
||||
this.APIKey = apiKey;
|
||||
|
||||
if (!initClient)
|
||||
return;
|
||||
|
||||
this.Client = new Base.MessageClient(this.APIKey);
|
||||
this.Client.TelegramClient.Timeout = new TimeSpan(0, 1, 0);
|
||||
|
||||
this.SystemCalls = new List<string>();
|
||||
|
||||
this.Sessions = new SessionBase();
|
||||
this.Sessions.Client = this.Client;
|
||||
}
|
||||
|
||||
@@ -86,15 +105,10 @@ namespace TelegramBotBase
|
||||
/// </summary>
|
||||
/// <param name="apiKey"></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.SystemCalls = new List<string>();
|
||||
|
||||
this.Sessions = new SessionBase();
|
||||
this.Sessions.Client = this.Client;
|
||||
}
|
||||
|
||||
@@ -103,15 +117,10 @@ namespace TelegramBotBase
|
||||
/// </summary>
|
||||
/// <param name="apiKey"></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.SystemCalls = new List<string>();
|
||||
|
||||
this.Sessions = new SessionBase();
|
||||
this.Sessions.Client = this.Client;
|
||||
}
|
||||
|
||||
@@ -120,17 +129,12 @@ namespace TelegramBotBase
|
||||
/// </summary>
|
||||
/// <param name="apiKey"></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);
|
||||
|
||||
this.Client = new Base.MessageClient(this.APIKey, url);
|
||||
|
||||
this.SystemCalls = new List<string>();
|
||||
|
||||
this.Sessions = new SessionBase();
|
||||
this.Sessions.Client = this.Client;
|
||||
}
|
||||
|
||||
@@ -140,15 +144,10 @@ namespace TelegramBotBase
|
||||
/// <param name="apiKey"></param>
|
||||
/// <param name="proxyHost">i.e. 127.0.0.1</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.SystemCalls = new List<string>();
|
||||
|
||||
this.Sessions = new SessionBase();
|
||||
this.Sessions.Client = this.Client;
|
||||
}
|
||||
|
||||
@@ -161,12 +160,27 @@ namespace TelegramBotBase
|
||||
return;
|
||||
|
||||
this.Client.Message += Client_Message;
|
||||
this.Client.MessageEdit += Client_MessageEdit;
|
||||
this.Client.Action += Client_Action;
|
||||
|
||||
if (this.StateMachine != null)
|
||||
{
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Stop your Bot
|
||||
/// </summary>
|
||||
@@ -179,6 +193,8 @@ namespace TelegramBotBase
|
||||
this.Client.Action -= Client_Action;
|
||||
|
||||
this.Client.TelegramClient.StopReceiving();
|
||||
|
||||
this.Sessions.SaveSessionStates();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -197,9 +213,9 @@ namespace TelegramBotBase
|
||||
}
|
||||
}
|
||||
|
||||
private 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;
|
||||
|
||||
try
|
||||
@@ -207,14 +223,14 @@ namespace TelegramBotBase
|
||||
DeviceSession ds = this.Sessions.GetSession(e.DeviceId);
|
||||
e.Device = ds;
|
||||
|
||||
if (LogAllMessages)
|
||||
if (this.GetSetting(eSettings.LogAllMessages, false))
|
||||
{
|
||||
OnMessage(new MessageIncomeResult(e.DeviceId, ds, e));
|
||||
OnMessage(new MessageIncomeEventArgs(e.DeviceId, ds, e));
|
||||
}
|
||||
|
||||
ds?.OnMessageReceived(new MessageReceivedEventArgs(e.Message));
|
||||
|
||||
Client_TryMessage(sender, e);
|
||||
await Client_TryMessage(sender, e);
|
||||
}
|
||||
catch (Telegram.Bot.Exceptions.ApiRequestException ex)
|
||||
{
|
||||
@@ -227,7 +243,7 @@ namespace TelegramBotBase
|
||||
}
|
||||
}
|
||||
|
||||
private async void Client_TryMessage(object sender, MessageResult e)
|
||||
private async Task Client_TryMessage(object sender, MessageResult e)
|
||||
{
|
||||
DeviceSession ds = e.Device;
|
||||
if (ds == null)
|
||||
@@ -237,17 +253,17 @@ namespace TelegramBotBase
|
||||
|
||||
ds.LastMessage = e.Message;
|
||||
|
||||
OnSessionBegins(new SessionBeginResult(e.DeviceId, ds));
|
||||
OnSessionBegins(new SessionBeginEventArgs(e.DeviceId, ds));
|
||||
}
|
||||
|
||||
ds.LastAction = DateTime.Now;
|
||||
ds.LastMessage = e.Message;
|
||||
|
||||
//Is this a systemcall ?
|
||||
if (e.IsSystemCall && this.SystemCalls.Contains(e.SystemCommand))
|
||||
//Is this a bot command ?
|
||||
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);
|
||||
await OnSystemCall(sce);
|
||||
var sce = new BotCommandEventArgs(e.BotCommand, e.BotCommandParameters, e.Message, ds.DeviceId, ds);
|
||||
await OnBotCommand(sce);
|
||||
|
||||
if (sce.Handled)
|
||||
return;
|
||||
@@ -286,14 +302,69 @@ namespace TelegramBotBase
|
||||
//Render Event
|
||||
if (!ds.FormSwitched)
|
||||
{
|
||||
|
||||
await activeForm.RenderControls(e);
|
||||
|
||||
await activeForm.Render(e);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if (this.GetSetting(eSettings.SkipAllMessages, false))
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
DeviceSession ds = this.Sessions.GetSession(e.DeviceId);
|
||||
e.Device = ds;
|
||||
|
||||
if (this.GetSetting(eSettings.LogAllMessages, false))
|
||||
{
|
||||
OnMessage(new MessageIncomeEventArgs(e.DeviceId, ds, e));
|
||||
}
|
||||
|
||||
//Call same, to handle received liked edited
|
||||
ds?.OnMessageReceived(new MessageReceivedEventArgs(e.Message));
|
||||
|
||||
await Client_TryMessageEdit(sender, e);
|
||||
}
|
||||
catch (Telegram.Bot.Exceptions.ApiRequestException ex)
|
||||
{
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
DeviceSession ds = this.Sessions.GetSession(e.DeviceId);
|
||||
OnException(new SystemExceptionEventArgs(e.Message.Text, ds?.DeviceId ?? -1, ds, ex));
|
||||
}
|
||||
}
|
||||
|
||||
private async Task Client_TryMessageEdit(object sender, MessageResult e)
|
||||
{
|
||||
DeviceSession ds = e.Device;
|
||||
if (ds == null)
|
||||
{
|
||||
ds = await this.Sessions.StartSession<T>(e.DeviceId);
|
||||
e.Device = ds;
|
||||
}
|
||||
|
||||
ds.LastAction = DateTime.Now;
|
||||
ds.LastMessage = e.Message;
|
||||
|
||||
//Pre Loading Event
|
||||
await ds.ActiveForm.Edited(e);
|
||||
|
||||
//When form has been switched due navigation within the edit method, reopen Client_Message
|
||||
if (ds.FormSwitched)
|
||||
{
|
||||
await Client_TryMessage(sender, e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -304,9 +375,9 @@ namespace TelegramBotBase
|
||||
DeviceSession ds = this.Sessions.GetSession(e.DeviceId);
|
||||
e.Device = ds;
|
||||
|
||||
if (LogAllMessages)
|
||||
if (this.GetSetting(eSettings.LogAllMessages, false))
|
||||
{
|
||||
OnMessage(new MessageIncomeResult(e.DeviceId, ds, e));
|
||||
OnMessage(new MessageIncomeEventArgs(e.DeviceId, ds, e));
|
||||
}
|
||||
|
||||
Client_TryAction(sender, e);
|
||||
@@ -327,7 +398,6 @@ namespace TelegramBotBase
|
||||
e.Device = ds;
|
||||
}
|
||||
|
||||
|
||||
ds.LastAction = DateTime.Now;
|
||||
ds.LastMessage = e.Message;
|
||||
|
||||
@@ -370,11 +440,8 @@ namespace TelegramBotBase
|
||||
|
||||
if (uhc.Handled)
|
||||
{
|
||||
if (ds.FormSwitched)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
e.Handled = true;
|
||||
if (!ds.FormSwitched)
|
||||
{
|
||||
break;
|
||||
}
|
||||
@@ -391,15 +458,75 @@ namespace TelegramBotBase
|
||||
await activeForm.Render(e);
|
||||
}
|
||||
|
||||
} while (ds.FormSwitched && i < NavigationMaximum);
|
||||
e.IsFirstHandler = false;
|
||||
|
||||
} 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>
|
||||
/// Will be called if a session/context gets started
|
||||
/// </summary>
|
||||
|
||||
public event EventHandler<SessionBeginResult> SessionBegins
|
||||
public event EventHandler<SessionBeginEventArgs> SessionBegins
|
||||
{
|
||||
add
|
||||
{
|
||||
@@ -411,16 +538,16 @@ namespace TelegramBotBase
|
||||
}
|
||||
}
|
||||
|
||||
public void OnSessionBegins(SessionBeginResult e)
|
||||
public void OnSessionBegins(SessionBeginEventArgs e)
|
||||
{
|
||||
(this.__Events[__evSessionBegins] as EventHandler<SessionBeginResult>)?.Invoke(this, e);
|
||||
(this.__Events[__evSessionBegins] as EventHandler<SessionBeginEventArgs>)?.Invoke(this, e);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Will be called on incomming message
|
||||
/// </summary>
|
||||
public event EventHandler<MessageIncomeResult> Message
|
||||
public event EventHandler<MessageIncomeEventArgs> Message
|
||||
{
|
||||
add
|
||||
{
|
||||
@@ -432,22 +559,22 @@ namespace TelegramBotBase
|
||||
}
|
||||
}
|
||||
|
||||
public void OnMessage(MessageIncomeResult e)
|
||||
public void OnMessage(MessageIncomeEventArgs e)
|
||||
{
|
||||
(this.__Events[__evMessage] as EventHandler<MessageIncomeResult>)?.Invoke(this, e);
|
||||
(this.__Events[__evMessage] as EventHandler<MessageIncomeEventArgs>)?.Invoke(this, e);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Will be called if a system call gets raised
|
||||
/// Will be called if a bot command gets raised
|
||||
/// </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)
|
||||
await SystemCall(this, e);
|
||||
if (this.BotCommand != null)
|
||||
await BotCommand(this, e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -491,5 +618,8 @@ namespace TelegramBotBase
|
||||
(this.__Events[__evUnhandledCall] as EventHandler<UnhandledCallEventArgs>)?.Invoke(this, e);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,5 +13,13 @@ namespace TelegramBotBase.Constants
|
||||
/// </summary>
|
||||
public const int MaxMessageLength = 4096;
|
||||
|
||||
public const int MaxInlineKeyBoardRows = 13;
|
||||
|
||||
public const int MaxInlineKeyBoardCols = 8;
|
||||
|
||||
public const int MaxReplyKeyboardRows = 25;
|
||||
|
||||
public const int MaxReplyKeyboardCols = 12;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics.SymbolStore;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Telegram.Bot.Types;
|
||||
using Telegram.Bot.Types.Enums;
|
||||
using Telegram.Bot.Types.ReplyMarkups;
|
||||
using TelegramBotBase.Args;
|
||||
using TelegramBotBase.Base;
|
||||
using TelegramBotBase.Enums;
|
||||
using TelegramBotBase.Exceptions;
|
||||
using TelegramBotBase.Form;
|
||||
using static TelegramBotBase.Base.Async;
|
||||
|
||||
namespace TelegramBotBase.Controls
|
||||
{
|
||||
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; } = "";
|
||||
|
||||
private bool RenderNecessary = true;
|
||||
|
||||
@@ -27,6 +34,63 @@ namespace TelegramBotBase.Controls
|
||||
|
||||
public int? MessageId { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Optional. Requests clients to resize the keyboard vertically for optimal fit (e.g., make the keyboard smaller if there are just two rows of buttons). Defaults to false, in which case the custom keyboard is always of the same height as the app's standard keyboard.
|
||||
/// Source: https://core.telegram.org/bots/api#replykeyboardmarkup
|
||||
/// </summary>
|
||||
public bool ResizeKeyboard { get; set; } = false;
|
||||
|
||||
public bool OneTimeKeyboard { get; set; } = false;
|
||||
|
||||
public bool HideKeyboardOnCleanup { get; set; } = true;
|
||||
|
||||
public bool DeletePreviousMessage { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Parsemode of the message.
|
||||
/// </summary>
|
||||
public ParseMode MessageParseMode { get; set; } = ParseMode.Default;
|
||||
|
||||
/// <summary>
|
||||
/// Enables automatic paging of buttons when the amount of rows is exceeding the limits.
|
||||
/// </summary>
|
||||
public bool EnablePaging { get; set; } = false;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Enabled a search function.
|
||||
/// </summary>
|
||||
public bool EnableSearch { get; set; } = false;
|
||||
|
||||
public String SearchQuery { get; set; }
|
||||
|
||||
public eNavigationBarVisibility NavigationBarVisibility { get; set; } = eNavigationBarVisibility.always;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Index of the current page
|
||||
/// </summary>
|
||||
public int CurrentPageIndex { get; set; } = 0;
|
||||
|
||||
public String PreviousPageLabel = Localizations.Default.Language["ButtonGrid_PreviousPage"];
|
||||
|
||||
public String NextPageLabel = Localizations.Default.Language["ButtonGrid_NextPage"];
|
||||
|
||||
public String NoItemsLabel = Localizations.Default.Language["ButtonGrid_NoItems"];
|
||||
|
||||
public String SearchLabel = Localizations.Default.Language["ButtonGrid_SearchFeature"];
|
||||
|
||||
/// <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>
|
||||
/// Defines which type of Button Keyboard should be rendered.
|
||||
/// </summary>
|
||||
@@ -34,12 +98,11 @@ namespace TelegramBotBase.Controls
|
||||
{
|
||||
get
|
||||
{
|
||||
|
||||
return m_eKeyboardType;
|
||||
}
|
||||
set
|
||||
{
|
||||
if(m_eKeyboardType != value)
|
||||
if (m_eKeyboardType != value)
|
||||
{
|
||||
this.RenderNecessary = true;
|
||||
|
||||
@@ -53,8 +116,6 @@ namespace TelegramBotBase.Controls
|
||||
|
||||
private eKeyboardType m_eKeyboardType = eKeyboardType.ReplyKeyboard;
|
||||
|
||||
private bool m_bVisible = true;
|
||||
|
||||
public ButtonGrid()
|
||||
{
|
||||
this.ButtonsForm = new ButtonForm();
|
||||
@@ -62,13 +123,19 @@ namespace TelegramBotBase.Controls
|
||||
|
||||
}
|
||||
|
||||
public ButtonGrid(eKeyboardType type) : this()
|
||||
{
|
||||
m_eKeyboardType = type;
|
||||
}
|
||||
|
||||
|
||||
public ButtonGrid(ButtonForm form)
|
||||
{
|
||||
this.ButtonsForm = form;
|
||||
}
|
||||
|
||||
|
||||
public event EventHandler<ButtonClickedEventArgs> ButtonClicked
|
||||
public event AsyncEventHandler<ButtonClickedEventArgs> ButtonClicked
|
||||
{
|
||||
add
|
||||
{
|
||||
@@ -80,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)
|
||||
@@ -90,13 +161,68 @@ namespace TelegramBotBase.Controls
|
||||
if (this.KeyboardType != eKeyboardType.ReplyKeyboard)
|
||||
return;
|
||||
|
||||
|
||||
var button = ButtonsForm.ToList().FirstOrDefault(a => a.Text == result.MessageText);
|
||||
|
||||
if (button == null)
|
||||
if (!result.IsFirstHandler)
|
||||
return;
|
||||
|
||||
OnButtonClicked(new ButtonClickedEventArgs(button));
|
||||
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 (result.MessageText == null)
|
||||
return;
|
||||
|
||||
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
|
||||
if (this.DeletePreviousMessage)
|
||||
await Device.DeleteMessage(result.MessageId);
|
||||
|
||||
result.Handled = true;
|
||||
|
||||
@@ -107,19 +233,47 @@ namespace TelegramBotBase.Controls
|
||||
if (result.Handled)
|
||||
return;
|
||||
|
||||
await result.ConfirmAction();
|
||||
if (!result.IsFirstHandler)
|
||||
return;
|
||||
|
||||
await result.ConfirmAction(this.ConfirmationText ?? "");
|
||||
|
||||
//Find clicked button depending on Text or Value (depending on markup type)
|
||||
switch (this.KeyboardType)
|
||||
{
|
||||
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)
|
||||
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;
|
||||
|
||||
@@ -128,47 +282,128 @@ namespace TelegramBotBase.Controls
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method checks of the amount of buttons
|
||||
/// </summary>
|
||||
private void CheckGrid()
|
||||
{
|
||||
switch (m_eKeyboardType)
|
||||
{
|
||||
case eKeyboardType.InlineKeyBoard:
|
||||
|
||||
if (ButtonsForm.Rows > Constants.Telegram.MaxInlineKeyBoardRows && !this.EnablePaging)
|
||||
{
|
||||
throw new MaximumRowsReachedException() { Value = ButtonsForm.Rows, Maximum = Constants.Telegram.MaxInlineKeyBoardRows };
|
||||
}
|
||||
|
||||
if (ButtonsForm.Cols > Constants.Telegram.MaxInlineKeyBoardCols)
|
||||
{
|
||||
throw new MaximumColsException() { Value = ButtonsForm.Rows, Maximum = Constants.Telegram.MaxInlineKeyBoardCols };
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case eKeyboardType.ReplyKeyboard:
|
||||
|
||||
if (ButtonsForm.Rows > Constants.Telegram.MaxReplyKeyboardRows && !this.EnablePaging)
|
||||
{
|
||||
throw new MaximumRowsReachedException() { Value = ButtonsForm.Rows, Maximum = Constants.Telegram.MaxReplyKeyboardRows };
|
||||
}
|
||||
|
||||
if (ButtonsForm.Cols > Constants.Telegram.MaxReplyKeyboardCols)
|
||||
{
|
||||
throw new MaximumColsException() { Value = ButtonsForm.Rows, Maximum = Constants.Telegram.MaxReplyKeyboardCols };
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public async override Task Render(MessageResult result)
|
||||
{
|
||||
if (!this.RenderNecessary)
|
||||
return;
|
||||
|
||||
//Check for rows and column limits
|
||||
CheckGrid();
|
||||
|
||||
this.RenderNecessary = false;
|
||||
|
||||
Message m = null;
|
||||
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)
|
||||
{
|
||||
//Reply Keyboard could only be updated with a new keyboard.
|
||||
case eKeyboardType.ReplyKeyboard:
|
||||
if (this.ButtonsForm.Count == 0)
|
||||
|
||||
if (this.MessageId != null)
|
||||
{
|
||||
await this.Device.Send("", new ReplyKeyboardRemove());
|
||||
if (form.Count == 0)
|
||||
{
|
||||
await this.Device.HideReplyKeyboard();
|
||||
this.MessageId = null;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
m = await this.Device.Send(this.Title, (ReplyKeyboardMarkup)this.ButtonsForm, disableNotification: true);
|
||||
|
||||
if (this.DeletePreviousMessage)
|
||||
await this.Device.DeleteMessage(this.MessageId.Value);
|
||||
}
|
||||
|
||||
if (form.Count == 0)
|
||||
return;
|
||||
|
||||
|
||||
var rkm = (ReplyKeyboardMarkup)form;
|
||||
rkm.ResizeKeyboard = this.ResizeKeyboard;
|
||||
rkm.OneTimeKeyboard = this.OneTimeKeyboard;
|
||||
m = await this.Device.Send(this.Title, rkm, disableNotification: true, parseMode: MessageParseMode, MarkdownV2AutoEscape: false);
|
||||
|
||||
break;
|
||||
|
||||
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
|
||||
{
|
||||
switch (this.KeyboardType)
|
||||
{
|
||||
case eKeyboardType.ReplyKeyboard:
|
||||
m = await this.Device.Send(this.Title, (ReplyKeyboardMarkup)this.ButtonsForm, disableNotification: true);
|
||||
break;
|
||||
m = await this.Device.Send(this.Title, (InlineKeyboardMarkup)form, disableNotification: true, parseMode: MessageParseMode, MarkdownV2AutoEscape: false);
|
||||
}
|
||||
|
||||
case eKeyboardType.InlineKeyBoard:
|
||||
m = await this.Device.Send(this.Title, (InlineKeyboardMarkup)this.ButtonsForm, disableNotification: true);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -176,27 +411,206 @@ namespace TelegramBotBase.Controls
|
||||
{
|
||||
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)
|
||||
{
|
||||
//Prepare for opening Modal, and comming back
|
||||
if (!FormClose)
|
||||
{
|
||||
this.Updated();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tells the control that it has been updated.
|
||||
/// </summary>
|
||||
public void Updated()
|
||||
{
|
||||
this.RenderNecessary = true;
|
||||
}
|
||||
|
||||
public async override Task Cleanup()
|
||||
{
|
||||
if (this.MessageId == null)
|
||||
return;
|
||||
|
||||
switch (this.KeyboardType)
|
||||
{
|
||||
case eKeyboardType.InlineKeyBoard:
|
||||
|
||||
await this.Device.DeleteMessage(this.MessageId.Value);
|
||||
|
||||
this.MessageId = null;
|
||||
|
||||
if (this.KeyboardType == eKeyboardType.ReplyKeyboard)
|
||||
break;
|
||||
case eKeyboardType.ReplyKeyboard:
|
||||
|
||||
if (this.HideKeyboardOnCleanup)
|
||||
{
|
||||
await this.Device.Send("", new ReplyKeyboardRemove());
|
||||
await this.Device.HideReplyKeyboard();
|
||||
}
|
||||
|
||||
this.MessageId = null;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace TelegramBotBase.Controls
|
||||
|
||||
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; }
|
||||
|
||||
@@ -55,7 +55,7 @@ namespace TelegramBotBase.Controls
|
||||
|
||||
switch (result.RawData)
|
||||
{
|
||||
case "next":
|
||||
case "$next$":
|
||||
|
||||
switch (this.PickerMode)
|
||||
{
|
||||
@@ -74,7 +74,7 @@ namespace TelegramBotBase.Controls
|
||||
|
||||
|
||||
break;
|
||||
case "prev":
|
||||
case "$prev$":
|
||||
|
||||
switch (this.PickerMode)
|
||||
{
|
||||
@@ -93,7 +93,7 @@ namespace TelegramBotBase.Controls
|
||||
|
||||
break;
|
||||
|
||||
case "monthtitle":
|
||||
case "$monthtitle$":
|
||||
|
||||
if (this.EnableMonthView)
|
||||
{
|
||||
@@ -102,7 +102,7 @@ namespace TelegramBotBase.Controls
|
||||
|
||||
break;
|
||||
|
||||
case "yeartitle":
|
||||
case "$yeartitle$":
|
||||
|
||||
if (this.EnableYearView)
|
||||
{
|
||||
@@ -110,7 +110,7 @@ namespace TelegramBotBase.Controls
|
||||
}
|
||||
|
||||
break;
|
||||
case "yearstitle":
|
||||
case "$yearstitle$":
|
||||
|
||||
if (this.EnableMonthView)
|
||||
{
|
||||
@@ -179,7 +179,7 @@ namespace TelegramBotBase.Controls
|
||||
string[] dayNamesNormal = this.Culture.DateTimeFormat.ShortestDayNames;
|
||||
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());
|
||||
|
||||
@@ -223,7 +223,7 @@ namespace TelegramBotBase.Controls
|
||||
|
||||
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;
|
||||
|
||||
@@ -235,7 +235,7 @@ namespace TelegramBotBase.Controls
|
||||
|
||||
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;
|
||||
|
||||
|
||||
@@ -12,15 +12,17 @@ namespace TelegramBotBase.Controls
|
||||
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; }
|
||||
|
||||
@@ -68,7 +70,7 @@ namespace TelegramBotBase.Controls
|
||||
if (result.Handled)
|
||||
return;
|
||||
|
||||
await result.ConfirmAction();
|
||||
await result.ConfirmAction(this.ChangedString);
|
||||
|
||||
switch (value ?? "unknown")
|
||||
{
|
||||
|
||||
@@ -20,12 +20,12 @@ namespace TelegramBotBase.Controls
|
||||
|
||||
private int? MessageId { get; set; }
|
||||
|
||||
public String MoveUpIcon { get; set; } = "🔼 up";
|
||||
public String MoveUpIcon { get; set; } = Localizations.Default.Language["TreeView_LevelUp"];
|
||||
|
||||
public TreeView()
|
||||
{
|
||||
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));
|
||||
|
||||
if (n != null)
|
||||
{
|
||||
if (n == null)
|
||||
return;
|
||||
|
||||
|
||||
if (n.ChildNodes.Count > 0)
|
||||
{
|
||||
this.VisibleNode = n;
|
||||
@@ -64,7 +66,7 @@ namespace TelegramBotBase.Controls
|
||||
}
|
||||
|
||||
result.Handled = true;
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace TelegramBotBase.Exceptions
|
||||
{
|
||||
public class MaximumColsException : Exception
|
||||
{
|
||||
public int Value { get; set; }
|
||||
|
||||
public int Maximum { get; set; }
|
||||
|
||||
|
||||
public override string Message
|
||||
{
|
||||
get
|
||||
{
|
||||
return $"You have exceeded the maximum of columns by {Value.ToString()} / {Maximum.ToString()}";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace TelegramBotBase.Exceptions
|
||||
{
|
||||
public class MaximumRowsReachedException : Exception
|
||||
{
|
||||
public int Value { get; set; }
|
||||
|
||||
public int Maximum { get; set; }
|
||||
|
||||
|
||||
public override string Message
|
||||
{
|
||||
get
|
||||
{
|
||||
return $"You have exceeded the maximum of rows by {Value.ToString()} / {Maximum.ToString()}";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using TelegramBotBase.Attributes;
|
||||
using TelegramBotBase.Base;
|
||||
|
||||
namespace TelegramBotBase.Form
|
||||
@@ -11,6 +12,7 @@ namespace TelegramBotBase.Form
|
||||
/// <summary>
|
||||
/// A simple prompt dialog with one ok Button
|
||||
/// </summary>
|
||||
[IgnoreState]
|
||||
public class AlertDialog : ConfirmDialog
|
||||
{
|
||||
public String ButtonText { get; set; }
|
||||
|
||||
@@ -4,6 +4,8 @@ using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using TelegramBotBase.Args;
|
||||
using TelegramBotBase.Attributes;
|
||||
using TelegramBotBase.Base;
|
||||
|
||||
namespace TelegramBotBase.Form
|
||||
@@ -11,11 +13,11 @@ namespace TelegramBotBase.Form
|
||||
/// <summary>
|
||||
/// A prompt with a lot of buttons
|
||||
/// </summary>
|
||||
[IgnoreState]
|
||||
public class ArrayPromptDialog : FormBase
|
||||
{
|
||||
public String Message { get; set; }
|
||||
|
||||
|
||||
public ButtonBase[][] Buttons { get; set; }
|
||||
|
||||
[Obsolete]
|
||||
|
||||
@@ -4,6 +4,8 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Telegram.Bot.Types;
|
||||
using TelegramBotBase.Args;
|
||||
using TelegramBotBase.Attributes;
|
||||
using TelegramBotBase.Base;
|
||||
using TelegramBotBase.Enums;
|
||||
|
||||
@@ -14,17 +16,20 @@ namespace TelegramBotBase.Form
|
||||
/// </summary>
|
||||
public class AutoCleanForm : FormBase
|
||||
{
|
||||
List<Message> OldMessages { get; set; }
|
||||
[SaveState]
|
||||
public List<int> OldMessages { get; set; }
|
||||
|
||||
[SaveState]
|
||||
public eDeleteMode DeleteMode { get; set; }
|
||||
|
||||
[SaveState]
|
||||
public eDeleteSide DeleteSide { get; set; }
|
||||
|
||||
|
||||
|
||||
public AutoCleanForm()
|
||||
{
|
||||
this.OldMessages = new List<Message>();
|
||||
this.OldMessages = new List<int>();
|
||||
this.DeleteMode = eDeleteMode.OnEveryCall;
|
||||
this.DeleteSide = eDeleteSide.BotOnly;
|
||||
|
||||
@@ -51,7 +56,7 @@ namespace TelegramBotBase.Form
|
||||
if (this.DeleteSide == eDeleteSide.BotOnly)
|
||||
return;
|
||||
|
||||
this.OldMessages.Add(e.Message);
|
||||
this.OldMessages.Add(e.Message.MessageId);
|
||||
}
|
||||
|
||||
private void Device_MessageSent(object sender, MessageSentEventArgs e)
|
||||
@@ -59,7 +64,7 @@ namespace TelegramBotBase.Form
|
||||
if (this.DeleteSide == eDeleteSide.UserOnly)
|
||||
return;
|
||||
|
||||
this.OldMessages.Add(e.Message);
|
||||
this.OldMessages.Add(e.Message.MessageId);
|
||||
}
|
||||
|
||||
public override async Task PreLoad(MessageResult message)
|
||||
@@ -76,7 +81,17 @@ namespace TelegramBotBase.Form
|
||||
/// <param name="Id"></param>
|
||||
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>
|
||||
@@ -85,11 +100,7 @@ namespace TelegramBotBase.Form
|
||||
/// <param name="Id"></param>
|
||||
public void LeaveMessage(int Id)
|
||||
{
|
||||
var m = this.OldMessages.FirstOrDefault(a => a.MessageId == Id);
|
||||
if (m == null)
|
||||
return;
|
||||
|
||||
this.OldMessages.Remove(m);
|
||||
this.OldMessages.Remove(Id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -108,7 +119,7 @@ namespace TelegramBotBase.Form
|
||||
if (this.DeleteMode != eDeleteMode.OnLeavingForm)
|
||||
return;
|
||||
|
||||
await MessageCleanup();
|
||||
MessageCleanup().Wait();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -119,7 +130,7 @@ namespace TelegramBotBase.Form
|
||||
{
|
||||
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
|
||||
if (this.OldMessages.Count > 0)
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace TelegramBotBase.Form
|
||||
/// </summary>
|
||||
public class ButtonBase
|
||||
{
|
||||
public String Text { get; set; }
|
||||
public virtual String Text { get; set; }
|
||||
|
||||
public String Value { get; set; }
|
||||
|
||||
|
||||
@@ -20,6 +20,37 @@ namespace TelegramBotBase.Form
|
||||
|
||||
public ControlBase DependencyControl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Contains the number of rows.
|
||||
/// </summary>
|
||||
public int Rows
|
||||
{
|
||||
get
|
||||
{
|
||||
return Buttons.Count;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Contains the highest number of columns in an row.
|
||||
/// </summary>
|
||||
public int Cols
|
||||
{
|
||||
get
|
||||
{
|
||||
return Buttons.Select(a => a.Count).OrderByDescending(a => a).FirstOrDefault();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public List<ButtonBase> this[int row]
|
||||
{
|
||||
get
|
||||
{
|
||||
return Buttons[row];
|
||||
}
|
||||
}
|
||||
|
||||
public ButtonForm()
|
||||
{
|
||||
|
||||
@@ -30,6 +61,11 @@ namespace TelegramBotBase.Form
|
||||
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)
|
||||
{
|
||||
Buttons.Add(row.ToList());
|
||||
@@ -40,6 +76,16 @@ namespace TelegramBotBase.Form
|
||||
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)
|
||||
{
|
||||
T[][] splitted = default(T[][]);
|
||||
@@ -64,7 +110,10 @@ namespace TelegramBotBase.Form
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,7 +134,7 @@ namespace TelegramBotBase.Form
|
||||
|
||||
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()
|
||||
@@ -102,6 +151,16 @@ namespace TelegramBotBase.Form
|
||||
return ikb;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the first Button with the given value.
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public ButtonBase GetButtonByValue(String value)
|
||||
{
|
||||
return this.ToList().Where(a => a.Value == value).FirstOrDefault();
|
||||
}
|
||||
|
||||
public static implicit operator InlineKeyboardMarkup(ButtonForm form)
|
||||
{
|
||||
if (form == null)
|
||||
@@ -121,5 +180,69 @@ namespace TelegramBotBase.Form
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,14 +4,21 @@ using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using TelegramBotBase.Args;
|
||||
using TelegramBotBase.Attributes;
|
||||
using TelegramBotBase.Base;
|
||||
|
||||
namespace TelegramBotBase.Form
|
||||
{
|
||||
[IgnoreState]
|
||||
public class ConfirmDialog : ModalDialog
|
||||
{
|
||||
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; }
|
||||
|
||||
@@ -47,6 +54,12 @@ namespace TelegramBotBase.Form
|
||||
|
||||
public override async Task Action(MessageResult message)
|
||||
{
|
||||
if (message.Handled)
|
||||
return;
|
||||
|
||||
if (!message.IsFirstHandler)
|
||||
return;
|
||||
|
||||
var call = message.GetData<CallbackData>();
|
||||
if (call == null)
|
||||
return;
|
||||
@@ -65,6 +78,9 @@ namespace TelegramBotBase.Form
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using TelegramBotBase.Args;
|
||||
using TelegramBotBase.Base;
|
||||
using static TelegramBotBase.Base.Async;
|
||||
|
||||
@@ -48,12 +49,16 @@ namespace TelegramBotBase.Form
|
||||
|
||||
default:
|
||||
|
||||
OnMessage(message);
|
||||
await OnMessage(message);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public override async Task Edited(MessageResult message)
|
||||
{
|
||||
await OnMessageEdit(message);
|
||||
}
|
||||
|
||||
public virtual async Task OnMemberChanges(MemberChangeEventArgs e)
|
||||
@@ -72,5 +77,10 @@ namespace TelegramBotBase.Form
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public virtual async Task OnMessageEdit(MessageResult e)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,18 +7,22 @@ namespace TelegramBotBase.Form
|
||||
{
|
||||
public class ModalDialog : FormBase
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Contains the parent from where the modal dialog has been opened.
|
||||
/// </summary>
|
||||
public FormBase ParentForm { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// This is a modal only function and does everything to close this form.
|
||||
/// </summary>
|
||||
public async Task CloseForm()
|
||||
{
|
||||
|
||||
await this.CloseControls();
|
||||
|
||||
await this.OnClosed(new EventArgs());
|
||||
|
||||
|
||||
await this.ParentForm?.ReturnFromModal(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,10 +4,14 @@ using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Telegram.Bot.Types;
|
||||
using Telegram.Bot.Types.ReplyMarkups;
|
||||
using TelegramBotBase.Attributes;
|
||||
using TelegramBotBase.Base;
|
||||
|
||||
namespace TelegramBotBase.Form
|
||||
{
|
||||
[IgnoreState]
|
||||
public class PromptDialog : ModalDialog
|
||||
{
|
||||
public String Message { get; set; }
|
||||
@@ -18,6 +22,14 @@ namespace TelegramBotBase.Form
|
||||
|
||||
private static object __evCompleted { get; } = new object();
|
||||
|
||||
public bool ShowBackButton { get; set; } = false;
|
||||
|
||||
public String BackLabel { get; set; } = Localizations.Default.Language["PromptDialog_Back"];
|
||||
|
||||
/// <summary>
|
||||
/// Contains the RAW received message.
|
||||
/// </summary>
|
||||
public Message ReceivedMessage { get; set; }
|
||||
|
||||
public PromptDialog()
|
||||
{
|
||||
@@ -34,9 +46,21 @@ namespace TelegramBotBase.Form
|
||||
if (message.Handled)
|
||||
return;
|
||||
|
||||
if (!message.IsFirstHandler)
|
||||
return;
|
||||
|
||||
if (this.ShowBackButton && message.MessageText == BackLabel)
|
||||
{
|
||||
await this.CloseForm();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.Value == null)
|
||||
{
|
||||
this.Value = message.MessageText;
|
||||
|
||||
ReceivedMessage = message.Message;
|
||||
}
|
||||
|
||||
|
||||
@@ -47,11 +71,21 @@ namespace TelegramBotBase.Form
|
||||
|
||||
if (this.Value == null)
|
||||
{
|
||||
if (this.ShowBackButton)
|
||||
{
|
||||
ButtonForm bf = new ButtonForm();
|
||||
bf.AddButtonRow(new ButtonBase(BackLabel, "back"));
|
||||
await this.Device.Send(this.Message, (ReplyMarkupBase)bf);
|
||||
return;
|
||||
}
|
||||
|
||||
await this.Device.Send(this.Message);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
message.Handled = true;
|
||||
|
||||
OnCompleted(new EventArgs());
|
||||
|
||||
await this.CloseForm();
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using TelegramBotBase.Args;
|
||||
using TelegramBotBase.Base;
|
||||
|
||||
namespace TelegramBotBase.Interfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// Is used to save specific fields into a session state to survive restarts or unhandled exceptions and crashes.
|
||||
/// </summary>
|
||||
public interface IStateForm
|
||||
{
|
||||
|
||||
void LoadState(LoadStateEventArgs e);
|
||||
|
||||
void SaveState(SaveStateEventArgs e);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using TelegramBotBase.Args;
|
||||
using TelegramBotBase.Base;
|
||||
using TelegramBotBase.Form;
|
||||
|
||||
namespace TelegramBotBase.Interfaces
|
||||
{
|
||||
public interface IStateMachine
|
||||
{
|
||||
Type FallbackStateForm { get; }
|
||||
|
||||
void SaveFormStates(SaveStatesEventArgs e);
|
||||
|
||||
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";
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,11 +2,15 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using Telegram.Bot.Types.Enums;
|
||||
|
||||
namespace TelegramBotBase.Markdown
|
||||
{
|
||||
/// <summary>
|
||||
/// https://core.telegram.org/bots/api#markdownv2-style
|
||||
/// </summary>
|
||||
public static class Generator
|
||||
{
|
||||
public static ParseMode OutputMode { get; set; } = ParseMode.Markdown;
|
||||
@@ -36,13 +40,24 @@ namespace TelegramBotBase.Markdown
|
||||
/// <param name="userId"></param>
|
||||
/// <param name="title"></param>
|
||||
/// <returns></returns>
|
||||
public static String MentionUser(this long userId, String title = null)
|
||||
public static String MentionUser(this int userId, String title = null)
|
||||
{
|
||||
return Link("tg://user?id=" + userId.ToString(), title);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a bold link in Markdown or HTML
|
||||
/// Returns a Link to the User, title is optional.
|
||||
/// </summary>
|
||||
/// <param name="userId"></param>
|
||||
/// <param name="title"></param>
|
||||
/// <returns></returns>
|
||||
public static String MentionUser(this String username, String title = null)
|
||||
{
|
||||
return Link("tg://user?id=" + username, title);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a bold text in Markdown or HTML
|
||||
/// </summary>
|
||||
/// <param name="text"></param>
|
||||
/// <returns></returns>
|
||||
@@ -51,7 +66,7 @@ namespace TelegramBotBase.Markdown
|
||||
switch (OutputMode)
|
||||
{
|
||||
case ParseMode.Markdown:
|
||||
return "**" + text + "**";
|
||||
return "*" + text + "*";
|
||||
case ParseMode.Html:
|
||||
return "<b>" + text + "</b>";
|
||||
}
|
||||
@@ -59,7 +74,24 @@ namespace TelegramBotBase.Markdown
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a italic link in Markdown or HTML
|
||||
/// Returns a strike through in Markdown or HTML
|
||||
/// </summary>
|
||||
/// <param name="text"></param>
|
||||
/// <returns></returns>
|
||||
public static String Strikesthrough(this String text)
|
||||
{
|
||||
switch (OutputMode)
|
||||
{
|
||||
case ParseMode.Markdown:
|
||||
return "~" + text + "~";
|
||||
case ParseMode.Html:
|
||||
return "<s>" + text + "</s>";
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a italic text in Markdown or HTML
|
||||
/// </summary>
|
||||
/// <param name="text"></param>
|
||||
/// <returns></returns>
|
||||
@@ -68,7 +100,7 @@ namespace TelegramBotBase.Markdown
|
||||
switch (OutputMode)
|
||||
{
|
||||
case ParseMode.Markdown:
|
||||
return "__" + text + "__";
|
||||
return "_" + text + "_";
|
||||
case ParseMode.Html:
|
||||
return "<i>" + text + "</i>";
|
||||
}
|
||||
@@ -76,7 +108,24 @@ namespace TelegramBotBase.Markdown
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a monospace link in Markdown or HTML
|
||||
/// Returns a underline text in Markdown or HTML
|
||||
/// </summary>
|
||||
/// <param name="text"></param>
|
||||
/// <returns></returns>
|
||||
public static String Underline(this String text)
|
||||
{
|
||||
switch (OutputMode)
|
||||
{
|
||||
case ParseMode.Markdown:
|
||||
return "__" + text + "__";
|
||||
case ParseMode.Html:
|
||||
return "<u>" + text + "</u>";
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a monospace text in Markdown or HTML
|
||||
/// </summary>
|
||||
/// <param name="text"></param>
|
||||
/// <returns></returns>
|
||||
@@ -93,7 +142,7 @@ namespace TelegramBotBase.Markdown
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a multi monospace link in Markdown or HTML
|
||||
/// Returns a multi monospace text in Markdown or HTML
|
||||
/// </summary>
|
||||
/// <param name="text"></param>
|
||||
/// <returns></returns>
|
||||
@@ -108,5 +157,22 @@ namespace TelegramBotBase.Markdown
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Escapes all characters as stated in the documentation: https://core.telegram.org/bots/api#markdownv2-style
|
||||
/// </summary>
|
||||
/// <param name="text"></param>
|
||||
/// <returns></returns>
|
||||
public static String MarkdownV2Escape(this String text, params char[] toKeep)
|
||||
{
|
||||
char[] toEscape = new char[] { '_', '*', '[', ']', '(', ')', '~', '`', '>', '#', '+', '-', '=', '|', '{', '}', '.', '!' };
|
||||
|
||||
return text.EscapeAll(toEscape.Where(a => !toKeep.Contains(a)).Select(a => a.ToString()).ToArray());
|
||||
}
|
||||
|
||||
public static string EscapeAll(this string seed, String[] chars, char escapeCharacter = '\\')
|
||||
{
|
||||
return chars.Aggregate(seed, (str, cItem) => str.Replace(cItem, escapeCharacter + cItem));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ using System.Runtime.InteropServices;
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("Florian Dahn")]
|
||||
[assembly: AssemblyProduct("TelegramBotBase Framework")]
|
||||
[assembly: AssemblyCopyright("Copyright © Florian Dahn 2019")]
|
||||
[assembly: AssemblyCopyright("Copyright © Florian Dahn 2020")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
|
||||
// Sie können alle Werte angeben oder die standardmäßigen Build- und Revisionsnummern
|
||||
// übernehmen, indem Sie "*" eingeben:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("2.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("2.0.0.0")]
|
||||
[assembly: AssemblyVersion("3.1.0.0")]
|
||||
[assembly: AssemblyFileVersion("3.1.0.0")]
|
||||
|
||||
@@ -1,22 +1,30 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using TelegramBotBase.Args;
|
||||
using TelegramBotBase.Attributes;
|
||||
using TelegramBotBase.Base;
|
||||
using TelegramBotBase.Form;
|
||||
using TelegramBotBase.Interfaces;
|
||||
using TelegramBotBase.Sessions;
|
||||
namespace TelegramBotBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for managing all active sessions
|
||||
/// </summary>
|
||||
public class SessionBase
|
||||
public class SessionBase<T>
|
||||
where T : FormBase
|
||||
{
|
||||
public MessageClient Client { get; set; }
|
||||
|
||||
public Dictionary<long, DeviceSession> SessionList { get; set; }
|
||||
|
||||
public BotBase<T> BotBase { get; set; }
|
||||
|
||||
|
||||
public SessionBase()
|
||||
{
|
||||
@@ -89,5 +97,218 @@ namespace TelegramBotBase
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns all active User Sessions.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public List<DeviceSession> GetUserSessions()
|
||||
{
|
||||
return this.SessionList.Where(a => a.Key > 0).Select(a => a.Value).ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns all active Group Sessions.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public List<DeviceSession> GetGroupSessions()
|
||||
{
|
||||
return this.SessionList.Where(a => a.Key < 0).Select(a => a.Value).ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads the previously saved states from the machine.
|
||||
/// </summary>
|
||||
public async void LoadSessionStates(IStateMachine statemachine)
|
||||
{
|
||||
if (statemachine == null)
|
||||
{
|
||||
throw new ArgumentNullException("StateMachine", "No StateMachine defined. Please set one to property BotBase.StateMachine");
|
||||
}
|
||||
|
||||
var container = statemachine.LoadFormStates();
|
||||
|
||||
foreach (var s in container.States)
|
||||
{
|
||||
Type t = Type.GetType(s.QualifiedName);
|
||||
if (t == null || !t.IsSubclassOf(typeof(FormBase)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var form = t.GetConstructor(new Type[] { })?.Invoke(new object[] { }) as FormBase;
|
||||
|
||||
//No default constructor, fallback
|
||||
if (form == null)
|
||||
{
|
||||
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)
|
||||
{
|
||||
var properties = s.Values.Where(a => a.Key.StartsWith("$"));
|
||||
var fields = form.GetType().GetProperties(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic).Where(a => a.GetCustomAttributes(typeof(SaveState), true).Length != 0).ToList();
|
||||
|
||||
foreach (var p in properties)
|
||||
{
|
||||
var f = fields.FirstOrDefault(a => a.Name == p.Key.Substring(1));
|
||||
if (f == null)
|
||||
continue;
|
||||
|
||||
try
|
||||
{
|
||||
if (f.PropertyType.IsEnum)
|
||||
{
|
||||
var ent = Enum.Parse(f.PropertyType, p.Value.ToString());
|
||||
|
||||
f.SetValue(form, ent);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
f.SetValue(form, p.Value);
|
||||
}
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Is Subclass of IStateForm
|
||||
var iform = form as IStateForm;
|
||||
if (iform != null)
|
||||
{
|
||||
var ls = new LoadStateEventArgs();
|
||||
ls.Values = s.Values;
|
||||
iform.LoadState(ls);
|
||||
}
|
||||
|
||||
|
||||
form.Client = Client;
|
||||
var device = new DeviceSession(s.DeviceId, form);
|
||||
|
||||
device.ChatTitle = s.ChatTitle;
|
||||
|
||||
this.SessionList.Add(s.DeviceId, device);
|
||||
|
||||
try
|
||||
{
|
||||
await form.OnInit(new InitEventArgs());
|
||||
|
||||
await form.OnOpened(new EventArgs());
|
||||
}
|
||||
catch
|
||||
{
|
||||
//Skip on exception
|
||||
this.SessionList.Remove(s.DeviceId);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves all open states into the machine.
|
||||
/// </summary>
|
||||
public void SaveSessionStates(IStateMachine statemachine)
|
||||
{
|
||||
if (statemachine == null)
|
||||
{
|
||||
throw new ArgumentNullException("StateMachine", "No StateMachine defined. Please set one to property BotBase.StateMachine");
|
||||
}
|
||||
|
||||
var states = new List<StateEntry>();
|
||||
|
||||
foreach (var s in this.SessionList)
|
||||
{
|
||||
if (s.Value == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var form = s.Value.ActiveForm;
|
||||
|
||||
try
|
||||
{
|
||||
var se = new StateEntry();
|
||||
se.DeviceId = s.Key;
|
||||
se.ChatTitle = s.Value.GetChatTitle();
|
||||
se.FormUri = form.GetType().FullName;
|
||||
se.QualifiedName = form.GetType().AssemblyQualifiedName;
|
||||
|
||||
//Skip classes where IgnoreState attribute is existing
|
||||
if (form.GetType().GetCustomAttributes(typeof(IgnoreState), true).Length != 0)
|
||||
{
|
||||
//Skip this form, when there is no fallback state form
|
||||
if (statemachine.FallbackStateForm == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
//Replace form by default State one.
|
||||
se.FormUri = statemachine.FallbackStateForm.FullName;
|
||||
se.QualifiedName = statemachine.FallbackStateForm.AssemblyQualifiedName;
|
||||
}
|
||||
|
||||
//Is Subclass of IStateForm
|
||||
var iform = form as IStateForm;
|
||||
if (iform != null)
|
||||
{
|
||||
//Loading Session states
|
||||
SaveStateEventArgs ssea = new SaveStateEventArgs();
|
||||
iform.SaveState(ssea);
|
||||
|
||||
se.Values = ssea.Values;
|
||||
}
|
||||
|
||||
//Search for public properties with SaveState attribute
|
||||
var fields = form.GetType().GetProperties(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic).Where(a => a.GetCustomAttributes(typeof(SaveState), true).Length != 0).ToList();
|
||||
|
||||
foreach (var f in fields)
|
||||
{
|
||||
var val = f.GetValue(form);
|
||||
|
||||
se.Values.Add("$" + f.Name, val);
|
||||
}
|
||||
|
||||
states.Add(se);
|
||||
}
|
||||
catch
|
||||
{
|
||||
//Continue on error (skip this form)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
var sc = new StateContainer();
|
||||
sc.States = states;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,9 +12,11 @@ using Telegram.Bot.Types;
|
||||
using Telegram.Bot.Types.Enums;
|
||||
using Telegram.Bot.Types.InputFiles;
|
||||
using Telegram.Bot.Types.ReplyMarkups;
|
||||
using TelegramBotBase.Args;
|
||||
using TelegramBotBase.Base;
|
||||
using TelegramBotBase.Exceptions;
|
||||
using TelegramBotBase.Form;
|
||||
using TelegramBotBase.Markdown;
|
||||
|
||||
namespace TelegramBotBase.Sessions
|
||||
{
|
||||
@@ -28,6 +30,23 @@ namespace TelegramBotBase.Sessions
|
||||
/// </summary>
|
||||
public long DeviceId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Username of user or group
|
||||
/// </summary>
|
||||
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>
|
||||
/// When did any last action happend (message received or button clicked)
|
||||
/// </summary>
|
||||
@@ -116,6 +135,7 @@ namespace TelegramBotBase.Sessions
|
||||
this.ActiveForm.Device = this;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Edits the text message
|
||||
/// </summary>
|
||||
@@ -123,11 +143,8 @@ namespace TelegramBotBase.Sessions
|
||||
/// <param name="text"></param>
|
||||
/// <param name="buttons"></param>
|
||||
/// <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;
|
||||
|
||||
if (text.Length > Constants.Telegram.MaxMessageLength)
|
||||
@@ -137,9 +154,7 @@ namespace TelegramBotBase.Sessions
|
||||
|
||||
try
|
||||
{
|
||||
var m = await this.Client.TelegramClient.EditMessageTextAsync(this.DeviceId, messageId, text, replyMarkup: markup);
|
||||
|
||||
return m;
|
||||
return await this.Client.TelegramClient.EditMessageTextAsync(this.DeviceId, messageId, text, parseMode, replyMarkup: markup);
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -157,11 +172,8 @@ namespace TelegramBotBase.Sessions
|
||||
/// <param name="text"></param>
|
||||
/// <param name="buttons"></param>
|
||||
/// <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)
|
||||
{
|
||||
throw new MaxLengthException(text.Length);
|
||||
@@ -169,9 +181,7 @@ namespace TelegramBotBase.Sessions
|
||||
|
||||
try
|
||||
{
|
||||
var m = await this.Client.TelegramClient.EditMessageTextAsync(this.DeviceId, messageId, text, replyMarkup: markup);
|
||||
|
||||
return m;
|
||||
return await this.Client.TelegramClient.EditMessageTextAsync(this.DeviceId, messageId, text, parseMode, replyMarkup: markup);
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -189,11 +199,8 @@ namespace TelegramBotBase.Sessions
|
||||
/// <param name="text"></param>
|
||||
/// <param name="buttons"></param>
|
||||
/// <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;
|
||||
|
||||
if (message.Text.Length > Constants.Telegram.MaxMessageLength)
|
||||
@@ -203,9 +210,7 @@ namespace TelegramBotBase.Sessions
|
||||
|
||||
try
|
||||
{
|
||||
var m = await this.Client.TelegramClient.EditMessageTextAsync(this.DeviceId, message.MessageId, message.Text, replyMarkup: markup);
|
||||
|
||||
return m;
|
||||
return await this.Client.TelegramClient.EditMessageTextAsync(this.DeviceId, message.MessageId, message.Text, parseMode, replyMarkup: markup);
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -216,6 +221,27 @@ namespace TelegramBotBase.Sessions
|
||||
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>
|
||||
/// Sends a simple text message
|
||||
/// </summary>
|
||||
@@ -224,7 +250,7 @@ namespace TelegramBotBase.Sessions
|
||||
/// <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)
|
||||
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)
|
||||
return null;
|
||||
@@ -238,13 +264,74 @@ namespace TelegramBotBase.Sessions
|
||||
throw new MaxLengthException(text.Length);
|
||||
}
|
||||
|
||||
if (parseMode == ParseMode.MarkdownV2 && MarkdownV2AutoEscape)
|
||||
{
|
||||
text = text.MarkdownV2Escape();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
m = await (this.Client.TelegramClient.SendTextMessageAsync(deviceId, text, parseMode, replyToMessageId: replyTo, replyMarkup: markup, disableNotification: disableNotification));
|
||||
|
||||
OnMessageSent(new MessageSentEventArgs(m));
|
||||
}
|
||||
catch (ApiRequestException)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
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>
|
||||
/// Sends a simple text message
|
||||
/// </summary>
|
||||
/// <param name="text"></param>
|
||||
/// <param name="markup"></param>
|
||||
/// <param name="replyTo"></param>
|
||||
/// <param name="disableNotification"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<Message> Send(String text, InlineKeyboardMarkup markup, int replyTo = 0, bool disableNotification = false, ParseMode parseMode = ParseMode.Default, bool MarkdownV2AutoEscape = true)
|
||||
{
|
||||
if (this.ActiveForm == null)
|
||||
return null;
|
||||
|
||||
Message m = null;
|
||||
|
||||
if (text.Length > Constants.Telegram.MaxMessageLength)
|
||||
{
|
||||
throw new MaxLengthException(text.Length);
|
||||
}
|
||||
|
||||
if (parseMode == ParseMode.MarkdownV2 && MarkdownV2AutoEscape)
|
||||
{
|
||||
text = text.MarkdownV2Escape();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
m = await (this.Client.TelegramClient.SendTextMessageAsync(this.DeviceId, text, parseMode, replyToMessageId: replyTo, replyMarkup: markup, disableNotification: disableNotification));
|
||||
|
||||
OnMessageSent(new MessageSentEventArgs(m));
|
||||
}
|
||||
catch (ApiRequestException ex)
|
||||
catch (ApiRequestException)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
@@ -264,7 +351,7 @@ namespace TelegramBotBase.Sessions
|
||||
/// <param name="replyTo"></param>
|
||||
/// <param name="disableNotification"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<Message> Send(String text, InlineKeyboardMarkup markup, int replyTo = 0, bool disableNotification = false, ParseMode parseMode = ParseMode.Default)
|
||||
public async Task<Message> Send(String text, ReplyMarkupBase markup, int replyTo = 0, bool disableNotification = false, ParseMode parseMode = ParseMode.Default, bool MarkdownV2AutoEscape = true)
|
||||
{
|
||||
if (this.ActiveForm == null)
|
||||
return null;
|
||||
@@ -276,42 +363,9 @@ namespace TelegramBotBase.Sessions
|
||||
throw new MaxLengthException(text.Length);
|
||||
}
|
||||
|
||||
try
|
||||
if (parseMode == ParseMode.MarkdownV2 && MarkdownV2AutoEscape)
|
||||
{
|
||||
m = await (this.Client.TelegramClient.SendTextMessageAsync(this.DeviceId, text, parseMode, replyToMessageId: replyTo, replyMarkup: markup, disableNotification: disableNotification));
|
||||
|
||||
OnMessageSent(new MessageSentEventArgs(m));
|
||||
}
|
||||
catch (ApiRequestException ex)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends a simple text message
|
||||
/// </summary>
|
||||
/// <param name="text"></param>
|
||||
/// <param name="markup"></param>
|
||||
/// <param name="replyTo"></param>
|
||||
/// <param name="disableNotification"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<Message> Send(String text, ReplyMarkupBase markup, int replyTo = 0, bool disableNotification = false, ParseMode parseMode = ParseMode.Default)
|
||||
{
|
||||
if (this.ActiveForm == null)
|
||||
return null;
|
||||
|
||||
Message m = null;
|
||||
|
||||
if (text.Length > Constants.Telegram.MaxMessageLength)
|
||||
{
|
||||
throw new MaxLengthException(text.Length);
|
||||
text = text.MarkdownV2Escape();
|
||||
}
|
||||
|
||||
try
|
||||
@@ -320,7 +374,7 @@ namespace TelegramBotBase.Sessions
|
||||
|
||||
OnMessageSent(new MessageSentEventArgs(m));
|
||||
}
|
||||
catch (ApiRequestException ex)
|
||||
catch (ApiRequestException)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
@@ -340,7 +394,7 @@ namespace TelegramBotBase.Sessions
|
||||
/// <param name="replyTo"></param>
|
||||
/// <param name="disableNotification"></param>
|
||||
/// <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)
|
||||
return null;
|
||||
@@ -351,11 +405,11 @@ namespace TelegramBotBase.Sessions
|
||||
|
||||
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));
|
||||
}
|
||||
catch (ApiRequestException ex)
|
||||
catch (ApiRequestException)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
@@ -376,15 +430,13 @@ namespace TelegramBotBase.Sessions
|
||||
/// <param name="replyTo"></param>
|
||||
/// <param name="disableNotification"></param>
|
||||
/// <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))
|
||||
{
|
||||
InputOnlineFile fts = new InputOnlineFile(fileStream, name);
|
||||
|
||||
var m = await SendPhoto(fts, buttons, replyTo, disableNotification);
|
||||
|
||||
return m;
|
||||
return await SendPhoto(fts, caption: caption, buttons, replyTo, disableNotification);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -397,16 +449,84 @@ namespace TelegramBotBase.Sessions
|
||||
/// <param name="replyTo"></param>
|
||||
/// <param name="disableNotification"></param>
|
||||
/// <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))
|
||||
{
|
||||
InputOnlineFile fts = new InputOnlineFile(fileStream, name);
|
||||
|
||||
var m = await SendPhoto(fts, buttons, replyTo, disableNotification);
|
||||
return await SendPhoto(fts, caption: caption, buttons, replyTo, disableNotification);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends an video
|
||||
/// </summary>
|
||||
/// <param name="file"></param>
|
||||
/// <param name="buttons"></param>
|
||||
/// <param name="replyTo"></param>
|
||||
/// <param name="disableNotification"></param>
|
||||
/// <returns></returns>
|
||||
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)
|
||||
return null;
|
||||
|
||||
InlineKeyboardMarkup markup = buttons;
|
||||
|
||||
Message m = null;
|
||||
|
||||
try
|
||||
{
|
||||
m = await this.Client.TelegramClient.SendVideoAsync(this.DeviceId, file, caption: caption, parseMode: parseMode, replyToMessageId: replyTo, replyMarkup: markup, disableNotification: disableNotification);
|
||||
|
||||
OnMessageSent(new MessageSentEventArgs(m));
|
||||
}
|
||||
catch (ApiRequestException)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends an video
|
||||
/// </summary>
|
||||
/// <param name="file"></param>
|
||||
/// <param name="buttons"></param>
|
||||
/// <param name="replyTo"></param>
|
||||
/// <param name="disableNotification"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<Message> SendVideo(String url, ButtonForm buttons = null, int replyTo = 0, bool disableNotification = false, ParseMode parseMode = ParseMode.Default)
|
||||
{
|
||||
if (this.ActiveForm == null)
|
||||
return null;
|
||||
|
||||
InlineKeyboardMarkup markup = buttons;
|
||||
|
||||
Message m = null;
|
||||
|
||||
try
|
||||
{
|
||||
m = await this.Client.TelegramClient.SendVideoAsync(this.DeviceId, new InputOnlineFile(url), parseMode: parseMode, replyToMessageId: replyTo, replyMarkup: markup, disableNotification: disableNotification);
|
||||
|
||||
OnMessageSent(new MessageSentEventArgs(m));
|
||||
}
|
||||
catch (ApiRequestException)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -425,9 +545,33 @@ namespace TelegramBotBase.Sessions
|
||||
|
||||
InputOnlineFile fts = new InputOnlineFile(ms, filename);
|
||||
|
||||
var m = await SendDocument(fts, caption, buttons, replyTo, disableNotification);
|
||||
return await SendDocument(fts, caption, buttons, replyTo, disableNotification);
|
||||
}
|
||||
|
||||
return m;
|
||||
/// <summary>
|
||||
/// Generates a Textfile from scratch with the specified encoding. (Default is UTF8)
|
||||
/// </summary>
|
||||
/// <param name="filename"></param>
|
||||
/// <param name="textcontent"></param>
|
||||
/// <param name="encoding">Default is UTF8</param>
|
||||
/// <param name="caption"></param>
|
||||
/// <param name="buttons"></param>
|
||||
/// <param name="replyTo"></param>
|
||||
/// <param name="disableNotification"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<Message> SendTextFile(String filename, String textcontent, Encoding encoding = null, String caption = "", ButtonForm buttons = null, int replyTo = 0, bool disableNotification = false)
|
||||
{
|
||||
encoding = encoding ?? Encoding.UTF8;
|
||||
|
||||
var ms = new MemoryStream();
|
||||
var sw = new StreamWriter(ms, encoding);
|
||||
|
||||
sw.Write(textcontent);
|
||||
sw.Flush();
|
||||
|
||||
var content = ms.ToArray();
|
||||
|
||||
return await SendDocument(filename, content, caption, buttons, replyTo, disableNotification);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -492,6 +636,26 @@ namespace TelegramBotBase.Sessions
|
||||
return await this.Client.TelegramClient.SendTextMessageAsync(this.DeviceId, requestMessage, replyMarkup: rcl);
|
||||
}
|
||||
|
||||
public async Task<Message> HideReplyKeyboard(String closedMsg = "Closed", bool autoDeleteResponse = true)
|
||||
{
|
||||
try
|
||||
{
|
||||
var m = await this.Send(closedMsg, new ReplyKeyboardRemove());
|
||||
|
||||
if (autoDeleteResponse && m != null)
|
||||
{
|
||||
await this.DeleteMessage(m);
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes a message
|
||||
/// </summary>
|
||||
@@ -505,7 +669,7 @@ namespace TelegramBotBase.Sessions
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (ApiRequestException ex)
|
||||
catch (ApiRequestException)
|
||||
{
|
||||
|
||||
}
|
||||
@@ -573,6 +737,19 @@ namespace TelegramBotBase.Sessions
|
||||
}
|
||||
}
|
||||
|
||||
public virtual async Task UnbanUser(int userId)
|
||||
{
|
||||
try
|
||||
{
|
||||
await this.Client.TelegramClient.UnbanChatMemberAsync(this.DeviceId, userId);
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Eventhandler for sent messages
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Serialization.Formatters;
|
||||
using System.Text;
|
||||
using TelegramBotBase.Args;
|
||||
using TelegramBotBase.Base;
|
||||
using TelegramBotBase.Form;
|
||||
using TelegramBotBase.Interfaces;
|
||||
|
||||
namespace TelegramBotBase.States
|
||||
{
|
||||
/// <summary>
|
||||
/// Is used for all complex data types. Use if other default machines are not working.
|
||||
/// </summary>
|
||||
public class JSONStateMachine : IStateMachine
|
||||
{
|
||||
public String FilePath { get; set; }
|
||||
|
||||
public bool Overwrite { get; set; }
|
||||
|
||||
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)
|
||||
{
|
||||
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.Overwrite = overwrite;
|
||||
}
|
||||
|
||||
public StateContainer LoadFormStates()
|
||||
{
|
||||
try
|
||||
{
|
||||
var content = System.IO.File.ReadAllText(FilePath);
|
||||
|
||||
var sc = Newtonsoft.Json.JsonConvert.DeserializeObject<StateContainer>(content, new JsonSerializerSettings
|
||||
{
|
||||
TypeNameHandling = TypeNameHandling.All,
|
||||
TypeNameAssemblyFormatHandling = TypeNameAssemblyFormatHandling.Simple
|
||||
}) as StateContainer;
|
||||
|
||||
return sc;
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
return new StateContainer();
|
||||
}
|
||||
|
||||
public void SaveFormStates(SaveStatesEventArgs e)
|
||||
{
|
||||
if (System.IO.File.Exists(FilePath))
|
||||
{
|
||||
if (!this.Overwrite)
|
||||
{
|
||||
throw new Exception("File exists already.");
|
||||
}
|
||||
|
||||
System.IO.File.Delete(FilePath);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var content = Newtonsoft.Json.JsonConvert.SerializeObject(e.States, Formatting.Indented, new JsonSerializerSettings
|
||||
{
|
||||
TypeNameHandling = TypeNameHandling.All,
|
||||
TypeNameAssemblyFormatHandling = TypeNameAssemblyFormatHandling.Simple
|
||||
});
|
||||
|
||||
System.IO.File.WriteAllText(FilePath, content);
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Serialization.Formatters;
|
||||
using System.Text;
|
||||
using TelegramBotBase.Args;
|
||||
using TelegramBotBase.Base;
|
||||
using TelegramBotBase.Form;
|
||||
using TelegramBotBase.Interfaces;
|
||||
|
||||
namespace TelegramBotBase.States
|
||||
{
|
||||
/// <summary>
|
||||
/// Is used for simple object structures like classes, lists or basic datatypes without generics and other compiler based data types.
|
||||
/// </summary>
|
||||
public class SimpleJSONStateMachine : IStateMachine
|
||||
{
|
||||
public String FilePath { get; set; }
|
||||
|
||||
public bool Overwrite { get; set; }
|
||||
|
||||
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)
|
||||
{
|
||||
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.Overwrite = overwrite;
|
||||
}
|
||||
|
||||
public StateContainer LoadFormStates()
|
||||
{
|
||||
try
|
||||
{
|
||||
var content = System.IO.File.ReadAllText(FilePath);
|
||||
|
||||
var sc = Newtonsoft.Json.JsonConvert.DeserializeObject<StateContainer>(content) as StateContainer;
|
||||
|
||||
return sc;
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
return new StateContainer();
|
||||
}
|
||||
|
||||
public void SaveFormStates(SaveStatesEventArgs e)
|
||||
{
|
||||
if (System.IO.File.Exists(FilePath))
|
||||
{
|
||||
if (!this.Overwrite)
|
||||
{
|
||||
throw new Exception("File exists already.");
|
||||
}
|
||||
|
||||
System.IO.File.Delete(FilePath);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var content = Newtonsoft.Json.JsonConvert.SerializeObject(e.States, Formatting.Indented);
|
||||
|
||||
System.IO.File.WriteAllText(FilePath, content);
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using System.Xml.Serialization;
|
||||
using TelegramBotBase.Args;
|
||||
using TelegramBotBase.Base;
|
||||
using TelegramBotBase.Form;
|
||||
using TelegramBotBase.Interfaces;
|
||||
|
||||
namespace TelegramBotBase.States
|
||||
{
|
||||
public class XMLStateMachine : IStateMachine
|
||||
{
|
||||
public String FilePath { get; set; }
|
||||
|
||||
public bool Overwrite { get; set; }
|
||||
|
||||
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)
|
||||
{
|
||||
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.Overwrite = overwrite;
|
||||
}
|
||||
|
||||
public StateContainer LoadFormStates()
|
||||
{
|
||||
try
|
||||
{
|
||||
DataContractSerializer serializer = new DataContractSerializer(typeof(StateContainer));
|
||||
|
||||
using (var reader = new StreamReader(FilePath))
|
||||
{
|
||||
using (var xml = new XmlTextReader(reader))
|
||||
{
|
||||
StateContainer sc = serializer.ReadObject(xml) as StateContainer;
|
||||
return sc;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
return new StateContainer();
|
||||
}
|
||||
|
||||
public void SaveFormStates(SaveStatesEventArgs e)
|
||||
{
|
||||
if (System.IO.File.Exists(FilePath))
|
||||
{
|
||||
if (!this.Overwrite)
|
||||
{
|
||||
throw new Exception("File exists already.");
|
||||
}
|
||||
|
||||
System.IO.File.Delete(FilePath);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
DataContractSerializer serializer = new DataContractSerializer(typeof(StateContainer));
|
||||
|
||||
using (var sw = new StreamWriter(this.FilePath))
|
||||
{
|
||||
using (var writer = new XmlTextWriter(sw))
|
||||
{
|
||||
writer.Formatting = Formatting.Indented; // indent the Xml so it’s human readable
|
||||
serializer.WriteObject(writer, e.States);
|
||||
writer.Flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,19 +1,28 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>netstandard2.0;net461</TargetFrameworks>
|
||||
<TargetFrameworks>netstandard2.1;net461;netcoreapp3.1</TargetFrameworks>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
|
||||
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
|
||||
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
|
||||
<PackageProjectUrl>https://github.com/MajMcCloud/TelegramBotFramework</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/MajMcCloud/TelegramBotFramework</RepositoryUrl>
|
||||
<PackageReleaseNotes>- moving from .Net Framework 4.7.2 to .Net Standard 2.1 for the Library and .Net Core 3.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>
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
<RunAnalyzersDuringBuild>false</RunAnalyzersDuringBuild>
|
||||
<RunAnalyzersDuringLiveAnalysis>false</RunAnalyzersDuringLiveAnalysis>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
@@ -55,6 +64,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="cpack.ps1" />
|
||||
<None Remove="cpack_bak.ps1" />
|
||||
<None Remove="cpush.ps1" />
|
||||
<None Remove="nuget.exe" />
|
||||
<None Remove="TelegramBotBase.1.5.0.nupkg" />
|
||||
@@ -63,13 +73,18 @@
|
||||
<None Remove="TelegramBotBase.1.5.1.zip" />
|
||||
<None Remove="TelegramBotBase.1.5.2.nupkg" />
|
||||
<None Remove="TelegramBotBase.1.5.2.zip" />
|
||||
<None Remove="TelegramBotBase.2.0.0.nupkg" />
|
||||
<None Remove="TelegramBotBase.2.1.0.nupkg" />
|
||||
<None Remove="TelegramBotBase.2.1.0.zip" />
|
||||
<None Remove="TelegramBotBase.3.0.0.nupkg" />
|
||||
<None Remove="TelegramBotBase.3.0.0.zip" />
|
||||
<None Remove="TelegramBotBase.nuspec" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
|
||||
<PackageReference Include="System.Drawing.Common" Version="4.6.0" />
|
||||
<PackageReference Include="Telegram.Bot" Version="15.0.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||
<PackageReference Include="System.Drawing.Common" Version="4.7.0" />
|
||||
<PackageReference Include="Telegram.Bot" Version="15.5.1" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,24 +1,27 @@
|
||||
<?xml version="1.0"?>
|
||||
<package >
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>$id$</id>
|
||||
<version>$version$</version>
|
||||
<title>$title$</title>
|
||||
<authors>$author$</authors>
|
||||
<owners>$author$</owners>
|
||||
<id>TelegramBotBase</id>
|
||||
<version>2.1.0</version>
|
||||
<authors>TelegramBotBase</authors>
|
||||
<owners>TelegramBotBase</owners>
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<license type="expression">MIT</license>
|
||||
<projectUrl>https://github.com/MajMcCloud/TelegramBotFramework</projectUrl>
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<description>$description$</description>
|
||||
<releaseNotes>This is a context based application framework for the C# TelegramBot library.</releaseNotes>
|
||||
<copyright>Copyright 2019</copyright>
|
||||
<tags>Telegram Bot Framework C# Addon Context Modules</tags>
|
||||
<description>Package Description</description>
|
||||
<releaseNotes>- moving from .Net Framework 4.7.2 to .Net Standard 2.1 for the Library and .Net Core 3.0 for the test project!</releaseNotes>
|
||||
<repository url="https://github.com/MajMcCloud/TelegramBotFramework" />
|
||||
<dependencies>
|
||||
<dependency id="Telegram.Bot" version="14.3.0" />
|
||||
<dependency id="Newtonsoft.Json" version="11.0.2" />
|
||||
<dependency id="System.Net.Requests" version="4.3.0" />
|
||||
<group targetFramework=".NETFramework4.6.1">
|
||||
<dependency id="Newtonsoft.Json" version="12.0.2" exclude="Build,Analyzers" />
|
||||
<dependency id="System.Drawing.Common" version="4.6.0" exclude="Build,Analyzers" />
|
||||
<dependency id="Telegram.Bot" version="15.0.0" exclude="Build,Analyzers" />
|
||||
</group>
|
||||
<group targetFramework=".NETStandard2.0">
|
||||
<dependency id="Newtonsoft.Json" version="12.0.2" exclude="Build,Analyzers" />
|
||||
<dependency id="System.Drawing.Common" version="4.6.0" exclude="Build,Analyzers" />
|
||||
<dependency id="Telegram.Bot" version="15.0.0" exclude="Build,Analyzers" />
|
||||
</group>
|
||||
</dependencies>
|
||||
<repository type="git"
|
||||
url="https://github.com/MajMcCloud/TelegramBotFramework" />
|
||||
</metadata>
|
||||
</package>
|
||||
@@ -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();
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using TelegramBotBase.Args;
|
||||
using TelegramBotBase.Controls;
|
||||
using TelegramBotBase.Form;
|
||||
|
||||
@@ -20,7 +21,7 @@ namespace TelegramBotBaseTest.Tests.Controls
|
||||
this.Init += ButtonGridForm_Init;
|
||||
}
|
||||
|
||||
private async Task ButtonGridForm_Init(object sender, TelegramBotBase.Base.InitEventArgs e)
|
||||
private async Task ButtonGridForm_Init(object sender, InitEventArgs e)
|
||||
{
|
||||
m_Buttons = new ButtonGrid();
|
||||
|
||||
@@ -43,7 +44,7 @@ namespace TelegramBotBaseTest.Tests.Controls
|
||||
|
||||
}
|
||||
|
||||
private async void Bg_ButtonClicked(object sender, TelegramBotBase.Base.ButtonClickedEventArgs e)
|
||||
private async Task Bg_ButtonClicked(object sender, ButtonClickedEventArgs e)
|
||||
{
|
||||
if (e.Button == null)
|
||||
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}");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ using System.Threading.Tasks;
|
||||
using TelegramBotBase.Base;
|
||||
using TelegramBotBase.Form;
|
||||
using TelegramBotBase.Controls;
|
||||
using TelegramBotBase.Args;
|
||||
|
||||
namespace TelegramBotBaseTest.Tests.Controls
|
||||
{
|
||||
|
||||
@@ -7,6 +7,7 @@ using System.Threading.Tasks;
|
||||
using TelegramBotBase.Base;
|
||||
using TelegramBotBase.Form;
|
||||
using TelegramBotBase.Controls;
|
||||
using TelegramBotBase.Args;
|
||||
|
||||
namespace TelegramBotBaseTest.Tests.Controls
|
||||
{
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using TelegramBotBase.Args;
|
||||
using TelegramBotBase.Controls;
|
||||
using TelegramBotBase.Form;
|
||||
|
||||
@@ -17,7 +18,7 @@ namespace TelegramBotBaseTest.Tests.Controls
|
||||
this.Init += ToggleButtons_Init;
|
||||
}
|
||||
|
||||
private async Task ToggleButtons_Init(object sender, TelegramBotBase.Base.InitEventArgs e)
|
||||
private async Task ToggleButtons_Init(object sender, InitEventArgs e)
|
||||
{
|
||||
|
||||
var tb = new ToggleButton();
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Threading.Tasks;
|
||||
using TelegramBotBase.Form;
|
||||
using TelegramBotBase.Controls;
|
||||
using TelegramBotBase.Base;
|
||||
using TelegramBotBase.Args;
|
||||
|
||||
namespace TelegramBotBaseTest.Tests.Controls
|
||||
{
|
||||
@@ -21,7 +22,7 @@ namespace TelegramBotBaseTest.Tests.Controls
|
||||
this.Init += TreeViewForms_Init;
|
||||
}
|
||||
|
||||
private async Task TreeViewForms_Init(object sender, TelegramBotBase.Base.InitEventArgs e)
|
||||
private async Task TreeViewForms_Init(object sender, InitEventArgs e)
|
||||
{
|
||||
view = new TreeView();
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using TelegramBotBase.Args;
|
||||
using TelegramBotBase.Base;
|
||||
using TelegramBotBase.Form;
|
||||
|
||||
|
||||
@@ -79,6 +79,10 @@ namespace TelegramBotBaseTest.Tests.Groups
|
||||
if (e.Message.From.IsBot)
|
||||
return;
|
||||
|
||||
//Are urls inside his message ?
|
||||
if (!HasLinks(e.MessageText))
|
||||
return;
|
||||
|
||||
var u = await Device.GetChatUser(from);
|
||||
|
||||
//Don't kick Admins or Creators
|
||||
@@ -88,11 +92,6 @@ namespace TelegramBotBaseTest.Tests.Groups
|
||||
return;
|
||||
}
|
||||
|
||||
//Are urls inside his message ?
|
||||
if (!HasLinks(e.MessageText))
|
||||
return;
|
||||
|
||||
|
||||
await e.Device.DeleteMessage(e.MessageId);
|
||||
|
||||
var cp = new ChatPermissions();
|
||||
@@ -133,6 +132,16 @@ namespace TelegramBotBaseTest.Tests.Groups
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Call onmessage also on edited message, if someone want to spoof a failed message and insert a link.
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <returns></returns>
|
||||
public override async Task OnMessageEdit(MessageResult message)
|
||||
{
|
||||
await OnMessage(message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// https://stackoverflow.com/a/20651284
|
||||
/// </summary>
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using TelegramBotBase.Base;
|
||||
using TelegramBotBase.Form;
|
||||
using TelegramBotBase.Args;
|
||||
|
||||
namespace TelegramBotBaseTest.Tests.Groups
|
||||
{
|
||||
|
||||
@@ -146,6 +146,16 @@ namespace TelegramBotBaseTest.Tests
|
||||
|
||||
await this.NavigateTo(bg);
|
||||
|
||||
break;
|
||||
|
||||
case "buttongridfilter":
|
||||
|
||||
message.Handled = true;
|
||||
|
||||
var bg2 = new Controls.ButtonGridPagingForm();
|
||||
|
||||
await this.NavigateTo(bg2);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -175,6 +185,8 @@ namespace TelegramBotBaseTest.Tests
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using TelegramBotBase.Args;
|
||||
using TelegramBotBase.Base;
|
||||
using TelegramBotBase.Form;
|
||||
|
||||
|
||||
@@ -12,6 +12,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
|
||||
README.md = README.md
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Examples", "Examples", "{BFA71E3F-31C0-4FC1-A320-4DCF704768C5}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SystemCommandsBot", "Examples\SystemCommandsBot\SystemCommandsBot.csproj", "{FC484952-3060-4F87-9809-4CD66D6961C0}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JoinHiderBot", "Examples\JoinHiderBot\JoinHiderBot.csproj", "{E804B9E5-7ACC-49D3-9253-806766C1D9A5}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -26,10 +32,22 @@ Global
|
||||
{88EC0E02-583D-4B9D-956C-81D63C8CFCFA}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{88EC0E02-583D-4B9D-956C-81D63C8CFCFA}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{88EC0E02-583D-4B9D-956C-81D63C8CFCFA}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{FC484952-3060-4F87-9809-4CD66D6961C0}.Debug|Any CPU.ActiveCfg = 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.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
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{FC484952-3060-4F87-9809-4CD66D6961C0} = {BFA71E3F-31C0-4FC1-A320-4DCF704768C5}
|
||||
{E804B9E5-7ACC-49D3-9253-806766C1D9A5} = {BFA71E3F-31C0-4FC1-A320-4DCF704768C5}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {59CB40E1-9FA7-4867-A56F-4F418286F057}
|
||||
EndGlobalSection
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.0 MiB |
Reference in New Issue
Block a user