Skip to content

Comments

[telegram] Add support for custom keyboards#18013

Open
Skinah wants to merge 1 commit intoopenhab:mainfrom
Skinah:telegram
Open

[telegram] Add support for custom keyboards#18013
Skinah wants to merge 1 commit intoopenhab:mainfrom
Skinah:telegram

Conversation

@Skinah
Copy link
Contributor

@Skinah Skinah commented Jan 1, 2025

Adds the following new functionality, just waiting on a milestone build to test the jar under java21.
closes #7279

| sendKeyboard(Long chatId, String message, String replyId, boolean oneTimeKeyboard, String[]... buttons) | Send a custom keyboard with multiple rows of buttons. |
| sendKeyboard(Long chatId, String message, String replyId, boolean oneTimeKeyboard, String... buttons)| Send a custom keyboard with a single row of buttons. |
| removeKeyboard(boolean isSelective) | Remove a custom keyboard. |

Signed-off-by: Matthew Skinner <matt@pcmus.com>
@Skinah Skinah added work in progress A PR that is not yet ready to be merged enhancement An enhancement or new feature for an existing add-on labels Jan 1, 2025
@wborn wborn requested a review from Copilot August 3, 2025 05:59
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR adds support for custom keyboards in the Telegram binding by implementing new functionality to send and remove custom keyboards with configurable button layouts.

  • Adds new keyboard action methods for sending single-row and multi-row button keyboards
  • Updates the Telegram bot API dependency from version 7.1.0 to 7.11.0
  • Updates documentation to include the new keyboard functionality

Reviewed Changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 10 comments.

File Description
TelegramActions.java Implements new keyboard sending methods and imports required classes
pom.xml Updates java-telegram-bot-api dependency version
README.md Documents the new keyboard action methods

Comment on lines +355 to +358
private boolean removeKeyboard(@ActionInput(name = "isSelective") boolean isSelective) {
Keyboard replyKeyboardRemove = new ReplyKeyboardRemove(isSelective);
sendReplyMarkup("324", 34354675676576546L, "foo", replyKeyboardRemove);
return true;
Copy link

Copilot AI Aug 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The removeKeyboard method contains hardcoded test values instead of using the actual parameters. This method should accept chatId and message parameters to function correctly.

Suggested change
private boolean removeKeyboard(@ActionInput(name = "isSelective") boolean isSelective) {
Keyboard replyKeyboardRemove = new ReplyKeyboardRemove(isSelective);
sendReplyMarkup("324", 34354675676576546L, "foo", replyKeyboardRemove);
return true;
private boolean removeKeyboard(@ActionInput(name = "chatId") @Nullable Long chatId,
@ActionInput(name = "message") @Nullable String message,
@ActionInput(name = "isSelective") boolean isSelective) {
Keyboard replyKeyboardRemove = new ReplyKeyboardRemove(isSelective);
if (chatId == null || message == null) {
logger.warn("chatId or message not defined; action skipped.");
return false;
}
return sendReplyMarkup(null, chatId, message, replyKeyboardRemove);

Copilot uses AI. Check for mistakes.
Comment on lines +331 to +335
if (replyId != null) {
if (!replyId.contains(" ")) {
sendMessage.replyMarkup(keyboard);
}
}
Copy link

Copilot AI Aug 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The keyboard is only applied when replyId is not null and doesn't contain spaces. This logic is incorrect - the keyboard should be applied regardless of the replyId condition, as keyboard functionality is independent of reply tracking.

Suggested change
if (replyId != null) {
if (!replyId.contains(" ")) {
sendMessage.replyMarkup(keyboard);
}
}
sendMessage.replyMarkup(keyboard);

Copilot uses AI. Check for mistakes.
Comment on lines +377 to +398
if (replyId != null) {
if (!replyId.contains(" ")) {
if (buttons.length > 0) {
KeyboardButton[][] keyboard2D = new KeyboardButton[buttons.length][];
for (int i = 0; i < buttons.length; i++) {
KeyboardButton[] rowOfButtons = new KeyboardButton[buttons[i].length];
for (int x = 0; x < buttons[i].length; x++) {
rowOfButtons[x] = new KeyboardButton(buttons[i][x]);
}
keyboard2D[i] = rowOfButtons;
}
ReplyKeyboardMarkup keyBoardMarkup = new ReplyKeyboardMarkup(keyboard2D);
sendMessage.replyMarkup(keyBoardMarkup);
} else {
logger.warn(
"The replyId {} for message {} is given, but no buttons are defined. ReplyKeyboardMarkup will be ignored.",
replyId, message);
}
} else {
logger.warn("replyId {} must not contain spaces. ReplyKeyboardMarkup will be ignored.", replyId);
}
}
Copy link

Copilot AI Aug 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The keyboard is only applied when replyId is not null and doesn't contain spaces. This logic is incorrect - the keyboard should be applied regardless of the replyId condition, as keyboard functionality is independent of reply tracking.

Suggested change
if (replyId != null) {
if (!replyId.contains(" ")) {
if (buttons.length > 0) {
KeyboardButton[][] keyboard2D = new KeyboardButton[buttons.length][];
for (int i = 0; i < buttons.length; i++) {
KeyboardButton[] rowOfButtons = new KeyboardButton[buttons[i].length];
for (int x = 0; x < buttons[i].length; x++) {
rowOfButtons[x] = new KeyboardButton(buttons[i][x]);
}
keyboard2D[i] = rowOfButtons;
}
ReplyKeyboardMarkup keyBoardMarkup = new ReplyKeyboardMarkup(keyboard2D);
sendMessage.replyMarkup(keyBoardMarkup);
} else {
logger.warn(
"The replyId {} for message {} is given, but no buttons are defined. ReplyKeyboardMarkup will be ignored.",
replyId, message);
}
} else {
logger.warn("replyId {} must not contain spaces. ReplyKeyboardMarkup will be ignored.", replyId);
}
}
// Apply keyboard markup if buttons are provided, regardless of replyId
if (buttons.length > 0) {
KeyboardButton[][] keyboard2D = new KeyboardButton[buttons.length][];
for (int i = 0; i < buttons.length; i++) {
KeyboardButton[] rowOfButtons = new KeyboardButton[buttons[i].length];
for (int x = 0; x < buttons[i].length; x++) {
rowOfButtons[x] = new KeyboardButton(buttons[i][x]);
}
keyboard2D[i] = rowOfButtons;
}
ReplyKeyboardMarkup keyBoardMarkup = new ReplyKeyboardMarkup(keyboard2D);
sendMessage.replyMarkup(keyBoardMarkup);
}
// Warn if replyId is present but contains spaces (for reply tracking only)
if (replyId != null && replyId.contains(" ")) {
logger.warn("replyId {} must not contain spaces. Reply tracking will be ignored.", replyId);
}
// Warn if replyId is present but no buttons are defined (optional, can be removed)
if (replyId != null && buttons.length == 0) {
logger.warn(
"The replyId {} for message {} is given, but no buttons are defined.", replyId, message);
}

Copilot uses AI. Check for mistakes.
Comment on lines +434 to +453
if (replyId != null) {
if (!replyId.contains(" ")) {
if (buttons.length > 0) {
KeyboardButton[][] keyboard2D = new KeyboardButton[1][];
KeyboardButton[] keyboard = new KeyboardButton[buttons.length];
keyboard2D[0] = keyboard;
for (int i = 0; i < buttons.length; i++) {
keyboard[i] = new KeyboardButton(buttons[i]);
}
ReplyKeyboardMarkup keyBoardMarkup = new ReplyKeyboardMarkup(keyboard2D);
sendMessage.replyMarkup(keyBoardMarkup);
} else {
logger.warn(
"The replyId {} for message {} is given, but no buttons are defined. ReplyKeyboardMarkup will be ignored.",
replyId, message);
}
} else {
logger.warn("replyId {} must not contain spaces. ReplyKeyboardMarkup will be ignored.", replyId);
}
}
Copy link

Copilot AI Aug 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The keyboard is only applied when replyId is not null and doesn't contain spaces. This logic is incorrect - the keyboard should be applied regardless of the replyId condition, as keyboard functionality is independent of reply tracking.

Suggested change
if (replyId != null) {
if (!replyId.contains(" ")) {
if (buttons.length > 0) {
KeyboardButton[][] keyboard2D = new KeyboardButton[1][];
KeyboardButton[] keyboard = new KeyboardButton[buttons.length];
keyboard2D[0] = keyboard;
for (int i = 0; i < buttons.length; i++) {
keyboard[i] = new KeyboardButton(buttons[i]);
}
ReplyKeyboardMarkup keyBoardMarkup = new ReplyKeyboardMarkup(keyboard2D);
sendMessage.replyMarkup(keyBoardMarkup);
} else {
logger.warn(
"The replyId {} for message {} is given, but no buttons are defined. ReplyKeyboardMarkup will be ignored.",
replyId, message);
}
} else {
logger.warn("replyId {} must not contain spaces. ReplyKeyboardMarkup will be ignored.", replyId);
}
}
if (buttons.length > 0) {
KeyboardButton[][] keyboard2D = new KeyboardButton[1][];
KeyboardButton[] keyboard = new KeyboardButton[buttons.length];
keyboard2D[0] = keyboard;
for (int i = 0; i < buttons.length; i++) {
keyboard[i] = new KeyboardButton(buttons[i]);
}
ReplyKeyboardMarkup keyBoardMarkup = new ReplyKeyboardMarkup(keyboard2D);
sendMessage.replyMarkup(keyBoardMarkup);
}
if (replyId != null && replyId.contains(" ")) {
logger.warn("replyId {} must not contain spaces. Reply tracking will be ignored.", replyId);
}

Copilot uses AI. Check for mistakes.
try {
retMessage = localHandler.execute(sendMessage);
} catch (Exception e) {
logger.warn("Exception occured whilst sending message:{}", e.getMessage());
Copy link

Copilot AI Aug 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spelling error: 'occured' should be 'occurred'.

Suggested change
logger.warn("Exception occured whilst sending message:{}", e.getMessage());
logger.warn("Exception occurred whilst sending message:{}", e.getMessage());

Copilot uses AI. Check for mistakes.
try {
retMessage = localHandler.execute(sendMessage);
} catch (Exception e) {
logger.warn("Exception occured whilst sending message:{}", e.getMessage());
Copy link

Copilot AI Aug 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spelling error: 'occured' should be 'occurred'.

Suggested change
logger.warn("Exception occured whilst sending message:{}", e.getMessage());
logger.warn("Exception occurred whilst sending message:{}", e.getMessage());

Copilot uses AI. Check for mistakes.
try {
retMessage = localHandler.execute(sendMessage);
} catch (Exception e) {
logger.warn("Exception occured whilst sending message:{}", e.getMessage());
Copy link

Copilot AI Aug 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spelling error: 'occured' should be 'occurred'.

Suggested change
logger.warn("Exception occured whilst sending message:{}", e.getMessage());
logger.warn("Exception occurred whilst sending message:{}", e.getMessage());

Copilot uses AI. Check for mistakes.
return true;
}

private boolean sendKeyboard(@ActionInput(name = "chatId") @Nullable Long chatId, @Nullable String message,
Copy link

Copilot AI Aug 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is significant code duplication between the two sendKeyboard methods. Consider extracting the common logic into a shared helper method to improve maintainability.

Copilot uses AI. Check for mistakes.
}

private boolean sendKeyboard(@ActionInput(name = "chatId") @Nullable Long chatId, @Nullable String message,
@Nullable String replyId, boolean oneTimeKeyboard, @Nullable String... buttons) {
Copy link

Copilot AI Aug 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The oneTimeKeyboard parameter is never used in the method implementation. It should be applied to the ReplyKeyboardMarkup to control whether the keyboard disappears after one use.

Copilot uses AI. Check for mistakes.
}

private boolean sendKeyboard(@ActionInput(name = "chatId") @Nullable Long chatId, @Nullable String message,
@Nullable String replyId, boolean oneTimeKeyboard, @Nullable String[]... buttons) {
Copy link

Copilot AI Aug 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The oneTimeKeyboard parameter is never used in the method implementation. It should be applied to the ReplyKeyboardMarkup to control whether the keyboard disappears after one use.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement An enhancement or new feature for an existing add-on work in progress A PR that is not yet ready to be merged

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[telegram] Support ReplyKeyboardMarkup

1 participant