diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b6b2607cf8..af68a25e488 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # TelegramBotAPI changelog +## 7.1.0 + +**This update contains changes according to the [Telegram Bot API 6.7](https://core.telegram.org/bots/api-changelog#april-21-2023)** + +* `API`: + * Rename `editMessageCaption` to `editMessageMedia` due to wrong old naming + * Add `edit` extensions for `InlineMessageIdentifier`s +* `BehaviourBuilder`: + * `BehaviourContext` extensions `onDeepLink` and `waitDeepLinks` now can be used with `Regex` or `String` as first parameters + ## 7.0.2 _This update brings experimental support of `linuxX64` and `mingwX64` platforms_ diff --git a/README.md b/README.md index cdfc5b81c88..2d37b38940e 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# TelegramBotAPI [![Maven Central](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi/badge.svg)](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi) [![Supported version](https://img.shields.io/badge/Telegram%20Bot%20API-6.6-blue)](https://core.telegram.org/bots/api-changelog#march-9-2023) +# TelegramBotAPI [![Maven Central](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi/badge.svg)](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi) [![Supported version](https://img.shields.io/badge/Telegram%20Bot%20API-6.7-blue)](https://core.telegram.org/bots/api-changelog#april-21-2023) | Docs | [![KDocs](https://img.shields.io/static/v1?label=Dokka&message=KDocs&color=blue&logo=kotlin)](https://tgbotapi.inmo.dev/index.html) [![Mini tutorial](https://img.shields.io/static/v1?label=Bookstack&message=Tutorial&color=blue&logo=bookstack)](https://bookstack.inmo.dev/books/telegrambotapi/chapter/introduction-tutorial) | |:----------------------:|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:| diff --git a/gradle.properties b/gradle.properties index 92de310c3b8..15b550f78c4 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,4 +6,4 @@ kotlin.incremental=true kotlin.incremental.js=true library_group=dev.inmo -library_version=7.0.2 +library_version=7.1.0 diff --git a/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/answers/AnswerInlineQuery.kt b/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/answers/AnswerInlineQuery.kt index b40ff79f44d..3e6a3da5e23 100644 --- a/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/answers/AnswerInlineQuery.kt +++ b/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/answers/AnswerInlineQuery.kt @@ -2,6 +2,7 @@ package dev.inmo.tgbotapi.extensions.api.answers import dev.inmo.tgbotapi.bot.TelegramBot import dev.inmo.tgbotapi.requests.answers.AnswerInlineQuery +import dev.inmo.tgbotapi.requests.answers.InlineQueryResultsButton import dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult.abstracts.InlineQueryResult import dev.inmo.tgbotapi.types.InlineQueries.query.InlineQuery import dev.inmo.tgbotapi.types.InlineQueryIdentifier @@ -12,8 +13,37 @@ suspend fun TelegramBot.answerInlineQuery( cachedTime: Int? = null, isPersonal: Boolean? = null, nextOffset: String? = null, - switchPmText: String? = null, - switchPmParameter: String? = null + button: InlineQueryResultsButton? = null +) = execute( + AnswerInlineQuery(inlineQueryID, results, cachedTime, isPersonal, nextOffset, button) +) + +suspend fun TelegramBot.answerInlineQuery( + inlineQuery: InlineQuery, + results: List = emptyList(), + cachedTime: Int? = null, + isPersonal: Boolean? = null, + nextOffset: String? = null, + button: InlineQueryResultsButton? = null +) = answerInlineQuery(inlineQuery.id, results, cachedTime, isPersonal, nextOffset, button) + +suspend fun TelegramBot.answer( + inlineQuery: InlineQuery, + results: List = emptyList(), + cachedTime: Int? = null, + isPersonal: Boolean? = null, + nextOffset: String? = null, + button: InlineQueryResultsButton? = null +) = answerInlineQuery(inlineQuery.id, results, cachedTime, isPersonal, nextOffset, button) + +suspend fun TelegramBot.answerInlineQuery( + inlineQueryID: InlineQueryIdentifier, + results: List = emptyList(), + cachedTime: Int? = null, + isPersonal: Boolean? = null, + nextOffset: String? = null, + switchPmText: String?, + switchPmParameter: String? ) = execute( AnswerInlineQuery(inlineQueryID, results, cachedTime, isPersonal, nextOffset, switchPmText, switchPmParameter) ) @@ -24,8 +54,8 @@ suspend fun TelegramBot.answerInlineQuery( cachedTime: Int? = null, isPersonal: Boolean? = null, nextOffset: String? = null, - switchPmText: String? = null, - switchPmParameter: String? = null + switchPmText: String?, + switchPmParameter: String? ) = answerInlineQuery(inlineQuery.id, results, cachedTime, isPersonal, nextOffset, switchPmText, switchPmParameter) suspend fun TelegramBot.answer( @@ -34,6 +64,6 @@ suspend fun TelegramBot.answer( cachedTime: Int? = null, isPersonal: Boolean? = null, nextOffset: String? = null, - switchPmText: String? = null, - switchPmParameter: String? = null + switchPmText: String?, + switchPmParameter: String? ) = answerInlineQuery(inlineQuery.id, results, cachedTime, isPersonal, nextOffset, switchPmText, switchPmParameter) diff --git a/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/bot/GetMyName.kt b/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/bot/GetMyName.kt new file mode 100644 index 00000000000..7db1ff1716c --- /dev/null +++ b/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/bot/GetMyName.kt @@ -0,0 +1,16 @@ +package dev.inmo.tgbotapi.extensions.api.bot + +import dev.inmo.micro_utils.language_codes.IetfLanguageCode +import dev.inmo.tgbotapi.bot.TelegramBot +import dev.inmo.tgbotapi.requests.bot.GetMyCommands +import dev.inmo.tgbotapi.requests.bot.GetMyName +import dev.inmo.tgbotapi.types.commands.BotCommandScope +import dev.inmo.tgbotapi.types.commands.BotCommandScopeDefault + +suspend fun TelegramBot.getMyName( + languageCode: IetfLanguageCode? = null +) = execute(GetMyName(languageCode)) + +suspend fun TelegramBot.getMyName( + languageCode: String? +) = getMyName(languageCode ?.let(::IetfLanguageCode)) diff --git a/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/bot/SetMyName.kt b/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/bot/SetMyName.kt new file mode 100644 index 00000000000..3af8abcbda7 --- /dev/null +++ b/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/bot/SetMyName.kt @@ -0,0 +1,19 @@ +package dev.inmo.tgbotapi.extensions.api.bot + +import dev.inmo.micro_utils.language_codes.IetfLanguageCode +import dev.inmo.tgbotapi.bot.TelegramBot +import dev.inmo.tgbotapi.requests.bot.GetMyCommands +import dev.inmo.tgbotapi.requests.bot.GetMyName +import dev.inmo.tgbotapi.requests.bot.SetMyName +import dev.inmo.tgbotapi.types.commands.BotCommandScope +import dev.inmo.tgbotapi.types.commands.BotCommandScopeDefault + +suspend fun TelegramBot.setMyName( + name: String? = null, + languageCode: IetfLanguageCode? = null +) = execute(SetMyName(name, languageCode)) + +suspend fun TelegramBot.setMyName( + name: String?, + languageCode: String? +) = setMyName(name, languageCode ?.let(::IetfLanguageCode)) diff --git a/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/edit/InlineEdits.kt b/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/edit/InlineEdits.kt new file mode 100644 index 00000000000..5f9f26f003b --- /dev/null +++ b/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/edit/InlineEdits.kt @@ -0,0 +1,114 @@ +package dev.inmo.tgbotapi.extensions.api.edit + +import dev.inmo.tgbotapi.abstracts.TextedWithTextSources +import dev.inmo.tgbotapi.bot.TelegramBot +import dev.inmo.tgbotapi.extensions.api.edit.caption.editMessageCaption +import dev.inmo.tgbotapi.extensions.api.edit.location.live.editLiveLocation +import dev.inmo.tgbotapi.extensions.api.edit.media.editMessageMedia +import dev.inmo.tgbotapi.extensions.api.edit.reply_markup.editMessageReplyMarkup +import dev.inmo.tgbotapi.extensions.api.edit.text.editMessageText +import dev.inmo.tgbotapi.types.* +import dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup +import dev.inmo.tgbotapi.types.chat.Chat +import dev.inmo.tgbotapi.types.location.LiveLocation +import dev.inmo.tgbotapi.types.media.TelegramMedia +import dev.inmo.tgbotapi.types.message.ParseMode +import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage +import dev.inmo.tgbotapi.types.message.abstracts.Message +import dev.inmo.tgbotapi.types.message.content.* +import dev.inmo.tgbotapi.types.message.textsources.TextSource +import dev.inmo.tgbotapi.types.message.textsources.TextSourcesList +import dev.inmo.tgbotapi.utils.EntitiesBuilderBody +import dev.inmo.tgbotapi.utils.buildEntities + +/** + * @param replyMarkup Some [InlineKeyboardMarkup]. See [dev.inmo.tgbotapi.extensions.utils.types.buttons.inlineKeyboard] + * as a builder for that + */ +suspend fun TelegramBot.edit( + messageId: InlineMessageIdentifier, + latitude: Double, + longitude: Double, + horizontalAccuracy: Meters? = null, + heading: Degrees? = null, + proximityAlertRadius: Meters? = null, + replyMarkup: InlineKeyboardMarkup? = null +) = editLiveLocation(messageId, latitude, longitude, horizontalAccuracy, heading, proximityAlertRadius, replyMarkup) + +/** + * @param replyMarkup Some [InlineKeyboardMarkup]. See [dev.inmo.tgbotapi.extensions.utils.types.buttons.inlineKeyboard] + * as a builder for that + */ +suspend fun TelegramBot.edit( + messageId: InlineMessageIdentifier, + location: LiveLocation, + replyMarkup: InlineKeyboardMarkup? = null +) = editLiveLocation( + messageId, location, replyMarkup +) + +/** + * @param replyMarkup Some [InlineKeyboardMarkup]. See [dev.inmo.tgbotapi.extensions.utils.types.buttons.inlineKeyboard] + * as a builder for that + */ +suspend fun TelegramBot.edit( + messageId: InlineMessageIdentifier, + media: TelegramMedia, + replyMarkup: InlineKeyboardMarkup? = null +) = editMessageMedia(messageId, media, replyMarkup) + +/** + * @param replyMarkup Some [InlineKeyboardMarkup]. See [dev.inmo.tgbotapi.extensions.utils.types.buttons.inlineKeyboard] + * as a builder for that + */ +suspend fun TelegramBot.edit( + messageId: InlineMessageIdentifier, + replyMarkup: InlineKeyboardMarkup? = null +) = editMessageReplyMarkup(messageId, replyMarkup) + +/** + * @param replyMarkup Some [InlineKeyboardMarkup]. See [dev.inmo.tgbotapi.extensions.utils.types.buttons.inlineKeyboard] + * as a builder for that + */ +suspend fun TelegramBot.edit( + messageId: InlineMessageIdentifier, + text: String, + parseMode: ParseMode? = null, + disableWebPagePreview: Boolean? = null, + replyMarkup: InlineKeyboardMarkup? = null +) = editMessageText(messageId, text, parseMode, disableWebPagePreview, replyMarkup) + +/** + * @param replyMarkup Some [InlineKeyboardMarkup]. See [dev.inmo.tgbotapi.extensions.utils.types.buttons.inlineKeyboard] + * as a builder for that + */ +suspend fun TelegramBot.edit( + messageId: InlineMessageIdentifier, + entities: TextSourcesList, + disableWebPagePreview: Boolean? = null, + replyMarkup: InlineKeyboardMarkup? = null +) = editMessageText(messageId, entities, disableWebPagePreview, replyMarkup) + +/** + * @param replyMarkup Some [InlineKeyboardMarkup]. See [dev.inmo.tgbotapi.extensions.utils.types.buttons.inlineKeyboard] + * as a builder for that + */ +suspend fun TelegramBot.edit( + messageId: InlineMessageIdentifier, + separator: TextSource? = null, + disableWebPagePreview: Boolean? = null, + replyMarkup: InlineKeyboardMarkup? = null, + builderBody: EntitiesBuilderBody +) = edit(messageId, buildEntities(separator, builderBody), disableWebPagePreview, replyMarkup) + +/** + * @param replyMarkup Some [InlineKeyboardMarkup]. See [dev.inmo.tgbotapi.extensions.utils.types.buttons.inlineKeyboard] + * as a builder for that + */ +suspend fun TelegramBot.edit( + messageId: InlineMessageIdentifier, + separator: String, + disableWebPagePreview: Boolean? = null, + replyMarkup: InlineKeyboardMarkup? = null, + builderBody: EntitiesBuilderBody +) = edit(messageId, buildEntities(separator, builderBody), disableWebPagePreview, replyMarkup) diff --git a/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/edit/media/EditInlineMessageMedia.kt b/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/edit/media/EditInlineMessageMedia.kt index 660e62bfcc4..20c6c9679a4 100644 --- a/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/edit/media/EditInlineMessageMedia.kt +++ b/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/edit/media/EditInlineMessageMedia.kt @@ -10,6 +10,17 @@ import dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup * @param replyMarkup Some [InlineKeyboardMarkup]. See [dev.inmo.tgbotapi.extensions.utils.types.buttons.inlineKeyboard] * as a builder for that */ +suspend fun TelegramBot.editMessageMedia( + inlineMessageId: InlineMessageIdentifier, + media: TelegramMedia, + replyMarkup: InlineKeyboardMarkup? = null +) = execute(EditInlineMessageMedia(inlineMessageId, media, replyMarkup)) + +/** + * @param replyMarkup Some [InlineKeyboardMarkup]. See [dev.inmo.tgbotapi.extensions.utils.types.buttons.inlineKeyboard] + * as a builder for that + */ +@Deprecated("Renamed", ReplaceWith("this.editMessageMedia(inlineMessageId, media, replyMarkup)", "dev.inmo.tgbotapi.extensions.api.edit.media.editMessageMedia")) suspend fun TelegramBot.editMessageCaption( inlineMessageId: InlineMessageIdentifier, media: TelegramMedia, diff --git a/tgbotapi.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/WaitDeepLinks.kt b/tgbotapi.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/WaitDeepLinks.kt index 129d7e72c17..b494adf0e61 100644 --- a/tgbotapi.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/WaitDeepLinks.kt +++ b/tgbotapi.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/WaitDeepLinks.kt @@ -21,3 +21,17 @@ suspend fun BehaviourContext.waitDeepLinks( .flattenCommandsWithParams().mapNotNull { it.first to (it.second.second.singleOrNull() ?.regularTextSourceOrNull() ?.source ?.removePrefix(" ") ?: return@mapNotNull null) } + +suspend fun BehaviourContext.waitDeepLinks( + regex: Regex, + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null }, +): Flow, String>> = waitDeepLinks(initRequest, errorFactory).filter { + regex.matches(it.second) +} + +suspend fun BehaviourContext.waitDeepLinks( + deepLink: String, + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null }, +): Flow, String>> = waitDeepLinks(Regex("^$deepLink$"), initRequest, errorFactory) diff --git a/tgbotapi.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/triggers_handling/DeepLinkHandling.kt b/tgbotapi.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/triggers_handling/DeepLinkHandling.kt index b713c2b1c93..62e38cda02c 100644 --- a/tgbotapi.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/triggers_handling/DeepLinkHandling.kt +++ b/tgbotapi.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/triggers_handling/DeepLinkHandling.kt @@ -46,3 +46,24 @@ suspend fun BC.onDeepLink( this@onDeepLink.launchSafelyWithoutExceptions { triggersHolder.handleableCommandsHolder.unregisterHandleable(startRegex) } } } + +suspend fun BC.onDeepLink( + regex: Regex, + initialFilter: SimpleFilter>? = null, + subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver, Update> = { (message, _), update -> MessageFilterByChat(this, message, update) }, + markerFactory: MarkerFactory, Any> = MarkerFactory { (message, _) -> ByChatMessageMarkerFactory(message) }, + scenarioReceiver: CustomBehaviourContextAndTypeReceiver> +): Job { + val internalFilter = SimpleFilter> { + regex.matches(it.second) + } + return onDeepLink(initialFilter ?.let { internalFilter * it } ?: internalFilter, subcontextUpdatesFilter, markerFactory, scenarioReceiver) +} + +suspend fun BC.onDeepLink( + deepLink: String, + initialFilter: SimpleFilter>? = null, + subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver, Update> = { (message, _), update -> MessageFilterByChat(this, message, update) }, + markerFactory: MarkerFactory, Any> = MarkerFactory { (message, _) -> ByChatMessageMarkerFactory(message) }, + scenarioReceiver: CustomBehaviourContextAndTypeReceiver> +): Job = onDeepLink(Regex("^$deepLink$"), initialFilter, subcontextUpdatesFilter, markerFactory, scenarioReceiver) diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/answers/AnswerInlineQuery.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/answers/AnswerInlineQuery.kt index e721e2389bc..7058ae061a4 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/answers/AnswerInlineQuery.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/answers/AnswerInlineQuery.kt @@ -23,11 +23,30 @@ data class AnswerInlineQuery( val isPersonal: Boolean? = null, @SerialName(nextOffsetField) val nextOffset: String? = null, - @SerialName(switchPmTextField) - val switchPmText: String? = null, - @SerialName(switchPmParameterField) - val switchPmParameter: String? = null + @SerialName(buttonField) + val button: InlineQueryResultsButton? = null, ) : SimpleRequest { + constructor( + inlineQueryID: InlineQueryIdentifier, + results: List = emptyList(), + cachedTime: Int? = null, + isPersonal: Boolean? = null, + nextOffset: String? = null, + switchPmText: String?, + switchPmParameter: String? + ) : this( + inlineQueryID, + results, + cachedTime, + isPersonal, + nextOffset, + switchPmText ?.let { + switchPmParameter ?.let { + InlineQueryResultsButton.Start(switchPmText, switchPmParameter) + } + } + ) + override fun method(): String = "answerInlineQuery" override val resultDeserializer: DeserializationStrategy get() = Boolean.serializer() @@ -40,8 +59,23 @@ fun InlineQuery.createAnswer( cachedTime: Int? = null, isPersonal: Boolean? = null, nextOffset: String? = null, - switchPmText: String? = null, - switchPmParameter: String? = null + button: InlineQueryResultsButton? = null, +) = AnswerInlineQuery( + id, + results, + cachedTime, + isPersonal, + nextOffset, + button +) + +fun InlineQuery.createAnswer( + results: List = emptyList(), + cachedTime: Int? = null, + isPersonal: Boolean? = null, + nextOffset: String? = null, + switchPmText: String?, + switchPmParameter: String? ) = AnswerInlineQuery( id, results, diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/answers/InlineQueryResultsButton.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/answers/InlineQueryResultsButton.kt new file mode 100644 index 00000000000..4cc8bf71b05 --- /dev/null +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/answers/InlineQueryResultsButton.kt @@ -0,0 +1,89 @@ +package dev.inmo.tgbotapi.requests.answers + +import dev.inmo.micro_utils.common.Warning +import dev.inmo.tgbotapi.types.StartParameter +import dev.inmo.tgbotapi.types.startParameterField +import dev.inmo.tgbotapi.types.textField +import dev.inmo.tgbotapi.types.webAppField +import dev.inmo.tgbotapi.types.webapps.WebAppInfo +import dev.inmo.tgbotapi.utils.internal.ClassCastsIncluded +import kotlinx.serialization.KSerializer +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder + +@Serializable(InlineQueryResultsButtonSerializer::class) +@ClassCastsIncluded +sealed interface InlineQueryResultsButton { + val text: String + + @Serializable + class Raw internal constructor( + @SerialName(textField) + val text: String, + @SerialName(webAppField) + val webAppInfo: WebAppInfo? = null, + @SerialName(startParameterField) + val deepLinkParameter: String? = null + ) + + @Serializable(InlineQueryResultsButtonSerializer::class) + data class WebApp( + @SerialName(textField) + override val text: String, + @SerialName(webAppField) + val webAppInfo: WebAppInfo + ) : InlineQueryResultsButton + + @Serializable(InlineQueryResultsButtonSerializer::class) + data class Start( + @SerialName(textField) + override val text: String, + @SerialName(startParameterField) + val deepLinkParameter: String + ) : InlineQueryResultsButton + + @Serializable(InlineQueryResultsButtonSerializer::class) + data class Unknown internal constructor ( + @SerialName(textField) + override val text: String + ) : InlineQueryResultsButton + + companion object { + operator fun invoke( + text: String, + deepLinkParameter: String + ) = Start(text, deepLinkParameter) + operator fun invoke( + text: String, + webAppInfo: WebAppInfo + ) = WebApp(text, webAppInfo) + } +} + +object InlineQueryResultsButtonSerializer : KSerializer { + override val descriptor: SerialDescriptor = InlineQueryResultsButton.Raw.serializer().descriptor + + override fun deserialize(decoder: Decoder): InlineQueryResultsButton { + val raw = InlineQueryResultsButton.Raw.serializer().deserialize(decoder) + + return when { + raw.webAppInfo != null -> InlineQueryResultsButton.WebApp(raw.text, raw.webAppInfo) + raw.deepLinkParameter != null -> InlineQueryResultsButton.Start(raw.text, raw.deepLinkParameter) + else -> InlineQueryResultsButton.Unknown(raw.text) + } + } + + override fun serialize(encoder: Encoder, value: InlineQueryResultsButton) { + InlineQueryResultsButton.Raw.serializer().serialize( + encoder, + InlineQueryResultsButton.Raw( + value.text, + (value as? InlineQueryResultsButton.WebApp)?.webAppInfo, + (value as? InlineQueryResultsButton.Start)?.deepLinkParameter, + ) + ) + } +} diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/bot/GetMyName.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/bot/GetMyName.kt new file mode 100644 index 00000000000..94c606ef2b0 --- /dev/null +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/bot/GetMyName.kt @@ -0,0 +1,23 @@ +package dev.inmo.tgbotapi.requests.bot + +import dev.inmo.micro_utils.language_codes.IetfLanguageCode +import dev.inmo.micro_utils.language_codes.IetfLanguageCodeSerializer +import dev.inmo.tgbotapi.requests.abstracts.SimpleRequest +import dev.inmo.tgbotapi.types.* +import dev.inmo.tgbotapi.types.abstracts.WithOptionalLanguageCode +import dev.inmo.tgbotapi.types.commands.* +import kotlinx.serialization.* +import kotlinx.serialization.builtins.serializer + +@Serializable +class GetMyName( + @SerialName(languageCodeField) + @Serializable(IetfLanguageCodeSerializer::class) + override val ietfLanguageCode: IetfLanguageCode? = null +) : SimpleRequest, WithOptionalLanguageCode { + override fun method(): String = "getMyName" + override val resultDeserializer: DeserializationStrategy + get() = BotName.serializer() + override val requestSerializer: SerializationStrategy<*> + get() = serializer() +} diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/bot/SetMyName.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/bot/SetMyName.kt new file mode 100644 index 00000000000..f1d867dd5e9 --- /dev/null +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/bot/SetMyName.kt @@ -0,0 +1,25 @@ +package dev.inmo.tgbotapi.requests.bot + +import dev.inmo.micro_utils.language_codes.IetfLanguageCode +import dev.inmo.micro_utils.language_codes.IetfLanguageCodeSerializer +import dev.inmo.tgbotapi.requests.abstracts.SimpleRequest +import dev.inmo.tgbotapi.types.* +import dev.inmo.tgbotapi.types.abstracts.WithOptionalLanguageCode +import dev.inmo.tgbotapi.types.commands.* +import kotlinx.serialization.* +import kotlinx.serialization.builtins.serializer + +@Serializable +class SetMyName( + @SerialName(nameField) + val name: String? = null, + @SerialName(languageCodeField) + @Serializable(IetfLanguageCodeSerializer::class) + override val ietfLanguageCode: IetfLanguageCode? = null +) : SimpleRequest, WithOptionalLanguageCode { + override fun method(): String = "setMyName" + override val resultDeserializer: DeserializationStrategy + get() = Boolean.serializer() + override val requestSerializer: SerializationStrategy<*> + get() = serializer() +} diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/BotName.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/BotName.kt new file mode 100644 index 00000000000..59f5a7db57a --- /dev/null +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/BotName.kt @@ -0,0 +1,10 @@ +package dev.inmo.tgbotapi.types + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class BotName( + @SerialName(nameField) + val name: String +) diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/ChatIdentifier.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/ChatIdentifier.kt index 872bda30e31..b870ad90ffd 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/ChatIdentifier.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/ChatIdentifier.kt @@ -13,8 +13,9 @@ import kotlinx.serialization.json.JsonPrimitive import kotlinx.serialization.json.longOrNull import kotlin.jvm.JvmInline +const val internalTgAppLinksBeginning = "tg://" const val internalLinkBeginning = "https://t.me" -const val internalUserLinkBeginning = "tg://user?id=" +const val internalUserLinkBeginning = "${internalTgAppLinksBeginning}user?id=" @Serializable(ChatIdentifierSerializer::class) @ClassCastsIncluded diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/Common.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/Common.kt index 73fa5dec7b9..ebcbf22d6ca 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/Common.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/Common.kt @@ -41,7 +41,10 @@ typealias WebAppQueryId = String @JvmInline value class CustomEmojiId( val string: String -) +) { + val appLink + get() = "${internalTgAppLinksBeginning}emoji?id=$this" +} typealias Seconds = Int typealias MilliSeconds = Long @@ -247,10 +250,15 @@ const val errorMessageField = "error_message" const val messageTextField = "message_text" const val isPersonalField = "is_personal" const val nextOffsetField = "next_offset" +const val buttonField = "button" const val switchPmTextField = "switch_pm_text" const val switchPmParameterField = "switch_pm_parameter" const val maxAllowedConnectionsField = "max_connections" const val allowedUpdatesField = "allowed_updates" +const val allowUserChatsField = "allow_user_chats" +const val allowBotChatsField = "allow_bot_chats" +const val allowGroupChatsField = "allow_group_chats" +const val allowChannelChatsField = "allow_channel_chats" const val dropPendingUpdatesField = "drop_pending_updates" const val secretTokenField = "secret_token" const val hasCustomCertificateField = "has_custom_certificate" @@ -271,10 +279,12 @@ const val loginUrlField = "login_url" const val forwardTextField = "forward_text" const val botUsernameField = "bot_username" const val switchInlineQueryCurrentChatField = "switch_inline_query_current_chat" +const val switchInlineQueryChosenChatField = "switch_inline_query_chosen_chat" const val switchInlineQueryField = "switch_inline_query" const val isAnimatedField = "is_animated" const val isVideoField = "is_video" const val inviteLinkField = "invite_link" +const val viaChatFolderInviteLinkField = "via_chat_folder_invite_link" const val pinnedMessageField = "pinned_message" const val activeUsernamesField = "active_usernames" const val customTitleField = "custom_title" @@ -596,4 +606,5 @@ const val temporaryRegistrationField = "temporary_registration" const val buttonTextField = "button_text" const val webAppField = "web_app" +const val webAppNameField = "web_app_name" const val menuButtonField = "menu_button" diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/UpdateTypes.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/UpdateTypes.kt index 913015c988b..11e84ff6257 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/UpdateTypes.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/UpdateTypes.kt @@ -11,9 +11,15 @@ const val UPDATE_SHIPPING_QUERY = "shipping_query" const val UPDATE_PRE_CHECKOUT_QUERY = "pre_checkout_query" const val UPDATE_POLL = "poll" const val UPDATE_POLL_ANSWER = "poll_answer" -const val MY_CHAT_MEMBER = "my_chat_member" -const val CHAT_MEMBER = "chat_member" -const val CHAT_JOIN_REQUEST = "chat_join_request" +const val UPDATE_MY_CHAT_MEMBER = "my_chat_member" +const val UPDATE_CHAT_MEMBER = "chat_member" +const val UPDATE_CHAT_JOIN_REQUEST = "chat_join_request" +@Deprecated("Renamed", ReplaceWith("UPDATE_MY_CHAT_MEMBER", "dev.inmo.tgbotapi.types.UPDATE_MY_CHAT_MEMBER")) +const val MY_CHAT_MEMBER = UPDATE_MY_CHAT_MEMBER +@Deprecated("Renamed", ReplaceWith("UPDATE_CHAT_MEMBER", "dev.inmo.tgbotapi.types.UPDATE_CHAT_MEMBER")) +const val CHAT_MEMBER = UPDATE_CHAT_MEMBER +@Deprecated("Renamed", ReplaceWith("UPDATE_CHAT_JOIN_REQUEST", "dev.inmo.tgbotapi.types.UPDATE_CHAT_JOIN_REQUEST")) +const val CHAT_JOIN_REQUEST = UPDATE_CHAT_JOIN_REQUEST val ALL_UPDATES_LIST = listOf( UPDATE_MESSAGE, @@ -27,7 +33,7 @@ val ALL_UPDATES_LIST = listOf( UPDATE_PRE_CHECKOUT_QUERY, UPDATE_POLL, UPDATE_POLL_ANSWER, - MY_CHAT_MEMBER, - CHAT_MEMBER, - CHAT_JOIN_REQUEST + UPDATE_MY_CHAT_MEMBER, + UPDATE_CHAT_MEMBER, + UPDATE_CHAT_JOIN_REQUEST ) diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/InlineKeyboardButtons/InlineKeyboardButton.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/InlineKeyboardButtons/InlineKeyboardButton.kt index 6c31cdccee5..f5ff00faf2f 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/InlineKeyboardButtons/InlineKeyboardButton.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/InlineKeyboardButtons/InlineKeyboardButton.kt @@ -98,6 +98,23 @@ data class SwitchInlineQueryCurrentChatInlineKeyboardButton( val switchInlineQueryCurrentChat: String ) : InlineKeyboardButton +/** + * Complex button with [switchInlineQueryCurrentChat] which will be sent to you in an [dev.inmo.tgbotapi.types.InlineQueries.query.InlineQuery] + * which you may catch in [dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onBaseInlineQuery] and get + * from [dev.inmo.tgbotapi.types.InlineQueries.query.BaseInlineQuery.query] (or changed by user query in case he will be + * the fastest hand in the wild west). Can be forwarded in any chat with message in case if it is the only one button in + * message, but will be converted to a [SwitchInlineQueryInlineKeyboardButton]. + * Remember that clicking on this button will automatically insert username of this bot in current chat, paste + * [switchInlineQueryCurrentChat] as a query and create and inline request to your bot + * Visit https://core.telegram.org/bots/api#inlinekeyboardbutton for more info + */ +@Serializable +data class SwitchInlineQueryChosenChatInlineKeyboardButton( + override val text: String, + @SerialName(switchInlineQueryChosenChatField) + val parameters: SwitchInlineQueryChosenChat +) : InlineKeyboardButton + /** * Complex button with [switchInlineQuery] which will be sent to you in an [dev.inmo.tgbotapi.types.InlineQueries.query.InlineQuery] * which you may catch in [dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onBaseInlineQuery] and get diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/InlineKeyboardButtons/InlineKeyboardButtonSerializer.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/InlineKeyboardButtons/InlineKeyboardButtonSerializer.kt index 70005d12c72..99b3e06ea55 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/InlineKeyboardButtons/InlineKeyboardButtonSerializer.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/InlineKeyboardButtons/InlineKeyboardButtonSerializer.kt @@ -27,6 +27,7 @@ object InlineKeyboardButtonSerializer : KSerializer { json[payField] != null -> PayInlineKeyboardButton.serializer() json[switchInlineQueryField] != null -> SwitchInlineQueryInlineKeyboardButton.serializer() json[switchInlineQueryCurrentChatField] != null -> SwitchInlineQueryCurrentChatInlineKeyboardButton.serializer() + json[switchInlineQueryChosenChatField] != null -> SwitchInlineQueryChosenChatInlineKeyboardButton.serializer() json[urlField] != null -> URLInlineKeyboardButton.serializer() else -> null } @@ -47,6 +48,7 @@ object InlineKeyboardButtonSerializer : KSerializer { is PayInlineKeyboardButton -> PayInlineKeyboardButton.serializer().serialize(encoder, value) is SwitchInlineQueryInlineKeyboardButton -> SwitchInlineQueryInlineKeyboardButton.serializer().serialize(encoder, value) is SwitchInlineQueryCurrentChatInlineKeyboardButton -> SwitchInlineQueryCurrentChatInlineKeyboardButton.serializer().serialize(encoder, value) + is SwitchInlineQueryChosenChatInlineKeyboardButton -> SwitchInlineQueryChosenChatInlineKeyboardButton.serializer().serialize(encoder, value) is URLInlineKeyboardButton -> URLInlineKeyboardButton.serializer().serialize(encoder, value) is WebAppInlineKeyboardButton -> WebAppInlineKeyboardButton.serializer().serialize(encoder, value) is CallbackGameInlineKeyboardButton -> CallbackGameInlineKeyboardButton.serializer().serialize(encoder, value) diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/InlineKeyboardButtons/SwitchInlineQueryChosenChat.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/InlineKeyboardButtons/SwitchInlineQueryChosenChat.kt new file mode 100644 index 00000000000..186a9fdb97f --- /dev/null +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/InlineKeyboardButtons/SwitchInlineQueryChosenChat.kt @@ -0,0 +1,32 @@ +package dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons + +import dev.inmo.tgbotapi.types.* +import kotlinx.serialization.EncodeDefault +import kotlinx.serialization.ExperimentalSerializationApi +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@OptIn(ExperimentalSerializationApi::class) +@Serializable +data class SwitchInlineQueryChosenChat ( + @SerialName(queryField) + val query: String? = null, + @SerialName(allowUserChatsField) + @EncodeDefault + val allowUsers: Boolean = false, + @SerialName(allowBotChatsField) + @EncodeDefault + val allowBots: Boolean = false, + @SerialName(allowGroupChatsField) + @EncodeDefault + val allowGroups: Boolean = false, + @SerialName(allowChannelChatsField) + @EncodeDefault + val allowChannels: Boolean = false, +) { + init { + require(allowUsers || allowBots || allowGroups || allowChannels) { + "Bot must allow to choose at least one of available variants in choosing of inline query recipient" + } + } +} diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/inline/InlineKeyboardButtonsShortcuts.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/inline/InlineKeyboardButtonsShortcuts.kt index 9f148a98fe4..da81c825470 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/inline/InlineKeyboardButtonsShortcuts.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/inline/InlineKeyboardButtonsShortcuts.kt @@ -57,6 +57,52 @@ inline fun inlineQueryInCurrentChatInlineButton( data: String ) = SwitchInlineQueryCurrentChatInlineKeyboardButton(text, data) +/** + * Creates and put [SwitchInlineQueryChosenChatInlineKeyboardButton] + * + * @see inlineKeyboard + * @see InlineKeyboardBuilder.row + */ +inline fun inlineQueryInCurrentChatInlineButton( + text: String, + parameters: SwitchInlineQueryChosenChat +) = SwitchInlineQueryChosenChatInlineKeyboardButton(text, parameters) + +/** + * Creates and put [SwitchInlineQueryChosenChatInlineKeyboardButton] + * + * @see inlineKeyboard + * @see InlineKeyboardBuilder.row + */ +inline fun inlineQueryInCurrentChatInlineButton( + text: String, + query: String? = null, + allowUsers: Boolean = false, + allowBots: Boolean = false, + allowGroups: Boolean = false, + allowChannels: Boolean = false, +) = inlineQueryInCurrentChatInlineButton( + text, + SwitchInlineQueryChosenChat( + query = query, + allowUsers = allowUsers, + allowBots = allowBots, + allowGroups = allowGroups, + allowChannels = allowChannels + ) +) + +/** + * Creates and put [SwitchInlineQueryChosenChatInlineKeyboardButton] + * + * @see inlineKeyboard + * @see InlineKeyboardBuilder.row + */ +inline fun inlineQueryInAnyCurrentChatInlineButton( + text: String, + query: String? = null, +) = inlineQueryInCurrentChatInlineButton(text, query, allowUsers = true, allowBots = true, allowGroups = true, allowChannels = true) + /** * Creates and put [SwitchInlineQueryInlineKeyboardButton] * diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/chat/member/ChatMemberUpdated.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/chat/member/ChatMemberUpdated.kt index 81f4ac184b4..8539a0c76ed 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/chat/member/ChatMemberUpdated.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/chat/member/ChatMemberUpdated.kt @@ -21,5 +21,7 @@ data class ChatMemberUpdated( @SerialName(newChatMemberField) val newChatMemberState: ChatMember, @SerialName(inviteLinkField) - val inviteLink: ChatInviteLink? = null + val inviteLink: ChatInviteLink? = null, + @SerialName(viaChatFolderInviteLinkField) + val viaChatFolderInviteLink: Boolean? = false ) : WithChat, WithUser diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/ChatEvents/forum/WriteAccessAllowed.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/ChatEvents/forum/WriteAccessAllowed.kt index 6cd4ad5a67f..2d6a630f5b4 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/ChatEvents/forum/WriteAccessAllowed.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/ChatEvents/forum/WriteAccessAllowed.kt @@ -1,7 +1,12 @@ package dev.inmo.tgbotapi.types.message.ChatEvents.forum import dev.inmo.tgbotapi.types.message.ChatEvents.abstracts.ForumEvent +import dev.inmo.tgbotapi.types.webAppNameField +import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @Serializable -object WriteAccessAllowed : ForumEvent +data class WriteAccessAllowed( + @SerialName(webAppNameField) + val webAppName: String? = null +) : ForumEvent diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/textsources/CustomEmojiTextSource.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/textsources/CustomEmojiTextSource.kt index 01a68e19352..cc958faf5af 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/textsources/CustomEmojiTextSource.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/textsources/CustomEmojiTextSource.kt @@ -16,8 +16,8 @@ data class CustomEmojiTextSource @RiskFeature(DirectInvocationOfTextSourceConstr override val subsources: TextSourcesList ) : MultilevelTextSource { override val markdown: String by lazy { source.customEmojiMarkdown() } - override val markdownV2: String by lazy { source.customEmojiMarkdownV2() } - override val html: String by lazy { source.customEmojiHTML() } + override val markdownV2: String by lazy { source.customEmojiMarkdownV2(customEmojiId) } + override val html: String by lazy { source.customEmojiHTML(customEmojiId) } } @Suppress("NOTHING_TO_INLINE", "EXPERIMENTAL_API_USAGE") diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/utils/internal/StringFormatting.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/utils/internal/StringFormatting.kt index 6a5ee9091a5..ce3a22f25e5 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/utils/internal/StringFormatting.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/utils/internal/StringFormatting.kt @@ -24,6 +24,7 @@ const val htmlCodeControl = "code" const val htmlPreControl = "pre" const val htmlUnderlineControl = "u" const val htmlStrikethroughControl = "s" +const val htmlCustomEmojiControl = "tg-emoji" private fun String.markdownDefault( openControlSymbol: String, @@ -120,8 +121,8 @@ internal fun String.commandMarkdownV2(): String = command(String::escapeMarkdown internal fun String.commandHTML(): String = command(String::toHtml) internal fun String.customEmojiMarkdown(): String = toMarkdown() -internal fun String.customEmojiMarkdownV2(): String = escapeMarkdownV2Common() -internal fun String.customEmojiHTML(): String = toHtml() +internal fun String.customEmojiMarkdownV2(customEmojiId: CustomEmojiId): String = "!${linkMarkdownV2(customEmojiId.appLink)}" +internal fun String.customEmojiHTML(customEmojiId: CustomEmojiId): String = "<$htmlCustomEmojiControl $htmlCustomEmojiControl=\"${customEmojiId.string}\">$this" internal fun String.regularMarkdown(): String = toMarkdown() internal fun String.regularMarkdownV2(): String = escapeMarkdownV2Common() diff --git a/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/ClassCastsNew.kt b/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/ClassCastsNew.kt index b8f5a82e4f0..0f55cd2733f 100644 --- a/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/ClassCastsNew.kt +++ b/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/ClassCastsNew.kt @@ -12,6 +12,7 @@ package dev.inmo.tgbotapi.extensions.utils import dev.inmo.tgbotapi.abstracts.CommonSendInvoiceData import dev.inmo.tgbotapi.abstracts.FromUser import dev.inmo.tgbotapi.abstracts.WithUser +import dev.inmo.tgbotapi.requests.answers.InlineQueryResultsButton import dev.inmo.tgbotapi.requests.send.payments.CreateInvoiceLink import dev.inmo.tgbotapi.requests.send.payments.SendInvoice import dev.inmo.tgbotapi.requests.stickers.InputSticker @@ -108,6 +109,7 @@ import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.CallbackGameInlineK import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.InlineKeyboardButton import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.LoginURLInlineKeyboardButton import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.PayInlineKeyboardButton +import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.SwitchInlineQueryChosenChatInlineKeyboardButton import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.SwitchInlineQueryCurrentChatInlineKeyboardButton import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.SwitchInlineQueryInlineKeyboardButton import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.URLInlineKeyboardButton @@ -1013,6 +1015,36 @@ public inline fun WithUser.ifMessageGameShortNameCallbackQuery(block: (MessageGameShortNameCallbackQuery) -> T): T? = messageGameShortNameCallbackQueryOrNull() ?.let(block) +public inline fun InlineQueryResultsButton.startOrNull(): InlineQueryResultsButton.Start? = this as? + dev.inmo.tgbotapi.requests.answers.InlineQueryResultsButton.Start + +public inline fun InlineQueryResultsButton.startOrThrow(): InlineQueryResultsButton.Start = this as + dev.inmo.tgbotapi.requests.answers.InlineQueryResultsButton.Start + +public inline fun + InlineQueryResultsButton.ifStart(block: (InlineQueryResultsButton.Start) -> T): T? = + startOrNull() ?.let(block) + +public inline fun InlineQueryResultsButton.unknownOrNull(): InlineQueryResultsButton.Unknown? = this + as? dev.inmo.tgbotapi.requests.answers.InlineQueryResultsButton.Unknown + +public inline fun InlineQueryResultsButton.unknownOrThrow(): InlineQueryResultsButton.Unknown = this + as dev.inmo.tgbotapi.requests.answers.InlineQueryResultsButton.Unknown + +public inline fun + InlineQueryResultsButton.ifUnknown(block: (InlineQueryResultsButton.Unknown) -> T): T? = + unknownOrNull() ?.let(block) + +public inline fun InlineQueryResultsButton.webAppOrNull(): InlineQueryResultsButton.WebApp? = this + as? dev.inmo.tgbotapi.requests.answers.InlineQueryResultsButton.WebApp + +public inline fun InlineQueryResultsButton.webAppOrThrow(): InlineQueryResultsButton.WebApp = this + as dev.inmo.tgbotapi.requests.answers.InlineQueryResultsButton.WebApp + +public inline fun + InlineQueryResultsButton.ifWebApp(block: (InlineQueryResultsButton.WebApp) -> T): T? = + webAppOrNull() ?.let(block) + public inline fun InputSticker.maskOrNull(): InputSticker.Mask? = this as? dev.inmo.tgbotapi.requests.stickers.InputSticker.Mask @@ -1898,6 +1930,18 @@ public inline fun InlineKeyboardButton.ifSwitchInlineQueryCurrentChatInlineKeyboardButton(block: (SwitchInlineQueryCurrentChatInlineKeyboardButton) -> T): T? = switchInlineQueryCurrentChatInlineKeyboardButtonOrNull() ?.let(block) +public inline fun InlineKeyboardButton.switchInlineQueryChosenChatInlineKeyboardButtonOrNull(): + SwitchInlineQueryChosenChatInlineKeyboardButton? = this as? + dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.SwitchInlineQueryChosenChatInlineKeyboardButton + +public inline fun InlineKeyboardButton.switchInlineQueryChosenChatInlineKeyboardButtonOrThrow(): + SwitchInlineQueryChosenChatInlineKeyboardButton = this as + dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.SwitchInlineQueryChosenChatInlineKeyboardButton + +public inline fun + InlineKeyboardButton.ifSwitchInlineQueryChosenChatInlineKeyboardButton(block: (SwitchInlineQueryChosenChatInlineKeyboardButton) -> T): + T? = switchInlineQueryChosenChatInlineKeyboardButtonOrNull() ?.let(block) + public inline fun InlineKeyboardButton.switchInlineQueryInlineKeyboardButtonOrNull(): SwitchInlineQueryInlineKeyboardButton? = this as? dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.SwitchInlineQueryInlineKeyboardButton diff --git a/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/types/buttons/InlineKeyboardBuilder.kt b/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/types/buttons/InlineKeyboardBuilder.kt index 06e844e9e12..796f06ce7c7 100644 --- a/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/types/buttons/InlineKeyboardBuilder.kt +++ b/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/types/buttons/InlineKeyboardBuilder.kt @@ -103,6 +103,45 @@ inline fun InlineKeyboardRowBuilder.inlineQueryInCurrentChatButton( data: String ) = add(SwitchInlineQueryCurrentChatInlineKeyboardButton(text, data)) +/** + * Creates and put [SwitchInlineQueryChosenChatInlineKeyboardButton] + * + * @see inlineKeyboard + * @see InlineKeyboardBuilder.row + */ +inline fun InlineKeyboardRowBuilder.inlineQueryInChosenChatButton( + text: String, + parameters: SwitchInlineQueryChosenChat +) = add(SwitchInlineQueryChosenChatInlineKeyboardButton(text, parameters)) + +/** + * Creates and put [SwitchInlineQueryChosenChatInlineKeyboardButton] + * + * @see inlineKeyboard + * @see InlineKeyboardBuilder.row + */ +inline fun InlineKeyboardRowBuilder.inlineQueryInChosenChatButton( + text: String, + query: String? = null, + allowUsers: Boolean = false, + allowBots: Boolean = false, + allowGroups: Boolean = false, + allowChannels: Boolean = false, +) = inlineQueryInChosenChatButton( + text, + SwitchInlineQueryChosenChat( + query = query, + allowUsers = allowUsers, + allowBots = allowBots, + allowGroups = allowGroups, + allowChannels = allowChannels + ) +) +inline fun InlineKeyboardRowBuilder.inlineQueryInAnyChosenChatButton( + text: String, + query: String? = null, +) = inlineQueryInChosenChatButton(text, query, allowUsers = true, allowBots = true, allowGroups = true, allowChannels = true) + /** * Creates and put [SwitchInlineQueryInlineKeyboardButton] *