1
0
mirror of https://github.com/InsanusMokrassar/TelegramBotAPI.git synced 2026-09-14 12:04:18 +00:00

Add Bot API 10.3 Reply markup support

This commit is contained in:
2026-08-25 12:33:45 +06:00
parent 752689447b
commit efd4667ffa
15 changed files with 247 additions and 36 deletions

View File

@@ -11654,6 +11654,7 @@ public final class dev/inmo/tgbotapi/types/CommonKt {
public static final field disableEditMessageField Ljava/lang/String;
public static final field disableNotificationField Ljava/lang/String;
public static final field disableWebPagePreviewField Ljava/lang/String;
public static final field disabledField Ljava/lang/String;
public static final field documentField Ljava/lang/String;
public static final field documentFileIdField Ljava/lang/String;
public static final field documentUrlField Ljava/lang/String;
@@ -17118,6 +17119,46 @@ public final class dev/inmo/tgbotapi/types/buttons/InlineKeyboardButtons/CopyTex
public final fun serializer ()Lkotlinx/serialization/KSerializer;
}
public final class dev/inmo/tgbotapi/types/buttons/InlineKeyboardButtons/DisabledButton {
public static final field INSTANCE Ldev/inmo/tgbotapi/types/buttons/InlineKeyboardButtons/DisabledButton;
public fun equals (Ljava/lang/Object;)Z
public fun hashCode ()I
public final fun serializer ()Lkotlinx/serialization/KSerializer;
public fun toString ()Ljava/lang/String;
}
public final class dev/inmo/tgbotapi/types/buttons/InlineKeyboardButtons/DisabledInlineKeyboardButton : dev/inmo/tgbotapi/types/buttons/InlineKeyboardButtons/InlineKeyboardButton {
public static final field Companion Ldev/inmo/tgbotapi/types/buttons/InlineKeyboardButtons/DisabledInlineKeyboardButton$Companion;
public synthetic fun <init> (Ljava/lang/String;Ljava/lang/String;Ldev/inmo/tgbotapi/types/buttons/KeyboardButtonStyle;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public synthetic fun <init> (Ljava/lang/String;Ljava/lang/String;Ldev/inmo/tgbotapi/types/buttons/KeyboardButtonStyle;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun component1 ()Ljava/lang/String;
public final fun component2-GbmMWyQ ()Ljava/lang/String;
public final fun component3 ()Ldev/inmo/tgbotapi/types/buttons/KeyboardButtonStyle;
public final fun copy-A-saiJc (Ljava/lang/String;Ljava/lang/String;Ldev/inmo/tgbotapi/types/buttons/KeyboardButtonStyle;)Ldev/inmo/tgbotapi/types/buttons/InlineKeyboardButtons/DisabledInlineKeyboardButton;
public static synthetic fun copy-A-saiJc$default (Ldev/inmo/tgbotapi/types/buttons/InlineKeyboardButtons/DisabledInlineKeyboardButton;Ljava/lang/String;Ljava/lang/String;Ldev/inmo/tgbotapi/types/buttons/KeyboardButtonStyle;ILjava/lang/Object;)Ldev/inmo/tgbotapi/types/buttons/InlineKeyboardButtons/DisabledInlineKeyboardButton;
public fun equals (Ljava/lang/Object;)Z
public fun getIconCustomEmojiId-GbmMWyQ ()Ljava/lang/String;
public fun getStyle ()Ldev/inmo/tgbotapi/types/buttons/KeyboardButtonStyle;
public fun getText ()Ljava/lang/String;
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}
public final synthetic class dev/inmo/tgbotapi/types/buttons/InlineKeyboardButtons/DisabledInlineKeyboardButton$$serializer : kotlinx/serialization/internal/GeneratedSerializer {
public static final field INSTANCE Ldev/inmo/tgbotapi/types/buttons/InlineKeyboardButtons/DisabledInlineKeyboardButton$$serializer;
public final fun childSerializers ()[Lkotlinx/serialization/KSerializer;
public final fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ldev/inmo/tgbotapi/types/buttons/InlineKeyboardButtons/DisabledInlineKeyboardButton;
public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object;
public final fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor;
public final fun serialize (Lkotlinx/serialization/encoding/Encoder;Ldev/inmo/tgbotapi/types/buttons/InlineKeyboardButtons/DisabledInlineKeyboardButton;)V
public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V
public fun typeParametersSerializers ()[Lkotlinx/serialization/KSerializer;
}
public final class dev/inmo/tgbotapi/types/buttons/InlineKeyboardButtons/DisabledInlineKeyboardButton$Companion {
public final fun serializer ()Lkotlinx/serialization/KSerializer;
}
public abstract interface class dev/inmo/tgbotapi/types/buttons/InlineKeyboardButtons/InlineKeyboardButton {
public static final field Companion Ldev/inmo/tgbotapi/types/buttons/InlineKeyboardButtons/InlineKeyboardButton$Companion;
public abstract fun getIconCustomEmojiId-GbmMWyQ ()Ljava/lang/String;
@@ -17443,11 +17484,14 @@ public final class dev/inmo/tgbotapi/types/buttons/InlineKeyboardButtons/WebAppI
public final class dev/inmo/tgbotapi/types/buttons/InlineKeyboardMarkup : dev/inmo/tgbotapi/types/buttons/KeyboardMarkup {
public static final field Companion Ldev/inmo/tgbotapi/types/buttons/InlineKeyboardMarkup$Companion;
public fun <init> (Ljava/util/List;)V
public fun <init> (Ljava/util/List;Ljava/lang/Boolean;)V
public synthetic fun <init> (Ljava/util/List;Ljava/lang/Boolean;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun component1 ()Ljava/util/List;
public final fun copy (Ljava/util/List;)Ldev/inmo/tgbotapi/types/buttons/InlineKeyboardMarkup;
public static synthetic fun copy$default (Ldev/inmo/tgbotapi/types/buttons/InlineKeyboardMarkup;Ljava/util/List;ILjava/lang/Object;)Ldev/inmo/tgbotapi/types/buttons/InlineKeyboardMarkup;
public final fun component2 ()Ljava/lang/Boolean;
public final fun copy (Ljava/util/List;Ljava/lang/Boolean;)Ldev/inmo/tgbotapi/types/buttons/InlineKeyboardMarkup;
public static synthetic fun copy$default (Ldev/inmo/tgbotapi/types/buttons/InlineKeyboardMarkup;Ljava/util/List;Ljava/lang/Boolean;ILjava/lang/Object;)Ldev/inmo/tgbotapi/types/buttons/InlineKeyboardMarkup;
public fun equals (Ljava/lang/Object;)Z
public final fun getForceReply ()Ljava/lang/Boolean;
public final fun getKeyboard ()Ljava/util/List;
public fun hashCode ()I
public final fun minus (Ldev/inmo/tgbotapi/types/buttons/InlineKeyboardMarkup;)Ldev/inmo/tgbotapi/types/buttons/InlineKeyboardMarkup;
@@ -17918,8 +17962,8 @@ public final class dev/inmo/tgbotapi/types/buttons/ReplyForce$Companion {
public final class dev/inmo/tgbotapi/types/buttons/ReplyKeyboardMarkup : dev/inmo/tgbotapi/types/buttons/KeyboardMarkup {
public static final field Companion Ldev/inmo/tgbotapi/types/buttons/ReplyKeyboardMarkup$Companion;
public fun <init> (Ljava/util/List;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/Boolean;)V
public synthetic fun <init> (Ljava/util/List;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/Boolean;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun <init> (Ljava/util/List;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;)V
public synthetic fun <init> (Ljava/util/List;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun add (Ldev/inmo/tgbotapi/types/buttons/ReplyKeyboardMarkup;Ljava/lang/String;)Ldev/inmo/tgbotapi/types/buttons/ReplyKeyboardMarkup;
public static synthetic fun add$default (Ldev/inmo/tgbotapi/types/buttons/ReplyKeyboardMarkup;Ldev/inmo/tgbotapi/types/buttons/ReplyKeyboardMarkup;Ljava/lang/String;ILjava/lang/Object;)Ldev/inmo/tgbotapi/types/buttons/ReplyKeyboardMarkup;
public final fun component1 ()Ljava/util/List;
@@ -17928,9 +17972,11 @@ public final class dev/inmo/tgbotapi/types/buttons/ReplyKeyboardMarkup : dev/inm
public final fun component4 ()Ljava/lang/String;
public final fun component5 ()Ljava/lang/Boolean;
public final fun component6 ()Ljava/lang/Boolean;
public final fun copy (Ljava/util/List;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/Boolean;)Ldev/inmo/tgbotapi/types/buttons/ReplyKeyboardMarkup;
public static synthetic fun copy$default (Ldev/inmo/tgbotapi/types/buttons/ReplyKeyboardMarkup;Ljava/util/List;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/Boolean;ILjava/lang/Object;)Ldev/inmo/tgbotapi/types/buttons/ReplyKeyboardMarkup;
public final fun component7 ()Ljava/lang/Boolean;
public final fun copy (Ljava/util/List;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;)Ldev/inmo/tgbotapi/types/buttons/ReplyKeyboardMarkup;
public static synthetic fun copy$default (Ldev/inmo/tgbotapi/types/buttons/ReplyKeyboardMarkup;Ljava/util/List;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;ILjava/lang/Object;)Ldev/inmo/tgbotapi/types/buttons/ReplyKeyboardMarkup;
public fun equals (Ljava/lang/Object;)Z
public final fun getForceReply ()Ljava/lang/Boolean;
public final fun getInputFieldPlaceholder ()Ljava/lang/String;
public final fun getKeyboard ()Ljava/util/List;
public final fun getOneTimeKeyboard ()Ljava/lang/Boolean;
@@ -18311,6 +18357,8 @@ public final class dev/inmo/tgbotapi/types/buttons/inline/InlineKeyboardButtonsS
public static synthetic fun copyTextButton-peVxY-Q$default (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ldev/inmo/tgbotapi/types/buttons/KeyboardButtonStyle;ILjava/lang/Object;)Ldev/inmo/tgbotapi/types/buttons/InlineKeyboardButtons/CopyTextButton;
public static final fun dataInlineButton-peVxY-Q (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ldev/inmo/tgbotapi/types/buttons/KeyboardButtonStyle;)Ldev/inmo/tgbotapi/types/buttons/InlineKeyboardButtons/CallbackDataInlineKeyboardButton;
public static synthetic fun dataInlineButton-peVxY-Q$default (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ldev/inmo/tgbotapi/types/buttons/KeyboardButtonStyle;ILjava/lang/Object;)Ldev/inmo/tgbotapi/types/buttons/InlineKeyboardButtons/CallbackDataInlineKeyboardButton;
public static final fun disabledInlineButton-A-saiJc (Ljava/lang/String;Ljava/lang/String;Ldev/inmo/tgbotapi/types/buttons/KeyboardButtonStyle;)Ldev/inmo/tgbotapi/types/buttons/InlineKeyboardButtons/DisabledInlineKeyboardButton;
public static synthetic fun disabledInlineButton-A-saiJc$default (Ljava/lang/String;Ljava/lang/String;Ldev/inmo/tgbotapi/types/buttons/KeyboardButtonStyle;ILjava/lang/Object;)Ldev/inmo/tgbotapi/types/buttons/InlineKeyboardButtons/DisabledInlineKeyboardButton;
public static final fun gameInlineButton-A-saiJc (Ljava/lang/String;Ljava/lang/String;Ldev/inmo/tgbotapi/types/buttons/KeyboardButtonStyle;)Ldev/inmo/tgbotapi/types/buttons/InlineKeyboardButtons/CallbackGameInlineKeyboardButton;
public static synthetic fun gameInlineButton-A-saiJc$default (Ljava/lang/String;Ljava/lang/String;Ldev/inmo/tgbotapi/types/buttons/KeyboardButtonStyle;ILjava/lang/Object;)Ldev/inmo/tgbotapi/types/buttons/InlineKeyboardButtons/CallbackGameInlineKeyboardButton;
public static final fun inlineQueryInAnyCurrentChatInlineButton-peVxY-Q (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ldev/inmo/tgbotapi/types/buttons/KeyboardButtonStyle;)Ldev/inmo/tgbotapi/types/buttons/InlineKeyboardButtons/SwitchInlineQueryChosenChatInlineKeyboardButton;

View File

@@ -776,6 +776,7 @@ const val disableEditMessageField = "disable_edit_message"
const val scoreField = "score"
const val forceField = "force"
const val forceReplyField = "force_reply"
const val disabledField = "disabled"
const val regularPollType = "regular"
const val quizPollType = "quiz"

View File

@@ -24,6 +24,34 @@ sealed interface InlineKeyboardButton {
val iconCustomEmojiId: CustomEmojiId?
}
/**
* A disabled inline keyboard button action. Telegram Bot API currently defines no fields for this object.
*
* @see DisabledInlineKeyboardButton
* @see https://core.telegram.org/bots/api#disabledbutton
*/
@Serializable
data object DisabledButton
/**
* An inline keyboard button which does nothing when pressed.
*
* @see https://core.telegram.org/bots/api#inlinekeyboardbutton
*/
@Serializable
data class DisabledInlineKeyboardButton(
@SerialName(textField)
override val text: String,
@SerialName(iconCustomEmojiIdField)
override val iconCustomEmojiId: CustomEmojiId? = null,
@SerialName(styleField)
override val style: KeyboardButtonStyle? = null
) : InlineKeyboardButton {
@SerialName(disabledField)
@EncodeDefault
private val disabled = DisabledButton
}
@Serializable
data class UnknownInlineKeyboardButton (
val rawData: JsonElement

View File

@@ -24,6 +24,7 @@ object InlineKeyboardButtonSerializer : KSerializer<InlineKeyboardButton> {
private fun resolveSerializer(json: JsonObject): KSerializer<out InlineKeyboardButton>? {
return when {
json[disabledField] != null -> DisabledInlineKeyboardButton.serializer()
json[callbackDataField] != null -> CallbackDataInlineKeyboardButton.serializer()
json[callbackGameField] != null -> CallbackGameInlineKeyboardButton.serializer()
json[loginUrlField] != null -> LoginURLInlineKeyboardButton.serializer()
@@ -47,6 +48,7 @@ object InlineKeyboardButtonSerializer : KSerializer<InlineKeyboardButton> {
override fun serialize(encoder: Encoder, value: InlineKeyboardButton) {
when (value) {
is DisabledInlineKeyboardButton -> DisabledInlineKeyboardButton.serializer().serialize(encoder, value)
is CallbackDataInlineKeyboardButton -> CallbackDataInlineKeyboardButton.serializer().serialize(encoder, value)
is LoginURLInlineKeyboardButton -> LoginURLInlineKeyboardButton.serializer().serialize(encoder, value)
is PayInlineKeyboardButton -> PayInlineKeyboardButton.serializer().serialize(encoder, value)

View File

@@ -2,6 +2,7 @@ package dev.inmo.tgbotapi.types.buttons
import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.InlineKeyboardButton
import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.PayInlineKeyboardButton
import dev.inmo.tgbotapi.types.forceReplyField
import dev.inmo.tgbotapi.types.inlineKeyboardField
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@@ -9,7 +10,13 @@ import kotlinx.serialization.Serializable
@Serializable
data class InlineKeyboardMarkup(
@SerialName(inlineKeyboardField)
val keyboard: Matrix<InlineKeyboardButton>
val keyboard: Matrix<InlineKeyboardButton>,
/**
* Requests a reply interface for the message. Telegram does not allow changing this value when editing the inline
* keyboard.
*/
@SerialName(forceReplyField)
val forceReply: Boolean? = null
) : KeyboardMarkup {
init {
val isTherePayButton = keyboard.any { it ->
@@ -28,20 +35,22 @@ data class InlineKeyboardMarkup(
operator fun plus(other: InlineKeyboardMarkup): InlineKeyboardMarkup {
return InlineKeyboardMarkup(
keyboard + other.keyboard
keyboard = keyboard + other.keyboard,
forceReply = forceReply ?.or(other.forceReply ?: false) ?: other.forceReply
)
}
operator fun minus(other: InlineKeyboardMarkup): InlineKeyboardMarkup {
val otherButtons = other.keyboard.flatten()
return InlineKeyboardMarkup(
keyboard.mapNotNull { row ->
keyboard = keyboard.mapNotNull { row ->
row.filter { button ->
button !in otherButtons
}.takeIf {
it.isNotEmpty()
}
}
},
forceReply = forceReply
)
}
}

View File

@@ -15,7 +15,12 @@ data class ReplyKeyboardMarkup(
val inputFieldPlaceholder: String? = null,
val selective: Boolean? = null,
@SerialName(isPersistentField)
val persistent: Boolean? = null
val persistent: Boolean? = null,
/**
* Requests a reply interface for the message.
*/
@SerialName(forceReplyField)
val forceReply: Boolean? = null
) : KeyboardMarkup {
init {
if (inputFieldPlaceholder != null && inputFieldPlaceholder.length !in inputFieldPlaceholderLimit) {
@@ -31,6 +36,7 @@ data class ReplyKeyboardMarkup(
inputFieldPlaceholder = inputFieldPlaceholder ?.plus(other.inputFieldPlaceholder ?.let { placeholderDelimiter + it } ?: "") ?: other.inputFieldPlaceholder,
selective = selective ?.or(other.selective ?: false) ?: other.selective,
persistent = persistent ?.or(other.persistent ?: false) ?: other.persistent,
forceReply = forceReply ?.or(other.forceReply ?: false) ?: other.forceReply,
)
}

View File

@@ -7,6 +7,15 @@ import dev.inmo.tgbotapi.types.buttons.KeyboardButtonStyle
import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.*
import dev.inmo.tgbotapi.types.webapps.WebAppInfo
/**
* Creates [DisabledInlineKeyboardButton].
*/
fun disabledInlineButton(
text: String,
iconCustomEmojiId: CustomEmojiId? = null,
style: KeyboardButtonStyle? = null
) = DisabledInlineKeyboardButton(text, iconCustomEmojiId, style)
/**
* Creates [PayInlineKeyboardButton]
*/

View File

@@ -0,0 +1,59 @@
package dev.inmo.tgbotapi.types
import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.DisabledInlineKeyboardButton
import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.InlineKeyboardButton
import dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup
import dev.inmo.tgbotapi.types.buttons.ReplyKeyboardMarkup
import dev.inmo.tgbotapi.types.buttons.SimpleKeyboardButton
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.jsonObject
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertTrue
class ReplyMarkupSerializationTest {
private val json = Json { encodeDefaults = false }
@Test
fun disabledInlineKeyboardButtonUsesEmptyDisabledObjectAndRoundTrips() {
val value: InlineKeyboardButton = DisabledInlineKeyboardButton("Unavailable")
val encoded = json.encodeToString(value)
val encodedObject = json.parseToJsonElement(encoded).jsonObject
assertEquals("{}", encodedObject.getValue(disabledField).toString())
assertEquals(value, json.decodeFromString<InlineKeyboardButton>(encoded))
}
@Test
fun inlineKeyboardMarkupSerializesForceReplyAndPreservesItWhenCombined() {
val value = InlineKeyboardMarkup(
keyboard = listOf(listOf(DisabledInlineKeyboardButton("Unavailable"))),
forceReply = true
)
val encodedObject = json.parseToJsonElement(json.encodeToString(value)).jsonObject
assertEquals(true, encodedObject.getValue(forceReplyField).toString().toBoolean())
assertEquals(value, json.decodeFromString<InlineKeyboardMarkup>(encodedObject.toString()))
assertTrue((value + InlineKeyboardMarkup(listOf(listOf(DisabledInlineKeyboardButton("Other"))))).forceReply == true)
assertTrue((value - InlineKeyboardMarkup(listOf(listOf(DisabledInlineKeyboardButton("Unavailable"))))).forceReply == true)
}
@Test
fun replyKeyboardMarkupSerializesForceReplyAndPreservesItWhenCombined() {
val value = ReplyKeyboardMarkup(
keyboard = listOf(listOf(SimpleKeyboardButton("Reply"))),
forceReply = true
)
val encodedObject = json.parseToJsonElement(json.encodeToString(value)).jsonObject
assertEquals(true, encodedObject.getValue(forceReplyField).toString().toBoolean())
assertEquals(value, json.decodeFromString<ReplyKeyboardMarkup>(encodedObject.toString()))
assertTrue((value + ReplyKeyboardMarkup(listOf(listOf(SimpleKeyboardButton("Other"))))).forceReply == true)
assertTrue((value - ReplyKeyboardMarkup(listOf(listOf(SimpleKeyboardButton("Reply"))))).forceReply == true)
}
}