fix: reformat using C# rules
This commit is contained in:
@@ -3,40 +3,36 @@ using System.Collections.Generic;
|
||||
using Telegram.Bot.Types;
|
||||
using TelegramBotBase.Sessions;
|
||||
|
||||
namespace TelegramBotBase.Args
|
||||
namespace TelegramBotBase.Args;
|
||||
|
||||
/// <summary>
|
||||
/// Base class for given bot command results
|
||||
/// </summary>
|
||||
public class BotCommandEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for given bot command results
|
||||
/// </summary>
|
||||
public class BotCommandEventArgs : EventArgs
|
||||
public BotCommandEventArgs()
|
||||
{
|
||||
public string Command { get; set; }
|
||||
|
||||
public List<string> Parameters { get; set; }
|
||||
|
||||
public long DeviceId { get; set; }
|
||||
|
||||
public DeviceSession Device { get; set; }
|
||||
|
||||
public bool Handled { get; set; } = false;
|
||||
|
||||
public Message OriginalMessage { get; set; }
|
||||
|
||||
|
||||
public BotCommandEventArgs()
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
public BotCommandEventArgs(string command, List<string> parameters, Message message, long deviceId, DeviceSession device)
|
||||
{
|
||||
this.Command = command;
|
||||
this.Parameters = parameters;
|
||||
OriginalMessage = message;
|
||||
this.DeviceId = deviceId;
|
||||
this.Device = device;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public BotCommandEventArgs(string command, List<string> parameters, Message message, long deviceId,
|
||||
DeviceSession device)
|
||||
{
|
||||
Command = command;
|
||||
Parameters = parameters;
|
||||
OriginalMessage = message;
|
||||
DeviceId = deviceId;
|
||||
Device = device;
|
||||
}
|
||||
|
||||
public string Command { get; set; }
|
||||
|
||||
public List<string> Parameters { get; set; }
|
||||
|
||||
public long DeviceId { get; set; }
|
||||
|
||||
public DeviceSession Device { get; set; }
|
||||
|
||||
public bool Handled { get; set; } = false;
|
||||
|
||||
public Message OriginalMessage { get; set; }
|
||||
}
|
||||
@@ -2,44 +2,41 @@
|
||||
using TelegramBotBase.Controls.Hybrid;
|
||||
using TelegramBotBase.Form;
|
||||
|
||||
namespace TelegramBotBase.Args
|
||||
namespace TelegramBotBase.Args;
|
||||
|
||||
/// <summary>
|
||||
/// Button get clicked event
|
||||
/// </summary>
|
||||
public class ButtonClickedEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Button get clicked event
|
||||
/// </summary>
|
||||
public class ButtonClickedEventArgs : EventArgs
|
||||
public ButtonClickedEventArgs()
|
||||
{
|
||||
public ButtonBase Button { get; set; }
|
||||
|
||||
public int Index { get; set; }
|
||||
|
||||
public object Tag { get; set; }
|
||||
|
||||
public ButtonRow Row { get; set; }
|
||||
|
||||
|
||||
public ButtonClickedEventArgs()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public ButtonClickedEventArgs(ButtonBase button)
|
||||
{
|
||||
Button = button;
|
||||
Index = -1;
|
||||
}
|
||||
|
||||
public ButtonClickedEventArgs(ButtonBase button, int index)
|
||||
{
|
||||
Button = button;
|
||||
this.Index = index;
|
||||
}
|
||||
|
||||
public ButtonClickedEventArgs(ButtonBase button, int index, ButtonRow row)
|
||||
{
|
||||
Button = button;
|
||||
this.Index = index;
|
||||
Row = row;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ButtonClickedEventArgs(ButtonBase button)
|
||||
{
|
||||
Button = button;
|
||||
Index = -1;
|
||||
}
|
||||
|
||||
public ButtonClickedEventArgs(ButtonBase button, int index)
|
||||
{
|
||||
Button = button;
|
||||
Index = index;
|
||||
}
|
||||
|
||||
public ButtonClickedEventArgs(ButtonBase button, int index, ButtonRow row)
|
||||
{
|
||||
Button = button;
|
||||
Index = index;
|
||||
Row = row;
|
||||
}
|
||||
|
||||
public ButtonBase Button { get; set; }
|
||||
|
||||
public int Index { get; set; }
|
||||
|
||||
public object Tag { get; set; }
|
||||
|
||||
public ButtonRow Row { get; set; }
|
||||
}
|
||||
@@ -1,41 +1,36 @@
|
||||
using System;
|
||||
using TelegramBotBase.Controls.Hybrid;
|
||||
|
||||
namespace TelegramBotBase.Args
|
||||
namespace TelegramBotBase.Args;
|
||||
|
||||
public class CheckedChangedEventArgs : EventArgs
|
||||
{
|
||||
public class CheckedChangedEventArgs : EventArgs
|
||||
public CheckedChangedEventArgs()
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains the index of the row where the button is inside.
|
||||
/// Contains -1 when it is a layout button or not found.
|
||||
/// </summary>
|
||||
public int Index { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Contains all buttons within this row, excluding the checkbox.
|
||||
/// </summary>
|
||||
public ButtonRow Row { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Contains the new checked status of the row.
|
||||
/// </summary>
|
||||
public bool Checked { get; set; }
|
||||
|
||||
|
||||
public CheckedChangedEventArgs()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public CheckedChangedEventArgs(ButtonRow row, int index, bool @checked)
|
||||
{
|
||||
Row = row;
|
||||
this.Index = index;
|
||||
this.Checked = @checked;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public CheckedChangedEventArgs(ButtonRow row, int index, bool @checked)
|
||||
{
|
||||
Row = row;
|
||||
Index = index;
|
||||
Checked = @checked;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Contains the index of the row where the button is inside.
|
||||
/// Contains -1 when it is a layout button or not found.
|
||||
/// </summary>
|
||||
public int Index { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Contains all buttons within this row, excluding the checkbox.
|
||||
/// </summary>
|
||||
public ButtonRow Row { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Contains the new checked status of the row.
|
||||
/// </summary>
|
||||
public bool Checked { get; set; }
|
||||
}
|
||||
@@ -2,21 +2,17 @@
|
||||
using Telegram.Bot.Types.Enums;
|
||||
using TelegramBotBase.Base;
|
||||
|
||||
namespace TelegramBotBase.Args
|
||||
namespace TelegramBotBase.Args;
|
||||
|
||||
public class GroupChangedEventArgs : EventArgs
|
||||
{
|
||||
public class GroupChangedEventArgs : EventArgs
|
||||
public GroupChangedEventArgs(MessageType type, MessageResult message)
|
||||
{
|
||||
public MessageType Type { get; set; }
|
||||
|
||||
public MessageResult OriginalMessage { get; set; }
|
||||
|
||||
public GroupChangedEventArgs(MessageType type, MessageResult message)
|
||||
{
|
||||
Type = type;
|
||||
OriginalMessage = message;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Type = type;
|
||||
OriginalMessage = message;
|
||||
}
|
||||
}
|
||||
|
||||
public MessageType Type { get; set; }
|
||||
|
||||
public MessageResult OriginalMessage { get; set; }
|
||||
}
|
||||
@@ -1,14 +1,13 @@
|
||||
using System;
|
||||
|
||||
namespace TelegramBotBase.Args
|
||||
{
|
||||
public class InitEventArgs : EventArgs
|
||||
{
|
||||
public object[] Args { get; set; }
|
||||
namespace TelegramBotBase.Args;
|
||||
|
||||
public InitEventArgs(params object[] args)
|
||||
{
|
||||
Args = args;
|
||||
}
|
||||
public class InitEventArgs : EventArgs
|
||||
{
|
||||
public InitEventArgs(params object[] args)
|
||||
{
|
||||
Args = args;
|
||||
}
|
||||
}
|
||||
|
||||
public object[] Args { get; set; }
|
||||
}
|
||||
@@ -1,55 +1,59 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace TelegramBotBase.Args
|
||||
namespace TelegramBotBase.Args;
|
||||
|
||||
public class LoadStateEventArgs
|
||||
{
|
||||
public class LoadStateEventArgs
|
||||
public LoadStateEventArgs()
|
||||
{
|
||||
public Dictionary<string,object> Values { get; set; }
|
||||
|
||||
public LoadStateEventArgs()
|
||||
{
|
||||
Values = new Dictionary<string, object>();
|
||||
}
|
||||
|
||||
public List<string> Keys => Values.Keys.ToList();
|
||||
|
||||
public string Get(string key)
|
||||
{
|
||||
return Values[key].ToString();
|
||||
}
|
||||
|
||||
public int GetInt(string key)
|
||||
{
|
||||
var 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)
|
||||
{
|
||||
var b = false;
|
||||
if (bool.TryParse(Values[key].ToString(), out b))
|
||||
return b;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public object GetObject(string key)
|
||||
{
|
||||
return Values[key];
|
||||
}
|
||||
|
||||
Values = new Dictionary<string, object>();
|
||||
}
|
||||
}
|
||||
|
||||
public Dictionary<string, object> Values { get; set; }
|
||||
|
||||
public List<string> Keys => Values.Keys.ToList();
|
||||
|
||||
public string Get(string key)
|
||||
{
|
||||
return Values[key].ToString();
|
||||
}
|
||||
|
||||
public int GetInt(string key)
|
||||
{
|
||||
var 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)
|
||||
{
|
||||
var b = false;
|
||||
if (bool.TryParse(Values[key].ToString(), out b))
|
||||
{
|
||||
return b;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public object GetObject(string key)
|
||||
{
|
||||
return Values[key];
|
||||
}
|
||||
}
|
||||
@@ -5,32 +5,25 @@ using Telegram.Bot.Types;
|
||||
using Telegram.Bot.Types.Enums;
|
||||
using TelegramBotBase.Base;
|
||||
|
||||
namespace TelegramBotBase.Args
|
||||
namespace TelegramBotBase.Args;
|
||||
|
||||
public class MemberChangeEventArgs : EventArgs
|
||||
{
|
||||
public class MemberChangeEventArgs : EventArgs
|
||||
public MemberChangeEventArgs()
|
||||
{
|
||||
public List<User> Members { get; set; }
|
||||
|
||||
public MessageType Type { get; set; }
|
||||
|
||||
public MessageResult Result { get; set; }
|
||||
|
||||
public MemberChangeEventArgs()
|
||||
{
|
||||
Members = new List<User>();
|
||||
|
||||
}
|
||||
|
||||
public MemberChangeEventArgs(MessageType type, MessageResult result, params User[] members)
|
||||
{
|
||||
Type = type;
|
||||
Result = result;
|
||||
Members = members.ToList();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Members = new List<User>();
|
||||
}
|
||||
}
|
||||
|
||||
public MemberChangeEventArgs(MessageType type, MessageResult result, params User[] members)
|
||||
{
|
||||
Type = type;
|
||||
Result = result;
|
||||
Members = members.ToList();
|
||||
}
|
||||
|
||||
public List<User> Members { get; set; }
|
||||
|
||||
public MessageType Type { get; set; }
|
||||
|
||||
public MessageResult Result { get; set; }
|
||||
}
|
||||
@@ -1,16 +1,11 @@
|
||||
namespace TelegramBotBase.Args
|
||||
namespace TelegramBotBase.Args;
|
||||
|
||||
public class MessageDeletedEventArgs
|
||||
{
|
||||
public class MessageDeletedEventArgs
|
||||
public MessageDeletedEventArgs(int messageId)
|
||||
{
|
||||
public int MessageId
|
||||
{
|
||||
get;set;
|
||||
}
|
||||
|
||||
public MessageDeletedEventArgs(int messageId)
|
||||
{
|
||||
MessageId = messageId;
|
||||
}
|
||||
|
||||
MessageId = messageId;
|
||||
}
|
||||
}
|
||||
|
||||
public int MessageId { get; set; }
|
||||
}
|
||||
@@ -1,26 +1,20 @@
|
||||
using System;
|
||||
using TelegramBotBase.Sessions;
|
||||
|
||||
namespace TelegramBotBase.Base
|
||||
namespace TelegramBotBase.Base;
|
||||
|
||||
public class MessageIncomeEventArgs : EventArgs
|
||||
{
|
||||
public class MessageIncomeEventArgs : EventArgs
|
||||
public MessageIncomeEventArgs(long deviceId, DeviceSession device, MessageResult message)
|
||||
{
|
||||
|
||||
public long DeviceId { get; set; }
|
||||
|
||||
public DeviceSession Device { get; set; }
|
||||
|
||||
public MessageResult Message { get; set; }
|
||||
|
||||
public MessageIncomeEventArgs(long deviceId, DeviceSession device, MessageResult message)
|
||||
{
|
||||
this.DeviceId = deviceId;
|
||||
this.Device = device;
|
||||
Message = message;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
DeviceId = deviceId;
|
||||
Device = device;
|
||||
Message = message;
|
||||
}
|
||||
}
|
||||
|
||||
public long DeviceId { get; set; }
|
||||
|
||||
public DeviceSession Device { get; set; }
|
||||
|
||||
public MessageResult Message { get; set; }
|
||||
}
|
||||
@@ -1,17 +1,15 @@
|
||||
using Telegram.Bot.Types;
|
||||
|
||||
namespace TelegramBotBase.Args
|
||||
namespace TelegramBotBase.Args;
|
||||
|
||||
public class MessageReceivedEventArgs
|
||||
{
|
||||
public class MessageReceivedEventArgs
|
||||
public MessageReceivedEventArgs(Message m)
|
||||
{
|
||||
public int MessageId => Message.MessageId;
|
||||
|
||||
public Message Message { get; set; }
|
||||
|
||||
public MessageReceivedEventArgs(Message m)
|
||||
{
|
||||
Message = m;
|
||||
}
|
||||
|
||||
Message = m;
|
||||
}
|
||||
}
|
||||
|
||||
public int MessageId => Message.MessageId;
|
||||
|
||||
public Message Message { get; set; }
|
||||
}
|
||||
@@ -1,26 +1,22 @@
|
||||
using System;
|
||||
using Telegram.Bot.Types;
|
||||
|
||||
namespace TelegramBotBase.Args
|
||||
namespace TelegramBotBase.Args;
|
||||
|
||||
public class MessageSentEventArgs : EventArgs
|
||||
{
|
||||
public class MessageSentEventArgs : EventArgs
|
||||
public MessageSentEventArgs(Message message, Type origin)
|
||||
{
|
||||
public int MessageId => Message.MessageId;
|
||||
|
||||
public Message Message { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Contains the element, which has called the method.
|
||||
/// </summary>
|
||||
public Type Origin { get; set; }
|
||||
|
||||
|
||||
public MessageSentEventArgs(Message message, Type origin)
|
||||
{
|
||||
Message = message;
|
||||
this.Origin = origin;
|
||||
}
|
||||
|
||||
|
||||
Message = message;
|
||||
Origin = origin;
|
||||
}
|
||||
}
|
||||
|
||||
public int MessageId => Message.MessageId;
|
||||
|
||||
public Message Message { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Contains the element, which has called the method.
|
||||
/// </summary>
|
||||
public Type Origin { get; set; }
|
||||
}
|
||||
@@ -1,10 +1,8 @@
|
||||
namespace TelegramBotBase.Args
|
||||
namespace TelegramBotBase.Args;
|
||||
|
||||
public class PromptDialogCompletedEventArgs
|
||||
{
|
||||
public class PromptDialogCompletedEventArgs
|
||||
{
|
||||
public object Tag { get; set; }
|
||||
public object Tag { get; set; }
|
||||
|
||||
public string Value { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
public string Value { get; set; }
|
||||
}
|
||||
@@ -1,18 +1,13 @@
|
||||
using System;
|
||||
|
||||
namespace TelegramBotBase.Args
|
||||
namespace TelegramBotBase.Args;
|
||||
|
||||
public class RenderViewEventArgs : EventArgs
|
||||
{
|
||||
public class RenderViewEventArgs : EventArgs
|
||||
public RenderViewEventArgs(int viewIndex)
|
||||
{
|
||||
public int CurrentView { get; set; }
|
||||
|
||||
|
||||
public RenderViewEventArgs(int viewIndex)
|
||||
{
|
||||
|
||||
CurrentView = viewIndex;
|
||||
}
|
||||
|
||||
|
||||
CurrentView = viewIndex;
|
||||
}
|
||||
}
|
||||
|
||||
public int CurrentView { get; set; }
|
||||
}
|
||||
@@ -1,39 +1,38 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace TelegramBotBase.Args
|
||||
namespace TelegramBotBase.Args;
|
||||
|
||||
public class SaveStateEventArgs
|
||||
{
|
||||
public class SaveStateEventArgs
|
||||
public 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;
|
||||
}
|
||||
public void SetObject(string key, object value)
|
||||
{
|
||||
Values[key] = value;
|
||||
}
|
||||
|
||||
Values = new Dictionary<string, object>();
|
||||
}
|
||||
}
|
||||
|
||||
public Dictionary<string, object> Values { get; set; }
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public void SetObject(string key, object value)
|
||||
{
|
||||
Values[key] = value;
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,13 @@
|
||||
using TelegramBotBase.Base;
|
||||
|
||||
namespace TelegramBotBase.Args
|
||||
namespace TelegramBotBase.Args;
|
||||
|
||||
public class SaveStatesEventArgs
|
||||
{
|
||||
public class SaveStatesEventArgs
|
||||
public SaveStatesEventArgs(StateContainer states)
|
||||
{
|
||||
public StateContainer States { get; set; }
|
||||
|
||||
|
||||
public SaveStatesEventArgs(StateContainer states)
|
||||
{
|
||||
States = states;
|
||||
}
|
||||
States = states;
|
||||
}
|
||||
}
|
||||
|
||||
public StateContainer States { get; set; }
|
||||
}
|
||||
@@ -1,18 +1,17 @@
|
||||
using System;
|
||||
using TelegramBotBase.Sessions;
|
||||
|
||||
namespace TelegramBotBase.Base
|
||||
namespace TelegramBotBase.Base;
|
||||
|
||||
public class SessionBeginEventArgs : EventArgs
|
||||
{
|
||||
public class SessionBeginEventArgs : EventArgs
|
||||
public SessionBeginEventArgs(long deviceId, DeviceSession device)
|
||||
{
|
||||
public long DeviceId { get; set; }
|
||||
|
||||
public DeviceSession Device { get; set; }
|
||||
|
||||
public SessionBeginEventArgs(long deviceId, DeviceSession device)
|
||||
{
|
||||
this.DeviceId = deviceId;
|
||||
this.Device = device;
|
||||
}
|
||||
DeviceId = deviceId;
|
||||
Device = device;
|
||||
}
|
||||
}
|
||||
|
||||
public long DeviceId { get; set; }
|
||||
|
||||
public DeviceSession Device { get; set; }
|
||||
}
|
||||
@@ -1,32 +1,27 @@
|
||||
using System;
|
||||
using TelegramBotBase.Sessions;
|
||||
|
||||
namespace TelegramBotBase.Args
|
||||
namespace TelegramBotBase.Args;
|
||||
|
||||
public class SystemExceptionEventArgs : EventArgs
|
||||
{
|
||||
public class SystemExceptionEventArgs : EventArgs
|
||||
public SystemExceptionEventArgs()
|
||||
{
|
||||
|
||||
public string Command { get; set; }
|
||||
|
||||
public long DeviceId { get; set; }
|
||||
|
||||
public DeviceSession Device { get; set; }
|
||||
|
||||
public Exception Error { get; set; }
|
||||
|
||||
public SystemExceptionEventArgs()
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
public SystemExceptionEventArgs(string command, long deviceId, DeviceSession device, Exception error)
|
||||
{
|
||||
this.Command = command;
|
||||
this.DeviceId = deviceId;
|
||||
this.Device = device;
|
||||
Error = error;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
public SystemExceptionEventArgs(string command, long deviceId, DeviceSession device, Exception error)
|
||||
{
|
||||
Command = command;
|
||||
DeviceId = deviceId;
|
||||
Device = device;
|
||||
Error = error;
|
||||
}
|
||||
|
||||
public string Command { get; set; }
|
||||
|
||||
public long DeviceId { get; set; }
|
||||
|
||||
public DeviceSession Device { get; set; }
|
||||
|
||||
public Exception Error { get; set; }
|
||||
}
|
||||
@@ -2,40 +2,37 @@
|
||||
using Telegram.Bot.Types;
|
||||
using TelegramBotBase.Sessions;
|
||||
|
||||
namespace TelegramBotBase.Args
|
||||
namespace TelegramBotBase.Args;
|
||||
|
||||
public class UnhandledCallEventArgs : EventArgs
|
||||
{
|
||||
public class UnhandledCallEventArgs : EventArgs
|
||||
public UnhandledCallEventArgs()
|
||||
{
|
||||
public string Command { get; set; }
|
||||
|
||||
public long DeviceId { get; set; }
|
||||
|
||||
public DeviceSession Device {get;set;}
|
||||
|
||||
public string RawData { get; set; }
|
||||
|
||||
public int MessageId { get; set; }
|
||||
|
||||
public Message Message { get; set; }
|
||||
|
||||
public bool Handled { get; set; }
|
||||
|
||||
|
||||
public UnhandledCallEventArgs()
|
||||
{
|
||||
Handled = false;
|
||||
|
||||
}
|
||||
|
||||
public UnhandledCallEventArgs(string command,string rawData, long deviceId, int messageId, Message message, DeviceSession device) : this()
|
||||
{
|
||||
this.Command = command;
|
||||
this.RawData = rawData;
|
||||
this.DeviceId = deviceId;
|
||||
this.MessageId = messageId;
|
||||
Message = message;
|
||||
this.Device = device;
|
||||
}
|
||||
|
||||
Handled = false;
|
||||
}
|
||||
}
|
||||
|
||||
public UnhandledCallEventArgs(string command, string rawData, long deviceId, int messageId, Message message,
|
||||
DeviceSession device) : this()
|
||||
{
|
||||
Command = command;
|
||||
RawData = rawData;
|
||||
DeviceId = deviceId;
|
||||
MessageId = messageId;
|
||||
Message = message;
|
||||
Device = device;
|
||||
}
|
||||
|
||||
public string Command { get; set; }
|
||||
|
||||
public long DeviceId { get; set; }
|
||||
|
||||
public DeviceSession Device { get; set; }
|
||||
|
||||
public string RawData { get; set; }
|
||||
|
||||
public int MessageId { get; set; }
|
||||
|
||||
public Message Message { get; set; }
|
||||
|
||||
public bool Handled { get; set; }
|
||||
}
|
||||
@@ -1,15 +1,11 @@
|
||||
using System;
|
||||
|
||||
namespace TelegramBotBase.Attributes
|
||||
namespace TelegramBotBase.Attributes;
|
||||
|
||||
/// <summary>
|
||||
/// Declares that this class should not be getting serialized
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class IgnoreState : Attribute
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Declares that this class should not be getting serialized
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class IgnoreState : Attribute
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,11 @@
|
||||
using System;
|
||||
|
||||
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; }
|
||||
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; }
|
||||
}
|
||||
@@ -3,22 +3,25 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace TelegramBotBase.Base
|
||||
{
|
||||
public static class Async
|
||||
{
|
||||
public delegate Task AsyncEventHandler<TEventArgs>(object sender, TEventArgs e) where TEventArgs : EventArgs;
|
||||
namespace TelegramBotBase.Base;
|
||||
|
||||
public static IEnumerable<AsyncEventHandler<TEventArgs>> GetHandlers<TEventArgs>(
|
||||
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)));
|
||||
|
||||
{
|
||||
return handler.GetInvocationList().Cast<AsyncEventHandler<TEventArgs>>();
|
||||
}
|
||||
}
|
||||
|
||||
public static Task InvokeAllAsync<TEventArgs>(this AsyncEventHandler<TEventArgs> handler, object sender,
|
||||
TEventArgs e)
|
||||
where TEventArgs : EventArgs
|
||||
{
|
||||
return Task.WhenAll(
|
||||
handler.GetHandlers()
|
||||
.Select(handleAsync => handleAsync(sender, e)));
|
||||
}
|
||||
}
|
||||
@@ -1,63 +1,59 @@
|
||||
using System.Threading.Tasks;
|
||||
using TelegramBotBase.Sessions;
|
||||
|
||||
namespace TelegramBotBase.Base
|
||||
namespace TelegramBotBase.Base;
|
||||
|
||||
/// <summary>
|
||||
/// Base class for controls
|
||||
/// </summary>
|
||||
public class ControlBase
|
||||
{
|
||||
public DeviceSession Device { get; set; }
|
||||
|
||||
public int Id { get; set; }
|
||||
|
||||
public string ControlId => "#c" + Id;
|
||||
|
||||
/// <summary>
|
||||
/// Base class for controls
|
||||
/// Defines if the control should be rendered and invoked with actions
|
||||
/// </summary>
|
||||
public class ControlBase
|
||||
public bool Enabled { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Get invoked when control will be added to a form and invoked.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public virtual void Init()
|
||||
{
|
||||
public DeviceSession Device { get; set; }
|
||||
|
||||
public int Id { get; set; }
|
||||
|
||||
public string ControlId => "#c" + Id;
|
||||
|
||||
/// <summary>
|
||||
/// Defines if the control should be rendered and invoked with actions
|
||||
/// </summary>
|
||||
public bool Enabled { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Get invoked when control will be added to a form and invoked.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public virtual void Init()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public virtual Task Load(MessageResult result)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public virtual Task Action(MessageResult result, string value = null)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public virtual Task Render(MessageResult result)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public virtual Task Hidden(bool formClose)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Will be called on a cleanup.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public virtual Task Cleanup()
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public virtual Task Load(MessageResult result)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public virtual Task Action(MessageResult result, string value = null)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
|
||||
public virtual Task Render(MessageResult result)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public virtual Task Hidden(bool formClose)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Will be called on a cleanup.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public virtual Task Cleanup()
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
+158
-160
@@ -7,166 +7,164 @@ using Telegram.Bot.Types;
|
||||
using Telegram.Bot.Types.Enums;
|
||||
using Telegram.Bot.Types.InputFiles;
|
||||
|
||||
namespace TelegramBotBase.Base
|
||||
namespace TelegramBotBase.Base;
|
||||
|
||||
/// <summary>
|
||||
/// Returns a class to manage attachments within messages.
|
||||
/// </summary>
|
||||
public class DataResult : ResultBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns a class to manage attachments within messages.
|
||||
/// </summary>
|
||||
public class DataResult : ResultBase
|
||||
public DataResult(UpdateResult update)
|
||||
{
|
||||
|
||||
//public Telegram.Bot.Args.MessageEventArgs RawMessageData { get; set; }
|
||||
|
||||
public UpdateResult UpdateData { get; set; }
|
||||
|
||||
|
||||
public Contact Contact => Message.Contact;
|
||||
|
||||
public Location Location => Message.Location;
|
||||
|
||||
public Document Document => Message.Document;
|
||||
|
||||
public Audio Audio => Message.Audio;
|
||||
|
||||
public Video Video => Message.Video;
|
||||
|
||||
public PhotoSize[] Photos => Message.Photo;
|
||||
|
||||
|
||||
public MessageType Type => Message?.Type ?? MessageType.Unknown;
|
||||
|
||||
public override Message Message => UpdateData?.Message;
|
||||
|
||||
/// <summary>
|
||||
/// Returns the FileId of the first reachable element.
|
||||
/// </summary>
|
||||
public string FileId =>
|
||||
(Document?.FileId ??
|
||||
Audio?.FileId ??
|
||||
Video?.FileId ??
|
||||
Photos.FirstOrDefault()?.FileId);
|
||||
|
||||
public DataResult(UpdateResult update)
|
||||
{
|
||||
UpdateData = update;
|
||||
}
|
||||
|
||||
|
||||
public async Task<InputOnlineFile> DownloadDocument()
|
||||
{
|
||||
var encryptedContent = new MemoryStream();
|
||||
encryptedContent.SetLength(Document.FileSize.Value);
|
||||
var file = await Device.Client.TelegramClient.GetInfoAndDownloadFileAsync(Document.FileId, encryptedContent);
|
||||
|
||||
return new InputOnlineFile(encryptedContent, Document.FileName);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Downloads a file and saves it to the given path.
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
/// <returns></returns>
|
||||
public async Task DownloadDocument(string path)
|
||||
{
|
||||
var file = await Device.Client.TelegramClient.GetFileAsync(Document.FileId);
|
||||
var fs = new FileStream(path, FileMode.Create);
|
||||
await Device.Client.TelegramClient.DownloadFileAsync(file.FilePath, fs);
|
||||
fs.Close();
|
||||
fs.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Downloads the document and returns an byte array.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<byte[]> DownloadRawDocument()
|
||||
{
|
||||
var ms = new MemoryStream();
|
||||
await Device.Client.TelegramClient.GetInfoAndDownloadFileAsync(Document.FileId, ms);
|
||||
return ms.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Downloads a document and returns it as string. (txt,csv,etc) Default encoding ist UTF8.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<string> DownloadRawTextDocument()
|
||||
{
|
||||
return await DownloadRawTextDocument(Encoding.UTF8);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Downloads a document and returns it as string. (txt,csv,etc)
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<string> DownloadRawTextDocument(Encoding encoding)
|
||||
{
|
||||
var ms = new MemoryStream();
|
||||
await Device.Client.TelegramClient.GetInfoAndDownloadFileAsync(Document.FileId, ms);
|
||||
|
||||
ms.Position = 0;
|
||||
|
||||
var sr = new StreamReader(ms, encoding);
|
||||
|
||||
return sr.ReadToEnd();
|
||||
}
|
||||
|
||||
public async Task<InputOnlineFile> DownloadVideo()
|
||||
{
|
||||
var encryptedContent = new MemoryStream();
|
||||
encryptedContent.SetLength(Video.FileSize.Value);
|
||||
var file = await Device.Client.TelegramClient.GetInfoAndDownloadFileAsync(Video.FileId, encryptedContent);
|
||||
|
||||
return new InputOnlineFile(encryptedContent, "");
|
||||
}
|
||||
|
||||
public async Task DownloadVideo(string path)
|
||||
{
|
||||
var file = await Device.Client.TelegramClient.GetFileAsync(Video.FileId);
|
||||
var fs = new FileStream(path, FileMode.Create);
|
||||
await Device.Client.TelegramClient.DownloadFileAsync(file.FilePath, fs);
|
||||
fs.Close();
|
||||
fs.Dispose();
|
||||
}
|
||||
|
||||
public async Task<InputOnlineFile> DownloadAudio()
|
||||
{
|
||||
var encryptedContent = new MemoryStream();
|
||||
encryptedContent.SetLength(Audio.FileSize.Value);
|
||||
var file = await Device.Client.TelegramClient.GetInfoAndDownloadFileAsync(Audio.FileId, encryptedContent);
|
||||
|
||||
return new InputOnlineFile(encryptedContent, "");
|
||||
}
|
||||
|
||||
public async Task DownloadAudio(string path)
|
||||
{
|
||||
var file = await Device.Client.TelegramClient.GetFileAsync(Audio.FileId);
|
||||
var fs = new FileStream(path, FileMode.Create);
|
||||
await Device.Client.TelegramClient.DownloadFileAsync(file.FilePath, fs);
|
||||
fs.Close();
|
||||
fs.Dispose();
|
||||
}
|
||||
|
||||
public async Task<InputOnlineFile> DownloadPhoto(int index)
|
||||
{
|
||||
var photo = Photos[index];
|
||||
var encryptedContent = new MemoryStream();
|
||||
encryptedContent.SetLength(photo.FileSize.Value);
|
||||
var file = await Device.Client.TelegramClient.GetInfoAndDownloadFileAsync(photo.FileId, encryptedContent);
|
||||
|
||||
return new InputOnlineFile(encryptedContent, "");
|
||||
}
|
||||
|
||||
public async Task DownloadPhoto(int index, string path)
|
||||
{
|
||||
var photo = Photos[index];
|
||||
var file = await Device.Client.TelegramClient.GetFileAsync(photo.FileId);
|
||||
var fs = new FileStream(path, FileMode.Create);
|
||||
await Device.Client.TelegramClient.DownloadFileAsync(file.FilePath, fs);
|
||||
fs.Close();
|
||||
fs.Dispose();
|
||||
}
|
||||
|
||||
UpdateData = update;
|
||||
}
|
||||
}
|
||||
|
||||
//public Telegram.Bot.Args.MessageEventArgs RawMessageData { get; set; }
|
||||
|
||||
public UpdateResult UpdateData { get; set; }
|
||||
|
||||
|
||||
public Contact Contact => Message.Contact;
|
||||
|
||||
public Location Location => Message.Location;
|
||||
|
||||
public Document Document => Message.Document;
|
||||
|
||||
public Audio Audio => Message.Audio;
|
||||
|
||||
public Video Video => Message.Video;
|
||||
|
||||
public PhotoSize[] Photos => Message.Photo;
|
||||
|
||||
|
||||
public MessageType Type => Message?.Type ?? MessageType.Unknown;
|
||||
|
||||
public override Message Message => UpdateData?.Message;
|
||||
|
||||
/// <summary>
|
||||
/// Returns the FileId of the first reachable element.
|
||||
/// </summary>
|
||||
public string FileId =>
|
||||
Document?.FileId ??
|
||||
Audio?.FileId ??
|
||||
Video?.FileId ??
|
||||
Photos.FirstOrDefault()?.FileId;
|
||||
|
||||
|
||||
public async Task<InputOnlineFile> DownloadDocument()
|
||||
{
|
||||
var encryptedContent = new MemoryStream();
|
||||
encryptedContent.SetLength(Document.FileSize.Value);
|
||||
var file = await Device.Client.TelegramClient.GetInfoAndDownloadFileAsync(Document.FileId,
|
||||
encryptedContent);
|
||||
|
||||
return new InputOnlineFile(encryptedContent, Document.FileName);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Downloads a file and saves it to the given path.
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
/// <returns></returns>
|
||||
public async Task DownloadDocument(string path)
|
||||
{
|
||||
var file = await Device.Client.TelegramClient.GetFileAsync(Document.FileId);
|
||||
var fs = new FileStream(path, FileMode.Create);
|
||||
await Device.Client.TelegramClient.DownloadFileAsync(file.FilePath, fs);
|
||||
fs.Close();
|
||||
fs.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Downloads the document and returns an byte array.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<byte[]> DownloadRawDocument()
|
||||
{
|
||||
var ms = new MemoryStream();
|
||||
await Device.Client.TelegramClient.GetInfoAndDownloadFileAsync(Document.FileId, ms);
|
||||
return ms.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Downloads a document and returns it as string. (txt,csv,etc) Default encoding ist UTF8.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<string> DownloadRawTextDocument()
|
||||
{
|
||||
return await DownloadRawTextDocument(Encoding.UTF8);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Downloads a document and returns it as string. (txt,csv,etc)
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<string> DownloadRawTextDocument(Encoding encoding)
|
||||
{
|
||||
var ms = new MemoryStream();
|
||||
await Device.Client.TelegramClient.GetInfoAndDownloadFileAsync(Document.FileId, ms);
|
||||
|
||||
ms.Position = 0;
|
||||
|
||||
var sr = new StreamReader(ms, encoding);
|
||||
|
||||
return sr.ReadToEnd();
|
||||
}
|
||||
|
||||
public async Task<InputOnlineFile> DownloadVideo()
|
||||
{
|
||||
var encryptedContent = new MemoryStream();
|
||||
encryptedContent.SetLength(Video.FileSize.Value);
|
||||
var file = await Device.Client.TelegramClient.GetInfoAndDownloadFileAsync(Video.FileId, encryptedContent);
|
||||
|
||||
return new InputOnlineFile(encryptedContent, "");
|
||||
}
|
||||
|
||||
public async Task DownloadVideo(string path)
|
||||
{
|
||||
var file = await Device.Client.TelegramClient.GetFileAsync(Video.FileId);
|
||||
var fs = new FileStream(path, FileMode.Create);
|
||||
await Device.Client.TelegramClient.DownloadFileAsync(file.FilePath, fs);
|
||||
fs.Close();
|
||||
fs.Dispose();
|
||||
}
|
||||
|
||||
public async Task<InputOnlineFile> DownloadAudio()
|
||||
{
|
||||
var encryptedContent = new MemoryStream();
|
||||
encryptedContent.SetLength(Audio.FileSize.Value);
|
||||
var file = await Device.Client.TelegramClient.GetInfoAndDownloadFileAsync(Audio.FileId, encryptedContent);
|
||||
|
||||
return new InputOnlineFile(encryptedContent, "");
|
||||
}
|
||||
|
||||
public async Task DownloadAudio(string path)
|
||||
{
|
||||
var file = await Device.Client.TelegramClient.GetFileAsync(Audio.FileId);
|
||||
var fs = new FileStream(path, FileMode.Create);
|
||||
await Device.Client.TelegramClient.DownloadFileAsync(file.FilePath, fs);
|
||||
fs.Close();
|
||||
fs.Dispose();
|
||||
}
|
||||
|
||||
public async Task<InputOnlineFile> DownloadPhoto(int index)
|
||||
{
|
||||
var photo = Photos[index];
|
||||
var encryptedContent = new MemoryStream();
|
||||
encryptedContent.SetLength(photo.FileSize.Value);
|
||||
var file = await Device.Client.TelegramClient.GetInfoAndDownloadFileAsync(photo.FileId, encryptedContent);
|
||||
|
||||
return new InputOnlineFile(encryptedContent, "");
|
||||
}
|
||||
|
||||
public async Task DownloadPhoto(int index, string path)
|
||||
{
|
||||
var photo = Photos[index];
|
||||
var file = await Device.Client.TelegramClient.GetFileAsync(photo.FileId);
|
||||
var fs = new FileStream(path, FileMode.Create);
|
||||
await Device.Client.TelegramClient.DownloadFileAsync(file.FilePath, fs);
|
||||
fs.Close();
|
||||
fs.Dispose();
|
||||
}
|
||||
}
|
||||
+424
-403
@@ -9,421 +9,442 @@ using TelegramBotBase.Form.Navigation;
|
||||
using TelegramBotBase.Sessions;
|
||||
using static TelegramBotBase.Base.Async;
|
||||
|
||||
namespace TelegramBotBase.Form
|
||||
namespace TelegramBotBase.Form;
|
||||
|
||||
/// <summary>
|
||||
/// Base class for forms
|
||||
/// </summary>
|
||||
public class FormBase : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for forms
|
||||
/// </summary>
|
||||
public class FormBase : IDisposable
|
||||
private static readonly object EvInit = new();
|
||||
|
||||
private static readonly object EvOpened = new();
|
||||
|
||||
private static readonly object EvClosed = new();
|
||||
|
||||
|
||||
public EventHandlerList Events = new();
|
||||
|
||||
|
||||
public FormBase()
|
||||
{
|
||||
Controls = new List<ControlBase>();
|
||||
}
|
||||
|
||||
public NavigationController NavigationController { get; set; }
|
||||
public FormBase(MessageClient client) : this()
|
||||
{
|
||||
Client = client;
|
||||
}
|
||||
|
||||
public DeviceSession Device { get; set; }
|
||||
public NavigationController NavigationController { get; set; }
|
||||
|
||||
public MessageClient Client { get; set; }
|
||||
public DeviceSession Device { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// has this formular already been disposed ?
|
||||
/// </summary>
|
||||
public bool IsDisposed { get; set; }
|
||||
public MessageClient Client { get; set; }
|
||||
|
||||
public List<ControlBase> Controls { get; set; }
|
||||
/// <summary>
|
||||
/// has this formular already been disposed ?
|
||||
/// </summary>
|
||||
public bool IsDisposed { get; set; }
|
||||
|
||||
public List<ControlBase> Controls { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Cleanup
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
Client = null;
|
||||
Device = null;
|
||||
IsDisposed = true;
|
||||
}
|
||||
|
||||
|
||||
public EventHandlerList Events = new EventHandlerList();
|
||||
|
||||
|
||||
private static readonly object EvInit = new object();
|
||||
|
||||
private static readonly object EvOpened = new object();
|
||||
|
||||
private static readonly object EvClosed = new object();
|
||||
|
||||
|
||||
public FormBase()
|
||||
public async Task OnInit(InitEventArgs e)
|
||||
{
|
||||
var handler = Events[EvInit]?.GetInvocationList().Cast<AsyncEventHandler<InitEventArgs>>();
|
||||
if (handler == null)
|
||||
{
|
||||
Controls = new List<ControlBase>();
|
||||
return;
|
||||
}
|
||||
|
||||
public FormBase(MessageClient client) : this()
|
||||
foreach (var h in handler)
|
||||
{
|
||||
this.Client = client;
|
||||
}
|
||||
|
||||
|
||||
public async Task OnInit(InitEventArgs e)
|
||||
{
|
||||
var handler = Events[EvInit]?.GetInvocationList().Cast<AsyncEventHandler<InitEventArgs>>();
|
||||
if (handler == null)
|
||||
return;
|
||||
|
||||
foreach (var h in handler)
|
||||
{
|
||||
await h.InvokeAllAsync(this, e);
|
||||
}
|
||||
}
|
||||
|
||||
///// <summary>
|
||||
///// Will get called at the initialization (once per context)
|
||||
///// </summary>
|
||||
public event AsyncEventHandler<InitEventArgs> Init
|
||||
{
|
||||
add => Events.AddHandler(EvInit, value);
|
||||
remove => Events.RemoveHandler(EvInit, value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public async Task OnOpened(EventArgs e)
|
||||
{
|
||||
var handler = Events[EvOpened]?.GetInvocationList().Cast<AsyncEventHandler<EventArgs>>();
|
||||
if (handler == null)
|
||||
return;
|
||||
|
||||
foreach (var h in handler)
|
||||
{
|
||||
await h.InvokeAllAsync(this, e);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets invoked if gets navigated to this form
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public event AsyncEventHandler<EventArgs> Opened
|
||||
{
|
||||
add => Events.AddHandler(EvOpened, value);
|
||||
remove => Events.RemoveHandler(EvOpened, value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public async Task OnClosed(EventArgs e)
|
||||
{
|
||||
var handler = Events[EvClosed]?.GetInvocationList().Cast<AsyncEventHandler<EventArgs>>();
|
||||
if (handler == null)
|
||||
return;
|
||||
|
||||
foreach (var h in handler)
|
||||
{
|
||||
await h.InvokeAllAsync(this, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Form has been closed (left)
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public event AsyncEventHandler<EventArgs> Closed
|
||||
{
|
||||
add => Events.AddHandler(EvClosed, value);
|
||||
remove => Events.RemoveHandler(EvClosed, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get invoked when a modal child from has been closed.
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <returns></returns>
|
||||
public virtual Task ReturnFromModal(ModalDialog modal)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Pre to form close, cleanup all controls
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Task CloseControls()
|
||||
{
|
||||
foreach (var b in Controls)
|
||||
{
|
||||
b.Cleanup().Wait();
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public virtual Task PreLoad(MessageResult message)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets invoked if a message was sent or an action triggered
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <returns></returns>
|
||||
public virtual async Task LoadControls(MessageResult message)
|
||||
{
|
||||
//Looking for the control by id, if not listened, raise event for all
|
||||
if (message.RawData?.StartsWith("#c") ?? false)
|
||||
{
|
||||
var c = Controls.FirstOrDefault(a => a.ControlId == message.RawData.Split('_')[0]);
|
||||
if (c != null)
|
||||
{
|
||||
await c.Load(message);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var b in Controls)
|
||||
{
|
||||
if (!b.Enabled)
|
||||
continue;
|
||||
|
||||
await b.Load(message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets invoked if the form gets loaded and on every message belongs to this context
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <returns></returns>
|
||||
public virtual Task Load(MessageResult message)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets invoked, when a messages has been edited.
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <returns></returns>
|
||||
public virtual Task Edited(MessageResult message)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets invoked if the user clicked a button.
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <returns></returns>
|
||||
public virtual async Task ActionControls(MessageResult message)
|
||||
{
|
||||
//Looking for the control by id, if not listened, raise event for all
|
||||
if (message.RawData.StartsWith("#c"))
|
||||
{
|
||||
var c = Controls.FirstOrDefault(a => a.ControlId == message.RawData.Split('_')[0]);
|
||||
if (c != null)
|
||||
{
|
||||
await c.Action(message, message.RawData.Split('_')[1]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var b in Controls)
|
||||
{
|
||||
if (!b.Enabled)
|
||||
continue;
|
||||
|
||||
await b.Action(message);
|
||||
|
||||
if (message.Handled)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets invoked if the user has clicked a button.
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <returns></returns>
|
||||
public virtual Task Action(MessageResult message)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets invoked if the user has sent some media (Photo, Audio, Video, Contact, Location, Document)
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <returns></returns>
|
||||
public virtual Task SentData(DataResult message)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets invoked at the end of the cycle to "Render" text, images, buttons, etc...
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <returns></returns>
|
||||
public virtual async Task RenderControls(MessageResult message)
|
||||
{
|
||||
foreach (var b in Controls)
|
||||
{
|
||||
if (!b.Enabled)
|
||||
continue;
|
||||
|
||||
await b.Render(message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets invoked at the end of the cycle to "Render" text, images, buttons, etc...
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <returns></returns>
|
||||
public virtual Task Render(MessageResult message)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Navigates to a new form
|
||||
/// </summary>
|
||||
/// <param name="newForm"></param>
|
||||
/// <returns></returns>
|
||||
public virtual async Task NavigateTo(FormBase newForm, params object[] args)
|
||||
{
|
||||
var ds = Device;
|
||||
if (ds == null)
|
||||
return;
|
||||
|
||||
ds.FormSwitched = true;
|
||||
|
||||
ds.PreviousForm = ds.ActiveForm;
|
||||
|
||||
ds.ActiveForm = newForm;
|
||||
newForm.Client = Client;
|
||||
newForm.Device = ds;
|
||||
|
||||
//Notify prior to close
|
||||
foreach (var b in Controls)
|
||||
{
|
||||
if (!b.Enabled)
|
||||
continue;
|
||||
|
||||
await b.Hidden(true);
|
||||
}
|
||||
|
||||
CloseControls().Wait();
|
||||
|
||||
await OnClosed(EventArgs.Empty);
|
||||
|
||||
await newForm.OnInit(new InitEventArgs(args));
|
||||
|
||||
await newForm.OnOpened(EventArgs.Empty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens this form modal, but don't closes the original ones
|
||||
/// </summary>
|
||||
/// <param name="newForm"></param>
|
||||
/// <returns></returns>
|
||||
public virtual async Task OpenModal(ModalDialog newForm, params object[] args)
|
||||
{
|
||||
var ds = Device;
|
||||
if (ds == null)
|
||||
return;
|
||||
|
||||
var parentForm = this;
|
||||
|
||||
ds.FormSwitched = true;
|
||||
|
||||
ds.PreviousForm = ds.ActiveForm;
|
||||
|
||||
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 Controls)
|
||||
{
|
||||
if (!b.Enabled)
|
||||
continue;
|
||||
|
||||
await b.Hidden(false);
|
||||
}
|
||||
|
||||
await newForm.OnInit(new InitEventArgs(args));
|
||||
|
||||
await newForm.OnOpened(EventArgs.Empty);
|
||||
}
|
||||
|
||||
public Task CloseModal(ModalDialog modalForm, FormBase oldForm)
|
||||
{
|
||||
var ds = Device;
|
||||
if (ds == null)
|
||||
return Task.CompletedTask;
|
||||
|
||||
if (modalForm == null)
|
||||
throw new Exception("No modal form");
|
||||
|
||||
ds.FormSwitched = true;
|
||||
|
||||
ds.PreviousForm = ds.ActiveForm;
|
||||
|
||||
ds.ActiveForm = oldForm;
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a control to the formular and sets its ID and Device.
|
||||
/// </summary>
|
||||
/// <param name="control"></param>
|
||||
public void AddControl(ControlBase control)
|
||||
{
|
||||
//Duplicate check
|
||||
if (Controls.Contains(control))
|
||||
throw new ArgumentException("Control has been already added.");
|
||||
|
||||
control.Id = Controls.Count + 1;
|
||||
control.Device = Device;
|
||||
Controls.Add(control);
|
||||
|
||||
control.Init();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes control from the formular and runs a cleanup on it.
|
||||
/// </summary>
|
||||
/// <param name="control"></param>
|
||||
public void RemoveControl(ControlBase control)
|
||||
{
|
||||
if (!Controls.Contains(control))
|
||||
return;
|
||||
|
||||
control.Cleanup().Wait();
|
||||
|
||||
Controls.Remove(control);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes all controls.
|
||||
/// </summary>
|
||||
public void RemoveAllControls()
|
||||
{
|
||||
foreach(var c in Controls)
|
||||
{
|
||||
c.Cleanup().Wait();
|
||||
|
||||
Controls.Remove(c);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cleanup
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
Client = null;
|
||||
Device = null;
|
||||
IsDisposed = true;
|
||||
await h.InvokeAllAsync(this, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///// <summary>
|
||||
///// Will get called at the initialization (once per context)
|
||||
///// </summary>
|
||||
public event AsyncEventHandler<InitEventArgs> Init
|
||||
{
|
||||
add => Events.AddHandler(EvInit, value);
|
||||
remove => Events.RemoveHandler(EvInit, value);
|
||||
}
|
||||
|
||||
|
||||
public async Task OnOpened(EventArgs e)
|
||||
{
|
||||
var handler = Events[EvOpened]?.GetInvocationList().Cast<AsyncEventHandler<EventArgs>>();
|
||||
if (handler == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var h in handler)
|
||||
{
|
||||
await h.InvokeAllAsync(this, e);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets invoked if gets navigated to this form
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public event AsyncEventHandler<EventArgs> Opened
|
||||
{
|
||||
add => Events.AddHandler(EvOpened, value);
|
||||
remove => Events.RemoveHandler(EvOpened, value);
|
||||
}
|
||||
|
||||
|
||||
public async Task OnClosed(EventArgs e)
|
||||
{
|
||||
var handler = Events[EvClosed]?.GetInvocationList().Cast<AsyncEventHandler<EventArgs>>();
|
||||
if (handler == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var h in handler)
|
||||
{
|
||||
await h.InvokeAllAsync(this, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Form has been closed (left)
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public event AsyncEventHandler<EventArgs> Closed
|
||||
{
|
||||
add => Events.AddHandler(EvClosed, value);
|
||||
remove => Events.RemoveHandler(EvClosed, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get invoked when a modal child from has been closed.
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <returns></returns>
|
||||
public virtual Task ReturnFromModal(ModalDialog modal)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Pre to form close, cleanup all controls
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Task CloseControls()
|
||||
{
|
||||
foreach (var b in Controls)
|
||||
{
|
||||
b.Cleanup().Wait();
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public virtual Task PreLoad(MessageResult message)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets invoked if a message was sent or an action triggered
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <returns></returns>
|
||||
public virtual async Task LoadControls(MessageResult message)
|
||||
{
|
||||
//Looking for the control by id, if not listened, raise event for all
|
||||
if (message.RawData?.StartsWith("#c") ?? false)
|
||||
{
|
||||
var c = Controls.FirstOrDefault(a => a.ControlId == message.RawData.Split('_')[0]);
|
||||
if (c != null)
|
||||
{
|
||||
await c.Load(message);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var b in Controls)
|
||||
{
|
||||
if (!b.Enabled)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
await b.Load(message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets invoked if the form gets loaded and on every message belongs to this context
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <returns></returns>
|
||||
public virtual Task Load(MessageResult message)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets invoked, when a messages has been edited.
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <returns></returns>
|
||||
public virtual Task Edited(MessageResult message)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets invoked if the user clicked a button.
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <returns></returns>
|
||||
public virtual async Task ActionControls(MessageResult message)
|
||||
{
|
||||
//Looking for the control by id, if not listened, raise event for all
|
||||
if (message.RawData.StartsWith("#c"))
|
||||
{
|
||||
var c = Controls.FirstOrDefault(a => a.ControlId == message.RawData.Split('_')[0]);
|
||||
if (c != null)
|
||||
{
|
||||
await c.Action(message, message.RawData.Split('_')[1]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var b in Controls)
|
||||
{
|
||||
if (!b.Enabled)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
await b.Action(message);
|
||||
|
||||
if (message.Handled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets invoked if the user has clicked a button.
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <returns></returns>
|
||||
public virtual Task Action(MessageResult message)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets invoked if the user has sent some media (Photo, Audio, Video, Contact, Location, Document)
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <returns></returns>
|
||||
public virtual Task SentData(DataResult message)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets invoked at the end of the cycle to "Render" text, images, buttons, etc...
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <returns></returns>
|
||||
public virtual async Task RenderControls(MessageResult message)
|
||||
{
|
||||
foreach (var b in Controls)
|
||||
{
|
||||
if (!b.Enabled)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
await b.Render(message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets invoked at the end of the cycle to "Render" text, images, buttons, etc...
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <returns></returns>
|
||||
public virtual Task Render(MessageResult message)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Navigates to a new form
|
||||
/// </summary>
|
||||
/// <param name="newForm"></param>
|
||||
/// <returns></returns>
|
||||
public virtual async Task NavigateTo(FormBase newForm, params object[] args)
|
||||
{
|
||||
var ds = Device;
|
||||
if (ds == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ds.FormSwitched = true;
|
||||
|
||||
ds.PreviousForm = ds.ActiveForm;
|
||||
|
||||
ds.ActiveForm = newForm;
|
||||
newForm.Client = Client;
|
||||
newForm.Device = ds;
|
||||
|
||||
//Notify prior to close
|
||||
foreach (var b in Controls)
|
||||
{
|
||||
if (!b.Enabled)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
await b.Hidden(true);
|
||||
}
|
||||
|
||||
CloseControls().Wait();
|
||||
|
||||
await OnClosed(EventArgs.Empty);
|
||||
|
||||
await newForm.OnInit(new InitEventArgs(args));
|
||||
|
||||
await newForm.OnOpened(EventArgs.Empty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens this form modal, but don't closes the original ones
|
||||
/// </summary>
|
||||
/// <param name="newForm"></param>
|
||||
/// <returns></returns>
|
||||
public virtual async Task OpenModal(ModalDialog newForm, params object[] args)
|
||||
{
|
||||
var ds = Device;
|
||||
if (ds == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var parentForm = this;
|
||||
|
||||
ds.FormSwitched = true;
|
||||
|
||||
ds.PreviousForm = ds.ActiveForm;
|
||||
|
||||
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 Controls)
|
||||
{
|
||||
if (!b.Enabled)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
await b.Hidden(false);
|
||||
}
|
||||
|
||||
await newForm.OnInit(new InitEventArgs(args));
|
||||
|
||||
await newForm.OnOpened(EventArgs.Empty);
|
||||
}
|
||||
|
||||
public Task CloseModal(ModalDialog modalForm, FormBase oldForm)
|
||||
{
|
||||
var ds = Device;
|
||||
if (ds == null)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
if (modalForm == null)
|
||||
{
|
||||
throw new Exception("No modal form");
|
||||
}
|
||||
|
||||
ds.FormSwitched = true;
|
||||
|
||||
ds.PreviousForm = ds.ActiveForm;
|
||||
|
||||
ds.ActiveForm = oldForm;
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a control to the formular and sets its ID and Device.
|
||||
/// </summary>
|
||||
/// <param name="control"></param>
|
||||
public void AddControl(ControlBase control)
|
||||
{
|
||||
//Duplicate check
|
||||
if (Controls.Contains(control))
|
||||
{
|
||||
throw new ArgumentException("Control has been already added.");
|
||||
}
|
||||
|
||||
control.Id = Controls.Count + 1;
|
||||
control.Device = Device;
|
||||
Controls.Add(control);
|
||||
|
||||
control.Init();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes control from the formular and runs a cleanup on it.
|
||||
/// </summary>
|
||||
/// <param name="control"></param>
|
||||
public void RemoveControl(ControlBase control)
|
||||
{
|
||||
if (!Controls.Contains(control))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
control.Cleanup().Wait();
|
||||
|
||||
Controls.Remove(control);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes all controls.
|
||||
/// </summary>
|
||||
public void RemoveAllControls()
|
||||
{
|
||||
foreach (var c in Controls)
|
||||
{
|
||||
c.Cleanup().Wait();
|
||||
|
||||
Controls.Remove(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,193 +10,186 @@ using Telegram.Bot.Exceptions;
|
||||
using Telegram.Bot.Extensions.Polling;
|
||||
using Telegram.Bot.Types;
|
||||
|
||||
namespace TelegramBotBase.Base
|
||||
namespace TelegramBotBase.Base;
|
||||
|
||||
/// <summary>
|
||||
/// Base class for message handling
|
||||
/// </summary>
|
||||
public class MessageClient
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for message handling
|
||||
/// </summary>
|
||||
public class MessageClient
|
||||
private static readonly object EvOnMessageLoop = new();
|
||||
|
||||
private static object __evOnMessage = new();
|
||||
|
||||
private static object __evOnMessageEdit = new();
|
||||
|
||||
private static object __evCallbackQuery = new();
|
||||
|
||||
private CancellationTokenSource _cancellationTokenSource;
|
||||
|
||||
|
||||
public MessageClient(string apiKey)
|
||||
{
|
||||
ApiKey = apiKey;
|
||||
TelegramClient = new TelegramBotClient(apiKey);
|
||||
|
||||
|
||||
public string ApiKey { get; set; }
|
||||
|
||||
public ITelegramBotClient TelegramClient { get; set; }
|
||||
|
||||
private EventHandlerList Events { get; set; } = new EventHandlerList();
|
||||
|
||||
private static readonly object EvOnMessageLoop = new object();
|
||||
|
||||
private static object __evOnMessage = new object();
|
||||
|
||||
private static object __evOnMessageEdit = new object();
|
||||
|
||||
private static object __evCallbackQuery = new object();
|
||||
|
||||
private CancellationTokenSource _cancellationTokenSource;
|
||||
|
||||
|
||||
public MessageClient(string apiKey)
|
||||
{
|
||||
this.ApiKey = apiKey;
|
||||
TelegramClient = new TelegramBotClient(apiKey);
|
||||
|
||||
Prepare();
|
||||
}
|
||||
|
||||
public MessageClient(string apiKey, HttpClient proxy)
|
||||
{
|
||||
this.ApiKey = apiKey;
|
||||
TelegramClient = new TelegramBotClient(apiKey, proxy);
|
||||
|
||||
|
||||
Prepare();
|
||||
}
|
||||
|
||||
|
||||
|
||||
public MessageClient(string apiKey, Uri proxyUrl, NetworkCredential credential = null)
|
||||
{
|
||||
this.ApiKey = apiKey;
|
||||
|
||||
var proxy = new WebProxy(proxyUrl)
|
||||
{
|
||||
Credentials = credential
|
||||
};
|
||||
|
||||
var httpClient = new HttpClient(
|
||||
new HttpClientHandler { Proxy = proxy, UseProxy = true }
|
||||
);
|
||||
|
||||
TelegramClient = new TelegramBotClient(apiKey, httpClient);
|
||||
|
||||
Prepare();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the client with a proxy
|
||||
/// </summary>
|
||||
/// <param name="apiKey"></param>
|
||||
/// <param name="proxyHost">i.e. 127.0.0.1</param>
|
||||
/// <param name="proxyPort">i.e. 10000</param>
|
||||
public MessageClient(string apiKey, string proxyHost, int proxyPort)
|
||||
{
|
||||
this.ApiKey = apiKey;
|
||||
|
||||
var proxy = new WebProxy(proxyHost, proxyPort);
|
||||
|
||||
var httpClient = new HttpClient(
|
||||
new HttpClientHandler { Proxy = proxy, UseProxy = true }
|
||||
);
|
||||
|
||||
TelegramClient = new TelegramBotClient(apiKey, httpClient);
|
||||
|
||||
Prepare();
|
||||
}
|
||||
|
||||
|
||||
|
||||
public MessageClient(string apiKey, TelegramBotClient client)
|
||||
{
|
||||
this.ApiKey = apiKey;
|
||||
TelegramClient = client;
|
||||
|
||||
Prepare();
|
||||
}
|
||||
|
||||
|
||||
public void Prepare()
|
||||
{
|
||||
TelegramClient.Timeout = new TimeSpan(0, 0, 30);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void StartReceiving()
|
||||
{
|
||||
_cancellationTokenSource = new CancellationTokenSource();
|
||||
|
||||
var receiverOptions = new ReceiverOptions();
|
||||
|
||||
TelegramClient.StartReceiving(HandleUpdateAsync, HandleErrorAsync, receiverOptions, _cancellationTokenSource.Token);
|
||||
}
|
||||
|
||||
public void StopReceiving()
|
||||
{
|
||||
_cancellationTokenSource.Cancel();
|
||||
}
|
||||
|
||||
|
||||
public Task HandleUpdateAsync(ITelegramBotClient botClient, Update update, CancellationToken cancellationToken)
|
||||
{
|
||||
OnMessageLoop(new UpdateResult(update, null));
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task HandleErrorAsync(ITelegramBotClient botClient, Exception exception, CancellationToken cancellationToken)
|
||||
{
|
||||
if (exception is ApiRequestException exApi)
|
||||
{
|
||||
Console.WriteLine($"Telegram API Error:\n[{exApi.ErrorCode}]\n{exApi.Message}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine(exception.ToString());
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// This will return the current list of bot commands.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<BotCommand[]> GetBotCommands(BotCommandScope scope = null, string languageCode = null)
|
||||
{
|
||||
return await TelegramClient.GetMyCommandsAsync(scope, languageCode);
|
||||
}
|
||||
|
||||
|
||||
/// <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, BotCommandScope scope = null, string languageCode = null)
|
||||
{
|
||||
await TelegramClient.SetMyCommandsAsync(botcommands, scope, languageCode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This will delete the current list of bot commands.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task DeleteBotCommands(BotCommandScope scope = null, string languageCode = null)
|
||||
{
|
||||
await TelegramClient.DeleteMyCommandsAsync(scope, languageCode);
|
||||
}
|
||||
|
||||
|
||||
#region "Events"
|
||||
|
||||
|
||||
|
||||
public event Async.AsyncEventHandler<UpdateResult> MessageLoop
|
||||
{
|
||||
add => Events.AddHandler(EvOnMessageLoop, value);
|
||||
remove => Events.RemoveHandler(EvOnMessageLoop, value);
|
||||
}
|
||||
|
||||
public void OnMessageLoop(UpdateResult update)
|
||||
{
|
||||
(Events[EvOnMessageLoop] as Async.AsyncEventHandler<UpdateResult>)?.Invoke(this, update);
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
Prepare();
|
||||
}
|
||||
}
|
||||
|
||||
public MessageClient(string apiKey, HttpClient proxy)
|
||||
{
|
||||
ApiKey = apiKey;
|
||||
TelegramClient = new TelegramBotClient(apiKey, proxy);
|
||||
|
||||
|
||||
Prepare();
|
||||
}
|
||||
|
||||
|
||||
public MessageClient(string apiKey, Uri proxyUrl, NetworkCredential credential = null)
|
||||
{
|
||||
ApiKey = apiKey;
|
||||
|
||||
var proxy = new WebProxy(proxyUrl)
|
||||
{
|
||||
Credentials = credential
|
||||
};
|
||||
|
||||
var httpClient = new HttpClient(
|
||||
new HttpClientHandler { Proxy = proxy, UseProxy = true }
|
||||
);
|
||||
|
||||
TelegramClient = new TelegramBotClient(apiKey, httpClient);
|
||||
|
||||
Prepare();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the client with a proxy
|
||||
/// </summary>
|
||||
/// <param name="apiKey"></param>
|
||||
/// <param name="proxyHost">i.e. 127.0.0.1</param>
|
||||
/// <param name="proxyPort">i.e. 10000</param>
|
||||
public MessageClient(string apiKey, string proxyHost, int proxyPort)
|
||||
{
|
||||
ApiKey = apiKey;
|
||||
|
||||
var proxy = new WebProxy(proxyHost, proxyPort);
|
||||
|
||||
var httpClient = new HttpClient(
|
||||
new HttpClientHandler { Proxy = proxy, UseProxy = true }
|
||||
);
|
||||
|
||||
TelegramClient = new TelegramBotClient(apiKey, httpClient);
|
||||
|
||||
Prepare();
|
||||
}
|
||||
|
||||
|
||||
public MessageClient(string apiKey, TelegramBotClient client)
|
||||
{
|
||||
ApiKey = apiKey;
|
||||
TelegramClient = client;
|
||||
|
||||
Prepare();
|
||||
}
|
||||
|
||||
|
||||
public string ApiKey { get; set; }
|
||||
|
||||
public ITelegramBotClient TelegramClient { get; set; }
|
||||
|
||||
private EventHandlerList Events { get; } = new();
|
||||
|
||||
|
||||
public void Prepare()
|
||||
{
|
||||
TelegramClient.Timeout = new TimeSpan(0, 0, 30);
|
||||
}
|
||||
|
||||
|
||||
public void StartReceiving()
|
||||
{
|
||||
_cancellationTokenSource = new CancellationTokenSource();
|
||||
|
||||
var receiverOptions = new ReceiverOptions();
|
||||
|
||||
TelegramClient.StartReceiving(HandleUpdateAsync, HandleErrorAsync, receiverOptions,
|
||||
_cancellationTokenSource.Token);
|
||||
}
|
||||
|
||||
public void StopReceiving()
|
||||
{
|
||||
_cancellationTokenSource.Cancel();
|
||||
}
|
||||
|
||||
|
||||
public Task HandleUpdateAsync(ITelegramBotClient botClient, Update update, CancellationToken cancellationToken)
|
||||
{
|
||||
OnMessageLoop(new UpdateResult(update, null));
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task HandleErrorAsync(ITelegramBotClient botClient, Exception exception,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
if (exception is ApiRequestException exApi)
|
||||
{
|
||||
Console.WriteLine($"Telegram API Error:\n[{exApi.ErrorCode}]\n{exApi.Message}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine(exception.ToString());
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// This will return the current list of bot commands.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<BotCommand[]> GetBotCommands(BotCommandScope scope = null, string languageCode = null)
|
||||
{
|
||||
return await TelegramClient.GetMyCommandsAsync(scope, languageCode);
|
||||
}
|
||||
|
||||
|
||||
/// <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, BotCommandScope scope = null,
|
||||
string languageCode = null)
|
||||
{
|
||||
await TelegramClient.SetMyCommandsAsync(botcommands, scope, languageCode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This will delete the current list of bot commands.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task DeleteBotCommands(BotCommandScope scope = null, string languageCode = null)
|
||||
{
|
||||
await TelegramClient.DeleteMyCommandsAsync(scope, languageCode);
|
||||
}
|
||||
|
||||
|
||||
#region "Events"
|
||||
|
||||
public event Async.AsyncEventHandler<UpdateResult> MessageLoop
|
||||
{
|
||||
add => Events.AddHandler(EvOnMessageLoop, value);
|
||||
remove => Events.RemoveHandler(EvOnMessageLoop, value);
|
||||
}
|
||||
|
||||
public void OnMessageLoop(UpdateResult update)
|
||||
{
|
||||
(Events[EvOnMessageLoop] as Async.AsyncEventHandler<UpdateResult>)?.Invoke(this, update);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -5,136 +5,134 @@ using Newtonsoft.Json;
|
||||
using Telegram.Bot.Types;
|
||||
using Telegram.Bot.Types.Enums;
|
||||
|
||||
namespace TelegramBotBase.Base
|
||||
namespace TelegramBotBase.Base;
|
||||
|
||||
public class MessageResult : ResultBase
|
||||
{
|
||||
public class MessageResult : ResultBase
|
||||
internal MessageResult()
|
||||
{
|
||||
}
|
||||
|
||||
public Update UpdateData { get; set; }
|
||||
public MessageResult(Update update)
|
||||
{
|
||||
UpdateData = update;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the Device/ChatId
|
||||
/// </summary>
|
||||
public override long DeviceId =>
|
||||
UpdateData?.Message?.Chat?.Id
|
||||
?? UpdateData?.EditedMessage?.Chat.Id
|
||||
?? UpdateData?.CallbackQuery.Message?.Chat.Id
|
||||
?? Device?.DeviceId
|
||||
?? 0;
|
||||
public Update UpdateData { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The message id
|
||||
/// </summary>
|
||||
public new int MessageId =>
|
||||
UpdateData?.Message?.MessageId
|
||||
?? Message?.MessageId
|
||||
?? UpdateData?.CallbackQuery?.Message?.MessageId
|
||||
?? 0;
|
||||
/// <summary>
|
||||
/// Returns the Device/ChatId
|
||||
/// </summary>
|
||||
public override long DeviceId =>
|
||||
UpdateData?.Message?.Chat?.Id
|
||||
?? UpdateData?.EditedMessage?.Chat.Id
|
||||
?? UpdateData?.CallbackQuery.Message?.Chat.Id
|
||||
?? Device?.DeviceId
|
||||
?? 0;
|
||||
|
||||
public string Command => UpdateData?.Message?.Text ?? "";
|
||||
/// <summary>
|
||||
/// The message id
|
||||
/// </summary>
|
||||
public new int MessageId =>
|
||||
UpdateData?.Message?.MessageId
|
||||
?? Message?.MessageId
|
||||
?? UpdateData?.CallbackQuery?.Message?.MessageId
|
||||
?? 0;
|
||||
|
||||
public string MessageText => UpdateData?.Message?.Text ?? "";
|
||||
public string Command => UpdateData?.Message?.Text ?? "";
|
||||
|
||||
public MessageType MessageType => Message?.Type ?? MessageType.Unknown;
|
||||
public string MessageText => UpdateData?.Message?.Text ?? "";
|
||||
|
||||
/// <summary>
|
||||
/// Is this an action ? (i.e. button click)
|
||||
/// </summary>
|
||||
public bool IsAction => (UpdateData.CallbackQuery != null);
|
||||
public MessageType MessageType => Message?.Type ?? MessageType.Unknown;
|
||||
|
||||
/// <summary>
|
||||
/// Is this a command ? Starts with a slash '/' and a command
|
||||
/// </summary>
|
||||
public bool IsBotCommand => (MessageText.StartsWith("/"));
|
||||
/// <summary>
|
||||
/// Is this an action ? (i.e. button click)
|
||||
/// </summary>
|
||||
public bool IsAction => UpdateData.CallbackQuery != null;
|
||||
|
||||
/// <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> BotCommandParameters
|
||||
/// <summary>
|
||||
/// Is this a command ? Starts with a slash '/' and a command
|
||||
/// </summary>
|
||||
public bool IsBotCommand => MessageText.StartsWith("/");
|
||||
|
||||
/// <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> BotCommandParameters
|
||||
{
|
||||
get
|
||||
{
|
||||
get
|
||||
if (!IsBotCommand)
|
||||
{
|
||||
if (!IsBotCommand)
|
||||
return new List<string>();
|
||||
|
||||
//Split by empty space and skip first entry (command itself), return as list
|
||||
return MessageText.Split(' ').Skip(1).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns just the command (i.e. /start 1 2 3 => /start)
|
||||
/// </summary>
|
||||
public string BotCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!IsBotCommand)
|
||||
return null;
|
||||
|
||||
return 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 => UpdateData?.CallbackQuery?.Data;
|
||||
|
||||
public T GetData<T>()
|
||||
where T : class
|
||||
{
|
||||
T cd = null;
|
||||
try
|
||||
{
|
||||
cd = JsonConvert.DeserializeObject<T>(RawData);
|
||||
|
||||
return cd;
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
return new List<string>();
|
||||
}
|
||||
|
||||
return null;
|
||||
//Split by empty space and skip first entry (command itself), return as list
|
||||
return MessageText.Split(' ').Skip(1).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Confirm incomming action (i.e. Button click)
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <returns></returns>
|
||||
public async Task ConfirmAction(string message = "", bool showAlert = false, string urlToOpen = null)
|
||||
/// <summary>
|
||||
/// Returns just the command (i.e. /start 1 2 3 => /start)
|
||||
/// </summary>
|
||||
public string BotCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
await Device.ConfirmAction(UpdateData.CallbackQuery.Id, message, showAlert, urlToOpen);
|
||||
}
|
||||
|
||||
public override async Task DeleteMessage()
|
||||
{
|
||||
try
|
||||
if (!IsBotCommand)
|
||||
{
|
||||
await base.DeleteMessage(MessageId);
|
||||
return null;
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
}
|
||||
return MessageText.Split(' ')[0];
|
||||
}
|
||||
}
|
||||
|
||||
internal MessageResult()
|
||||
/// <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 => UpdateData?.CallbackQuery?.Data;
|
||||
|
||||
public T GetData<T>()
|
||||
where T : class
|
||||
{
|
||||
T cd = null;
|
||||
try
|
||||
{
|
||||
cd = JsonConvert.DeserializeObject<T>(RawData);
|
||||
|
||||
return cd;
|
||||
}
|
||||
|
||||
public MessageResult(Update update)
|
||||
catch
|
||||
{
|
||||
UpdateData = update;
|
||||
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Confirm incomming action (i.e. Button click)
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <returns></returns>
|
||||
public async Task ConfirmAction(string message = "", bool showAlert = false, string urlToOpen = null)
|
||||
{
|
||||
await Device.ConfirmAction(UpdateData.CallbackQuery.Id, message, showAlert, urlToOpen);
|
||||
}
|
||||
|
||||
public override async Task DeleteMessage()
|
||||
{
|
||||
try
|
||||
{
|
||||
await base.DeleteMessage(MessageId);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,48 +4,42 @@ using Telegram.Bot;
|
||||
using Telegram.Bot.Types;
|
||||
using TelegramBotBase.Sessions;
|
||||
|
||||
namespace TelegramBotBase.Base
|
||||
namespace TelegramBotBase.Base;
|
||||
|
||||
public class ResultBase : EventArgs
|
||||
{
|
||||
public class ResultBase : EventArgs
|
||||
public DeviceSession Device { get; set; }
|
||||
|
||||
public virtual long DeviceId { get; set; }
|
||||
|
||||
public int MessageId => Message.MessageId;
|
||||
|
||||
public virtual Message Message { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Deletes the current message
|
||||
/// </summary>
|
||||
/// <param name="messageId"></param>
|
||||
/// <returns></returns>
|
||||
public virtual async Task DeleteMessage()
|
||||
{
|
||||
public DeviceSession Device
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public virtual long DeviceId { get; set; }
|
||||
|
||||
public int MessageId => Message.MessageId;
|
||||
|
||||
public virtual Message Message { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Deletes the current message
|
||||
/// </summary>
|
||||
/// <param name="messageId"></param>
|
||||
/// <returns></returns>
|
||||
public virtual async Task DeleteMessage()
|
||||
{
|
||||
await DeleteMessage(MessageId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///Deletes the current message or the given one.
|
||||
/// </summary>
|
||||
/// <param name="messageId"></param>
|
||||
/// <returns></returns>
|
||||
public virtual async Task DeleteMessage(int messageId = -1)
|
||||
{
|
||||
try
|
||||
{
|
||||
await Device.Client.TelegramClient.DeleteMessageAsync(DeviceId, (messageId == -1 ? MessageId : messageId));
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
await DeleteMessage(MessageId);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes the current message or the given one.
|
||||
/// </summary>
|
||||
/// <param name="messageId"></param>
|
||||
/// <returns></returns>
|
||||
public virtual async Task DeleteMessage(int messageId = -1)
|
||||
{
|
||||
try
|
||||
{
|
||||
await Device.Client.TelegramClient.DeleteMessageAsync(DeviceId,
|
||||
messageId == -1 ? MessageId : messageId);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,32 +1,24 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace TelegramBotBase.Base
|
||||
namespace TelegramBotBase.Base;
|
||||
|
||||
public class StateContainer
|
||||
{
|
||||
public class StateContainer
|
||||
public 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()
|
||||
{
|
||||
States = new List<StateEntry>();
|
||||
}
|
||||
|
||||
States = new List<StateEntry>();
|
||||
}
|
||||
}
|
||||
|
||||
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(); }
|
||||
}
|
||||
}
|
||||
@@ -1,41 +1,38 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace TelegramBotBase.Base
|
||||
namespace TelegramBotBase.Base;
|
||||
|
||||
[DebuggerDisplay("Device: {DeviceId}, {FormUri}")]
|
||||
public class StateEntry
|
||||
{
|
||||
|
||||
[DebuggerDisplay("Device: {DeviceId}, {FormUri}")]
|
||||
public class StateEntry
|
||||
public 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()
|
||||
{
|
||||
Values = new Dictionary<string, object>();
|
||||
}
|
||||
|
||||
Values = new Dictionary<string, object>();
|
||||
}
|
||||
}
|
||||
|
||||
/// <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; }
|
||||
}
|
||||
@@ -1,35 +1,31 @@
|
||||
using Telegram.Bot.Types;
|
||||
using TelegramBotBase.Sessions;
|
||||
|
||||
namespace TelegramBotBase.Base
|
||||
namespace TelegramBotBase.Base;
|
||||
|
||||
public class UpdateResult : ResultBase
|
||||
{
|
||||
public class UpdateResult : ResultBase
|
||||
public UpdateResult(Update rawData, DeviceSession device)
|
||||
{
|
||||
public UpdateResult(Update rawData, DeviceSession device)
|
||||
{
|
||||
RawData = rawData;
|
||||
Device = device;
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the Device/ChatId
|
||||
/// </summary>
|
||||
public override long DeviceId =>
|
||||
RawData?.Message?.Chat?.Id
|
||||
?? RawData?.CallbackQuery?.Message?.Chat?.Id
|
||||
?? Device?.DeviceId
|
||||
?? 0;
|
||||
|
||||
public Update RawData { get; set; }
|
||||
|
||||
public override Message Message =>
|
||||
RawData?.Message
|
||||
?? RawData?.EditedMessage
|
||||
?? RawData?.ChannelPost
|
||||
?? RawData?.EditedChannelPost
|
||||
?? RawData?.CallbackQuery?.Message;
|
||||
RawData = rawData;
|
||||
Device = device;
|
||||
}
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns the Device/ChatId
|
||||
/// </summary>
|
||||
public override long DeviceId =>
|
||||
RawData?.Message?.Chat?.Id
|
||||
?? RawData?.CallbackQuery?.Message?.Chat?.Id
|
||||
?? Device?.DeviceId
|
||||
?? 0;
|
||||
|
||||
public Update RawData { get; set; }
|
||||
|
||||
public override Message Message =>
|
||||
RawData?.Message
|
||||
?? RawData?.EditedMessage
|
||||
?? RawData?.ChannelPost
|
||||
?? RawData?.EditedChannelPost
|
||||
?? RawData?.CallbackQuery?.Message;
|
||||
}
|
||||
+390
-394
@@ -2,413 +2,409 @@
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Telegram.Bot;
|
||||
using Telegram.Bot.Exceptions;
|
||||
using Telegram.Bot.Types;
|
||||
using Telegram.Bot.Types.Enums;
|
||||
using TelegramBotBase.Args;
|
||||
using TelegramBotBase.Attributes;
|
||||
using TelegramBotBase.Base;
|
||||
using TelegramBotBase.Enums;
|
||||
using TelegramBotBase.MessageLoops;
|
||||
using TelegramBotBase.Form;
|
||||
using TelegramBotBase.Interfaces;
|
||||
using TelegramBotBase.Sessions;
|
||||
using Console = TelegramBotBase.Tools.Console;
|
||||
|
||||
namespace TelegramBotBase
|
||||
namespace TelegramBotBase;
|
||||
|
||||
/// <summary>
|
||||
/// Bot base class for full Device/Context and Messagehandling
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public class BotBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Bot base class for full Device/Context and Messagehandling
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public class BotBase
|
||||
public BotBase()
|
||||
{
|
||||
public MessageClient Client { get; set; }
|
||||
SystemSettings = new Dictionary<ESettings, uint>();
|
||||
|
||||
/// <summary>
|
||||
/// Your TelegramBot APIKey
|
||||
/// </summary>
|
||||
public string ApiKey { get; set; } = "";
|
||||
SetSetting(ESettings.MaxNumberOfRetries, 5);
|
||||
SetSetting(ESettings.NavigationMaximum, 10);
|
||||
SetSetting(ESettings.LogAllMessages, false);
|
||||
SetSetting(ESettings.SkipAllMessages, false);
|
||||
SetSetting(ESettings.SaveSessionsOnConsoleExit, false);
|
||||
|
||||
/// <summary>
|
||||
/// List of all running/active sessions
|
||||
/// </summary>
|
||||
public SessionBase Sessions { get; set; }
|
||||
BotCommandScopes = new Dictionary<BotCommandScope, List<BotCommand>>();
|
||||
|
||||
/// <summary>
|
||||
/// Contains System commands which will be available at everytime and didnt get passed to forms, i.e. /start
|
||||
/// </summary>
|
||||
public Dictionary<BotCommandScope, List<BotCommand>> BotCommandScopes { get; set; } = new Dictionary<BotCommandScope, List<BotCommand>>();
|
||||
|
||||
|
||||
#region "Events"
|
||||
|
||||
private readonly EventHandlerList _events = new EventHandlerList();
|
||||
|
||||
private static readonly object EvSessionBegins = new object();
|
||||
|
||||
private static readonly object EvMessage = new object();
|
||||
|
||||
private static object __evSystemCall = new object();
|
||||
|
||||
public delegate Task BotCommandEventHandler(object sender, BotCommandEventArgs e);
|
||||
|
||||
private static readonly object EvException = new object();
|
||||
|
||||
private static readonly object EvUnhandledCall = new object();
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Enable the SessionState (you need to implement on call forms the IStateForm interface)
|
||||
/// </summary>
|
||||
public IStateMachine StateMachine { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Offers functionality to manage the creation process of the start form.
|
||||
/// </summary>
|
||||
public IStartFormFactory StartFormFactory { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Contains the message loop factory, which cares about "message-management."
|
||||
/// </summary>
|
||||
public IMessageLoopFactory MessageLoopFactory { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// All internal used settings.
|
||||
/// </summary>
|
||||
public Dictionary<ESettings, uint> SystemSettings { get; private set; }
|
||||
|
||||
public BotBase()
|
||||
Sessions = new SessionBase
|
||||
{
|
||||
SystemSettings = new Dictionary<ESettings, uint>();
|
||||
|
||||
SetSetting(ESettings.MaxNumberOfRetries, 5);
|
||||
SetSetting(ESettings.NavigationMaximum, 10);
|
||||
SetSetting(ESettings.LogAllMessages, false);
|
||||
SetSetting(ESettings.SkipAllMessages, false);
|
||||
SetSetting(ESettings.SaveSessionsOnConsoleExit, false);
|
||||
|
||||
BotCommandScopes = new Dictionary<BotCommandScope, List<BotCommand>>();
|
||||
|
||||
Sessions = new SessionBase
|
||||
{
|
||||
BotBase = this
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Start your Bot
|
||||
/// </summary>
|
||||
public void Start()
|
||||
{
|
||||
if (Client == null)
|
||||
return;
|
||||
|
||||
Client.MessageLoop += Client_MessageLoop;
|
||||
|
||||
|
||||
if (StateMachine != null)
|
||||
{
|
||||
Sessions.LoadSessionStates(StateMachine);
|
||||
}
|
||||
|
||||
//Enable auto session saving
|
||||
if (GetSetting(ESettings.SaveSessionsOnConsoleExit, false))
|
||||
{
|
||||
Tools.Console.SetHandler(() =>
|
||||
{
|
||||
Sessions.SaveSessionStates();
|
||||
});
|
||||
}
|
||||
|
||||
DeviceSession.MaxNumberOfRetries = GetSetting(ESettings.MaxNumberOfRetries, 5);
|
||||
|
||||
Client.StartReceiving();
|
||||
}
|
||||
|
||||
|
||||
private async Task Client_MessageLoop(object sender, UpdateResult e)
|
||||
{
|
||||
var ds = Sessions.GetSession(e.DeviceId);
|
||||
if (ds == null)
|
||||
{
|
||||
ds = Sessions.StartSession(e.DeviceId).GetAwaiter().GetResult();
|
||||
e.Device = ds;
|
||||
ds.LastMessage = e.RawData.Message;
|
||||
|
||||
OnSessionBegins(new SessionBeginEventArgs(e.DeviceId, ds));
|
||||
}
|
||||
|
||||
var mr = new MessageResult(e.RawData);
|
||||
|
||||
var i = 0;
|
||||
|
||||
//Should formulars get navigated (allow maximum of 10, to dont get loops)
|
||||
do
|
||||
{
|
||||
i++;
|
||||
|
||||
//Reset navigation
|
||||
ds.FormSwitched = false;
|
||||
|
||||
await MessageLoopFactory.MessageLoop(this, ds, e, mr);
|
||||
|
||||
mr.IsFirstHandler = false;
|
||||
|
||||
} while (ds.FormSwitched && i < GetSetting(ESettings.NavigationMaximum, 10));
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Stop your Bot
|
||||
/// </summary>
|
||||
public void Stop()
|
||||
{
|
||||
if (Client == null)
|
||||
return;
|
||||
|
||||
Client.MessageLoop -= Client_MessageLoop;
|
||||
|
||||
|
||||
Client.StopReceiving();
|
||||
|
||||
Sessions.SaveSessionStates();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send a message to all active Sessions.
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <returns></returns>
|
||||
public async Task SentToAll(string message)
|
||||
{
|
||||
if (Client == null)
|
||||
return;
|
||||
|
||||
foreach (var s in Sessions.SessionList)
|
||||
{
|
||||
await Client.TelegramClient.SendTextMessageAsync(s.Key, message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// This will invoke the full message loop for the device even when no "userevent" like message or action has been raised.
|
||||
/// </summary>
|
||||
/// <param name="deviceId">Contains the device/chat id of the device to update.</param>
|
||||
public async Task InvokeMessageLoop(long deviceId)
|
||||
{
|
||||
var mr = new MessageResult
|
||||
{
|
||||
UpdateData = new Update()
|
||||
{
|
||||
Message = new Message()
|
||||
}
|
||||
};
|
||||
|
||||
await InvokeMessageLoop(deviceId, mr);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This will invoke the full message loop for the device even when no "userevent" like message or action has been raised.
|
||||
/// </summary>
|
||||
/// <param name="deviceId">Contains the device/chat id of the device to update.</param>
|
||||
/// <param name="e"></param>
|
||||
public async Task InvokeMessageLoop(long deviceId, MessageResult e)
|
||||
{
|
||||
try
|
||||
{
|
||||
var ds = Sessions.GetSession(deviceId);
|
||||
e.Device = ds;
|
||||
|
||||
await MessageLoopFactory.MessageLoop(this, ds, new UpdateResult(e.UpdateData, ds), e);
|
||||
//await Client_Loop(this, e);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
var ds = Sessions.GetSession(deviceId);
|
||||
OnException(new SystemExceptionEventArgs(e.Message.Text, deviceId, ds, ex));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Will get invoke on an unhandled call.
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
public void MessageLoopFactory_UnhandledCall(object sender, UnhandledCallEventArgs e)
|
||||
{
|
||||
OnUnhandledCall(e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method will update all local created bot commands to the botfather.
|
||||
/// </summary>
|
||||
public async Task UploadBotCommands()
|
||||
{
|
||||
foreach (var bs in BotCommandScopes)
|
||||
{
|
||||
if(bs.Value !=null)
|
||||
{
|
||||
await Client.SetBotCommands(bs.Value, bs.Key);
|
||||
}
|
||||
else
|
||||
{
|
||||
await Client.DeleteBotCommands(bs.Key);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Searching if parameter is a known command in all configured BotCommandScopes.
|
||||
/// </summary>
|
||||
/// <param name="command"></param>
|
||||
/// <returns></returns>
|
||||
public bool IsKnownBotCommand(string command)
|
||||
{
|
||||
foreach (var scope in BotCommandScopes)
|
||||
{
|
||||
if (scope.Value.Any(a => "/" + a.Command == command))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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 (!SystemSettings.ContainsKey(set))
|
||||
return defaultValue;
|
||||
|
||||
return 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 (!SystemSettings.ContainsKey(set))
|
||||
return defaultValue;
|
||||
|
||||
return SystemSettings[set] == 0u ? false : true;
|
||||
}
|
||||
|
||||
#region "Events"
|
||||
|
||||
/// <summary>
|
||||
/// Will be called if a session/context gets started
|
||||
/// </summary>
|
||||
|
||||
public event EventHandler<SessionBeginEventArgs> SessionBegins
|
||||
{
|
||||
add => _events.AddHandler(EvSessionBegins, value);
|
||||
remove => _events.RemoveHandler(EvSessionBegins, value);
|
||||
}
|
||||
|
||||
public void OnSessionBegins(SessionBeginEventArgs e)
|
||||
{
|
||||
(_events[EvSessionBegins] as EventHandler<SessionBeginEventArgs>)?.Invoke(this, e);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Will be called on incomming message
|
||||
/// </summary>
|
||||
public event EventHandler<MessageIncomeEventArgs> Message
|
||||
{
|
||||
add => _events.AddHandler(EvMessage, value);
|
||||
remove => _events.RemoveHandler(EvMessage, value);
|
||||
}
|
||||
|
||||
public void OnMessage(MessageIncomeEventArgs e)
|
||||
{
|
||||
(_events[EvMessage] as EventHandler<MessageIncomeEventArgs>)?.Invoke(this, e);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Will be called if a bot command gets raised
|
||||
/// </summary>
|
||||
public event BotCommandEventHandler BotCommand;
|
||||
|
||||
|
||||
public async Task OnBotCommand(BotCommandEventArgs e)
|
||||
{
|
||||
if (BotCommand != null)
|
||||
await BotCommand(this, e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Will be called on an inner exception
|
||||
/// </summary>
|
||||
public event EventHandler<SystemExceptionEventArgs> Exception
|
||||
{
|
||||
add => _events.AddHandler(EvException, value);
|
||||
remove => _events.RemoveHandler(EvException, value);
|
||||
}
|
||||
|
||||
public void OnException(SystemExceptionEventArgs e)
|
||||
{
|
||||
(_events[EvException] as EventHandler<SystemExceptionEventArgs>)?.Invoke(this, e);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Will be called if no form handeled this call
|
||||
/// </summary>
|
||||
public event EventHandler<UnhandledCallEventArgs> UnhandledCall
|
||||
{
|
||||
add => _events.AddHandler(EvUnhandledCall, value);
|
||||
remove => _events.RemoveHandler(EvUnhandledCall, value);
|
||||
}
|
||||
|
||||
public void OnUnhandledCall(UnhandledCallEventArgs e)
|
||||
{
|
||||
(_events[EvUnhandledCall] as EventHandler<UnhandledCallEventArgs>)?.Invoke(this, e);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
BotBase = this
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public MessageClient Client { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Your TelegramBot APIKey
|
||||
/// </summary>
|
||||
public string ApiKey { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// List of all running/active sessions
|
||||
/// </summary>
|
||||
public SessionBase Sessions { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Contains System commands which will be available at everytime and didnt get passed to forms, i.e. /start
|
||||
/// </summary>
|
||||
public Dictionary<BotCommandScope, List<BotCommand>> BotCommandScopes { get; set; } = new();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Enable the SessionState (you need to implement on call forms the IStateForm interface)
|
||||
/// </summary>
|
||||
public IStateMachine StateMachine { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Offers functionality to manage the creation process of the start form.
|
||||
/// </summary>
|
||||
public IStartFormFactory StartFormFactory { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Contains the message loop factory, which cares about "message-management."
|
||||
/// </summary>
|
||||
public IMessageLoopFactory MessageLoopFactory { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// All internal used settings.
|
||||
/// </summary>
|
||||
public Dictionary<ESettings, uint> SystemSettings { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Start your Bot
|
||||
/// </summary>
|
||||
public void Start()
|
||||
{
|
||||
if (Client == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Client.MessageLoop += Client_MessageLoop;
|
||||
|
||||
|
||||
if (StateMachine != null)
|
||||
{
|
||||
Sessions.LoadSessionStates(StateMachine);
|
||||
}
|
||||
|
||||
//Enable auto session saving
|
||||
if (GetSetting(ESettings.SaveSessionsOnConsoleExit, false))
|
||||
{
|
||||
Console.SetHandler(() => { Sessions.SaveSessionStates(); });
|
||||
}
|
||||
|
||||
DeviceSession.MaxNumberOfRetries = GetSetting(ESettings.MaxNumberOfRetries, 5);
|
||||
|
||||
Client.StartReceiving();
|
||||
}
|
||||
|
||||
|
||||
private async Task Client_MessageLoop(object sender, UpdateResult e)
|
||||
{
|
||||
var ds = Sessions.GetSession(e.DeviceId);
|
||||
if (ds == null)
|
||||
{
|
||||
ds = Sessions.StartSession(e.DeviceId).GetAwaiter().GetResult();
|
||||
e.Device = ds;
|
||||
ds.LastMessage = e.RawData.Message;
|
||||
|
||||
OnSessionBegins(new SessionBeginEventArgs(e.DeviceId, ds));
|
||||
}
|
||||
|
||||
var mr = new MessageResult(e.RawData);
|
||||
|
||||
var i = 0;
|
||||
|
||||
//Should formulars get navigated (allow maximum of 10, to dont get loops)
|
||||
do
|
||||
{
|
||||
i++;
|
||||
|
||||
//Reset navigation
|
||||
ds.FormSwitched = false;
|
||||
|
||||
await MessageLoopFactory.MessageLoop(this, ds, e, mr);
|
||||
|
||||
mr.IsFirstHandler = false;
|
||||
} while (ds.FormSwitched && i < GetSetting(ESettings.NavigationMaximum, 10));
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Stop your Bot
|
||||
/// </summary>
|
||||
public void Stop()
|
||||
{
|
||||
if (Client == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Client.MessageLoop -= Client_MessageLoop;
|
||||
|
||||
|
||||
Client.StopReceiving();
|
||||
|
||||
Sessions.SaveSessionStates();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send a message to all active Sessions.
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <returns></returns>
|
||||
public async Task SentToAll(string message)
|
||||
{
|
||||
if (Client == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var s in Sessions.SessionList)
|
||||
{
|
||||
await Client.TelegramClient.SendTextMessageAsync(s.Key, message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// This will invoke the full message loop for the device even when no "userevent" like message or action has been
|
||||
/// raised.
|
||||
/// </summary>
|
||||
/// <param name="deviceId">Contains the device/chat id of the device to update.</param>
|
||||
public async Task InvokeMessageLoop(long deviceId)
|
||||
{
|
||||
var mr = new MessageResult
|
||||
{
|
||||
UpdateData = new Update
|
||||
{
|
||||
Message = new Message()
|
||||
}
|
||||
};
|
||||
|
||||
await InvokeMessageLoop(deviceId, mr);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This will invoke the full message loop for the device even when no "userevent" like message or action has been
|
||||
/// raised.
|
||||
/// </summary>
|
||||
/// <param name="deviceId">Contains the device/chat id of the device to update.</param>
|
||||
/// <param name="e"></param>
|
||||
public async Task InvokeMessageLoop(long deviceId, MessageResult e)
|
||||
{
|
||||
try
|
||||
{
|
||||
var ds = Sessions.GetSession(deviceId);
|
||||
e.Device = ds;
|
||||
|
||||
await MessageLoopFactory.MessageLoop(this, ds, new UpdateResult(e.UpdateData, ds), e);
|
||||
//await Client_Loop(this, e);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
var ds = Sessions.GetSession(deviceId);
|
||||
OnException(new SystemExceptionEventArgs(e.Message.Text, deviceId, ds, ex));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Will get invoke on an unhandled call.
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
public void MessageLoopFactory_UnhandledCall(object sender, UnhandledCallEventArgs e)
|
||||
{
|
||||
OnUnhandledCall(e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method will update all local created bot commands to the botfather.
|
||||
/// </summary>
|
||||
public async Task UploadBotCommands()
|
||||
{
|
||||
foreach (var bs in BotCommandScopes)
|
||||
{
|
||||
if (bs.Value != null)
|
||||
{
|
||||
await Client.SetBotCommands(bs.Value, bs.Key);
|
||||
}
|
||||
else
|
||||
{
|
||||
await Client.DeleteBotCommands(bs.Key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Searching if parameter is a known command in all configured BotCommandScopes.
|
||||
/// </summary>
|
||||
/// <param name="command"></param>
|
||||
/// <returns></returns>
|
||||
public bool IsKnownBotCommand(string command)
|
||||
{
|
||||
foreach (var scope in BotCommandScopes)
|
||||
{
|
||||
if (scope.Value.Any(a => "/" + a.Command == command))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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 (!SystemSettings.ContainsKey(set))
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
return 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 (!SystemSettings.ContainsKey(set))
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
return SystemSettings[set] == 0u ? false : true;
|
||||
}
|
||||
|
||||
|
||||
#region "Events"
|
||||
|
||||
private readonly EventHandlerList _events = new();
|
||||
|
||||
private static readonly object EvSessionBegins = new();
|
||||
|
||||
private static readonly object EvMessage = new();
|
||||
|
||||
private static object __evSystemCall = new();
|
||||
|
||||
public delegate Task BotCommandEventHandler(object sender, BotCommandEventArgs e);
|
||||
|
||||
private static readonly object EvException = new();
|
||||
|
||||
private static readonly object EvUnhandledCall = new();
|
||||
|
||||
#endregion
|
||||
|
||||
#region "Events"
|
||||
|
||||
/// <summary>
|
||||
/// Will be called if a session/context gets started
|
||||
/// </summary>
|
||||
public event EventHandler<SessionBeginEventArgs> SessionBegins
|
||||
{
|
||||
add => _events.AddHandler(EvSessionBegins, value);
|
||||
remove => _events.RemoveHandler(EvSessionBegins, value);
|
||||
}
|
||||
|
||||
public void OnSessionBegins(SessionBeginEventArgs e)
|
||||
{
|
||||
(_events[EvSessionBegins] as EventHandler<SessionBeginEventArgs>)?.Invoke(this, e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Will be called on incomming message
|
||||
/// </summary>
|
||||
public event EventHandler<MessageIncomeEventArgs> Message
|
||||
{
|
||||
add => _events.AddHandler(EvMessage, value);
|
||||
remove => _events.RemoveHandler(EvMessage, value);
|
||||
}
|
||||
|
||||
public void OnMessage(MessageIncomeEventArgs e)
|
||||
{
|
||||
(_events[EvMessage] as EventHandler<MessageIncomeEventArgs>)?.Invoke(this, e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Will be called if a bot command gets raised
|
||||
/// </summary>
|
||||
public event BotCommandEventHandler BotCommand;
|
||||
|
||||
|
||||
public async Task OnBotCommand(BotCommandEventArgs e)
|
||||
{
|
||||
if (BotCommand != null)
|
||||
{
|
||||
await BotCommand(this, e);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Will be called on an inner exception
|
||||
/// </summary>
|
||||
public event EventHandler<SystemExceptionEventArgs> Exception
|
||||
{
|
||||
add => _events.AddHandler(EvException, value);
|
||||
remove => _events.RemoveHandler(EvException, value);
|
||||
}
|
||||
|
||||
public void OnException(SystemExceptionEventArgs e)
|
||||
{
|
||||
(_events[EvException] as EventHandler<SystemExceptionEventArgs>)?.Invoke(this, e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Will be called if no form handeled this call
|
||||
/// </summary>
|
||||
public event EventHandler<UnhandledCallEventArgs> UnhandledCall
|
||||
{
|
||||
add => _events.AddHandler(EvUnhandledCall, value);
|
||||
remove => _events.RemoveHandler(EvUnhandledCall, value);
|
||||
}
|
||||
|
||||
public void OnUnhandledCall(UnhandledCallEventArgs e)
|
||||
{
|
||||
(_events[EvUnhandledCall] as EventHandler<UnhandledCallEventArgs>)?.Invoke(this, e);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -13,362 +13,360 @@ using TelegramBotBase.Localizations;
|
||||
using TelegramBotBase.MessageLoops;
|
||||
using TelegramBotBase.States;
|
||||
|
||||
namespace TelegramBotBase.Builder
|
||||
namespace TelegramBotBase.Builder;
|
||||
|
||||
public class BotBaseBuilder : IAPIKeySelectionStage, IMessageLoopSelectionStage, IStartFormSelectionStage,
|
||||
IBuildingStage, INetworkingSelectionStage, IBotCommandsStage, ISessionSerializationStage,
|
||||
ILanguageSelectionStage
|
||||
{
|
||||
public class BotBaseBuilder : IAPIKeySelectionStage, IMessageLoopSelectionStage, IStartFormSelectionStage, IBuildingStage, INetworkingSelectionStage, IBotCommandsStage, ISessionSerializationStage, ILanguageSelectionStage
|
||||
private string _apiKey;
|
||||
|
||||
private MessageClient _client;
|
||||
|
||||
private IStartFormFactory _factory;
|
||||
|
||||
private IMessageLoopFactory _messageLoopFactory;
|
||||
|
||||
private IStateMachine _statemachine;
|
||||
|
||||
private BotBaseBuilder()
|
||||
{
|
||||
private string _apiKey;
|
||||
|
||||
private IStartFormFactory _factory;
|
||||
|
||||
private MessageClient _client;
|
||||
|
||||
/// <summary>
|
||||
/// Contains different Botcommands for different areas.
|
||||
/// </summary>
|
||||
private Dictionary<BotCommandScope, List<BotCommand>> BotCommandScopes { get; set; } = new Dictionary<BotCommandScope, List<BotCommand>>();
|
||||
|
||||
private IStateMachine _statemachine;
|
||||
|
||||
private IMessageLoopFactory _messageLoopFactory;
|
||||
|
||||
private BotBaseBuilder()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public static IAPIKeySelectionStage Create()
|
||||
{
|
||||
return new BotBaseBuilder();
|
||||
}
|
||||
|
||||
#region "Step 1 (Basic Stuff)"
|
||||
|
||||
public IMessageLoopSelectionStage WithAPIKey(string apiKey)
|
||||
{
|
||||
_apiKey = apiKey;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public IBuildingStage QuickStart(string apiKey, Type StartForm)
|
||||
{
|
||||
_apiKey = apiKey;
|
||||
_factory = new DefaultStartFormFactory(StartForm);
|
||||
|
||||
DefaultMessageLoop();
|
||||
|
||||
NoProxy();
|
||||
|
||||
OnlyStart();
|
||||
|
||||
NoSerialization();
|
||||
|
||||
DefaultLanguage();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public IBuildingStage QuickStart<T>(string apiKey)
|
||||
where T : FormBase
|
||||
{
|
||||
_apiKey = apiKey;
|
||||
_factory = new DefaultStartFormFactory(typeof(T));
|
||||
|
||||
DefaultMessageLoop();
|
||||
|
||||
NoProxy();
|
||||
|
||||
OnlyStart();
|
||||
|
||||
NoSerialization();
|
||||
|
||||
DefaultLanguage();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public IBuildingStage QuickStart(string apiKey, IStartFormFactory StartFormFactory)
|
||||
{
|
||||
_apiKey = apiKey;
|
||||
_factory = StartFormFactory;
|
||||
|
||||
DefaultMessageLoop();
|
||||
|
||||
NoProxy();
|
||||
|
||||
OnlyStart();
|
||||
|
||||
NoSerialization();
|
||||
|
||||
DefaultLanguage();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region "Step 2 (Message Loop)"
|
||||
|
||||
public IStartFormSelectionStage DefaultMessageLoop()
|
||||
{
|
||||
_messageLoopFactory = new FormBaseMessageLoop();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public IStartFormSelectionStage MinimalMessageLoop()
|
||||
{
|
||||
_messageLoopFactory = new MinimalMessageLoop();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public IStartFormSelectionStage CustomMessageLoop(IMessageLoopFactory messageLoopClass)
|
||||
{
|
||||
_messageLoopFactory = messageLoopClass;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public IStartFormSelectionStage CustomMessageLoop<T>()
|
||||
where T : class, new()
|
||||
{
|
||||
_messageLoopFactory = typeof(T).GetConstructor(new Type[] { })?.Invoke(new object[] { }) as IMessageLoopFactory;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region "Step 3 (Start Form/Factory)"
|
||||
|
||||
public INetworkingSelectionStage WithStartForm(Type startFormClass)
|
||||
{
|
||||
_factory = new DefaultStartFormFactory(startFormClass);
|
||||
return this;
|
||||
}
|
||||
|
||||
public INetworkingSelectionStage WithStartForm<T>()
|
||||
where T : FormBase, new()
|
||||
{
|
||||
_factory = new DefaultStartFormFactory(typeof(T));
|
||||
return this;
|
||||
}
|
||||
|
||||
public INetworkingSelectionStage WithServiceProvider(Type startFormClass, IServiceProvider serviceProvider)
|
||||
{
|
||||
_factory = new ServiceProviderStartFormFactory(startFormClass, serviceProvider);
|
||||
return this;
|
||||
}
|
||||
|
||||
public INetworkingSelectionStage WithServiceProvider<T>(IServiceProvider serviceProvider)
|
||||
where T : FormBase
|
||||
{
|
||||
_factory = new ServiceProviderStartFormFactory<T>(serviceProvider);
|
||||
return this;
|
||||
}
|
||||
|
||||
public INetworkingSelectionStage WithStartFormFactory(IStartFormFactory factory)
|
||||
{
|
||||
_factory = factory;
|
||||
return this;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region "Step 4 (Network Settings)"
|
||||
|
||||
public IBotCommandsStage WithProxy(string proxyAddress)
|
||||
{
|
||||
var url = new Uri(proxyAddress);
|
||||
_client = new MessageClient(_apiKey, url)
|
||||
{
|
||||
TelegramClient =
|
||||
{
|
||||
Timeout = new TimeSpan(0, 1, 0)
|
||||
}
|
||||
};
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public IBotCommandsStage NoProxy()
|
||||
{
|
||||
_client = new MessageClient(_apiKey)
|
||||
{
|
||||
TelegramClient =
|
||||
{
|
||||
Timeout = new TimeSpan(0, 1, 0)
|
||||
}
|
||||
};
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public IBotCommandsStage WithBotClient(TelegramBotClient tgclient)
|
||||
{
|
||||
_client = new MessageClient(_apiKey, tgclient)
|
||||
{
|
||||
TelegramClient =
|
||||
{
|
||||
Timeout = new TimeSpan(0, 1, 0)
|
||||
}
|
||||
};
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public IBotCommandsStage WithHostAndPort(string proxyHost, int proxyPort)
|
||||
{
|
||||
_client = new MessageClient(_apiKey, proxyHost, proxyPort)
|
||||
{
|
||||
TelegramClient =
|
||||
{
|
||||
Timeout = new TimeSpan(0, 1, 0)
|
||||
}
|
||||
};
|
||||
return this;
|
||||
}
|
||||
|
||||
public IBotCommandsStage WithHttpClient(HttpClient tgclient)
|
||||
{
|
||||
_client = new MessageClient(_apiKey, tgclient)
|
||||
{
|
||||
TelegramClient =
|
||||
{
|
||||
Timeout = new TimeSpan(0, 1, 0)
|
||||
}
|
||||
};
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region "Step 5 (Bot Commands)"
|
||||
|
||||
public ISessionSerializationStage NoCommands()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
public ISessionSerializationStage OnlyStart()
|
||||
{
|
||||
BotCommandScopes.Start("Starts the bot");
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
public ISessionSerializationStage DefaultCommands()
|
||||
{
|
||||
BotCommandScopes.Start("Starts the bot");
|
||||
BotCommandScopes.Help("Should show you some help");
|
||||
BotCommandScopes.Settings("Should show you some settings");
|
||||
return this;
|
||||
}
|
||||
|
||||
public ISessionSerializationStage CustomCommands(Action<Dictionary<BotCommandScope, List<BotCommand>>> action)
|
||||
{
|
||||
action?.Invoke(BotCommandScopes);
|
||||
return this;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region "Step 6 (Serialization)"
|
||||
|
||||
public ILanguageSelectionStage NoSerialization()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
public ILanguageSelectionStage UseSerialization(IStateMachine machine)
|
||||
{
|
||||
_statemachine = machine;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public ILanguageSelectionStage UseJSON(string path)
|
||||
{
|
||||
_statemachine = new JsonStateMachine(path);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ILanguageSelectionStage UseSimpleJSON(string path)
|
||||
{
|
||||
_statemachine = new SimpleJsonStateMachine(path);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ILanguageSelectionStage UseXML(string path)
|
||||
{
|
||||
_statemachine = new XmlStateMachine(path);
|
||||
return this;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region "Step 7 (Language)"
|
||||
|
||||
public IBuildingStage DefaultLanguage()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
public IBuildingStage UseEnglish()
|
||||
{
|
||||
Default.Language = new English();
|
||||
return this;
|
||||
}
|
||||
|
||||
public IBuildingStage UseGerman()
|
||||
{
|
||||
Default.Language = new German();
|
||||
return this;
|
||||
}
|
||||
|
||||
public IBuildingStage Custom(Localization language)
|
||||
{
|
||||
Default.Language = language;
|
||||
return this;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
public BotBase Build()
|
||||
{
|
||||
var bb = new BotBase
|
||||
{
|
||||
ApiKey = _apiKey,
|
||||
StartFormFactory = _factory,
|
||||
Client = _client
|
||||
};
|
||||
|
||||
bb.Sessions.Client = bb.Client;
|
||||
|
||||
bb.BotCommandScopes = BotCommandScopes;
|
||||
|
||||
bb.StateMachine = _statemachine;
|
||||
|
||||
bb.MessageLoopFactory = _messageLoopFactory;
|
||||
|
||||
bb.MessageLoopFactory.UnhandledCall += bb.MessageLoopFactory_UnhandledCall;
|
||||
|
||||
return bb;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Contains different Botcommands for different areas.
|
||||
/// </summary>
|
||||
private Dictionary<BotCommandScope, List<BotCommand>> BotCommandScopes { get; } = new();
|
||||
|
||||
|
||||
public BotBase Build()
|
||||
{
|
||||
var bb = new BotBase
|
||||
{
|
||||
ApiKey = _apiKey,
|
||||
StartFormFactory = _factory,
|
||||
Client = _client
|
||||
};
|
||||
|
||||
bb.Sessions.Client = bb.Client;
|
||||
|
||||
bb.BotCommandScopes = BotCommandScopes;
|
||||
|
||||
bb.StateMachine = _statemachine;
|
||||
|
||||
bb.MessageLoopFactory = _messageLoopFactory;
|
||||
|
||||
bb.MessageLoopFactory.UnhandledCall += bb.MessageLoopFactory_UnhandledCall;
|
||||
|
||||
return bb;
|
||||
}
|
||||
|
||||
public static IAPIKeySelectionStage Create()
|
||||
{
|
||||
return new BotBaseBuilder();
|
||||
}
|
||||
|
||||
#region "Step 1 (Basic Stuff)"
|
||||
|
||||
public IMessageLoopSelectionStage WithAPIKey(string apiKey)
|
||||
{
|
||||
_apiKey = apiKey;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public IBuildingStage QuickStart(string apiKey, Type StartForm)
|
||||
{
|
||||
_apiKey = apiKey;
|
||||
_factory = new DefaultStartFormFactory(StartForm);
|
||||
|
||||
DefaultMessageLoop();
|
||||
|
||||
NoProxy();
|
||||
|
||||
OnlyStart();
|
||||
|
||||
NoSerialization();
|
||||
|
||||
DefaultLanguage();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public IBuildingStage QuickStart<T>(string apiKey)
|
||||
where T : FormBase
|
||||
{
|
||||
_apiKey = apiKey;
|
||||
_factory = new DefaultStartFormFactory(typeof(T));
|
||||
|
||||
DefaultMessageLoop();
|
||||
|
||||
NoProxy();
|
||||
|
||||
OnlyStart();
|
||||
|
||||
NoSerialization();
|
||||
|
||||
DefaultLanguage();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public IBuildingStage QuickStart(string apiKey, IStartFormFactory StartFormFactory)
|
||||
{
|
||||
_apiKey = apiKey;
|
||||
_factory = StartFormFactory;
|
||||
|
||||
DefaultMessageLoop();
|
||||
|
||||
NoProxy();
|
||||
|
||||
OnlyStart();
|
||||
|
||||
NoSerialization();
|
||||
|
||||
DefaultLanguage();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region "Step 2 (Message Loop)"
|
||||
|
||||
public IStartFormSelectionStage DefaultMessageLoop()
|
||||
{
|
||||
_messageLoopFactory = new FormBaseMessageLoop();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public IStartFormSelectionStage MinimalMessageLoop()
|
||||
{
|
||||
_messageLoopFactory = new MinimalMessageLoop();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public IStartFormSelectionStage CustomMessageLoop(IMessageLoopFactory messageLoopClass)
|
||||
{
|
||||
_messageLoopFactory = messageLoopClass;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public IStartFormSelectionStage CustomMessageLoop<T>()
|
||||
where T : class, new()
|
||||
{
|
||||
_messageLoopFactory =
|
||||
typeof(T).GetConstructor(new Type[] { })?.Invoke(new object[] { }) as IMessageLoopFactory;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region "Step 3 (Start Form/Factory)"
|
||||
|
||||
public INetworkingSelectionStage WithStartForm(Type startFormClass)
|
||||
{
|
||||
_factory = new DefaultStartFormFactory(startFormClass);
|
||||
return this;
|
||||
}
|
||||
|
||||
public INetworkingSelectionStage WithStartForm<T>()
|
||||
where T : FormBase, new()
|
||||
{
|
||||
_factory = new DefaultStartFormFactory(typeof(T));
|
||||
return this;
|
||||
}
|
||||
|
||||
public INetworkingSelectionStage WithServiceProvider(Type startFormClass, IServiceProvider serviceProvider)
|
||||
{
|
||||
_factory = new ServiceProviderStartFormFactory(startFormClass, serviceProvider);
|
||||
return this;
|
||||
}
|
||||
|
||||
public INetworkingSelectionStage WithServiceProvider<T>(IServiceProvider serviceProvider)
|
||||
where T : FormBase
|
||||
{
|
||||
_factory = new ServiceProviderStartFormFactory<T>(serviceProvider);
|
||||
return this;
|
||||
}
|
||||
|
||||
public INetworkingSelectionStage WithStartFormFactory(IStartFormFactory factory)
|
||||
{
|
||||
_factory = factory;
|
||||
return this;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region "Step 4 (Network Settings)"
|
||||
|
||||
public IBotCommandsStage WithProxy(string proxyAddress)
|
||||
{
|
||||
var url = new Uri(proxyAddress);
|
||||
_client = new MessageClient(_apiKey, url)
|
||||
{
|
||||
TelegramClient =
|
||||
{
|
||||
Timeout = new TimeSpan(0, 1, 0)
|
||||
}
|
||||
};
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public IBotCommandsStage NoProxy()
|
||||
{
|
||||
_client = new MessageClient(_apiKey)
|
||||
{
|
||||
TelegramClient =
|
||||
{
|
||||
Timeout = new TimeSpan(0, 1, 0)
|
||||
}
|
||||
};
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public IBotCommandsStage WithBotClient(TelegramBotClient tgclient)
|
||||
{
|
||||
_client = new MessageClient(_apiKey, tgclient)
|
||||
{
|
||||
TelegramClient =
|
||||
{
|
||||
Timeout = new TimeSpan(0, 1, 0)
|
||||
}
|
||||
};
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public IBotCommandsStage WithHostAndPort(string proxyHost, int proxyPort)
|
||||
{
|
||||
_client = new MessageClient(_apiKey, proxyHost, proxyPort)
|
||||
{
|
||||
TelegramClient =
|
||||
{
|
||||
Timeout = new TimeSpan(0, 1, 0)
|
||||
}
|
||||
};
|
||||
return this;
|
||||
}
|
||||
|
||||
public IBotCommandsStage WithHttpClient(HttpClient tgclient)
|
||||
{
|
||||
_client = new MessageClient(_apiKey, tgclient)
|
||||
{
|
||||
TelegramClient =
|
||||
{
|
||||
Timeout = new TimeSpan(0, 1, 0)
|
||||
}
|
||||
};
|
||||
return this;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region "Step 5 (Bot Commands)"
|
||||
|
||||
public ISessionSerializationStage NoCommands()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
public ISessionSerializationStage OnlyStart()
|
||||
{
|
||||
BotCommandScopes.Start("Starts the bot");
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public ISessionSerializationStage DefaultCommands()
|
||||
{
|
||||
BotCommandScopes.Start("Starts the bot");
|
||||
BotCommandScopes.Help("Should show you some help");
|
||||
BotCommandScopes.Settings("Should show you some settings");
|
||||
return this;
|
||||
}
|
||||
|
||||
public ISessionSerializationStage CustomCommands(Action<Dictionary<BotCommandScope, List<BotCommand>>> action)
|
||||
{
|
||||
action?.Invoke(BotCommandScopes);
|
||||
return this;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region "Step 6 (Serialization)"
|
||||
|
||||
public ILanguageSelectionStage NoSerialization()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
public ILanguageSelectionStage UseSerialization(IStateMachine machine)
|
||||
{
|
||||
_statemachine = machine;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public ILanguageSelectionStage UseJSON(string path)
|
||||
{
|
||||
_statemachine = new JsonStateMachine(path);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ILanguageSelectionStage UseSimpleJSON(string path)
|
||||
{
|
||||
_statemachine = new SimpleJsonStateMachine(path);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ILanguageSelectionStage UseXML(string path)
|
||||
{
|
||||
_statemachine = new XmlStateMachine(path);
|
||||
return this;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region "Step 7 (Language)"
|
||||
|
||||
public IBuildingStage DefaultLanguage()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
public IBuildingStage UseEnglish()
|
||||
{
|
||||
Default.Language = new English();
|
||||
return this;
|
||||
}
|
||||
|
||||
public IBuildingStage UseGerman()
|
||||
{
|
||||
Default.Language = new German();
|
||||
return this;
|
||||
}
|
||||
|
||||
public IBuildingStage Custom(Localization language)
|
||||
{
|
||||
Default.Language = language;
|
||||
return this;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -2,42 +2,41 @@
|
||||
using TelegramBotBase.Form;
|
||||
using TelegramBotBase.Interfaces;
|
||||
|
||||
namespace TelegramBotBase.Builder.Interfaces
|
||||
namespace TelegramBotBase.Builder.Interfaces;
|
||||
|
||||
public interface IAPIKeySelectionStage
|
||||
{
|
||||
public interface IAPIKeySelectionStage
|
||||
{
|
||||
/// <summary>
|
||||
/// Sets the API Key which will be used by the telegram bot client.
|
||||
/// </summary>
|
||||
/// <param name="apiKey"></param>
|
||||
/// <returns></returns>
|
||||
IMessageLoopSelectionStage WithAPIKey(string apiKey);
|
||||
/// <summary>
|
||||
/// Sets the API Key which will be used by the telegram bot client.
|
||||
/// </summary>
|
||||
/// <param name="apiKey"></param>
|
||||
/// <returns></returns>
|
||||
IMessageLoopSelectionStage WithAPIKey(string apiKey);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Quick and easy way to create a BotBase instance.
|
||||
/// Uses: DefaultMessageLoop, NoProxy, OnlyStart, NoSerialization, DefaultLanguage
|
||||
/// </summary>
|
||||
/// <param name="apiKey"></param>
|
||||
/// <param name="StartForm"></param>
|
||||
/// <returns></returns>
|
||||
IBuildingStage QuickStart(string apiKey, Type StartForm);
|
||||
/// <summary>
|
||||
/// Quick and easy way to create a BotBase instance.
|
||||
/// Uses: DefaultMessageLoop, NoProxy, OnlyStart, NoSerialization, DefaultLanguage
|
||||
/// </summary>
|
||||
/// <param name="apiKey"></param>
|
||||
/// <param name="StartForm"></param>
|
||||
/// <returns></returns>
|
||||
IBuildingStage QuickStart(string apiKey, Type StartForm);
|
||||
|
||||
/// <summary>
|
||||
/// Quick and easy way to create a BotBase instance.
|
||||
/// Uses: DefaultMessageLoop, NoProxy, OnlyStart, NoSerialization, DefaultLanguage
|
||||
/// </summary>
|
||||
/// <param name="apiKey"></param>
|
||||
/// <returns></returns>
|
||||
IBuildingStage QuickStart<T>(string apiKey) where T : FormBase;
|
||||
/// <summary>
|
||||
/// Quick and easy way to create a BotBase instance.
|
||||
/// Uses: DefaultMessageLoop, NoProxy, OnlyStart, NoSerialization, DefaultLanguage
|
||||
/// </summary>
|
||||
/// <param name="apiKey"></param>
|
||||
/// <returns></returns>
|
||||
IBuildingStage QuickStart<T>(string apiKey) where T : FormBase;
|
||||
|
||||
/// <summary>
|
||||
/// Quick and easy way to create a BotBase instance.
|
||||
/// Uses: DefaultMessageLoop, NoProxy, OnlyStart, NoSerialization, DefaultLanguage
|
||||
/// </summary>
|
||||
/// <param name="apiKey"></param>
|
||||
/// <param name="StartFormFactory"></param>
|
||||
/// <returns></returns>
|
||||
IBuildingStage QuickStart(string apiKey, IStartFormFactory StartFormFactory);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Quick and easy way to create a BotBase instance.
|
||||
/// Uses: DefaultMessageLoop, NoProxy, OnlyStart, NoSerialization, DefaultLanguage
|
||||
/// </summary>
|
||||
/// <param name="apiKey"></param>
|
||||
/// <param name="StartFormFactory"></param>
|
||||
/// <returns></returns>
|
||||
IBuildingStage QuickStart(string apiKey, IStartFormFactory StartFormFactory);
|
||||
}
|
||||
@@ -2,39 +2,35 @@
|
||||
using System.Collections.Generic;
|
||||
using Telegram.Bot.Types;
|
||||
|
||||
namespace TelegramBotBase.Builder.Interfaces
|
||||
namespace TelegramBotBase.Builder.Interfaces;
|
||||
|
||||
public interface IBotCommandsStage
|
||||
{
|
||||
public interface IBotCommandsStage
|
||||
{
|
||||
/// <summary>
|
||||
/// Does not create any commands.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
ISessionSerializationStage NoCommands();
|
||||
/// <summary>
|
||||
/// Does not create any commands.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
ISessionSerializationStage NoCommands();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Creates default commands for start, help and settings.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
ISessionSerializationStage DefaultCommands();
|
||||
/// <summary>
|
||||
/// Creates default commands for start, help and settings.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
ISessionSerializationStage DefaultCommands();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Only adds the start command.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
ISessionSerializationStage OnlyStart();
|
||||
/// <summary>
|
||||
/// Only adds the start command.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
ISessionSerializationStage OnlyStart();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gives you the ability to add custom commands.
|
||||
/// </summary>
|
||||
/// <param name="action"></param>
|
||||
/// <returns></returns>
|
||||
|
||||
ISessionSerializationStage CustomCommands(Action<Dictionary<BotCommandScope, List<BotCommand>>> action);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Gives you the ability to add custom commands.
|
||||
/// </summary>
|
||||
/// <param name="action"></param>
|
||||
/// <returns></returns>
|
||||
ISessionSerializationStage CustomCommands(Action<Dictionary<BotCommandScope, List<BotCommand>>> action);
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
namespace TelegramBotBase.Builder.Interfaces
|
||||
namespace TelegramBotBase.Builder.Interfaces;
|
||||
|
||||
public interface IBuildingStage
|
||||
{
|
||||
public interface IBuildingStage
|
||||
{
|
||||
BotBase Build();
|
||||
}
|
||||
}
|
||||
BotBase Build();
|
||||
}
|
||||
@@ -1,33 +1,30 @@
|
||||
using TelegramBotBase.Localizations;
|
||||
|
||||
namespace TelegramBotBase.Builder.Interfaces
|
||||
namespace TelegramBotBase.Builder.Interfaces;
|
||||
|
||||
public interface ILanguageSelectionStage
|
||||
{
|
||||
public interface ILanguageSelectionStage
|
||||
{
|
||||
/// <summary>
|
||||
/// Selects the default language for control usage. (English)
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
IBuildingStage DefaultLanguage();
|
||||
|
||||
/// <summary>
|
||||
/// Selects the default language for control usage. (English)
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
IBuildingStage DefaultLanguage();
|
||||
/// <summary>
|
||||
/// Selects english as the default language for control labels.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
IBuildingStage UseEnglish();
|
||||
|
||||
/// <summary>
|
||||
/// Selects english as the default language for control labels.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
IBuildingStage UseEnglish();
|
||||
/// <summary>
|
||||
/// Selects german as the default language for control labels.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
IBuildingStage UseGerman();
|
||||
|
||||
/// <summary>
|
||||
/// Selects german as the default language for control labels.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
IBuildingStage UseGerman();
|
||||
|
||||
/// <summary>
|
||||
/// Selects a custom language as the default language for control labels.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
IBuildingStage Custom(Localization language);
|
||||
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Selects a custom language as the default language for control labels.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
IBuildingStage Custom(Localization language);
|
||||
}
|
||||
@@ -1,40 +1,36 @@
|
||||
using TelegramBotBase.Interfaces;
|
||||
|
||||
namespace TelegramBotBase.Builder.Interfaces
|
||||
namespace TelegramBotBase.Builder.Interfaces;
|
||||
|
||||
public interface IMessageLoopSelectionStage
|
||||
{
|
||||
public interface IMessageLoopSelectionStage
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Chooses a default message loop.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
IStartFormSelectionStage DefaultMessageLoop();
|
||||
/// <summary>
|
||||
/// Chooses a default message loop.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
IStartFormSelectionStage DefaultMessageLoop();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Chooses a minimalistic message loop, which catches all update types and only calls the Load function.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
IStartFormSelectionStage MinimalMessageLoop();
|
||||
/// <summary>
|
||||
/// Chooses a minimalistic message loop, which catches all update types and only calls the Load function.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
IStartFormSelectionStage MinimalMessageLoop();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Chooses a custom message loop.
|
||||
/// </summary>
|
||||
/// <param name="startFormClass"></param>
|
||||
/// <returns></returns>
|
||||
IStartFormSelectionStage CustomMessageLoop(IMessageLoopFactory startFormClass);
|
||||
/// <summary>
|
||||
/// Chooses a custom message loop.
|
||||
/// </summary>
|
||||
/// <param name="startFormClass"></param>
|
||||
/// <returns></returns>
|
||||
IStartFormSelectionStage CustomMessageLoop(IMessageLoopFactory startFormClass);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Chooses a custom message loop.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
IStartFormSelectionStage CustomMessageLoop<T>() where T : class, new();
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Chooses a custom message loop.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
IStartFormSelectionStage CustomMessageLoop<T>() where T : class, new();
|
||||
}
|
||||
@@ -1,48 +1,44 @@
|
||||
using System.Net.Http;
|
||||
using Telegram.Bot;
|
||||
|
||||
namespace TelegramBotBase.Builder.Interfaces
|
||||
namespace TelegramBotBase.Builder.Interfaces;
|
||||
|
||||
public interface INetworkingSelectionStage
|
||||
{
|
||||
public interface INetworkingSelectionStage
|
||||
{
|
||||
/// <summary>
|
||||
/// Chooses a proxy as network configuration.
|
||||
/// </summary>
|
||||
/// <param name="proxyAddress"></param>
|
||||
/// <returns></returns>
|
||||
IBotCommandsStage WithProxy(string proxyAddress);
|
||||
|
||||
/// <summary>
|
||||
/// Chooses a proxy as network configuration.
|
||||
/// </summary>
|
||||
/// <param name="proxyAddress"></param>
|
||||
/// <returns></returns>
|
||||
IBotCommandsStage WithProxy(string proxyAddress);
|
||||
|
||||
/// <summary>
|
||||
/// Do not choose a proxy as network configuration.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
IBotCommandsStage NoProxy();
|
||||
/// <summary>
|
||||
/// Do not choose a proxy as network configuration.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
IBotCommandsStage NoProxy();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Chooses a custom instance of TelegramBotClient.
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <returns></returns>
|
||||
IBotCommandsStage WithBotClient(TelegramBotClient client);
|
||||
/// <summary>
|
||||
/// Chooses a custom instance of TelegramBotClient.
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <returns></returns>
|
||||
IBotCommandsStage WithBotClient(TelegramBotClient client);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Sets the custom proxy host and port.
|
||||
/// </summary>
|
||||
/// <param name="proxyHost"></param>
|
||||
/// <param name="Port"></param>
|
||||
/// <returns></returns>
|
||||
IBotCommandsStage WithHostAndPort(string proxyHost, int Port);
|
||||
/// <summary>
|
||||
/// Sets the custom proxy host and port.
|
||||
/// </summary>
|
||||
/// <param name="proxyHost"></param>
|
||||
/// <param name="Port"></param>
|
||||
/// <returns></returns>
|
||||
IBotCommandsStage WithHostAndPort(string proxyHost, int Port);
|
||||
|
||||
/// <summary>
|
||||
/// Uses a custom http client.
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <returns></returns>
|
||||
IBotCommandsStage WithHttpClient(HttpClient client);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Uses a custom http client.
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <returns></returns>
|
||||
IBotCommandsStage WithHttpClient(HttpClient client);
|
||||
}
|
||||
@@ -1,46 +1,44 @@
|
||||
using TelegramBotBase.Interfaces;
|
||||
|
||||
namespace TelegramBotBase.Builder.Interfaces
|
||||
namespace TelegramBotBase.Builder.Interfaces;
|
||||
|
||||
public interface ISessionSerializationStage
|
||||
{
|
||||
public interface ISessionSerializationStage
|
||||
{
|
||||
/// <summary>
|
||||
/// Do not uses serialization.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
ILanguageSelectionStage NoSerialization();
|
||||
/// <summary>
|
||||
/// Do not uses serialization.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
ILanguageSelectionStage NoSerialization();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Sets the state machine for serialization.
|
||||
/// </summary>
|
||||
/// <param name="machine"></param>
|
||||
/// <returns></returns>
|
||||
ILanguageSelectionStage UseSerialization(IStateMachine machine);
|
||||
/// <summary>
|
||||
/// Sets the state machine for serialization.
|
||||
/// </summary>
|
||||
/// <param name="machine"></param>
|
||||
/// <returns></returns>
|
||||
ILanguageSelectionStage UseSerialization(IStateMachine machine);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Using the complex version of .Net JSON, which can serialize all objects.
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
/// <returns></returns>
|
||||
ILanguageSelectionStage UseJSON(string path);
|
||||
/// <summary>
|
||||
/// Using the complex version of .Net JSON, which can serialize all objects.
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
/// <returns></returns>
|
||||
ILanguageSelectionStage UseJSON(string path);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Use the easy version of .Net JSON, which can serialize basic types, but not generics and others.
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
/// <returns></returns>
|
||||
ILanguageSelectionStage UseSimpleJSON(string path);
|
||||
/// <summary>
|
||||
/// Use the easy version of .Net JSON, which can serialize basic types, but not generics and others.
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
/// <returns></returns>
|
||||
ILanguageSelectionStage UseSimpleJSON(string path);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Uses the XML serializer for session serialization.
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
/// <returns></returns>
|
||||
ILanguageSelectionStage UseXML(string path);
|
||||
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Uses the XML serializer for session serialization.
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
/// <returns></returns>
|
||||
ILanguageSelectionStage UseXML(string path);
|
||||
}
|
||||
@@ -2,47 +2,44 @@
|
||||
using TelegramBotBase.Form;
|
||||
using TelegramBotBase.Interfaces;
|
||||
|
||||
namespace TelegramBotBase.Builder.Interfaces
|
||||
namespace TelegramBotBase.Builder.Interfaces;
|
||||
|
||||
public interface IStartFormSelectionStage
|
||||
{
|
||||
public interface IStartFormSelectionStage
|
||||
{
|
||||
/// <summary>
|
||||
/// Chooses a start form type which will be used for new sessions.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
INetworkingSelectionStage WithStartForm(Type startFormClass);
|
||||
|
||||
/// <summary>
|
||||
/// Chooses a start form type which will be used for new sessions.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
INetworkingSelectionStage WithStartForm(Type startFormClass);
|
||||
/// <summary>
|
||||
/// Chooses a generic start form which will be used for new sessions.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
INetworkingSelectionStage WithStartForm<T>() where T : FormBase, new();
|
||||
|
||||
/// <summary>
|
||||
/// Chooses a generic start form which will be used for new sessions.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
INetworkingSelectionStage WithStartForm<T>() where T : FormBase, new();
|
||||
/// <summary>
|
||||
/// Chooses a StartFormFactory which will be use for new sessions.
|
||||
/// </summary>
|
||||
/// <param name="startFormClass"></param>
|
||||
/// <param name="serviceProvider"></param>
|
||||
/// <returns></returns>
|
||||
INetworkingSelectionStage WithServiceProvider(Type startFormClass, IServiceProvider serviceProvider);
|
||||
|
||||
/// <summary>
|
||||
/// Chooses a StartFormFactory which will be use for new sessions.
|
||||
/// </summary>
|
||||
/// <param name="startFormClass"></param>
|
||||
/// <param name="serviceProvider"></param>
|
||||
/// <returns></returns>
|
||||
INetworkingSelectionStage WithServiceProvider(Type startFormClass, IServiceProvider serviceProvider);
|
||||
/// <summary>
|
||||
/// Chooses a StartFormFactory which will be use for new sessions.
|
||||
/// </summary>
|
||||
/// <param name="serviceProvider"></param>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
INetworkingSelectionStage WithServiceProvider<T>(IServiceProvider serviceProvider) where T : FormBase;
|
||||
|
||||
/// <summary>
|
||||
/// Chooses a StartFormFactory which will be use for new sessions.
|
||||
/// </summary>
|
||||
/// <param name="serviceProvider"></param>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
INetworkingSelectionStage WithServiceProvider<T>(IServiceProvider serviceProvider) where T : FormBase;
|
||||
|
||||
/// <summary>
|
||||
/// Chooses a StartFormFactory which will be use for new sessions.
|
||||
/// </summary>
|
||||
/// <param name="factory"></param>
|
||||
/// <returns></returns>
|
||||
INetworkingSelectionStage WithStartFormFactory(IStartFormFactory factory);
|
||||
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Chooses a StartFormFactory which will be use for new sessions.
|
||||
/// </summary>
|
||||
/// <param name="factory"></param>
|
||||
/// <returns></returns>
|
||||
INetworkingSelectionStage WithStartFormFactory(IStartFormFactory factory);
|
||||
}
|
||||
@@ -2,141 +2,181 @@
|
||||
using System.Linq;
|
||||
using Telegram.Bot.Types;
|
||||
|
||||
namespace TelegramBotBase.Commands
|
||||
namespace TelegramBotBase.Commands;
|
||||
|
||||
public static class Extensions
|
||||
{
|
||||
public static class Extensions
|
||||
/// <summary>
|
||||
/// Adding the command with a description.
|
||||
/// </summary>
|
||||
/// <param name="cmds"></param>
|
||||
/// <param name="command"></param>
|
||||
/// <param name="description"></param>
|
||||
public static void Add(this Dictionary<BotCommandScope, List<BotCommand>> cmds, string command,
|
||||
string description, BotCommandScope scope = null)
|
||||
{
|
||||
/// <summary>
|
||||
/// Adding the command with a description.
|
||||
/// </summary>
|
||||
/// <param name="cmds"></param>
|
||||
/// <param name="command"></param>
|
||||
/// <param name="description"></param>
|
||||
public static void Add(this Dictionary<BotCommandScope, List<BotCommand>> cmds, string command, string description, BotCommandScope scope = null)
|
||||
if (scope == null)
|
||||
{
|
||||
if (scope == null)
|
||||
{
|
||||
scope = BotCommandScope.Default();
|
||||
}
|
||||
|
||||
var item = cmds.FirstOrDefault(a => a.Key.Type == scope.Type);
|
||||
|
||||
if (item.Value != null)
|
||||
{
|
||||
item.Value.Add(new BotCommand { Command = command, Description = description });
|
||||
}
|
||||
else
|
||||
{
|
||||
cmds.Add(scope, new List<BotCommand> { new BotCommand { Command = command, Description = description } });
|
||||
}
|
||||
scope = BotCommandScope.Default();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adding the command with a description.
|
||||
/// </summary>
|
||||
/// <param name="cmds"></param>
|
||||
/// <param name="command"></param>
|
||||
/// <param name="description"></param>
|
||||
public static void Clear(this Dictionary<BotCommandScope, List<BotCommand>> cmds, BotCommandScope scope = null)
|
||||
var item = cmds.FirstOrDefault(a => a.Key.Type == scope.Type);
|
||||
|
||||
if (item.Value != null)
|
||||
{
|
||||
if (scope == null)
|
||||
{
|
||||
scope = BotCommandScope.Default();
|
||||
}
|
||||
|
||||
var item = cmds.FirstOrDefault(a => a.Key.Type == scope.Type);
|
||||
|
||||
if (item.Key != null)
|
||||
{
|
||||
cmds[item.Key] = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
cmds[scope] = null;
|
||||
}
|
||||
item.Value.Add(new BotCommand { Command = command, Description = description });
|
||||
}
|
||||
else
|
||||
{
|
||||
cmds.Add(scope, new List<BotCommand> { new() { Command = command, Description = description } });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adding the default /start command with a description.
|
||||
/// </summary>
|
||||
/// <param name="cmds"></param>
|
||||
/// <param name="description"></param>
|
||||
public static void Start(this Dictionary<BotCommandScope, List<BotCommand>> cmds, string description) => Add(cmds, "start", description);
|
||||
|
||||
/// <summary>
|
||||
/// Adding the default /help command with a description.
|
||||
/// </summary>
|
||||
/// <param name="cmds"></param>
|
||||
/// <param name="description"></param>
|
||||
public static void Help(this Dictionary<BotCommandScope, List<BotCommand>> cmds, string description) => Add(cmds, "help", description);
|
||||
|
||||
/// <summary>
|
||||
/// Adding the default /settings command with a description.
|
||||
/// </summary>
|
||||
/// <param name="cmds"></param>
|
||||
/// <param name="description"></param>
|
||||
public static void Settings(this Dictionary<BotCommandScope, List<BotCommand>> cmds, string description) => Add(cmds, "settings", description);
|
||||
|
||||
/// <summary>
|
||||
/// Clears all default commands.
|
||||
/// </summary>
|
||||
/// <param name="cmds"></param>
|
||||
public static void ClearDefaultCommands(this Dictionary<BotCommandScope, List<BotCommand>> cmds) => Clear(cmds);
|
||||
|
||||
/// <summary>
|
||||
/// Clears all commands of a specific device.
|
||||
/// </summary>
|
||||
/// <param name="cmds"></param>
|
||||
public static void ClearChatCommands(this Dictionary<BotCommandScope, List<BotCommand>> cmds, long deviceId) => Clear(cmds, new BotCommandScopeChat { ChatId = deviceId });
|
||||
|
||||
/// <summary>
|
||||
/// Adding a chat command with a description.
|
||||
/// </summary>
|
||||
/// <param name="cmds"></param>
|
||||
/// <param name="command"></param>
|
||||
/// <param name="description"></param>
|
||||
public static void AddChatCommand(this Dictionary<BotCommandScope, List<BotCommand>> cmds, long deviceId, string command, string description) => Add(cmds, command, description, new BotCommandScopeChat { ChatId = deviceId });
|
||||
|
||||
/// <summary>
|
||||
/// Adding a group command with a description.
|
||||
/// </summary>
|
||||
/// <param name="cmds"></param>
|
||||
/// <param name="command"></param>
|
||||
/// <param name="description"></param>
|
||||
public static void AddGroupCommand(this Dictionary<BotCommandScope, List<BotCommand>> cmds, string command, string description) => Add(cmds, command, description, new BotCommandScopeAllGroupChats());
|
||||
|
||||
/// <summary>
|
||||
/// Clears all group commands.
|
||||
/// </summary>
|
||||
/// <param name="cmds"></param>
|
||||
public static void ClearGroupCommands(this Dictionary<BotCommandScope, List<BotCommand>> cmds) => Clear(cmds, new BotCommandScopeAllGroupChats());
|
||||
|
||||
/// <summary>
|
||||
/// Adding group admin command with a description.
|
||||
/// </summary>
|
||||
/// <param name="cmds"></param>
|
||||
/// <param name="command"></param>
|
||||
/// <param name="description"></param>
|
||||
public static void AddGroupAdminCommand(this Dictionary<BotCommandScope, List<BotCommand>> cmds, string command, string description) => Add(cmds, command, description, new BotCommandScopeAllChatAdministrators());
|
||||
|
||||
/// <summary>
|
||||
/// Clears all group admin commands.
|
||||
/// </summary>
|
||||
/// <param name="cmds"></param>
|
||||
public static void ClearGroupAdminCommand(this Dictionary<BotCommandScope, List<BotCommand>> cmds) => Clear(cmds, new BotCommandScopeAllChatAdministrators());
|
||||
|
||||
/// <summary>
|
||||
/// Adding a privat command with a description.
|
||||
/// </summary>
|
||||
/// <param name="cmds"></param>
|
||||
/// <param name="command"></param>
|
||||
/// <param name="description"></param>
|
||||
public static void AddPrivateChatCommand(this Dictionary<BotCommandScope, List<BotCommand>> cmds, string command, string description) => Add(cmds, command, description, new BotCommandScopeAllPrivateChats());
|
||||
|
||||
/// <summary>
|
||||
/// Clears all private commands.
|
||||
/// </summary>
|
||||
/// <param name="cmds"></param>
|
||||
public static void ClearPrivateChatCommand(this Dictionary<BotCommandScope, List<BotCommand>> cmds) => Clear(cmds, new BotCommandScopeAllPrivateChats());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adding the command with a description.
|
||||
/// </summary>
|
||||
/// <param name="cmds"></param>
|
||||
/// <param name="command"></param>
|
||||
/// <param name="description"></param>
|
||||
public static void Clear(this Dictionary<BotCommandScope, List<BotCommand>> cmds, BotCommandScope scope = null)
|
||||
{
|
||||
if (scope == null)
|
||||
{
|
||||
scope = BotCommandScope.Default();
|
||||
}
|
||||
|
||||
var item = cmds.FirstOrDefault(a => a.Key.Type == scope.Type);
|
||||
|
||||
if (item.Key != null)
|
||||
{
|
||||
cmds[item.Key] = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
cmds[scope] = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adding the default /start command with a description.
|
||||
/// </summary>
|
||||
/// <param name="cmds"></param>
|
||||
/// <param name="description"></param>
|
||||
public static void Start(this Dictionary<BotCommandScope, List<BotCommand>> cmds, string description)
|
||||
{
|
||||
Add(cmds, "start", description);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adding the default /help command with a description.
|
||||
/// </summary>
|
||||
/// <param name="cmds"></param>
|
||||
/// <param name="description"></param>
|
||||
public static void Help(this Dictionary<BotCommandScope, List<BotCommand>> cmds, string description)
|
||||
{
|
||||
Add(cmds, "help", description);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adding the default /settings command with a description.
|
||||
/// </summary>
|
||||
/// <param name="cmds"></param>
|
||||
/// <param name="description"></param>
|
||||
public static void Settings(this Dictionary<BotCommandScope, List<BotCommand>> cmds, string description)
|
||||
{
|
||||
Add(cmds, "settings", description);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears all default commands.
|
||||
/// </summary>
|
||||
/// <param name="cmds"></param>
|
||||
public static void ClearDefaultCommands(this Dictionary<BotCommandScope, List<BotCommand>> cmds)
|
||||
{
|
||||
Clear(cmds);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears all commands of a specific device.
|
||||
/// </summary>
|
||||
/// <param name="cmds"></param>
|
||||
public static void ClearChatCommands(this Dictionary<BotCommandScope, List<BotCommand>> cmds, long deviceId)
|
||||
{
|
||||
Clear(cmds, new BotCommandScopeChat { ChatId = deviceId });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adding a chat command with a description.
|
||||
/// </summary>
|
||||
/// <param name="cmds"></param>
|
||||
/// <param name="command"></param>
|
||||
/// <param name="description"></param>
|
||||
public static void AddChatCommand(this Dictionary<BotCommandScope, List<BotCommand>> cmds, long deviceId,
|
||||
string command, string description)
|
||||
{
|
||||
Add(cmds, command, description, new BotCommandScopeChat { ChatId = deviceId });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adding a group command with a description.
|
||||
/// </summary>
|
||||
/// <param name="cmds"></param>
|
||||
/// <param name="command"></param>
|
||||
/// <param name="description"></param>
|
||||
public static void AddGroupCommand(this Dictionary<BotCommandScope, List<BotCommand>> cmds, string command,
|
||||
string description)
|
||||
{
|
||||
Add(cmds, command, description, new BotCommandScopeAllGroupChats());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears all group commands.
|
||||
/// </summary>
|
||||
/// <param name="cmds"></param>
|
||||
public static void ClearGroupCommands(this Dictionary<BotCommandScope, List<BotCommand>> cmds)
|
||||
{
|
||||
Clear(cmds, new BotCommandScopeAllGroupChats());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adding group admin command with a description.
|
||||
/// </summary>
|
||||
/// <param name="cmds"></param>
|
||||
/// <param name="command"></param>
|
||||
/// <param name="description"></param>
|
||||
public static void AddGroupAdminCommand(this Dictionary<BotCommandScope, List<BotCommand>> cmds, string command,
|
||||
string description)
|
||||
{
|
||||
Add(cmds, command, description, new BotCommandScopeAllChatAdministrators());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears all group admin commands.
|
||||
/// </summary>
|
||||
/// <param name="cmds"></param>
|
||||
public static void ClearGroupAdminCommand(this Dictionary<BotCommandScope, List<BotCommand>> cmds)
|
||||
{
|
||||
Clear(cmds, new BotCommandScopeAllChatAdministrators());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adding a privat command with a description.
|
||||
/// </summary>
|
||||
/// <param name="cmds"></param>
|
||||
/// <param name="command"></param>
|
||||
/// <param name="description"></param>
|
||||
public static void AddPrivateChatCommand(this Dictionary<BotCommandScope, List<BotCommand>> cmds,
|
||||
string command, string description)
|
||||
{
|
||||
Add(cmds, command, description, new BotCommandScopeAllPrivateChats());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears all private commands.
|
||||
/// </summary>
|
||||
/// <param name="cmds"></param>
|
||||
public static void ClearPrivateChatCommand(this Dictionary<BotCommandScope, List<BotCommand>> cmds)
|
||||
{
|
||||
Clear(cmds, new BotCommandScopeAllPrivateChats());
|
||||
}
|
||||
}
|
||||
@@ -1,21 +1,19 @@
|
||||
namespace TelegramBotBase.Constants
|
||||
namespace TelegramBotBase.Constants;
|
||||
|
||||
public static class Telegram
|
||||
{
|
||||
public static class Telegram
|
||||
{
|
||||
/// <summary>
|
||||
/// The maximum length of message text before the API throws an exception. (We will catch it before)
|
||||
/// </summary>
|
||||
public const int MaxMessageLength = 4096;
|
||||
/// <summary>
|
||||
/// The maximum length of message text before the API throws an exception. (We will catch it before)
|
||||
/// </summary>
|
||||
public const int MaxMessageLength = 4096;
|
||||
|
||||
public const int MaxInlineKeyBoardRows = 13;
|
||||
public const int MaxInlineKeyBoardRows = 13;
|
||||
|
||||
public const int MaxInlineKeyBoardCols = 8;
|
||||
public const int MaxInlineKeyBoardCols = 8;
|
||||
|
||||
public const int MaxReplyKeyboardRows = 25;
|
||||
public const int MaxReplyKeyboardRows = 25;
|
||||
|
||||
public const int MaxReplyKeyboardCols = 12;
|
||||
public const int MaxReplyKeyboardCols = 12;
|
||||
|
||||
public const int MessageDeletionsPerSecond = 30;
|
||||
|
||||
}
|
||||
}
|
||||
public const int MessageDeletionsPerSecond = 30;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -4,93 +4,101 @@ using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using TelegramBotBase.Form;
|
||||
|
||||
namespace TelegramBotBase.Controls.Hybrid
|
||||
namespace TelegramBotBase.Controls.Hybrid;
|
||||
|
||||
[DebuggerDisplay("{Count} columns")]
|
||||
public class ButtonRow
|
||||
{
|
||||
[DebuggerDisplay("{Count} columns")]
|
||||
public class ButtonRow
|
||||
private List<ButtonBase> _buttons = new();
|
||||
|
||||
public ButtonRow()
|
||||
{
|
||||
private List<ButtonBase> _buttons = new List<ButtonBase>();
|
||||
|
||||
public ButtonRow()
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
public ButtonRow(params ButtonBase[] buttons)
|
||||
{
|
||||
_buttons = buttons.ToList();
|
||||
}
|
||||
|
||||
|
||||
public ButtonBase this[int index] => _buttons[index];
|
||||
|
||||
public int Count => _buttons.Count;
|
||||
|
||||
public void Add(ButtonBase button)
|
||||
{
|
||||
_buttons.Add(button);
|
||||
}
|
||||
|
||||
public void AddRange(ButtonBase button)
|
||||
{
|
||||
_buttons.Add(button);
|
||||
}
|
||||
|
||||
public void Insert(int index, ButtonBase button)
|
||||
{
|
||||
_buttons.Insert(index, button);
|
||||
}
|
||||
|
||||
public IEnumerator<ButtonBase> GetEnumerator()
|
||||
{
|
||||
return _buttons.GetEnumerator();
|
||||
}
|
||||
|
||||
public ButtonBase[] ToArray()
|
||||
{
|
||||
return _buttons.ToArray();
|
||||
}
|
||||
|
||||
public List<ButtonBase> ToList()
|
||||
{
|
||||
return _buttons.ToList();
|
||||
}
|
||||
|
||||
public bool Matches(string text, bool useText = true)
|
||||
{
|
||||
foreach (var b in _buttons)
|
||||
{
|
||||
if (useText && b.Text.Trim().Equals(text, StringComparison.InvariantCultureIgnoreCase))
|
||||
return true;
|
||||
|
||||
if (!useText && b.Value.Equals(text, StringComparison.InvariantCultureIgnoreCase))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the button inside of the row which matches.
|
||||
/// </summary>
|
||||
/// <param name="text"></param>
|
||||
/// <param name="useText"></param>
|
||||
/// <returns></returns>
|
||||
public ButtonBase GetButtonMatch(string text, bool useText = true)
|
||||
{
|
||||
foreach (var b in _buttons)
|
||||
{
|
||||
if (useText && b.Text.Trim().Equals(text, StringComparison.InvariantCultureIgnoreCase))
|
||||
return b;
|
||||
if (!useText && b.Value.Equals(text, StringComparison.InvariantCultureIgnoreCase))
|
||||
return b;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static implicit operator ButtonRow(List<ButtonBase> list)
|
||||
{
|
||||
return new ButtonRow { _buttons = list };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ButtonRow(params ButtonBase[] buttons)
|
||||
{
|
||||
_buttons = buttons.ToList();
|
||||
}
|
||||
|
||||
|
||||
public ButtonBase this[int index] => _buttons[index];
|
||||
|
||||
public int Count => _buttons.Count;
|
||||
|
||||
public void Add(ButtonBase button)
|
||||
{
|
||||
_buttons.Add(button);
|
||||
}
|
||||
|
||||
public void AddRange(ButtonBase button)
|
||||
{
|
||||
_buttons.Add(button);
|
||||
}
|
||||
|
||||
public void Insert(int index, ButtonBase button)
|
||||
{
|
||||
_buttons.Insert(index, button);
|
||||
}
|
||||
|
||||
public IEnumerator<ButtonBase> GetEnumerator()
|
||||
{
|
||||
return _buttons.GetEnumerator();
|
||||
}
|
||||
|
||||
public ButtonBase[] ToArray()
|
||||
{
|
||||
return _buttons.ToArray();
|
||||
}
|
||||
|
||||
public List<ButtonBase> ToList()
|
||||
{
|
||||
return _buttons.ToList();
|
||||
}
|
||||
|
||||
public bool Matches(string text, bool useText = true)
|
||||
{
|
||||
foreach (var b in _buttons)
|
||||
{
|
||||
if (useText && b.Text.Trim().Equals(text, StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!useText && b.Value.Equals(text, StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the button inside of the row which matches.
|
||||
/// </summary>
|
||||
/// <param name="text"></param>
|
||||
/// <param name="useText"></param>
|
||||
/// <returns></returns>
|
||||
public ButtonBase GetButtonMatch(string text, bool useText = true)
|
||||
{
|
||||
foreach (var b in _buttons)
|
||||
{
|
||||
if (useText && b.Text.Trim().Equals(text, StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
return b;
|
||||
}
|
||||
|
||||
if (!useText && b.Value.Equals(text, StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static implicit operator ButtonRow(List<ButtonBase> list)
|
||||
{
|
||||
return new ButtonRow { _buttons = list };
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3,124 +3,125 @@ using System.Threading.Tasks;
|
||||
using TelegramBotBase.Args;
|
||||
using TelegramBotBase.Base;
|
||||
|
||||
namespace TelegramBotBase.Controls.Hybrid
|
||||
namespace TelegramBotBase.Controls.Hybrid;
|
||||
|
||||
/// <summary>
|
||||
/// This Control is for having a basic form content switching control.
|
||||
/// </summary>
|
||||
public abstract class MultiView : ControlBase
|
||||
{
|
||||
private int _mISelectedViewIndex;
|
||||
|
||||
/// <summary>
|
||||
/// This Control is for having a basic form content switching control.
|
||||
/// Hold if the View has been rendered already.
|
||||
/// </summary>
|
||||
public abstract class MultiView : ControlBase
|
||||
private bool _rendered;
|
||||
|
||||
|
||||
public MultiView()
|
||||
{
|
||||
/// <summary>
|
||||
/// Index of the current View.
|
||||
/// </summary>
|
||||
public int SelectedViewIndex
|
||||
{
|
||||
get => _mISelectedViewIndex;
|
||||
set
|
||||
{
|
||||
_mISelectedViewIndex = value;
|
||||
|
||||
//Already rendered? Re-Render
|
||||
if (_rendered)
|
||||
ForceRender().Wait();
|
||||
}
|
||||
}
|
||||
|
||||
private int _mISelectedViewIndex;
|
||||
|
||||
/// <summary>
|
||||
/// Hold if the View has been rendered already.
|
||||
/// </summary>
|
||||
private bool _rendered;
|
||||
|
||||
private List<int> Messages { get; set; }
|
||||
|
||||
|
||||
public MultiView()
|
||||
{
|
||||
Messages = new List<int>();
|
||||
}
|
||||
|
||||
|
||||
private Task Device_MessageSent(object sender, MessageSentEventArgs e)
|
||||
{
|
||||
if (e.Origin == null || !e.Origin.IsSubclassOf(typeof(MultiView)))
|
||||
return Task.CompletedTask;
|
||||
|
||||
Messages.Add(e.MessageId);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public override void Init()
|
||||
{
|
||||
Device.MessageSent += Device_MessageSent;
|
||||
}
|
||||
|
||||
public override Task Load(MessageResult result)
|
||||
{
|
||||
_rendered = false;
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
|
||||
public override async Task Render(MessageResult result)
|
||||
{
|
||||
//When already rendered, skip rendering
|
||||
if (_rendered)
|
||||
return;
|
||||
|
||||
await CleanUpView();
|
||||
|
||||
await RenderView(new RenderViewEventArgs(SelectedViewIndex));
|
||||
|
||||
_rendered = true;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Will get invoked on rendering the current controls view.
|
||||
/// </summary>
|
||||
/// <param name="e"></param>
|
||||
public virtual Task RenderView(RenderViewEventArgs e)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private async Task CleanUpView()
|
||||
{
|
||||
|
||||
var tasks = new List<Task>();
|
||||
|
||||
foreach (var msg in Messages)
|
||||
{
|
||||
tasks.Add(Device.DeleteMessage(msg));
|
||||
}
|
||||
|
||||
await Task.WhenAll(tasks);
|
||||
|
||||
Messages.Clear();
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Forces render of control contents.
|
||||
/// </summary>
|
||||
public async Task ForceRender()
|
||||
{
|
||||
await CleanUpView();
|
||||
|
||||
await RenderView(new RenderViewEventArgs(SelectedViewIndex));
|
||||
|
||||
_rendered = true;
|
||||
}
|
||||
|
||||
public override async Task Cleanup()
|
||||
{
|
||||
Device.MessageSent -= Device_MessageSent;
|
||||
|
||||
await CleanUpView();
|
||||
}
|
||||
|
||||
Messages = new List<int>();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Index of the current View.
|
||||
/// </summary>
|
||||
public int SelectedViewIndex
|
||||
{
|
||||
get => _mISelectedViewIndex;
|
||||
set
|
||||
{
|
||||
_mISelectedViewIndex = value;
|
||||
|
||||
//Already rendered? Re-Render
|
||||
if (_rendered)
|
||||
{
|
||||
ForceRender().Wait();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<int> Messages { get; }
|
||||
|
||||
|
||||
private Task Device_MessageSent(object sender, MessageSentEventArgs e)
|
||||
{
|
||||
if (e.Origin == null || !e.Origin.IsSubclassOf(typeof(MultiView)))
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
Messages.Add(e.MessageId);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public override void Init()
|
||||
{
|
||||
Device.MessageSent += Device_MessageSent;
|
||||
}
|
||||
|
||||
public override Task Load(MessageResult result)
|
||||
{
|
||||
_rendered = false;
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
|
||||
public override async Task Render(MessageResult result)
|
||||
{
|
||||
//When already rendered, skip rendering
|
||||
if (_rendered)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
await CleanUpView();
|
||||
|
||||
await RenderView(new RenderViewEventArgs(SelectedViewIndex));
|
||||
|
||||
_rendered = true;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Will get invoked on rendering the current controls view.
|
||||
/// </summary>
|
||||
/// <param name="e"></param>
|
||||
public virtual Task RenderView(RenderViewEventArgs e)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private async Task CleanUpView()
|
||||
{
|
||||
var tasks = new List<Task>();
|
||||
|
||||
foreach (var msg in Messages)
|
||||
{
|
||||
tasks.Add(Device.DeleteMessage(msg));
|
||||
}
|
||||
|
||||
await Task.WhenAll(tasks);
|
||||
|
||||
Messages.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Forces render of control contents.
|
||||
/// </summary>
|
||||
public async Task ForceRender()
|
||||
{
|
||||
await CleanUpView();
|
||||
|
||||
await RenderView(new RenderViewEventArgs(SelectedViewIndex));
|
||||
|
||||
_rendered = true;
|
||||
}
|
||||
|
||||
public override async Task Cleanup()
|
||||
{
|
||||
Device.MessageSent -= Device_MessageSent;
|
||||
|
||||
await CleanUpView();
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -10,254 +10,257 @@ using TelegramBotBase.Localizations;
|
||||
using static TelegramBotBase.Tools.Arrays;
|
||||
using static TelegramBotBase.Tools.Time;
|
||||
|
||||
namespace TelegramBotBase.Controls.Inline
|
||||
namespace TelegramBotBase.Controls.Inline;
|
||||
|
||||
public class CalendarPicker : ControlBase
|
||||
{
|
||||
public class CalendarPicker : ControlBase
|
||||
public CalendarPicker(CultureInfo culture)
|
||||
{
|
||||
SelectedDate = DateTime.Today;
|
||||
VisibleMonth = DateTime.Today;
|
||||
FirstDayOfWeek = DayOfWeek.Monday;
|
||||
Culture = culture;
|
||||
PickerMode = EMonthPickerMode.day;
|
||||
}
|
||||
|
||||
public DateTime SelectedDate { get; set; }
|
||||
public CalendarPicker() : this(new CultureInfo("en-en"))
|
||||
{
|
||||
}
|
||||
|
||||
public DateTime VisibleMonth { get; set; }
|
||||
public DateTime SelectedDate { get; set; }
|
||||
|
||||
public DayOfWeek FirstDayOfWeek { get; set; }
|
||||
public DateTime VisibleMonth { get; set; }
|
||||
|
||||
public CultureInfo Culture { get; set; }
|
||||
public DayOfWeek FirstDayOfWeek { get; set; }
|
||||
|
||||
public CultureInfo Culture { get; set; }
|
||||
|
||||
|
||||
private int? MessageId { get; set; }
|
||||
private int? MessageId { get; set; }
|
||||
|
||||
public string Title { get; set; } = Default.Language["CalendarPicker_Title"];
|
||||
public string Title { get; set; } = Default.Language["CalendarPicker_Title"];
|
||||
|
||||
public EMonthPickerMode PickerMode { get; set; }
|
||||
public EMonthPickerMode PickerMode { get; set; }
|
||||
|
||||
public bool EnableDayView { get; set; } = true;
|
||||
public bool EnableDayView { get; set; } = true;
|
||||
|
||||
public bool EnableMonthView { get; set; } = true;
|
||||
public bool EnableMonthView { get; set; } = true;
|
||||
|
||||
public bool EnableYearView { get; set; } = true;
|
||||
public bool EnableYearView { get; set; } = true;
|
||||
|
||||
public CalendarPicker(CultureInfo culture)
|
||||
|
||||
public override async Task Action(MessageResult result, string value = null)
|
||||
{
|
||||
await result.ConfirmAction();
|
||||
|
||||
switch (result.RawData)
|
||||
{
|
||||
SelectedDate = DateTime.Today;
|
||||
VisibleMonth = DateTime.Today;
|
||||
FirstDayOfWeek = DayOfWeek.Monday;
|
||||
Culture = culture;
|
||||
PickerMode = EMonthPickerMode.day;
|
||||
}
|
||||
case "$next$":
|
||||
|
||||
public CalendarPicker() : this(new CultureInfo("en-en")) { }
|
||||
VisibleMonth = PickerMode switch
|
||||
{
|
||||
EMonthPickerMode.day => VisibleMonth.AddMonths(1),
|
||||
EMonthPickerMode.month => VisibleMonth.AddYears(1),
|
||||
EMonthPickerMode.year => VisibleMonth.AddYears(10),
|
||||
_ => VisibleMonth
|
||||
};
|
||||
|
||||
break;
|
||||
case "$prev$":
|
||||
|
||||
VisibleMonth = PickerMode switch
|
||||
{
|
||||
EMonthPickerMode.day => VisibleMonth.AddMonths(-1),
|
||||
EMonthPickerMode.month => VisibleMonth.AddYears(-1),
|
||||
EMonthPickerMode.year => VisibleMonth.AddYears(-10),
|
||||
_ => VisibleMonth
|
||||
};
|
||||
|
||||
break;
|
||||
|
||||
public override async Task Action(MessageResult result, string value = null)
|
||||
{
|
||||
await result.ConfirmAction();
|
||||
case "$monthtitle$":
|
||||
|
||||
switch (result.RawData)
|
||||
{
|
||||
case "$next$":
|
||||
if (EnableMonthView)
|
||||
{
|
||||
PickerMode = EMonthPickerMode.month;
|
||||
}
|
||||
|
||||
VisibleMonth = PickerMode switch
|
||||
{
|
||||
EMonthPickerMode.day => VisibleMonth.AddMonths(1),
|
||||
EMonthPickerMode.month => VisibleMonth.AddYears(1),
|
||||
EMonthPickerMode.year => VisibleMonth.AddYears(10),
|
||||
_ => VisibleMonth
|
||||
};
|
||||
break;
|
||||
|
||||
break;
|
||||
case "$prev$":
|
||||
case "$yeartitle$":
|
||||
|
||||
VisibleMonth = PickerMode switch
|
||||
{
|
||||
EMonthPickerMode.day => VisibleMonth.AddMonths(-1),
|
||||
EMonthPickerMode.month => VisibleMonth.AddYears(-1),
|
||||
EMonthPickerMode.year => VisibleMonth.AddYears(-10),
|
||||
_ => VisibleMonth
|
||||
};
|
||||
if (EnableYearView)
|
||||
{
|
||||
PickerMode = EMonthPickerMode.year;
|
||||
}
|
||||
|
||||
break;
|
||||
break;
|
||||
case "$yearstitle$":
|
||||
|
||||
case "$monthtitle$":
|
||||
if (EnableMonthView)
|
||||
{
|
||||
PickerMode = EMonthPickerMode.month;
|
||||
}
|
||||
|
||||
if (EnableMonthView)
|
||||
{
|
||||
PickerMode = EMonthPickerMode.month;
|
||||
}
|
||||
VisibleMonth = SelectedDate;
|
||||
|
||||
break;
|
||||
break;
|
||||
|
||||
case "$yeartitle$":
|
||||
default:
|
||||
|
||||
if (EnableYearView)
|
||||
{
|
||||
PickerMode = EMonthPickerMode.year;
|
||||
}
|
||||
|
||||
break;
|
||||
case "$yearstitle$":
|
||||
|
||||
if (EnableMonthView)
|
||||
{
|
||||
PickerMode = EMonthPickerMode.month;
|
||||
}
|
||||
var day = 0;
|
||||
if (result.RawData.StartsWith("d-") &&
|
||||
TryParseDay(result.RawData.Split('-')[1], SelectedDate, out day))
|
||||
{
|
||||
SelectedDate = new DateTime(VisibleMonth.Year, VisibleMonth.Month, day);
|
||||
}
|
||||
|
||||
var month = 0;
|
||||
if (result.RawData.StartsWith("m-") && TryParseMonth(result.RawData.Split('-')[1], out month))
|
||||
{
|
||||
SelectedDate = new DateTime(VisibleMonth.Year, month, 1);
|
||||
VisibleMonth = SelectedDate;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
var day = 0;
|
||||
if (result.RawData.StartsWith("d-") && TryParseDay(result.RawData.Split('-')[1], SelectedDate, out day))
|
||||
if (EnableDayView)
|
||||
{
|
||||
SelectedDate = new DateTime(VisibleMonth.Year, VisibleMonth.Month, day);
|
||||
PickerMode = EMonthPickerMode.day;
|
||||
}
|
||||
}
|
||||
|
||||
var month = 0;
|
||||
if (result.RawData.StartsWith("m-") && TryParseMonth(result.RawData.Split('-')[1], out month))
|
||||
var year = 0;
|
||||
if (result.RawData.StartsWith("y-") && TryParseYear(result.RawData.Split('-')[1], out year))
|
||||
{
|
||||
SelectedDate = new DateTime(year, SelectedDate.Month, SelectedDate.Day);
|
||||
VisibleMonth = SelectedDate;
|
||||
|
||||
if (EnableMonthView)
|
||||
{
|
||||
SelectedDate = new DateTime(VisibleMonth.Year, month, 1);
|
||||
VisibleMonth = SelectedDate;
|
||||
|
||||
if (EnableDayView)
|
||||
{
|
||||
PickerMode = EMonthPickerMode.day;
|
||||
}
|
||||
PickerMode = EMonthPickerMode.month;
|
||||
}
|
||||
}
|
||||
|
||||
var year = 0;
|
||||
if (result.RawData.StartsWith("y-") && TryParseYear(result.RawData.Split('-')[1], out year))
|
||||
{
|
||||
SelectedDate = new DateTime(year, SelectedDate.Month, SelectedDate.Day);
|
||||
VisibleMonth = SelectedDate;
|
||||
|
||||
if (EnableMonthView)
|
||||
{
|
||||
PickerMode = EMonthPickerMode.month;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public override async Task Render(MessageResult result)
|
||||
{
|
||||
|
||||
|
||||
|
||||
var bf = new ButtonForm();
|
||||
|
||||
switch (PickerMode)
|
||||
{
|
||||
case EMonthPickerMode.day:
|
||||
|
||||
var month = VisibleMonth;
|
||||
|
||||
var dayNamesNormal = Culture.DateTimeFormat.ShortestDayNames;
|
||||
var dayNamesShifted = Shift(dayNamesNormal, (int)FirstDayOfWeek);
|
||||
|
||||
bf.AddButtonRow(new ButtonBase(Default.Language["CalendarPicker_PreviousPage"], "$prev$"), new ButtonBase(Culture.DateTimeFormat.MonthNames[month.Month - 1] + " " + month.Year, "$monthtitle$"), new ButtonBase(Default.Language["CalendarPicker_NextPage"], "$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(FirstDayOfWeek);
|
||||
|
||||
//End of week where last day of month is (right border)
|
||||
var end = lastDay.EndOfWeek(FirstDayOfWeek);
|
||||
|
||||
for (var i = 0; i <= ((end - start).Days / 7); i++)
|
||||
{
|
||||
var lst = new List<ButtonBase>();
|
||||
for (var id = 0; id < 7; id++)
|
||||
{
|
||||
var d = start.AddDays((i * 7) + id);
|
||||
if (d < firstDay | d > lastDay)
|
||||
{
|
||||
lst.Add(new ButtonBase("-", "m-" + d.Day));
|
||||
continue;
|
||||
}
|
||||
|
||||
var day = d.Day.ToString();
|
||||
|
||||
if (d == DateTime.Today)
|
||||
{
|
||||
day = "(" + day + ")";
|
||||
}
|
||||
|
||||
lst.Add(new ButtonBase((SelectedDate == d ? "[" + day + "]" : day), "d-" + d.Day));
|
||||
}
|
||||
bf.AddButtonRow(lst);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case EMonthPickerMode.month:
|
||||
|
||||
bf.AddButtonRow(new ButtonBase(Default.Language["CalendarPicker_PreviousPage"], "$prev$"), new ButtonBase(VisibleMonth.Year.ToString("0000"), "$yeartitle$"), new ButtonBase(Default.Language["CalendarPicker_NextPage"], "$next$"));
|
||||
|
||||
var months = Culture.DateTimeFormat.MonthNames;
|
||||
|
||||
var buttons = months.Select((a, b) => new ButtonBase((b == SelectedDate.Month - 1 && SelectedDate.Year == VisibleMonth.Year ? "[ " + a + " ]" : a), "m-" + (b + 1)));
|
||||
|
||||
bf.AddSplitted(buttons);
|
||||
|
||||
break;
|
||||
|
||||
case EMonthPickerMode.year:
|
||||
|
||||
bf.AddButtonRow(new ButtonBase(Default.Language["CalendarPicker_PreviousPage"], "$prev$"), new ButtonBase("Year", "$yearstitle$"), new ButtonBase(Default.Language["CalendarPicker_NextPage"], "$next$"));
|
||||
|
||||
var starti = Math.Floor(VisibleMonth.Year / 10f) * 10;
|
||||
|
||||
for (var i = 0; i < 10; i++)
|
||||
{
|
||||
var m = starti + (i * 2);
|
||||
bf.AddButtonRow(new ButtonBase((SelectedDate.Year == m ? "[ " + m + " ]" : m.ToString()), "y-" + m), new ButtonBase((SelectedDate.Year == (m + 1) ? "[ " + (m + 1) + " ]" : (m + 1).ToString()), "y-" + (m + 1)));
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
|
||||
if (MessageId != null)
|
||||
{
|
||||
var m = await Device.Edit(MessageId.Value, Title, bf);
|
||||
}
|
||||
else
|
||||
{
|
||||
var m = await Device.Send(Title, bf);
|
||||
MessageId = m.MessageId;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public override async Task Cleanup()
|
||||
{
|
||||
|
||||
if (MessageId != null)
|
||||
{
|
||||
await Device.DeleteMessage(MessageId.Value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public override async Task Render(MessageResult result)
|
||||
{
|
||||
var bf = new ButtonForm();
|
||||
|
||||
switch (PickerMode)
|
||||
{
|
||||
case EMonthPickerMode.day:
|
||||
|
||||
var month = VisibleMonth;
|
||||
|
||||
var dayNamesNormal = Culture.DateTimeFormat.ShortestDayNames;
|
||||
var dayNamesShifted = Shift(dayNamesNormal, (int)FirstDayOfWeek);
|
||||
|
||||
bf.AddButtonRow(new ButtonBase(Default.Language["CalendarPicker_PreviousPage"], "$prev$"),
|
||||
new ButtonBase(Culture.DateTimeFormat.MonthNames[month.Month - 1] + " " + month.Year,
|
||||
"$monthtitle$"),
|
||||
new ButtonBase(Default.Language["CalendarPicker_NextPage"], "$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(FirstDayOfWeek);
|
||||
|
||||
//End of week where last day of month is (right border)
|
||||
var end = lastDay.EndOfWeek(FirstDayOfWeek);
|
||||
|
||||
for (var i = 0; i <= (end - start).Days / 7; i++)
|
||||
{
|
||||
var lst = new List<ButtonBase>();
|
||||
for (var id = 0; id < 7; id++)
|
||||
{
|
||||
var d = start.AddDays(i * 7 + id);
|
||||
if ((d < firstDay) | (d > lastDay))
|
||||
{
|
||||
lst.Add(new ButtonBase("-", "m-" + d.Day));
|
||||
continue;
|
||||
}
|
||||
|
||||
var day = d.Day.ToString();
|
||||
|
||||
if (d == DateTime.Today)
|
||||
{
|
||||
day = "(" + day + ")";
|
||||
}
|
||||
|
||||
lst.Add(new ButtonBase(SelectedDate == d ? "[" + day + "]" : day, "d-" + d.Day));
|
||||
}
|
||||
|
||||
bf.AddButtonRow(lst);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case EMonthPickerMode.month:
|
||||
|
||||
bf.AddButtonRow(new ButtonBase(Default.Language["CalendarPicker_PreviousPage"], "$prev$"),
|
||||
new ButtonBase(VisibleMonth.Year.ToString("0000"), "$yeartitle$"),
|
||||
new ButtonBase(Default.Language["CalendarPicker_NextPage"], "$next$"));
|
||||
|
||||
var months = Culture.DateTimeFormat.MonthNames;
|
||||
|
||||
var buttons = months.Select((a, b) =>
|
||||
new ButtonBase(
|
||||
b == SelectedDate.Month - 1 &&
|
||||
SelectedDate.Year == VisibleMonth.Year
|
||||
? "[ " + a + " ]"
|
||||
: a,
|
||||
"m-" + (b + 1)));
|
||||
|
||||
bf.AddSplitted(buttons);
|
||||
|
||||
break;
|
||||
|
||||
case EMonthPickerMode.year:
|
||||
|
||||
bf.AddButtonRow(new ButtonBase(Default.Language["CalendarPicker_PreviousPage"], "$prev$"),
|
||||
new ButtonBase("Year", "$yearstitle$"),
|
||||
new ButtonBase(Default.Language["CalendarPicker_NextPage"], "$next$"));
|
||||
|
||||
var starti = Math.Floor(VisibleMonth.Year / 10f) * 10;
|
||||
|
||||
for (var i = 0; i < 10; i++)
|
||||
{
|
||||
var m = starti + i * 2;
|
||||
bf.AddButtonRow(
|
||||
new ButtonBase(SelectedDate.Year == m ? "[ " + m + " ]" : m.ToString(), "y-" + m),
|
||||
new ButtonBase(SelectedDate.Year == m + 1 ? "[ " + (m + 1) + " ]" : (m + 1).ToString(),
|
||||
"y-" + (m + 1)));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (MessageId != null)
|
||||
{
|
||||
var m = await Device.Edit(MessageId.Value, Title, bf);
|
||||
}
|
||||
else
|
||||
{
|
||||
var m = await Device.Send(Title, bf);
|
||||
MessageId = m.MessageId;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public override async Task Cleanup()
|
||||
{
|
||||
if (MessageId != null)
|
||||
{
|
||||
await Device.DeleteMessage(MessageId.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,12 @@
|
||||
using TelegramBotBase.Enums;
|
||||
|
||||
namespace TelegramBotBase.Controls.Inline
|
||||
namespace TelegramBotBase.Controls.Inline;
|
||||
|
||||
public class MonthPicker : CalendarPicker
|
||||
{
|
||||
public class MonthPicker : CalendarPicker
|
||||
public MonthPicker()
|
||||
{
|
||||
|
||||
|
||||
|
||||
public MonthPicker()
|
||||
{
|
||||
PickerMode = EMonthPickerMode.month;
|
||||
EnableDayView = false;
|
||||
}
|
||||
|
||||
|
||||
PickerMode = EMonthPickerMode.month;
|
||||
EnableDayView = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,152 +6,147 @@ using TelegramBotBase.Base;
|
||||
using TelegramBotBase.Form;
|
||||
using TelegramBotBase.Localizations;
|
||||
|
||||
namespace TelegramBotBase.Controls.Inline
|
||||
namespace TelegramBotBase.Controls.Inline;
|
||||
|
||||
public class MultiToggleButton : ControlBase
|
||||
{
|
||||
public class MultiToggleButton : ControlBase
|
||||
private static readonly object EvToggled = new();
|
||||
|
||||
private readonly EventHandlerList _events = new();
|
||||
|
||||
private bool _renderNecessary = true;
|
||||
|
||||
|
||||
public MultiToggleButton()
|
||||
{
|
||||
/// <summary>
|
||||
/// This contains the selected icon.
|
||||
/// </summary>
|
||||
public string SelectedIcon { get; set; } = Default.Language["MultiToggleButton_SelectedIcon"];
|
||||
Options = new List<ButtonBase>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This will appear on the ConfirmAction message (if not empty)
|
||||
/// </summary>
|
||||
public string ChangedString { get; set; } = Default.Language["MultiToggleButton_Changed"];
|
||||
/// <summary>
|
||||
/// This contains the selected icon.
|
||||
/// </summary>
|
||||
public string SelectedIcon { get; set; } = Default.Language["MultiToggleButton_SelectedIcon"];
|
||||
|
||||
/// <summary>
|
||||
/// This holds the title of the control.
|
||||
/// </summary>
|
||||
public string Title { get; set; } = Default.Language["MultiToggleButton_Title"];
|
||||
/// <summary>
|
||||
/// This will appear on the ConfirmAction message (if not empty)
|
||||
/// </summary>
|
||||
public string ChangedString { get; set; } = Default.Language["MultiToggleButton_Changed"];
|
||||
|
||||
public int? MessageId { get; set; }
|
||||
/// <summary>
|
||||
/// This holds the title of the control.
|
||||
/// </summary>
|
||||
public string Title { get; set; } = Default.Language["MultiToggleButton_Title"];
|
||||
|
||||
private bool _renderNecessary = true;
|
||||
public int? MessageId { get; set; }
|
||||
|
||||
private static readonly object EvToggled = new object();
|
||||
/// <summary>
|
||||
/// This will hold all options available.
|
||||
/// </summary>
|
||||
public List<ButtonBase> Options { get; set; }
|
||||
|
||||
private readonly EventHandlerList _events = new EventHandlerList();
|
||||
/// <summary>
|
||||
/// This will set if an empty selection (null) is allowed.
|
||||
/// </summary>
|
||||
public bool AllowEmptySelection { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// This will hold all options available.
|
||||
/// </summary>
|
||||
public List<ButtonBase> Options { get; set; }
|
||||
public ButtonBase SelectedOption { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// This will set if an empty selection (null) is allowed.
|
||||
/// </summary>
|
||||
public bool AllowEmptySelection { get; set; } = true;
|
||||
public event EventHandler Toggled
|
||||
{
|
||||
add => _events.AddHandler(EvToggled, value);
|
||||
remove => _events.RemoveHandler(EvToggled, value);
|
||||
}
|
||||
|
||||
public void OnToggled(EventArgs e)
|
||||
{
|
||||
(_events[EvToggled] as EventHandler)?.Invoke(this, e);
|
||||
}
|
||||
|
||||
public MultiToggleButton()
|
||||
public override async Task Action(MessageResult result, string value = null)
|
||||
{
|
||||
if (result.Handled)
|
||||
{
|
||||
Options = new List<ButtonBase>();
|
||||
return;
|
||||
}
|
||||
|
||||
public event EventHandler Toggled
|
||||
await result.ConfirmAction(ChangedString);
|
||||
|
||||
switch (value ?? "unknown")
|
||||
{
|
||||
add => _events.AddHandler(EvToggled, value);
|
||||
remove => _events.RemoveHandler(EvToggled, value);
|
||||
}
|
||||
default:
|
||||
|
||||
public void OnToggled(EventArgs e)
|
||||
{
|
||||
(_events[EvToggled] as EventHandler)?.Invoke(this, e);
|
||||
}
|
||||
var s = value.Split('$');
|
||||
|
||||
public override async Task Action(MessageResult result, string value = null)
|
||||
{
|
||||
if (result.Handled)
|
||||
return;
|
||||
|
||||
await result.ConfirmAction(ChangedString);
|
||||
|
||||
switch (value ?? "unknown")
|
||||
{
|
||||
default:
|
||||
|
||||
var s = value.Split('$');
|
||||
|
||||
if (s[0] == "check" && s.Length > 1)
|
||||
if (s[0] == "check" && s.Length > 1)
|
||||
{
|
||||
var index = 0;
|
||||
if (!int.TryParse(s[1], out index))
|
||||
{
|
||||
var index = 0;
|
||||
if (!int.TryParse(s[1], out index))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if(SelectedOption== null || SelectedOption != Options[index])
|
||||
{
|
||||
SelectedOption = Options[index];
|
||||
OnToggled(EventArgs.Empty);
|
||||
}
|
||||
else if(AllowEmptySelection)
|
||||
{
|
||||
SelectedOption = null;
|
||||
OnToggled(EventArgs.Empty);
|
||||
}
|
||||
|
||||
_renderNecessary = true;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (SelectedOption == null || SelectedOption != Options[index])
|
||||
{
|
||||
SelectedOption = Options[index];
|
||||
OnToggled(EventArgs.Empty);
|
||||
}
|
||||
else if (AllowEmptySelection)
|
||||
{
|
||||
SelectedOption = null;
|
||||
OnToggled(EventArgs.Empty);
|
||||
}
|
||||
|
||||
_renderNecessary = false;
|
||||
_renderNecessary = true;
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
result.Handled = true;
|
||||
|
||||
}
|
||||
|
||||
public override async Task Render(MessageResult result)
|
||||
{
|
||||
if (!_renderNecessary)
|
||||
return;
|
||||
|
||||
var bf = new ButtonForm(this);
|
||||
|
||||
var lst = new List<ButtonBase>();
|
||||
foreach (var o in Options)
|
||||
{
|
||||
var index = Options.IndexOf(o);
|
||||
if (o == SelectedOption)
|
||||
{
|
||||
lst.Add(new ButtonBase(SelectedIcon + " " + o.Text, "check$" + index));
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
|
||||
lst.Add(new ButtonBase(o.Text, "check$" + index));
|
||||
}
|
||||
|
||||
bf.AddButtonRow(lst);
|
||||
|
||||
if (MessageId != null)
|
||||
{
|
||||
var m = await Device.Edit(MessageId.Value, Title, bf);
|
||||
}
|
||||
else
|
||||
{
|
||||
var m = await Device.Send(Title, bf, disableNotification: true);
|
||||
if (m != null)
|
||||
{
|
||||
MessageId = m.MessageId;
|
||||
}
|
||||
}
|
||||
|
||||
_renderNecessary = false;
|
||||
|
||||
_renderNecessary = false;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
public ButtonBase SelectedOption
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
result.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task Render(MessageResult result)
|
||||
{
|
||||
if (!_renderNecessary)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var bf = new ButtonForm(this);
|
||||
|
||||
var lst = new List<ButtonBase>();
|
||||
foreach (var o in Options)
|
||||
{
|
||||
var index = Options.IndexOf(o);
|
||||
if (o == SelectedOption)
|
||||
{
|
||||
lst.Add(new ButtonBase(SelectedIcon + " " + o.Text, "check$" + index));
|
||||
continue;
|
||||
}
|
||||
|
||||
lst.Add(new ButtonBase(o.Text, "check$" + index));
|
||||
}
|
||||
|
||||
bf.AddButtonRow(lst);
|
||||
|
||||
if (MessageId != null)
|
||||
{
|
||||
var m = await Device.Edit(MessageId.Value, Title, bf);
|
||||
}
|
||||
else
|
||||
{
|
||||
var m = await Device.Send(Title, bf, disableNotification: true);
|
||||
if (m != null)
|
||||
{
|
||||
MessageId = m.MessageId;
|
||||
}
|
||||
}
|
||||
|
||||
_renderNecessary = false;
|
||||
}
|
||||
}
|
||||
@@ -2,266 +2,255 @@
|
||||
using System.Threading.Tasks;
|
||||
using TelegramBotBase.Base;
|
||||
|
||||
namespace TelegramBotBase.Controls.Inline
|
||||
namespace TelegramBotBase.Controls.Inline;
|
||||
|
||||
/// <summary>
|
||||
/// A simple control for show and managing progress.
|
||||
/// </summary>
|
||||
public class ProgressBar : ControlBase
|
||||
{
|
||||
/// <summary>
|
||||
/// A simple control for show and managing progress.
|
||||
/// </summary>
|
||||
public class ProgressBar : ControlBase
|
||||
public enum EProgressStyle
|
||||
{
|
||||
public enum EProgressStyle
|
||||
{
|
||||
standard = 0,
|
||||
squares = 1,
|
||||
circles = 2,
|
||||
lines = 3,
|
||||
squaredLines = 4,
|
||||
custom = 10
|
||||
}
|
||||
|
||||
public EProgressStyle ProgressStyle
|
||||
{
|
||||
get => _mEStyle;
|
||||
set
|
||||
{
|
||||
_mEStyle = value;
|
||||
LoadStyle();
|
||||
}
|
||||
}
|
||||
|
||||
private EProgressStyle _mEStyle = EProgressStyle.standard;
|
||||
|
||||
|
||||
public int Value
|
||||
{
|
||||
get => _mIValue;
|
||||
set
|
||||
{
|
||||
if (value > Max)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_mIValue != value)
|
||||
{
|
||||
RenderNecessary = true;
|
||||
}
|
||||
_mIValue = value;
|
||||
}
|
||||
}
|
||||
|
||||
private int _mIValue;
|
||||
|
||||
public int Max
|
||||
{
|
||||
get => _mIMax;
|
||||
set
|
||||
{
|
||||
if (_mIMax != value)
|
||||
{
|
||||
RenderNecessary = true;
|
||||
}
|
||||
_mIMax = value;
|
||||
}
|
||||
}
|
||||
|
||||
private int _mIMax = 100;
|
||||
|
||||
public int? MessageId { get; set; }
|
||||
|
||||
private bool RenderNecessary { get; set; }
|
||||
|
||||
public int Steps
|
||||
{
|
||||
get
|
||||
{
|
||||
return ProgressStyle switch
|
||||
{
|
||||
EProgressStyle.standard => 1,
|
||||
EProgressStyle.squares => 10,
|
||||
EProgressStyle.circles => 10,
|
||||
EProgressStyle.lines => 5,
|
||||
EProgressStyle.squaredLines => 5,
|
||||
_ => 1
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Filled block (reached percentage)
|
||||
/// </summary>
|
||||
public string BlockChar
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unfilled block (not reached yet)
|
||||
/// </summary>
|
||||
public string EmptyBlockChar
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// String at the beginning of the progress bar
|
||||
/// </summary>
|
||||
public string StartChar
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// String at the end of the progress bar
|
||||
/// </summary>
|
||||
public string EndChar
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public ProgressBar()
|
||||
{
|
||||
ProgressStyle = EProgressStyle.standard;
|
||||
|
||||
Value = 0;
|
||||
Max = 100;
|
||||
|
||||
RenderNecessary = true;
|
||||
}
|
||||
|
||||
public ProgressBar(int value, int max, EProgressStyle style)
|
||||
{
|
||||
this.Value = value;
|
||||
this.Max = max;
|
||||
ProgressStyle = style;
|
||||
|
||||
RenderNecessary = true;
|
||||
}
|
||||
|
||||
public override async Task Cleanup()
|
||||
{
|
||||
if (MessageId == null || MessageId == -1)
|
||||
return;
|
||||
|
||||
|
||||
await Device.DeleteMessage(MessageId.Value);
|
||||
}
|
||||
|
||||
public void LoadStyle()
|
||||
{
|
||||
StartChar = "";
|
||||
EndChar = "";
|
||||
|
||||
switch (ProgressStyle)
|
||||
{
|
||||
case EProgressStyle.circles:
|
||||
|
||||
BlockChar = "⚫️ ";
|
||||
EmptyBlockChar = "⚪️ ";
|
||||
|
||||
break;
|
||||
case EProgressStyle.squares:
|
||||
|
||||
BlockChar = "⬛️ ";
|
||||
EmptyBlockChar = "⬜️ ";
|
||||
|
||||
break;
|
||||
case EProgressStyle.lines:
|
||||
|
||||
BlockChar = "█";
|
||||
EmptyBlockChar = "▁";
|
||||
|
||||
break;
|
||||
case EProgressStyle.squaredLines:
|
||||
|
||||
BlockChar = "▇";
|
||||
EmptyBlockChar = "—";
|
||||
|
||||
StartChar = "[";
|
||||
EndChar = "]";
|
||||
|
||||
break;
|
||||
case EProgressStyle.standard:
|
||||
case EProgressStyle.custom:
|
||||
|
||||
BlockChar = "";
|
||||
EmptyBlockChar = "";
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public override async Task Render(MessageResult result)
|
||||
{
|
||||
if (!RenderNecessary)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (Device == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var message = "";
|
||||
var blocks = 0;
|
||||
var maxBlocks = 0;
|
||||
|
||||
switch (ProgressStyle)
|
||||
{
|
||||
case EProgressStyle.standard:
|
||||
|
||||
message = Value.ToString("0") + "%";
|
||||
|
||||
break;
|
||||
|
||||
case EProgressStyle.squares:
|
||||
case EProgressStyle.circles:
|
||||
case EProgressStyle.lines:
|
||||
case EProgressStyle.squaredLines:
|
||||
case EProgressStyle.custom:
|
||||
|
||||
blocks = (int)Math.Floor((decimal)Value / Steps);
|
||||
|
||||
maxBlocks = (Max / Steps);
|
||||
|
||||
message += StartChar;
|
||||
|
||||
for (var i = 0; i < blocks; i++)
|
||||
{
|
||||
message += BlockChar;
|
||||
}
|
||||
|
||||
for (var i = 0; i < (maxBlocks - blocks); i++)
|
||||
{
|
||||
message += EmptyBlockChar;
|
||||
}
|
||||
|
||||
message += EndChar;
|
||||
|
||||
message += " " + Value.ToString("0") + "%";
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (MessageId == null)
|
||||
{
|
||||
var m = await Device.Send(message);
|
||||
|
||||
MessageId = m.MessageId;
|
||||
}
|
||||
else
|
||||
{
|
||||
await Device.Edit(MessageId.Value, message);
|
||||
}
|
||||
|
||||
RenderNecessary = false;
|
||||
}
|
||||
|
||||
standard = 0,
|
||||
squares = 1,
|
||||
circles = 2,
|
||||
lines = 3,
|
||||
squaredLines = 4,
|
||||
custom = 10
|
||||
}
|
||||
}
|
||||
|
||||
private EProgressStyle _mEStyle = EProgressStyle.standard;
|
||||
|
||||
private int _mIMax = 100;
|
||||
|
||||
private int _mIValue;
|
||||
|
||||
public ProgressBar()
|
||||
{
|
||||
ProgressStyle = EProgressStyle.standard;
|
||||
|
||||
Value = 0;
|
||||
Max = 100;
|
||||
|
||||
RenderNecessary = true;
|
||||
}
|
||||
|
||||
public ProgressBar(int value, int max, EProgressStyle style)
|
||||
{
|
||||
Value = value;
|
||||
Max = max;
|
||||
ProgressStyle = style;
|
||||
|
||||
RenderNecessary = true;
|
||||
}
|
||||
|
||||
public EProgressStyle ProgressStyle
|
||||
{
|
||||
get => _mEStyle;
|
||||
set
|
||||
{
|
||||
_mEStyle = value;
|
||||
LoadStyle();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public int Value
|
||||
{
|
||||
get => _mIValue;
|
||||
set
|
||||
{
|
||||
if (value > Max)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_mIValue != value)
|
||||
{
|
||||
RenderNecessary = true;
|
||||
}
|
||||
|
||||
_mIValue = value;
|
||||
}
|
||||
}
|
||||
|
||||
public int Max
|
||||
{
|
||||
get => _mIMax;
|
||||
set
|
||||
{
|
||||
if (_mIMax != value)
|
||||
{
|
||||
RenderNecessary = true;
|
||||
}
|
||||
|
||||
_mIMax = value;
|
||||
}
|
||||
}
|
||||
|
||||
public int? MessageId { get; set; }
|
||||
|
||||
private bool RenderNecessary { get; set; }
|
||||
|
||||
public int Steps
|
||||
{
|
||||
get
|
||||
{
|
||||
return ProgressStyle switch
|
||||
{
|
||||
EProgressStyle.standard => 1,
|
||||
EProgressStyle.squares => 10,
|
||||
EProgressStyle.circles => 10,
|
||||
EProgressStyle.lines => 5,
|
||||
EProgressStyle.squaredLines => 5,
|
||||
_ => 1
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Filled block (reached percentage)
|
||||
/// </summary>
|
||||
public string BlockChar { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Unfilled block (not reached yet)
|
||||
/// </summary>
|
||||
public string EmptyBlockChar { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// String at the beginning of the progress bar
|
||||
/// </summary>
|
||||
public string StartChar { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// String at the end of the progress bar
|
||||
/// </summary>
|
||||
public string EndChar { get; set; }
|
||||
|
||||
public override async Task Cleanup()
|
||||
{
|
||||
if (MessageId == null || MessageId == -1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
await Device.DeleteMessage(MessageId.Value);
|
||||
}
|
||||
|
||||
public void LoadStyle()
|
||||
{
|
||||
StartChar = "";
|
||||
EndChar = "";
|
||||
|
||||
switch (ProgressStyle)
|
||||
{
|
||||
case EProgressStyle.circles:
|
||||
|
||||
BlockChar = "⚫️ ";
|
||||
EmptyBlockChar = "⚪️ ";
|
||||
|
||||
break;
|
||||
case EProgressStyle.squares:
|
||||
|
||||
BlockChar = "⬛️ ";
|
||||
EmptyBlockChar = "⬜️ ";
|
||||
|
||||
break;
|
||||
case EProgressStyle.lines:
|
||||
|
||||
BlockChar = "█";
|
||||
EmptyBlockChar = "▁";
|
||||
|
||||
break;
|
||||
case EProgressStyle.squaredLines:
|
||||
|
||||
BlockChar = "▇";
|
||||
EmptyBlockChar = "—";
|
||||
|
||||
StartChar = "[";
|
||||
EndChar = "]";
|
||||
|
||||
break;
|
||||
case EProgressStyle.standard:
|
||||
case EProgressStyle.custom:
|
||||
|
||||
BlockChar = "";
|
||||
EmptyBlockChar = "";
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task Render(MessageResult result)
|
||||
{
|
||||
if (!RenderNecessary)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (Device == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var message = "";
|
||||
var blocks = 0;
|
||||
var maxBlocks = 0;
|
||||
|
||||
switch (ProgressStyle)
|
||||
{
|
||||
case EProgressStyle.standard:
|
||||
|
||||
message = Value.ToString("0") + "%";
|
||||
|
||||
break;
|
||||
|
||||
case EProgressStyle.squares:
|
||||
case EProgressStyle.circles:
|
||||
case EProgressStyle.lines:
|
||||
case EProgressStyle.squaredLines:
|
||||
case EProgressStyle.custom:
|
||||
|
||||
blocks = (int)Math.Floor((decimal)Value / Steps);
|
||||
|
||||
maxBlocks = Max / Steps;
|
||||
|
||||
message += StartChar;
|
||||
|
||||
for (var i = 0; i < blocks; i++)
|
||||
{
|
||||
message += BlockChar;
|
||||
}
|
||||
|
||||
for (var i = 0; i < maxBlocks - blocks; i++)
|
||||
{
|
||||
message += EmptyBlockChar;
|
||||
}
|
||||
|
||||
message += EndChar;
|
||||
|
||||
message += " " + Value.ToString("0") + "%";
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (MessageId == null)
|
||||
{
|
||||
var m = await Device.Send(message);
|
||||
|
||||
MessageId = m.MessageId;
|
||||
}
|
||||
else
|
||||
{
|
||||
await Device.Edit(MessageId.Value, message);
|
||||
}
|
||||
|
||||
RenderNecessary = false;
|
||||
}
|
||||
}
|
||||
@@ -5,135 +5,133 @@ using TelegramBotBase.Base;
|
||||
using TelegramBotBase.Form;
|
||||
using TelegramBotBase.Localizations;
|
||||
|
||||
namespace TelegramBotBase.Controls.Inline
|
||||
namespace TelegramBotBase.Controls.Inline;
|
||||
|
||||
public class ToggleButton : ControlBase
|
||||
{
|
||||
public class ToggleButton : ControlBase
|
||||
private static readonly object EvToggled = new();
|
||||
|
||||
private readonly EventHandlerList _events = new();
|
||||
|
||||
private bool _renderNecessary = true;
|
||||
|
||||
|
||||
public ToggleButton()
|
||||
{
|
||||
|
||||
public string UncheckedIcon { get; set; } = Default.Language["ToggleButton_OffIcon"];
|
||||
|
||||
public string CheckedIcon { get; set; } = Default.Language["ToggleButton_OnIcon"];
|
||||
|
||||
public string CheckedString { get; set; } = Default.Language["ToggleButton_On"];
|
||||
|
||||
public string UncheckedString { get; set; } = Default.Language["ToggleButton_Off"];
|
||||
|
||||
public string ChangedString { get; set; } = Default.Language["ToggleButton_Changed"];
|
||||
|
||||
public string Title { get; set; } = Default.Language["ToggleButton_Title"];
|
||||
|
||||
public int? MessageId { get; set; }
|
||||
|
||||
public bool Checked { get; set; }
|
||||
|
||||
private bool _renderNecessary = true;
|
||||
|
||||
private static readonly object EvToggled = new object();
|
||||
|
||||
private readonly EventHandlerList _events = new EventHandlerList();
|
||||
|
||||
|
||||
public ToggleButton()
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
public ToggleButton(string checkedString, string uncheckedString)
|
||||
{
|
||||
this.CheckedString = checkedString;
|
||||
this.UncheckedString = uncheckedString;
|
||||
}
|
||||
|
||||
public event EventHandler Toggled
|
||||
{
|
||||
add => _events.AddHandler(EvToggled, value);
|
||||
remove => _events.RemoveHandler(EvToggled, value);
|
||||
}
|
||||
|
||||
public void OnToggled(EventArgs e)
|
||||
{
|
||||
(_events[EvToggled] as EventHandler)?.Invoke(this, e);
|
||||
}
|
||||
|
||||
public override async Task Action(MessageResult result, string value = null)
|
||||
{
|
||||
|
||||
if (result.Handled)
|
||||
return;
|
||||
|
||||
await result.ConfirmAction(ChangedString);
|
||||
|
||||
switch (value ?? "unknown")
|
||||
{
|
||||
case "on":
|
||||
|
||||
if (Checked)
|
||||
return;
|
||||
|
||||
_renderNecessary = true;
|
||||
|
||||
Checked = true;
|
||||
|
||||
OnToggled(EventArgs.Empty);
|
||||
|
||||
break;
|
||||
|
||||
case "off":
|
||||
|
||||
if (!Checked)
|
||||
return;
|
||||
|
||||
_renderNecessary = true;
|
||||
|
||||
Checked = false;
|
||||
|
||||
OnToggled(EventArgs.Empty);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
_renderNecessary = false;
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
result.Handled = true;
|
||||
|
||||
}
|
||||
|
||||
public override async Task Render(MessageResult result)
|
||||
{
|
||||
if (!_renderNecessary)
|
||||
return;
|
||||
|
||||
var bf = new ButtonForm(this);
|
||||
|
||||
var bOn = new ButtonBase((Checked ? CheckedIcon : UncheckedIcon) + " " + CheckedString, "on");
|
||||
|
||||
var bOff = new ButtonBase((!Checked ? CheckedIcon : UncheckedIcon) + " " + UncheckedString, "off");
|
||||
|
||||
bf.AddButtonRow(bOn, bOff);
|
||||
|
||||
if (MessageId != null)
|
||||
{
|
||||
var m = await Device.Edit(MessageId.Value, Title, bf);
|
||||
}
|
||||
else
|
||||
{
|
||||
var m = await Device.Send(Title, bf, disableNotification: true);
|
||||
if (m != null)
|
||||
{
|
||||
MessageId = m.MessageId;
|
||||
}
|
||||
}
|
||||
|
||||
_renderNecessary = false;
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public ToggleButton(string checkedString, string uncheckedString)
|
||||
{
|
||||
CheckedString = checkedString;
|
||||
UncheckedString = uncheckedString;
|
||||
}
|
||||
|
||||
public string UncheckedIcon { get; set; } = Default.Language["ToggleButton_OffIcon"];
|
||||
|
||||
public string CheckedIcon { get; set; } = Default.Language["ToggleButton_OnIcon"];
|
||||
|
||||
public string CheckedString { get; set; } = Default.Language["ToggleButton_On"];
|
||||
|
||||
public string UncheckedString { get; set; } = Default.Language["ToggleButton_Off"];
|
||||
|
||||
public string ChangedString { get; set; } = Default.Language["ToggleButton_Changed"];
|
||||
|
||||
public string Title { get; set; } = Default.Language["ToggleButton_Title"];
|
||||
|
||||
public int? MessageId { get; set; }
|
||||
|
||||
public bool Checked { get; set; }
|
||||
|
||||
public event EventHandler Toggled
|
||||
{
|
||||
add => _events.AddHandler(EvToggled, value);
|
||||
remove => _events.RemoveHandler(EvToggled, value);
|
||||
}
|
||||
|
||||
public void OnToggled(EventArgs e)
|
||||
{
|
||||
(_events[EvToggled] as EventHandler)?.Invoke(this, e);
|
||||
}
|
||||
|
||||
public override async Task Action(MessageResult result, string value = null)
|
||||
{
|
||||
if (result.Handled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
await result.ConfirmAction(ChangedString);
|
||||
|
||||
switch (value ?? "unknown")
|
||||
{
|
||||
case "on":
|
||||
|
||||
if (Checked)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_renderNecessary = true;
|
||||
|
||||
Checked = true;
|
||||
|
||||
OnToggled(EventArgs.Empty);
|
||||
|
||||
break;
|
||||
|
||||
case "off":
|
||||
|
||||
if (!Checked)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_renderNecessary = true;
|
||||
|
||||
Checked = false;
|
||||
|
||||
OnToggled(EventArgs.Empty);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
_renderNecessary = false;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
result.Handled = true;
|
||||
}
|
||||
|
||||
public override async Task Render(MessageResult result)
|
||||
{
|
||||
if (!_renderNecessary)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var bf = new ButtonForm(this);
|
||||
|
||||
var bOn = new ButtonBase((Checked ? CheckedIcon : UncheckedIcon) + " " + CheckedString, "on");
|
||||
|
||||
var bOff = new ButtonBase((!Checked ? CheckedIcon : UncheckedIcon) + " " + UncheckedString, "off");
|
||||
|
||||
bf.AddButtonRow(bOn, bOff);
|
||||
|
||||
if (MessageId != null)
|
||||
{
|
||||
var m = await Device.Edit(MessageId.Value, Title, bf);
|
||||
}
|
||||
else
|
||||
{
|
||||
var m = await Device.Send(Title, bf, disableNotification: true);
|
||||
if (m != null)
|
||||
{
|
||||
MessageId = m.MessageId;
|
||||
}
|
||||
}
|
||||
|
||||
_renderNecessary = false;
|
||||
}
|
||||
}
|
||||
@@ -5,117 +5,117 @@ using TelegramBotBase.Base;
|
||||
using TelegramBotBase.Form;
|
||||
using TelegramBotBase.Localizations;
|
||||
|
||||
namespace TelegramBotBase.Controls.Inline
|
||||
namespace TelegramBotBase.Controls.Inline;
|
||||
|
||||
public class TreeView : ControlBase
|
||||
{
|
||||
public class TreeView : ControlBase
|
||||
public TreeView()
|
||||
{
|
||||
public List<TreeViewNode> Nodes { get; set; }
|
||||
Nodes = new List<TreeViewNode>();
|
||||
Title = Default.Language["TreeView_Title"];
|
||||
}
|
||||
|
||||
public TreeViewNode SelectedNode { get; set; }
|
||||
public List<TreeViewNode> Nodes { get; set; }
|
||||
|
||||
public TreeViewNode VisibleNode { get; set; }
|
||||
public TreeViewNode SelectedNode { get; set; }
|
||||
|
||||
public string Title { get; set; }
|
||||
public TreeViewNode VisibleNode { get; set; }
|
||||
|
||||
private int? MessageId { get; set; }
|
||||
public string Title { get; set; }
|
||||
|
||||
public string MoveUpIcon { get; set; } = Default.Language["TreeView_LevelUp"];
|
||||
private int? MessageId { get; set; }
|
||||
|
||||
public TreeView()
|
||||
public string MoveUpIcon { get; set; } = Default.Language["TreeView_LevelUp"];
|
||||
|
||||
|
||||
public override async Task Action(MessageResult result, string value = null)
|
||||
{
|
||||
await result.ConfirmAction();
|
||||
|
||||
if (result.Handled)
|
||||
{
|
||||
Nodes = new List<TreeViewNode>();
|
||||
Title = Default.Language["TreeView_Title"];
|
||||
return;
|
||||
}
|
||||
|
||||
var val = result.RawData;
|
||||
|
||||
public override async Task Action(MessageResult result, string value = null)
|
||||
switch (val)
|
||||
{
|
||||
await result.ConfirmAction();
|
||||
case "up":
|
||||
case "parent":
|
||||
|
||||
if (result.Handled)
|
||||
return;
|
||||
VisibleNode = VisibleNode?.ParentNode;
|
||||
|
||||
var val = result.RawData;
|
||||
result.Handled = true;
|
||||
|
||||
switch (val)
|
||||
{
|
||||
case "up":
|
||||
case "parent":
|
||||
break;
|
||||
default:
|
||||
|
||||
VisibleNode = (VisibleNode?.ParentNode);
|
||||
var n = VisibleNode != null
|
||||
? VisibleNode.FindNodeByValue(val)
|
||||
: Nodes.FirstOrDefault(a => a.Value == val);
|
||||
|
||||
result.Handled = true;
|
||||
|
||||
break;
|
||||
default:
|
||||
|
||||
var n = (VisibleNode != null ? VisibleNode.FindNodeByValue(val) : Nodes.FirstOrDefault(a => a.Value == val));
|
||||
|
||||
if (n == null)
|
||||
return;
|
||||
|
||||
|
||||
if (n.ChildNodes.Count > 0)
|
||||
{
|
||||
VisibleNode = n;
|
||||
}
|
||||
else
|
||||
{
|
||||
SelectedNode = (SelectedNode != n ? n : null);
|
||||
}
|
||||
|
||||
result.Handled = true;
|
||||
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public override async Task Render(MessageResult result)
|
||||
{
|
||||
var startnode = VisibleNode;
|
||||
|
||||
var nodes = (startnode?.ChildNodes ?? Nodes);
|
||||
|
||||
var bf = new ButtonForm();
|
||||
|
||||
if (startnode != null)
|
||||
{
|
||||
bf.AddButtonRow(new ButtonBase(MoveUpIcon, "up"), new ButtonBase(startnode.Text, "parent"));
|
||||
}
|
||||
|
||||
foreach (var n in nodes)
|
||||
{
|
||||
var s = n.Text;
|
||||
if (SelectedNode == n)
|
||||
if (n == null)
|
||||
{
|
||||
s = "[ " + s + " ]";
|
||||
return;
|
||||
}
|
||||
|
||||
bf.AddButtonRow(new ButtonBase(s, n.Value, n.Url));
|
||||
}
|
||||
|
||||
if (n.ChildNodes.Count > 0)
|
||||
{
|
||||
VisibleNode = n;
|
||||
}
|
||||
else
|
||||
{
|
||||
SelectedNode = SelectedNode != n ? n : null;
|
||||
}
|
||||
|
||||
result.Handled = true;
|
||||
|
||||
|
||||
|
||||
if (MessageId != null)
|
||||
{
|
||||
var m = await Device.Edit(MessageId.Value, Title, bf);
|
||||
}
|
||||
else
|
||||
{
|
||||
var m = await Device.Send(Title, bf);
|
||||
MessageId = m.MessageId;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
public string GetPath()
|
||||
{
|
||||
return (VisibleNode?.GetPath() ?? "\\");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public override async Task Render(MessageResult result)
|
||||
{
|
||||
var startnode = VisibleNode;
|
||||
|
||||
var nodes = startnode?.ChildNodes ?? Nodes;
|
||||
|
||||
var bf = new ButtonForm();
|
||||
|
||||
if (startnode != null)
|
||||
{
|
||||
bf.AddButtonRow(new ButtonBase(MoveUpIcon, "up"), new ButtonBase(startnode.Text, "parent"));
|
||||
}
|
||||
|
||||
foreach (var n in nodes)
|
||||
{
|
||||
var s = n.Text;
|
||||
if (SelectedNode == n)
|
||||
{
|
||||
s = "[ " + s + " ]";
|
||||
}
|
||||
|
||||
bf.AddButtonRow(new ButtonBase(s, n.Value, n.Url));
|
||||
}
|
||||
|
||||
|
||||
if (MessageId != null)
|
||||
{
|
||||
var m = await Device.Edit(MessageId.Value, Title, bf);
|
||||
}
|
||||
else
|
||||
{
|
||||
var m = await Device.Send(Title, bf);
|
||||
MessageId = m.MessageId;
|
||||
}
|
||||
}
|
||||
|
||||
public string GetPath()
|
||||
{
|
||||
return VisibleNode?.GetPath() ?? "\\";
|
||||
}
|
||||
}
|
||||
@@ -1,62 +1,61 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace TelegramBotBase.Controls.Inline
|
||||
namespace TelegramBotBase.Controls.Inline;
|
||||
|
||||
public class TreeViewNode
|
||||
{
|
||||
public class TreeViewNode
|
||||
public TreeViewNode(string text, string value)
|
||||
{
|
||||
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 ChildNodes.FirstOrDefault(a => a.Value == value);
|
||||
}
|
||||
|
||||
public string GetPath()
|
||||
{
|
||||
var s = "\\" + Value;
|
||||
var p = this;
|
||||
while (p.ParentNode != null)
|
||||
{
|
||||
s = "\\" + p.ParentNode.Value + s;
|
||||
p = p.ParentNode;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
Text = text;
|
||||
Value = value;
|
||||
}
|
||||
}
|
||||
|
||||
public TreeViewNode(string text, string value, string url) : this(text, value)
|
||||
{
|
||||
Url = url;
|
||||
}
|
||||
|
||||
public TreeViewNode(string text, string value, params TreeViewNode[] childnodes) : this(text, value)
|
||||
{
|
||||
foreach (var c in childnodes)
|
||||
{
|
||||
AddNode(c);
|
||||
}
|
||||
}
|
||||
|
||||
public string Text { get; set; }
|
||||
|
||||
public string Value { get; set; }
|
||||
|
||||
public string Url { get; set; }
|
||||
|
||||
public List<TreeViewNode> ChildNodes { get; set; } = new();
|
||||
|
||||
public TreeViewNode ParentNode { get; set; }
|
||||
|
||||
|
||||
public void AddNode(TreeViewNode node)
|
||||
{
|
||||
node.ParentNode = this;
|
||||
ChildNodes.Add(node);
|
||||
}
|
||||
|
||||
public TreeViewNode FindNodeByValue(string value)
|
||||
{
|
||||
return ChildNodes.FirstOrDefault(a => a.Value == value);
|
||||
}
|
||||
|
||||
public string GetPath()
|
||||
{
|
||||
var s = "\\" + Value;
|
||||
var p = this;
|
||||
while (p.ParentNode != null)
|
||||
{
|
||||
s = "\\" + p.ParentNode.Value + s;
|
||||
p = p.ParentNode;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
}
|
||||
@@ -4,132 +4,134 @@ using TelegramBotBase.Controls.Hybrid;
|
||||
using TelegramBotBase.Form;
|
||||
using TelegramBotBase.Interfaces;
|
||||
|
||||
namespace TelegramBotBase.DataSources
|
||||
namespace TelegramBotBase.DataSources;
|
||||
|
||||
public class ButtonFormDataSource : IDataSource<ButtonRow>
|
||||
{
|
||||
public class ButtonFormDataSource : IDataSource<ButtonRow>
|
||||
private ButtonForm _buttonform;
|
||||
|
||||
public ButtonFormDataSource()
|
||||
{
|
||||
public virtual ButtonForm ButtonForm
|
||||
{
|
||||
get => _buttonform;
|
||||
set => _buttonform = value;
|
||||
}
|
||||
|
||||
private ButtonForm _buttonform;
|
||||
|
||||
public ButtonFormDataSource()
|
||||
{
|
||||
_buttonform = new ButtonForm();
|
||||
}
|
||||
|
||||
public ButtonFormDataSource(ButtonForm bf)
|
||||
{
|
||||
_buttonform = bf;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns the amount of rows exisiting.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public virtual int Count => ButtonForm.Count;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns the amount of rows.
|
||||
/// </summary>
|
||||
public virtual int RowCount => ButtonForm.Rows;
|
||||
|
||||
/// <summary>
|
||||
/// Returns the maximum amount of columns.
|
||||
/// </summary>
|
||||
public virtual int ColumnCount => ButtonForm.Cols;
|
||||
|
||||
/// <summary>
|
||||
/// Returns the row with the specific index.
|
||||
/// </summary>
|
||||
/// <param name="index"></param>
|
||||
/// <returns></returns>
|
||||
public virtual ButtonRow ItemAt(int index)
|
||||
{
|
||||
return ButtonForm[index];
|
||||
}
|
||||
|
||||
public virtual List<ButtonRow> ItemRange(int start, int count)
|
||||
{
|
||||
return ButtonForm.GetRange(start, count);
|
||||
}
|
||||
|
||||
public virtual List<ButtonRow> AllItems()
|
||||
{
|
||||
return ButtonForm.ToArray();
|
||||
}
|
||||
|
||||
public virtual ButtonForm PickItems(int start, int count, string filter = null)
|
||||
{
|
||||
var bf = new ButtonForm();
|
||||
ButtonForm dataForm = null;
|
||||
|
||||
if (filter == null)
|
||||
{
|
||||
dataForm = ButtonForm.Duplicate();
|
||||
}
|
||||
else
|
||||
{
|
||||
dataForm = ButtonForm.FilterDuplicate(filter, true);
|
||||
}
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
var it = start + i;
|
||||
|
||||
if (it > dataForm.Rows - 1)
|
||||
break;
|
||||
|
||||
bf.AddButtonRow(dataForm[it]);
|
||||
}
|
||||
|
||||
return bf;
|
||||
}
|
||||
|
||||
public virtual ButtonForm PickAllItems(string filter = null)
|
||||
{
|
||||
if (filter == null)
|
||||
return ButtonForm.Duplicate();
|
||||
|
||||
|
||||
return ButtonForm.FilterDuplicate(filter, true);
|
||||
}
|
||||
|
||||
public virtual Tuple<ButtonRow, int> FindRow(string text, bool useText = true)
|
||||
{
|
||||
return ButtonForm.FindRow(text, useText);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the maximum items of this data source.
|
||||
/// </summary>
|
||||
/// <param name="filter"></param>
|
||||
/// <returns></returns>
|
||||
public virtual int CalculateMax(string filter = null)
|
||||
{
|
||||
return PickAllItems(filter).Rows;
|
||||
}
|
||||
|
||||
public virtual ButtonRow Render(object data)
|
||||
{
|
||||
return data as ButtonRow;
|
||||
}
|
||||
|
||||
|
||||
public static implicit operator ButtonFormDataSource(ButtonForm bf)
|
||||
{
|
||||
return new ButtonFormDataSource(bf);
|
||||
}
|
||||
|
||||
public static implicit operator ButtonForm(ButtonFormDataSource ds)
|
||||
{
|
||||
return ds.ButtonForm;
|
||||
}
|
||||
|
||||
_buttonform = new ButtonForm();
|
||||
}
|
||||
}
|
||||
|
||||
public ButtonFormDataSource(ButtonForm bf)
|
||||
{
|
||||
_buttonform = bf;
|
||||
}
|
||||
|
||||
public virtual ButtonForm ButtonForm
|
||||
{
|
||||
get => _buttonform;
|
||||
set => _buttonform = value;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns the amount of rows.
|
||||
/// </summary>
|
||||
public virtual int RowCount => ButtonForm.Rows;
|
||||
|
||||
/// <summary>
|
||||
/// Returns the maximum amount of columns.
|
||||
/// </summary>
|
||||
public virtual int ColumnCount => ButtonForm.Cols;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns the amount of rows exisiting.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public virtual int Count => ButtonForm.Count;
|
||||
|
||||
/// <summary>
|
||||
/// Returns the row with the specific index.
|
||||
/// </summary>
|
||||
/// <param name="index"></param>
|
||||
/// <returns></returns>
|
||||
public virtual ButtonRow ItemAt(int index)
|
||||
{
|
||||
return ButtonForm[index];
|
||||
}
|
||||
|
||||
public virtual List<ButtonRow> ItemRange(int start, int count)
|
||||
{
|
||||
return ButtonForm.GetRange(start, count);
|
||||
}
|
||||
|
||||
public virtual List<ButtonRow> AllItems()
|
||||
{
|
||||
return ButtonForm.ToArray();
|
||||
}
|
||||
|
||||
public virtual ButtonForm PickItems(int start, int count, string filter = null)
|
||||
{
|
||||
var bf = new ButtonForm();
|
||||
ButtonForm dataForm = null;
|
||||
|
||||
if (filter == null)
|
||||
{
|
||||
dataForm = ButtonForm.Duplicate();
|
||||
}
|
||||
else
|
||||
{
|
||||
dataForm = ButtonForm.FilterDuplicate(filter, true);
|
||||
}
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
var it = start + i;
|
||||
|
||||
if (it > dataForm.Rows - 1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
bf.AddButtonRow(dataForm[it]);
|
||||
}
|
||||
|
||||
return bf;
|
||||
}
|
||||
|
||||
public virtual ButtonForm PickAllItems(string filter = null)
|
||||
{
|
||||
if (filter == null)
|
||||
{
|
||||
return ButtonForm.Duplicate();
|
||||
}
|
||||
|
||||
|
||||
return ButtonForm.FilterDuplicate(filter, true);
|
||||
}
|
||||
|
||||
public virtual Tuple<ButtonRow, int> FindRow(string text, bool useText = true)
|
||||
{
|
||||
return ButtonForm.FindRow(text, useText);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the maximum items of this data source.
|
||||
/// </summary>
|
||||
/// <param name="filter"></param>
|
||||
/// <returns></returns>
|
||||
public virtual int CalculateMax(string filter = null)
|
||||
{
|
||||
return PickAllItems(filter).Rows;
|
||||
}
|
||||
|
||||
public virtual ButtonRow Render(object data)
|
||||
{
|
||||
return data as ButtonRow;
|
||||
}
|
||||
|
||||
|
||||
public static implicit operator ButtonFormDataSource(ButtonForm bf)
|
||||
{
|
||||
return new ButtonFormDataSource(bf);
|
||||
}
|
||||
|
||||
public static implicit operator ButtonForm(ButtonFormDataSource ds)
|
||||
{
|
||||
return ds.ButtonForm;
|
||||
}
|
||||
}
|
||||
@@ -2,38 +2,36 @@
|
||||
using System.Linq;
|
||||
using TelegramBotBase.Interfaces;
|
||||
|
||||
namespace TelegramBotBase.DataSources
|
||||
namespace TelegramBotBase.DataSources;
|
||||
|
||||
public class StaticDataSource<T> : IDataSource<T>
|
||||
{
|
||||
public class StaticDataSource<T> : IDataSource<T>
|
||||
public StaticDataSource()
|
||||
{
|
||||
private List<T> Data { get; set; }
|
||||
|
||||
public StaticDataSource()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public StaticDataSource(List<T> data)
|
||||
{
|
||||
Data = data;
|
||||
}
|
||||
|
||||
|
||||
public int Count => Data.Count;
|
||||
|
||||
public T ItemAt(int index)
|
||||
{
|
||||
return Data[index];
|
||||
}
|
||||
|
||||
public List<T> ItemRange(int start, int count)
|
||||
{
|
||||
return Data.Skip(start).Take(count).ToList();
|
||||
}
|
||||
|
||||
public List<T> AllItems()
|
||||
{
|
||||
return Data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public StaticDataSource(List<T> data)
|
||||
{
|
||||
Data = data;
|
||||
}
|
||||
|
||||
private List<T> Data { get; }
|
||||
|
||||
|
||||
public int Count => Data.Count;
|
||||
|
||||
public T ItemAt(int index)
|
||||
{
|
||||
return Data[index];
|
||||
}
|
||||
|
||||
public List<T> ItemRange(int start, int count)
|
||||
{
|
||||
return Data.Skip(start).Take(count).ToList();
|
||||
}
|
||||
|
||||
public List<T> AllItems()
|
||||
{
|
||||
return Data;
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,19 @@
|
||||
namespace TelegramBotBase.Enums
|
||||
namespace TelegramBotBase.Enums;
|
||||
|
||||
public enum EDeleteMode
|
||||
{
|
||||
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
|
||||
}
|
||||
}
|
||||
/// <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
|
||||
}
|
||||
@@ -1,18 +1,19 @@
|
||||
namespace TelegramBotBase.Enums
|
||||
namespace TelegramBotBase.Enums;
|
||||
|
||||
public enum EDeleteSide
|
||||
{
|
||||
public enum EDeleteSide
|
||||
{
|
||||
/// <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
|
||||
}
|
||||
}
|
||||
/// <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
|
||||
}
|
||||
@@ -1,16 +1,14 @@
|
||||
namespace TelegramBotBase.Enums
|
||||
namespace TelegramBotBase.Enums;
|
||||
|
||||
public enum EKeyboardType
|
||||
{
|
||||
public enum EKeyboardType
|
||||
{
|
||||
/// <summary>
|
||||
/// Uses a ReplyKeyboardMarkup
|
||||
/// </summary>
|
||||
ReplyKeyboard = 0,
|
||||
/// <summary>
|
||||
/// Uses a ReplyKeyboardMarkup
|
||||
/// </summary>
|
||||
ReplyKeyboard = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Uses a InlineKeyboardMakup
|
||||
/// </summary>
|
||||
InlineKeyBoard = 1
|
||||
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Uses a InlineKeyboardMakup
|
||||
/// </summary>
|
||||
InlineKeyBoard = 1
|
||||
}
|
||||
@@ -1,18 +1,19 @@
|
||||
namespace TelegramBotBase.Enums
|
||||
namespace TelegramBotBase.Enums;
|
||||
|
||||
public enum EMonthPickerMode
|
||||
{
|
||||
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
|
||||
}
|
||||
}
|
||||
/// <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
|
||||
}
|
||||
@@ -1,21 +1,19 @@
|
||||
namespace TelegramBotBase.Enums
|
||||
namespace TelegramBotBase.Enums;
|
||||
|
||||
public enum ENavigationBarVisibility
|
||||
{
|
||||
public enum ENavigationBarVisibility
|
||||
{
|
||||
/// <summary>
|
||||
/// Shows it depending on the amount of items.
|
||||
/// </summary>
|
||||
auto = 0,
|
||||
/// <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 not show it at any time.
|
||||
/// </summary>
|
||||
never = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Will show it at any time.
|
||||
/// </summary>
|
||||
always = 2
|
||||
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Will show it at any time.
|
||||
/// </summary>
|
||||
always = 2
|
||||
}
|
||||
@@ -1,36 +1,34 @@
|
||||
namespace TelegramBotBase.Enums
|
||||
namespace TelegramBotBase.Enums;
|
||||
|
||||
public enum ESettings
|
||||
{
|
||||
public enum ESettings
|
||||
{
|
||||
/// <summary>
|
||||
/// How often could a form navigate to another (within one user action/call/message)
|
||||
/// </summary>
|
||||
NavigationMaximum = 1,
|
||||
/// <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>
|
||||
/// 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>
|
||||
/// 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,
|
||||
/// <summary>
|
||||
/// Does stick to the console event handler and saves all sessions on exit.
|
||||
/// </summary>
|
||||
SaveSessionsOnConsoleExit = 4,
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Indicates the maximum number of times a request that received error
|
||||
/// 429 will be sent again after a timeout until it receives code 200 or an error code not equal to 429.
|
||||
/// </summary>
|
||||
MaxNumberOfRetries = 5,
|
||||
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Indicates the maximum number of times a request that received error
|
||||
/// 429 will be sent again after a timeout until it receives code 200 or an error code not equal to 429.
|
||||
/// </summary>
|
||||
MaxNumberOfRetries = 5
|
||||
}
|
||||
@@ -1,13 +1,11 @@
|
||||
using System;
|
||||
|
||||
namespace TelegramBotBase.Exceptions
|
||||
{
|
||||
public class MaxLengthException : Exception
|
||||
{
|
||||
public MaxLengthException(int length) : base($"Your messages with a length of {length} is too long for telegram. Actually is {Constants.Telegram.MaxMessageLength} characters allowed. Please split it.")
|
||||
{
|
||||
|
||||
}
|
||||
namespace TelegramBotBase.Exceptions;
|
||||
|
||||
public class MaxLengthException : Exception
|
||||
{
|
||||
public MaxLengthException(int length) : base(
|
||||
$"Your messages with a length of {length} is too long for telegram. Actually is {Constants.Telegram.MaxMessageLength} characters allowed. Please split it.")
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,14 @@
|
||||
using System;
|
||||
|
||||
namespace TelegramBotBase.Exceptions
|
||||
namespace TelegramBotBase.Exceptions;
|
||||
|
||||
public class MaximumColsException : Exception
|
||||
{
|
||||
public class MaximumColsException : Exception
|
||||
{
|
||||
public int Value { get; set; }
|
||||
public int Value { get; set; }
|
||||
|
||||
public int Maximum { get; set; }
|
||||
public int Maximum { get; set; }
|
||||
|
||||
|
||||
public override string Message => $"You have exceeded the maximum of columns by {Value.ToString()} / {Maximum.ToString()}";
|
||||
}
|
||||
}
|
||||
public override string Message =>
|
||||
$"You have exceeded the maximum of columns by {Value.ToString()} / {Maximum.ToString()}";
|
||||
}
|
||||
@@ -1,14 +1,14 @@
|
||||
using System;
|
||||
|
||||
namespace TelegramBotBase.Exceptions
|
||||
namespace TelegramBotBase.Exceptions;
|
||||
|
||||
public class MaximumRowsReachedException : Exception
|
||||
{
|
||||
public class MaximumRowsReachedException : Exception
|
||||
{
|
||||
public int Value { get; set; }
|
||||
public int Value { get; set; }
|
||||
|
||||
public int Maximum { get; set; }
|
||||
public int Maximum { get; set; }
|
||||
|
||||
|
||||
public override string Message => $"You have exceeded the maximum of rows by {Value.ToString()} / {Maximum.ToString()}";
|
||||
}
|
||||
}
|
||||
public override string Message =>
|
||||
$"You have exceeded the maximum of rows by {Value.ToString()} / {Maximum.ToString()}";
|
||||
}
|
||||
@@ -2,24 +2,25 @@
|
||||
using TelegramBotBase.Form;
|
||||
using TelegramBotBase.Interfaces;
|
||||
|
||||
namespace TelegramBotBase.Factories
|
||||
namespace TelegramBotBase.Factories;
|
||||
|
||||
public class DefaultStartFormFactory : IStartFormFactory
|
||||
{
|
||||
public class DefaultStartFormFactory : IStartFormFactory
|
||||
private readonly Type _startFormClass;
|
||||
|
||||
public DefaultStartFormFactory(Type startFormClass)
|
||||
{
|
||||
private readonly Type _startFormClass;
|
||||
|
||||
public DefaultStartFormFactory(Type startFormClass)
|
||||
if (!typeof(FormBase).IsAssignableFrom(startFormClass))
|
||||
{
|
||||
if (!typeof(FormBase).IsAssignableFrom(startFormClass))
|
||||
throw new ArgumentException("startFormClass argument must be a FormBase type");
|
||||
|
||||
_startFormClass = startFormClass;
|
||||
throw new ArgumentException("startFormClass argument must be a FormBase type");
|
||||
}
|
||||
|
||||
|
||||
public FormBase CreateForm()
|
||||
{
|
||||
return _startFormClass.GetConstructor(new Type[] { })?.Invoke(new object[] { }) as FormBase;
|
||||
}
|
||||
_startFormClass = startFormClass;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public FormBase CreateForm()
|
||||
{
|
||||
return _startFormClass.GetConstructor(new Type[] { })?.Invoke(new object[] { }) as FormBase;
|
||||
}
|
||||
}
|
||||
@@ -1,22 +1,21 @@
|
||||
using TelegramBotBase.Form;
|
||||
using TelegramBotBase.Interfaces;
|
||||
|
||||
namespace TelegramBotBase.Factories
|
||||
namespace TelegramBotBase.Factories;
|
||||
|
||||
public class LambdaStartFormFactory : IStartFormFactory
|
||||
{
|
||||
public class LambdaStartFormFactory : IStartFormFactory
|
||||
public delegate FormBase CreateFormDelegate();
|
||||
|
||||
private readonly CreateFormDelegate _lambda;
|
||||
|
||||
public LambdaStartFormFactory(CreateFormDelegate lambda)
|
||||
{
|
||||
public delegate FormBase CreateFormDelegate();
|
||||
|
||||
private readonly CreateFormDelegate _lambda;
|
||||
|
||||
public LambdaStartFormFactory(CreateFormDelegate lambda)
|
||||
{
|
||||
_lambda = lambda;
|
||||
}
|
||||
|
||||
public FormBase CreateForm()
|
||||
{
|
||||
return _lambda();
|
||||
}
|
||||
_lambda = lambda;
|
||||
}
|
||||
}
|
||||
|
||||
public FormBase CreateForm()
|
||||
{
|
||||
return _lambda();
|
||||
}
|
||||
}
|
||||
@@ -3,33 +3,34 @@ using Microsoft.Extensions.DependencyInjection;
|
||||
using TelegramBotBase.Form;
|
||||
using TelegramBotBase.Interfaces;
|
||||
|
||||
namespace TelegramBotBase.Factories
|
||||
namespace TelegramBotBase.Factories;
|
||||
|
||||
public class ServiceProviderStartFormFactory : IStartFormFactory
|
||||
{
|
||||
public class ServiceProviderStartFormFactory : IStartFormFactory
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly Type _startFormClass;
|
||||
|
||||
public ServiceProviderStartFormFactory(Type startFormClass, IServiceProvider serviceProvider)
|
||||
{
|
||||
private readonly Type _startFormClass;
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
|
||||
public ServiceProviderStartFormFactory(Type startFormClass, IServiceProvider serviceProvider)
|
||||
if (!typeof(FormBase).IsAssignableFrom(startFormClass))
|
||||
{
|
||||
if (!typeof(FormBase).IsAssignableFrom(startFormClass))
|
||||
throw new ArgumentException("startFormClass argument must be a FormBase type");
|
||||
|
||||
_startFormClass = startFormClass;
|
||||
_serviceProvider = serviceProvider;
|
||||
throw new ArgumentException("startFormClass argument must be a FormBase type");
|
||||
}
|
||||
|
||||
public FormBase CreateForm()
|
||||
{
|
||||
return (FormBase)ActivatorUtilities.CreateInstance(_serviceProvider, _startFormClass);
|
||||
}
|
||||
_startFormClass = startFormClass;
|
||||
_serviceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
public class ServiceProviderStartFormFactory<T> : ServiceProviderStartFormFactory
|
||||
where T : FormBase
|
||||
public FormBase CreateForm()
|
||||
{
|
||||
public ServiceProviderStartFormFactory(IServiceProvider serviceProvider) : base(typeof(T), serviceProvider)
|
||||
{
|
||||
}
|
||||
return (FormBase)ActivatorUtilities.CreateInstance(_serviceProvider, _startFormClass);
|
||||
}
|
||||
}
|
||||
|
||||
public class ServiceProviderStartFormFactory<T> : ServiceProviderStartFormFactory
|
||||
where T : FormBase
|
||||
{
|
||||
public ServiceProviderStartFormFactory(IServiceProvider serviceProvider) : base(typeof(T), serviceProvider)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,21 +1,18 @@
|
||||
using TelegramBotBase.Attributes;
|
||||
|
||||
namespace TelegramBotBase.Form
|
||||
namespace TelegramBotBase.Form;
|
||||
|
||||
/// <summary>
|
||||
/// A simple prompt dialog with one ok Button
|
||||
/// </summary>
|
||||
[IgnoreState]
|
||||
public class AlertDialog : ConfirmDialog
|
||||
{
|
||||
/// <summary>
|
||||
/// A simple prompt dialog with one ok Button
|
||||
/// </summary>
|
||||
[IgnoreState]
|
||||
public class AlertDialog : ConfirmDialog
|
||||
public AlertDialog(string message, string buttonText) : base(message)
|
||||
{
|
||||
public string ButtonText { get; set; }
|
||||
|
||||
public AlertDialog(string message, string buttonText) : base(message)
|
||||
{
|
||||
Buttons.Add(new ButtonBase(buttonText, "ok"));
|
||||
this.ButtonText = buttonText;
|
||||
|
||||
}
|
||||
|
||||
Buttons.Add(new ButtonBase(buttonText, "ok"));
|
||||
ButtonText = buttonText;
|
||||
}
|
||||
}
|
||||
|
||||
public string ButtonText { get; set; }
|
||||
}
|
||||
@@ -1,113 +1,112 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using TelegramBotBase.Args;
|
||||
using TelegramBotBase.Attributes;
|
||||
using TelegramBotBase.Base;
|
||||
|
||||
namespace TelegramBotBase.Form
|
||||
namespace TelegramBotBase.Form;
|
||||
|
||||
/// <summary>
|
||||
/// A prompt with a lot of buttons
|
||||
/// </summary>
|
||||
[IgnoreState]
|
||||
public class ArrayPromptDialog : FormBase
|
||||
{
|
||||
/// <summary>
|
||||
/// A prompt with a lot of buttons
|
||||
/// </summary>
|
||||
[IgnoreState]
|
||||
public class ArrayPromptDialog : FormBase
|
||||
public ArrayPromptDialog()
|
||||
{
|
||||
/// <summary>
|
||||
/// The message the users sees.
|
||||
/// </summary>
|
||||
public string Message { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An additional optional value.
|
||||
/// </summary>
|
||||
public object Tag { get; set; }
|
||||
public ArrayPromptDialog(string message)
|
||||
{
|
||||
Message = message;
|
||||
}
|
||||
|
||||
public ButtonBase[][] Buttons { get; set; }
|
||||
public ArrayPromptDialog(string message, params ButtonBase[][] buttons)
|
||||
{
|
||||
Message = message;
|
||||
Buttons = buttons;
|
||||
}
|
||||
|
||||
[Obsolete]
|
||||
public Dictionary<string, FormBase> ButtonForms { get; set; } = new Dictionary<string, FormBase>();
|
||||
/// <summary>
|
||||
/// The message the users sees.
|
||||
/// </summary>
|
||||
public string Message { get; set; }
|
||||
|
||||
private static object EvButtonClicked { get; } = new object();
|
||||
/// <summary>
|
||||
/// An additional optional value.
|
||||
/// </summary>
|
||||
public object Tag { get; set; }
|
||||
|
||||
public ArrayPromptDialog()
|
||||
public ButtonBase[][] Buttons { get; set; }
|
||||
|
||||
[Obsolete] public Dictionary<string, FormBase> ButtonForms { get; set; } = new();
|
||||
|
||||
private static object EvButtonClicked { get; } = new();
|
||||
|
||||
public override async Task Action(MessageResult message)
|
||||
{
|
||||
var call = message.GetData<CallbackData>();
|
||||
|
||||
message.Handled = true;
|
||||
|
||||
if (!message.IsAction)
|
||||
{
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
public ArrayPromptDialog(string message)
|
||||
await message.ConfirmAction();
|
||||
|
||||
await message.DeleteMessage();
|
||||
|
||||
var buttons = Buttons.Aggregate((a, b) => a.Union(b).ToArray()).ToList();
|
||||
|
||||
if (call == null)
|
||||
{
|
||||
this.Message = message;
|
||||
return;
|
||||
}
|
||||
|
||||
public ArrayPromptDialog(string message, params ButtonBase[][] buttons)
|
||||
var button = buttons.FirstOrDefault(a => a.Value == call.Value);
|
||||
|
||||
if (button == null)
|
||||
{
|
||||
this.Message = message;
|
||||
this.Buttons = buttons;
|
||||
return;
|
||||
}
|
||||
|
||||
public override async Task Action(MessageResult message)
|
||||
OnButtonClicked(new ButtonClickedEventArgs(button) { Tag = Tag });
|
||||
|
||||
var fb = ButtonForms.ContainsKey(call.Value) ? ButtonForms[call.Value] : null;
|
||||
|
||||
if (fb != null)
|
||||
{
|
||||
var call = message.GetData<CallbackData>();
|
||||
|
||||
message.Handled = true;
|
||||
|
||||
if (!message.IsAction)
|
||||
return;
|
||||
|
||||
await message.ConfirmAction();
|
||||
|
||||
await message.DeleteMessage();
|
||||
|
||||
var buttons = Buttons.Aggregate((a, b) => a.Union(b).ToArray()).ToList();
|
||||
|
||||
if(call==null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var button = buttons.FirstOrDefault(a => a.Value == call.Value);
|
||||
|
||||
if (button == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
OnButtonClicked(new ButtonClickedEventArgs(button) { Tag = Tag });
|
||||
|
||||
var fb = ButtonForms.ContainsKey(call.Value) ? ButtonForms[call.Value] : null;
|
||||
|
||||
if (fb != null)
|
||||
{
|
||||
await NavigateTo(fb);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public override async Task Render(MessageResult message)
|
||||
{
|
||||
var btn = new ButtonForm();
|
||||
|
||||
foreach(var bl in Buttons)
|
||||
{
|
||||
btn.AddButtonRow(bl.Select(a => new ButtonBase(a.Text, CallbackData.Create("action", a.Value))).ToList());
|
||||
}
|
||||
|
||||
await Device.Send(Message, btn);
|
||||
}
|
||||
|
||||
|
||||
public event EventHandler<ButtonClickedEventArgs> ButtonClicked
|
||||
{
|
||||
add => Events.AddHandler(EvButtonClicked, value);
|
||||
remove => Events.RemoveHandler(EvButtonClicked, value);
|
||||
}
|
||||
|
||||
public void OnButtonClicked(ButtonClickedEventArgs e)
|
||||
{
|
||||
(Events[EvButtonClicked] as EventHandler<ButtonClickedEventArgs>)?.Invoke(this, e);
|
||||
await NavigateTo(fb);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public override async Task Render(MessageResult message)
|
||||
{
|
||||
var btn = new ButtonForm();
|
||||
|
||||
foreach (var bl in Buttons)
|
||||
{
|
||||
btn.AddButtonRow(
|
||||
bl.Select(a => new ButtonBase(a.Text, CallbackData.Create("action", a.Value))).ToList());
|
||||
}
|
||||
|
||||
await Device.Send(Message, btn);
|
||||
}
|
||||
|
||||
|
||||
public event EventHandler<ButtonClickedEventArgs> ButtonClicked
|
||||
{
|
||||
add => Events.AddHandler(EvButtonClicked, value);
|
||||
remove => Events.RemoveHandler(EvButtonClicked, value);
|
||||
}
|
||||
|
||||
public void OnButtonClicked(ButtonClickedEventArgs e)
|
||||
{
|
||||
(Events[EvButtonClicked] as EventHandler<ButtonClickedEventArgs>)?.Invoke(this, e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,135 +11,143 @@ using TelegramBotBase.Attributes;
|
||||
using TelegramBotBase.Base;
|
||||
using TelegramBotBase.Enums;
|
||||
|
||||
namespace TelegramBotBase.Form
|
||||
namespace TelegramBotBase.Form;
|
||||
|
||||
/// <summary>
|
||||
/// A form which cleans up old messages sent within
|
||||
/// </summary>
|
||||
public class AutoCleanForm : FormBase
|
||||
{
|
||||
/// <summary>
|
||||
/// A form which cleans up old messages sent within
|
||||
/// </summary>
|
||||
public class AutoCleanForm : FormBase
|
||||
public AutoCleanForm()
|
||||
{
|
||||
[SaveState]
|
||||
public List<int> OldMessages { get; set; }
|
||||
OldMessages = new List<int>();
|
||||
DeleteMode = EDeleteMode.OnEveryCall;
|
||||
DeleteSide = EDeleteSide.BotOnly;
|
||||
|
||||
[SaveState]
|
||||
public EDeleteMode DeleteMode { get; set; }
|
||||
Init += AutoCleanForm_Init;
|
||||
|
||||
[SaveState]
|
||||
public EDeleteSide DeleteSide { get; set; }
|
||||
Closed += AutoCleanForm_Closed;
|
||||
}
|
||||
|
||||
[SaveState] public List<int> OldMessages { get; set; }
|
||||
|
||||
[SaveState] public EDeleteMode DeleteMode { get; set; }
|
||||
|
||||
public AutoCleanForm()
|
||||
[SaveState] public EDeleteSide DeleteSide { get; set; }
|
||||
|
||||
private Task AutoCleanForm_Init(object sender, InitEventArgs e)
|
||||
{
|
||||
if (Device == null)
|
||||
{
|
||||
OldMessages = new List<int>();
|
||||
DeleteMode = EDeleteMode.OnEveryCall;
|
||||
DeleteSide = EDeleteSide.BotOnly;
|
||||
|
||||
Init += AutoCleanForm_Init;
|
||||
|
||||
Closed += AutoCleanForm_Closed;
|
||||
|
||||
}
|
||||
|
||||
private Task AutoCleanForm_Init(object sender, InitEventArgs e)
|
||||
{
|
||||
if (Device == null)
|
||||
return Task.CompletedTask;
|
||||
|
||||
Device.MessageSent += Device_MessageSent;
|
||||
|
||||
Device.MessageReceived += Device_MessageReceived;
|
||||
|
||||
Device.MessageDeleted += Device_MessageDeleted;
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private void Device_MessageDeleted(object sender, MessageDeletedEventArgs e)
|
||||
Device.MessageSent += Device_MessageSent;
|
||||
|
||||
Device.MessageReceived += Device_MessageReceived;
|
||||
|
||||
Device.MessageDeleted += Device_MessageDeleted;
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private void Device_MessageDeleted(object sender, MessageDeletedEventArgs e)
|
||||
{
|
||||
if (OldMessages.Contains(e.MessageId))
|
||||
{
|
||||
if (OldMessages.Contains(e.MessageId))
|
||||
OldMessages.Remove(e.MessageId);
|
||||
OldMessages.Remove(e.MessageId);
|
||||
}
|
||||
}
|
||||
|
||||
private void Device_MessageReceived(object sender, MessageReceivedEventArgs e)
|
||||
{
|
||||
if (DeleteSide == EDeleteSide.BotOnly)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
private void Device_MessageReceived(object sender, MessageReceivedEventArgs e)
|
||||
OldMessages.Add(e.Message.MessageId);
|
||||
}
|
||||
|
||||
private Task Device_MessageSent(object sender, MessageSentEventArgs e)
|
||||
{
|
||||
if (DeleteSide == EDeleteSide.UserOnly)
|
||||
{
|
||||
if (DeleteSide == EDeleteSide.BotOnly)
|
||||
return;
|
||||
|
||||
OldMessages.Add(e.Message.MessageId);
|
||||
}
|
||||
|
||||
private Task Device_MessageSent(object sender, MessageSentEventArgs e)
|
||||
{
|
||||
if (DeleteSide == EDeleteSide.UserOnly)
|
||||
return Task.CompletedTask;
|
||||
|
||||
OldMessages.Add(e.Message.MessageId);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public override async Task PreLoad(MessageResult message)
|
||||
{
|
||||
if (DeleteMode != EDeleteMode.OnEveryCall)
|
||||
return;
|
||||
OldMessages.Add(e.Message.MessageId);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
await MessageCleanup();
|
||||
public override async Task PreLoad(MessageResult message)
|
||||
{
|
||||
if (DeleteMode != EDeleteMode.OnEveryCall)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a message to this of removable ones
|
||||
/// </summary>
|
||||
/// <param name="Id"></param>
|
||||
public void AddMessage(Message m)
|
||||
await MessageCleanup();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a message to this of removable ones
|
||||
/// </summary>
|
||||
/// <param name="Id"></param>
|
||||
public void AddMessage(Message m)
|
||||
{
|
||||
OldMessages.Add(m.MessageId);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Adds a message to this of removable ones
|
||||
/// </summary>
|
||||
/// <param name="Id"></param>
|
||||
public void AddMessage(int messageId)
|
||||
{
|
||||
OldMessages.Add(messageId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Keeps the message by removing it from the list
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
public void LeaveMessage(int id)
|
||||
{
|
||||
OldMessages.Remove(id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Keeps the last sent message
|
||||
/// </summary>
|
||||
public void LeaveLastMessage()
|
||||
{
|
||||
if (OldMessages.Count == 0)
|
||||
{
|
||||
OldMessages.Add(m.MessageId);
|
||||
return;
|
||||
}
|
||||
|
||||
OldMessages.RemoveAt(OldMessages.Count - 1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a message to this of removable ones
|
||||
/// </summary>
|
||||
/// <param name="Id"></param>
|
||||
public void AddMessage(int messageId)
|
||||
private Task AutoCleanForm_Closed(object sender, EventArgs e)
|
||||
{
|
||||
if (DeleteMode != EDeleteMode.OnLeavingForm)
|
||||
{
|
||||
OldMessages.Add(messageId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Keeps the message by removing it from the list
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
public void LeaveMessage(int id)
|
||||
{
|
||||
OldMessages.Remove(id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Keeps the last sent message
|
||||
/// </summary>
|
||||
public void LeaveLastMessage()
|
||||
{
|
||||
if (OldMessages.Count == 0)
|
||||
return;
|
||||
|
||||
OldMessages.RemoveAt(OldMessages.Count - 1);
|
||||
}
|
||||
|
||||
private Task AutoCleanForm_Closed(object sender, EventArgs e)
|
||||
{
|
||||
if (DeleteMode != EDeleteMode.OnLeavingForm)
|
||||
return Task.CompletedTask;
|
||||
|
||||
MessageCleanup().Wait();
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cleans up all remembered messages.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task MessageCleanup()
|
||||
{
|
||||
var oldMessages = OldMessages.AsEnumerable();
|
||||
MessageCleanup().Wait();
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cleans up all remembered messages.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task MessageCleanup()
|
||||
{
|
||||
var oldMessages = OldMessages.AsEnumerable();
|
||||
|
||||
#if !NETSTANDARD2_0
|
||||
while (oldMessages.Any())
|
||||
@@ -181,51 +189,51 @@ namespace TelegramBotBase.Form
|
||||
await retryAfterTask;
|
||||
}
|
||||
#else
|
||||
while (oldMessages.Any())
|
||||
while (oldMessages.Any())
|
||||
{
|
||||
using (var cts = new CancellationTokenSource())
|
||||
{
|
||||
using (var cts = new CancellationTokenSource())
|
||||
var deletedMessages = new ConcurrentBag<int>();
|
||||
var parallelQuery = OldMessages.AsParallel()
|
||||
.WithCancellation(cts.Token);
|
||||
Task retryAfterTask = null;
|
||||
try
|
||||
{
|
||||
var deletedMessages = new ConcurrentBag<int>();
|
||||
var parallelQuery = OldMessages.AsParallel()
|
||||
.WithCancellation(cts.Token);
|
||||
Task retryAfterTask = null;
|
||||
try
|
||||
parallelQuery.ForAll(i =>
|
||||
{
|
||||
parallelQuery.ForAll(i =>
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
Device.DeleteMessage(i).GetAwaiter().GetResult();
|
||||
deletedMessages.Add(i);
|
||||
}
|
||||
catch (ApiRequestException req) when (req.ErrorCode == 400)
|
||||
{
|
||||
deletedMessages.Add(i);
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (AggregateException ex)
|
||||
{
|
||||
cts.Cancel();
|
||||
Device.DeleteMessage(i).GetAwaiter().GetResult();
|
||||
deletedMessages.Add(i);
|
||||
}
|
||||
catch (ApiRequestException req) when (req.ErrorCode == 400)
|
||||
{
|
||||
deletedMessages.Add(i);
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (AggregateException ex)
|
||||
{
|
||||
cts.Cancel();
|
||||
|
||||
var retryAfterSeconds = ex.InnerExceptions
|
||||
.Where(e => e is ApiRequestException apiEx && apiEx.ErrorCode == 429)
|
||||
.Max(e => ((ApiRequestException)e).Parameters.RetryAfter) ?? 0;
|
||||
retryAfterTask = Task.Delay(retryAfterSeconds * 1000);
|
||||
}
|
||||
var retryAfterSeconds = ex.InnerExceptions
|
||||
.Where(e => e is ApiRequestException apiEx && apiEx.ErrorCode == 429)
|
||||
.Max(e => ((ApiRequestException)e).Parameters.RetryAfter) ?? 0;
|
||||
retryAfterTask = Task.Delay(retryAfterSeconds * 1000);
|
||||
}
|
||||
|
||||
//deletedMessages.AsParallel().ForAll(i => Device.OnMessageDeleted(new MessageDeletedEventArgs(i)));
|
||||
|
||||
oldMessages = oldMessages.Where(x => !deletedMessages.Contains(x));
|
||||
if (retryAfterTask != null)
|
||||
await retryAfterTask;
|
||||
//deletedMessages.AsParallel().ForAll(i => Device.OnMessageDeleted(new MessageDeletedEventArgs(i)));
|
||||
oldMessages = oldMessages.Where(x => !deletedMessages.Contains(x));
|
||||
if (retryAfterTask != null)
|
||||
{
|
||||
await retryAfterTask;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
OldMessages.Clear();
|
||||
}
|
||||
OldMessages.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,66 +1,62 @@
|
||||
using System.Diagnostics;
|
||||
using Telegram.Bot.Types.ReplyMarkups;
|
||||
|
||||
namespace TelegramBotBase.Form
|
||||
namespace TelegramBotBase.Form;
|
||||
|
||||
[DebuggerDisplay("{Text}, {Value}")]
|
||||
/// <summary>
|
||||
/// Base class for button handling
|
||||
/// </summary>
|
||||
public class ButtonBase
|
||||
{
|
||||
[DebuggerDisplay("{Text}, {Value}")]
|
||||
/// <summary>
|
||||
/// Base class for button handling
|
||||
/// </summary>
|
||||
public class ButtonBase
|
||||
public ButtonBase()
|
||||
{
|
||||
public virtual string Text { get; set; }
|
||||
|
||||
public string Value { get; set; }
|
||||
|
||||
public string Url { get; set; }
|
||||
|
||||
public ButtonBase()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public ButtonBase(string text, string value, string url = null)
|
||||
{
|
||||
this.Text = text;
|
||||
this.Value = value;
|
||||
this.Url = url;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns an inline Button
|
||||
/// </summary>
|
||||
/// <param name="form"></param>
|
||||
/// <returns></returns>
|
||||
public virtual InlineKeyboardButton ToInlineButton(ButtonForm form)
|
||||
{
|
||||
var id = (form.DependencyControl != null ? form.DependencyControl.ControlId + "_" : "");
|
||||
if (Url == null)
|
||||
{
|
||||
return InlineKeyboardButton.WithCallbackData(Text, id + Value);
|
||||
}
|
||||
|
||||
var ikb = new InlineKeyboardButton(Text)
|
||||
{
|
||||
//ikb.Text = this.Text;
|
||||
Url = Url
|
||||
};
|
||||
|
||||
return ikb;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns a KeyBoardButton
|
||||
/// </summary>
|
||||
/// <param name="form"></param>
|
||||
/// <returns></returns>
|
||||
public virtual KeyboardButton ToKeyboardButton(ButtonForm form)
|
||||
{
|
||||
return new KeyboardButton(Text);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public ButtonBase(string text, string value, string url = null)
|
||||
{
|
||||
Text = text;
|
||||
Value = value;
|
||||
Url = url;
|
||||
}
|
||||
|
||||
public virtual string Text { get; set; }
|
||||
|
||||
public string Value { get; set; }
|
||||
|
||||
public string Url { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns an inline Button
|
||||
/// </summary>
|
||||
/// <param name="form"></param>
|
||||
/// <returns></returns>
|
||||
public virtual InlineKeyboardButton ToInlineButton(ButtonForm form)
|
||||
{
|
||||
var id = form.DependencyControl != null ? form.DependencyControl.ControlId + "_" : "";
|
||||
if (Url == null)
|
||||
{
|
||||
return InlineKeyboardButton.WithCallbackData(Text, id + Value);
|
||||
}
|
||||
|
||||
var ikb = new InlineKeyboardButton(Text)
|
||||
{
|
||||
//ikb.Text = this.Text;
|
||||
Url = Url
|
||||
};
|
||||
|
||||
return ikb;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns a KeyBoardButton
|
||||
/// </summary>
|
||||
/// <param name="form"></param>
|
||||
/// <returns></returns>
|
||||
public virtual KeyboardButton ToKeyboardButton(ButtonForm form)
|
||||
{
|
||||
return new KeyboardButton(Text);
|
||||
}
|
||||
}
|
||||
+321
-305
@@ -5,321 +5,337 @@ using Telegram.Bot.Types.ReplyMarkups;
|
||||
using TelegramBotBase.Base;
|
||||
using TelegramBotBase.Controls.Hybrid;
|
||||
|
||||
namespace TelegramBotBase.Form
|
||||
namespace TelegramBotBase.Form;
|
||||
|
||||
/// <summary>
|
||||
/// Base class for an buttons array
|
||||
/// </summary>
|
||||
public class ButtonForm
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for an buttons array
|
||||
/// </summary>
|
||||
public class ButtonForm
|
||||
private readonly List<ButtonRow> _buttons = new();
|
||||
|
||||
public ButtonForm()
|
||||
{
|
||||
private List<ButtonRow> _buttons = new List<ButtonRow>();
|
||||
}
|
||||
|
||||
public ButtonForm(ControlBase control)
|
||||
{
|
||||
DependencyControl = control;
|
||||
}
|
||||
|
||||
|
||||
public IReplyMarkup Markup { get; set; }
|
||||
public IReplyMarkup Markup { get; set; }
|
||||
|
||||
public ControlBase DependencyControl { get; set; }
|
||||
public ControlBase DependencyControl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Contains the number of rows.
|
||||
/// </summary>
|
||||
public int Rows => _buttons.Count;
|
||||
/// <summary>
|
||||
/// Contains the number of rows.
|
||||
/// </summary>
|
||||
public int Rows => _buttons.Count;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the highest number of columns in an row.
|
||||
/// </summary>
|
||||
public int Cols
|
||||
/// <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 ButtonRow this[int row] => _buttons[row];
|
||||
|
||||
public int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
get
|
||||
if (_buttons.Count == 0)
|
||||
{
|
||||
return _buttons.Select(a => a.Count).OrderByDescending(a => a).FirstOrDefault();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public ButtonRow this[int row] => _buttons[row];
|
||||
|
||||
public ButtonForm()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public ButtonForm(ControlBase control)
|
||||
{
|
||||
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(ButtonRow row)
|
||||
//{
|
||||
// Buttons.Add(row.ToList());
|
||||
//}
|
||||
|
||||
public void AddButtonRow(ButtonRow row)
|
||||
{
|
||||
_buttons.Add(row);
|
||||
}
|
||||
|
||||
public void AddButtonRow(params ButtonBase[] row)
|
||||
{
|
||||
AddButtonRow(row.ToList());
|
||||
}
|
||||
|
||||
public void AddButtonRows(IEnumerable<ButtonRow> rows)
|
||||
{
|
||||
_buttons.AddRange(rows);
|
||||
}
|
||||
|
||||
public void InsertButtonRow(int index, IEnumerable<ButtonBase> row)
|
||||
{
|
||||
_buttons.Insert(index, row.ToList());
|
||||
}
|
||||
|
||||
public void InsertButtonRow(int index, ButtonRow row)
|
||||
{
|
||||
_buttons.Insert(index, row);
|
||||
}
|
||||
|
||||
//public void InsertButtonRow(int index, params ButtonBase[] row)
|
||||
//{
|
||||
// InsertButtonRow(index, row.ToList());
|
||||
//}
|
||||
|
||||
public static T[][] SplitTo<T>(IEnumerable<T> items, int itemsPerRow = 2)
|
||||
{
|
||||
var splitted = default(T[][]);
|
||||
|
||||
try
|
||||
{
|
||||
var t = items.Select((a, index) => new { a, index })
|
||||
.GroupBy(a => a.index / itemsPerRow)
|
||||
.Select(a => a.Select(b => b.a).ToArray()).ToArray();
|
||||
|
||||
splitted = t;
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return splitted;
|
||||
}
|
||||
|
||||
public int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_buttons.Count == 0)
|
||||
return 0;
|
||||
|
||||
return _buttons.Select(a => a.ToArray()).ToList().Aggregate((a, b) => a.Union(b).ToArray()).Length;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add buttons splitted in the amount of columns (i.e. 2 per row...)
|
||||
/// </summary>
|
||||
/// <param name="buttons"></param>
|
||||
/// <param name="buttonsPerRow"></param>
|
||||
public void AddSplitted(IEnumerable<ButtonBase> buttons, int buttonsPerRow = 2)
|
||||
{
|
||||
var sp = SplitTo(buttons, buttonsPerRow);
|
||||
|
||||
foreach (var bl in sp)
|
||||
{
|
||||
AddButtonRow(bl);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a range of rows from the buttons.
|
||||
/// </summary>
|
||||
/// <param name="start"></param>
|
||||
/// <param name="count"></param>
|
||||
/// <returns></returns>
|
||||
public List<ButtonRow> GetRange(int start, int count)
|
||||
{
|
||||
return _buttons.Skip(start).Take(count).ToList();
|
||||
}
|
||||
|
||||
|
||||
public List<ButtonBase> ToList()
|
||||
{
|
||||
return _buttons.DefaultIfEmpty(new List<ButtonBase>()).Select(a => a.ToList()).Aggregate((a, b) => a.Union(b).ToList());
|
||||
}
|
||||
|
||||
public InlineKeyboardButton[][] ToInlineButtonArray()
|
||||
{
|
||||
var ikb = _buttons.Select(a => a.ToArray().Select(b => b.ToInlineButton(this)).ToArray()).ToArray();
|
||||
|
||||
return ikb;
|
||||
}
|
||||
|
||||
public KeyboardButton[][] ToReplyButtonArray()
|
||||
{
|
||||
var ikb = _buttons.Select(a => a.ToArray().Select(b => b.ToKeyboardButton(this)).ToArray()).ToArray();
|
||||
|
||||
return ikb;
|
||||
}
|
||||
|
||||
public List<ButtonRow> ToArray()
|
||||
{
|
||||
return _buttons;
|
||||
}
|
||||
|
||||
public int FindRowByButton(ButtonBase button)
|
||||
{
|
||||
var row = _buttons.FirstOrDefault(a => a.ToArray().Count(b => b == button) > 0);
|
||||
if (row == null)
|
||||
return -1;
|
||||
|
||||
return _buttons.IndexOf(row);
|
||||
}
|
||||
|
||||
public Tuple<ButtonRow, int> FindRow(string text, bool useText = true)
|
||||
{
|
||||
var r = _buttons.FirstOrDefault(a => a.Matches(text, useText));
|
||||
if (r == null)
|
||||
return null;
|
||||
|
||||
var i = _buttons.IndexOf(r);
|
||||
return new Tuple<ButtonRow, int>(r, i);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns the first Button with the given value.
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public ButtonBase GetButtonByValue(string value)
|
||||
{
|
||||
return ToList().Where(a => a.Value == value).FirstOrDefault();
|
||||
}
|
||||
|
||||
public static implicit operator InlineKeyboardMarkup(ButtonForm form)
|
||||
{
|
||||
if (form == null)
|
||||
return null;
|
||||
|
||||
var ikm = new InlineKeyboardMarkup(form.ToInlineButtonArray());
|
||||
|
||||
return ikm;
|
||||
}
|
||||
|
||||
public static implicit operator ReplyKeyboardMarkup(ButtonForm form)
|
||||
{
|
||||
if (form == null)
|
||||
return null;
|
||||
|
||||
var ikm = new ReplyKeyboardMarkup(form.ToReplyButtonArray());
|
||||
|
||||
return ikm;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a copy of this form.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public ButtonForm Duplicate()
|
||||
{
|
||||
var bf = new ButtonForm
|
||||
{
|
||||
Markup = Markup,
|
||||
DependencyControl = DependencyControl
|
||||
};
|
||||
|
||||
foreach (var b in _buttons)
|
||||
{
|
||||
var lst = new ButtonRow();
|
||||
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 = Markup,
|
||||
DependencyControl = DependencyControl
|
||||
};
|
||||
|
||||
foreach (var b in _buttons)
|
||||
{
|
||||
var lst = new ButtonRow();
|
||||
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 = b;
|
||||
break;
|
||||
}
|
||||
|
||||
lst.Add(b2);
|
||||
}
|
||||
|
||||
if (lst.Count > 0)
|
||||
bf._buttons.Add(lst);
|
||||
}
|
||||
|
||||
return bf;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a copy of this form and filters by the parameter.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public ButtonForm TagDuplicate(List<string> tags, bool byRow = false)
|
||||
{
|
||||
var bf = new ButtonForm
|
||||
{
|
||||
Markup = Markup,
|
||||
DependencyControl = DependencyControl
|
||||
};
|
||||
|
||||
foreach (var b in _buttons)
|
||||
{
|
||||
var lst = new ButtonRow();
|
||||
foreach (var b2 in b)
|
||||
{
|
||||
if (!(b2 is TagButtonBase tb))
|
||||
continue;
|
||||
|
||||
if (!tags.Contains(tb.Tag))
|
||||
continue;
|
||||
|
||||
//Copy full row, when at least one match has found.
|
||||
if (byRow)
|
||||
{
|
||||
lst = b;
|
||||
break;
|
||||
}
|
||||
|
||||
lst.Add(b2);
|
||||
}
|
||||
|
||||
if (lst.Count > 0)
|
||||
bf._buttons.Add(lst);
|
||||
}
|
||||
|
||||
return bf;
|
||||
return _buttons.Select(a => a.ToArray()).ToList().Aggregate((a, b) => a.Union(b).ToArray()).Length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void AddButtonRow(string text, string value, string url = null)
|
||||
{
|
||||
_buttons.Add(new List<ButtonBase> { new(text, value, url) });
|
||||
}
|
||||
|
||||
//public void AddButtonRow(ButtonRow row)
|
||||
//{
|
||||
// Buttons.Add(row.ToList());
|
||||
//}
|
||||
|
||||
public void AddButtonRow(ButtonRow row)
|
||||
{
|
||||
_buttons.Add(row);
|
||||
}
|
||||
|
||||
public void AddButtonRow(params ButtonBase[] row)
|
||||
{
|
||||
AddButtonRow(row.ToList());
|
||||
}
|
||||
|
||||
public void AddButtonRows(IEnumerable<ButtonRow> rows)
|
||||
{
|
||||
_buttons.AddRange(rows);
|
||||
}
|
||||
|
||||
public void InsertButtonRow(int index, IEnumerable<ButtonBase> row)
|
||||
{
|
||||
_buttons.Insert(index, row.ToList());
|
||||
}
|
||||
|
||||
public void InsertButtonRow(int index, ButtonRow row)
|
||||
{
|
||||
_buttons.Insert(index, row);
|
||||
}
|
||||
|
||||
//public void InsertButtonRow(int index, params ButtonBase[] row)
|
||||
//{
|
||||
// InsertButtonRow(index, row.ToList());
|
||||
//}
|
||||
|
||||
public static T[][] SplitTo<T>(IEnumerable<T> items, int itemsPerRow = 2)
|
||||
{
|
||||
var splitted = default(T[][]);
|
||||
|
||||
try
|
||||
{
|
||||
var t = items.Select((a, index) => new { a, index })
|
||||
.GroupBy(a => a.index / itemsPerRow)
|
||||
.Select(a => a.Select(b => b.a).ToArray()).ToArray();
|
||||
|
||||
splitted = t;
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
return splitted;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add buttons splitted in the amount of columns (i.e. 2 per row...)
|
||||
/// </summary>
|
||||
/// <param name="buttons"></param>
|
||||
/// <param name="buttonsPerRow"></param>
|
||||
public void AddSplitted(IEnumerable<ButtonBase> buttons, int buttonsPerRow = 2)
|
||||
{
|
||||
var sp = SplitTo(buttons, buttonsPerRow);
|
||||
|
||||
foreach (var bl in sp)
|
||||
{
|
||||
AddButtonRow(bl);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a range of rows from the buttons.
|
||||
/// </summary>
|
||||
/// <param name="start"></param>
|
||||
/// <param name="count"></param>
|
||||
/// <returns></returns>
|
||||
public List<ButtonRow> GetRange(int start, int count)
|
||||
{
|
||||
return _buttons.Skip(start).Take(count).ToList();
|
||||
}
|
||||
|
||||
|
||||
public List<ButtonBase> ToList()
|
||||
{
|
||||
return _buttons.DefaultIfEmpty(new List<ButtonBase>()).Select(a => a.ToList())
|
||||
.Aggregate((a, b) => a.Union(b).ToList());
|
||||
}
|
||||
|
||||
public InlineKeyboardButton[][] ToInlineButtonArray()
|
||||
{
|
||||
var ikb = _buttons.Select(a => a.ToArray().Select(b => b.ToInlineButton(this)).ToArray()).ToArray();
|
||||
|
||||
return ikb;
|
||||
}
|
||||
|
||||
public KeyboardButton[][] ToReplyButtonArray()
|
||||
{
|
||||
var ikb = _buttons.Select(a => a.ToArray().Select(b => b.ToKeyboardButton(this)).ToArray()).ToArray();
|
||||
|
||||
return ikb;
|
||||
}
|
||||
|
||||
public List<ButtonRow> ToArray()
|
||||
{
|
||||
return _buttons;
|
||||
}
|
||||
|
||||
public int FindRowByButton(ButtonBase button)
|
||||
{
|
||||
var row = _buttons.FirstOrDefault(a => a.ToArray().Count(b => b == button) > 0);
|
||||
if (row == null)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return _buttons.IndexOf(row);
|
||||
}
|
||||
|
||||
public Tuple<ButtonRow, int> FindRow(string text, bool useText = true)
|
||||
{
|
||||
var r = _buttons.FirstOrDefault(a => a.Matches(text, useText));
|
||||
if (r == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var i = _buttons.IndexOf(r);
|
||||
return new Tuple<ButtonRow, int>(r, i);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns the first Button with the given value.
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public ButtonBase GetButtonByValue(string value)
|
||||
{
|
||||
return ToList().Where(a => a.Value == value).FirstOrDefault();
|
||||
}
|
||||
|
||||
public static implicit operator InlineKeyboardMarkup(ButtonForm form)
|
||||
{
|
||||
if (form == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var ikm = new InlineKeyboardMarkup(form.ToInlineButtonArray());
|
||||
|
||||
return ikm;
|
||||
}
|
||||
|
||||
public static implicit operator ReplyKeyboardMarkup(ButtonForm form)
|
||||
{
|
||||
if (form == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var ikm = new ReplyKeyboardMarkup(form.ToReplyButtonArray());
|
||||
|
||||
return ikm;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a copy of this form.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public ButtonForm Duplicate()
|
||||
{
|
||||
var bf = new ButtonForm
|
||||
{
|
||||
Markup = Markup,
|
||||
DependencyControl = DependencyControl
|
||||
};
|
||||
|
||||
foreach (var b in _buttons)
|
||||
{
|
||||
var lst = new ButtonRow();
|
||||
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 = Markup,
|
||||
DependencyControl = DependencyControl
|
||||
};
|
||||
|
||||
foreach (var b in _buttons)
|
||||
{
|
||||
var lst = new ButtonRow();
|
||||
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 = b;
|
||||
break;
|
||||
}
|
||||
|
||||
lst.Add(b2);
|
||||
}
|
||||
|
||||
if (lst.Count > 0)
|
||||
{
|
||||
bf._buttons.Add(lst);
|
||||
}
|
||||
}
|
||||
|
||||
return bf;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a copy of this form and filters by the parameter.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public ButtonForm TagDuplicate(List<string> tags, bool byRow = false)
|
||||
{
|
||||
var bf = new ButtonForm
|
||||
{
|
||||
Markup = Markup,
|
||||
DependencyControl = DependencyControl
|
||||
};
|
||||
|
||||
foreach (var b in _buttons)
|
||||
{
|
||||
var lst = new ButtonRow();
|
||||
foreach (var b2 in b)
|
||||
{
|
||||
if (!(b2 is TagButtonBase tb))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!tags.Contains(tb.Tag))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
//Copy full row, when at least one match has found.
|
||||
if (byRow)
|
||||
{
|
||||
lst = b;
|
||||
break;
|
||||
}
|
||||
|
||||
lst.Add(b2);
|
||||
}
|
||||
|
||||
if (lst.Count > 0)
|
||||
{
|
||||
bf._buttons.Add(lst);
|
||||
}
|
||||
}
|
||||
|
||||
return bf;
|
||||
}
|
||||
}
|
||||
@@ -1,76 +1,67 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace TelegramBotBase.Form
|
||||
namespace TelegramBotBase.Form;
|
||||
|
||||
/// <summary>
|
||||
/// Base class for serializing buttons and data
|
||||
/// </summary>
|
||||
public class CallbackData
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for serializing buttons and data
|
||||
/// </summary>
|
||||
public class CallbackData
|
||||
public CallbackData()
|
||||
{
|
||||
[JsonProperty("m")]
|
||||
public string Method { get; set; }
|
||||
|
||||
[JsonProperty("v")]
|
||||
public string Value { get; set; }
|
||||
|
||||
|
||||
public CallbackData()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public CallbackData(string method, string value)
|
||||
{
|
||||
Method = method;
|
||||
Value = value;
|
||||
}
|
||||
|
||||
public static string Create(string method, string value)
|
||||
{
|
||||
return new CallbackData(method, value).Serialize();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes data to json string
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public string Serialize()
|
||||
{
|
||||
var s = "";
|
||||
try
|
||||
{
|
||||
|
||||
s = JsonConvert.SerializeObject(this);
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes data from json string
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
/// <returns></returns>
|
||||
public static CallbackData Deserialize(string data)
|
||||
{
|
||||
CallbackData cd = null;
|
||||
try
|
||||
{
|
||||
cd = JsonConvert.DeserializeObject<CallbackData>(data);
|
||||
|
||||
return cd;
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public CallbackData(string method, string value)
|
||||
{
|
||||
Method = method;
|
||||
Value = value;
|
||||
}
|
||||
|
||||
[JsonProperty("m")] public string Method { get; set; }
|
||||
|
||||
[JsonProperty("v")] public string Value { get; set; }
|
||||
|
||||
public static string Create(string method, string value)
|
||||
{
|
||||
return new CallbackData(method, value).Serialize();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes data to json string
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public string Serialize()
|
||||
{
|
||||
var s = "";
|
||||
try
|
||||
{
|
||||
s = JsonConvert.SerializeObject(this);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes data from json string
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
/// <returns></returns>
|
||||
public static CallbackData Deserialize(string data)
|
||||
{
|
||||
CallbackData cd = null;
|
||||
try
|
||||
{
|
||||
cd = JsonConvert.DeserializeObject<CallbackData>(data);
|
||||
|
||||
return cd;
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,115 +1,119 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using TelegramBotBase.Args;
|
||||
using TelegramBotBase.Attributes;
|
||||
using TelegramBotBase.Base;
|
||||
|
||||
namespace TelegramBotBase.Form
|
||||
namespace TelegramBotBase.Form;
|
||||
|
||||
[IgnoreState]
|
||||
public class ConfirmDialog : ModalDialog
|
||||
{
|
||||
[IgnoreState]
|
||||
public class ConfirmDialog : ModalDialog
|
||||
public ConfirmDialog()
|
||||
{
|
||||
/// <summary>
|
||||
/// The message the users sees.
|
||||
/// </summary>
|
||||
public string Message { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// An additional optional value.
|
||||
/// </summary>
|
||||
public object Tag { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Automatically close form on button click
|
||||
/// </summary>
|
||||
public bool AutoCloseOnClick { get; set; } = true;
|
||||
|
||||
public List<ButtonBase> Buttons { get; set; }
|
||||
|
||||
private static object EvButtonClicked { get; } = new object();
|
||||
|
||||
public ConfirmDialog()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public ConfirmDialog(string message)
|
||||
{
|
||||
this.Message = message;
|
||||
Buttons = new List<ButtonBase>();
|
||||
}
|
||||
|
||||
public ConfirmDialog(string message, params ButtonBase[] buttons)
|
||||
{
|
||||
this.Message = message;
|
||||
this.Buttons = buttons.ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds one Button
|
||||
/// </summary>
|
||||
/// <param name="button"></param>
|
||||
public void AddButton(ButtonBase button)
|
||||
{
|
||||
Buttons.Add(button);
|
||||
}
|
||||
|
||||
public override async Task Action(MessageResult message)
|
||||
{
|
||||
if (message.Handled)
|
||||
return;
|
||||
|
||||
if (!message.IsFirstHandler)
|
||||
return;
|
||||
|
||||
var call = message.GetData<CallbackData>();
|
||||
if (call == null)
|
||||
return;
|
||||
|
||||
message.Handled = true;
|
||||
|
||||
await message.ConfirmAction();
|
||||
|
||||
await message.DeleteMessage();
|
||||
|
||||
var button = Buttons.FirstOrDefault(a => a.Value == call.Value);
|
||||
|
||||
if (button == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
OnButtonClicked(new ButtonClickedEventArgs(button) { Tag = Tag });
|
||||
|
||||
if (AutoCloseOnClick)
|
||||
await CloseForm();
|
||||
}
|
||||
|
||||
|
||||
public override async Task Render(MessageResult message)
|
||||
{
|
||||
var btn = new ButtonForm();
|
||||
|
||||
var buttons = Buttons.Select(a => new ButtonBase(a.Text, CallbackData.Create("action", a.Value))).ToList();
|
||||
btn.AddButtonRow(buttons);
|
||||
|
||||
await Device.Send(Message, btn);
|
||||
}
|
||||
|
||||
|
||||
public event EventHandler<ButtonClickedEventArgs> ButtonClicked
|
||||
{
|
||||
add => Events.AddHandler(EvButtonClicked, value);
|
||||
remove => Events.RemoveHandler(EvButtonClicked, value);
|
||||
}
|
||||
|
||||
public void OnButtonClicked(ButtonClickedEventArgs e)
|
||||
{
|
||||
(Events[EvButtonClicked] as EventHandler<ButtonClickedEventArgs>)?.Invoke(this, e);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public ConfirmDialog(string message)
|
||||
{
|
||||
Message = message;
|
||||
Buttons = new List<ButtonBase>();
|
||||
}
|
||||
|
||||
public ConfirmDialog(string message, params ButtonBase[] buttons)
|
||||
{
|
||||
Message = message;
|
||||
Buttons = buttons.ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The message the users sees.
|
||||
/// </summary>
|
||||
public string Message { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// An additional optional value.
|
||||
/// </summary>
|
||||
public object Tag { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Automatically close form on button click
|
||||
/// </summary>
|
||||
public bool AutoCloseOnClick { get; set; } = true;
|
||||
|
||||
public List<ButtonBase> Buttons { get; set; }
|
||||
|
||||
private static object EvButtonClicked { get; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Adds one Button
|
||||
/// </summary>
|
||||
/// <param name="button"></param>
|
||||
public void AddButton(ButtonBase button)
|
||||
{
|
||||
Buttons.Add(button);
|
||||
}
|
||||
|
||||
public override async Task Action(MessageResult message)
|
||||
{
|
||||
if (message.Handled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!message.IsFirstHandler)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var call = message.GetData<CallbackData>();
|
||||
if (call == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
message.Handled = true;
|
||||
|
||||
await message.ConfirmAction();
|
||||
|
||||
await message.DeleteMessage();
|
||||
|
||||
var button = Buttons.FirstOrDefault(a => a.Value == call.Value);
|
||||
|
||||
if (button == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
OnButtonClicked(new ButtonClickedEventArgs(button) { Tag = Tag });
|
||||
|
||||
if (AutoCloseOnClick)
|
||||
{
|
||||
await CloseForm();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public override async Task Render(MessageResult message)
|
||||
{
|
||||
var btn = new ButtonForm();
|
||||
|
||||
var buttons = Buttons.Select(a => new ButtonBase(a.Text, CallbackData.Create("action", a.Value))).ToList();
|
||||
btn.AddButtonRow(buttons);
|
||||
|
||||
await Device.Send(Message, btn);
|
||||
}
|
||||
|
||||
|
||||
public event EventHandler<ButtonClickedEventArgs> ButtonClicked
|
||||
{
|
||||
add => Events.AddHandler(EvButtonClicked, value);
|
||||
remove => Events.RemoveHandler(EvButtonClicked, value);
|
||||
}
|
||||
|
||||
public void OnButtonClicked(ButtonClickedEventArgs e)
|
||||
{
|
||||
(Events[EvButtonClicked] as EventHandler<ButtonClickedEventArgs>)?.Invoke(this, e);
|
||||
}
|
||||
}
|
||||
@@ -1,33 +1,30 @@
|
||||
using System;
|
||||
|
||||
namespace TelegramBotBase.Form
|
||||
namespace TelegramBotBase.Form;
|
||||
|
||||
public class DynamicButton : ButtonBase
|
||||
{
|
||||
public class DynamicButton : ButtonBase
|
||||
private readonly Func<string> _getText;
|
||||
|
||||
private string _mText = "";
|
||||
|
||||
public DynamicButton(string text, string value, string url = null)
|
||||
{
|
||||
public override string Text
|
||||
{
|
||||
get => _getText?.Invoke() ?? _mText;
|
||||
set => _mText = value;
|
||||
}
|
||||
|
||||
private string _mText = "";
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
Text = text;
|
||||
Value = value;
|
||||
Url = url;
|
||||
}
|
||||
}
|
||||
|
||||
public DynamicButton(Func<string> getText, string value, string url = null)
|
||||
{
|
||||
_getText = getText;
|
||||
Value = value;
|
||||
Url = url;
|
||||
}
|
||||
|
||||
public override string Text
|
||||
{
|
||||
get => _getText?.Invoke() ?? _mText;
|
||||
set => _mText = value;
|
||||
}
|
||||
}
|
||||
@@ -3,73 +3,73 @@ using Telegram.Bot.Types.Enums;
|
||||
using TelegramBotBase.Args;
|
||||
using TelegramBotBase.Base;
|
||||
|
||||
namespace TelegramBotBase.Form
|
||||
namespace TelegramBotBase.Form;
|
||||
|
||||
public class GroupForm : FormBase
|
||||
{
|
||||
public class GroupForm : FormBase
|
||||
public override async Task Load(MessageResult message)
|
||||
{
|
||||
public override async Task Load(MessageResult message)
|
||||
switch (message.MessageType)
|
||||
{
|
||||
switch (message.MessageType)
|
||||
{
|
||||
case MessageType.ChatMembersAdded:
|
||||
case MessageType.ChatMembersAdded:
|
||||
|
||||
await OnMemberChanges(new MemberChangeEventArgs(MessageType.ChatMembersAdded, message, message.Message.NewChatMembers));
|
||||
await OnMemberChanges(new MemberChangeEventArgs(MessageType.ChatMembersAdded, message,
|
||||
message.Message.NewChatMembers));
|
||||
|
||||
break;
|
||||
case MessageType.ChatMemberLeft:
|
||||
break;
|
||||
case MessageType.ChatMemberLeft:
|
||||
|
||||
await OnMemberChanges(new MemberChangeEventArgs(MessageType.ChatMemberLeft, message, message.Message.LeftChatMember));
|
||||
await OnMemberChanges(new MemberChangeEventArgs(MessageType.ChatMemberLeft, message,
|
||||
message.Message.LeftChatMember));
|
||||
|
||||
break;
|
||||
break;
|
||||
|
||||
case MessageType.ChatPhotoChanged:
|
||||
case MessageType.ChatPhotoDeleted:
|
||||
case MessageType.ChatTitleChanged:
|
||||
case MessageType.MigratedFromGroup:
|
||||
case MessageType.MigratedToSupergroup:
|
||||
case MessageType.MessagePinned:
|
||||
case MessageType.GroupCreated:
|
||||
case MessageType.SupergroupCreated:
|
||||
case MessageType.ChannelCreated:
|
||||
case MessageType.ChatPhotoChanged:
|
||||
case MessageType.ChatPhotoDeleted:
|
||||
case MessageType.ChatTitleChanged:
|
||||
case MessageType.MigratedFromGroup:
|
||||
case MessageType.MigratedToSupergroup:
|
||||
case MessageType.MessagePinned:
|
||||
case MessageType.GroupCreated:
|
||||
case MessageType.SupergroupCreated:
|
||||
case MessageType.ChannelCreated:
|
||||
|
||||
await OnGroupChanged(new GroupChangedEventArgs(message.MessageType, message));
|
||||
await OnGroupChanged(new GroupChangedEventArgs(message.MessageType, message));
|
||||
|
||||
break;
|
||||
break;
|
||||
|
||||
default:
|
||||
default:
|
||||
|
||||
await OnMessage(message);
|
||||
await OnMessage(message);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public override async Task Edited(MessageResult message)
|
||||
{
|
||||
await OnMessageEdit(message);
|
||||
}
|
||||
|
||||
public virtual Task OnMemberChanges(MemberChangeEventArgs e)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
|
||||
public virtual Task OnGroupChanged(GroupChangedEventArgs e)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
|
||||
public virtual Task OnMessage(MessageResult e)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public virtual Task OnMessageEdit(MessageResult e)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task Edited(MessageResult message)
|
||||
{
|
||||
await OnMessageEdit(message);
|
||||
}
|
||||
|
||||
public virtual Task OnMemberChanges(MemberChangeEventArgs e)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
|
||||
public virtual Task OnGroupChanged(GroupChangedEventArgs e)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
|
||||
public virtual Task OnMessage(MessageResult e)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public virtual Task OnMessageEdit(MessageResult e)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
@@ -1,26 +1,25 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace TelegramBotBase.Form
|
||||
namespace TelegramBotBase.Form;
|
||||
|
||||
public class ModalDialog : FormBase
|
||||
{
|
||||
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()
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains the parent from where the modal dialog has been opened.
|
||||
/// </summary>
|
||||
public FormBase ParentForm { get; set; }
|
||||
await CloseControls();
|
||||
|
||||
/// <summary>
|
||||
/// This is a modal only function and does everything to close this form.
|
||||
/// </summary>
|
||||
public async Task CloseForm()
|
||||
{
|
||||
await CloseControls();
|
||||
|
||||
await OnClosed(EventArgs.Empty);
|
||||
await OnClosed(EventArgs.Empty);
|
||||
|
||||
|
||||
await ParentForm?.ReturnFromModal(this);
|
||||
}
|
||||
await ParentForm?.ReturnFromModal(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,348 +10,356 @@ using TelegramBotBase.Base;
|
||||
using TelegramBotBase.Interfaces;
|
||||
using TelegramBotBase.Tools;
|
||||
|
||||
namespace TelegramBotBase.Form.Navigation
|
||||
namespace TelegramBotBase.Form.Navigation;
|
||||
|
||||
[DebuggerDisplay("{Index+1} Forms")]
|
||||
public class NavigationController : FormBase, IStateForm
|
||||
{
|
||||
[DebuggerDisplay("{Index+1} Forms")]
|
||||
public class NavigationController : FormBase, IStateForm
|
||||
public NavigationController()
|
||||
{
|
||||
History = new List<FormBase>();
|
||||
Index = -1;
|
||||
ForceCleanupOnLastPop = true;
|
||||
|
||||
[SaveState]
|
||||
private List<FormBase> History { get; set; }
|
||||
Init += NavigationController_Init;
|
||||
Opened += NavigationController_Opened;
|
||||
Closed += NavigationController_Closed;
|
||||
}
|
||||
|
||||
[SaveState]
|
||||
public int Index { get; set; }
|
||||
public NavigationController(FormBase startForm, params FormBase[] forms) : this()
|
||||
{
|
||||
Client = startForm.Client;
|
||||
Device = startForm.Device;
|
||||
startForm.NavigationController = this;
|
||||
|
||||
/// <summary>
|
||||
/// Will replace the controller when poping a form to the root form.
|
||||
/// </summary>
|
||||
[SaveState]
|
||||
public bool ForceCleanupOnLastPop { get; set; }
|
||||
History.Add(startForm);
|
||||
Index = 0;
|
||||
|
||||
public NavigationController()
|
||||
if (forms.Length > 0)
|
||||
{
|
||||
History = new List<FormBase>();
|
||||
Index = -1;
|
||||
ForceCleanupOnLastPop = true;
|
||||
|
||||
Init += NavigationController_Init;
|
||||
Opened += NavigationController_Opened;
|
||||
Closed += NavigationController_Closed;
|
||||
History.AddRange(forms);
|
||||
Index = History.Count - 1;
|
||||
}
|
||||
}
|
||||
|
||||
public NavigationController(FormBase startForm, params FormBase[] forms) : this()
|
||||
{
|
||||
Client = startForm.Client;
|
||||
Device = startForm.Device;
|
||||
startForm.NavigationController = this;
|
||||
[SaveState] private List<FormBase> History { get; }
|
||||
|
||||
History.Add(startForm);
|
||||
Index = 0;
|
||||
[SaveState] public int Index { get; set; }
|
||||
|
||||
if (forms.Length > 0)
|
||||
{
|
||||
History.AddRange(forms);
|
||||
Index = History.Count - 1;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Will replace the controller when poping a form to the root form.
|
||||
/// </summary>
|
||||
[SaveState]
|
||||
public bool ForceCleanupOnLastPop { get; set; }
|
||||
|
||||
private async Task NavigationController_Init(object sender, InitEventArgs e)
|
||||
{
|
||||
if (CurrentForm == null)
|
||||
return;
|
||||
|
||||
await CurrentForm.OnInit(e);
|
||||
}
|
||||
|
||||
private async Task NavigationController_Opened(object sender, EventArgs e)
|
||||
{
|
||||
if (CurrentForm == null)
|
||||
return;
|
||||
|
||||
await CurrentForm.OnOpened(e);
|
||||
}
|
||||
|
||||
private async Task NavigationController_Closed(object sender, EventArgs e)
|
||||
{
|
||||
if (CurrentForm == null)
|
||||
return;
|
||||
|
||||
await CurrentForm.OnClosed(e);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Remove the current active form on the stack.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public virtual async Task PopAsync()
|
||||
/// <summary>
|
||||
/// Returns the current form from the stack.
|
||||
/// </summary>
|
||||
public FormBase CurrentForm
|
||||
{
|
||||
get
|
||||
{
|
||||
if (History.Count == 0)
|
||||
return;
|
||||
|
||||
var form = History[Index];
|
||||
|
||||
form.NavigationController = null;
|
||||
History.Remove(form);
|
||||
Index--;
|
||||
|
||||
Device.FormSwitched = true;
|
||||
|
||||
await form.OnClosed(EventArgs.Empty);
|
||||
|
||||
//Leave NavigationController and move to the last one
|
||||
if (ForceCleanupOnLastPop && History.Count == 1)
|
||||
{
|
||||
var lastForm = History[0];
|
||||
lastForm.NavigationController = null;
|
||||
await NavigateTo(lastForm);
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
if (History.Count > 0)
|
||||
{
|
||||
form = History[Index];
|
||||
await form.OnOpened(EventArgs.Empty);
|
||||
}
|
||||
return History[Index];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void LoadState(LoadStateEventArgs e)
|
||||
{
|
||||
if (e.Get("$controller.history.count") == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pop's through all forms back to the root form.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public virtual async Task PopToRootAsync()
|
||||
{
|
||||
while (Index > 0)
|
||||
{
|
||||
await PopAsync();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pushing the given form to the stack and renders it.
|
||||
/// </summary>
|
||||
/// <param name="form"></param>
|
||||
/// <returns></returns>
|
||||
public virtual async Task PushAsync(FormBase form, params object[] args)
|
||||
var historyCount = e.GetInt("$controller.history.count");
|
||||
|
||||
for (var i = 0; i < historyCount; i++)
|
||||
{
|
||||
form.Client = Client;
|
||||
var c = e.GetObject($"$controller.history[{i}]") as Dictionary<string, object>;
|
||||
|
||||
|
||||
var qname = e.Get($"$controller.history[{i}].type");
|
||||
|
||||
if (qname == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var t = Type.GetType(qname);
|
||||
if (t == null || !t.IsSubclassOf(typeof(FormBase)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
//No default constructor, fallback
|
||||
if (t.GetConstructor(new Type[] { })?.Invoke(new object[] { }) is not FormBase form)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var properties = c.Where(a => a.Key.StartsWith("$"));
|
||||
|
||||
var fields = form.GetType()
|
||||
.GetProperties(BindingFlags.Instance | BindingFlags.Public | 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)
|
||||
{
|
||||
Conversion.CustomConversionChecks(form, p, f);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
form.Device = Device;
|
||||
form.Client = Client;
|
||||
form.NavigationController = this;
|
||||
|
||||
form.OnInit(new InitEventArgs());
|
||||
|
||||
History.Add(form);
|
||||
Index++;
|
||||
}
|
||||
}
|
||||
|
||||
Device.FormSwitched = true;
|
||||
public void SaveState(SaveStateEventArgs e)
|
||||
{
|
||||
e.Set("$controller.history.count", History.Count.ToString());
|
||||
|
||||
if (Index < 2)
|
||||
return;
|
||||
var i = 0;
|
||||
foreach (var form in History)
|
||||
{
|
||||
var fields = form.GetType()
|
||||
.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
|
||||
.Where(a => a.GetCustomAttributes(typeof(SaveState), true).Length != 0).ToList();
|
||||
|
||||
await form.OnInit(new InitEventArgs(args));
|
||||
var dt = new Dictionary<string, object>();
|
||||
foreach (var f in fields)
|
||||
{
|
||||
var val = f.GetValue(form);
|
||||
|
||||
dt.Add("$" + f.Name, val);
|
||||
}
|
||||
|
||||
e.Set($"$controller.history[{i}].type", form.GetType().AssemblyQualifiedName);
|
||||
|
||||
e.SetObject($"$controller.history[{i}]", dt);
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task NavigationController_Init(object sender, InitEventArgs e)
|
||||
{
|
||||
if (CurrentForm == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
await CurrentForm.OnInit(e);
|
||||
}
|
||||
|
||||
private async Task NavigationController_Opened(object sender, EventArgs e)
|
||||
{
|
||||
if (CurrentForm == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
await CurrentForm.OnOpened(e);
|
||||
}
|
||||
|
||||
private async Task NavigationController_Closed(object sender, EventArgs e)
|
||||
{
|
||||
if (CurrentForm == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
await CurrentForm.OnClosed(e);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Remove the current active form on the stack.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public virtual async Task PopAsync()
|
||||
{
|
||||
if (History.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var form = History[Index];
|
||||
|
||||
form.NavigationController = null;
|
||||
History.Remove(form);
|
||||
Index--;
|
||||
|
||||
Device.FormSwitched = true;
|
||||
|
||||
await form.OnClosed(EventArgs.Empty);
|
||||
|
||||
//Leave NavigationController and move to the last one
|
||||
if (ForceCleanupOnLastPop && History.Count == 1)
|
||||
{
|
||||
var lastForm = History[0];
|
||||
lastForm.NavigationController = null;
|
||||
await NavigateTo(lastForm);
|
||||
return;
|
||||
}
|
||||
|
||||
if (History.Count > 0)
|
||||
{
|
||||
form = History[Index];
|
||||
await form.OnOpened(EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pops the current form and pushes a new one.
|
||||
/// Will help to remove forms so you can not navigate back to them.
|
||||
/// </summary>
|
||||
/// <param name="form"></param>
|
||||
/// <param name="args"></param>
|
||||
/// <returns></returns>
|
||||
public virtual async Task PushAndReplaceAsync(FormBase form, params object[] args)
|
||||
/// <summary>
|
||||
/// Pop's through all forms back to the root form.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public virtual async Task PopToRootAsync()
|
||||
{
|
||||
while (Index > 0)
|
||||
{
|
||||
await PopAsync();
|
||||
|
||||
await PushAsync(form, args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the current form from the stack.
|
||||
/// </summary>
|
||||
public FormBase CurrentForm
|
||||
{
|
||||
get
|
||||
{
|
||||
if (History.Count == 0)
|
||||
return null;
|
||||
|
||||
return History[Index];
|
||||
}
|
||||
}
|
||||
|
||||
public List<FormBase> GetAllForms()
|
||||
{
|
||||
return History.ToList();
|
||||
}
|
||||
|
||||
|
||||
public void LoadState(LoadStateEventArgs e)
|
||||
{
|
||||
if (e.Get("$controller.history.count") == null)
|
||||
return;
|
||||
|
||||
|
||||
var historyCount = e.GetInt("$controller.history.count");
|
||||
|
||||
for (var i = 0; i < historyCount; i++)
|
||||
{
|
||||
|
||||
var c = e.GetObject($"$controller.history[{i}]") as Dictionary<string, object>;
|
||||
|
||||
|
||||
|
||||
var qname = e.Get($"$controller.history[{i}].type");
|
||||
|
||||
if (qname == null)
|
||||
continue;
|
||||
|
||||
var t = Type.GetType(qname);
|
||||
if (t == null || !t.IsSubclassOf(typeof(FormBase)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
//No default constructor, fallback
|
||||
if (t.GetConstructor(new Type[] { })?.Invoke(new object[] { }) is not FormBase form)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var properties = c.Where(a => a.Key.StartsWith("$"));
|
||||
|
||||
var fields = form.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public | 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)
|
||||
{
|
||||
|
||||
Conversion.CustomConversionChecks(form, p, f);
|
||||
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
form.Device = Device;
|
||||
form.Client = Client;
|
||||
form.NavigationController = this;
|
||||
|
||||
form.OnInit(new InitEventArgs());
|
||||
|
||||
History.Add(form);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void SaveState(SaveStateEventArgs e)
|
||||
{
|
||||
e.Set("$controller.history.count", History.Count.ToString());
|
||||
|
||||
var i = 0;
|
||||
foreach (var form in History)
|
||||
{
|
||||
var fields = form.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).Where(a => a.GetCustomAttributes(typeof(SaveState), true).Length != 0).ToList();
|
||||
|
||||
var dt = new Dictionary<string, object>();
|
||||
foreach (var f in fields)
|
||||
{
|
||||
var val = f.GetValue(form);
|
||||
|
||||
dt.Add("$" + f.Name, val);
|
||||
}
|
||||
|
||||
e.Set($"$controller.history[{i}].type", form.GetType().AssemblyQualifiedName);
|
||||
|
||||
e.SetObject($"$controller.history[{i}]", dt);
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#region "Methods passthrough"
|
||||
|
||||
public override async Task NavigateTo(FormBase newForm, params object[] args)
|
||||
{
|
||||
await CurrentForm.NavigateTo(newForm, args);
|
||||
}
|
||||
|
||||
public override async Task LoadControls(MessageResult message)
|
||||
{
|
||||
await CurrentForm.LoadControls(message);
|
||||
}
|
||||
|
||||
public override async Task Load(MessageResult message)
|
||||
{
|
||||
await CurrentForm.Load(message);
|
||||
}
|
||||
|
||||
public override async Task ActionControls(MessageResult message)
|
||||
{
|
||||
await CurrentForm.ActionControls(message);
|
||||
}
|
||||
|
||||
public override async Task Action(MessageResult message)
|
||||
{
|
||||
await CurrentForm.Action(message);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public override async Task Edited(MessageResult message)
|
||||
{
|
||||
await CurrentForm.Edited(message);
|
||||
}
|
||||
|
||||
public override async Task Render(MessageResult message)
|
||||
{
|
||||
await CurrentForm.Render(message);
|
||||
}
|
||||
|
||||
public override async Task RenderControls(MessageResult message)
|
||||
{
|
||||
await CurrentForm.RenderControls(message);
|
||||
}
|
||||
|
||||
public override async Task PreLoad(MessageResult message)
|
||||
{
|
||||
await CurrentForm.PreLoad(message);
|
||||
}
|
||||
|
||||
public override async Task ReturnFromModal(ModalDialog modal)
|
||||
{
|
||||
await CurrentForm.ReturnFromModal(modal);
|
||||
}
|
||||
|
||||
public override async Task SentData(DataResult message)
|
||||
{
|
||||
await CurrentForm.SentData(message);
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pushing the given form to the stack and renders it.
|
||||
/// </summary>
|
||||
/// <param name="form"></param>
|
||||
/// <returns></returns>
|
||||
public virtual async Task PushAsync(FormBase form, params object[] args)
|
||||
{
|
||||
form.Client = Client;
|
||||
form.Device = Device;
|
||||
form.NavigationController = this;
|
||||
|
||||
History.Add(form);
|
||||
Index++;
|
||||
|
||||
Device.FormSwitched = true;
|
||||
|
||||
if (Index < 2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
await form.OnInit(new InitEventArgs(args));
|
||||
|
||||
await form.OnOpened(EventArgs.Empty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pops the current form and pushes a new one.
|
||||
/// Will help to remove forms so you can not navigate back to them.
|
||||
/// </summary>
|
||||
/// <param name="form"></param>
|
||||
/// <param name="args"></param>
|
||||
/// <returns></returns>
|
||||
public virtual async Task PushAndReplaceAsync(FormBase form, params object[] args)
|
||||
{
|
||||
await PopAsync();
|
||||
|
||||
await PushAsync(form, args);
|
||||
}
|
||||
|
||||
public List<FormBase> GetAllForms()
|
||||
{
|
||||
return History.ToList();
|
||||
}
|
||||
|
||||
|
||||
#region "Methods passthrough"
|
||||
|
||||
public override async Task NavigateTo(FormBase newForm, params object[] args)
|
||||
{
|
||||
await CurrentForm.NavigateTo(newForm, args);
|
||||
}
|
||||
|
||||
public override async Task LoadControls(MessageResult message)
|
||||
{
|
||||
await CurrentForm.LoadControls(message);
|
||||
}
|
||||
|
||||
public override async Task Load(MessageResult message)
|
||||
{
|
||||
await CurrentForm.Load(message);
|
||||
}
|
||||
|
||||
public override async Task ActionControls(MessageResult message)
|
||||
{
|
||||
await CurrentForm.ActionControls(message);
|
||||
}
|
||||
|
||||
public override async Task Action(MessageResult message)
|
||||
{
|
||||
await CurrentForm.Action(message);
|
||||
}
|
||||
|
||||
|
||||
public override async Task Edited(MessageResult message)
|
||||
{
|
||||
await CurrentForm.Edited(message);
|
||||
}
|
||||
|
||||
public override async Task Render(MessageResult message)
|
||||
{
|
||||
await CurrentForm.Render(message);
|
||||
}
|
||||
|
||||
public override async Task RenderControls(MessageResult message)
|
||||
{
|
||||
await CurrentForm.RenderControls(message);
|
||||
}
|
||||
|
||||
public override async Task PreLoad(MessageResult message)
|
||||
{
|
||||
await CurrentForm.PreLoad(message);
|
||||
}
|
||||
|
||||
public override async Task ReturnFromModal(ModalDialog modal)
|
||||
{
|
||||
await CurrentForm.ReturnFromModal(modal);
|
||||
}
|
||||
|
||||
public override async Task SentData(DataResult message)
|
||||
{
|
||||
await CurrentForm.SentData(message);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Threading.Tasks;
|
||||
using Telegram.Bot.Types;
|
||||
using Telegram.Bot.Types.ReplyMarkups;
|
||||
@@ -8,108 +7,106 @@ using TelegramBotBase.Attributes;
|
||||
using TelegramBotBase.Base;
|
||||
using TelegramBotBase.Localizations;
|
||||
|
||||
namespace TelegramBotBase.Form
|
||||
namespace TelegramBotBase.Form;
|
||||
|
||||
[IgnoreState]
|
||||
public class PromptDialog : ModalDialog
|
||||
{
|
||||
[IgnoreState]
|
||||
public class PromptDialog : ModalDialog
|
||||
public PromptDialog()
|
||||
{
|
||||
/// <summary>
|
||||
/// The message the users sees.
|
||||
/// </summary>
|
||||
public string Message { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The returned text value by the user.
|
||||
/// </summary>
|
||||
public string Value { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// An additional optional value.
|
||||
/// </summary>
|
||||
public object Tag { get; set; }
|
||||
|
||||
private static object EvCompleted { get; } = new object();
|
||||
|
||||
public bool ShowBackButton { get; set; } = false;
|
||||
|
||||
public string BackLabel { get; set; } = Default.Language["PromptDialog_Back"];
|
||||
|
||||
/// <summary>
|
||||
/// Contains the RAW received message.
|
||||
/// </summary>
|
||||
public Message ReceivedMessage { get; set; }
|
||||
|
||||
public PromptDialog()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public PromptDialog(string message)
|
||||
{
|
||||
this.Message = message;
|
||||
}
|
||||
|
||||
public override async Task Load(MessageResult message)
|
||||
{
|
||||
if (message.Handled)
|
||||
return;
|
||||
|
||||
if (!message.IsFirstHandler)
|
||||
return;
|
||||
|
||||
if (ShowBackButton && message.MessageText == BackLabel)
|
||||
{
|
||||
await CloseForm();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (Value == null)
|
||||
{
|
||||
Value = message.MessageText;
|
||||
|
||||
ReceivedMessage = message.Message;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public override async Task Render(MessageResult message)
|
||||
{
|
||||
|
||||
if (Value == null)
|
||||
{
|
||||
if (ShowBackButton)
|
||||
{
|
||||
var bf = new ButtonForm();
|
||||
bf.AddButtonRow(new ButtonBase(BackLabel, "back"));
|
||||
await Device.Send(Message, (ReplyMarkupBase)bf);
|
||||
return;
|
||||
}
|
||||
|
||||
await Device.Send(Message);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
message.Handled = true;
|
||||
|
||||
OnCompleted(new PromptDialogCompletedEventArgs { Tag = Tag, Value = Value });
|
||||
|
||||
await CloseForm();
|
||||
}
|
||||
|
||||
|
||||
public event EventHandler<PromptDialogCompletedEventArgs> Completed
|
||||
{
|
||||
add => Events.AddHandler(EvCompleted, value);
|
||||
remove => Events.RemoveHandler(EvCompleted, value);
|
||||
}
|
||||
|
||||
public void OnCompleted(PromptDialogCompletedEventArgs e)
|
||||
{
|
||||
(Events[EvCompleted] as EventHandler<PromptDialogCompletedEventArgs>)?.Invoke(this, e);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public PromptDialog(string message)
|
||||
{
|
||||
Message = message;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The message the users sees.
|
||||
/// </summary>
|
||||
public string Message { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The returned text value by the user.
|
||||
/// </summary>
|
||||
public string Value { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// An additional optional value.
|
||||
/// </summary>
|
||||
public object Tag { get; set; }
|
||||
|
||||
private static object EvCompleted { get; } = new();
|
||||
|
||||
public bool ShowBackButton { get; set; } = false;
|
||||
|
||||
public string BackLabel { get; set; } = Default.Language["PromptDialog_Back"];
|
||||
|
||||
/// <summary>
|
||||
/// Contains the RAW received message.
|
||||
/// </summary>
|
||||
public Message ReceivedMessage { get; set; }
|
||||
|
||||
public override async Task Load(MessageResult message)
|
||||
{
|
||||
if (message.Handled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!message.IsFirstHandler)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (ShowBackButton && message.MessageText == BackLabel)
|
||||
{
|
||||
await CloseForm();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (Value == null)
|
||||
{
|
||||
Value = message.MessageText;
|
||||
|
||||
ReceivedMessage = message.Message;
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task Render(MessageResult message)
|
||||
{
|
||||
if (Value == null)
|
||||
{
|
||||
if (ShowBackButton)
|
||||
{
|
||||
var bf = new ButtonForm();
|
||||
bf.AddButtonRow(new ButtonBase(BackLabel, "back"));
|
||||
await Device.Send(Message, (ReplyMarkupBase)bf);
|
||||
return;
|
||||
}
|
||||
|
||||
await Device.Send(Message);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
message.Handled = true;
|
||||
|
||||
OnCompleted(new PromptDialogCompletedEventArgs { Tag = Tag, Value = Value });
|
||||
|
||||
await CloseForm();
|
||||
}
|
||||
|
||||
|
||||
public event EventHandler<PromptDialogCompletedEventArgs> Completed
|
||||
{
|
||||
add => Events.AddHandler(EvCompleted, value);
|
||||
remove => Events.RemoveHandler(EvCompleted, value);
|
||||
}
|
||||
|
||||
public void OnCompleted(PromptDialogCompletedEventArgs e)
|
||||
{
|
||||
(Events[EvCompleted] as EventHandler<PromptDialogCompletedEventArgs>)?.Invoke(this, e);
|
||||
}
|
||||
}
|
||||
@@ -2,95 +2,92 @@
|
||||
using Telegram.Bot.Types.Enums;
|
||||
using TelegramBotBase.Base;
|
||||
|
||||
namespace TelegramBotBase.Form
|
||||
namespace TelegramBotBase.Form;
|
||||
|
||||
/// <summary>
|
||||
/// This is used to split incomming requests depending on the chat type.
|
||||
/// </summary>
|
||||
public class SplitterForm : FormBase
|
||||
{
|
||||
/// <summary>
|
||||
/// This is used to split incomming requests depending on the chat type.
|
||||
/// </summary>
|
||||
public class SplitterForm : FormBase
|
||||
private static object __evOpenSupergroup = new();
|
||||
private static object __evOpenGroup = new();
|
||||
private static object __evOpenChannel = new();
|
||||
private static object __evOpen = new();
|
||||
|
||||
|
||||
public override async Task Load(MessageResult message)
|
||||
{
|
||||
|
||||
private static object __evOpenSupergroup = new object();
|
||||
private static object __evOpenGroup = new object();
|
||||
private static object __evOpenChannel = new object();
|
||||
private static object __evOpen = new object();
|
||||
|
||||
|
||||
public override async Task Load(MessageResult message)
|
||||
if (message.Message.Chat.Type == ChatType.Channel)
|
||||
{
|
||||
if (await OpenChannel(message))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (message.Message.Chat.Type == ChatType.Channel)
|
||||
if (message.Message.Chat.Type == ChatType.Supergroup)
|
||||
{
|
||||
if (await OpenSupergroup(message))
|
||||
{
|
||||
if (await OpenChannel(message))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (message.Message.Chat.Type == ChatType.Supergroup)
|
||||
{
|
||||
if (await OpenSupergroup(message))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (await OpenGroup(message))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (message.Message.Chat.Type == ChatType.Group)
|
||||
{
|
||||
if (await OpenGroup(message))
|
||||
{
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
await Open(message);
|
||||
if (await OpenGroup(message))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public virtual Task<bool> OpenSupergroup(MessageResult e)
|
||||
if (message.Message.Chat.Type == ChatType.Group)
|
||||
{
|
||||
return Task.FromResult(false);
|
||||
}
|
||||
|
||||
public virtual Task<bool> OpenChannel(MessageResult e)
|
||||
{
|
||||
return Task.FromResult(false);
|
||||
}
|
||||
|
||||
public virtual Task<bool> Open(MessageResult e)
|
||||
{
|
||||
return Task.FromResult(false);
|
||||
}
|
||||
|
||||
public virtual Task<bool> OpenGroup(MessageResult e)
|
||||
{
|
||||
return Task.FromResult(false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public override Task Action(MessageResult message)
|
||||
{
|
||||
return base.Action(message);
|
||||
}
|
||||
|
||||
public override Task PreLoad(MessageResult message)
|
||||
{
|
||||
return base.PreLoad(message);
|
||||
}
|
||||
|
||||
public override Task Render(MessageResult message)
|
||||
{
|
||||
return base.Render(message);
|
||||
}
|
||||
|
||||
public override Task SentData(DataResult message)
|
||||
{
|
||||
return base.SentData(message);
|
||||
if (await OpenGroup(message))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
await Open(message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public virtual Task<bool> OpenSupergroup(MessageResult e)
|
||||
{
|
||||
return Task.FromResult(false);
|
||||
}
|
||||
|
||||
public virtual Task<bool> OpenChannel(MessageResult e)
|
||||
{
|
||||
return Task.FromResult(false);
|
||||
}
|
||||
|
||||
public virtual Task<bool> Open(MessageResult e)
|
||||
{
|
||||
return Task.FromResult(false);
|
||||
}
|
||||
|
||||
public virtual Task<bool> OpenGroup(MessageResult e)
|
||||
{
|
||||
return Task.FromResult(false);
|
||||
}
|
||||
|
||||
|
||||
public override Task Action(MessageResult message)
|
||||
{
|
||||
return base.Action(message);
|
||||
}
|
||||
|
||||
public override Task PreLoad(MessageResult message)
|
||||
{
|
||||
return base.PreLoad(message);
|
||||
}
|
||||
|
||||
public override Task Render(MessageResult message)
|
||||
{
|
||||
return base.Render(message);
|
||||
}
|
||||
|
||||
public override Task SentData(DataResult message)
|
||||
{
|
||||
return base.SentData(message);
|
||||
}
|
||||
}
|
||||
@@ -1,50 +1,46 @@
|
||||
using Telegram.Bot.Types.ReplyMarkups;
|
||||
|
||||
namespace TelegramBotBase.Form
|
||||
namespace TelegramBotBase.Form;
|
||||
|
||||
/// <summary>
|
||||
/// Base class for button handling
|
||||
/// </summary>
|
||||
public class TagButtonBase : ButtonBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for button handling
|
||||
/// </summary>
|
||||
public class TagButtonBase : ButtonBase
|
||||
public TagButtonBase()
|
||||
{
|
||||
public string Tag { get; set; }
|
||||
|
||||
public TagButtonBase()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public TagButtonBase(string text, string value, string tag)
|
||||
{
|
||||
this.Text = text;
|
||||
this.Value = value;
|
||||
this.Tag = tag;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns an inline Button
|
||||
/// </summary>
|
||||
/// <param name="form"></param>
|
||||
/// <returns></returns>
|
||||
public override InlineKeyboardButton ToInlineButton(ButtonForm form)
|
||||
{
|
||||
var id = (form.DependencyControl != null ? form.DependencyControl.ControlId + "_" : "");
|
||||
|
||||
return InlineKeyboardButton.WithCallbackData(Text, id + Value);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns a KeyBoardButton
|
||||
/// </summary>
|
||||
/// <param name="form"></param>
|
||||
/// <returns></returns>
|
||||
public override KeyboardButton ToKeyboardButton(ButtonForm form)
|
||||
{
|
||||
return new KeyboardButton(Text);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public TagButtonBase(string text, string value, string tag)
|
||||
{
|
||||
Text = text;
|
||||
Value = value;
|
||||
Tag = tag;
|
||||
}
|
||||
|
||||
public string Tag { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns an inline Button
|
||||
/// </summary>
|
||||
/// <param name="form"></param>
|
||||
/// <returns></returns>
|
||||
public override InlineKeyboardButton ToInlineButton(ButtonForm form)
|
||||
{
|
||||
var id = form.DependencyControl != null ? form.DependencyControl.ControlId + "_" : "";
|
||||
|
||||
return InlineKeyboardButton.WithCallbackData(Text, id + Value);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns a KeyBoardButton
|
||||
/// </summary>
|
||||
/// <param name="form"></param>
|
||||
/// <returns></returns>
|
||||
public override KeyboardButton ToKeyboardButton(ButtonForm form)
|
||||
{
|
||||
return new KeyboardButton(Text);
|
||||
}
|
||||
}
|
||||
@@ -1,40 +1,36 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace TelegramBotBase.Interfaces
|
||||
namespace TelegramBotBase.Interfaces;
|
||||
|
||||
public interface IDataSource<T>
|
||||
{
|
||||
public interface IDataSource<T>
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Returns the amount of items within this source.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
int Count { get; }
|
||||
/// <summary>
|
||||
/// Returns the amount of items within this source.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
int Count { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns the item at the specific index.
|
||||
/// </summary>
|
||||
/// <param name="index"></param>
|
||||
/// <returns></returns>
|
||||
T ItemAt(int index);
|
||||
/// <summary>
|
||||
/// Returns the item at the specific index.
|
||||
/// </summary>
|
||||
/// <param name="index"></param>
|
||||
/// <returns></returns>
|
||||
T ItemAt(int index);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get all items from this source within this range.
|
||||
/// </summary>
|
||||
/// <param name="start"></param>
|
||||
/// <param name="count"></param>
|
||||
/// <returns></returns>
|
||||
List<T> ItemRange(int start, int count);
|
||||
/// <summary>
|
||||
/// Get all items from this source within this range.
|
||||
/// </summary>
|
||||
/// <param name="start"></param>
|
||||
/// <param name="count"></param>
|
||||
/// <returns></returns>
|
||||
List<T> ItemRange(int start, int count);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of all items of this datasource.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
List<T> AllItems();
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets a list of all items of this datasource.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
List<T> AllItems();
|
||||
}
|
||||
@@ -1,40 +1,38 @@
|
||||
using System;
|
||||
using TelegramBotBase.Form;
|
||||
|
||||
namespace TelegramBotBase.Interfaces
|
||||
namespace TelegramBotBase.Interfaces;
|
||||
|
||||
internal interface IDeviceSession
|
||||
{
|
||||
internal interface IDeviceSession
|
||||
{
|
||||
/// <summary>
|
||||
/// Device or chat id
|
||||
/// </summary>
|
||||
long DeviceId { get; set; }
|
||||
/// <summary>
|
||||
/// Device or chat id
|
||||
/// </summary>
|
||||
long DeviceId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Username of user or group
|
||||
/// </summary>
|
||||
string ChatTitle { get; set; }
|
||||
/// <summary>
|
||||
/// Username of user or group
|
||||
/// </summary>
|
||||
string ChatTitle { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// When did any last action happend (message received or button clicked)
|
||||
/// </summary>
|
||||
DateTime LastAction { get; set; }
|
||||
/// <summary>
|
||||
/// When did any last action happend (message received or button clicked)
|
||||
/// </summary>
|
||||
DateTime LastAction { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the form where the user/group is at the moment.
|
||||
/// </summary>
|
||||
FormBase ActiveForm { get; set; }
|
||||
/// <summary>
|
||||
/// Returns the form where the user/group is at the moment.
|
||||
/// </summary>
|
||||
FormBase ActiveForm { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the previous shown form
|
||||
/// </summary>
|
||||
FormBase PreviousForm { get; set; }
|
||||
/// <summary>
|
||||
/// Returns the previous shown form
|
||||
/// </summary>
|
||||
FormBase PreviousForm { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// contains if the form has been switched (navigated)
|
||||
/// </summary>
|
||||
bool FormSwitched { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// contains if the form has been switched (navigated)
|
||||
/// </summary>
|
||||
bool FormSwitched { get; set; }
|
||||
}
|
||||
@@ -4,15 +4,11 @@ using TelegramBotBase.Args;
|
||||
using TelegramBotBase.Base;
|
||||
using TelegramBotBase.Sessions;
|
||||
|
||||
namespace TelegramBotBase.Interfaces
|
||||
namespace TelegramBotBase.Interfaces;
|
||||
|
||||
public interface IMessageLoopFactory
|
||||
{
|
||||
public interface IMessageLoopFactory
|
||||
{
|
||||
Task MessageLoop(BotBase bot, DeviceSession session, UpdateResult ur, MessageResult e);
|
||||
|
||||
Task MessageLoop(BotBase bot, DeviceSession session, UpdateResult ur, MessageResult e);
|
||||
|
||||
event EventHandler<UnhandledCallEventArgs> UnhandledCall;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
event EventHandler<UnhandledCallEventArgs> UnhandledCall;
|
||||
}
|
||||
@@ -1,9 +1,8 @@
|
||||
using TelegramBotBase.Form;
|
||||
|
||||
namespace TelegramBotBase.Interfaces
|
||||
namespace TelegramBotBase.Interfaces;
|
||||
|
||||
public interface IStartFormFactory
|
||||
{
|
||||
public interface IStartFormFactory
|
||||
{
|
||||
FormBase CreateForm();
|
||||
}
|
||||
}
|
||||
FormBase CreateForm();
|
||||
}
|
||||
@@ -1,16 +1,13 @@
|
||||
using TelegramBotBase.Args;
|
||||
|
||||
namespace TelegramBotBase.Interfaces
|
||||
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
|
||||
{
|
||||
/// <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 LoadState(LoadStateEventArgs e);
|
||||
|
||||
void SaveState(SaveStateEventArgs e);
|
||||
|
||||
}
|
||||
}
|
||||
void SaveState(SaveStateEventArgs e);
|
||||
}
|
||||
@@ -2,14 +2,13 @@
|
||||
using TelegramBotBase.Args;
|
||||
using TelegramBotBase.Base;
|
||||
|
||||
namespace TelegramBotBase.Interfaces
|
||||
namespace TelegramBotBase.Interfaces;
|
||||
|
||||
public interface IStateMachine
|
||||
{
|
||||
public interface IStateMachine
|
||||
{
|
||||
Type FallbackStateForm { get; }
|
||||
Type FallbackStateForm { get; }
|
||||
|
||||
void SaveFormStates(SaveStatesEventArgs e);
|
||||
void SaveFormStates(SaveStatesEventArgs e);
|
||||
|
||||
StateContainer LoadFormStates();
|
||||
}
|
||||
}
|
||||
StateContainer LoadFormStates();
|
||||
}
|
||||
@@ -1,10 +1,6 @@
|
||||
namespace TelegramBotBase.Localizations
|
||||
namespace TelegramBotBase.Localizations;
|
||||
|
||||
public static class Default
|
||||
{
|
||||
public static class Default
|
||||
{
|
||||
|
||||
public static Localization Language = new English();
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
public static Localization Language = new English();
|
||||
}
|
||||
@@ -1,37 +1,35 @@
|
||||
namespace TelegramBotBase.Localizations
|
||||
namespace TelegramBotBase.Localizations;
|
||||
|
||||
public class English : Localization
|
||||
{
|
||||
public class English : Localization
|
||||
public English()
|
||||
{
|
||||
public English()
|
||||
{
|
||||
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["ButtonGrid_Back"] = "Back";
|
||||
Values["ButtonGrid_CheckAll"] = "Check all";
|
||||
Values["ButtonGrid_UncheckAll"] = "Uncheck all";
|
||||
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["ToggleButton_Changed"] = "Choosen";
|
||||
Values["MultiToggleButton_SelectedIcon"] = "✅";
|
||||
Values["MultiToggleButton_Title"] = "Multi-Toggle";
|
||||
Values["MultiToggleButton_Changed"] = "Choosen";
|
||||
Values["PromptDialog_Back"] = "Back";
|
||||
Values["ToggleButton_Changed"] = "Setting changed";
|
||||
}
|
||||
|
||||
|
||||
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["ButtonGrid_Back"] = "Back";
|
||||
Values["ButtonGrid_CheckAll"] = "Check all";
|
||||
Values["ButtonGrid_UncheckAll"] = "Uncheck all";
|
||||
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["ToggleButton_Changed"] = "Choosen";
|
||||
Values["MultiToggleButton_SelectedIcon"] = "✅";
|
||||
Values["MultiToggleButton_Title"] = "Multi-Toggle";
|
||||
Values["MultiToggleButton_Changed"] = "Choosen";
|
||||
Values["PromptDialog_Back"] = "Back";
|
||||
Values["ToggleButton_Changed"] = "Setting changed";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,37 +1,35 @@
|
||||
namespace TelegramBotBase.Localizations
|
||||
namespace TelegramBotBase.Localizations;
|
||||
|
||||
public class German : Localization
|
||||
{
|
||||
public class German : Localization
|
||||
public German()
|
||||
{
|
||||
public German()
|
||||
{
|
||||
Values["Language"] = "Deutsch (German)";
|
||||
Values["ButtonGrid_Title"] = "Menü";
|
||||
Values["ButtonGrid_NoItems"] = "Es sind keine Einträge vorhanden.";
|
||||
Values["ButtonGrid_PreviousPage"] = "◀️";
|
||||
Values["ButtonGrid_NextPage"] = "▶️";
|
||||
Values["ButtonGrid_CurrentPage"] = "Seite {0} von {1}";
|
||||
Values["ButtonGrid_SearchFeature"] = "💡 Sende eine Nachricht um die Liste zu filtern. Klicke die 🔍 um den Filter zurückzusetzen.";
|
||||
Values["ButtonGrid_Back"] = "Zurück";
|
||||
Values["ButtonGrid_CheckAll"] = "Alle auswählen";
|
||||
Values["ButtonGrid_UncheckAll"] = "Keine auswählen";
|
||||
Values["CalendarPicker_Title"] = "Datum auswählen";
|
||||
Values["CalendarPicker_PreviousPage"] = "◀️";
|
||||
Values["CalendarPicker_NextPage"] = "▶️";
|
||||
Values["TreeView_Title"] = "Knoten auswählen";
|
||||
Values["TreeView_LevelUp"] = "🔼 Stufe hoch";
|
||||
Values["ToggleButton_On"] = "An";
|
||||
Values["ToggleButton_Off"] = "Aus";
|
||||
Values["ToggleButton_OnIcon"] = "⚫";
|
||||
Values["ToggleButton_OffIcon"] = "⚪";
|
||||
Values["ToggleButton_Title"] = "Schalter";
|
||||
Values["ToggleButton_Changed"] = "Ausgewählt";
|
||||
Values["MultiToggleButton_SelectedIcon"] = "✅";
|
||||
Values["MultiToggleButton_Title"] = "Mehrfach-Schalter";
|
||||
Values["MultiToggleButton_Changed"] = "Ausgewählt";
|
||||
Values["PromptDialog_Back"] = "Zurück";
|
||||
Values["ToggleButton_Changed"] = "Einstellung geändert";
|
||||
}
|
||||
|
||||
|
||||
Values["Language"] = "Deutsch (German)";
|
||||
Values["ButtonGrid_Title"] = "Menü";
|
||||
Values["ButtonGrid_NoItems"] = "Es sind keine Einträge vorhanden.";
|
||||
Values["ButtonGrid_PreviousPage"] = "◀️";
|
||||
Values["ButtonGrid_NextPage"] = "▶️";
|
||||
Values["ButtonGrid_CurrentPage"] = "Seite {0} von {1}";
|
||||
Values["ButtonGrid_SearchFeature"] =
|
||||
"💡 Sende eine Nachricht um die Liste zu filtern. Klicke die 🔍 um den Filter zurückzusetzen.";
|
||||
Values["ButtonGrid_Back"] = "Zurück";
|
||||
Values["ButtonGrid_CheckAll"] = "Alle auswählen";
|
||||
Values["ButtonGrid_UncheckAll"] = "Keine auswählen";
|
||||
Values["CalendarPicker_Title"] = "Datum auswählen";
|
||||
Values["CalendarPicker_PreviousPage"] = "◀️";
|
||||
Values["CalendarPicker_NextPage"] = "▶️";
|
||||
Values["TreeView_Title"] = "Knoten auswählen";
|
||||
Values["TreeView_LevelUp"] = "🔼 Stufe hoch";
|
||||
Values["ToggleButton_On"] = "An";
|
||||
Values["ToggleButton_Off"] = "Aus";
|
||||
Values["ToggleButton_OnIcon"] = "⚫";
|
||||
Values["ToggleButton_OffIcon"] = "⚪";
|
||||
Values["ToggleButton_Title"] = "Schalter";
|
||||
Values["ToggleButton_Changed"] = "Ausgewählt";
|
||||
Values["MultiToggleButton_SelectedIcon"] = "✅";
|
||||
Values["MultiToggleButton_Title"] = "Mehrfach-Schalter";
|
||||
Values["MultiToggleButton_Changed"] = "Ausgewählt";
|
||||
Values["PromptDialog_Back"] = "Zurück";
|
||||
Values["ToggleButton_Changed"] = "Einstellung geändert";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,10 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace TelegramBotBase.Localizations
|
||||
namespace TelegramBotBase.Localizations;
|
||||
|
||||
public abstract class Localization
|
||||
{
|
||||
public abstract class Localization
|
||||
{
|
||||
public Dictionary<string, string> Values = new Dictionary<string, string>();
|
||||
|
||||
public string this[string key] => Values[key];
|
||||
}
|
||||
}
|
||||
public Dictionary<string, string> Values = new();
|
||||
|
||||
public string this[string key] => Values[key];
|
||||
}
|
||||
@@ -1,159 +1,159 @@
|
||||
using System.Linq;
|
||||
using Telegram.Bot.Types.Enums;
|
||||
|
||||
namespace TelegramBotBase.Markdown
|
||||
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;
|
||||
|
||||
/// <summary>
|
||||
/// https://core.telegram.org/bots/api#markdownv2-style
|
||||
/// Generates a link with title in Markdown or HTML
|
||||
/// </summary>
|
||||
public static class Generator
|
||||
/// <param name="url"></param>
|
||||
/// <param name="title"></param>
|
||||
/// <param name="tooltip"></param>
|
||||
/// <returns></returns>
|
||||
public static string Link(this string url, string title = null, string tooltip = null)
|
||||
{
|
||||
public static ParseMode OutputMode { get; set; } = ParseMode.Markdown;
|
||||
|
||||
/// <summary>
|
||||
/// Generates a link with title in Markdown or HTML
|
||||
/// </summary>
|
||||
/// <param name="url"></param>
|
||||
/// <param name="title"></param>
|
||||
/// <param name="tooltip"></param>
|
||||
/// <returns></returns>
|
||||
public static string Link(this string url, string title = null, string tooltip = null)
|
||||
return OutputMode switch
|
||||
{
|
||||
return OutputMode switch
|
||||
{
|
||||
ParseMode.Markdown => "[" + (title ?? url) + "](" + url + " " + (tooltip ?? "") + ")",
|
||||
ParseMode.Html => $"<a href=\"{url}\" title=\"{tooltip ?? ""}\">{title ?? ""}</b>",
|
||||
_ => url
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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 int userId, string title = null)
|
||||
{
|
||||
return Link("tg://user?id=" + userId, title);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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>
|
||||
public static string Bold(this string text)
|
||||
{
|
||||
return OutputMode switch
|
||||
{
|
||||
ParseMode.Markdown => "*" + text + "*",
|
||||
ParseMode.Html => "<b>" + text + "</b>",
|
||||
_ => text
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a strike through in Markdown or HTML
|
||||
/// </summary>
|
||||
/// <param name="text"></param>
|
||||
/// <returns></returns>
|
||||
public static string Strikesthrough(this string text)
|
||||
{
|
||||
return OutputMode switch
|
||||
{
|
||||
ParseMode.Markdown => "~" + text + "~",
|
||||
ParseMode.Html => "<s>" + text + "</s>",
|
||||
_ => text
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a italic text in Markdown or HTML
|
||||
/// </summary>
|
||||
/// <param name="text"></param>
|
||||
/// <returns></returns>
|
||||
public static string Italic(this string text)
|
||||
{
|
||||
return OutputMode switch
|
||||
{
|
||||
ParseMode.Markdown => "_" + text + "_",
|
||||
ParseMode.Html => "<i>" + text + "</i>",
|
||||
_ => text
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a underline text in Markdown or HTML
|
||||
/// </summary>
|
||||
/// <param name="text"></param>
|
||||
/// <returns></returns>
|
||||
public static string Underline(this string text)
|
||||
{
|
||||
return OutputMode switch
|
||||
{
|
||||
ParseMode.Markdown => "__" + text + "__",
|
||||
ParseMode.Html => "<u>" + text + "</u>",
|
||||
_ => text
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a monospace text in Markdown or HTML
|
||||
/// </summary>
|
||||
/// <param name="text"></param>
|
||||
/// <returns></returns>
|
||||
public static string Monospace(this string text)
|
||||
{
|
||||
return OutputMode switch
|
||||
{
|
||||
ParseMode.Markdown => "`" + text + "`",
|
||||
ParseMode.Html => "<code>" + text + "</code>",
|
||||
_ => text
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a multi monospace text in Markdown or HTML
|
||||
/// </summary>
|
||||
/// <param name="text"></param>
|
||||
/// <returns></returns>
|
||||
public static string MultiMonospace(this string text)
|
||||
{
|
||||
return OutputMode switch
|
||||
{
|
||||
ParseMode.Markdown => "```" + text + "```",
|
||||
ParseMode.Html => "<pre>" + text + "</pre>",
|
||||
_ => 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)
|
||||
{
|
||||
var toEscape = new[] { '_', '*', '[', ']', '(', ')', '~', '`', '>', '#', '+', '-', '=', '|', '{', '}', '.', '!' };
|
||||
|
||||
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));
|
||||
}
|
||||
ParseMode.Markdown => "[" + (title ?? url) + "](" + url + " " + (tooltip ?? "") + ")",
|
||||
ParseMode.Html => $"<a href=\"{url}\" title=\"{tooltip ?? ""}\">{title ?? ""}</b>",
|
||||
_ => url
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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 int userId, string title = null)
|
||||
{
|
||||
return Link("tg://user?id=" + userId, title);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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>
|
||||
public static string Bold(this string text)
|
||||
{
|
||||
return OutputMode switch
|
||||
{
|
||||
ParseMode.Markdown => "*" + text + "*",
|
||||
ParseMode.Html => "<b>" + text + "</b>",
|
||||
_ => text
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a strike through in Markdown or HTML
|
||||
/// </summary>
|
||||
/// <param name="text"></param>
|
||||
/// <returns></returns>
|
||||
public static string Strikesthrough(this string text)
|
||||
{
|
||||
return OutputMode switch
|
||||
{
|
||||
ParseMode.Markdown => "~" + text + "~",
|
||||
ParseMode.Html => "<s>" + text + "</s>",
|
||||
_ => text
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a italic text in Markdown or HTML
|
||||
/// </summary>
|
||||
/// <param name="text"></param>
|
||||
/// <returns></returns>
|
||||
public static string Italic(this string text)
|
||||
{
|
||||
return OutputMode switch
|
||||
{
|
||||
ParseMode.Markdown => "_" + text + "_",
|
||||
ParseMode.Html => "<i>" + text + "</i>",
|
||||
_ => text
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a underline text in Markdown or HTML
|
||||
/// </summary>
|
||||
/// <param name="text"></param>
|
||||
/// <returns></returns>
|
||||
public static string Underline(this string text)
|
||||
{
|
||||
return OutputMode switch
|
||||
{
|
||||
ParseMode.Markdown => "__" + text + "__",
|
||||
ParseMode.Html => "<u>" + text + "</u>",
|
||||
_ => text
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a monospace text in Markdown or HTML
|
||||
/// </summary>
|
||||
/// <param name="text"></param>
|
||||
/// <returns></returns>
|
||||
public static string Monospace(this string text)
|
||||
{
|
||||
return OutputMode switch
|
||||
{
|
||||
ParseMode.Markdown => "`" + text + "`",
|
||||
ParseMode.Html => "<code>" + text + "</code>",
|
||||
_ => text
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a multi monospace text in Markdown or HTML
|
||||
/// </summary>
|
||||
/// <param name="text"></param>
|
||||
/// <returns></returns>
|
||||
public static string MultiMonospace(this string text)
|
||||
{
|
||||
return OutputMode switch
|
||||
{
|
||||
ParseMode.Markdown => "```" + text + "```",
|
||||
ParseMode.Html => "<pre>" + text + "</pre>",
|
||||
_ => 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)
|
||||
{
|
||||
var toEscape = new[]
|
||||
{ '_', '*', '[', ']', '(', ')', '~', '`', '>', '#', '+', '-', '=', '|', '{', '}', '.', '!' };
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
@@ -7,116 +7,116 @@ using TelegramBotBase.Base;
|
||||
using TelegramBotBase.Interfaces;
|
||||
using TelegramBotBase.Sessions;
|
||||
|
||||
namespace TelegramBotBase.MessageLoops
|
||||
namespace TelegramBotBase.MessageLoops;
|
||||
|
||||
/// <summary>
|
||||
/// Thats the default message loop which reacts to Message, EditMessage and CallbackQuery.
|
||||
/// </summary>
|
||||
public class FormBaseMessageLoop : IMessageLoopFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// Thats the default message loop which reacts to Message, EditMessage and CallbackQuery.
|
||||
/// </summary>
|
||||
public class FormBaseMessageLoop : IMessageLoopFactory
|
||||
private static readonly object EvUnhandledCall = new();
|
||||
|
||||
private readonly EventHandlerList _events = new();
|
||||
|
||||
public async Task MessageLoop(BotBase bot, DeviceSession session, UpdateResult ur, MessageResult mr)
|
||||
{
|
||||
private static readonly object EvUnhandledCall = new object();
|
||||
var update = ur.RawData;
|
||||
|
||||
private readonly EventHandlerList _events = new EventHandlerList();
|
||||
|
||||
public async Task MessageLoop(BotBase bot, DeviceSession session, UpdateResult ur, MessageResult mr)
|
||||
if (update.Type != UpdateType.Message
|
||||
&& update.Type != UpdateType.EditedMessage
|
||||
&& update.Type != UpdateType.CallbackQuery)
|
||||
{
|
||||
var update = ur.RawData;
|
||||
return;
|
||||
}
|
||||
|
||||
//Is this a bot command ?
|
||||
if (mr.IsFirstHandler && mr.IsBotCommand && bot.IsKnownBotCommand(mr.BotCommand))
|
||||
{
|
||||
var sce = new BotCommandEventArgs(mr.BotCommand, mr.BotCommandParameters, mr.Message, session.DeviceId,
|
||||
session);
|
||||
await bot.OnBotCommand(sce);
|
||||
|
||||
if (update.Type != UpdateType.Message
|
||||
&& update.Type != UpdateType.EditedMessage
|
||||
&& update.Type != UpdateType.CallbackQuery)
|
||||
if (sce.Handled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//Is this a bot command ?
|
||||
if (mr.IsFirstHandler && mr.IsBotCommand && bot.IsKnownBotCommand(mr.BotCommand))
|
||||
mr.Device = session;
|
||||
|
||||
var activeForm = session.ActiveForm;
|
||||
|
||||
//Pre Loading Event
|
||||
await activeForm.PreLoad(mr);
|
||||
|
||||
//Send Load event to controls
|
||||
await activeForm.LoadControls(mr);
|
||||
|
||||
//Loading Event
|
||||
await activeForm.Load(mr);
|
||||
|
||||
|
||||
//Is Attachment ? (Photo, Audio, Video, Contact, Location, Document) (Ignore Callback Queries)
|
||||
if (update.Type == UpdateType.Message)
|
||||
{
|
||||
if ((mr.MessageType == MessageType.Contact)
|
||||
| (mr.MessageType == MessageType.Document)
|
||||
| (mr.MessageType == MessageType.Location)
|
||||
| (mr.MessageType == MessageType.Photo)
|
||||
| (mr.MessageType == MessageType.Video)
|
||||
| (mr.MessageType == MessageType.Audio))
|
||||
{
|
||||
var sce = new BotCommandEventArgs(mr.BotCommand, mr.BotCommandParameters, mr.Message, session.DeviceId, session);
|
||||
await bot.OnBotCommand(sce);
|
||||
|
||||
if (sce.Handled)
|
||||
return;
|
||||
await activeForm.SentData(new DataResult(ur));
|
||||
}
|
||||
}
|
||||
|
||||
mr.Device = session;
|
||||
//Action Event
|
||||
if (!session.FormSwitched && mr.IsAction)
|
||||
{
|
||||
//Send Action event to controls
|
||||
await activeForm.ActionControls(mr);
|
||||
|
||||
var activeForm = session.ActiveForm;
|
||||
//Send Action event to form itself
|
||||
await activeForm.Action(mr);
|
||||
|
||||
//Pre Loading Event
|
||||
await activeForm.PreLoad(mr);
|
||||
|
||||
//Send Load event to controls
|
||||
await activeForm.LoadControls(mr);
|
||||
|
||||
//Loading Event
|
||||
await activeForm.Load(mr);
|
||||
|
||||
|
||||
//Is Attachment ? (Photo, Audio, Video, Contact, Location, Document) (Ignore Callback Queries)
|
||||
if (update.Type == UpdateType.Message)
|
||||
if (!mr.Handled)
|
||||
{
|
||||
if (mr.MessageType == MessageType.Contact
|
||||
| mr.MessageType == MessageType.Document
|
||||
| mr.MessageType == MessageType.Location
|
||||
| mr.MessageType == MessageType.Photo
|
||||
| mr.MessageType == MessageType.Video
|
||||
| mr.MessageType == MessageType.Audio)
|
||||
var uhc = new UnhandledCallEventArgs(ur.Message.Text, mr.RawData, session.DeviceId, mr.MessageId,
|
||||
ur.Message, session);
|
||||
OnUnhandledCall(uhc);
|
||||
|
||||
if (uhc.Handled)
|
||||
{
|
||||
await activeForm.SentData(new DataResult(ur));
|
||||
}
|
||||
}
|
||||
|
||||
//Action Event
|
||||
if (!session.FormSwitched && mr.IsAction)
|
||||
{
|
||||
//Send Action event to controls
|
||||
await activeForm.ActionControls(mr);
|
||||
|
||||
//Send Action event to form itself
|
||||
await activeForm.Action(mr);
|
||||
|
||||
if (!mr.Handled)
|
||||
{
|
||||
var uhc = new UnhandledCallEventArgs(ur.Message.Text, mr.RawData, session.DeviceId, mr.MessageId, ur.Message, session);
|
||||
OnUnhandledCall(uhc);
|
||||
|
||||
if (uhc.Handled)
|
||||
mr.Handled = true;
|
||||
if (!session.FormSwitched)
|
||||
{
|
||||
mr.Handled = true;
|
||||
if (!session.FormSwitched)
|
||||
{
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!session.FormSwitched)
|
||||
{
|
||||
//Render Event
|
||||
await activeForm.RenderControls(mr);
|
||||
|
||||
await activeForm.Render(mr);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Will be called if no form handeled this call
|
||||
/// </summary>
|
||||
public event EventHandler<UnhandledCallEventArgs> UnhandledCall
|
||||
if (!session.FormSwitched)
|
||||
{
|
||||
add => _events.AddHandler(EvUnhandledCall, value);
|
||||
remove => _events.RemoveHandler(EvUnhandledCall, value);
|
||||
}
|
||||
|
||||
public void OnUnhandledCall(UnhandledCallEventArgs e)
|
||||
{
|
||||
(_events[EvUnhandledCall] as EventHandler<UnhandledCallEventArgs>)?.Invoke(this, e);
|
||||
//Render Event
|
||||
await activeForm.RenderControls(mr);
|
||||
|
||||
await activeForm.Render(mr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Will be called if no form handeled this call
|
||||
/// </summary>
|
||||
public event EventHandler<UnhandledCallEventArgs> UnhandledCall
|
||||
{
|
||||
add => _events.AddHandler(EvUnhandledCall, value);
|
||||
remove => _events.RemoveHandler(EvUnhandledCall, value);
|
||||
}
|
||||
|
||||
public void OnUnhandledCall(UnhandledCallEventArgs e)
|
||||
{
|
||||
(_events[EvUnhandledCall] as EventHandler<UnhandledCallEventArgs>)?.Invoke(this, e);
|
||||
}
|
||||
}
|
||||
@@ -7,109 +7,109 @@ using TelegramBotBase.Base;
|
||||
using TelegramBotBase.Interfaces;
|
||||
using TelegramBotBase.Sessions;
|
||||
|
||||
namespace TelegramBotBase.MessageLoops
|
||||
namespace TelegramBotBase.MessageLoops;
|
||||
|
||||
/// <summary>
|
||||
/// This message loop reacts to all update types.
|
||||
/// </summary>
|
||||
public class FullMessageLoop : IMessageLoopFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// This message loop reacts to all update types.
|
||||
/// </summary>
|
||||
public class FullMessageLoop : IMessageLoopFactory
|
||||
private static readonly object EvUnhandledCall = new();
|
||||
|
||||
private readonly EventHandlerList _events = new();
|
||||
|
||||
public async Task MessageLoop(BotBase bot, DeviceSession session, UpdateResult ur, MessageResult mr)
|
||||
{
|
||||
private static readonly object EvUnhandledCall = new object();
|
||||
var update = ur.RawData;
|
||||
|
||||
private readonly EventHandlerList _events = new EventHandlerList();
|
||||
|
||||
public async Task MessageLoop(BotBase bot, DeviceSession session, UpdateResult ur, MessageResult mr)
|
||||
//Is this a bot command ?
|
||||
if (mr.IsFirstHandler && mr.IsBotCommand && bot.IsKnownBotCommand(mr.BotCommand))
|
||||
{
|
||||
var update = ur.RawData;
|
||||
var sce = new BotCommandEventArgs(mr.BotCommand, mr.BotCommandParameters, mr.Message, session.DeviceId,
|
||||
session);
|
||||
await bot.OnBotCommand(sce);
|
||||
|
||||
|
||||
//Is this a bot command ?
|
||||
if (mr.IsFirstHandler && mr.IsBotCommand && bot.IsKnownBotCommand(mr.BotCommand))
|
||||
if (sce.Handled)
|
||||
{
|
||||
var sce = new BotCommandEventArgs(mr.BotCommand, mr.BotCommandParameters, mr.Message, session.DeviceId, session);
|
||||
await bot.OnBotCommand(sce);
|
||||
|
||||
if (sce.Handled)
|
||||
return;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
mr.Device = session;
|
||||
mr.Device = session;
|
||||
|
||||
var activeForm = session.ActiveForm;
|
||||
var activeForm = session.ActiveForm;
|
||||
|
||||
//Pre Loading Event
|
||||
await activeForm.PreLoad(mr);
|
||||
//Pre Loading Event
|
||||
await activeForm.PreLoad(mr);
|
||||
|
||||
//Send Load event to controls
|
||||
await activeForm.LoadControls(mr);
|
||||
//Send Load event to controls
|
||||
await activeForm.LoadControls(mr);
|
||||
|
||||
//Loading Event
|
||||
await activeForm.Load(mr);
|
||||
//Loading Event
|
||||
await activeForm.Load(mr);
|
||||
|
||||
|
||||
//Is Attachment ? (Photo, Audio, Video, Contact, Location, Document) (Ignore Callback Queries)
|
||||
if (update.Type == UpdateType.Message)
|
||||
//Is Attachment ? (Photo, Audio, Video, Contact, Location, Document) (Ignore Callback Queries)
|
||||
if (update.Type == UpdateType.Message)
|
||||
{
|
||||
if ((mr.MessageType == MessageType.Contact)
|
||||
| (mr.MessageType == MessageType.Document)
|
||||
| (mr.MessageType == MessageType.Location)
|
||||
| (mr.MessageType == MessageType.Photo)
|
||||
| (mr.MessageType == MessageType.Video)
|
||||
| (mr.MessageType == MessageType.Audio))
|
||||
{
|
||||
if (mr.MessageType == MessageType.Contact
|
||||
| mr.MessageType == MessageType.Document
|
||||
| mr.MessageType == MessageType.Location
|
||||
| mr.MessageType == MessageType.Photo
|
||||
| mr.MessageType == MessageType.Video
|
||||
| mr.MessageType == MessageType.Audio)
|
||||
{
|
||||
await activeForm.SentData(new DataResult(ur));
|
||||
}
|
||||
await activeForm.SentData(new DataResult(ur));
|
||||
}
|
||||
}
|
||||
|
||||
//Action Event
|
||||
if (!session.FormSwitched && mr.IsAction)
|
||||
//Action Event
|
||||
if (!session.FormSwitched && mr.IsAction)
|
||||
{
|
||||
//Send Action event to controls
|
||||
await activeForm.ActionControls(mr);
|
||||
|
||||
//Send Action event to form itself
|
||||
await activeForm.Action(mr);
|
||||
|
||||
if (!mr.Handled)
|
||||
{
|
||||
//Send Action event to controls
|
||||
await activeForm.ActionControls(mr);
|
||||
var uhc = new UnhandledCallEventArgs(ur.Message.Text, mr.RawData, session.DeviceId, mr.MessageId,
|
||||
ur.Message, session);
|
||||
OnUnhandledCall(uhc);
|
||||
|
||||
//Send Action event to form itself
|
||||
await activeForm.Action(mr);
|
||||
|
||||
if (!mr.Handled)
|
||||
if (uhc.Handled)
|
||||
{
|
||||
var uhc = new UnhandledCallEventArgs(ur.Message.Text, mr.RawData, session.DeviceId, mr.MessageId, ur.Message, session);
|
||||
OnUnhandledCall(uhc);
|
||||
|
||||
if (uhc.Handled)
|
||||
mr.Handled = true;
|
||||
if (!session.FormSwitched)
|
||||
{
|
||||
mr.Handled = true;
|
||||
if (!session.FormSwitched)
|
||||
{
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!session.FormSwitched)
|
||||
{
|
||||
//Render Event
|
||||
await activeForm.RenderControls(mr);
|
||||
|
||||
await activeForm.Render(mr);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Will be called if no form handeled this call
|
||||
/// </summary>
|
||||
public event EventHandler<UnhandledCallEventArgs> UnhandledCall
|
||||
if (!session.FormSwitched)
|
||||
{
|
||||
add => _events.AddHandler(EvUnhandledCall, value);
|
||||
remove => _events.RemoveHandler(EvUnhandledCall, value);
|
||||
}
|
||||
|
||||
public void OnUnhandledCall(UnhandledCallEventArgs e)
|
||||
{
|
||||
(_events[EvUnhandledCall] as EventHandler<UnhandledCallEventArgs>)?.Invoke(this, e);
|
||||
//Render Event
|
||||
await activeForm.RenderControls(mr);
|
||||
|
||||
await activeForm.Render(mr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Will be called if no form handeled this call
|
||||
/// </summary>
|
||||
public event EventHandler<UnhandledCallEventArgs> UnhandledCall
|
||||
{
|
||||
add => _events.AddHandler(EvUnhandledCall, value);
|
||||
remove => _events.RemoveHandler(EvUnhandledCall, value);
|
||||
}
|
||||
|
||||
public void OnUnhandledCall(UnhandledCallEventArgs e)
|
||||
{
|
||||
(_events[EvUnhandledCall] as EventHandler<UnhandledCallEventArgs>)?.Invoke(this, e);
|
||||
}
|
||||
}
|
||||
@@ -6,44 +6,41 @@ using TelegramBotBase.Base;
|
||||
using TelegramBotBase.Interfaces;
|
||||
using TelegramBotBase.Sessions;
|
||||
|
||||
namespace TelegramBotBase.MessageLoops
|
||||
namespace TelegramBotBase.MessageLoops;
|
||||
|
||||
/// <summary>
|
||||
/// This is a minimal message loop which will react to all update types and just calling the Load method.
|
||||
/// </summary>
|
||||
public class MinimalMessageLoop : IMessageLoopFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// This is a minimal message loop which will react to all update types and just calling the Load method.
|
||||
/// </summary>
|
||||
public class MinimalMessageLoop : IMessageLoopFactory
|
||||
private static readonly object EvUnhandledCall = new();
|
||||
|
||||
private readonly EventHandlerList _events = new();
|
||||
|
||||
public async Task MessageLoop(BotBase bot, DeviceSession session, UpdateResult ur, MessageResult mr)
|
||||
{
|
||||
private static readonly object EvUnhandledCall = new object();
|
||||
|
||||
private readonly EventHandlerList _events = new EventHandlerList();
|
||||
|
||||
public async Task MessageLoop(BotBase bot, DeviceSession session, UpdateResult ur, MessageResult mr)
|
||||
{
|
||||
var update = ur.RawData;
|
||||
var update = ur.RawData;
|
||||
|
||||
|
||||
mr.Device = session;
|
||||
mr.Device = session;
|
||||
|
||||
var activeForm = session.ActiveForm;
|
||||
var activeForm = session.ActiveForm;
|
||||
|
||||
//Loading Event
|
||||
await activeForm.Load(mr);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Will be called if no form handeled this call
|
||||
/// </summary>
|
||||
public event EventHandler<UnhandledCallEventArgs> UnhandledCall
|
||||
{
|
||||
add => _events.AddHandler(EvUnhandledCall, value);
|
||||
remove => _events.RemoveHandler(EvUnhandledCall, value);
|
||||
}
|
||||
|
||||
public void OnUnhandledCall(UnhandledCallEventArgs e)
|
||||
{
|
||||
(_events[EvUnhandledCall] as EventHandler<UnhandledCallEventArgs>)?.Invoke(this, e);
|
||||
|
||||
}
|
||||
//Loading Event
|
||||
await activeForm.Load(mr);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Will be called if no form handeled this call
|
||||
/// </summary>
|
||||
public event EventHandler<UnhandledCallEventArgs> UnhandledCall
|
||||
{
|
||||
add => _events.AddHandler(EvUnhandledCall, value);
|
||||
remove => _events.RemoveHandler(EvUnhandledCall, value);
|
||||
}
|
||||
|
||||
public void OnUnhandledCall(UnhandledCallEventArgs e)
|
||||
{
|
||||
(_events[EvUnhandledCall] as EventHandler<UnhandledCallEventArgs>)?.Invoke(this, e);
|
||||
}
|
||||
}
|
||||
@@ -32,4 +32,4 @@ using System.Runtime.InteropServices;
|
||||
// übernehmen, indem Sie "*" eingeben:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("3.1.0.0")]
|
||||
[assembly: AssemblyFileVersion("3.1.0.0")]
|
||||
[assembly: AssemblyFileVersion("3.1.0.0")]
|
||||
+275
-267
@@ -11,330 +11,338 @@ using TelegramBotBase.Interfaces;
|
||||
using TelegramBotBase.Sessions;
|
||||
using TelegramBotBase.Tools;
|
||||
|
||||
namespace TelegramBotBase
|
||||
namespace TelegramBotBase;
|
||||
|
||||
/// <summary>
|
||||
/// Base class for managing all active sessions
|
||||
/// </summary>
|
||||
public class SessionBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for managing all active sessions
|
||||
/// </summary>
|
||||
public class SessionBase
|
||||
public SessionBase()
|
||||
{
|
||||
/// <summary>
|
||||
/// The Basic message client.
|
||||
/// </summary>
|
||||
public MessageClient Client { get; set; }
|
||||
SessionList = new Dictionary<long, DeviceSession>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A list of all active sessions.
|
||||
/// </summary>
|
||||
public Dictionary<long, DeviceSession> SessionList { get; set; }
|
||||
/// <summary>
|
||||
/// The Basic message client.
|
||||
/// </summary>
|
||||
public MessageClient Client { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A list of all active sessions.
|
||||
/// </summary>
|
||||
public Dictionary<long, DeviceSession> SessionList { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Reference to the Main BotBase instance for later use.
|
||||
/// </summary>
|
||||
public BotBase BotBase { get; set; }
|
||||
/// <summary>
|
||||
/// Reference to the Main BotBase instance for later use.
|
||||
/// </summary>
|
||||
public BotBase BotBase { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Get device session from Device/ChatId
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <returns></returns>
|
||||
public DeviceSession this[long key]
|
||||
{
|
||||
get => SessionList[key];
|
||||
set => SessionList[key] = value;
|
||||
}
|
||||
|
||||
public SessionBase()
|
||||
/// <summary>
|
||||
/// Get device session from Device/ChatId
|
||||
/// </summary>
|
||||
/// <param name="deviceId"></param>
|
||||
/// <returns></returns>
|
||||
public DeviceSession GetSession(long deviceId)
|
||||
{
|
||||
var ds = SessionList.FirstOrDefault(a => a.Key == deviceId).Value ?? null;
|
||||
return ds;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start a new session
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="deviceId"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<DeviceSession> StartSession(long deviceId)
|
||||
{
|
||||
var start = BotBase.StartFormFactory.CreateForm();
|
||||
|
||||
start.Client = Client;
|
||||
|
||||
var ds = new DeviceSession(deviceId, start);
|
||||
|
||||
start.Device = ds;
|
||||
await start.OnInit(new InitEventArgs());
|
||||
|
||||
await start.OnOpened(EventArgs.Empty);
|
||||
|
||||
this[deviceId] = ds;
|
||||
return ds;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// End session
|
||||
/// </summary>
|
||||
/// <param name="deviceId"></param>
|
||||
public void EndSession(long deviceId)
|
||||
{
|
||||
var d = this[deviceId];
|
||||
if (d != null)
|
||||
{
|
||||
SessionList = new Dictionary<long, DeviceSession>();
|
||||
SessionList.Remove(deviceId);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns all active User Sessions.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public List<DeviceSession> GetUserSessions()
|
||||
{
|
||||
return 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 SessionList.Where(a => a.Key < 0).Select(a => a.Value).ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads the previously saved states from the machine.
|
||||
/// </summary>
|
||||
public async void LoadSessionStates()
|
||||
{
|
||||
if (BotBase.StateMachine == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get device session from Device/ChatId
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <returns></returns>
|
||||
public DeviceSession this[long key]
|
||||
LoadSessionStates(BotBase.StateMachine);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Loads the previously saved states from the machine.
|
||||
/// </summary>
|
||||
public async void LoadSessionStates(IStateMachine statemachine)
|
||||
{
|
||||
if (statemachine == null)
|
||||
{
|
||||
get => SessionList[key];
|
||||
set => SessionList[key] = value;
|
||||
throw new ArgumentNullException("StateMachine",
|
||||
"No StateMachine defined. Please set one to property BotBase.StateMachine");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get device session from Device/ChatId
|
||||
/// </summary>
|
||||
/// <param name="deviceId"></param>
|
||||
/// <returns></returns>
|
||||
public DeviceSession GetSession(long deviceId)
|
||||
var container = statemachine.LoadFormStates();
|
||||
|
||||
foreach (var s in container.States)
|
||||
{
|
||||
var ds = SessionList.FirstOrDefault(a => a.Key == deviceId).Value ?? null;
|
||||
return ds;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start a new session
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="deviceId"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<DeviceSession> StartSession(long deviceId)
|
||||
{
|
||||
var start = BotBase.StartFormFactory.CreateForm();
|
||||
|
||||
start.Client = Client;
|
||||
|
||||
var ds = new DeviceSession(deviceId, start);
|
||||
|
||||
start.Device = ds;
|
||||
await start.OnInit(new InitEventArgs());
|
||||
|
||||
await start.OnOpened(EventArgs.Empty);
|
||||
|
||||
this[deviceId] = ds;
|
||||
return ds;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// End session
|
||||
/// </summary>
|
||||
/// <param name="deviceId"></param>
|
||||
public void EndSession(long deviceId)
|
||||
{
|
||||
var d = this[deviceId];
|
||||
if (d != null)
|
||||
var t = Type.GetType(s.QualifiedName);
|
||||
if (t == null || !t.IsSubclassOf(typeof(FormBase)))
|
||||
{
|
||||
SessionList.Remove(deviceId);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns all active User Sessions.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public List<DeviceSession> GetUserSessions()
|
||||
{
|
||||
return 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 SessionList.Where(a => a.Key < 0).Select(a => a.Value).ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads the previously saved states from the machine.
|
||||
/// </summary>
|
||||
public async void LoadSessionStates()
|
||||
{
|
||||
if (BotBase.StateMachine == null)
|
||||
{
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
|
||||
LoadSessionStates(BotBase.StateMachine);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Loads the previously saved states from the machine.
|
||||
/// </summary>
|
||||
public async void LoadSessionStates(IStateMachine statemachine)
|
||||
{
|
||||
if (statemachine == null)
|
||||
//Key already existing
|
||||
if (SessionList.ContainsKey(s.DeviceId))
|
||||
{
|
||||
throw new ArgumentNullException("StateMachine", "No StateMachine defined. Please set one to property BotBase.StateMachine");
|
||||
continue;
|
||||
}
|
||||
|
||||
var container = statemachine.LoadFormStates();
|
||||
|
||||
foreach (var s in container.States)
|
||||
//No default constructor, fallback
|
||||
if (!(t.GetConstructor(new Type[] { })?.Invoke(new object[] { }) is FormBase form))
|
||||
{
|
||||
var t = Type.GetType(s.QualifiedName);
|
||||
if (t == null || !t.IsSubclassOf(typeof(FormBase)))
|
||||
if (!statemachine.FallbackStateForm.IsSubclassOf(typeof(FormBase)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
//Key already existing
|
||||
if (SessionList.ContainsKey(s.DeviceId))
|
||||
form =
|
||||
statemachine.FallbackStateForm.GetConstructor(new Type[] { })
|
||||
?.Invoke(new object[] { }) as FormBase;
|
||||
|
||||
//Fallback failed, due missing default constructor
|
||||
if (form == null)
|
||||
{
|
||||
continue;
|
||||
|
||||
//No default constructor, fallback
|
||||
if (!(t.GetConstructor(new Type[] { })?.Invoke(new object[] { }) is FormBase form))
|
||||
{
|
||||
if (!statemachine.FallbackStateForm.IsSubclassOf(typeof(FormBase)))
|
||||
continue;
|
||||
|
||||
form = statemachine.FallbackStateForm.GetConstructor(new Type[] { })?.Invoke(new object[] { }) as FormBase;
|
||||
|
||||
//Fallback failed, due missing default constructor
|
||||
if (form == null)
|
||||
continue;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (s.Values != null && s.Values.Count > 0)
|
||||
if (s.Values != null && s.Values.Count > 0)
|
||||
{
|
||||
var properties = s.Values.Where(a => a.Key.StartsWith("$"));
|
||||
var fields = form.GetType()
|
||||
.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
|
||||
.Where(a => a.GetCustomAttributes(typeof(SaveState), true).Length != 0).ToList();
|
||||
|
||||
foreach (var p in properties)
|
||||
{
|
||||
var properties = s.Values.Where(a => a.Key.StartsWith("$"));
|
||||
var fields = form.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public | 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)
|
||||
{
|
||||
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;
|
||||
|
||||
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)
|
||||
{
|
||||
|
||||
Conversion.CustomConversionChecks(form, p, f);
|
||||
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
}
|
||||
f.SetValue(form, p.Value);
|
||||
}
|
||||
catch (ArgumentException)
|
||||
{
|
||||
Conversion.CustomConversionChecks(form, p, f);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
form.Client = Client;
|
||||
var device = new DeviceSession(s.DeviceId, form)
|
||||
form.Client = Client;
|
||||
var device = new DeviceSession(s.DeviceId, form)
|
||||
{
|
||||
ChatTitle = s.ChatTitle
|
||||
};
|
||||
|
||||
SessionList.Add(s.DeviceId, device);
|
||||
|
||||
//Is Subclass of IStateForm
|
||||
if (form is IStateForm iform)
|
||||
{
|
||||
var ls = new LoadStateEventArgs
|
||||
{
|
||||
ChatTitle = s.ChatTitle
|
||||
Values = s.Values
|
||||
};
|
||||
iform.LoadState(ls);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await form.OnInit(new InitEventArgs());
|
||||
|
||||
await form.OnOpened(EventArgs.Empty);
|
||||
}
|
||||
catch
|
||||
{
|
||||
//Skip on exception
|
||||
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 SessionList)
|
||||
{
|
||||
if (s.Value == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var form = s.Value.ActiveForm;
|
||||
|
||||
try
|
||||
{
|
||||
var se = new StateEntry
|
||||
{
|
||||
DeviceId = s.Key,
|
||||
ChatTitle = s.Value.GetChatTitle(),
|
||||
FormUri = form.GetType().FullName,
|
||||
QualifiedName = form.GetType().AssemblyQualifiedName
|
||||
};
|
||||
|
||||
SessionList.Add(s.DeviceId, device);
|
||||
//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
|
||||
if (form is IStateForm iform)
|
||||
{
|
||||
var ls = new LoadStateEventArgs
|
||||
{
|
||||
Values = s.Values
|
||||
};
|
||||
iform.LoadState(ls);
|
||||
//Loading Session states
|
||||
var ssea = new SaveStateEventArgs();
|
||||
iform.SaveState(ssea);
|
||||
|
||||
se.Values = ssea.Values;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await form.OnInit(new InitEventArgs());
|
||||
//Search for public properties with SaveState attribute
|
||||
var fields = form.GetType()
|
||||
.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
|
||||
.Where(a => a.GetCustomAttributes(typeof(SaveState), true).Length != 0).ToList();
|
||||
|
||||
await form.OnOpened(EventArgs.Empty);
|
||||
}
|
||||
catch
|
||||
foreach (var f in fields)
|
||||
{
|
||||
//Skip on exception
|
||||
SessionList.Remove(s.DeviceId);
|
||||
var val = f.GetValue(form);
|
||||
|
||||
se.Values.Add("$" + f.Name, val);
|
||||
}
|
||||
|
||||
states.Add(se);
|
||||
}
|
||||
catch
|
||||
{
|
||||
//Continue on error (skip this form)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Saves all open states into the machine.
|
||||
/// </summary>
|
||||
public void SaveSessionStates(IStateMachine statemachine)
|
||||
var sc = new StateContainer
|
||||
{
|
||||
if (statemachine == null)
|
||||
{
|
||||
throw new ArgumentNullException("StateMachine", "No StateMachine defined. Please set one to property BotBase.StateMachine");
|
||||
}
|
||||
States = states
|
||||
};
|
||||
|
||||
var states = new List<StateEntry>();
|
||||
statemachine.SaveFormStates(new SaveStatesEventArgs(sc));
|
||||
}
|
||||
|
||||
foreach (var s in SessionList)
|
||||
{
|
||||
if (s.Value == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var form = s.Value.ActiveForm;
|
||||
|
||||
try
|
||||
{
|
||||
var se = new StateEntry
|
||||
{
|
||||
DeviceId = s.Key,
|
||||
ChatTitle = s.Value.GetChatTitle(),
|
||||
FormUri = form.GetType().FullName,
|
||||
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
|
||||
if (form is IStateForm iform)
|
||||
{
|
||||
//Loading Session states
|
||||
var ssea = new SaveStateEventArgs();
|
||||
iform.SaveState(ssea);
|
||||
|
||||
se.Values = ssea.Values;
|
||||
}
|
||||
|
||||
//Search for public properties with SaveState attribute
|
||||
var fields = form.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public | 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)
|
||||
}
|
||||
}
|
||||
|
||||
var sc = new StateContainer
|
||||
{
|
||||
States = states
|
||||
};
|
||||
|
||||
statemachine.SaveFormStates(new SaveStatesEventArgs(sc));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves all open states into the machine.
|
||||
/// </summary>
|
||||
public void SaveSessionStates()
|
||||
/// <summary>
|
||||
/// Saves all open states into the machine.
|
||||
/// </summary>
|
||||
public void SaveSessionStates()
|
||||
{
|
||||
if (BotBase.StateMachine == null)
|
||||
{
|
||||
if (BotBase.StateMachine == null)
|
||||
return;
|
||||
|
||||
|
||||
SaveSessionStates(BotBase.StateMachine);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
SaveSessionStates(BotBase.StateMachine);
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -6,87 +6,87 @@ using TelegramBotBase.Base;
|
||||
using TelegramBotBase.Form;
|
||||
using TelegramBotBase.Interfaces;
|
||||
|
||||
namespace TelegramBotBase.States
|
||||
namespace TelegramBotBase.States;
|
||||
|
||||
/// <summary>
|
||||
/// Is used for all complex data types. Use if other default machines are not working.
|
||||
/// </summary>
|
||||
public class JsonStateMachine : IStateMachine
|
||||
{
|
||||
/// <summary>
|
||||
/// Is used for all complex data types. Use if other default machines are not working.
|
||||
/// Will initialize the state machine.
|
||||
/// </summary>
|
||||
public class JsonStateMachine : IStateMachine
|
||||
/// <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)
|
||||
{
|
||||
public string FilePath { get; set; }
|
||||
FallbackStateForm = fallbackStateForm;
|
||||
|
||||
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 (FallbackStateForm != null && !FallbackStateForm.IsSubclassOf(typeof(FormBase)))
|
||||
{
|
||||
FallbackStateForm = fallbackStateForm;
|
||||
|
||||
if (FallbackStateForm != null && !FallbackStateForm.IsSubclassOf(typeof(FormBase)))
|
||||
{
|
||||
throw new ArgumentException("FallbackStateForm is not a subclass of FormBase");
|
||||
}
|
||||
|
||||
FilePath = file ?? throw new ArgumentNullException(nameof(file));
|
||||
Overwrite = overwrite;
|
||||
throw new ArgumentException("FallbackStateForm is not a subclass of FormBase");
|
||||
}
|
||||
|
||||
public StateContainer LoadFormStates()
|
||||
FilePath = file ?? throw new ArgumentNullException(nameof(file));
|
||||
Overwrite = overwrite;
|
||||
}
|
||||
|
||||
public string FilePath { get; set; }
|
||||
|
||||
public bool Overwrite { get; set; }
|
||||
|
||||
public Type FallbackStateForm { get; }
|
||||
|
||||
public StateContainer LoadFormStates()
|
||||
{
|
||||
try
|
||||
{
|
||||
try
|
||||
var content = File.ReadAllText(FilePath);
|
||||
|
||||
var sc = JsonConvert.DeserializeObject<StateContainer>(content, new JsonSerializerSettings
|
||||
{
|
||||
var content = File.ReadAllText(FilePath);
|
||||
TypeNameHandling = TypeNameHandling.All,
|
||||
TypeNameAssemblyFormatHandling = TypeNameAssemblyFormatHandling.Simple
|
||||
});
|
||||
|
||||
var sc = JsonConvert.DeserializeObject<StateContainer>(content, new JsonSerializerSettings
|
||||
{
|
||||
TypeNameHandling = TypeNameHandling.All,
|
||||
TypeNameAssemblyFormatHandling = TypeNameAssemblyFormatHandling.Simple
|
||||
});
|
||||
|
||||
return sc;
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
return new StateContainer();
|
||||
return sc;
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
public void SaveFormStates(SaveStatesEventArgs e)
|
||||
return new StateContainer();
|
||||
}
|
||||
|
||||
public void SaveFormStates(SaveStatesEventArgs e)
|
||||
{
|
||||
if (File.Exists(FilePath))
|
||||
{
|
||||
if (File.Exists(FilePath))
|
||||
if (!Overwrite)
|
||||
{
|
||||
if (!Overwrite)
|
||||
{
|
||||
throw new Exception("File exists already.");
|
||||
}
|
||||
|
||||
File.Delete(FilePath);
|
||||
throw new Exception("File exists already.");
|
||||
}
|
||||
|
||||
try
|
||||
File.Delete(FilePath);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var content = JsonConvert.SerializeObject(e.States, Formatting.Indented, new JsonSerializerSettings
|
||||
{
|
||||
var content = JsonConvert.SerializeObject(e.States, Formatting.Indented, new JsonSerializerSettings
|
||||
{
|
||||
TypeNameHandling = TypeNameHandling.All,
|
||||
TypeNameAssemblyFormatHandling = TypeNameAssemblyFormatHandling.Simple
|
||||
});
|
||||
|
||||
File.WriteAllText(FilePath, content);
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
}
|
||||
TypeNameHandling = TypeNameHandling.All,
|
||||
TypeNameAssemblyFormatHandling = TypeNameAssemblyFormatHandling.Simple
|
||||
});
|
||||
|
||||
File.WriteAllText(FilePath, content);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user