From 09c9ce4941693df318d267af62b8df0c8f8c44c8 Mon Sep 17 00:00:00 2001 From: "Vyacheslav N. Boyko" Date: Wed, 21 Feb 2018 16:13:54 +0300 Subject: [PATCH] simple multipage menu --- .gitignore | 1 + README.md | 131 ++++++++++++++- pom.xml | 47 ++++++ .../ru/bvn13/examples/bot/Application.java | 27 ++++ .../java/ru/bvn13/examples/bot/MenuBot.java | 149 ++++++++++++++++++ .../accessories/InlineKeyboardBuilder.java | 75 +++++++++ .../ru/bvn13/examples/bot/menu/MenuItem.java | 32 ++++ .../bvn13/examples/bot/menu/MenuManager.java | 115 ++++++++++++++ 8 files changed, 576 insertions(+), 1 deletion(-) create mode 100644 .gitignore create mode 100644 pom.xml create mode 100644 src/main/java/ru/bvn13/examples/bot/Application.java create mode 100644 src/main/java/ru/bvn13/examples/bot/MenuBot.java create mode 100644 src/main/java/ru/bvn13/examples/bot/accessories/InlineKeyboardBuilder.java create mode 100644 src/main/java/ru/bvn13/examples/bot/menu/MenuItem.java create mode 100644 src/main/java/ru/bvn13/examples/bot/menu/MenuManager.java diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..485dee6 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.idea diff --git a/README.md b/README.md index cbd7beb..a3c5d31 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,131 @@ -# TelegramInlineMultipageMenu +# Telegram Inline Multipage Menu + Multipage inline menu for Telegram Bots API + +_powered with [rubenlagus/TelegramBots API](https://github.com/rubenlagus/TelegramBots)_ + + +Create our own dynamical menu like this: + +![](https://bvn13.tk/files/81) ![](https://bvn13.tk/files/82) ![](https://bvn13.tk/files/83) ![](https://bvn13.tk/files/84) + + +## Create your menu + +```java +public class MenuBot extends TelegramLongPollingBot { + + private MenuManager menuManager = new MenuManager(); + + //... +} +``` + + +## Init the menu + +```java + + //... + + public void init() { + menuManager.setColumnsCount(2); + + menuManager.addMenuItem("Action 1", "action 1"); + menuManager.addMenuItem("Action 2", "action 2"); + menuManager.addMenuItem("Action 3", "action 3"); + menuManager.addMenuItem("Action 4", "action 4"); + menuManager.addMenuItem("Action 5", "action 5"); + menuManager.addMenuItem("Action 6", "action 6"); + menuManager.addMenuItem("Action 7", "action 7"); + menuManager.addMenuItem("Action 8", "action 8"); + menuManager.addMenuItem("Action 9", "action 9"); + menuManager.addMenuItem("Action 10", "action 10"); + menuManager.addMenuItem("Action 11", "action 11"); + menuManager.addMenuItem("Action 12", "action 12"); + menuManager.addMenuItem("Action 13", "action 13"); + menuManager.addMenuItem("Action 14", "action 14"); + menuManager.addMenuItem("Action 15", "action 15"); + menuManager.addMenuItem("Action 16", "action 16"); + menuManager.addMenuItem("Action 17", "action 17"); + menuManager.addMenuItem("Action 18", "action 18"); + menuManager.addMenuItem("Action 19", "action 19"); + menuManager.addMenuItem("Action 20", "action 20"); + + menuManager.init(); + } + + //... + +``` + + +## Render the menu + +```java +public void onUpdateReceived(Update update) { + + // We check if the update has a message and the message has text + if (update.hasMessage() && update.getMessage().hasText()) { + + if (update.getMessage().getText().equals("/menu")) { + long chatId = update.getMessage().getChatId(); + + // lets render the menu + InlineKeyboardBuilder builder = menuManager.createMenuForPage(0, true); + + builder.setChatId(chatId).setText("Choose action:"); + SendMessage message = builder.build(); + + try { + // Send the message + execute(message); + } catch (TelegramApiException e) { + e.printStackTrace(); + } + + } else { + + } + + } +} +``` + + +## Don't forget for acting on page switching + +```java +public void onUpdateReceived(Update update) { + if (update.hasCallbackQuery()) { + // Set variables + long chatId = update.getCallbackQuery().getMessage().getChatId(); + String callData = update.getCallbackQuery().getData(); + long messageId = update.getCallbackQuery().getMessage().getMessageId(); + + // here will be menu buttons callbacks + + if (callData.equals(MenuManager.CANCEL_ACTION)) { + replaceMessageWithText(chatId, messageId, "Cancelled."); + + + } else if (callData.startsWith(MenuManager.PREV_ACTION) || callData.startsWith(MenuManager.NEXT_ACTION)) { + + String pageNum = "0"; + if (callData.startsWith(MenuManager.PREV_ACTION)) { + pageNum = callData.replace(MenuManager.PREV_ACTION+":", ""); + } else { + pageNum = callData.replace(MenuManager.NEXT_ACTION+":", ""); + } + + InlineKeyboardBuilder builder = menuManager.createMenuForPage(Integer.parseInt(pageNum), true); + + builder.setChatId(chatId).setText("Choose action:"); + SendMessage message = builder.build(); + + replaceMessage(chatId, messageId, message); + + } + } +} +``` \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..5719925 --- /dev/null +++ b/pom.xml @@ -0,0 +1,47 @@ + + + 4.0.0 + + ru.bvn13.examples.bot + menubot + 1.1.0 + + + + org.apache.maven.plugins + maven-compiler-plugin + + 1.8 + 1.8 + + + + + jar + + Menu Bot + Telegram Inline Multipage Menu + + + + UTF-8 + UTF-8 + 1.8 + + + + + + + + org.telegram + telegrambots + 3.5 + + + + + + + diff --git a/src/main/java/ru/bvn13/examples/bot/Application.java b/src/main/java/ru/bvn13/examples/bot/Application.java new file mode 100644 index 0000000..e2932b8 --- /dev/null +++ b/src/main/java/ru/bvn13/examples/bot/Application.java @@ -0,0 +1,27 @@ +package ru.bvn13.examples.bot; + +import org.telegram.telegrambots.ApiContextInitializer; +import org.telegram.telegrambots.TelegramBotsApi; +import org.telegram.telegrambots.exceptions.TelegramApiException; + +/** + * Created by bvn13 on 21.02.2018. + */ +public class Application { + public static void main(String[] args) { + // Initialize Api Context + ApiContextInitializer.init(); + + // Instantiate Telegram Bots API + TelegramBotsApi botsApi = new TelegramBotsApi(); + + // Register our bot + MenuBot bot = new MenuBot(); + bot.init(); + try { + botsApi.registerBot(bot); + } catch (TelegramApiException e) { + e.printStackTrace(); + } + } +} \ No newline at end of file diff --git a/src/main/java/ru/bvn13/examples/bot/MenuBot.java b/src/main/java/ru/bvn13/examples/bot/MenuBot.java new file mode 100644 index 0000000..47b4289 --- /dev/null +++ b/src/main/java/ru/bvn13/examples/bot/MenuBot.java @@ -0,0 +1,149 @@ +package ru.bvn13.examples.bot; + +import org.telegram.telegrambots.api.methods.send.SendMessage; +import org.telegram.telegrambots.api.methods.updatingmessages.EditMessageText; +import org.telegram.telegrambots.api.objects.Update; +import org.telegram.telegrambots.api.objects.replykeyboard.InlineKeyboardMarkup; +import org.telegram.telegrambots.bots.TelegramLongPollingBot; +import org.telegram.telegrambots.exceptions.TelegramApiException; +import ru.bvn13.examples.bot.accessories.InlineKeyboardBuilder; +import ru.bvn13.examples.bot.menu.MenuManager; + +/** + * Created by bvn13 on 21.02.2018. + */ +public class MenuBot extends TelegramLongPollingBot { + + private MenuManager menuManager = new MenuManager(); + + public void init() { + menuManager.setColumnsCount(2); + + menuManager.addMenuItem("Action 1", "action 1"); + menuManager.addMenuItem("Action 2", "action 2"); + menuManager.addMenuItem("Action 3", "action 3"); + menuManager.addMenuItem("Action 4", "action 4"); + menuManager.addMenuItem("Action 5", "action 5"); + menuManager.addMenuItem("Action 6", "action 6"); + menuManager.addMenuItem("Action 7", "action 7"); + menuManager.addMenuItem("Action 8", "action 8"); + menuManager.addMenuItem("Action 9", "action 9"); + menuManager.addMenuItem("Action 10", "action 10"); + menuManager.addMenuItem("Action 11", "action 11"); + menuManager.addMenuItem("Action 12", "action 12"); + menuManager.addMenuItem("Action 13", "action 13"); + menuManager.addMenuItem("Action 14", "action 14"); + menuManager.addMenuItem("Action 15", "action 15"); + menuManager.addMenuItem("Action 16", "action 16"); + menuManager.addMenuItem("Action 17", "action 17"); + menuManager.addMenuItem("Action 18", "action 18"); + menuManager.addMenuItem("Action 19", "action 19"); + menuManager.addMenuItem("Action 20", "action 20"); + + menuManager.init(); + } + + + private void replaceMessageWithText(long chatId, long messageId, String text) { + EditMessageText newMessage = new EditMessageText() + .setChatId(chatId) + .setMessageId(Math.toIntExact(messageId)) + .setText(text); + try { + execute(newMessage); + } catch (TelegramApiException e) { + e.printStackTrace(); + } + } + + + private void replaceMessage(long chatId, long messageId, SendMessage message) { + EditMessageText newMessage = new EditMessageText() + .setChatId(chatId) + .setMessageId(Math.toIntExact(messageId)) + .setText(message.getText()) + .setReplyMarkup((InlineKeyboardMarkup) message.getReplyMarkup()); + try { + execute(newMessage); + } catch (TelegramApiException e) { + e.printStackTrace(); + } + } + + + @Override + public void onUpdateReceived(Update update) { + + + // We check if the update has a message and the message has text + if (update.hasMessage() && update.getMessage().hasText()) { + + if (update.getMessage().getText().equals("/menu")) { + long chatId = update.getMessage().getChatId(); + + // lets render the menu + InlineKeyboardBuilder builder = menuManager.createMenuForPage(0, true); + + builder.setChatId(chatId).setText("Choose action:"); + SendMessage message = builder.build(); + + try { + // Send the message + execute(message); + } catch (TelegramApiException e) { + e.printStackTrace(); + } + + } else { + + } + + } else if (update.hasCallbackQuery()) { + + // Set variables + long chatId = update.getCallbackQuery().getMessage().getChatId(); + String callData = update.getCallbackQuery().getData(); + long messageId = update.getCallbackQuery().getMessage().getMessageId(); + + // here will be menu buttons callbacks + + if (callData.equals(MenuManager.CANCEL_ACTION)) { + replaceMessageWithText(chatId, messageId, "Cancelled."); + + + } else if (callData.startsWith(MenuManager.PREV_ACTION) || callData.startsWith(MenuManager.NEXT_ACTION)) { + + String pageNum = "0"; + if (callData.startsWith(MenuManager.PREV_ACTION)) { + pageNum = callData.replace(MenuManager.PREV_ACTION+":", ""); + } else { + pageNum = callData.replace(MenuManager.NEXT_ACTION+":", ""); + } + + InlineKeyboardBuilder builder = menuManager.createMenuForPage(Integer.parseInt(pageNum), true); + + builder.setChatId(chatId).setText("Choose action:"); + SendMessage message = builder.build(); + + replaceMessage(chatId, messageId, message); + + } + + } + } + + @Override + public String getBotUsername() { + // Return bot username + // If bot username is @MyAmazingBot, it must return 'MyAmazingBot' + return "MenuBot"; + } + + @Override + public String getBotToken() { + // Return bot token from BotFather + return "12345:qwertyuiopASDGFHKMK"; + } + +} + diff --git a/src/main/java/ru/bvn13/examples/bot/accessories/InlineKeyboardBuilder.java b/src/main/java/ru/bvn13/examples/bot/accessories/InlineKeyboardBuilder.java new file mode 100644 index 0000000..d07a28b --- /dev/null +++ b/src/main/java/ru/bvn13/examples/bot/accessories/InlineKeyboardBuilder.java @@ -0,0 +1,75 @@ +package ru.bvn13.examples.bot.accessories; + +import org.telegram.telegrambots.api.methods.send.SendMessage; +import org.telegram.telegrambots.api.objects.replykeyboard.InlineKeyboardMarkup; +import org.telegram.telegrambots.api.objects.replykeyboard.buttons.InlineKeyboardButton; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by bvn13 on 21.02.2018. + */ +public class InlineKeyboardBuilder { + + private Long chatId; + private String text; + + private List> keyboard = new ArrayList<>(); + private List row = null; + + private InlineKeyboardBuilder() {} + + public static InlineKeyboardBuilder create() { + InlineKeyboardBuilder builder = new InlineKeyboardBuilder(); + return builder; + } + + public static InlineKeyboardBuilder create(Long chatId) { + InlineKeyboardBuilder builder = new InlineKeyboardBuilder(); + builder.setChatId(chatId); + return builder; + } + + public InlineKeyboardBuilder setText(String text) { + this.text = text; + return this; + } + + public InlineKeyboardBuilder setChatId(Long chatId) { + this.chatId = chatId; + return this; + } + + public InlineKeyboardBuilder row() { + this.row = new ArrayList<>(); + return this; + } + + public InlineKeyboardBuilder button(String text, String callbackData) { + row.add(new InlineKeyboardButton().setText(text).setCallbackData(callbackData)); + return this; + } + + public InlineKeyboardBuilder endRow() { + this.keyboard.add(this.row); + this.row = null; + return this; + } + + + public SendMessage build() { + SendMessage message = new SendMessage(); + + message.setChatId(chatId); + message.setText(text); + + InlineKeyboardMarkup keyboardMarkup = new InlineKeyboardMarkup(); + + keyboardMarkup.setKeyboard(keyboard); + message.setReplyMarkup(keyboardMarkup); + + return message; + } + +} diff --git a/src/main/java/ru/bvn13/examples/bot/menu/MenuItem.java b/src/main/java/ru/bvn13/examples/bot/menu/MenuItem.java new file mode 100644 index 0000000..31e2166 --- /dev/null +++ b/src/main/java/ru/bvn13/examples/bot/menu/MenuItem.java @@ -0,0 +1,32 @@ +package ru.bvn13.examples.bot.menu; + +/** + * Created by bvn13 on 21.02.2018. + */ +public class MenuItem { + + private String name; + private String action; + + + public MenuItem(String name, String action) { + this.name = name; + this.action = action; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getAction() { + return action; + } + + public void setAction(String action) { + this.action = action; + } +} diff --git a/src/main/java/ru/bvn13/examples/bot/menu/MenuManager.java b/src/main/java/ru/bvn13/examples/bot/menu/MenuManager.java new file mode 100644 index 0000000..f423f0d --- /dev/null +++ b/src/main/java/ru/bvn13/examples/bot/menu/MenuManager.java @@ -0,0 +1,115 @@ +package ru.bvn13.examples.bot.menu; + +import ru.bvn13.examples.bot.accessories.InlineKeyboardBuilder; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by bvn13 on 21.02.2018. + */ +public class MenuManager { + + public static final String PREV_ACTION = "page-prev"; + public static final String NEXT_ACTION = "page-next"; + public static final String CANCEL_ACTION = "cancel"; + + private int buttonsPerPage = 6; + public void setButtonsPerPage(int buttonsPerPage) { + this.buttonsPerPage = buttonsPerPage; + } + + private int total; + private int lastPage; + + private MenuItem btnPrev = new MenuItem("<<", PREV_ACTION); + private MenuItem btnNext = new MenuItem(">>", NEXT_ACTION); + private MenuItem btnCancel = new MenuItem("Cancel", CANCEL_ACTION); + + private List menu = new ArrayList<>(); + + private int columnsCount; + public void setColumnsCount(int columnsCount) { + this.columnsCount = columnsCount; + } + + public void init() { + this.total = menu.size(); + this.lastPage = (int) Math.ceil((double) total / buttonsPerPage) - 1; + } + + public void addMenuItem(String name, String action) { + this.menu.add(new MenuItem(name, action)); + } + + private List getPage(int page) { + List pageMenu = new ArrayList<>(); + + if (page > lastPage) { + return pageMenu; + } + + int start = page* buttonsPerPage; + int end = (page+1)* buttonsPerPage -1; + + if (start < 0) start = 0; + if (end >= total) end = total-1; + + for (int i = start; i <= end; i++) { + pageMenu.add(menu.get(i)); + } + + return pageMenu; + } + + private List getControlButtonsForPage(int page, boolean hasCancel) { + List buttons = new ArrayList<>(); + if (page > 0) { + buttons.add(btnPrev); + } + if (hasCancel) { + buttons.add(btnCancel); + } + if (page < lastPage) { + buttons.add(btnNext); + } + return buttons; + } + + public InlineKeyboardBuilder createMenuForPage(int page, boolean hasCancel) { + List pageButtons = getPage(page); + List controlButtons = getControlButtonsForPage(page, hasCancel); + + InlineKeyboardBuilder builder = InlineKeyboardBuilder.create(); + int col = 0; + int num = 0; + builder.row(); + for (MenuItem button : pageButtons) { + builder.button(button.getName(), button.getAction()); + if (++col >= columnsCount) { + col = 0; + builder.endRow(); + if (num++ <= pageButtons.size()) { + builder.row(); + } + } + } + builder.endRow(); + + builder.row(); + for (MenuItem button : controlButtons) { + if (button.getAction().equals(PREV_ACTION)) { + builder.button(button.getName(), button.getAction()+":"+(page-1)); + } else if (button.getAction().equals(NEXT_ACTION)) { + builder.button(button.getName(), button.getAction()+":"+(page+1)); + } else { + builder.button(button.getName(), button.getAction()); + } + } + builder.endRow(); + + return builder; + } + + +}