diff --git a/CHANGELOG.md b/CHANGELOG.md index 9045fe7f92..a6fcaa13d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,16 @@ # TelegramBotAPI changelog +## 3.1.0 + +**This update contains including of Bot API 6.2** + +* `Versions`: + * `Ktor`: `2.0.3` -> `2.1.0` + * `MicroUtils`: `0.12.0` -> `0.12.1` +* `Core`: + * Add support of `custom emoji`s + * Add support of `sticker_type` + ## 3.0.2 **ALL OLD DEPRECATIONS HAVE BEEN REMOVED** diff --git a/README.md b/README.md index 57749cc97f..d60597acac 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.1-blue)](https://core.telegram.org/bots/api-changelog#june-20-2022) +# 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.2-blue)](https://core.telegram.org/bots/api-changelog#august-12-2022) | 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 190ca33ac5..6ca3ff5cb4 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,4 +6,4 @@ kotlin.incremental=true kotlin.incremental.js=true library_group=dev.inmo -library_version=3.0.2 +library_version=3.1.0 diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 3674f3a5cc..0eb6cd212b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -8,12 +8,12 @@ javax-activation = "1.1.1" korlibs = "3.0.0" uuid = "0.5.0" -ktor = "2.0.3" +ktor = "2.1.0" ksp = "1.7.10-1.0.6" kotlin-poet = "1.12.0" -microutils = "0.12.0" +microutils = "0.12.1" github-release-plugin = "2.4.1" diff --git a/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/get/GetCustomEmojiStickers.kt b/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/get/GetCustomEmojiStickers.kt new file mode 100644 index 0000000000..60e3784a8d --- /dev/null +++ b/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/get/GetCustomEmojiStickers.kt @@ -0,0 +1,37 @@ +package dev.inmo.tgbotapi.extensions.api.get + +import dev.inmo.tgbotapi.bot.TelegramBot +import dev.inmo.tgbotapi.requests.get.GetCustomEmojiStickers +import dev.inmo.tgbotapi.requests.get.GetStickerSet +import dev.inmo.tgbotapi.types.CustomEmojiId +import dev.inmo.tgbotapi.types.files.Sticker +import kotlin.js.JsName +import kotlin.jvm.JvmName + +suspend fun TelegramBot.getCustomEmojiStickers( + customEmojiIds: List +) = execute( + GetCustomEmojiStickers(customEmojiIds) +) + +@JvmName("getCustomEmojiStickersWithStringsList") +@JsName("getCustomEmojiStickersWithStringsList") +suspend fun TelegramBot.getCustomEmojiStickers( + customEmojiIds: List +) = getCustomEmojiStickers(customEmojiIds.map(::CustomEmojiId)) + +suspend fun TelegramBot.getCustomEmojiStickerOrNull( + customEmojiId: CustomEmojiId +) = getCustomEmojiStickers(listOf(customEmojiId)).firstOrNull() + +suspend fun TelegramBot.getCustomEmojiStickerOrThrow( + customEmojiId: CustomEmojiId +) = getCustomEmojiStickers(listOf(customEmojiId)).first() + +suspend fun TelegramBot.getCustomEmojiStickerOrNull( + customEmojiId: String +) = getCustomEmojiStickerOrNull(CustomEmojiId(customEmojiId)) + +suspend fun TelegramBot.getCustomEmojiStickerOrThrow( + customEmojiId: String +) = getCustomEmojiStickerOrThrow(CustomEmojiId(customEmojiId)) diff --git a/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/stickers/CreateNewMaskAnimatedStickerSet.kt b/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/stickers/CreateNewMaskAnimatedStickerSet.kt new file mode 100644 index 0000000000..23dea7d300 --- /dev/null +++ b/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/stickers/CreateNewMaskAnimatedStickerSet.kt @@ -0,0 +1,54 @@ +package dev.inmo.tgbotapi.extensions.api.stickers + +import dev.inmo.tgbotapi.bot.TelegramBot +import dev.inmo.tgbotapi.requests.abstracts.FileId +import dev.inmo.tgbotapi.requests.abstracts.MultipartFile +import dev.inmo.tgbotapi.requests.stickers.* +import dev.inmo.tgbotapi.types.chat.CommonUser +import dev.inmo.tgbotapi.types.UserId +import dev.inmo.tgbotapi.types.stickers.MaskPosition + +suspend fun TelegramBot.createNewMaskAnimatedStickerSet( + userId: UserId, + name: String, + title: String, + sticker: FileId, + emojis: String, + maskPosition: MaskPosition +) = execute( + CreateNewMaskAnimatedStickerSet(userId, name, title, sticker, emojis, maskPosition) +) + +suspend fun TelegramBot.createNewMaskAnimatedStickerSet( + userId: UserId, + name: String, + title: String, + sticker: MultipartFile, + emojis: String, + maskPosition: MaskPosition +) = execute( + CreateNewMaskAnimatedStickerSet(userId, name, title, sticker, emojis, maskPosition) +) + + +suspend fun TelegramBot.createNewMaskAnimatedStickerSet( + user: CommonUser, + name: String, + title: String, + sticker: FileId, + emojis: String, + maskPosition: MaskPosition +) = createNewMaskAnimatedStickerSet( + user.id, name, title, sticker, emojis, maskPosition +) + +suspend fun TelegramBot.createNewMaskAnimatedStickerSet( + user: CommonUser, + name: String, + title: String, + sticker: MultipartFile, + emojis: String, + maskPosition: MaskPosition +) = createNewMaskAnimatedStickerSet( + user.id, name, title, sticker, emojis, maskPosition +) diff --git a/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/stickers/CreateNewMaskStickerSet.kt b/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/stickers/CreateNewMaskStickerSet.kt new file mode 100644 index 0000000000..743f19300f --- /dev/null +++ b/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/stickers/CreateNewMaskStickerSet.kt @@ -0,0 +1,54 @@ +package dev.inmo.tgbotapi.extensions.api.stickers + +import dev.inmo.tgbotapi.bot.TelegramBot +import dev.inmo.tgbotapi.requests.abstracts.FileId +import dev.inmo.tgbotapi.requests.abstracts.MultipartFile +import dev.inmo.tgbotapi.requests.stickers.* +import dev.inmo.tgbotapi.types.chat.CommonUser +import dev.inmo.tgbotapi.types.UserId +import dev.inmo.tgbotapi.types.stickers.MaskPosition + +suspend fun TelegramBot.createNewMaskStickerSet( + userId: UserId, + name: String, + title: String, + sticker: FileId, + emojis: String, + maskPosition: MaskPosition +) = execute( + CreateNewMaskStickerSet(userId, name, title, sticker, emojis, maskPosition) +) + +suspend fun TelegramBot.createNewMaskStickerSet( + userId: UserId, + name: String, + title: String, + sticker: MultipartFile, + emojis: String, + maskPosition: MaskPosition +) = execute( + CreateNewMaskStickerSet(userId, name, title, sticker, emojis, maskPosition) +) + + +suspend fun TelegramBot.createNewMaskStickerSet( + user: CommonUser, + name: String, + title: String, + sticker: FileId, + emojis: String, + maskPosition: MaskPosition +) = createNewMaskStickerSet( + user.id, name, title, sticker, emojis, maskPosition +) + +suspend fun TelegramBot.createNewMaskStickerSet( + user: CommonUser, + name: String, + title: String, + sticker: MultipartFile, + emojis: String, + maskPosition: MaskPosition +) = createNewMaskStickerSet( + user.id, name, title, sticker, emojis, maskPosition +) diff --git a/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/stickers/CreateNewMaskVideoStickerSet.kt b/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/stickers/CreateNewMaskVideoStickerSet.kt new file mode 100644 index 0000000000..c519ec0565 --- /dev/null +++ b/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/stickers/CreateNewMaskVideoStickerSet.kt @@ -0,0 +1,54 @@ +package dev.inmo.tgbotapi.extensions.api.stickers + +import dev.inmo.tgbotapi.bot.TelegramBot +import dev.inmo.tgbotapi.requests.abstracts.FileId +import dev.inmo.tgbotapi.requests.abstracts.MultipartFile +import dev.inmo.tgbotapi.requests.stickers.* +import dev.inmo.tgbotapi.types.chat.CommonUser +import dev.inmo.tgbotapi.types.UserId +import dev.inmo.tgbotapi.types.stickers.MaskPosition + +suspend fun TelegramBot.createNewMaskVideoStickerSet( + userId: UserId, + name: String, + title: String, + sticker: FileId, + emojis: String, + maskPosition: MaskPosition +) = execute( + CreateNewMaskVideoStickerSet(userId, name, title, sticker, emojis, maskPosition) +) + +suspend fun TelegramBot.createNewMaskVideoStickerSet( + userId: UserId, + name: String, + title: String, + sticker: MultipartFile, + emojis: String, + maskPosition: MaskPosition +) = execute( + CreateNewMaskVideoStickerSet(userId, name, title, sticker, emojis, maskPosition) +) + + +suspend fun TelegramBot.createNewMaskVideoStickerSet( + user: CommonUser, + name: String, + title: String, + sticker: FileId, + emojis: String, + maskPosition: MaskPosition +) = createNewMaskVideoStickerSet( + user.id, name, title, sticker, emojis, maskPosition +) + +suspend fun TelegramBot.createNewMaskVideoStickerSet( + user: CommonUser, + name: String, + title: String, + sticker: MultipartFile, + emojis: String, + maskPosition: MaskPosition +) = createNewMaskVideoStickerSet( + user.id, name, title, sticker, emojis, maskPosition +) diff --git a/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/stickers/CreateNewRegularAnimatedStickerSet.kt b/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/stickers/CreateNewRegularAnimatedStickerSet.kt new file mode 100644 index 0000000000..3b64f0ea6d --- /dev/null +++ b/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/stickers/CreateNewRegularAnimatedStickerSet.kt @@ -0,0 +1,50 @@ +package dev.inmo.tgbotapi.extensions.api.stickers + +import dev.inmo.tgbotapi.bot.TelegramBot +import dev.inmo.tgbotapi.requests.abstracts.FileId +import dev.inmo.tgbotapi.requests.abstracts.MultipartFile +import dev.inmo.tgbotapi.requests.stickers.* +import dev.inmo.tgbotapi.types.chat.CommonUser +import dev.inmo.tgbotapi.types.UserId +import dev.inmo.tgbotapi.types.stickers.MaskPosition + +suspend fun TelegramBot.createNewRegularAnimatedStickerSet( + userId: UserId, + name: String, + title: String, + sticker: FileId, + emojis: String +) = execute( + CreateNewRegularAnimatedStickerSet(userId, name, title, sticker, emojis) +) + +suspend fun TelegramBot.createNewRegularAnimatedStickerSet( + userId: UserId, + name: String, + title: String, + sticker: MultipartFile, + emojis: String +) = execute( + CreateNewRegularAnimatedStickerSet(userId, name, title, sticker, emojis) +) + + +suspend fun TelegramBot.createNewRegularAnimatedStickerSet( + user: CommonUser, + name: String, + title: String, + sticker: FileId, + emojis: String +) = createNewRegularAnimatedStickerSet( + user.id, name, title, sticker, emojis +) + +suspend fun TelegramBot.createNewRegularAnimatedStickerSet( + user: CommonUser, + name: String, + title: String, + sticker: MultipartFile, + emojis: String +) = createNewRegularAnimatedStickerSet( + user.id, name, title, sticker, emojis +) diff --git a/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/stickers/CreateNewRegularStickerSet.kt b/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/stickers/CreateNewRegularStickerSet.kt new file mode 100644 index 0000000000..a48a4d2afe --- /dev/null +++ b/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/stickers/CreateNewRegularStickerSet.kt @@ -0,0 +1,50 @@ +package dev.inmo.tgbotapi.extensions.api.stickers + +import dev.inmo.tgbotapi.bot.TelegramBot +import dev.inmo.tgbotapi.requests.abstracts.FileId +import dev.inmo.tgbotapi.requests.abstracts.MultipartFile +import dev.inmo.tgbotapi.requests.stickers.* +import dev.inmo.tgbotapi.types.chat.CommonUser +import dev.inmo.tgbotapi.types.UserId +import dev.inmo.tgbotapi.types.stickers.MaskPosition + +suspend fun TelegramBot.createNewRegularStickerSet( + userId: UserId, + name: String, + title: String, + sticker: FileId, + emojis: String +) = execute( + CreateNewRegularStickerSet(userId, name, title, sticker, emojis) +) + +suspend fun TelegramBot.createNewRegularStickerSet( + userId: UserId, + name: String, + title: String, + sticker: MultipartFile, + emojis: String +) = execute( + CreateNewRegularStickerSet(userId, name, title, sticker, emojis) +) + + +suspend fun TelegramBot.createNewRegularStickerSet( + user: CommonUser, + name: String, + title: String, + sticker: FileId, + emojis: String +) = createNewRegularStickerSet( + user.id, name, title, sticker, emojis +) + +suspend fun TelegramBot.createNewRegularStickerSet( + user: CommonUser, + name: String, + title: String, + sticker: MultipartFile, + emojis: String +) = createNewRegularStickerSet( + user.id, name, title, sticker, emojis +) diff --git a/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/stickers/CreateNewRegularVideoStickerSet.kt b/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/stickers/CreateNewRegularVideoStickerSet.kt new file mode 100644 index 0000000000..a27c7b1e08 --- /dev/null +++ b/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/stickers/CreateNewRegularVideoStickerSet.kt @@ -0,0 +1,50 @@ +package dev.inmo.tgbotapi.extensions.api.stickers + +import dev.inmo.tgbotapi.bot.TelegramBot +import dev.inmo.tgbotapi.requests.abstracts.FileId +import dev.inmo.tgbotapi.requests.abstracts.MultipartFile +import dev.inmo.tgbotapi.requests.stickers.* +import dev.inmo.tgbotapi.types.chat.CommonUser +import dev.inmo.tgbotapi.types.UserId +import dev.inmo.tgbotapi.types.stickers.MaskPosition + +suspend fun TelegramBot.createNewRegularVideoStickerSet( + userId: UserId, + name: String, + title: String, + sticker: FileId, + emojis: String +) = execute( + CreateNewRegularVideoStickerSet(userId, name, title, sticker, emojis) +) + +suspend fun TelegramBot.createNewRegularVideoStickerSet( + userId: UserId, + name: String, + title: String, + sticker: MultipartFile, + emojis: String +) = execute( + CreateNewRegularVideoStickerSet(userId, name, title, sticker, emojis) +) + + +suspend fun TelegramBot.createNewRegularVideoStickerSet( + user: CommonUser, + name: String, + title: String, + sticker: FileId, + emojis: String +) = createNewRegularVideoStickerSet( + user.id, name, title, sticker, emojis +) + +suspend fun TelegramBot.createNewRegularVideoStickerSet( + user: CommonUser, + name: String, + title: String, + sticker: MultipartFile, + emojis: String +) = createNewRegularVideoStickerSet( + user.id, name, title, sticker, emojis +) diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/get/GetCustomEmojiStickers.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/get/GetCustomEmojiStickers.kt new file mode 100644 index 0000000000..8cba482df8 --- /dev/null +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/get/GetCustomEmojiStickers.kt @@ -0,0 +1,22 @@ +package dev.inmo.tgbotapi.requests.get + +import dev.inmo.tgbotapi.requests.abstracts.SimpleRequest +import dev.inmo.tgbotapi.types.* +import dev.inmo.tgbotapi.types.files.CustomEmojiSticker +import dev.inmo.tgbotapi.types.files.StickerSerializer +import kotlinx.serialization.* +import kotlinx.serialization.builtins.ListSerializer + +internal val getCustomEmojiStickersResultSerializer = ListSerializer(StickerSerializer) as DeserializationStrategy> + +@Serializable +data class GetCustomEmojiStickers( + @SerialName(customEmojiIdsField) + val customEmojiIds: List +): SimpleRequest> { + override fun method(): String = "getCustomEmojiStickers" + override val resultDeserializer: DeserializationStrategy> + get() = getCustomEmojiStickersResultSerializer + override val requestSerializer: SerializationStrategy<*> + get() = serializer() +} diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/get/GetStickerSet.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/get/GetStickerSet.kt index a9262458ef..2303e7f920 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/get/GetStickerSet.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/get/GetStickerSet.kt @@ -1,13 +1,14 @@ package dev.inmo.tgbotapi.requests.get import dev.inmo.tgbotapi.requests.abstracts.SimpleRequest +import dev.inmo.tgbotapi.types.nameField import dev.inmo.tgbotapi.types.stickerSetNameField import dev.inmo.tgbotapi.types.stickers.StickerSet import kotlinx.serialization.* @Serializable data class GetStickerSet( - @SerialName(stickerSetNameField) + @SerialName(nameField) val name: String ): SimpleRequest { override fun method(): String = "getStickerSet" diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/stickers/CreateNewAnimatedStickerSet.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/stickers/CreateNewAnimatedStickerSet.kt index 6571ac6829..0dbebdb595 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/stickers/CreateNewAnimatedStickerSet.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/stickers/CreateNewAnimatedStickerSet.kt @@ -8,26 +8,8 @@ import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.stickers.MaskPosition import kotlinx.serialization.* -fun CreateNewAnimatedStickerSet( - userId: UserId, - name: String, - title: String, - sticker: InputFile, - emojis: String, - containsMasks: Boolean? = null, - maskPosition: MaskPosition? = null -): Request { - val data = CreateNewAnimatedStickerSet(userId, name, title, emojis, sticker as? FileId, containsMasks, maskPosition) - return when (sticker) { - is MultipartFile -> CommonMultipartFileRequest( - data, - mapOf(tgsStickerField to sticker) - ) - is FileId -> data - } -} - @Serializable +@Deprecated("Use CreateNewStickerSet class instead") data class CreateNewAnimatedStickerSet internal constructor( @SerialName(userIdField) override val userId: UserId, @@ -40,6 +22,7 @@ data class CreateNewAnimatedStickerSet internal constructor( @SerialName(tgsStickerField) val sticker: FileId? = null, @SerialName(containsMasksField) + @Deprecated("Will be removed soon due to its redundancy") val containsMasks: Boolean? = null, @SerialName(maskPositionField) override val maskPosition: MaskPosition? = null diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/stickers/CreateNewStaticStickerSet.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/stickers/CreateNewStaticStickerSet.kt index 85b0d5a514..6e12b9d012 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/stickers/CreateNewStaticStickerSet.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/stickers/CreateNewStaticStickerSet.kt @@ -8,36 +8,8 @@ import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.stickers.MaskPosition import kotlinx.serialization.* -fun CreateNewStaticStickerSet( - userId: UserId, - name: String, - title: String, - sticker: InputFile, - emojis: String, - containsMasks: Boolean? = null, - maskPosition: MaskPosition? = null -): Request { - val data = CreateNewStaticStickerSet(userId, name, title, emojis, sticker as? FileId, containsMasks, maskPosition) - return when (sticker) { - is MultipartFile -> CommonMultipartFileRequest( - data, - mapOf(pngStickerField to sticker) - ) - is FileId -> data - } -} - -fun CreateNewStickerSet( - userId: UserId, - name: String, - title: String, - sticker: InputFile, - emojis: String, - containsMasks: Boolean? = null, - maskPosition: MaskPosition? = null -): Request = CreateNewStaticStickerSet(userId, name, title, sticker, emojis, containsMasks, maskPosition) - @Serializable +@Deprecated("Use CreateNewStickerSet class instead") data class CreateNewStaticStickerSet internal constructor( @SerialName(userIdField) override val userId: UserId, @@ -50,6 +22,7 @@ data class CreateNewStaticStickerSet internal constructor( @SerialName(pngStickerField) val sticker: FileId? = null, @SerialName(containsMasksField) + @Deprecated("Will be removed soon due to its redundancy") val containsMasks: Boolean? = null, @SerialName(maskPositionField) override val maskPosition: MaskPosition? = null diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/stickers/CreateNewStickerSet.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/stickers/CreateNewStickerSet.kt new file mode 100644 index 0000000000..537c5f70b5 --- /dev/null +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/stickers/CreateNewStickerSet.kt @@ -0,0 +1,77 @@ +package dev.inmo.tgbotapi.requests.stickers + +import dev.inmo.tgbotapi.requests.abstracts.* +import dev.inmo.tgbotapi.requests.common.CommonMultipartFileRequest +import dev.inmo.tgbotapi.requests.stickers.abstracts.CreateStickerSetAction +import dev.inmo.tgbotapi.types.* +import dev.inmo.tgbotapi.types.stickers.MaskPosition +import kotlinx.serialization.* + +internal fun CreateNewStickerSet( + userId: UserId, + name: String, + title: String, + emojis: String, + stickerType: StickerType = StickerType.Regular, + pngSticker: InputFile? = null, + tgsSticker: InputFile? = null, + webmSticker: InputFile? = null, + maskPosition: MaskPosition? = null +): Request { + val data = CreateNewStickerSet( + userId, + name, + title, + emojis, + stickerType, + pngSticker as? FileId, + tgsSticker as? FileId, + webmSticker as? FileId, + maskPosition + ) + return if (pngSticker is MultipartFile || tgsSticker is MultipartFile || webmSticker is MultipartFile) { + CommonMultipartFileRequest( + data, + listOfNotNull( + (pngSticker as? MultipartFile) ?.let { pngStickerField to it }, + (tgsSticker as? MultipartFile) ?.let { tgsStickerField to it }, + (webmSticker as? MultipartFile) ?.let { webmStickerField to it }, + ).toMap() + ) + } else { + data + } +} + +@Serializable +data class CreateNewStickerSet internal constructor( + @SerialName(userIdField) + override val userId: UserId, + @SerialName(nameField) + override val name: String, + @SerialName(titleField) + override val title: String, + @SerialName(emojisField) + override val emojis: String, + @SerialName(stickerTypeField) + val stickerType: StickerType = StickerType.Regular, + @SerialName(pngStickerField) + val pngSticker: FileId? = null, + @SerialName(tgsStickerField) + val tgsSticker: FileId? = null, + @SerialName(webmStickerField) + val webmSticker: FileId? = null, + @SerialName(maskPositionField) + override val maskPosition: MaskPosition? = null +) : CreateStickerSetAction { + init { + if(emojis.isEmpty()) { + throw IllegalArgumentException("Emojis must not be empty") + } + } + + override val requestSerializer: SerializationStrategy<*> + get() = serializer() + + override fun method(): String = "createNewStickerSet" +} diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/stickers/CreateNewVideoStickerSet.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/stickers/CreateNewVideoStickerSet.kt index c112c3498c..cfaeb78075 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/stickers/CreateNewVideoStickerSet.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/stickers/CreateNewVideoStickerSet.kt @@ -8,26 +8,8 @@ import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.stickers.MaskPosition import kotlinx.serialization.* -fun CreateNewVideoStickerSet( - userId: UserId, - linkName: String, - title: String, - sticker: InputFile, - emojis: String, - containsMasks: Boolean? = null, - maskPosition: MaskPosition? = null -): Request { - val data = CreateNewVideoStickerSet(userId, linkName, title, emojis, sticker as? FileId, containsMasks, maskPosition) - return when (sticker) { - is MultipartFile -> CommonMultipartFileRequest( - data, - mapOf(webmStickerField to sticker) - ) - is FileId -> data - } -} - @Serializable +@Deprecated("Use CreateNewStickerSet class instead") data class CreateNewVideoStickerSet internal constructor( @SerialName(userIdField) override val userId: UserId, @@ -40,6 +22,7 @@ data class CreateNewVideoStickerSet internal constructor( @SerialName(webmStickerField) val sticker: FileId? = null, @SerialName(containsMasksField) + @Deprecated("Will be removed soon due to its redundancy") val containsMasks: Boolean? = null, @SerialName(maskPositionField) override val maskPosition: MaskPosition? = null diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/stickers/NewCreateNewStickerSetFunctions.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/stickers/NewCreateNewStickerSetFunctions.kt new file mode 100644 index 0000000000..2cd56868bf --- /dev/null +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/stickers/NewCreateNewStickerSetFunctions.kt @@ -0,0 +1,105 @@ +package dev.inmo.tgbotapi.requests.stickers + +import dev.inmo.tgbotapi.requests.abstracts.InputFile +import dev.inmo.tgbotapi.requests.abstracts.Request +import dev.inmo.tgbotapi.types.StickerType +import dev.inmo.tgbotapi.types.UserId +import dev.inmo.tgbotapi.types.stickers.MaskPosition + + +fun CreateNewRegularStickerSet( + userId: UserId, + name: String, + title: String, + sticker: InputFile, + emojis: String +): Request = CreateNewStickerSet( + userId, + name, + title, + emojis, + StickerType.Regular, + pngSticker = sticker +) + +fun CreateNewRegularVideoStickerSet( + userId: UserId, + name: String, + title: String, + sticker: InputFile, + emojis: String +): Request = CreateNewStickerSet( + userId, + name, + title, + emojis, + StickerType.Regular, + webmSticker = sticker +) + +fun CreateNewRegularAnimatedStickerSet( + userId: UserId, + name: String, + title: String, + sticker: InputFile, + emojis: String +): Request = CreateNewStickerSet( + userId, + name, + title, + emojis, + StickerType.Regular, + tgsSticker = sticker +) + + +fun CreateNewMaskStickerSet( + userId: UserId, + name: String, + title: String, + sticker: InputFile, + emojis: String, + maskPosition: MaskPosition +): Request = CreateNewStickerSet( + userId, + name, + title, + emojis, + StickerType.Mask, + pngSticker = sticker, + maskPosition = maskPosition +) + +fun CreateNewMaskVideoStickerSet( + userId: UserId, + name: String, + title: String, + sticker: InputFile, + emojis: String, + maskPosition: MaskPosition +): Request = CreateNewStickerSet( + userId, + name, + title, + emojis, + StickerType.Mask, + webmSticker = sticker, + maskPosition = maskPosition +) + +fun CreateNewMaskAnimatedStickerSet( + userId: UserId, + name: String, + title: String, + sticker: InputFile, + emojis: String, + maskPosition: MaskPosition +): Request = CreateNewStickerSet( + userId, + name, + title, + emojis, + StickerType.Mask, + tgsSticker = sticker, + maskPosition = maskPosition +) diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/stickers/OldCreateNewStickerSetFunctions.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/stickers/OldCreateNewStickerSetFunctions.kt new file mode 100644 index 0000000000..69f747c53f --- /dev/null +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/stickers/OldCreateNewStickerSetFunctions.kt @@ -0,0 +1,80 @@ +package dev.inmo.tgbotapi.requests.stickers + +import dev.inmo.tgbotapi.requests.abstracts.InputFile +import dev.inmo.tgbotapi.requests.abstracts.Request +import dev.inmo.tgbotapi.types.StickerType +import dev.inmo.tgbotapi.types.UserId +import dev.inmo.tgbotapi.types.stickers.MaskPosition + + +fun CreateNewVideoStickerSet( + userId: UserId, + linkName: String, + title: String, + sticker: InputFile, + emojis: String, + containsMasks: Boolean? = null, + maskPosition: MaskPosition? = null +): Request = CreateNewStickerSet( + userId, + linkName, + title, + emojis, + if (containsMasks == true) StickerType.Mask else StickerType.Regular, + webmSticker = sticker, + maskPosition = maskPosition +) + +fun CreateNewStaticStickerSet( + userId: UserId, + name: String, + title: String, + sticker: InputFile, + emojis: String, + containsMasks: Boolean? = null, + maskPosition: MaskPosition? = null +): Request = CreateNewStickerSet( + userId, + name, + title, + emojis, + if (containsMasks == true) StickerType.Mask else StickerType.Regular, + pngSticker = sticker, + maskPosition = maskPosition +) + +fun CreateNewStickerSet( + userId: UserId, + name: String, + title: String, + sticker: InputFile, + emojis: String, + containsMasks: Boolean? = null, + maskPosition: MaskPosition? = null +): Request = CreateNewStickerSet( + userId, + name, + title, + emojis, + if (containsMasks == true) StickerType.Mask else StickerType.Regular, + pngSticker = sticker, + maskPosition = maskPosition +) + +fun CreateNewAnimatedStickerSet( + userId: UserId, + name: String, + title: String, + sticker: InputFile, + emojis: String, + containsMasks: Boolean? = null, + maskPosition: MaskPosition? = null +): Request = CreateNewStickerSet( + userId, + name, + title, + emojis, + if (containsMasks == true) StickerType.Mask else StickerType.Regular, + tgsSticker = sticker, + maskPosition = maskPosition +) 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 345512153b..103f327380 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 @@ -1,6 +1,13 @@ package dev.inmo.tgbotapi.types import dev.inmo.tgbotapi.utils.BuiltinMimeTypes +import kotlinx.serialization.KSerializer +import kotlinx.serialization.Serializable +import kotlinx.serialization.builtins.serializer +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder +import kotlin.jvm.JvmInline typealias Identifier = Long typealias MessageIdentifier = Long @@ -28,6 +35,11 @@ typealias GooglePlaceId = String typealias GooglePlaceType = String typealias MembersLimit = Int typealias WebAppQueryId = String +@Serializable +@JvmInline +value class CustomEmojiId( + val string: String +) typealias Seconds = Int typealias MilliSeconds = Long @@ -37,6 +49,38 @@ typealias UnixTimeStamp = LongSeconds typealias Meters = Float typealias Degrees = Int +@Serializable(StickerType.Serializer::class) +sealed interface StickerType { + val type: String + + @Serializable + object Regular : StickerType { override val type: String = "regular" } + @Serializable + object Mask : StickerType { override val type: String = "mask" } + @Serializable + object CustomEmoji : StickerType { override val type: String = "custom_emoji" } + @Serializable + data class Unknown(override val type: String = "custom_emoji") : StickerType + + object Serializer : KSerializer { + override val descriptor: SerialDescriptor = String.serializer().descriptor + + override fun deserialize(decoder: Decoder): StickerType { + return when (val type = decoder.decodeString()) { + Regular.type -> Regular + Mask.type -> Mask + CustomEmoji.type -> CustomEmoji + else -> Unknown(type) + } + } + + override fun serialize(encoder: Encoder, value: StickerType) { + encoder.encodeString(value.type) + } + + } +} + val degreesLimit = 1 .. 360 val horizontalAccuracyLimit = 0F .. 1500F @@ -126,6 +170,8 @@ const val supportInlineQueriesField = "supports_inline_queries" const val textEntitiesField = "text_entities" const val entitiesField = "entities" const val stickerSetNameField = "set_name" +const val customEmojiIdField = "custom_emoji_id" +const val customEmojiIdsField = "custom_emoji_ids" const val premiumAnimationField = "premium_animation" const val stickerSetNameFullField = "sticker_set_name" const val slowModeDelayField = "slow_mode_delay" @@ -290,6 +336,7 @@ const val tgsStickerField = "tgs_sticker" const val webmStickerField = "webm_sticker" const val oldChatMemberField = "old_chat_member" const val newChatMemberField = "new_chat_member" +const val stickerTypeField = "sticker_type" const val okField = "ok" const val captionField = "caption" diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/files/Sticker.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/files/Sticker.kt index d1f8e484b9..5df612670a 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/files/Sticker.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/files/Sticker.kt @@ -4,16 +4,19 @@ import dev.inmo.tgbotapi.requests.abstracts.FileId import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.stickers.MaskPosition import dev.inmo.tgbotapi.utils.RiskFeature +import dev.inmo.tgbotapi.utils.nonstrictJsonFormat import kotlinx.serialization.* import kotlinx.serialization.descriptors.SerialDescriptor import kotlinx.serialization.encoding.Decoder import kotlinx.serialization.encoding.Encoder +import kotlinx.serialization.json.JsonElement @Serializable @RiskFeature("This class is used for serialization/deserialization of Sticker interface") data class StickerSurrogate( val file_id: FileId, val file_unique_id: FileUniqueId, + val type: StickerType, val width: Int, val height: Int, val is_animated: Boolean? = null, @@ -21,33 +24,138 @@ data class StickerSurrogate( val thumb: PhotoSize? = null, val emoji: String? = null, val set_name: StickerSetName? = null, + val premium_animation: File? = null, val mask_position: MaskPosition? = null, - val file_size: Long? = null, - val premium_animation: File? = null + val custom_emoji_id: CustomEmojiId? = null, + val file_size: Long? = null ) // TODO:: Serializer @Serializable(StickerSerializer::class) sealed interface Sticker : TelegramMediaFile, SizedMediaFile, ThumbedMediaFile { val emoji: String? - val maskPosition: MaskPosition? val stickerSetName: StickerSetName? - val premiumAnimationFile: File? val isAnimated - get() = this is AnimatedSticker + get() = false val isVideo - get() = this is VideoSticker + get() = false } object StickerSerializer : KSerializer { override val descriptor: SerialDescriptor = StickerSurrogate.serializer().descriptor override fun deserialize(decoder: Decoder): Sticker { - val surrogate = StickerSurrogate.serializer().deserialize(decoder) + val json = JsonElement.serializer().deserialize(decoder) + val surrogate = nonstrictJsonFormat.decodeFromJsonElement(StickerSurrogate.serializer(), json) - return when { - surrogate.is_animated == true -> AnimatedSticker( + return when (surrogate.type) { + StickerType.Regular -> when { + surrogate.is_animated == true -> RegularAnimatedSticker( + surrogate.file_id, + surrogate.file_unique_id, + surrogate.width, + surrogate.height, + surrogate.thumb, + surrogate.emoji, + surrogate.set_name, + surrogate.premium_animation, + surrogate.file_size + ) + surrogate.is_video == true -> RegularVideoSticker( + surrogate.file_id, + surrogate.file_unique_id, + surrogate.width, + surrogate.height, + surrogate.thumb, + surrogate.emoji, + surrogate.set_name, + surrogate.premium_animation, + surrogate.file_size + ) + else -> RegularSimpleSticker( + surrogate.file_id, + surrogate.file_unique_id, + surrogate.width, + surrogate.height, + surrogate.thumb, + surrogate.emoji, + surrogate.set_name, + surrogate.premium_animation, + surrogate.file_size + ) + } + StickerType.Mask -> when { + surrogate.is_animated == true -> MaskAnimatedSticker( + surrogate.file_id, + surrogate.file_unique_id, + surrogate.width, + surrogate.height, + surrogate.mask_position ?: error("For mask stickers field mask_position should be presented"), + surrogate.thumb, + surrogate.emoji, + surrogate.set_name, + surrogate.file_size + ) + surrogate.is_video == true -> MaskVideoSticker( + surrogate.file_id, + surrogate.file_unique_id, + surrogate.width, + surrogate.height, + surrogate.mask_position ?: error("For mask stickers field mask_position should be presented"), + surrogate.thumb, + surrogate.emoji, + surrogate.set_name, + surrogate.file_size + ) + else -> MaskSimpleSticker( + surrogate.file_id, + surrogate.file_unique_id, + surrogate.width, + surrogate.height, + surrogate.mask_position ?: error("For mask stickers field mask_position should be presented"), + surrogate.thumb, + surrogate.emoji, + surrogate.set_name, + surrogate.file_size + ) + } + StickerType.CustomEmoji -> when { + surrogate.is_animated == true -> CustomEmojiAnimatedSticker( + surrogate.file_id, + surrogate.file_unique_id, + surrogate.width, + surrogate.height, + surrogate.custom_emoji_id ?: error("For mask stickers field mask_position should be presented"), + surrogate.thumb, + surrogate.emoji, + surrogate.set_name, + surrogate.file_size + ) + surrogate.is_video == true -> CustomEmojiVideoSticker( + surrogate.file_id, + surrogate.file_unique_id, + surrogate.width, + surrogate.height, + surrogate.custom_emoji_id ?: error("For mask stickers field mask_position should be presented"), + surrogate.thumb, + surrogate.emoji, + surrogate.set_name, + surrogate.file_size + ) + else -> CustomEmojiSimpleSticker( + surrogate.file_id, + surrogate.file_unique_id, + surrogate.width, + surrogate.height, + surrogate.custom_emoji_id ?: error("For mask stickers field mask_position should be presented"), + surrogate.thumb, + surrogate.emoji, + surrogate.set_name, + surrogate.file_size + ) + } + is StickerType.Unknown -> UnknownSticker( surrogate.file_id, surrogate.file_unique_id, surrogate.width, @@ -55,33 +163,8 @@ object StickerSerializer : KSerializer { surrogate.thumb, surrogate.emoji, surrogate.set_name, - surrogate.premium_animation, - surrogate.mask_position, - surrogate.file_size - ) - surrogate.is_video == true -> VideoSticker( - surrogate.file_id, - surrogate.file_unique_id, - surrogate.width, - surrogate.height, - surrogate.thumb, - surrogate.emoji, - surrogate.set_name, - surrogate.premium_animation, - surrogate.mask_position, - surrogate.file_size - ) - else -> SimpleSticker( - surrogate.file_id, - surrogate.file_unique_id, - surrogate.width, - surrogate.height, - surrogate.thumb, - surrogate.emoji, - surrogate.set_name, - surrogate.premium_animation, - surrogate.mask_position, - surrogate.file_size + surrogate.file_size, + json ) } } @@ -93,53 +176,23 @@ object StickerSerializer : KSerializer { } @Serializable -data class SimpleSticker( - @SerialName(fileIdField) - override val fileId: FileId, - @SerialName(fileUniqueIdField) - override val fileUniqueId: FileUniqueId, - @SerialName(widthField) - override val width: Int, - @SerialName(heightField) - override val height: Int, - @SerialName(thumbField) - override val thumb: PhotoSize? = null, - @SerialName(emojiField) - override val emoji: String? = null, - @SerialName(stickerSetNameField) - override val stickerSetName: StickerSetName? = null, - @SerialName(premiumAnimationField) - override val premiumAnimationFile: File?, - @SerialName(maskPositionField) - override val maskPosition: MaskPosition? = null, - @SerialName(fileSizeField) - override val fileSize: Long? = null, -) : Sticker +sealed interface VideoSticker : Sticker { + override val isVideo: Boolean + get() = true +} @Serializable -data class AnimatedSticker( - @SerialName(fileIdField) - override val fileId: FileId, - @SerialName(fileUniqueIdField) - override val fileUniqueId: FileUniqueId, - @SerialName(widthField) - override val width: Int, - @SerialName(heightField) - override val height: Int, - @SerialName(thumbField) - override val thumb: PhotoSize? = null, - @SerialName(emojiField) - override val emoji: String? = null, - @SerialName(stickerSetNameField) - override val stickerSetName: StickerSetName? = null, - @SerialName(premiumAnimationField) - override val premiumAnimationFile: File?, - @SerialName(maskPositionField) - override val maskPosition: MaskPosition? = null, - @SerialName(fileSizeField) - override val fileSize: Long? = null, -) : Sticker +sealed interface AnimatedSticker : Sticker { + override val isAnimated: Boolean + get() = true +} + @Serializable -data class VideoSticker( +sealed interface RegularSticker : Sticker { + val premiumAnimationFile: File? +} + +@Serializable +data class RegularSimpleSticker( @SerialName(fileIdField) override val fileId: FileId, @SerialName(fileUniqueIdField) @@ -156,8 +209,209 @@ data class VideoSticker( override val stickerSetName: StickerSetName? = null, @SerialName(premiumAnimationField) override val premiumAnimationFile: File?, - @SerialName(maskPositionField) - override val maskPosition: MaskPosition? = null, @SerialName(fileSizeField) override val fileSize: Long? = null, +) : RegularSticker +@Deprecated("Renamed", ReplaceWith("SimpleRegularSticker", "dev.inmo.tgbotapi.types.files.SimpleRegularSticker")) +typealias SimpleSticker = RegularSimpleSticker +@Serializable +data class RegularAnimatedSticker( + @SerialName(fileIdField) + override val fileId: FileId, + @SerialName(fileUniqueIdField) + override val fileUniqueId: FileUniqueId, + @SerialName(widthField) + override val width: Int, + @SerialName(heightField) + override val height: Int, + @SerialName(thumbField) + override val thumb: PhotoSize? = null, + @SerialName(emojiField) + override val emoji: String? = null, + @SerialName(stickerSetNameField) + override val stickerSetName: StickerSetName? = null, + @SerialName(premiumAnimationField) + override val premiumAnimationFile: File?, + @SerialName(fileSizeField) + override val fileSize: Long? = null, +) : RegularSticker, AnimatedSticker +@Serializable +data class RegularVideoSticker( + @SerialName(fileIdField) + override val fileId: FileId, + @SerialName(fileUniqueIdField) + override val fileUniqueId: FileUniqueId, + @SerialName(widthField) + override val width: Int, + @SerialName(heightField) + override val height: Int, + @SerialName(thumbField) + override val thumb: PhotoSize? = null, + @SerialName(emojiField) + override val emoji: String? = null, + @SerialName(stickerSetNameField) + override val stickerSetName: StickerSetName? = null, + @SerialName(premiumAnimationField) + override val premiumAnimationFile: File?, + @SerialName(fileSizeField) + override val fileSize: Long? = null, +) : RegularSticker, VideoSticker + + +@Serializable +sealed interface MaskSticker : Sticker { + val maskPosition: MaskPosition +} +@Serializable +data class MaskSimpleSticker( + @SerialName(fileIdField) + override val fileId: FileId, + @SerialName(fileUniqueIdField) + override val fileUniqueId: FileUniqueId, + @SerialName(widthField) + override val width: Int, + @SerialName(heightField) + override val height: Int, + @SerialName(maskPositionField) + override val maskPosition: MaskPosition, + @SerialName(thumbField) + override val thumb: PhotoSize? = null, + @SerialName(emojiField) + override val emoji: String? = null, + @SerialName(stickerSetNameField) + override val stickerSetName: StickerSetName? = null, + @SerialName(fileSizeField) + override val fileSize: Long? = null, +) : MaskSticker +@Serializable +data class MaskAnimatedSticker( + @SerialName(fileIdField) + override val fileId: FileId, + @SerialName(fileUniqueIdField) + override val fileUniqueId: FileUniqueId, + @SerialName(widthField) + override val width: Int, + @SerialName(heightField) + override val height: Int, + @SerialName(maskPositionField) + override val maskPosition: MaskPosition, + @SerialName(thumbField) + override val thumb: PhotoSize? = null, + @SerialName(emojiField) + override val emoji: String? = null, + @SerialName(stickerSetNameField) + override val stickerSetName: StickerSetName? = null, + @SerialName(fileSizeField) + override val fileSize: Long? = null, +) : MaskSticker, AnimatedSticker +@Serializable +data class MaskVideoSticker( + @SerialName(fileIdField) + override val fileId: FileId, + @SerialName(fileUniqueIdField) + override val fileUniqueId: FileUniqueId, + @SerialName(widthField) + override val width: Int, + @SerialName(heightField) + override val height: Int, + @SerialName(maskPositionField) + override val maskPosition: MaskPosition, + @SerialName(thumbField) + override val thumb: PhotoSize? = null, + @SerialName(emojiField) + override val emoji: String? = null, + @SerialName(stickerSetNameField) + override val stickerSetName: StickerSetName? = null, + @SerialName(fileSizeField) + override val fileSize: Long? = null, +) : MaskSticker, VideoSticker + +@Serializable +sealed interface CustomEmojiSticker : Sticker { + val customEmojiId: CustomEmojiId +} + +@Serializable +data class CustomEmojiSimpleSticker( + @SerialName(fileIdField) + override val fileId: FileId, + @SerialName(fileUniqueIdField) + override val fileUniqueId: FileUniqueId, + @SerialName(widthField) + override val width: Int, + @SerialName(heightField) + override val height: Int, + @SerialName(customEmojiIdField) + override val customEmojiId: CustomEmojiId, + @SerialName(thumbField) + override val thumb: PhotoSize? = null, + @SerialName(emojiField) + override val emoji: String? = null, + @SerialName(stickerSetNameField) + override val stickerSetName: StickerSetName? = null, + @SerialName(fileSizeField) + override val fileSize: Long? = null, +) : CustomEmojiSticker +@Serializable +data class CustomEmojiAnimatedSticker( + @SerialName(fileIdField) + override val fileId: FileId, + @SerialName(fileUniqueIdField) + override val fileUniqueId: FileUniqueId, + @SerialName(widthField) + override val width: Int, + @SerialName(heightField) + override val height: Int, + @SerialName(customEmojiIdField) + override val customEmojiId: CustomEmojiId, + @SerialName(thumbField) + override val thumb: PhotoSize? = null, + @SerialName(emojiField) + override val emoji: String? = null, + @SerialName(stickerSetNameField) + override val stickerSetName: StickerSetName? = null, + @SerialName(fileSizeField) + override val fileSize: Long? = null, +) : CustomEmojiSticker, AnimatedSticker +@Serializable +data class CustomEmojiVideoSticker( + @SerialName(fileIdField) + override val fileId: FileId, + @SerialName(fileUniqueIdField) + override val fileUniqueId: FileUniqueId, + @SerialName(widthField) + override val width: Int, + @SerialName(heightField) + override val height: Int, + @SerialName(customEmojiIdField) + override val customEmojiId: CustomEmojiId, + @SerialName(thumbField) + override val thumb: PhotoSize? = null, + @SerialName(emojiField) + override val emoji: String? = null, + @SerialName(stickerSetNameField) + override val stickerSetName: StickerSetName? = null, + @SerialName(fileSizeField) + override val fileSize: Long? = null, +) : CustomEmojiSticker, VideoSticker + +@Serializable +data class UnknownSticker( + @SerialName(fileIdField) + override val fileId: FileId, + @SerialName(fileUniqueIdField) + override val fileUniqueId: FileUniqueId, + @SerialName(widthField) + override val width: Int, + @SerialName(heightField) + override val height: Int, + @SerialName(thumbField) + override val thumb: PhotoSize? = null, + @SerialName(emojiField) + override val emoji: String? = null, + @SerialName(stickerSetNameField) + override val stickerSetName: StickerSetName? = null, + @SerialName(fileSizeField) + override val fileSize: Long? = null, + val raw: JsonElement ) : Sticker diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/RawMessageEntity.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/RawMessageEntity.kt index 32386318c3..8d4e49fe0a 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/RawMessageEntity.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/RawMessageEntity.kt @@ -1,5 +1,6 @@ package dev.inmo.tgbotapi.types.message +import dev.inmo.tgbotapi.types.CustomEmojiId import dev.inmo.tgbotapi.types.chat.User import dev.inmo.tgbotapi.types.message.textsources.* import kotlinx.serialization.Serializable @@ -11,7 +12,8 @@ internal data class RawMessageEntity( val length: Int, val url: String? = null, val user: User? = null, - val language: String? = null + val language: String? = null, + val custom_emoji_id: CustomEmojiId? = null ) { internal val range by lazy { offset until (offset + length) @@ -50,6 +52,7 @@ internal fun RawMessageEntity.asTextSource( "underline" -> UnderlineTextSource(sourceSubstring, subPartsWithRegulars) "strikethrough" -> StrikethroughTextSource(sourceSubstring, subPartsWithRegulars) "spoiler" -> SpoilerTextSource(sourceSubstring, subPartsWithRegulars) + "custom_emoji" -> CustomEmojiTextSource(sourceSubstring, custom_emoji_id ?: error("For custom emoji custom_emoji_id should exists"), subPartsWithRegulars) else -> RegularTextSource(sourceSubstring) } } @@ -158,7 +161,8 @@ internal fun TextSource.toRawMessageEntities(offset: Int = 0): List RawMessageEntity("underline", offset, length) is StrikethroughTextSource -> RawMessageEntity("strikethrough", offset, length) is SpoilerTextSource -> RawMessageEntity("spoiler", offset, length) - else -> null + is CustomEmojiTextSource -> RawMessageEntity("custom_emoji", offset, length, custom_emoji_id = customEmojiId) + is RegularTextSource -> null } ) + if (this is MultilevelTextSource) { subsources.toRawMessageEntities(offset) 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 new file mode 100644 index 0000000000..01a68e1935 --- /dev/null +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/textsources/CustomEmojiTextSource.kt @@ -0,0 +1,31 @@ +package dev.inmo.tgbotapi.types.message.textsources + +import dev.inmo.tgbotapi.types.CustomEmojiId +import dev.inmo.tgbotapi.utils.RiskFeature +import dev.inmo.tgbotapi.utils.extensions.makeString +import dev.inmo.tgbotapi.utils.internal.* +import kotlinx.serialization.Serializable + +/** + * @see customEmoji + */ +@Serializable +data class CustomEmojiTextSource @RiskFeature(DirectInvocationOfTextSourceConstructor) constructor ( + override val source: String, + val customEmojiId: CustomEmojiId, + 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() } +} + +@Suppress("NOTHING_TO_INLINE", "EXPERIMENTAL_API_USAGE") +inline fun customEmoji(emojiId: CustomEmojiId, parts: TextSourcesList) = CustomEmojiTextSource(parts.makeString(), emojiId, parts) +@Suppress("NOTHING_TO_INLINE") +inline fun customEmoji(emojiId: CustomEmojiId, vararg parts: TextSource) = customEmoji(emojiId, parts.toList()) +/** + * Without sharp (#) + */ +@Suppress("NOTHING_TO_INLINE") +inline fun customEmoji(emojiId: CustomEmojiId, text: String) = customEmoji(emojiId, regular(text)) diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/textsources/TextSource.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/textsources/TextSource.kt index 5a0fc2b1ef..4a44363d69 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/textsources/TextSource.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/textsources/TextSource.kt @@ -36,7 +36,7 @@ sealed interface MultilevelTextSource : TextSource { val subsources: List } -fun List.separateForMessage(limit: IntRange, numberOfParts: Int? = null): List> { +fun List.splitForMessage(limit: IntRange, numberOfParts: Int? = null): List> { if (isEmpty()) { return emptyList() } @@ -70,13 +70,27 @@ fun List.separateForMessage(limit: IntRange, numberOfParts: Int? = n * This method will prepare [TextSource]s list for messages. Remember, that first part will be separated with * [captionLength] and all others with */ -fun List.separateForCaption(): List> { - val captionPart = separateForMessage(captionLength, 1).first() - return listOf(captionPart) + minus(captionPart).separateForMessage(textLength) +fun List.splitForCaption(): List> { + val captionPart = splitForMessage(captionLength, 1).first() + return listOf(captionPart) + minus(captionPart).splitForMessage(textLength) } /** * This method will prepare [TextSource]s list for messages with [textLength] */ @Suppress("NOTHING_TO_INLINE") -inline fun List.separateForText(): List> = separateForMessage(textLength) +inline fun List.splitForText(): List> = splitForMessage(textLength) + +fun List.separateForMessage(limit: IntRange, numberOfParts: Int? = null): List> = splitForMessage(limit, numberOfParts) + +/** + * This method will prepare [TextSource]s list for messages. Remember, that first part will be separated with + * [captionLength] and all others with + */ +fun List.separateForCaption(): List> = splitForCaption() + +/** + * This method will prepare [TextSource]s list for messages with [textLength] + */ +@Suppress("NOTHING_TO_INLINE") +inline fun List.separateForText(): List> = splitForText() diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/textsources/TextSourceSerializer.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/textsources/TextSourceSerializer.kt index c451984989..e93d87f575 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/textsources/TextSourceSerializer.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/textsources/TextSourceSerializer.kt @@ -21,6 +21,7 @@ private val baseSerializers: Map> = mapOf( "hashtag" to HashTagTextSource.serializer(), "cashtag" to CashTagTextSource.serializer(), "spoiler" to SpoilerTextSource.serializer(), + "custom_emoji" to CustomEmojiTextSource.serializer(), ) object TextSourceSerializer : TypedSerializer(TextSource::class, baseSerializers) { diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/stickers/StickerSet.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/stickers/StickerSet.kt index 84e13732bb..922c6c6b52 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/stickers/StickerSet.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/stickers/StickerSet.kt @@ -1,25 +1,298 @@ package dev.inmo.tgbotapi.types.stickers import dev.inmo.tgbotapi.types.* -import dev.inmo.tgbotapi.types.files.PhotoSize -import dev.inmo.tgbotapi.types.files.Sticker -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable +import dev.inmo.tgbotapi.types.files.* +import dev.inmo.tgbotapi.utils.nonstrictJsonFormat +import kotlinx.serialization.* +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.JsonElement @Serializable -data class StickerSet( - @SerialName(nameField) +data class SurrogateStickerSet( val name: String, - @SerialName(titleField) val title: String, - @SerialName(stickersField) - val stickers: List, - @SerialName(isAnimatedField) - val isAnimated: Boolean = false, - @SerialName(isVideoField) - val isVideo: Boolean = false, - @SerialName(containsMasksField) - val containsMasks: Boolean = false, - @SerialName(thumbField) + val sticker_type: StickerType, + val is_animated: Boolean? = false, + val is_video: Boolean? = false, + val stickers: List<@Serializable(StickerSerializer::class) Sticker> = emptyList(), val thumb: PhotoSize? = null ) + +@Serializable(StickerSet.Serializer::class) +sealed interface StickerSet { + val name: String + val title: String + val stickerType: StickerType + val stickers: List + val isAnimated: Boolean + get() = false + val isVideo: Boolean + get() = false + val thumb: PhotoSize? + @Deprecated("Will be removed soon due to its redundancy") + val containsMasks: Boolean + get() = this is MaskStickerSet + + object Serializer : KSerializer { + override val descriptor: SerialDescriptor = JsonElement.serializer().descriptor + + override fun deserialize(decoder: Decoder): StickerSet { + val json = JsonElement.serializer().deserialize(decoder) + val surrogate = nonstrictJsonFormat.decodeFromJsonElement(SurrogateStickerSet.serializer(), json) + + return when (surrogate.sticker_type) { + StickerType.CustomEmoji -> when { + surrogate.is_animated == true -> CustomEmojiAnimatedStickerSet( + surrogate.name, + surrogate.title, + surrogate.stickers.filterIsInstance(), + surrogate.thumb + ) + surrogate.is_video == true -> CustomEmojiVideoStickerSet( + surrogate.name, + surrogate.title, + surrogate.stickers.filterIsInstance(), + surrogate.thumb + ) + else -> CustomEmojiSimpleStickerSet( + surrogate.name, + surrogate.title, + surrogate.stickers.filterIsInstance(), + surrogate.thumb + ) + } + StickerType.Mask -> when { + surrogate.is_animated == true -> MaskAnimatedStickerSet( + surrogate.name, + surrogate.title, + surrogate.stickers.filterIsInstance(), + surrogate.thumb + ) + surrogate.is_video == true -> MaskVideoStickerSet( + surrogate.name, + surrogate.title, + surrogate.stickers.filterIsInstance(), + surrogate.thumb + ) + else -> MaskSimpleStickerSet( + surrogate.name, + surrogate.title, + surrogate.stickers.filterIsInstance(), + surrogate.thumb + ) + } + StickerType.Regular -> when { + surrogate.is_animated == true -> RegularAnimatedStickerSet( + surrogate.name, + surrogate.title, + surrogate.stickers.filterIsInstance(), + surrogate.thumb + ) + surrogate.is_video == true -> RegularVideoStickerSet( + surrogate.name, + surrogate.title, + surrogate.stickers.filterIsInstance(), + surrogate.thumb + ) + else -> RegularSimpleStickerSet( + surrogate.name, + surrogate.title, + surrogate.stickers.filterIsInstance(), + surrogate.thumb + ) + } + is StickerType.Unknown -> UnknownStickerSet( + surrogate.name, + surrogate.title, + surrogate.stickers.filterIsInstance(), + surrogate.sticker_type, + surrogate.thumb, + json + ) + } + } + + override fun serialize(encoder: Encoder, value: StickerSet) { + TODO("Not yet implemented") + } + } +} + +@Serializable +sealed interface AnimatedStickerSet : StickerSet { + override val isAnimated: Boolean + get() = true +} +@Serializable +sealed interface VideoStickerSet : StickerSet { + override val isVideo: Boolean + get() = true +} +@Serializable +sealed interface RegularStickerSet : StickerSet +@Serializable +sealed interface MaskStickerSet : StickerSet +@Serializable +sealed interface CustomEmojiStickerSet : StickerSet + +@Serializable +data class RegularSimpleStickerSet( + @SerialName(nameField) + override val name: String, + @SerialName(titleField) + override val title: String, + @SerialName(stickersField) + override val stickers: List, + @SerialName(thumbField) + override val thumb: PhotoSize? = null +) : RegularStickerSet { + @SerialName(stickerTypeField) + @EncodeDefault + override val stickerType: StickerType = StickerType.Regular +} + +@Serializable +data class RegularAnimatedStickerSet( + @SerialName(nameField) + override val name: String, + @SerialName(titleField) + override val title: String, + @SerialName(stickersField) + override val stickers: List, + @SerialName(thumbField) + override val thumb: PhotoSize? = null +) : RegularStickerSet, AnimatedStickerSet { + @SerialName(stickerTypeField) + @EncodeDefault + override val stickerType: StickerType = StickerType.Regular +} + +@Serializable +data class RegularVideoStickerSet( + @SerialName(nameField) + override val name: String, + @SerialName(titleField) + override val title: String, + @SerialName(stickersField) + override val stickers: List, + @SerialName(thumbField) + override val thumb: PhotoSize? = null +) : RegularStickerSet, VideoStickerSet { + @SerialName(stickerTypeField) + @EncodeDefault + override val stickerType: StickerType = StickerType.Regular +} + +@Serializable +data class MaskSimpleStickerSet( + @SerialName(nameField) + override val name: String, + @SerialName(titleField) + override val title: String, + @SerialName(stickersField) + override val stickers: List, + @SerialName(thumbField) + override val thumb: PhotoSize? = null +) : MaskStickerSet { + @SerialName(stickerTypeField) + @EncodeDefault + override val stickerType: StickerType = StickerType.Mask +} + +@Serializable +data class MaskAnimatedStickerSet( + @SerialName(nameField) + override val name: String, + @SerialName(titleField) + override val title: String, + @SerialName(stickersField) + override val stickers: List, + @SerialName(thumbField) + override val thumb: PhotoSize? = null +) : MaskStickerSet, AnimatedStickerSet { + @SerialName(stickerTypeField) + @EncodeDefault + override val stickerType: StickerType = StickerType.Mask +} + +@Serializable +data class MaskVideoStickerSet( + @SerialName(nameField) + override val name: String, + @SerialName(titleField) + override val title: String, + @SerialName(stickersField) + override val stickers: List, + @SerialName(thumbField) + override val thumb: PhotoSize? = null +) : MaskStickerSet, VideoStickerSet { + @SerialName(stickerTypeField) + @EncodeDefault + override val stickerType: StickerType = StickerType.Mask +} + +@Serializable +data class CustomEmojiSimpleStickerSet( + @SerialName(nameField) + override val name: String, + @SerialName(titleField) + override val title: String, + @SerialName(stickersField) + override val stickers: List, + @SerialName(thumbField) + override val thumb: PhotoSize? = null +) : CustomEmojiStickerSet { + @SerialName(stickerTypeField) + @EncodeDefault + override val stickerType: StickerType = StickerType.CustomEmoji +} + +@Serializable +data class CustomEmojiAnimatedStickerSet( + @SerialName(nameField) + override val name: String, + @SerialName(titleField) + override val title: String, + @SerialName(stickersField) + override val stickers: List, + @SerialName(thumbField) + override val thumb: PhotoSize? = null +) : CustomEmojiStickerSet, AnimatedStickerSet { + @SerialName(stickerTypeField) + @EncodeDefault + override val stickerType: StickerType = StickerType.CustomEmoji +} + +@Serializable +data class CustomEmojiVideoStickerSet( + @SerialName(nameField) + override val name: String, + @SerialName(titleField) + override val title: String, + @SerialName(stickersField) + override val stickers: List, + @SerialName(thumbField) + override val thumb: PhotoSize? = null +) : CustomEmojiStickerSet, VideoStickerSet { + @SerialName(stickerTypeField) + @EncodeDefault + override val stickerType: StickerType = StickerType.CustomEmoji +} + +@Serializable +data class UnknownStickerSet( + @SerialName(nameField) + override val name: String, + @SerialName(titleField) + override val title: String, + @SerialName(stickersField) + override val stickers: List, + @SerialName(stickerTypeField) + override val stickerType: StickerType, + @SerialName(thumbField) + override val thumb: PhotoSize? = null, + val raw: JsonElement +) : CustomEmojiStickerSet, VideoStickerSet 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 b7640743e0..6a5ee9091a 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 @@ -119,6 +119,10 @@ internal fun String.commandMarkdown(): String = command(String::toMarkdown) internal fun String.commandMarkdownV2(): String = command(String::escapeMarkdownV2Common) 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.regularMarkdown(): String = toMarkdown() internal fun String.regularMarkdownV2(): String = escapeMarkdownV2Common() internal fun String.regularHtml(): String = toHtml() 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 c7c17929cb..54668e5609 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 @@ -167,18 +167,30 @@ import dev.inmo.tgbotapi.types.dice.SlotMachineDiceAnimationType import dev.inmo.tgbotapi.types.files.AnimatedSticker import dev.inmo.tgbotapi.types.files.AnimationFile import dev.inmo.tgbotapi.types.files.AudioFile +import dev.inmo.tgbotapi.types.files.CustomEmojiAnimatedSticker +import dev.inmo.tgbotapi.types.files.CustomEmojiSimpleSticker +import dev.inmo.tgbotapi.types.files.CustomEmojiSticker +import dev.inmo.tgbotapi.types.files.CustomEmojiVideoSticker import dev.inmo.tgbotapi.types.files.DocumentFile import dev.inmo.tgbotapi.types.files.File +import dev.inmo.tgbotapi.types.files.MaskAnimatedSticker +import dev.inmo.tgbotapi.types.files.MaskSimpleSticker +import dev.inmo.tgbotapi.types.files.MaskSticker +import dev.inmo.tgbotapi.types.files.MaskVideoSticker import dev.inmo.tgbotapi.types.files.MimedMediaFile import dev.inmo.tgbotapi.types.files.PassportFile import dev.inmo.tgbotapi.types.files.PathedFile import dev.inmo.tgbotapi.types.files.PhotoSize import dev.inmo.tgbotapi.types.files.PlayableMediaFile -import dev.inmo.tgbotapi.types.files.SimpleSticker +import dev.inmo.tgbotapi.types.files.RegularAnimatedSticker +import dev.inmo.tgbotapi.types.files.RegularSimpleSticker +import dev.inmo.tgbotapi.types.files.RegularSticker +import dev.inmo.tgbotapi.types.files.RegularVideoSticker import dev.inmo.tgbotapi.types.files.SizedMediaFile import dev.inmo.tgbotapi.types.files.Sticker import dev.inmo.tgbotapi.types.files.TelegramMediaFile import dev.inmo.tgbotapi.types.files.ThumbedMediaFile +import dev.inmo.tgbotapi.types.files.UnknownSticker import dev.inmo.tgbotapi.types.files.VideoFile import dev.inmo.tgbotapi.types.files.VideoNoteFile import dev.inmo.tgbotapi.types.files.VideoSticker @@ -295,6 +307,7 @@ import dev.inmo.tgbotapi.types.message.textsources.BoldTextSource import dev.inmo.tgbotapi.types.message.textsources.BotCommandTextSource import dev.inmo.tgbotapi.types.message.textsources.CashTagTextSource import dev.inmo.tgbotapi.types.message.textsources.CodeTextSource +import dev.inmo.tgbotapi.types.message.textsources.CustomEmojiTextSource import dev.inmo.tgbotapi.types.message.textsources.EMailTextSource import dev.inmo.tgbotapi.types.message.textsources.HashTagTextSource import dev.inmo.tgbotapi.types.message.textsources.ItalicTextSource @@ -2266,14 +2279,14 @@ public inline fun TelegramMediaFile.stickerOrThrow(): Sticker = this as public inline fun TelegramMediaFile.ifSticker(block: (Sticker) -> T): T? = stickerOrNull() ?.let(block) -public inline fun TelegramMediaFile.simpleStickerOrNull(): SimpleSticker? = this as? - dev.inmo.tgbotapi.types.files.SimpleSticker +public inline fun TelegramMediaFile.videoStickerOrNull(): VideoSticker? = this as? + dev.inmo.tgbotapi.types.files.VideoSticker -public inline fun TelegramMediaFile.simpleStickerOrThrow(): SimpleSticker = this as - dev.inmo.tgbotapi.types.files.SimpleSticker +public inline fun TelegramMediaFile.videoStickerOrThrow(): VideoSticker = this as + dev.inmo.tgbotapi.types.files.VideoSticker -public inline fun TelegramMediaFile.ifSimpleSticker(block: (SimpleSticker) -> T): T? = - simpleStickerOrNull() ?.let(block) +public inline fun TelegramMediaFile.ifVideoSticker(block: (VideoSticker) -> T): T? = + videoStickerOrNull() ?.let(block) public inline fun TelegramMediaFile.animatedStickerOrNull(): AnimatedSticker? = this as? dev.inmo.tgbotapi.types.files.AnimatedSticker @@ -2284,14 +2297,126 @@ public inline fun TelegramMediaFile.animatedStickerOrThrow(): AnimatedSticker = public inline fun TelegramMediaFile.ifAnimatedSticker(block: (AnimatedSticker) -> T): T? = animatedStickerOrNull() ?.let(block) -public inline fun TelegramMediaFile.videoStickerOrNull(): VideoSticker? = this as? - dev.inmo.tgbotapi.types.files.VideoSticker +public inline fun TelegramMediaFile.regularStickerOrNull(): RegularSticker? = this as? + dev.inmo.tgbotapi.types.files.RegularSticker -public inline fun TelegramMediaFile.videoStickerOrThrow(): VideoSticker = this as - dev.inmo.tgbotapi.types.files.VideoSticker +public inline fun TelegramMediaFile.regularStickerOrThrow(): RegularSticker = this as + dev.inmo.tgbotapi.types.files.RegularSticker -public inline fun TelegramMediaFile.ifVideoSticker(block: (VideoSticker) -> T): T? = - videoStickerOrNull() ?.let(block) +public inline fun TelegramMediaFile.ifRegularSticker(block: (RegularSticker) -> T): T? = + regularStickerOrNull() ?.let(block) + +public inline fun TelegramMediaFile.regularSimpleStickerOrNull(): RegularSimpleSticker? = this as? + dev.inmo.tgbotapi.types.files.RegularSimpleSticker + +public inline fun TelegramMediaFile.regularSimpleStickerOrThrow(): RegularSimpleSticker = this as + dev.inmo.tgbotapi.types.files.RegularSimpleSticker + +public inline fun TelegramMediaFile.ifRegularSimpleSticker(block: (RegularSimpleSticker) -> T): + T? = regularSimpleStickerOrNull() ?.let(block) + +public inline fun TelegramMediaFile.regularAnimatedStickerOrNull(): RegularAnimatedSticker? = this + as? dev.inmo.tgbotapi.types.files.RegularAnimatedSticker + +public inline fun TelegramMediaFile.regularAnimatedStickerOrThrow(): RegularAnimatedSticker = this + as dev.inmo.tgbotapi.types.files.RegularAnimatedSticker + +public inline fun + TelegramMediaFile.ifRegularAnimatedSticker(block: (RegularAnimatedSticker) -> T): T? = + regularAnimatedStickerOrNull() ?.let(block) + +public inline fun TelegramMediaFile.regularVideoStickerOrNull(): RegularVideoSticker? = this as? + dev.inmo.tgbotapi.types.files.RegularVideoSticker + +public inline fun TelegramMediaFile.regularVideoStickerOrThrow(): RegularVideoSticker = this as + dev.inmo.tgbotapi.types.files.RegularVideoSticker + +public inline fun TelegramMediaFile.ifRegularVideoSticker(block: (RegularVideoSticker) -> T): T? + = regularVideoStickerOrNull() ?.let(block) + +public inline fun TelegramMediaFile.maskStickerOrNull(): MaskSticker? = this as? + dev.inmo.tgbotapi.types.files.MaskSticker + +public inline fun TelegramMediaFile.maskStickerOrThrow(): MaskSticker = this as + dev.inmo.tgbotapi.types.files.MaskSticker + +public inline fun TelegramMediaFile.ifMaskSticker(block: (MaskSticker) -> T): T? = + maskStickerOrNull() ?.let(block) + +public inline fun TelegramMediaFile.maskSimpleStickerOrNull(): MaskSimpleSticker? = this as? + dev.inmo.tgbotapi.types.files.MaskSimpleSticker + +public inline fun TelegramMediaFile.maskSimpleStickerOrThrow(): MaskSimpleSticker = this as + dev.inmo.tgbotapi.types.files.MaskSimpleSticker + +public inline fun TelegramMediaFile.ifMaskSimpleSticker(block: (MaskSimpleSticker) -> T): T? = + maskSimpleStickerOrNull() ?.let(block) + +public inline fun TelegramMediaFile.maskAnimatedStickerOrNull(): MaskAnimatedSticker? = this as? + dev.inmo.tgbotapi.types.files.MaskAnimatedSticker + +public inline fun TelegramMediaFile.maskAnimatedStickerOrThrow(): MaskAnimatedSticker = this as + dev.inmo.tgbotapi.types.files.MaskAnimatedSticker + +public inline fun TelegramMediaFile.ifMaskAnimatedSticker(block: (MaskAnimatedSticker) -> T): T? + = maskAnimatedStickerOrNull() ?.let(block) + +public inline fun TelegramMediaFile.maskVideoStickerOrNull(): MaskVideoSticker? = this as? + dev.inmo.tgbotapi.types.files.MaskVideoSticker + +public inline fun TelegramMediaFile.maskVideoStickerOrThrow(): MaskVideoSticker = this as + dev.inmo.tgbotapi.types.files.MaskVideoSticker + +public inline fun TelegramMediaFile.ifMaskVideoSticker(block: (MaskVideoSticker) -> T): T? = + maskVideoStickerOrNull() ?.let(block) + +public inline fun TelegramMediaFile.customEmojiStickerOrNull(): CustomEmojiSticker? = this as? + dev.inmo.tgbotapi.types.files.CustomEmojiSticker + +public inline fun TelegramMediaFile.customEmojiStickerOrThrow(): CustomEmojiSticker = this as + dev.inmo.tgbotapi.types.files.CustomEmojiSticker + +public inline fun TelegramMediaFile.ifCustomEmojiSticker(block: (CustomEmojiSticker) -> T): T? = + customEmojiStickerOrNull() ?.let(block) + +public inline fun TelegramMediaFile.customEmojiSimpleStickerOrNull(): CustomEmojiSimpleSticker? = + this as? dev.inmo.tgbotapi.types.files.CustomEmojiSimpleSticker + +public inline fun TelegramMediaFile.customEmojiSimpleStickerOrThrow(): CustomEmojiSimpleSticker = + this as dev.inmo.tgbotapi.types.files.CustomEmojiSimpleSticker + +public inline fun + TelegramMediaFile.ifCustomEmojiSimpleSticker(block: (CustomEmojiSimpleSticker) -> T): T? = + customEmojiSimpleStickerOrNull() ?.let(block) + +public inline fun TelegramMediaFile.customEmojiAnimatedStickerOrNull(): CustomEmojiAnimatedSticker? + = this as? dev.inmo.tgbotapi.types.files.CustomEmojiAnimatedSticker + +public inline fun TelegramMediaFile.customEmojiAnimatedStickerOrThrow(): CustomEmojiAnimatedSticker + = this as dev.inmo.tgbotapi.types.files.CustomEmojiAnimatedSticker + +public inline fun + TelegramMediaFile.ifCustomEmojiAnimatedSticker(block: (CustomEmojiAnimatedSticker) -> T): T? = + customEmojiAnimatedStickerOrNull() ?.let(block) + +public inline fun TelegramMediaFile.customEmojiVideoStickerOrNull(): CustomEmojiVideoSticker? = this + as? dev.inmo.tgbotapi.types.files.CustomEmojiVideoSticker + +public inline fun TelegramMediaFile.customEmojiVideoStickerOrThrow(): CustomEmojiVideoSticker = this + as dev.inmo.tgbotapi.types.files.CustomEmojiVideoSticker + +public inline fun + TelegramMediaFile.ifCustomEmojiVideoSticker(block: (CustomEmojiVideoSticker) -> T): T? = + customEmojiVideoStickerOrNull() ?.let(block) + +public inline fun TelegramMediaFile.unknownStickerOrNull(): UnknownSticker? = this as? + dev.inmo.tgbotapi.types.files.UnknownSticker + +public inline fun TelegramMediaFile.unknownStickerOrThrow(): UnknownSticker = this as + dev.inmo.tgbotapi.types.files.UnknownSticker + +public inline fun TelegramMediaFile.ifUnknownSticker(block: (UnknownSticker) -> T): T? = + unknownStickerOrNull() ?.let(block) public inline fun TelegramMediaFile.thumbedMediaFileOrNull(): ThumbedMediaFile? = this as? dev.inmo.tgbotapi.types.files.ThumbedMediaFile @@ -3427,6 +3552,15 @@ public inline fun TextSource.codeTextSourceOrThrow(): CodeTextSource = this as public inline fun TextSource.ifCodeTextSource(block: (CodeTextSource) -> T): T? = codeTextSourceOrNull() ?.let(block) +public inline fun TextSource.customEmojiTextSourceOrNull(): CustomEmojiTextSource? = this as? + dev.inmo.tgbotapi.types.message.textsources.CustomEmojiTextSource + +public inline fun TextSource.customEmojiTextSourceOrThrow(): CustomEmojiTextSource = this as + dev.inmo.tgbotapi.types.message.textsources.CustomEmojiTextSource + +public inline fun TextSource.ifCustomEmojiTextSource(block: (CustomEmojiTextSource) -> T): T? = + customEmojiTextSourceOrNull() ?.let(block) + public inline fun TextSource.eMailTextSourceOrNull(): EMailTextSource? = this as? dev.inmo.tgbotapi.types.message.textsources.EMailTextSource diff --git a/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/extensions/raw/Sticker.kt b/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/extensions/raw/Sticker.kt index edf5d1a448..4a5692d50a 100644 --- a/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/extensions/raw/Sticker.kt +++ b/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/extensions/raw/Sticker.kt @@ -1,8 +1,8 @@ package dev.inmo.tgbotapi.extensions.utils.extensions.raw +import dev.inmo.tgbotapi.extensions.utils.* import dev.inmo.tgbotapi.requests.abstracts.FileId -import dev.inmo.tgbotapi.types.FileUniqueId -import dev.inmo.tgbotapi.types.StickerSetName +import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.files.* import dev.inmo.tgbotapi.types.stickers.MaskPosition @@ -17,8 +17,10 @@ inline val Sticker.is_video: Boolean inline val Sticker.set_name: StickerSetName? get() = stickerSetName inline val Sticker.mask_position: MaskPosition? - get() = maskPosition + get() = maskStickerOrNull() ?.maskPosition inline val Sticker.file_size: Long? get() = fileSize inline val Sticker.premium_animation: File? - get() = premiumAnimationFile + get() = regularStickerOrNull() ?.premiumAnimationFile +inline val Sticker.custom_emoji_id: CustomEmojiId? + get() = customEmojiStickerOrNull() ?.customEmojiId diff --git a/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/formatting/EntitiesBuilder.kt b/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/formatting/EntitiesBuilder.kt index ddcfcc4bd2..d8a809aa4f 100644 --- a/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/formatting/EntitiesBuilder.kt +++ b/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/formatting/EntitiesBuilder.kt @@ -3,6 +3,7 @@ package dev.inmo.tgbotapi.extensions.utils.formatting import dev.inmo.micro_utils.common.joinTo +import dev.inmo.tgbotapi.types.CustomEmojiId import dev.inmo.tgbotapi.types.chat.User import dev.inmo.tgbotapi.types.message.textsources.* import dev.inmo.tgbotapi.utils.RiskFeature @@ -510,3 +511,39 @@ inline fun EntitiesBuilder.underline(text: String) = add(dev.inmo.tgbotapi.types * Version of [EntitiesBuilder.underline] with new line at the end */ inline fun EntitiesBuilder.underlineln(text: String) = underline(text) + newLine + + +/** + * Add customEmoji using [EntitiesBuilder.add] with [dev.inmo.tgbotapi.types.message.textsources.customEmoji] + */ +inline fun EntitiesBuilder.customEmoji(customEmojiId: CustomEmojiId, parts: TextSourcesList) = add(dev.inmo.tgbotapi.types.message.textsources.customEmoji(customEmojiId, parts)) +/** + * Version of [EntitiesBuilder.customEmoji] with new line at the end + */ +inline fun EntitiesBuilder.customEmojiln(customEmojiId: CustomEmojiId, parts: TextSourcesList) = customEmoji(customEmojiId, parts) + newLine +/** + * Add customEmoji using [EntitiesBuilder.add] with [dev.inmo.tgbotapi.types.message.textsources.customEmoji]. + * Will reuse separator config from [buildEntities] + */ +inline fun EntitiesBuilder.customEmoji(customEmojiId: CustomEmojiId, noinline init: EntitiesBuilderBody) = add(dev.inmo.tgbotapi.types.message.textsources.customEmoji(customEmojiId, buildEntities(separator, init))) +/** + * Version of [EntitiesBuilder.customEmoji] with new line at the end. + * Will reuse separator config from [buildEntities] + */ +inline fun EntitiesBuilder.customEmojiln(customEmojiId: CustomEmojiId, noinline init: EntitiesBuilderBody) = customEmoji(customEmojiId, init) + newLine +/** + * Add customEmoji using [EntitiesBuilder.add] with [dev.inmo.tgbotapi.types.message.textsources.customEmoji] + */ +inline fun EntitiesBuilder.customEmoji(customEmojiId: CustomEmojiId, vararg parts: TextSource) = add(dev.inmo.tgbotapi.types.message.textsources.customEmoji(customEmojiId, *parts)) +/** + * Version of [EntitiesBuilder.customEmoji] with new line at the end + */ +inline fun EntitiesBuilder.customEmojiln(customEmojiId: CustomEmojiId, vararg parts: TextSource) = customEmoji(customEmojiId, *parts) + newLine +/** + * Add customEmoji using [EntitiesBuilder.add] with [dev.inmo.tgbotapi.types.message.textsources.customEmoji] + */ +inline fun EntitiesBuilder.customEmoji(customEmojiId: CustomEmojiId, text: String) = add(dev.inmo.tgbotapi.types.message.textsources.customEmoji(customEmojiId, text)) +/** + * Version of [EntitiesBuilder.customEmoji] with new line at the end + */ +inline fun EntitiesBuilder.customEmojiln(customEmojiId: CustomEmojiId, text: String) = customEmoji(customEmojiId, text) + newLine diff --git a/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/formatting/LinksFormatting.kt b/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/formatting/LinksFormatting.kt index 1faac5ea31..21ec91f1fc 100644 --- a/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/formatting/LinksFormatting.kt +++ b/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/formatting/LinksFormatting.kt @@ -5,16 +5,23 @@ import dev.inmo.tgbotapi.types.chat.* import dev.inmo.tgbotapi.types.message.abstracts.Message import dev.inmo.tgbotapi.types.message.textsources.link + fun makeUsernameLink(username: String) = "$internalLinkBeginning/$username" fun makeUsernameDeepLinkPrefix(username: String) = "${makeUsernameLink(username)}?start=" +fun makeUsernameStartattachPrefix(username: String) = "$internalLinkBeginning/$username?startattach" +fun makeUsernameStartattachLink(username: String, data: String? = null) = "${makeUsernameStartattachPrefix(username)}${data?.let { "=$it" } ?: ""}" inline val Username.link get() = makeUsernameLink(usernameWithoutAt) inline val Username.deepLinkPrefix get() = makeUsernameDeepLinkPrefix(usernameWithoutAt) +inline val Username.startattachPrefix + get() = makeUsernameStartattachPrefix(usernameWithoutAt) inline fun makeLink(username: Username) = username.link inline fun makeTelegramDeepLink(username: String, startParameter: String) = "${makeUsernameDeepLinkPrefix(username)}$startParameter" +inline fun makeTelegramStartattach(username: String, data: String? = null) = makeUsernameStartattachLink(username, data) inline fun makeDeepLink(username: Username, startParameter: String) = "${username.deepLinkPrefix}$startParameter" inline fun makeTelegramDeepLink(username: Username, startParameter: String) = makeDeepLink(username, startParameter) +inline fun makeTelegramStartattach(username: Username, data: String? = null) = makeTelegramStartattach(username.username, data) fun makeLinkToMessage( username: String,