mirror of
https://github.com/InsanusMokrassar/TelegramBotAPI.git
synced 2024-11-14 04:13:47 +00:00
add spoiler support
This commit is contained in:
parent
bd60c4f411
commit
5c5a19c91a
@ -11,6 +11,8 @@
|
|||||||
* `Klock`: `2.4.8` -> `2.4.10`
|
* `Klock`: `2.4.8` -> `2.4.10`
|
||||||
* `Ktor`: `1.6.5` -> `1.6.7`
|
* `Ktor`: `1.6.5` -> `1.6.7`
|
||||||
* `MicroUtils`: `0.8.7` -> `0.9.0`
|
* `MicroUtils`: `0.8.7` -> `0.9.0`
|
||||||
|
* `Core`:
|
||||||
|
* Add `SpoilerTextSource` (as part of `Telegram Bot API 5.6` update)
|
||||||
|
|
||||||
## 0.37.4
|
## 0.37.4
|
||||||
|
|
||||||
|
@ -49,6 +49,7 @@ internal fun RawMessageEntity.asTextSource(
|
|||||||
)
|
)
|
||||||
"underline" -> UnderlineTextSource(sourceSubstring, subPartsWithRegulars)
|
"underline" -> UnderlineTextSource(sourceSubstring, subPartsWithRegulars)
|
||||||
"strikethrough" -> StrikethroughTextSource(sourceSubstring, subPartsWithRegulars)
|
"strikethrough" -> StrikethroughTextSource(sourceSubstring, subPartsWithRegulars)
|
||||||
|
"spoiler" -> SpoilerTextSource(sourceSubstring, subPartsWithRegulars)
|
||||||
else -> RegularTextSource(sourceSubstring)
|
else -> RegularTextSource(sourceSubstring)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -158,6 +159,7 @@ internal fun TextSource.toRawMessageEntities(offset: Int = 0): List<RawMessageEn
|
|||||||
is TextMentionTextSource -> RawMessageEntity("text_mention", offset, length, user = user)
|
is TextMentionTextSource -> RawMessageEntity("text_mention", offset, length, user = user)
|
||||||
is UnderlineTextSource -> RawMessageEntity("underline", offset, length)
|
is UnderlineTextSource -> RawMessageEntity("underline", offset, length)
|
||||||
is StrikethroughTextSource -> RawMessageEntity("strikethrough", offset, length)
|
is StrikethroughTextSource -> RawMessageEntity("strikethrough", offset, length)
|
||||||
|
is SpoilerTextSource -> RawMessageEntity("spoiler", offset, length)
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
) + if (this is MultilevelTextSource) {
|
) + if (this is MultilevelTextSource) {
|
||||||
|
@ -0,0 +1,27 @@
|
|||||||
|
package dev.inmo.tgbotapi.types.MessageEntity.textsources
|
||||||
|
|
||||||
|
import dev.inmo.tgbotapi.utils.RiskFeature
|
||||||
|
import dev.inmo.tgbotapi.utils.extensions.makeString
|
||||||
|
import dev.inmo.tgbotapi.utils.internal.*
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see italic
|
||||||
|
*/
|
||||||
|
@Serializable
|
||||||
|
data class SpoilerTextSource @RiskFeature(DirectInvocationOfTextSourceConstructor) constructor (
|
||||||
|
override val source: String,
|
||||||
|
override val subsources: TextSourcesList
|
||||||
|
) : MultilevelTextSource {
|
||||||
|
override val markdown: String by lazy { source.spoilerMarkdown() }
|
||||||
|
override val markdownV2: String by lazy { spoilerMarkdownV2() }
|
||||||
|
override val html: String by lazy { spoilerHTML() }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
inline fun spoiler(parts: TextSourcesList) = SpoilerTextSource(parts.makeString(), parts)
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
inline fun spoiler(vararg parts: TextSource) = spoiler(parts.toList())
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
inline fun spoiler(text: String) = spoiler(regular(text))
|
||||||
|
|
@ -20,6 +20,7 @@ private val baseSerializers: Map<String, KSerializer<out TextSource>> = mapOf(
|
|||||||
"text_mention" to TextMentionTextSource.serializer(),
|
"text_mention" to TextMentionTextSource.serializer(),
|
||||||
"hashtag" to HashTagTextSource.serializer(),
|
"hashtag" to HashTagTextSource.serializer(),
|
||||||
"cashtag" to CashTagTextSource.serializer(),
|
"cashtag" to CashTagTextSource.serializer(),
|
||||||
|
"spoiler" to SpoilerTextSource.serializer(),
|
||||||
)
|
)
|
||||||
|
|
||||||
object TextSourceSerializer : TypedSerializer<TextSource>(TextSource::class, baseSerializers) {
|
object TextSourceSerializer : TypedSerializer<TextSource>(TextSource::class, baseSerializers) {
|
||||||
|
@ -49,6 +49,10 @@ internal fun MultilevelTextSource.italicMarkdownV2(): String = markdownV2Default
|
|||||||
internal fun MultilevelTextSource.italicHTML(): String = htmlDefault(htmlItalicControl)
|
internal fun MultilevelTextSource.italicHTML(): String = htmlDefault(htmlItalicControl)
|
||||||
|
|
||||||
|
|
||||||
|
internal fun MultilevelTextSource.spoilerMarkdownV2(): String = markdownV2Default(markdownSpoilerControl)
|
||||||
|
internal fun MultilevelTextSource.spoilerHTML(): String = htmlDefault(htmlSpoilerControl, htmlSpoilerClosingControl)
|
||||||
|
|
||||||
|
|
||||||
internal fun MultilevelTextSource.strikethroughMarkdownV2(): String = markdownV2Default(markdownV2StrikethroughControl)
|
internal fun MultilevelTextSource.strikethroughMarkdownV2(): String = markdownV2Default(markdownV2StrikethroughControl)
|
||||||
internal fun MultilevelTextSource.strikethroughHTML(): String = htmlDefault(htmlStrikethroughControl)
|
internal fun MultilevelTextSource.strikethroughHTML(): String = htmlDefault(htmlStrikethroughControl)
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ import dev.inmo.tgbotapi.utils.extensions.*
|
|||||||
|
|
||||||
const val markdownBoldControl = "*"
|
const val markdownBoldControl = "*"
|
||||||
const val markdownItalicControl = "_"
|
const val markdownItalicControl = "_"
|
||||||
|
const val markdownSpoilerControl = "||"
|
||||||
const val markdownCodeControl = "`"
|
const val markdownCodeControl = "`"
|
||||||
const val markdownPreControl = "```"
|
const val markdownPreControl = "```"
|
||||||
|
|
||||||
@ -18,6 +19,8 @@ const val markdownV2ItalicEndControl = "$markdownItalicControl$markdownV2ItalicU
|
|||||||
|
|
||||||
const val htmlBoldControl = "b"
|
const val htmlBoldControl = "b"
|
||||||
const val htmlItalicControl = "i"
|
const val htmlItalicControl = "i"
|
||||||
|
const val htmlSpoilerControl = "span class=\"tg-spoiler\""
|
||||||
|
const val htmlSpoilerClosingControl = "span"
|
||||||
const val htmlCodeControl = "code"
|
const val htmlCodeControl = "code"
|
||||||
const val htmlPreControl = "pre"
|
const val htmlPreControl = "pre"
|
||||||
const val htmlUnderlineControl = "u"
|
const val htmlUnderlineControl = "u"
|
||||||
@ -46,12 +49,13 @@ internal fun String.boldMarkdown(): String = markdownDefault(markdownBoldControl
|
|||||||
|
|
||||||
internal fun String.italicMarkdown(): String = markdownDefault(markdownItalicControl)
|
internal fun String.italicMarkdown(): String = markdownDefault(markdownItalicControl)
|
||||||
|
|
||||||
|
internal fun String.spoilerMarkdown(): String = markdownDefault(markdownSpoilerControl)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Crutch for support of strikethrough in default markdown. Simply add modifier, but it will not look like correct
|
* Crutch for support of strikethrough in default markdown. Simply add modifier, but it will not look like correct
|
||||||
*/
|
*/
|
||||||
|
|
||||||
internal fun String.strikethroughMarkdown(): String = map { it + "\u0336" }.joinToString("")
|
internal fun String.strikethroughMarkdown(): String = map { it + "\u0336" }.joinToString("")
|
||||||
internal fun String.strikethroughMarkdownV2(): String = markdownV2Default(markdownV2StrikethroughControl)
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -4,8 +4,8 @@ import dev.inmo.tgbotapi.types.MessageEntity.textsources.*
|
|||||||
import kotlin.test.assertTrue
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
const val testText = "It is simple hello world with #tag and @mention"
|
const val testText = "It is simple hello world with #tag and @mention"
|
||||||
const val formattedV2Text = "It *_is_ ~__simple__~* hello world with \\#tag and @mention"
|
const val formattedV2Text = "It *_is_ ~__simple__~* ||hello world|| with \\#tag and @mention"
|
||||||
const val formattedHtmlText = "It <b><i>is</i> <s><u>simple</u></s></b> hello world with #tag and @mention"
|
const val formattedHtmlText = "It <b><i>is</i> <s><u>simple</u></s></b> <span class=\"tg-spoiler\">hello world</span> with #tag and @mention"
|
||||||
internal val testTextEntities = listOf(
|
internal val testTextEntities = listOf(
|
||||||
RawMessageEntity(
|
RawMessageEntity(
|
||||||
"bold",
|
"bold",
|
||||||
@ -27,6 +27,11 @@ internal val testTextEntities = listOf(
|
|||||||
6,
|
6,
|
||||||
6
|
6
|
||||||
),
|
),
|
||||||
|
RawMessageEntity(
|
||||||
|
"spoiler",
|
||||||
|
13,
|
||||||
|
11
|
||||||
|
),
|
||||||
RawMessageEntity(
|
RawMessageEntity(
|
||||||
"hashtag",
|
"hashtag",
|
||||||
30,
|
30,
|
||||||
@ -43,9 +48,11 @@ fun TextSourcesList.testTextSources() {
|
|||||||
assertTrue (first() is RegularTextSource)
|
assertTrue (first() is RegularTextSource)
|
||||||
assertTrue (get(1) is BoldTextSource)
|
assertTrue (get(1) is BoldTextSource)
|
||||||
assertTrue (get(2) is RegularTextSource)
|
assertTrue (get(2) is RegularTextSource)
|
||||||
assertTrue (get(3) is HashTagTextSource)
|
assertTrue (get(3) is SpoilerTextSource)
|
||||||
assertTrue (get(4) is RegularTextSource)
|
assertTrue (get(4) is RegularTextSource)
|
||||||
assertTrue (get(5) is MentionTextSource)
|
assertTrue (get(5) is HashTagTextSource)
|
||||||
|
assertTrue (get(6) is RegularTextSource)
|
||||||
|
assertTrue (get(7) is MentionTextSource)
|
||||||
|
|
||||||
val boldSource = get(1) as BoldTextSource
|
val boldSource = get(1) as BoldTextSource
|
||||||
assertTrue (boldSource.subsources.first() is ItalicTextSource)
|
assertTrue (boldSource.subsources.first() is ItalicTextSource)
|
||||||
|
@ -42,7 +42,9 @@ class StringFormattingTests {
|
|||||||
bold(italic("is") +
|
bold(italic("is") +
|
||||||
" " +
|
" " +
|
||||||
strikethrough(underline("simple"))) +
|
strikethrough(underline("simple"))) +
|
||||||
" hello world with " +
|
" " +
|
||||||
|
spoiler("hello world") +
|
||||||
|
" with " +
|
||||||
hashtag("tag") +
|
hashtag("tag") +
|
||||||
" and " +
|
" and " +
|
||||||
mention("mention")
|
mention("mention")
|
||||||
|
@ -3,6 +3,7 @@ package dev.inmo.tgbotapi.types
|
|||||||
import dev.inmo.tgbotapi.TestsJsonFormat
|
import dev.inmo.tgbotapi.TestsJsonFormat
|
||||||
import dev.inmo.tgbotapi.extensions.utils.formatting.*
|
import dev.inmo.tgbotapi.extensions.utils.formatting.*
|
||||||
import dev.inmo.tgbotapi.types.MessageEntity.textsources.TextSourceSerializer
|
import dev.inmo.tgbotapi.types.MessageEntity.textsources.TextSourceSerializer
|
||||||
|
import dev.inmo.tgbotapi.types.MessageEntity.textsources.spoiler
|
||||||
import dev.inmo.tgbotapi.utils.extensions.makeString
|
import dev.inmo.tgbotapi.utils.extensions.makeString
|
||||||
import kotlinx.serialization.builtins.ListSerializer
|
import kotlinx.serialization.builtins.ListSerializer
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
@ -16,6 +17,11 @@ class TextSourcesTests {
|
|||||||
italic("It")
|
italic("It")
|
||||||
link("is example", "https://is.example")
|
link("is example", "https://is.example")
|
||||||
}
|
}
|
||||||
|
spoiler {
|
||||||
|
regular("and")
|
||||||
|
italic("that")
|
||||||
|
link("is spoiler", "https://is.example")
|
||||||
|
}
|
||||||
underline("of")
|
underline("of")
|
||||||
italic(
|
italic(
|
||||||
buildEntities {
|
buildEntities {
|
||||||
@ -32,6 +38,6 @@ class TextSourcesTests {
|
|||||||
)
|
)
|
||||||
assertEquals(testList, deserialized)
|
assertEquals(testList, deserialized)
|
||||||
assertEquals(testList.makeString(), deserialized.makeString())
|
assertEquals(testList.makeString(), deserialized.makeString())
|
||||||
assertEquals("It is example of complex text", testList.makeString())
|
assertEquals("It is example and that is spoiler of complex text", testList.makeString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -99,6 +99,41 @@ inline fun EntitiesBuilder.bold(text: String) = add(dev.inmo.tgbotapi.types.Mess
|
|||||||
*/
|
*/
|
||||||
inline fun EntitiesBuilder.boldln(text: String) = bold(text) + newLine
|
inline fun EntitiesBuilder.boldln(text: String) = bold(text) + newLine
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add spoiler using [EntitiesBuilder.add] with [dev.inmo.tgbotapi.types.MessageEntity.textsources.spoiler]
|
||||||
|
*/
|
||||||
|
inline fun EntitiesBuilder.spoiler(parts: TextSourcesList) = add(dev.inmo.tgbotapi.types.MessageEntity.textsources.spoiler(parts))
|
||||||
|
/**
|
||||||
|
* Version of [EntitiesBuilder.spoiler] with new line at the end
|
||||||
|
*/
|
||||||
|
inline fun EntitiesBuilder.spoilerln(parts: TextSourcesList) = spoiler(parts) + newLine
|
||||||
|
/**
|
||||||
|
* Add spoiler using [EntitiesBuilder.add] with [dev.inmo.tgbotapi.types.MessageEntity.textsources.spoiler].
|
||||||
|
* Will reuse separator config from [buildEntities]
|
||||||
|
*/
|
||||||
|
inline fun EntitiesBuilder.spoiler(noinline init: EntitiesBuilderBody) = add(dev.inmo.tgbotapi.types.MessageEntity.textsources.spoiler(buildEntities(separator, init)))
|
||||||
|
/**
|
||||||
|
* Version of [EntitiesBuilder.spoiler] with new line at the end.
|
||||||
|
* Will reuse separator config from [buildEntities]
|
||||||
|
*/
|
||||||
|
inline fun EntitiesBuilder.spoilerln(noinline init: EntitiesBuilderBody) = spoiler(init) + newLine
|
||||||
|
/**
|
||||||
|
* Add spoiler using [EntitiesBuilder.add] with [dev.inmo.tgbotapi.types.MessageEntity.textsources.spoiler]
|
||||||
|
*/
|
||||||
|
inline fun EntitiesBuilder.spoiler(vararg parts: TextSource) = add(dev.inmo.tgbotapi.types.MessageEntity.textsources.spoiler(*parts))
|
||||||
|
/**
|
||||||
|
* Version of [EntitiesBuilder.spoiler] with new line at the end
|
||||||
|
*/
|
||||||
|
inline fun EntitiesBuilder.spoilerln(vararg parts: TextSource) = spoiler(*parts) + newLine
|
||||||
|
/**
|
||||||
|
* Add spoiler using [EntitiesBuilder.add] with [dev.inmo.tgbotapi.types.MessageEntity.textsources.spoiler]
|
||||||
|
*/
|
||||||
|
inline fun EntitiesBuilder.spoiler(text: String) = add(dev.inmo.tgbotapi.types.MessageEntity.textsources.spoiler(text))
|
||||||
|
/**
|
||||||
|
* Version of [EntitiesBuilder.spoiler] with new line at the end
|
||||||
|
*/
|
||||||
|
inline fun EntitiesBuilder.spoilerln(text: String) = spoiler(text) + newLine
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add botCommand using [EntitiesBuilder.add] with [dev.inmo.tgbotapi.types.MessageEntity.textsources.botCommand]
|
* Add botCommand using [EntitiesBuilder.add] with [dev.inmo.tgbotapi.types.MessageEntity.textsources.botCommand]
|
||||||
|
Loading…
Reference in New Issue
Block a user