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 7698ed7051..57efb1874d 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 @@ -59,6 +59,8 @@ sealed interface StickerType { 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 @@ -68,7 +70,7 @@ sealed interface StickerType { Regular.type -> Regular Mask.type -> Regular CustomEmoji.type -> Regular - else -> error("Unknown type of emoji $type") + else -> Unknown(type) } } 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 bb380507eb..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,10 +4,12 @@ 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") @@ -44,7 +46,8 @@ 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.type) { StickerType.Regular -> when { @@ -82,19 +85,41 @@ object StickerSerializer : KSerializer { surrogate.file_size ) } - StickerType.Mask -> MaskSticker( - 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.is_animated == true, - surrogate.is_video == true, - surrogate.thumb, - surrogate.emoji, - surrogate.set_name, - 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, @@ -130,6 +155,17 @@ object StickerSerializer : KSerializer { surrogate.file_size ) } + is StickerType.Unknown -> UnknownSticker( + surrogate.file_id, + surrogate.file_unique_id, + surrogate.width, + surrogate.height, + surrogate.thumb, + surrogate.emoji, + surrogate.set_name, + surrogate.file_size, + json + ) } } @@ -139,48 +175,22 @@ object StickerSerializer : KSerializer { } -@Serializable(StickerSerializer::class) +@Serializable sealed interface VideoSticker : Sticker { override val isVideo: Boolean get() = true } -@Serializable(StickerSerializer::class) +@Serializable sealed interface AnimatedSticker : Sticker { override val isAnimated: Boolean get() = true } -@Serializable(StickerSerializer::class) +@Serializable sealed interface RegularSticker : Sticker { val premiumAnimationFile: File? } -@Serializable -data class MaskSticker( - @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) - val maskPosition: MaskPosition, - @SerialName(isAnimatedField) - override val isAnimated: Boolean, - @SerialName(isVideoField) - override val isVideo: Boolean, - @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, -) : Sticker - @Serializable data class RegularSimpleSticker( @SerialName(fileIdField) @@ -247,7 +257,76 @@ data class RegularVideoSticker( override val fileSize: Long? = null, ) : RegularSticker, VideoSticker -@Serializable(StickerSerializer::class) + +@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 } @@ -315,3 +394,24 @@ data class CustomEmojiVideoSticker( @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/stickers/StickerSet.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/stickers/StickerSet.kt index 663a6e48bc..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 @@ -2,86 +2,297 @@ package dev.inmo.tgbotapi.types.stickers import dev.inmo.tgbotapi.types.* 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 SurrogateStickerSet( + val name: String, + val title: String, + 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 { - @SerialName(nameField) val name: String - @SerialName(titleField) val title: String - @SerialName(stickerTypeField) val stickerType: StickerType - @SerialName(stickersField) val stickers: List - @SerialName(isAnimatedField) val isAnimated: Boolean - @SerialName(isVideoField) + get() = false val isVideo: Boolean - @SerialName(containsMasksField) + get() = false + val thumb: PhotoSize? @Deprecated("Will be removed soon due to its redundancy") val containsMasks: Boolean get() = this is MaskStickerSet - @SerialName(thumbField) - val thumb: PhotoSize? + + 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 -data class RegularStickerSet( +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(isAnimatedField) - override val isAnimated: Boolean = false, - @SerialName(isVideoField) - override val isVideo: Boolean = false, + override val stickers: List, @SerialName(thumbField) override val thumb: PhotoSize? = null -) : StickerSet { +) : RegularStickerSet { @SerialName(stickerTypeField) @EncodeDefault override val stickerType: StickerType = StickerType.Regular } @Serializable -data class MaskStickerSet( +data class RegularAnimatedStickerSet( @SerialName(nameField) override val name: String, @SerialName(titleField) override val title: String, @SerialName(stickersField) - override val stickers: List, - @SerialName(isAnimatedField) - override val isAnimated: Boolean = false, - @SerialName(isVideoField) - override val isVideo: Boolean = false, + override val stickers: List, @SerialName(thumbField) override val thumb: PhotoSize? = null -) : StickerSet { +) : 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 CustomEmojiStickerSet( +data class MaskAnimatedStickerSet( @SerialName(nameField) override val name: String, @SerialName(titleField) override val title: String, @SerialName(stickersField) - override val stickers: List, - @SerialName(isAnimatedField) - override val isAnimated: Boolean = false, - @SerialName(isVideoField) - override val isVideo: Boolean = false, + override val stickers: List, @SerialName(thumbField) override val thumb: PhotoSize? = null -) : StickerSet { +) : 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