Compare commits

..
11 Commits
Author SHA1 Message Date
Florian Dahn 3a309baeae Update README.md 2019-07-14 23:14:37 +02:00
FlorianDahn e02af0fc76 Merge branch 'master' of https://github.com/MajMcCloud/TelegramBotFramework 2019-07-14 23:13:19 +02:00
FlorianDahn 530e01f971 new images 2019-07-14 23:13:16 +02:00
Florian Dahn dcf3cf804f Update README.md 2019-07-14 23:00:06 +02:00
Florian Dahn a42d3934b5 Update README.md 2019-07-14 22:52:59 +02:00
Florian Dahn 2126b45fed Update README.md 2019-07-14 22:47:04 +02:00
FlorianDahn b6b9d5b6b1 Update images 2019-07-14 22:46:29 +02:00
FlorianDahn eed5f012dc adding images for example 2019-07-14 22:38:10 +02:00
FlorianDahn de4cc138ae - New control: CalendarPicker
- New control: MonthPicker
- New control TreeView
- adding examples for all 3
- small change on Progress Bar Control
- due latest changes on the base it is now easier to create controls which will be rendered (or not)in several forms depending on user context
2019-07-14 22:27:16 +02:00
FlorianDahn e4da70d37d - Update of FormBase for better async event management
- Update of ControlBase for partial rendering options
- Updating serveral base classes to better asyc event management
- separating Enums into different folder
- some small bug fixes
- removed "CustomEventManagement" cause it doesnt make sense now
2019-07-14 22:22:04 +02:00
FlorianDahn cb4a797b12 Updating ButtonBase to enable Url Buttons 2019-07-14 22:13:23 +02:00
46 changed files with 1288 additions and 110 deletions
+52 -2
View File
@@ -1,4 +1,5 @@
# .Net Telegram Bot Framework - Context based addon # .Net Telegram Bot Framework - Context based addon
[![NuGet version (TelegramBotBase)](https://img.shields.io/nuget/v/TelegramBotBase.svg?style=flat-square)](https://www.nuget.org/packages/TelegramBotBase/) [![NuGet version (TelegramBotBase)](https://img.shields.io/nuget/v/TelegramBotBase.svg?style=flat-square)](https://www.nuget.org/packages/TelegramBotBase/)
@@ -38,6 +39,14 @@ Download a release: [Releases](https://github.com/MajMcCloud/TelegramBotFramewor
* [PromptDialog](#prompt-dialog) * [PromptDialog](#prompt-dialog)
- [Controls](#controls)
* [ProgressBar](#progress-bar)
* [CalendarPicker](#calendar-picker)
* [MonthPicker](#month-picker)
+ [TreeView](#tree-view)
--- ---
@@ -221,7 +230,7 @@ On every input the user is sending back to the bot the Action event gets raised.
### Lets start with text messages (Example #1 - Simple Test) ### Lets start with text messages (Example #1 - Simple Test)
<img src="images/example1.PNG" />
``` ```
public class SimpleForm : AutoCleanForm public class SimpleForm : AutoCleanForm
@@ -276,6 +285,7 @@ public class SimpleForm : AutoCleanForm
I using a different base class (AutoCleanForm) I created for a better "feeling" inside the bot which will delete "old" messages from this form. You have some settings within this class to manage when messages should be getting deleted. I using a different base class (AutoCleanForm) I created for a better "feeling" inside the bot which will delete "old" messages from this form. You have some settings within this class to manage when messages should be getting deleted.
<img src="images/example2.PNG" />
``` ```
public class ButtonTestForm : AutoCleanForm public class ButtonTestForm : AutoCleanForm
@@ -353,6 +363,8 @@ public class ButtonTestForm : AutoCleanForm
btn.AddButtonRow(new ButtonBase("Button 3", new CallbackData("a", "button3").Serialize()), new ButtonBase("Button 4", new CallbackData("a", "button4").Serialize())); btn.AddButtonRow(new ButtonBase("Button 3", new CallbackData("a", "button3").Serialize()), new ButtonBase("Button 4", new CallbackData("a", "button4").Serialize()));
btn.AddButtonRow(new ButtonBase("Google.com", "google", "https://www.google.com"), new ButtonBase("Telegram", "telegram", "https://telegram.org/"));
btn.AddButtonRow(new ButtonBase("Back", new CallbackData("a", "back").Serialize())); btn.AddButtonRow(new ButtonBase("Back", new CallbackData("a", "back").Serialize()));
await this.Device.Send("Click a button", btn); await this.Device.Send("Click a button", btn);
@@ -368,6 +380,8 @@ public class ButtonTestForm : AutoCleanForm
Sometimes it makes sense to show the end user a type of progressbar or status. For this i tried to make a simple control, which is useful for some situations. Sometimes it makes sense to show the end user a type of progressbar or status. For this i tried to make a simple control, which is useful for some situations.
Maybe, if i got more ideas, i will add other "controls" in the future. Maybe, if i got more ideas, i will add other "controls" in the future.
<img src="images/example3.PNG" />
``` ```
public class ProgressTest : AutoCleanForm public class ProgressTest : AutoCleanForm
@@ -502,6 +516,14 @@ public override async Task Closed()
I read it a lot in different Telegram groups that some developers are searching for easy solutions to create context based apps. For this is my project an ideal solution here. I read it a lot in different Telegram groups that some developers are searching for easy solutions to create context based apps. For this is my project an ideal solution here.
To give you an example about the possiblities, i added into the Test project an example for a registration form. To give you an example about the possiblities, i added into the Test project an example for a registration form.
<img src="images/example4.1.PNG" />
<img src="images/example4.2.PNG" />
<img src="images/example4.3.PNG" />
<img src="images/example4.4.PNG" />
``` ```
public class PerForm : AutoCleanForm public class PerForm : AutoCleanForm
@@ -624,6 +646,8 @@ For now we have the following:
### Alert Dialog ### Alert Dialog
<img src="images/alertdialog.PNG" />
``` ```
var fto = new TestForm2(); var fto = new TestForm2();
@@ -637,10 +661,12 @@ await this.NavigateTo(ad);
### AutoCleanForm ### AutoCleanForm
No example yet
### Prompt Dialog ### Prompt Dialog
<img src="images/promptdialog.PNG" />
#### Without Eventhandler (pre-init of form necessary) #### Without Eventhandler (pre-init of form necessary)
``` ```
@@ -678,6 +704,30 @@ await this.NavigateTo(pd);
``` ```
## Controls
### Progress Bar
<img src="images/progressbar.PNG?raw=true" />
### Calendar Picker
<img src="images/calendarpicker.PNG?raw=true" />
### Month Picker
<img src="images/monthpicker1.PNG?raw=true" />
<img src="images/monthpicker2.PNG?raw=true" />
### Tree View
<img src="images/treeview1.PNG?raw=true" />
<img src="images/treeview2.PNG?raw=true" />
<img src="images/treeview3.PNG?raw=true" />
<img src="images/treeview4.PNG?raw=true" />
--- ---
I will add more notes to it soon, so stay tuned. I will add more notes to it soon, so stay tuned.
+8 -1
View File
@@ -11,7 +11,12 @@ namespace TelegramBaseTest.Tests
public class ButtonTestForm : AutoCleanForm public class ButtonTestForm : AutoCleanForm
{ {
public override async Task Opened() public ButtonTestForm()
{
this.Opened += ButtonTestForm_Opened;
}
private async Task ButtonTestForm_Opened(object sender, EventArgs e)
{ {
await this.Device.Send("Hello world! (Click 'back' to get back to Start)"); await this.Device.Send("Hello world! (Click 'back' to get back to Start)");
} }
@@ -83,6 +88,8 @@ namespace TelegramBaseTest.Tests
btn.AddButtonRow(new ButtonBase("Button 3", new CallbackData("a", "button3").Serialize()), new ButtonBase("Button 4", new CallbackData("a", "button4").Serialize())); btn.AddButtonRow(new ButtonBase("Button 3", new CallbackData("a", "button3").Serialize()), new ButtonBase("Button 4", new CallbackData("a", "button4").Serialize()));
btn.AddButtonRow(new ButtonBase("Google.com", "google", "https://www.google.com"), new ButtonBase("Telegram", "telegram", "https://telegram.org/"));
btn.AddButtonRow(new ButtonBase("Back", new CallbackData("a", "back").Serialize())); btn.AddButtonRow(new ButtonBase("Back", new CallbackData("a", "back").Serialize()));
await this.Device.Send("Click a button", btn); await this.Device.Send("Click a button", btn);
@@ -0,0 +1,79 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TelegramBotBase.Base;
using TelegramBotBase.Form;
using TelegramBotBase.Controls;
namespace TelegramBaseTest.Tests.Controls
{
public class CalendarPickerForm : AutoCleanForm
{
public CalendarPicker Picker { get; set; }
int? selectedDateMessage { get; set; }
public CalendarPickerForm()
{
this.DeleteMode = TelegramBotBase.Enums.eDeleteMode.OnLeavingForm;
this.Init += CalendarPickerForm_Init;
}
private async Task CalendarPickerForm_Init(object sender, InitEventArgs e)
{
this.Picker = new CalendarPicker();
this.Picker.Title = "Datum auswählen / Pick date";
this.AddControl(Picker);
}
public override async Task Action(MessageResult message)
{
switch(message.RawData)
{
case "back":
var s = new Start();
await this.NavigateTo(s);
break;
}
}
public override async Task Render(MessageResult message)
{
String s = "";
s = "Selected date is " + this.Picker.SelectedDate.ToShortDateString() + "\r\n";
s += "Selected month is " + this.Picker.Culture.DateTimeFormat.MonthNames[this.Picker.VisibleMonth.Month - 1] + "\r\n";
s += "Selected year is " + this.Picker.VisibleMonth.Year.ToString();
ButtonForm bf = new ButtonForm();
bf.AddButtonRow(new ButtonBase("Back","back"));
if (selectedDateMessage != null)
{
await this.Device.Edit(this.selectedDateMessage.Value, s, bf);
}
else
{
var m = await this.Device.Send(s, bf);
this.selectedDateMessage = m.MessageId;
}
}
}
}
@@ -0,0 +1,77 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TelegramBotBase.Base;
using TelegramBotBase.Form;
using TelegramBotBase.Controls;
namespace TelegramBaseTest.Tests.Controls
{
public class MonthPickerForm : AutoCleanForm
{
public MonthPicker Picker { get; set; }
int? selectedDateMessage { get; set; }
public MonthPickerForm()
{
this.DeleteMode = TelegramBotBase.Enums.eDeleteMode.OnLeavingForm;
this.Init += MonthPickerForm_Init;
}
private async Task MonthPickerForm_Init(object sender, InitEventArgs e)
{
this.Picker = new MonthPicker();
this.Picker.Title = "Monat auswählen / Pick month";
this.AddControl(Picker);
}
public override async Task Action(MessageResult message)
{
switch(message.RawData)
{
case "back":
var s = new Start();
await this.NavigateTo(s);
break;
}
}
public override async Task Render(MessageResult message)
{
String s = "";
s += "Selected month is " + this.Picker.Culture.DateTimeFormat.MonthNames[this.Picker.SelectedDate.Month - 1] + "\r\n";
s += "Selected year is " + this.Picker.VisibleMonth.Year.ToString();
ButtonForm bf = new ButtonForm();
bf.AddButtonRow(new ButtonBase("Back","back"));
if (selectedDateMessage != null)
{
await this.Device.Edit(this.selectedDateMessage.Value, s, bf);
}
else
{
var m = await this.Device.Send(s, bf);
this.selectedDateMessage = m.MessageId;
}
}
}
}
@@ -0,0 +1,99 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TelegramBotBase.Form;
using TelegramBotBase.Controls;
using TelegramBotBase.Base;
namespace TelegramBaseTest.Tests.Controls
{
public class TreeViewForms : AutoCleanForm
{
public TreeView view { get; set; }
private int? MessageId { get; set; }
public TreeViewForms()
{
this.DeleteMode = TelegramBotBase.Enums.eDeleteMode.OnLeavingForm;
this.Init += TreeViewForms_Init;
}
private async Task TreeViewForms_Init(object sender, TelegramBotBase.Base.InitEventArgs e)
{
view = new TreeView();
var tvn = new TreeViewNode("Cars", "cars");
tvn.AddNode(new TreeViewNode("Porsche", "porsche", new TreeViewNode("Website", "web", "https://www.porsche.com/germany/"), new TreeViewNode("911", "911"), new TreeViewNode("918 Spyder", "918")));
tvn.AddNode(new TreeViewNode("BMW", "bmw"));
tvn.AddNode(new TreeViewNode("Audi", "audi"));
tvn.AddNode(new TreeViewNode("VW", "vw"));
tvn.AddNode(new TreeViewNode("Lamborghini", "lamborghini"));
view.Nodes.Add(tvn);
tvn = new TreeViewNode("Fruits", "fruits");
tvn.AddNode(new TreeViewNode("Apple", "apple"));
tvn.AddNode(new TreeViewNode("Orange", "orange"));
tvn.AddNode(new TreeViewNode("Lemon", "lemon"));
view.Nodes.Add(tvn);
this.AddControl(view);
}
public override async Task Action(MessageResult message)
{
await message.ConfirmAction();
if (message.Handled)
return;
switch (message.RawData)
{
case "back":
message.Handled = true;
var start = new Start();
await this.NavigateTo(start);
break;
}
}
public override async Task Render(MessageResult message)
{
String s = "";
s += "Selected Node: " + (this.view.SelectedNode?.Text ?? "(null)") + "\r\n";
s += "Visible Node: " + (this.view.VisibleNode?.Text ?? "(top)") + "\r\n";
s += "Visible Path: " + this.view.GetPath() + "\r\n";
s += "Selected Path: " + (this.view.SelectedNode?.GetPath() ?? "(null)") + "\r\n";
ButtonForm bf = new ButtonForm();
bf.AddButtonRow(new ButtonBase("Back", "back"));
if (MessageId != null)
{
await this.Device.Edit(this.MessageId.Value, s, bf);
}
else
{
var m = await this.Device.Send(s, bf);
this.MessageId = m.MessageId;
}
}
}
}
+8 -12
View File
@@ -14,10 +14,13 @@ namespace TelegramBaseTest.Tests
public ProgressTest() public ProgressTest()
{ {
this.DeleteMode = eDeleteMode.OnLeavingForm; this.DeleteMode = TelegramBotBase.Enums.eDeleteMode.OnLeavingForm;
this.Opened += ProgressTest_Opened;
this.Closed += ProgressTest_Closed;
} }
public override async Task Opened()
private async Task ProgressTest_Opened(object sender, EventArgs e)
{ {
await this.Device.Send("Welcome to ProgressTest"); await this.Device.Send("Welcome to ProgressTest");
} }
@@ -87,14 +90,14 @@ namespace TelegramBaseTest.Tests
//Render Progress bar and show some "example" progress //Render Progress bar and show some "example" progress
await Bar.Render(); await Bar.Render(message);
this.Controls.Add(Bar); this.Controls.Add(Bar);
for (int i = 0; i <= 100; i++) for (int i = 0; i <= 100; i++)
{ {
Bar.Value++; Bar.Value++;
await Bar.Render(); await Bar.Render(message);
Thread.Sleep(250); Thread.Sleep(250);
} }
@@ -117,17 +120,10 @@ namespace TelegramBaseTest.Tests
await this.Device.Send("Choose your progress bar:", btn); await this.Device.Send("Choose your progress bar:", btn);
} }
public override async Task Closed() private async Task ProgressTest_Closed(object sender, EventArgs e)
{ {
foreach (var b in this.Controls)
{
await b.Cleanup();
}
await this.Device.Send("Ciao from ProgressTest"); await this.Device.Send("Ciao from ProgressTest");
} }
} }
} }
@@ -12,11 +12,17 @@ namespace TelegramBaseTest.Tests.Register.Steps
{ {
public Data UserData { get; set; } public Data UserData { get; set; }
public async override Task Init(params object[] args) public Step1()
{
this.Init += Step1_Init;
}
private async Task Step1_Init(object sender, InitEventArgs e)
{ {
this.UserData = new Data(); this.UserData = new Data();
} }
public async override Task Load(MessageResult message) public async override Task Load(MessageResult message)
{ {
if (message.Handled) if (message.Handled)
+5 -4
View File
@@ -13,16 +13,17 @@ namespace TelegramBaseTest.Tests
public SimpleForm() public SimpleForm()
{ {
this.DeleteSide = eSide.Both; this.DeleteSide = TelegramBotBase.Enums.eSide.Both;
this.DeleteMode = eDeleteMode.OnLeavingForm; this.DeleteMode = TelegramBotBase.Enums.eDeleteMode.OnLeavingForm;
this.Opened += SimpleForm_Opened;
} }
public override async Task Opened() private async Task SimpleForm_Opened(object sender, EventArgs e)
{ {
await this.Device.Send("Hello world! (send 'back' to get back to Start)\r\nOr\r\nhi, hello, maybe, bye and ciao"); await this.Device.Send("Hello world! (send 'back' to get back to Start)\r\nOr\r\nhi, hello, maybe, bye and ciao");
} }
public override async Task Load(MessageResult message) public override async Task Load(MessageResult message)
{ {
//message.MessageText will work also, cause it is a string you could manage a lot different scenerios here //message.MessageText will work also, cause it is a string you could manage a lot different scenerios here
+39 -1
View File
@@ -8,8 +8,12 @@ using TelegramBotBase.Form;
namespace TelegramBaseTest.Tests namespace TelegramBaseTest.Tests
{ {
public class Start : FormBase public class Start : AutoCleanForm
{ {
public Start()
{
this.DeleteMode = TelegramBotBase.Enums.eDeleteMode.OnLeavingForm;
}
public override async Task Action(MessageResult message) public override async Task Action(MessageResult message)
{ {
@@ -79,6 +83,36 @@ namespace TelegramBaseTest.Tests
await this.NavigateTo(data); await this.NavigateTo(data);
break;
case "calendar":
message.Handled = true;
var calendar = new Controls.CalendarPickerForm();
await this.NavigateTo(calendar);
break;
case "month":
message.Handled = true;
var month = new Controls.MonthPickerForm();
await this.NavigateTo(month);
break;
case "treeview":
message.Handled = true;
var tree = new Controls.TreeViewForms();
await this.NavigateTo(tree);
break; break;
} }
@@ -99,6 +133,10 @@ namespace TelegramBaseTest.Tests
btn.AddButtonRow(new ButtonBase("#6 Form2 Command", new CallbackData("a", "form2").Serialize())); btn.AddButtonRow(new ButtonBase("#6 Form2 Command", new CallbackData("a", "form2").Serialize()));
btn.AddButtonRow(new ButtonBase("#7 Data Handling", new CallbackData("a", "data").Serialize())); btn.AddButtonRow(new ButtonBase("#7 Data Handling", new CallbackData("a", "data").Serialize()));
btn.AddButtonRow(new ButtonBase("#8 Calendar Picker", new CallbackData("a", "calendar").Serialize()));
btn.AddButtonRow(new ButtonBase("#9 Month Picker", new CallbackData("a", "month").Serialize()));
btn.AddButtonRow(new ButtonBase("#10 TreeView", new CallbackData("a", "treeview").Serialize()));
await this.Device.Send("Choose your test:", btn); await this.Device.Send("Choose your test:", btn);
} }
+7 -2
View File
@@ -15,13 +15,18 @@ namespace TelegramBaseTest.Tests
String LastMessage { get; set; } String LastMessage { get; set; }
public TestForm()
{
this.Opened += TestForm_Opened;
this.Closed += TestForm_Closed;
}
public override async Task Opened() private async Task TestForm_Opened(object sender, EventArgs e)
{ {
await this.Device.Send("Welcome to Form 1"); await this.Device.Send("Welcome to Form 1");
} }
public override async Task Closed() private async Task TestForm_Closed(object sender, EventArgs e)
{ {
await this.Device.Send("Ciao from Form 1"); await this.Device.Send("Ciao from Form 1");
} }
+10 -2
View File
@@ -16,17 +16,25 @@ namespace TelegramBaseTest.Tests
{ {
public override async Task Opened() public TestForm2()
{
this.Opened += TestForm2_Opened;
this.Closed += TestForm2_Closed;
}
private async Task TestForm2_Opened(object sender, EventArgs e)
{ {
await this.Device.Send("Welcome to Form 2"); await this.Device.Send("Welcome to Form 2");
} }
public override async Task Closed() private async Task TestForm2_Closed(object sender, EventArgs e)
{ {
await this.Device.Send("Ciao from Form 2"); await this.Device.Send("Ciao from Form 2");
} }
public override async Task Action(MessageResult message) public override async Task Action(MessageResult message)
{ {
var call = message.GetData<CallbackData>(); var call = message.GetData<CallbackData>();
+25
View File
@@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TelegramBotBase.Base
{
public static class Async
{
public delegate Task AsyncEventHandler<TEventArgs>(object sender, TEventArgs e) where TEventArgs : EventArgs;
public static IEnumerable<AsyncEventHandler<TEventArgs>> GetHandlers<TEventArgs>(
this AsyncEventHandler<TEventArgs> handler)
where TEventArgs : EventArgs
=> handler.GetInvocationList().Cast<AsyncEventHandler<TEventArgs>>();
public static Task InvokeAllAsync<TEventArgs>(this AsyncEventHandler<TEventArgs> handler, object sender, TEventArgs e)
where TEventArgs : EventArgs
=> Task.WhenAll(
handler.GetHandlers()
.Select(handleAsync => handleAsync(sender, e)));
}
}
+18 -1
View File
@@ -13,9 +13,26 @@ namespace TelegramBotBase.Base
{ {
public Sessions.DeviceSession Device { get; set; } public Sessions.DeviceSession Device { get; set; }
public virtual async Task Render() public int ID { get; set; }
/// <summary>
/// Defines if the control should be rendered and invoked with actions
/// </summary>
public bool Enabled { get; set; } = true;
public virtual async Task Action(MessageResult result)
{ {
}
public virtual async Task Render(MessageResult result)
{
} }
public virtual async Task Cleanup() public virtual async Task Cleanup()
+142 -13
View File
@@ -1,10 +1,12 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using TelegramBotBase.Base; using TelegramBotBase.Base;
using TelegramBotBase.Sessions; using TelegramBotBase.Sessions;
using static TelegramBotBase.Base.Async;
namespace TelegramBotBase.Form namespace TelegramBotBase.Form
{ {
@@ -13,12 +15,11 @@ namespace TelegramBotBase.Form
/// </summary> /// </summary>
public class FormBase : IDisposable public class FormBase : IDisposable
{ {
public DeviceSession Device { get; set; } public DeviceSession Device { get; set; }
public MessageClient Client { get; set; } public MessageClient Client { get; set; }
public bool CustomEventManagement { get; set; } = false;
/// <summary> /// <summary>
/// has this formular already been disposed ? /// has this formular already been disposed ?
/// </summary> /// </summary>
@@ -26,6 +27,17 @@ namespace TelegramBotBase.Form
public List<ControlBase> Controls { get; set; } public List<ControlBase> Controls { get; set; }
private EventHandlerList Events = new EventHandlerList();
private static object __evInit = new object();
private static object __evOpened = new object();
private static object __evClosed = new object();
public FormBase() public FormBase()
{ {
this.Controls = new List<Base.ControlBase>(); this.Controls = new List<Base.ControlBase>();
@@ -36,24 +48,98 @@ namespace TelegramBotBase.Form
this.Client = Client; this.Client = Client;
} }
/// <summary>
/// Will get called at the initialization (once per context)
/// </summary>
public virtual async Task Init(params object[] args)
{
public async Task OnInit(InitEventArgs e)
{
if (this.Events[__evInit] == null)
return;
var handler = this.Events[__evInit].GetInvocationList().Cast<AsyncEventHandler<InitEventArgs>>();
foreach(var h in handler)
{
await Async.InvokeAllAsync<InitEventArgs>(h, this, e);
}
}
///// <summary>
///// Will get called at the initialization (once per context)
///// </summary>
public event AsyncEventHandler<InitEventArgs> Init
{
add
{
this.Events.AddHandler(__evInit, value);
}
remove
{
this.Events.RemoveHandler(__evInit, value);
}
}
public async Task OnOpened(EventArgs e)
{
if (this.Events[__evOpened] == null)
return;
var handler = this.Events[__evOpened].GetInvocationList().Cast<AsyncEventHandler<EventArgs>>();
foreach (var h in handler)
{
await Async.InvokeAllAsync<EventArgs>(h, this, e);
}
} }
/// <summary> /// <summary>
/// Gets invoked if gets navigated to this form /// Gets invoked if gets navigated to this form
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public virtual async Task Opened() public event AsyncEventHandler<EventArgs> Opened
{ {
add
{
this.Events.AddHandler(__evOpened, value);
}
remove
{
this.Events.RemoveHandler(__evOpened, value);
}
} }
public virtual async Task Closed() public async Task OnClosed(EventArgs e)
{
if (this.Events[__evClosed] == null)
return;
var handler = this.Events[__evClosed].GetInvocationList().Cast<AsyncEventHandler<EventArgs>>();
foreach (var h in handler)
{
await Async.InvokeAllAsync<EventArgs>(h, this, e);
}
}
/// <summary>
/// Form has been closed (left)
/// </summary>
/// <returns></returns>
public event AsyncEventHandler<EventArgs> Closed
{
add
{
this.Events.AddHandler(__evClosed, value);
}
remove
{
this.Events.RemoveHandler(__evClosed, value);
}
}
/// <summary>
/// Pre to form close, cleanup all controls
/// </summary>
/// <returns></returns>
public async Task CloseControls()
{ {
foreach (var b in this.Controls) foreach (var b in this.Controls)
{ {
@@ -76,6 +162,22 @@ namespace TelegramBotBase.Form
} }
/// <summary>
/// Gets invoked if the user clicked a button.
/// </summary>
/// <param name="message"></param>
/// <returns></returns>
public async Task ActionControls(MessageResult message)
{
foreach (var b in this.Controls)
{
if (!b.Enabled)
continue;
await b.Action(message);
}
}
/// <summary> /// <summary>
/// Gets invoked if the user has clicked a button. /// Gets invoked if the user has clicked a button.
/// </summary> /// </summary>
@@ -96,6 +198,22 @@ namespace TelegramBotBase.Form
} }
/// <summary>
/// Gets invoked at the end of the cycle to "Render" text, images, buttons, etc...
/// </summary>
/// <param name="message"></param>
/// <returns></returns>
public async Task RenderControls(MessageResult message)
{
foreach (var b in this.Controls)
{
if (!b.Enabled)
continue;
await b.Render(message);
}
}
/// <summary> /// <summary>
/// Gets invoked at the end of the cycle to "Render" text, images, buttons, etc... /// Gets invoked at the end of the cycle to "Render" text, images, buttons, etc...
/// </summary> /// </summary>
@@ -106,6 +224,8 @@ namespace TelegramBotBase.Form
} }
/// <summary> /// <summary>
/// Navigates to a new form /// Navigates to a new form
/// </summary> /// </summary>
@@ -125,11 +245,20 @@ namespace TelegramBotBase.Form
newForm.Client = this.Client; newForm.Client = this.Client;
newForm.Device = ds; newForm.Device = ds;
await newForm.Init(args); await newForm.OnInit(new InitEventArgs(args));
await this.Closed(); await this.CloseControls();
await newForm.Opened(); await this.OnClosed(new EventArgs());
await newForm.OnOpened(new EventArgs());
}
public void AddControl(ControlBase control)
{
control.ID = this.Controls.Count + 1;
control.Device = this.Device;
this.Controls.Add(control);
} }
/// <summary> /// <summary>
+18
View File
@@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TelegramBotBase.Base
{
public class InitEventArgs : EventArgs
{
public object[] Args { get; set; }
public InitEventArgs(params object[] args)
{
this.Args = args;
}
}
}
+8 -8
View File
@@ -264,10 +264,6 @@ namespace TelegramBotBase
activeForm = ds.ActiveForm; activeForm = ds.ActiveForm;
//If the form manages the events by itselfs, skip here
if (activeForm.CustomEventManagement)
return;
//Pre Loading Event //Pre Loading Event
await activeForm.PreLoad(e); await activeForm.PreLoad(e);
@@ -337,10 +333,6 @@ namespace TelegramBotBase
activeForm = ds.ActiveForm; activeForm = ds.ActiveForm;
//If the form manages the events by itselfs, skip here
if (activeForm.CustomEventManagement)
return;
//Pre Loading Event //Pre Loading Event
await activeForm.PreLoad(e); await activeForm.PreLoad(e);
@@ -350,6 +342,10 @@ namespace TelegramBotBase
//Action Event //Action Event
if (!ds.FormSwitched) if (!ds.FormSwitched)
{ {
//Send Action event to controls
await activeForm.ActionControls(e);
//Send Action event to form itself
await activeForm.Action(e); await activeForm.Action(e);
if (!e.Handled) if (!e.Handled)
@@ -374,7 +370,11 @@ namespace TelegramBotBase
//Render Event //Render Event
if (!ds.FormSwitched) if (!ds.FormSwitched)
{
await activeForm.RenderControls(e);
await activeForm.Render(e); await activeForm.Render(e);
}
} while (ds.FormSwitched && i < NavigationMaximum); } while (ds.FormSwitched && i < NavigationMaximum);
+277
View File
@@ -0,0 +1,277 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TelegramBotBase.Base;
using TelegramBotBase.Enums;
using TelegramBotBase.Form;
using static TelegramBotBase.Tools.Arrays;
using static TelegramBotBase.Tools.Time;
namespace TelegramBotBase.Controls
{
public class CalendarPicker : Base.ControlBase
{
public DateTime SelectedDate { get; set; }
public DateTime VisibleMonth { get; set; }
public DayOfWeek FirstDayOfWeek { get; set; }
public CultureInfo Culture { get; set; }
private int? MessageId { get; set; }
public String Title { get; set; } = "Pick Date";
public eMonthPickerMode PickerMode { get; set; }
public bool EnableDayView { get; set; } = true;
public bool EnableMonthView { get; set; } = true;
public bool EnableYearView { get; set; } = true;
public CalendarPicker()
{
this.SelectedDate = DateTime.Today;
this.VisibleMonth = DateTime.Today;
this.FirstDayOfWeek = DayOfWeek.Monday;
this.Culture = new CultureInfo("de-de");
this.PickerMode = eMonthPickerMode.day;
}
public override async Task Action(MessageResult result)
{
await result.ConfirmAction();
switch (result.RawData)
{
case "next":
switch (this.PickerMode)
{
case eMonthPickerMode.day:
this.VisibleMonth = this.VisibleMonth.AddMonths(1);
break;
case eMonthPickerMode.month:
this.VisibleMonth = this.VisibleMonth.AddYears(1);
break;
case eMonthPickerMode.year:
this.VisibleMonth = this.VisibleMonth.AddYears(10);
break;
}
break;
case "prev":
switch (this.PickerMode)
{
case eMonthPickerMode.day:
this.VisibleMonth = this.VisibleMonth.AddMonths(-1);
break;
case eMonthPickerMode.month:
this.VisibleMonth = this.VisibleMonth.AddYears(-1);
break;
case eMonthPickerMode.year:
this.VisibleMonth = this.VisibleMonth.AddYears(-10);
break;
}
break;
case "monthtitle":
if (this.EnableMonthView)
{
this.PickerMode = eMonthPickerMode.month;
}
break;
case "yeartitle":
if (this.EnableYearView)
{
this.PickerMode = eMonthPickerMode.year;
}
break;
case "yearstitle":
if (this.EnableMonthView)
{
this.PickerMode = eMonthPickerMode.month;
}
this.VisibleMonth = this.SelectedDate;
break;
default:
int day = 0;
if (result.RawData.StartsWith("d-") && int.TryParse(result.RawData.Split('-')[1], out day))
{
this.SelectedDate = new DateTime(this.VisibleMonth.Year, this.VisibleMonth.Month, day);
}
int month = 0;
if (result.RawData.StartsWith("m-") && int.TryParse(result.RawData.Split('-')[1], out month))
{
this.SelectedDate = new DateTime(this.VisibleMonth.Year, month, 1);
this.VisibleMonth = this.SelectedDate;
if (this.EnableDayView)
{
this.PickerMode = eMonthPickerMode.day;
}
}
int year = 0;
if (result.RawData.StartsWith("y-") && int.TryParse(result.RawData.Split('-')[1], out year))
{
this.SelectedDate = new DateTime(year, SelectedDate.Month, SelectedDate.Day);
this.VisibleMonth = this.SelectedDate;
if (this.EnableMonthView)
{
this.PickerMode = eMonthPickerMode.month;
}
}
break;
}
}
public override async Task Render(MessageResult result)
{
ButtonForm bf = new ButtonForm();
switch (this.PickerMode)
{
case eMonthPickerMode.day:
var month = this.VisibleMonth;
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(dayNamesShifted.Select(a => new ButtonBase(a, a)).ToList());
//First Day of month
var firstDay = new DateTime(month.Year, month.Month, 1);
//Last Day of month
var lastDay = firstDay.LastDayOfMonth();
//Start of Week where first day of month is (left border)
var start = firstDay.StartOfWeek(this.FirstDayOfWeek);
//End of week where last day of month is (right border)
var end = lastDay.EndOfWeek(this.FirstDayOfWeek);
for (int i = 0; i <= ((end - start).Days / 7); i++)
{
var lst = new List<ButtonBase>();
for (int id = 0; id < 7; id++)
{
var d = start.AddDays((i * 7) + id);
if (d < firstDay | d > lastDay)
{
lst.Add(new ButtonBase("-", "m-" + d.Day.ToString()));
continue;
}
var day = d.Day.ToString();
if (d == DateTime.Today)
{
day = "(" + day + ")";
}
lst.Add(new ButtonBase((this.SelectedDate == d ? "[" + day + "]" : day), "d-" + d.Day.ToString()));
}
bf.AddButtonRow(lst);
}
break;
case eMonthPickerMode.month:
bf.AddButtonRow(new ButtonBase("<<", "prev"), new ButtonBase(this.VisibleMonth.Year.ToString("0000"), "yeartitle"), new ButtonBase(">>", "next"));
var months = this.Culture.DateTimeFormat.MonthNames;
var buttons = months.Select((a, b) => new ButtonBase((b == this.SelectedDate.Month - 1 && this.SelectedDate.Year == this.VisibleMonth.Year ? "[ " + a + " ]" : a), "m-" + (b + 1).ToString()));
bf.AddSplitted(buttons, 2);
break;
case eMonthPickerMode.year:
bf.AddButtonRow(new ButtonBase("<<", "prev"), new ButtonBase("Year", "yearstitle"), new ButtonBase(">>", "next"));
var starti = Math.Floor(this.VisibleMonth.Year / 10f) * 10;
for (int i = 0; i < 10; i++)
{
var m = starti + (i * 2);
bf.AddButtonRow(new ButtonBase((this.SelectedDate.Year == m ? "[ " + m.ToString() + " ]" : m.ToString()), "y-" + m.ToString()), new ButtonBase((this.SelectedDate.Year == (m + 1) ? "[ " + (m + 1).ToString() + " ]" : (m + 1).ToString()), "y-" + (m + 1).ToString()));
}
break;
}
if (this.MessageId != null)
{
var m = await this.Device.Edit(this.MessageId.Value, this.Title, bf);
}
else
{
var m = await this.Device.Send(this.Title, bf);
this.MessageId = m.MessageId;
}
}
public override async Task Cleanup()
{
if (this.MessageId != null)
{
await this.Device.DeleteMessage(this.MessageId.Value);
}
}
}
}
+26
View File
@@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TelegramBotBase.Base;
using TelegramBotBase.Enums;
using TelegramBotBase.Form;
namespace TelegramBotBase.Controls
{
public class MonthPicker : CalendarPicker
{
public MonthPicker()
{
this.PickerMode = eMonthPickerMode.month;
this.EnableDayView = false;
}
}
}
+2 -1
View File
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using TelegramBotBase.Base;
namespace TelegramBotBase.Controls namespace TelegramBotBase.Controls
{ {
@@ -220,7 +221,7 @@ namespace TelegramBotBase.Controls
} }
public async override Task Render() public async override Task Render(MessageResult result)
{ {
if (!this.RenderNecessary) if (!this.RenderNecessary)
{ {
+120
View File
@@ -0,0 +1,120 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TelegramBotBase.Base;
using TelegramBotBase.Form;
namespace TelegramBotBase.Controls
{
public class TreeView : ControlBase
{
public List<TreeViewNode> Nodes { get; set; }
public TreeViewNode SelectedNode { get; set; }
public TreeViewNode VisibleNode { get; set; }
public String Title { get; set; }
private int? MessageId { get; set; }
public String MoveUpIcon { get; set; } = "🔼 up";
public TreeView()
{
this.Nodes = new List<TreeViewNode>();
this.Title = "Select node";
}
public override async Task Action(MessageResult result)
{
await result.ConfirmAction();
if (result.Handled)
return;
var value = result.RawData;
switch (value)
{
case "up":
case "parent":
this.VisibleNode = (this.VisibleNode?.ParentNode);
result.Handled = true;
break;
default:
var n = (this.VisibleNode != null ? this.VisibleNode.FindNodeByValue(value) : this.Nodes.FirstOrDefault(a => a.Value == value));
if (n != null)
{
if (n.ChildNodes.Count > 0)
{
this.VisibleNode = n;
}
else
{
this.SelectedNode = (this.SelectedNode != n ? n : null);
}
result.Handled = true;
}
break;
}
}
public override async Task Render(MessageResult result)
{
var startnode = this.VisibleNode;
var nodes = (startnode?.ChildNodes ?? this.Nodes);
ButtonForm bf = new ButtonForm();
if (startnode != null)
{
bf.AddButtonRow(new ButtonBase(this.MoveUpIcon, "up"), new ButtonBase(startnode.Text, "parent"));
}
foreach (var n in nodes)
{
var s = n.Text;
if (this.SelectedNode == n)
{
s = "[ " + s + " ]";
}
bf.AddButtonRow(new ButtonBase(s, n.Value, n.Url));
}
if (this.MessageId != null)
{
var m = await this.Device.Edit(this.MessageId.Value, this.Title, bf);
}
else
{
var m = await this.Device.Send(this.Title, bf);
this.MessageId = m.MessageId;
}
}
public String GetPath()
{
return (this.VisibleNode?.GetPath() ?? "\\");
}
}
}
+65
View File
@@ -0,0 +1,65 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TelegramBotBase.Controls
{
public class TreeViewNode
{
public String Text { get; set; }
public String Value { get; set; }
public String Url { get; set; }
public List<TreeViewNode> ChildNodes { get; set; } = new List<TreeViewNode>();
public TreeViewNode ParentNode { get; set; }
public TreeViewNode(String Text, String Value)
{
this.Text = Text;
this.Value = Value;
}
public TreeViewNode(String Text, String Value, String Url) : this(Text, Value)
{
this.Url = Url;
}
public TreeViewNode(String Text, String Value, params TreeViewNode[] childnodes) : this(Text, Value)
{
foreach(var c in childnodes)
{
AddNode(c);
}
}
public void AddNode(TreeViewNode node)
{
node.ParentNode = this;
ChildNodes.Add(node);
}
public TreeViewNode FindNodeByValue(String Value)
{
return this.ChildNodes.FirstOrDefault(a => a.Value == Value);
}
public String GetPath()
{
String s = "\\" + this.Value;
var p = this;
while (p.ParentNode != null)
{
s = "\\" + p.ParentNode.Value + s;
p = p.ParentNode;
}
return s;
}
}
}
+56
View File
@@ -0,0 +1,56 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TelegramBotBase.Enums
{
public enum eDeleteMode
{
/// <summary>
/// Don't delete any message.
/// </summary>
None = 0,
/// <summary>
/// Delete messages on every callback/action.
/// </summary>
OnEveryCall = 1,
/// <summary>
/// Delete on leaving this form.
/// </summary>
OnLeavingForm = 2
}
public enum eSide
{
/// <summary>
/// Delete only messages from this bot.
/// </summary>
BotOnly = 0,
/// <summary>
/// Delete only user messages.
/// </summary>
UserOnly = 1,
/// <summary>
/// Delete all messages in this context.
/// </summary>
Both = 2
}
public enum eMonthPickerMode
{
/// <summary>
/// Shows the calendar with day picker mode
/// </summary>
day = 0,
/// <summary>
/// Shows the calendar with month overview
/// </summary>
month = 1,
/// <summary>
/// Shows the calendar with year overview
/// </summary>
year = 2
}
}
+8 -33
View File
@@ -5,6 +5,7 @@ using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Telegram.Bot.Types; using Telegram.Bot.Types;
using TelegramBotBase.Base; using TelegramBotBase.Base;
using TelegramBotBase.Enums;
namespace TelegramBotBase.Form namespace TelegramBotBase.Form
{ {
@@ -19,37 +20,7 @@ namespace TelegramBotBase.Form
public eSide DeleteSide { get; set; } public eSide DeleteSide { get; set; }
public enum eDeleteMode
{
/// <summary>
/// Don't delete any message.
/// </summary>
None = 0,
/// <summary>
/// Delete messages on every callback/action.
/// </summary>
OnEveryCall = 1,
/// <summary>
/// Delete on leaving this form.
/// </summary>
OnLeavingForm = 2
}
public enum eSide
{
/// <summary>
/// Delete only messages from this bot.
/// </summary>
BotOnly = 0,
/// <summary>
/// Delete only user messages.
/// </summary>
UserOnly = 1,
/// <summary>
/// Delete all messages in this context.
/// </summary>
Both = 2
}
public AutoCleanForm() public AutoCleanForm()
{ {
@@ -57,9 +28,14 @@ namespace TelegramBotBase.Form
this.DeleteMode = eDeleteMode.OnEveryCall; this.DeleteMode = eDeleteMode.OnEveryCall;
this.DeleteSide = eSide.BotOnly; this.DeleteSide = eSide.BotOnly;
this.Init += AutoCleanForm_Init;
this.Closed += AutoCleanForm_Closed;
} }
public override async Task Init(params object[] args)
private async Task AutoCleanForm_Init(object sender, InitEventArgs e)
{ {
if (this.Device == null) if (this.Device == null)
return; return;
@@ -127,7 +103,7 @@ namespace TelegramBotBase.Form
this.OldMessages.RemoveAt(this.OldMessages.Count - 1); this.OldMessages.RemoveAt(this.OldMessages.Count - 1);
} }
public async override Task Closed() private async Task AutoCleanForm_Closed(object sender, EventArgs e)
{ {
if (this.DeleteMode != eDeleteMode.OnLeavingForm) if (this.DeleteMode != eDeleteMode.OnLeavingForm)
return; return;
@@ -135,7 +111,6 @@ namespace TelegramBotBase.Form
await MessageCleanup(); await MessageCleanup();
} }
/// <summary> /// <summary>
/// Cleans up all remembered messages. /// Cleans up all remembered messages.
/// </summary> /// </summary>
+22 -1
View File
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Telegram.Bot.Types.ReplyMarkups;
namespace TelegramBotBase.Form namespace TelegramBotBase.Form
{ {
@@ -15,15 +16,35 @@ namespace TelegramBotBase.Form
public String Value { get; set; } public String Value { get; set; }
public String Url { get; set; }
public ButtonBase() public ButtonBase()
{ {
} }
public ButtonBase(String Text, String Value) public ButtonBase(String Text, String Value, String Url = null)
{ {
this.Text = Text; this.Text = Text;
this.Value = Value; this.Value = Value;
this.Url = Url;
}
public InlineKeyboardButton ToInlineButton()
{
if (this.Url == null)
{
return InlineKeyboardButton.WithCallbackData(this.Text, this.Value);
}
var ikb = new InlineKeyboardButton();
ikb.Text = this.Text;
ikb.Url = this.Url;
return ikb;
} }
} }
+10 -3
View File
@@ -14,14 +14,18 @@ namespace TelegramBotBase.Form
{ {
List<List<ButtonBase>> Buttons = new List<List<ButtonBase>>(); List<List<ButtonBase>> Buttons = new List<List<ButtonBase>>();
public IReplyMarkup Markup { get; set; }
public ButtonForm() public ButtonForm()
{ {
} }
public void AddButtonRow(List<ButtonBase> row) public void AddButtonRow(IEnumerable<ButtonBase> row)
{ {
Buttons.Add(row); Buttons.Add(row.ToList());
} }
public void AddButtonRow(params ButtonBase[] row) public void AddButtonRow(params ButtonBase[] row)
@@ -66,13 +70,16 @@ namespace TelegramBotBase.Form
public InlineKeyboardButton[][] ToArray() public InlineKeyboardButton[][] ToArray()
{ {
var ikb = this.Buttons.Select(a => a.Select(b => InlineKeyboardButton.WithCallbackData(b.Text, b.Value)).ToArray()).ToArray(); var ikb = this.Buttons.Select(a => a.Select(b => b.ToInlineButton()).ToArray()).ToArray();
return ikb; return ikb;
} }
public static implicit operator InlineKeyboardMarkup(ButtonForm form) public static implicit operator InlineKeyboardMarkup(ButtonForm form)
{ {
if (form == null)
return null;
InlineKeyboardMarkup ikm = new InlineKeyboardMarkup(form.ToArray()); InlineKeyboardMarkup ikm = new InlineKeyboardMarkup(form.ToArray());
return ikm; return ikm;
+2 -2
View File
@@ -67,9 +67,9 @@ namespace TelegramBotBase
DeviceSession ds = new Sessions.DeviceSession(deviceId, start); DeviceSession ds = new Sessions.DeviceSession(deviceId, start);
start.Device = ds; start.Device = ds;
await start.Init(); await start.OnInit(new InitEventArgs());
await start.Opened(); await start.OnOpened(new EventArgs());
this[deviceId] = ds; this[deviceId] = ds;
return ds; return ds;
+37 -20
View File
@@ -127,11 +127,7 @@ namespace TelegramBotBase.Sessions
if (this.ActiveForm == null) if (this.ActiveForm == null)
return null; return null;
InlineKeyboardMarkup markup = null; InlineKeyboardMarkup markup = buttons;
if (buttons != null)
{
markup = buttons;
}
try try
{ {
@@ -160,11 +156,7 @@ namespace TelegramBotBase.Sessions
if (this.ActiveForm == null) if (this.ActiveForm == null)
return null; return null;
InlineKeyboardMarkup markup = null; InlineKeyboardMarkup markup = buttons;
if (buttons != null)
{
markup = buttons;
}
try try
{ {
@@ -194,11 +186,7 @@ namespace TelegramBotBase.Sessions
if (this.ActiveForm == null) if (this.ActiveForm == null)
return null; return null;
InlineKeyboardMarkup markup = null; InlineKeyboardMarkup markup = buttons;
if (buttons != null)
{
markup = buttons;
}
Message m = null; Message m = null;
@@ -253,6 +241,39 @@ namespace TelegramBotBase.Sessions
return m; 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, ReplyKeyboardMarkup markup, int replyTo = 0, bool disableNotification = false)
{
if (this.ActiveForm == null)
return null;
Message m = null;
try
{
m = await (this.Client.TelegramClient.SendTextMessageAsync(this.DeviceId, text, replyToMessageId: replyTo, replyMarkup: markup, disableNotification: disableNotification));
OnMessageSent(new MessageSentEventArgs(m));
}
catch (ApiRequestException ex)
{
return null;
}
catch
{
return null;
}
return m;
}
/// <summary> /// <summary>
/// Sends an image /// Sends an image
/// </summary> /// </summary>
@@ -266,11 +287,7 @@ namespace TelegramBotBase.Sessions
if (this.ActiveForm == null) if (this.ActiveForm == null)
return null; return null;
InlineKeyboardMarkup markup = null; InlineKeyboardMarkup markup = buttons;
if (buttons != null)
{
markup = buttons;
}
Message m = null; Message m = null;
+22
View File
@@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TelegramBotBase.Base;
using TelegramBotBase.Form;
namespace TelegramBotBase.Tools
{
public static class Arrays
{
public static T[] Shift<T>(T[] array, int positions)
{
T[] copy = new T[array.Length];
Array.Copy(array, 0, copy, array.Length - positions, positions);
Array.Copy(array, positions, copy, 0, array.Length - positions);
return copy;
}
}
}
+36
View File
@@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TelegramBotBase.Tools
{
public static class Time
{
public static DateTime StartOfWeek(this DateTime dt, DayOfWeek startOfWeek)
{
int diff = dt.DayOfWeek - startOfWeek;
if (diff < 0)
{
diff += 7;
}
return dt.AddDays(-1 * diff).Date;
}
public static DateTime EndOfWeek(this DateTime dt, DayOfWeek startOfWeek)
{
return StartOfWeek(dt, startOfWeek).AddDays(6);
}
public static DateTime FirstDayOfMonth(this DateTime date)
{
return new DateTime(date.Year, date.Month, 1);
}
public static DateTime LastDayOfMonth(this DateTime date)
{
return FirstDayOfMonth(date).AddMonths(1).AddDays(-1);
}
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB