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 ee4df3827e..b30bc94e4e 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 @@ -229,6 +229,7 @@ const val textEntitiesField = "text_entities" const val entitiesField = "entities" const val stickerSetNameField = "set_name" const val customEmojiIdField = "custom_emoji_id" +const val customEmojiField = "custom_emoji" const val customEmojiIdsField = "custom_emoji_ids" const val premiumAnimationField = "premium_animation" const val stickerSetNameFullField = "sticker_set_name" diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/reactions/Reaction.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/reactions/Reaction.kt new file mode 100644 index 0000000000..15aadf8e94 --- /dev/null +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/reactions/Reaction.kt @@ -0,0 +1,93 @@ +package dev.inmo.tgbotapi.types.reactions + +import dev.inmo.tgbotapi.types.CustomEmojiId +import dev.inmo.tgbotapi.types.customEmojiField +import dev.inmo.tgbotapi.types.emojiField +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 +import kotlinx.serialization.json.JsonDecoder +import kotlinx.serialization.json.JsonElement + +@Serializable +@ClassCastsIncluded +sealed interface Reaction { + val type: String + + @Serializable(Reaction.Companion::class) + data class Emoji( + val emoji: String + ) : Reaction { + override val type: String + get() = Companion.type + companion object { + const val type: String = "emoji" + } + } + + @Serializable(Reaction.Companion::class) + data class CustomEmoji( + val customEmoji: CustomEmojiId + ) : Reaction { + override val type: String + get() = Companion.type + companion object { + const val type: String = "custom_emoji" + } + } + + @Serializable(Reaction.Companion::class) + data class Unknown( + override val type: String, + val sourceJson: JsonElement? + ) : Reaction + + @Serializable + private data class Surrogate( + val type: String, + @SerialName(emojiField) + val emoji: String? = null, + @SerialName(customEmojiField) + val customEmoji: CustomEmojiId? = null + ) + + companion object : KSerializer { + override val descriptor: SerialDescriptor + get() = Surrogate.serializer().descriptor + + override fun deserialize(decoder: Decoder): Reaction { + val (surrogate, json) = if (decoder is JsonDecoder) { + val json = decoder.decodeJsonElement() + decoder.json.decodeFromJsonElement(Surrogate.serializer(), json) to json + } else { + Surrogate.serializer().deserialize(decoder) to null + } + + return when { + surrogate.emoji != null -> Emoji(surrogate.emoji) + surrogate.customEmoji != null -> CustomEmoji(surrogate.customEmoji) + else -> Unknown(surrogate.type, json) + } + } + + override fun serialize(encoder: Encoder, value: Reaction) { + if (value is Unknown && value.sourceJson != null) { + JsonElement.serializer().serialize(encoder, value.sourceJson) + } else { + Surrogate.serializer().serialize( + encoder, + Surrogate( + type = value.type, + emoji = (value as? Emoji) ?.emoji, + customEmoji = (value as? CustomEmoji) ?.customEmoji, + ) + ) + } + } + + } +} 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 5dadba2ded..932b1e9fc9 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 @@ -415,6 +415,7 @@ import dev.inmo.tgbotapi.types.queries.callback.MessageCallbackQuery import dev.inmo.tgbotapi.types.queries.callback.MessageDataCallbackQuery import dev.inmo.tgbotapi.types.queries.callback.MessageGameShortNameCallbackQuery import dev.inmo.tgbotapi.types.queries.callback.UnknownCallbackQueryType +import dev.inmo.tgbotapi.types.reactions.Reaction import dev.inmo.tgbotapi.types.request.ChatShared import dev.inmo.tgbotapi.types.request.ChatSharedRequest import dev.inmo.tgbotapi.types.request.RequestResponse @@ -4485,6 +4486,33 @@ public inline fun Poll.quizPollOrThrow(): QuizPoll = this as dev.inmo.tgbotapi.t public inline fun Poll.ifQuizPoll(block: (QuizPoll) -> T): T? = quizPollOrNull() ?.let(block) +public inline fun Reaction.customEmojiOrNull(): Reaction.CustomEmoji? = this as? + dev.inmo.tgbotapi.types.reactions.Reaction.CustomEmoji + +public inline fun Reaction.customEmojiOrThrow(): Reaction.CustomEmoji = this as + dev.inmo.tgbotapi.types.reactions.Reaction.CustomEmoji + +public inline fun Reaction.ifCustomEmoji(block: (Reaction.CustomEmoji) -> T): T? = + customEmojiOrNull() ?.let(block) + +public inline fun Reaction.emojiOrNull(): Reaction.Emoji? = this as? + dev.inmo.tgbotapi.types.reactions.Reaction.Emoji + +public inline fun Reaction.emojiOrThrow(): Reaction.Emoji = this as + dev.inmo.tgbotapi.types.reactions.Reaction.Emoji + +public inline fun Reaction.ifEmoji(block: (Reaction.Emoji) -> T): T? = emojiOrNull() + ?.let(block) + +public inline fun Reaction.unknownOrNull(): Reaction.Unknown? = this as? + dev.inmo.tgbotapi.types.reactions.Reaction.Unknown + +public inline fun Reaction.unknownOrThrow(): Reaction.Unknown = this as + dev.inmo.tgbotapi.types.reactions.Reaction.Unknown + +public inline fun Reaction.ifUnknown(block: (Reaction.Unknown) -> T): T? = unknownOrNull() + ?.let(block) + public inline fun RequestResponse.chatSharedOrNull(): ChatShared? = this as? dev.inmo.tgbotapi.types.request.ChatShared