From f7578384e6dba372600c48cfb15db2e401844d93 Mon Sep 17 00:00:00 2001 From: FlorianDahn Date: Sun, 10 Sep 2023 16:58:12 +0200 Subject: [PATCH] Adding new example project for Inline- and ReplyMarkup combination --- .../Baseclasses/MultipleChoiceForm.cs | 86 ++++++++++++++++++ .../Forms/StartForm.cs | 67 ++++++++++++++ .../Forms/Steps/MainForm.cs | 90 +++++++++++++++++++ .../Forms/Steps/SecondForm.cs | 89 ++++++++++++++++++ .../Forms/Steps/Summary.cs | 83 +++++++++++++++++ .../Forms/Steps/ThirdForm.cs | 89 ++++++++++++++++++ .../InlineAndReplyCombination.csproj | 14 +++ .../Model/UserDetails.cs | 20 +++++ Examples/InlineAndReplyCombination/Program.cs | 41 +++++++++ README.md | 6 +- TelegramBotFramework.sln | 9 +- 11 files changed, 592 insertions(+), 2 deletions(-) create mode 100644 Examples/InlineAndReplyCombination/Baseclasses/MultipleChoiceForm.cs create mode 100644 Examples/InlineAndReplyCombination/Forms/StartForm.cs create mode 100644 Examples/InlineAndReplyCombination/Forms/Steps/MainForm.cs create mode 100644 Examples/InlineAndReplyCombination/Forms/Steps/SecondForm.cs create mode 100644 Examples/InlineAndReplyCombination/Forms/Steps/Summary.cs create mode 100644 Examples/InlineAndReplyCombination/Forms/Steps/ThirdForm.cs create mode 100644 Examples/InlineAndReplyCombination/InlineAndReplyCombination.csproj create mode 100644 Examples/InlineAndReplyCombination/Model/UserDetails.cs create mode 100644 Examples/InlineAndReplyCombination/Program.cs diff --git a/Examples/InlineAndReplyCombination/Baseclasses/MultipleChoiceForm.cs b/Examples/InlineAndReplyCombination/Baseclasses/MultipleChoiceForm.cs new file mode 100644 index 0000000..ace5620 --- /dev/null +++ b/Examples/InlineAndReplyCombination/Baseclasses/MultipleChoiceForm.cs @@ -0,0 +1,86 @@ +using InlineAndReplyCombination.Forms; +using InlineAndReplyCombination.Model; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using TelegramBotBase.Attributes; +using TelegramBotBase.Controls.Hybrid; +using TelegramBotBase.Form; + +namespace InlineAndReplyCombination.Baseclasses +{ + public class MultipleChoiceForm : AutoCleanForm + { + [SaveState] + public UserDetails UserDetails { get; set; } + + ButtonGrid ReplyButtonGrid; + + public String ReplyButtonTitle { get; set; } = "Restart"; + + protected int CurrentStep = 1; + protected int MaxSteps = 3; + + public MultipleChoiceForm() + { + this.Init += MultipleChoiceForm_Init; + } + + private async Task MultipleChoiceForm_Init(object sender, TelegramBotBase.Args.InitEventArgs e) + { + //Reply keyboard + var bf = new ButtonForm(); + + bf.AddButtonRow(ReplyButtonTitle, "replyButtonID"); + + ReplyButtonGrid = new ButtonGrid(bf); + + ReplyButtonGrid.Title = $"Step {CurrentStep} / {MaxSteps}"; + ReplyButtonGrid.KeyboardType = TelegramBotBase.Enums.EKeyboardType.ReplyKeyboard; + + ReplyButtonGrid.ButtonClicked += ReplyButtonGrid_ButtonClicked; + + AddControl(ReplyButtonGrid); + } + + + private async Task ReplyButtonGrid_ButtonClicked(object sender, TelegramBotBase.Args.ButtonClickedEventArgs e) + { + if (e.Button == null) + return; + + switch (e.Button.Value) + { + case "replyButtonID": + + await PressReplyButton(); + + + break; + + } + + } + + + public virtual Task PressReplyButton() + { + return Task.CompletedTask; + } + + public override Task NavigateTo(FormBase newForm, params object[] args) + { + //Move user details over to navigating form + if (newForm is MultipleChoiceForm mcf) + { + mcf.UserDetails = UserDetails; + } + + return base.NavigateTo(newForm, args); + } + + + } +} diff --git a/Examples/InlineAndReplyCombination/Forms/StartForm.cs b/Examples/InlineAndReplyCombination/Forms/StartForm.cs new file mode 100644 index 0000000..34bf6c0 --- /dev/null +++ b/Examples/InlineAndReplyCombination/Forms/StartForm.cs @@ -0,0 +1,67 @@ +using InlineAndReplyCombination.Baseclasses; +using InlineAndReplyCombination.Forms.Steps; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using TelegramBotBase.Base; +using TelegramBotBase.Controls.Hybrid; +using TelegramBotBase.Form; + +namespace InlineAndReplyCombination.Forms +{ + public class StartForm : AutoCleanForm + { + ButtonGrid buttonGrid; + + public StartForm() + { + this.Init += StartForm_Init; + + } + + private async Task StartForm_Init(object sender, TelegramBotBase.Args.InitEventArgs e) + { + var bf = new ButtonForm(); + + bf.AddButtonRow("Start registration", "start"); + + buttonGrid = new ButtonGrid(bf); + + buttonGrid.Title = "Welcome to The InlineAndReplyCombination Bot!"; + buttonGrid.ButtonClicked += ButtonGrid_ButtonClicked; + buttonGrid.KeyboardType = TelegramBotBase.Enums.EKeyboardType.ReplyKeyboard; + + AddControl(buttonGrid); + + } + + private async Task ButtonGrid_ButtonClicked(object sender, TelegramBotBase.Args.ButtonClickedEventArgs e) + { + if(e.Button == null) + { + return; + } + + + switch(e.Button.Value) + { + case "start": + + var mf = new MainForm(); + + mf.UserDetails = new Model.UserDetails(); + + await NavigateTo(mf); + + break; + + } + + + } + + + } +} diff --git a/Examples/InlineAndReplyCombination/Forms/Steps/MainForm.cs b/Examples/InlineAndReplyCombination/Forms/Steps/MainForm.cs new file mode 100644 index 0000000..c9e5220 --- /dev/null +++ b/Examples/InlineAndReplyCombination/Forms/Steps/MainForm.cs @@ -0,0 +1,90 @@ +using InlineAndReplyCombination.Baseclasses; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Numerics; +using System.Text; +using System.Threading.Tasks; +using Telegram.Bot.Types; +using TelegramBotBase.Base; +using TelegramBotBase.Controls.Hybrid; +using TelegramBotBase.Form; + +namespace InlineAndReplyCombination.Forms.Steps +{ + public class MainForm : MultipleChoiceForm + { + + ButtonGrid InlineButtonGrid; + + public static List> AllowedInlineInputs = null; + + static MainForm() + { + AllowedInlineInputs = new List>() + { + new("< 18", "<18"), + new("18 to 25", "18t25"), + new("25 to 35", "25t35"), + new("35 to 50", "35t50"), + new("over 50", "o50") + }; + + } + + public MainForm() + { + + Init += MainForm_Init; + + ReplyButtonTitle = "Start over"; + CurrentStep = 1; + } + + private async Task MainForm_Init(object sender, TelegramBotBase.Args.InitEventArgs e) + { + + //Inline Keyboard + var bf_ages = new ButtonForm(); + + //Add all options in a single column + bf_ages.AddSplitted(AllowedInlineInputs.Select(a => new ButtonBase(a.Item1, a.Item2)), 1); + + bf_ages.AddButtonRow("Some invalid input", "Invalid"); + + InlineButtonGrid = new ButtonGrid(bf_ages); + InlineButtonGrid.ConfirmationText = "Thank you"; + InlineButtonGrid.Title = "Please choose your age:"; + InlineButtonGrid.ButtonClicked += InlineButtonGrid_ButtonClicked; + + InlineButtonGrid.KeyboardType = TelegramBotBase.Enums.EKeyboardType.InlineKeyBoard; + + AddControl(InlineButtonGrid); + + } + + private async Task InlineButtonGrid_ButtonClicked(object sender, TelegramBotBase.Args.ButtonClickedEventArgs e) + { + //Not found + if (!AllowedInlineInputs.Any(a => a.Item2 == e.Button.Value)) + { + await Device.Send("Invalid input!"); + return; + } + + this.UserDetails.AgeRange = e.Button?.Value ?? "unknown"; + + var sf = new SecondForm(); + + await NavigateTo(sf); + } + + + public override async Task PressReplyButton() + { + var sf = new StartForm(); + + await NavigateTo(sf); + } + } +} diff --git a/Examples/InlineAndReplyCombination/Forms/Steps/SecondForm.cs b/Examples/InlineAndReplyCombination/Forms/Steps/SecondForm.cs new file mode 100644 index 0000000..862f84e --- /dev/null +++ b/Examples/InlineAndReplyCombination/Forms/Steps/SecondForm.cs @@ -0,0 +1,89 @@ +using InlineAndReplyCombination.Baseclasses; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Numerics; +using System.Text; +using System.Threading.Tasks; +using Telegram.Bot.Types; +using TelegramBotBase.Base; +using TelegramBotBase.Controls.Hybrid; +using TelegramBotBase.Form; + +namespace InlineAndReplyCombination.Forms.Steps +{ + public class SecondForm : MultipleChoiceForm + { + + ButtonGrid InlineButtonGrid; + + public static List> AllowedInlineInputs = null; + + static SecondForm() + { + AllowedInlineInputs = new List>() + { + new("Green", "green"), + new("Yellow", "yellow"), + new("Red", "red"), + new("Purple", "purple"), + new("Black", "black"), + new("Gold", "gold") + }; + } + + public SecondForm() + { + + Init += SecondForm_Init; + + ReplyButtonTitle = "Go back"; + CurrentStep = 2; + + } + + private async Task SecondForm_Init(object sender, TelegramBotBase.Args.InitEventArgs e) + { + + //Inline Keyboard + var bf_ages = new ButtonForm(); + + //Add all options in a single column + bf_ages.AddSplitted(AllowedInlineInputs.Select(a => new ButtonBase(a.Item1, a.Item2)), 1); + + InlineButtonGrid = new ButtonGrid(bf_ages); + InlineButtonGrid.ConfirmationText = "Thank you"; + InlineButtonGrid.Title = "Please choose your favourite color:"; + InlineButtonGrid.ButtonClicked += InlineButtonGrid_ButtonClicked; + + InlineButtonGrid.KeyboardType = TelegramBotBase.Enums.EKeyboardType.InlineKeyBoard; + + AddControl(InlineButtonGrid); + + } + + private async Task InlineButtonGrid_ButtonClicked(object sender, TelegramBotBase.Args.ButtonClickedEventArgs e) + { + //Not found + if (!AllowedInlineInputs.Any(a => a.Item2 == e.Button.Value)) + { + await Device.Send("Invalid input!"); + return; + } + + this.UserDetails.FavouriteColor = e.Button?.Value ?? "unknown"; + + var tf = new ThirdForm(); + + await NavigateTo(tf); + } + + + public override async Task PressReplyButton() + { + var mf = new MainForm(); + + await NavigateTo(mf); + } + } +} diff --git a/Examples/InlineAndReplyCombination/Forms/Steps/Summary.cs b/Examples/InlineAndReplyCombination/Forms/Steps/Summary.cs new file mode 100644 index 0000000..9a601cc --- /dev/null +++ b/Examples/InlineAndReplyCombination/Forms/Steps/Summary.cs @@ -0,0 +1,83 @@ +using InlineAndReplyCombination.Model; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using TelegramBotBase.Attributes; +using TelegramBotBase.Base; +using TelegramBotBase.Controls.Hybrid; +using TelegramBotBase.Form; + +namespace InlineAndReplyCombination.Forms.Steps +{ + public class Summary : AutoCleanForm + { + [SaveState] + public UserDetails UserDetails { get; set; } + + ButtonGrid ReplyButtonGrid { get; set; } + + public Summary() + { + Init += Summary_Init; + + } + + private async Task Summary_Init(object sender, TelegramBotBase.Args.InitEventArgs e) + { + var bf = new ButtonForm(); + + bf.AddButtonRow("Go back", "back"); + bf.AddButtonRow("Return to Start", "start"); + + + + ReplyButtonGrid = new ButtonGrid(bf); + ReplyButtonGrid.Title = "Thank you for your time!"; + ReplyButtonGrid.ButtonClicked += ReplyButtonGrid_ButtonClicked; + + AddControl(ReplyButtonGrid); + + } + + public override async Task Load(MessageResult message) + { + + if (UserDetails == null) + { + var sf = new StartForm(); + await NavigateTo(sf); + return; + } + + await Device.Send($"Your inputs are:\r\n\r\nYour age: {UserDetails.AgeRange}\r\nYour favourite color: {UserDetails.FavouriteColor}\r\nYour favourite city: {UserDetails.FavouriteCity}"); + } + + private async Task ReplyButtonGrid_ButtonClicked(object sender, TelegramBotBase.Args.ButtonClickedEventArgs e) + { + switch (e.Button.Value ?? "") + { + case "start": + + var sf = new StartForm(); + + await NavigateTo(sf); + + break; + + case "back": + + var tf = new ThirdForm(); + + tf.UserDetails = UserDetails; + + await NavigateTo(tf); + + break; + + } + + } + } +} diff --git a/Examples/InlineAndReplyCombination/Forms/Steps/ThirdForm.cs b/Examples/InlineAndReplyCombination/Forms/Steps/ThirdForm.cs new file mode 100644 index 0000000..5382db7 --- /dev/null +++ b/Examples/InlineAndReplyCombination/Forms/Steps/ThirdForm.cs @@ -0,0 +1,89 @@ +using InlineAndReplyCombination.Baseclasses; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Numerics; +using System.Text; +using System.Threading.Tasks; +using Telegram.Bot.Types; +using TelegramBotBase.Base; +using TelegramBotBase.Controls.Hybrid; +using TelegramBotBase.Form; + +namespace InlineAndReplyCombination.Forms.Steps +{ + public class ThirdForm : MultipleChoiceForm + { + + ButtonGrid InlineButtonGrid; + + public static List> AllowedInlineInputs = null; + + static ThirdForm() + { + AllowedInlineInputs = new List>() + { + new("Berlin", "Berlin"), + new("Vienna", "Vienna"), + new("Rome", "Rome"), + new("London", "London"), + new("Moscow", "Moscow"), + new("Bukarest", "Bukarest") + }; + } + + public ThirdForm() + { + Init += SecondForm_Init; + + ReplyButtonTitle = "Go back"; + CurrentStep = 3; + + } + + private async Task SecondForm_Init(object sender, TelegramBotBase.Args.InitEventArgs e) + { + + //Inline Keyboard + var bf_ages = new ButtonForm(); + + //Add all options in a single column + bf_ages.AddSplitted(AllowedInlineInputs.Select(a => new ButtonBase(a.Item1, a.Item2)), 1); + + InlineButtonGrid = new ButtonGrid(bf_ages); + InlineButtonGrid.ConfirmationText = "Thank you"; + InlineButtonGrid.Title = "Please choose your favourite city:"; + InlineButtonGrid.ButtonClicked += InlineButtonGrid_ButtonClicked; + + InlineButtonGrid.KeyboardType = TelegramBotBase.Enums.EKeyboardType.InlineKeyBoard; + + AddControl(InlineButtonGrid); + + } + + private async Task InlineButtonGrid_ButtonClicked(object sender, TelegramBotBase.Args.ButtonClickedEventArgs e) + { + //Not found + if (!AllowedInlineInputs.Any(a => a.Item2 == e.Button.Value)) + { + await Device.Send("Invalid input!"); + return; + } + + this.UserDetails.FavouriteCity = e.Button?.Value ?? "unknown"; + + var sum = new Summary(); + sum.UserDetails = this.UserDetails; + await NavigateTo(sum); + + } + + + public override async Task PressReplyButton() + { + var sf = new SecondForm(); + + await NavigateTo(sf); + } + } +} diff --git a/Examples/InlineAndReplyCombination/InlineAndReplyCombination.csproj b/Examples/InlineAndReplyCombination/InlineAndReplyCombination.csproj new file mode 100644 index 0000000..352fe2f --- /dev/null +++ b/Examples/InlineAndReplyCombination/InlineAndReplyCombination.csproj @@ -0,0 +1,14 @@ + + + + Exe + net6.0 + enable + enable + + + + + + + diff --git a/Examples/InlineAndReplyCombination/Model/UserDetails.cs b/Examples/InlineAndReplyCombination/Model/UserDetails.cs new file mode 100644 index 0000000..a3b410e --- /dev/null +++ b/Examples/InlineAndReplyCombination/Model/UserDetails.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace InlineAndReplyCombination.Model +{ + [DebuggerDisplay("{AgeRange}, {FavouriteColor}, {FavouriteCity}")] + public class UserDetails + { + public String AgeRange { get; set; } + + public String FavouriteColor { get; set; } + + public String FavouriteCity { get; set; } + + } +} diff --git a/Examples/InlineAndReplyCombination/Program.cs b/Examples/InlineAndReplyCombination/Program.cs new file mode 100644 index 0000000..5e4e4fe --- /dev/null +++ b/Examples/InlineAndReplyCombination/Program.cs @@ -0,0 +1,41 @@ +using InlineAndReplyCombination.Forms; +using TelegramBotBase; +using TelegramBotBase.Builder; + +namespace InlineAndReplyCombination +{ + internal class Program + { + public static BotBase BotBaseInstance { get; private set; } + + static async Task Main(string[] args) + { + + + BotBaseInstance = BotBaseBuilder.Create() + .WithAPIKey(Environment.GetEnvironmentVariable("API_KEY") ?? + throw new Exception("API_KEY is not set")) + .DefaultMessageLoop() + .WithStartForm() + .NoProxy() + .DefaultCommands() + .UseJSON(Path.Combine(Directory.GetCurrentDirectory(), "states.json")) + .UseEnglish() + .Build(); + + + + await BotBaseInstance.UploadBotCommands(); + + + await BotBaseInstance.Start(); + + Console.WriteLine("Telegram Bot started"); + + Console.ReadLine(); + + + await BotBaseInstance.Stop(); + } + } +} \ No newline at end of file diff --git a/README.md b/README.md index 4239e84..cf3022c 100644 --- a/README.md +++ b/README.md @@ -1035,4 +1035,8 @@ method of BotBase. Having already a web application and want to add a TelegramBot side-by-side with it running ? Here is an example how you could do it. -- [Examples/BotAndWebApplication](Examples/BotAndWebApplication) \ No newline at end of file +- [Examples/BotAndWebApplication](Examples/BotAndWebApplication) + +Want to use Inline- and ReplyMarkup at the same time ? Here is an example how you can do that: + +- [Examples/InlineAndReplyCombination](Examples/InlineAndReplyCombination) \ No newline at end of file diff --git a/TelegramBotFramework.sln b/TelegramBotFramework.sln index 4a5f86b..885b8a0 100644 --- a/TelegramBotFramework.sln +++ b/TelegramBotFramework.sln @@ -28,7 +28,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TelegramBotBase.Extensions. EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EFCoreBot", "Examples\EFCoreBot\EFCoreBot.csproj", "{261BED47-0404-4A9A-86FC-047DE42A7D25}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BotAndWebApplication", "Examples\BotAndWebApplication\BotAndWebApplication.csproj", "{52EA3201-02E8-46F5-87C4-B4752C8A815C}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BotAndWebApplication", "Examples\BotAndWebApplication\BotAndWebApplication.csproj", "{52EA3201-02E8-46F5-87C4-B4752C8A815C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InlineAndReplyCombination", "Examples\InlineAndReplyCombination\InlineAndReplyCombination.csproj", "{067E8EBE-F90A-4AFF-A0FF-20578216486E}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -72,6 +74,10 @@ Global {52EA3201-02E8-46F5-87C4-B4752C8A815C}.Debug|Any CPU.Build.0 = Debug|Any CPU {52EA3201-02E8-46F5-87C4-B4752C8A815C}.Release|Any CPU.ActiveCfg = Release|Any CPU {52EA3201-02E8-46F5-87C4-B4752C8A815C}.Release|Any CPU.Build.0 = Release|Any CPU + {067E8EBE-F90A-4AFF-A0FF-20578216486E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {067E8EBE-F90A-4AFF-A0FF-20578216486E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {067E8EBE-F90A-4AFF-A0FF-20578216486E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {067E8EBE-F90A-4AFF-A0FF-20578216486E}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -84,6 +90,7 @@ Global {889B170E-32E9-4F26-BB04-8D06EA367857} = {E3193182-6FDA-4FA3-AD26-A487291E7681} {261BED47-0404-4A9A-86FC-047DE42A7D25} = {BFA71E3F-31C0-4FC1-A320-4DCF704768C5} {52EA3201-02E8-46F5-87C4-B4752C8A815C} = {BFA71E3F-31C0-4FC1-A320-4DCF704768C5} + {067E8EBE-F90A-4AFF-A0FF-20578216486E} = {BFA71E3F-31C0-4FC1-A320-4DCF704768C5} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {59CB40E1-9FA7-4867-A56F-4F418286F057}