From c3668e978b2d1058df6149a627f5a8c9db4a53d9 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Fri, 12 Aug 2022 23:21:53 +0600 Subject: [PATCH] add support of custom emojis --- CHANGELOG.md | 3 ++ .../kotlin/dev/inmo/tgbotapi/types/Common.kt | 7 ++++ .../types/message/RawMessageEntity.kt | 8 +++- .../textsources/CustomEmojiTextSource.kt | 31 ++++++++++++++++ .../textsources/TextSourceSerializer.kt | 1 + .../utils/internal/StringFormatting.kt | 4 ++ .../extensions/utils/ClassCastsNew.kt | 10 +++++ .../utils/formatting/EntitiesBuilder.kt | 37 +++++++++++++++++++ 8 files changed, 99 insertions(+), 2 deletions(-) create mode 100644 tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/textsources/CustomEmojiTextSource.kt diff --git a/CHANGELOG.md b/CHANGELOG.md index 62e51d386b..91d0d46c06 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ ## 3.1.0 +* `Core`: + * Add support of `custom emoji`s + ## 3.0.2 **ALL OLD DEPRECATIONS HAVE BEEN REMOVED** 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..cd3148226a 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,8 @@ package dev.inmo.tgbotapi.types import dev.inmo.tgbotapi.utils.BuiltinMimeTypes +import kotlinx.serialization.Serializable +import kotlin.jvm.JvmInline typealias Identifier = Long typealias MessageIdentifier = Long @@ -28,6 +30,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 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..13ef5a42f8 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) + 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/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/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..13f4fe7b02 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 @@ -295,6 +295,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 @@ -3427,6 +3428,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/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