1
0
mirror of https://github.com/InsanusMokrassar/TelegramBotAPI.git synced 2026-01-02 19:39:26 +00:00

Compare commits

...

25 Commits

Author SHA1 Message Date
83ea4f6435 Update gradle.properties 2022-04-08 09:49:06 +06:00
52204d8df1 Experemtally update kotlin 2022-04-08 09:44:37 +06:00
81b9ccdf6a Update VideoContent.kt 2022-04-08 09:29:07 +06:00
fa74f12505 Update CHANGELOG.md 2022-04-08 02:09:22 +06:00
be284c4d96 Update dependencies 2022-04-08 02:08:21 +06:00
1769fcacfd update gradle 2022-04-06 11:45:08 +06:00
4207d89c92 accumulated updates improvements 2022-04-04 13:16:18 +06:00
87ee2f280b remove redundant TextedMediaInputMediaContent 2022-04-03 19:56:34 +06:00
3d458b2dc6 fixes in builds and filling up functionality related to new classes 2022-04-03 19:48:48 +06:00
ee1c7c6533 TextedMediaGroupMediaInput 2022-04-03 19:37:56 +06:00
97d122c770 TextedMediaContent fixes 2022-04-03 19:29:48 +06:00
49da0faf45 replies with texted content 2022-04-03 19:21:38 +06:00
d426cb1210 TextedMediaContent 2022-04-03 19:06:27 +06:00
af83ac79e7 start 0.38.12 2022-04-03 18:35:17 +06:00
602f15c206 Update README.md 2022-04-01 00:01:25 +06:00
c2f40534e6 Update README.md 2022-03-31 23:55:34 +06:00
5693d4d808 Merge pull request #548 from InsanusMokrassar/0.38.11
0.38.11
2022-03-29 23:40:04 +06:00
9fe55aa6ef Update CHANGELOG.md 2022-03-29 12:42:02 +06:00
8f817f1492 reply with any media file 2022-03-29 12:37:54 +06:00
0fd146655d old matrix and row deprecation 2022-03-29 12:27:03 +06:00
94e5f74a90 reply with content 2022-03-29 12:20:52 +06:00
b9bffbb71b update dependencies 2022-03-27 13:47:38 +06:00
5ec5c3bdfd Fixes in "TextSourcesList" creating in from "RawMessageEntities" 2022-03-27 13:44:41 +06:00
a5ed2a82bb start 0.38.11 2022-03-27 13:36:21 +06:00
1b7dd11e75 Merge pull request #545 from InsanusMokrassar/0.38.10
0.38.10
2022-03-25 10:36:21 +06:00
48 changed files with 695 additions and 142 deletions

View File

@@ -1,5 +1,33 @@
# TelegramBotAPI changelog # TelegramBotAPI changelog
## 0.38.12
* `Common`:
* `Version`:
* `MicroUtils`: `0.9.17` -> `0.9.19`
* `Coroutines`: `1.6.0` -> `1.6.1`
* `Core`:
* New type `TextedMediaContent` which will unite `TextedInput` and `MediaContent`
* `MediaGroupContent` and all subsequent inheritors have been replaced to the package `dev.inmo.tgbotapi.types.message.content.media`
* `MediaGroupContent` Now extends `TextedMediaContent` instead of `MediaContent`
* Add `reply` functions with the texted content with including of text
* `Utils`:
* Improve work with retrieving of accumulated updates
## 0.38.11
* `Common`:
* `Version`:
* `MicroUtils`: `0.9.16` -> `0.9.17`
* `Klock`: `2.6.3` -> `2.7.0`
* `Core`:
* Fixes in `TextSourcesList` creating in from `RawMessageEntities`
* Old ways to create keyboards (`matrix` and `row`) have been deprecated
* `API`:
* Add ability to `reply` with `Poll`
* Add ability to `reply` with any `MessageContent`
* Add ability to `reply` with any `TelegramMediaFile`
## 0.38.10 ## 0.38.10
* `API`: * `API`:

View File

@@ -1,8 +1,8 @@
# 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-5.7-blue)](https://core.telegram.org/bots/api-changelog#january-31-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-5.7-blue)](https://core.telegram.org/bots/api-changelog#january-31-2022)
| [![Awesome Kotlin Badge](https://kotlin.link/awesome-kotlin.svg)](https://github.com/KotlinBy/awesome-kotlin) [![Build Status](https://github.com/InsanusMokrassar/TelegramBotAPI/workflows/Build/badge.svg)](https://github.com/InsanusMokrassar/TelegramBotAPI/actions) [![Small survey](https://img.shields.io/static/v1?label=Google&message=Survey&color=blue)](https://forms.gle/2Hex2ynbHWHhi1KY7) [![Chat in Telegram](https://img.shields.io/static/v1?label=Telegram&message=Chat&color=blue)](https://t.me/InMoTelegramBotAPI) | | [![Awesome Kotlin Badge](https://kotlin.link/awesome-kotlin.svg)](https://github.com/KotlinBy/awesome-kotlin) [![Build Status](https://github.com/InsanusMokrassar/TelegramBotAPI/workflows/Build/badge.svg)](https://github.com/InsanusMokrassar/TelegramBotAPI/actions) [![Small survey](https://img.shields.io/static/v1?label=Google&message=Survey&color=blue&logo=google-sheets)](https://docs.google.com/forms/d/e/1FAIpQLSctdJHT_aEniyYT0-IUAEfo1hsIlezX2owlkEAYX4KPl2V2_A/viewform?usp=sf_link) [![Chat in Telegram](https://img.shields.io/static/v1?label=Telegram&message=Chat&color=blue&logo=telegram)](https://t.me/InMoTelegramBotAPI) |
|:---:| |:---:|
| [![Create bot](https://img.shields.io/static/v1?label=Github&message=Template&color=blue)](https://github.com/InsanusMokrassar/TelegramBotAPI-bot_template/generate) [![Examples](https://img.shields.io/static/v1?label=Github&message=Examples&color=blue)](https://github.com/InsanusMokrassar/TelegramBotAPI-examples/) [![KDocs](https://img.shields.io/static/v1?label=Dokka&message=KDocs&color=blue)](https://tgbotapi.inmo.dev/index.html) [![Mini tutorial](https://img.shields.io/static/v1?label=Bookstack&message=Tutorial&color=blue)](https://bookstack.inmo.dev/books/telegrambotapi/chapter/introduction-tutorial) | | [![Create bot](https://img.shields.io/static/v1?label=Github&message=Template&color=blue&logo=github)](https://github.com/InsanusMokrassar/TelegramBotAPI-bot_template/generate) [![Examples](https://img.shields.io/static/v1?label=Github&message=Examples&color=blue&logo=github)](https://github.com/InsanusMokrassar/TelegramBotAPI-examples/) [![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) |
Hello! This is a set of libraries for working with Telegram Bot API. Hello! This is a set of libraries for working with Telegram Bot API.

View File

@@ -6,13 +6,13 @@ kotlin.incremental=true
kotlin.incremental.js=true kotlin.incremental.js=true
kotlin_version=1.6.10 kotlin_version=1.6.10
kotlin_coroutines_version=1.6.0 kotlin_coroutines_version=1.6.1
kotlin_serialisation_runtime_version=1.3.2 kotlin_serialisation_runtime_version=1.3.2
klock_version=2.6.3 klock_version=2.7.0
uuid_version=0.4.0 uuid_version=0.4.0
ktor_version=1.6.8 ktor_version=1.6.8
micro_utils_version=0.9.16 micro_utils_version=0.9.19
javax_activation_version=1.1.1 javax_activation_version=1.1.1
@@ -20,6 +20,6 @@ javax_activation_version=1.1.1
dokka_version=1.6.10 dokka_version=1.6.10
library_group=dev.inmo library_group=dev.inmo
library_version=0.38.10 library_version=0.38.12
github_release_plugin_version=2.2.12 github_release_plugin_version=2.2.12

View File

@@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.1-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip

View File

@@ -2,18 +2,14 @@ package dev.inmo.tgbotapi.extensions.api.send
import dev.inmo.tgbotapi.bot.TelegramBot import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.extensions.api.send.media.sendMediaGroup import dev.inmo.tgbotapi.extensions.api.send.media.sendMediaGroup
import dev.inmo.tgbotapi.requests.send.CopyMessage
import dev.inmo.tgbotapi.types.ChatIdentifier import dev.inmo.tgbotapi.types.ChatIdentifier
import dev.inmo.tgbotapi.types.InputMedia.* import dev.inmo.tgbotapi.types.InputMedia.*
import dev.inmo.tgbotapi.types.MessageEntity.textsources.TextSourcesList import dev.inmo.tgbotapi.types.MessageEntity.textsources.TextSourcesList
import dev.inmo.tgbotapi.types.MessageIdentifier import dev.inmo.tgbotapi.types.MessageIdentifier
import dev.inmo.tgbotapi.types.ParseMode.ParseMode import dev.inmo.tgbotapi.types.ParseMode.ParseMode
import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup
import dev.inmo.tgbotapi.types.chat.abstracts.Chat import dev.inmo.tgbotapi.types.chat.abstracts.Chat
import dev.inmo.tgbotapi.types.message.abstracts.MediaGroupMessage import dev.inmo.tgbotapi.types.message.abstracts.MediaGroupMessage
import dev.inmo.tgbotapi.types.message.abstracts.Message import dev.inmo.tgbotapi.types.message.content.media.MediaGroupContent
import dev.inmo.tgbotapi.types.message.content.abstracts.MediaGroupContent
import dev.inmo.tgbotapi.types.update.MediaGroupUpdates.MediaGroupUpdate
import dev.inmo.tgbotapi.types.update.MediaGroupUpdates.SentMediaGroupUpdate import dev.inmo.tgbotapi.types.update.MediaGroupUpdates.SentMediaGroupUpdate
/** /**

View File

@@ -10,6 +10,7 @@ import dev.inmo.tgbotapi.requests.abstracts.InputFile
import dev.inmo.tgbotapi.requests.send.media.rawSendingMediaGroupsWarning import dev.inmo.tgbotapi.requests.send.media.rawSendingMediaGroupsWarning
import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.InputMedia.* import dev.inmo.tgbotapi.types.InputMedia.*
import dev.inmo.tgbotapi.types.MessageEntity.textsources.TextSource
import dev.inmo.tgbotapi.types.MessageEntity.textsources.TextSourcesList import dev.inmo.tgbotapi.types.MessageEntity.textsources.TextSourcesList
import dev.inmo.tgbotapi.types.ParseMode.ParseMode import dev.inmo.tgbotapi.types.ParseMode.ParseMode
import dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup import dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup
@@ -17,10 +18,14 @@ import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup
import dev.inmo.tgbotapi.types.chat.abstracts.Chat import dev.inmo.tgbotapi.types.chat.abstracts.Chat
import dev.inmo.tgbotapi.types.dice.DiceAnimationType import dev.inmo.tgbotapi.types.dice.DiceAnimationType
import dev.inmo.tgbotapi.types.files.* import dev.inmo.tgbotapi.types.files.*
import dev.inmo.tgbotapi.types.files.abstracts.TelegramMediaFile
import dev.inmo.tgbotapi.types.files.sticker.Sticker import dev.inmo.tgbotapi.types.files.sticker.Sticker
import dev.inmo.tgbotapi.types.games.Game import dev.inmo.tgbotapi.types.games.Game
import dev.inmo.tgbotapi.types.location.StaticLocation import dev.inmo.tgbotapi.types.location.*
import dev.inmo.tgbotapi.types.message.abstracts.Message import dev.inmo.tgbotapi.types.message.abstracts.Message
import dev.inmo.tgbotapi.types.message.content.*
import dev.inmo.tgbotapi.types.message.content.abstracts.MessageContent
import dev.inmo.tgbotapi.types.message.content.media.*
import dev.inmo.tgbotapi.types.payments.LabeledPrice import dev.inmo.tgbotapi.types.payments.LabeledPrice
import dev.inmo.tgbotapi.types.payments.abstracts.Currency import dev.inmo.tgbotapi.types.payments.abstracts.Currency
import dev.inmo.tgbotapi.types.polls.* import dev.inmo.tgbotapi.types.polls.*
@@ -118,6 +123,7 @@ suspend inline fun TelegramBot.reply(
longitude: Double, longitude: Double,
disableNotification: Boolean = false, disableNotification: Boolean = false,
protectContent: Boolean = false, protectContent: Boolean = false,
allowSendingWithoutReply: Boolean? = null,
replyMarkup: KeyboardMarkup? = null replyMarkup: KeyboardMarkup? = null
) = sendLocation( ) = sendLocation(
to.chat, to.chat,
@@ -125,6 +131,7 @@ suspend inline fun TelegramBot.reply(
longitude, longitude,
disableNotification, disableNotification,
protectContent, protectContent,
allowSendingWithoutReply,
to.messageId, to.messageId,
replyMarkup replyMarkup
) )
@@ -138,12 +145,14 @@ suspend inline fun TelegramBot.reply(
location: StaticLocation, location: StaticLocation,
disableNotification: Boolean = false, disableNotification: Boolean = false,
protectContent: Boolean = false, protectContent: Boolean = false,
allowSendingWithoutReply: Boolean? = null,
replyMarkup: KeyboardMarkup? = null replyMarkup: KeyboardMarkup? = null
) = sendLocation( ) = sendLocation(
to.chat, to.chat,
location, location,
disableNotification, disableNotification,
protectContent, protectContent,
allowSendingWithoutReply,
to.messageId, to.messageId,
replyMarkup replyMarkup
) )
@@ -887,6 +896,52 @@ suspend inline fun TelegramBot.reply(
replyMarkup: KeyboardMarkup? = null replyMarkup: KeyboardMarkup? = null
) = sendQuizPoll(to.chat, isClosed, quizPoll, question, options, correctOptionId, isAnonymous, entities, closeInfo, disableNotification, protectContent, to.messageId, allowSendingWithoutReply, replyMarkup) ) = sendQuizPoll(to.chat, isClosed, quizPoll, question, options, correctOptionId, isAnonymous, entities, closeInfo, disableNotification, protectContent, to.messageId, allowSendingWithoutReply, replyMarkup)
suspend inline fun TelegramBot.reply(
to: Message,
poll: Poll,
isClosed: Boolean = false,
question: String = poll.question,
options: List<String> = poll.options.map { it.text },
isAnonymous: Boolean = poll.isAnonymous,
closeInfo: ScheduledCloseInfo? = null,
disableNotification: Boolean = false,
protectContent: Boolean = false,
allowSendingWithoutReply: Boolean? = null,
replyMarkup: KeyboardMarkup? = null
) = when (poll) {
is RegularPoll -> reply(
to = to,
poll = poll,
isClosed = isClosed,
question = question,
options = options,
isAnonymous = isAnonymous,
allowMultipleAnswers = isAnonymous,
closeInfo = closeInfo,
disableNotification = disableNotification,
protectContent = protectContent,
allowSendingWithoutReply = allowSendingWithoutReply,
replyMarkup = replyMarkup
)
is UnknownPollType -> error("Unable to send poll with unknown type ($poll)")
is QuizPoll -> reply(
to = to,
quizPoll = poll,
entities = poll.textSources,
isClosed = isClosed,
question = question,
options = options,
isAnonymous = isAnonymous,
closeInfo = closeInfo,
disableNotification = disableNotification,
protectContent = protectContent,
allowSendingWithoutReply = allowSendingWithoutReply,
replyMarkup = replyMarkup
)
}
suspend inline fun TelegramBot.reply( suspend inline fun TelegramBot.reply(
to: Message, to: Message,
fromChatId: ChatIdentifier, fromChatId: ChatIdentifier,
@@ -921,3 +976,248 @@ suspend inline fun TelegramBot.reply(
allowSendingWithoutReply: Boolean? = null, allowSendingWithoutReply: Boolean? = null,
replyMarkup: KeyboardMarkup? = null replyMarkup: KeyboardMarkup? = null
) = reply(to, copy.chat.id, copy.messageId, text, parseMode, disableNotification, protectContent, allowSendingWithoutReply, replyMarkup) ) = reply(to, copy.chat.id, copy.messageId, text, parseMode, disableNotification, protectContent, allowSendingWithoutReply, replyMarkup)
suspend fun TelegramBot.reply(
to: Message,
content: MessageContent,
disableNotification: Boolean = false,
protectContent: Boolean = false,
allowSendingWithoutReply: Boolean? = null,
replyMarkup: KeyboardMarkup? = null
) {
execute(
content.createResend(
to.chat.id,
disableNotification,
protectContent,
to.messageId,
allowSendingWithoutReply,
replyMarkup
)
)
}
suspend fun TelegramBot.reply(
to: Message,
mediaFile: TelegramMediaFile,
disableNotification: Boolean = false,
protectContent: Boolean = false,
allowSendingWithoutReply: Boolean? = null,
replyMarkup: KeyboardMarkup? = null
) {
when (mediaFile) {
is AudioFile -> reply(
to = to,
audio = mediaFile,
disableNotification = disableNotification,
protectContent = protectContent,
allowSendingWithoutReply = allowSendingWithoutReply,
replyMarkup = replyMarkup
)
is AnimationFile -> reply(
to = to,
animation = mediaFile,
disableNotification = disableNotification,
protectContent = protectContent,
allowSendingWithoutReply = allowSendingWithoutReply,
replyMarkup = replyMarkup
)
is VoiceFile -> reply(
to = to,
voice = mediaFile,
disableNotification = disableNotification,
protectContent = protectContent,
allowSendingWithoutReply = allowSendingWithoutReply,
replyMarkup = replyMarkup
)
is VideoFile -> reply(
to = to,
video = mediaFile,
disableNotification = disableNotification,
protectContent = protectContent,
allowSendingWithoutReply = allowSendingWithoutReply,
replyMarkup = replyMarkup
)
is VideoNoteFile -> reply(
to = to,
videoNote = mediaFile,
disableNotification = disableNotification,
protectContent = protectContent,
allowSendingWithoutReply = allowSendingWithoutReply,
replyMarkup = replyMarkup
)
is DocumentFile -> reply(
to = to,
document = mediaFile,
disableNotification = disableNotification,
protectContent = protectContent,
allowSendingWithoutReply = allowSendingWithoutReply,
replyMarkup = replyMarkup
)
is Sticker -> reply(
to = to,
sticker = mediaFile,
disableNotification = disableNotification,
protectContent = protectContent,
allowSendingWithoutReply = allowSendingWithoutReply,
replyMarkup = replyMarkup
)
is PhotoSize -> reply(
to = to,
photoSize = mediaFile,
disableNotification = disableNotification,
protectContent = protectContent,
allowSendingWithoutReply = allowSendingWithoutReply,
replyMarkup = replyMarkup
)
else -> reply(
to = to,
document = mediaFile.asDocumentFile(),
disableNotification = disableNotification,
protectContent = protectContent,
allowSendingWithoutReply = allowSendingWithoutReply,
replyMarkup = replyMarkup
)
}
}
suspend fun TelegramBot.reply(
to: Message,
content: TextedMediaContent,
text: String?,
parseMode: ParseMode? = null,
disableNotification: Boolean = false,
protectContent: Boolean = false,
allowSendingWithoutReply: Boolean? = null,
replyMarkup: KeyboardMarkup? = null
) {
when (content) {
is VoiceContent -> reply(
to = to,
voice = content.media,
text = text,
parseMode = parseMode,
disableNotification = disableNotification,
protectContent = protectContent,
allowSendingWithoutReply = allowSendingWithoutReply,
replyMarkup = replyMarkup
)
is AudioMediaGroupContent -> reply(
to = to,
audio = content.media,
text = text,
parseMode = parseMode,
disableNotification = disableNotification,
protectContent = protectContent,
allowSendingWithoutReply = allowSendingWithoutReply,
replyMarkup = replyMarkup
)
is PhotoContent -> reply(
to = to,
photoSize = content.media,
text = text,
parseMode = parseMode,
disableNotification = disableNotification,
protectContent = protectContent,
allowSendingWithoutReply = allowSendingWithoutReply,
replyMarkup = replyMarkup
)
is VideoContent -> reply(
to = to,
video = content.media,
text = text,
parseMode = parseMode,
disableNotification = disableNotification,
protectContent = protectContent,
allowSendingWithoutReply = allowSendingWithoutReply,
replyMarkup = replyMarkup
)
is AnimationContent -> reply(
to = to,
animation = content.media,
text = text,
parseMode = parseMode,
disableNotification = disableNotification,
protectContent = protectContent,
allowSendingWithoutReply = allowSendingWithoutReply,
replyMarkup = replyMarkup
)
else -> reply(
to = to,
document = content.media.asDocumentFile(),
text = text,
parseMode = parseMode,
disableNotification = disableNotification,
protectContent = protectContent,
allowSendingWithoutReply = allowSendingWithoutReply,
replyMarkup = replyMarkup
)
}
}
suspend fun TelegramBot.reply(
to: Message,
content: TextedMediaContent,
entities: List<TextSource>,
disableNotification: Boolean = false,
protectContent: Boolean = false,
allowSendingWithoutReply: Boolean? = null,
replyMarkup: KeyboardMarkup? = null
) {
when (content) {
is VoiceContent -> reply(
to = to,
voice = content.media,
entities = entities,
disableNotification = disableNotification,
protectContent = protectContent,
allowSendingWithoutReply = allowSendingWithoutReply,
replyMarkup = replyMarkup
)
is AudioMediaGroupContent -> reply(
to = to,
audio = content.media,
entities = entities,
disableNotification = disableNotification,
protectContent = protectContent,
allowSendingWithoutReply = allowSendingWithoutReply,
replyMarkup = replyMarkup
)
is PhotoContent -> reply(
to = to,
photoSize = content.media,
entities = entities,
disableNotification = disableNotification,
protectContent = protectContent,
allowSendingWithoutReply = allowSendingWithoutReply,
replyMarkup = replyMarkup
)
is VideoContent -> reply(
to = to,
video = content.media,
entities = entities,
disableNotification = disableNotification,
protectContent = protectContent,
allowSendingWithoutReply = allowSendingWithoutReply,
replyMarkup = replyMarkup
)
is AnimationContent -> reply(
to = to,
animation = content.media,
entities = entities,
disableNotification = disableNotification,
protectContent = protectContent,
allowSendingWithoutReply = allowSendingWithoutReply,
replyMarkup = replyMarkup
)
else -> reply(
to = to,
document = content.media.asDocumentFile(),
entities = entities,
disableNotification = disableNotification,
protectContent = protectContent,
allowSendingWithoutReply = allowSendingWithoutReply,
replyMarkup = replyMarkup
)
}
}

View File

@@ -18,6 +18,7 @@ suspend fun TelegramBot.sendLocation(
longitude: Double, longitude: Double,
disableNotification: Boolean = false, disableNotification: Boolean = false,
protectContent: Boolean = false, protectContent: Boolean = false,
allowSendingWithoutReply: Boolean? = null,
replyToMessageId: MessageIdentifier? = null, replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null replyMarkup: KeyboardMarkup? = null
) = execute( ) = execute(
@@ -27,6 +28,7 @@ suspend fun TelegramBot.sendLocation(
longitude, longitude,
disableNotification = disableNotification, disableNotification = disableNotification,
protectContent = protectContent, protectContent = protectContent,
allowSendingWithoutReply = allowSendingWithoutReply,
replyToMessageId = replyToMessageId, replyToMessageId = replyToMessageId,
replyMarkup = replyMarkup replyMarkup = replyMarkup
) )
@@ -41,6 +43,7 @@ suspend fun TelegramBot.sendLocation(
location: StaticLocation, location: StaticLocation,
disableNotification: Boolean = false, disableNotification: Boolean = false,
protectContent: Boolean = false, protectContent: Boolean = false,
allowSendingWithoutReply: Boolean? = null,
replyToMessageId: MessageIdentifier? = null, replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null replyMarkup: KeyboardMarkup? = null
) = sendLocation( ) = sendLocation(
@@ -49,6 +52,7 @@ suspend fun TelegramBot.sendLocation(
location.longitude, location.longitude,
disableNotification, disableNotification,
protectContent, protectContent,
allowSendingWithoutReply,
replyToMessageId, replyToMessageId,
replyMarkup replyMarkup
) )
@@ -63,6 +67,7 @@ suspend fun TelegramBot.sendLocation(
longitude: Double, longitude: Double,
disableNotification: Boolean = false, disableNotification: Boolean = false,
protectContent: Boolean = false, protectContent: Boolean = false,
allowSendingWithoutReply: Boolean? = null,
replyToMessageId: MessageIdentifier? = null, replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null replyMarkup: KeyboardMarkup? = null
) = sendLocation( ) = sendLocation(
@@ -71,6 +76,7 @@ suspend fun TelegramBot.sendLocation(
longitude, longitude,
disableNotification, disableNotification,
protectContent, protectContent,
allowSendingWithoutReply,
replyToMessageId, replyToMessageId,
replyMarkup replyMarkup
) )
@@ -84,6 +90,7 @@ suspend fun TelegramBot.sendLocation(
location: StaticLocation, location: StaticLocation,
disableNotification: Boolean = false, disableNotification: Boolean = false,
protectContent: Boolean = false, protectContent: Boolean = false,
allowSendingWithoutReply: Boolean? = null,
replyToMessageId: MessageIdentifier? = null, replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null replyMarkup: KeyboardMarkup? = null
) = sendLocation( ) = sendLocation(
@@ -92,6 +99,7 @@ suspend fun TelegramBot.sendLocation(
location.longitude, location.longitude,
disableNotification, disableNotification,
protectContent, protectContent,
allowSendingWithoutReply,
replyToMessageId, replyToMessageId,
replyMarkup replyMarkup
) )
@@ -106,9 +114,10 @@ suspend fun TelegramBot.sendStaticLocation(
longitude: Double, longitude: Double,
disableNotification: Boolean = false, disableNotification: Boolean = false,
protectContent: Boolean = false, protectContent: Boolean = false,
allowSendingWithoutReply: Boolean? = null,
replyToMessageId: MessageIdentifier? = null, replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null replyMarkup: KeyboardMarkup? = null
) = sendLocation(chatId, latitude, longitude, disableNotification, protectContent, replyToMessageId, replyMarkup) ) = sendLocation(chatId, latitude, longitude, disableNotification, protectContent, allowSendingWithoutReply, replyToMessageId, replyMarkup)
/** /**
* @param replyMarkup Some of [KeyboardMarkup]. See [dev.inmo.tgbotapi.extensions.utils.types.buttons.replyKeyboard] or * @param replyMarkup Some of [KeyboardMarkup]. See [dev.inmo.tgbotapi.extensions.utils.types.buttons.replyKeyboard] or
@@ -119,9 +128,10 @@ suspend fun TelegramBot.sendStaticLocation(
location: StaticLocation, location: StaticLocation,
disableNotification: Boolean = false, disableNotification: Boolean = false,
protectContent: Boolean = false, protectContent: Boolean = false,
allowSendingWithoutReply: Boolean? = null,
replyToMessageId: MessageIdentifier? = null, replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null replyMarkup: KeyboardMarkup? = null
) = sendLocation(chatId, location.latitude, location.longitude, disableNotification, protectContent, replyToMessageId, replyMarkup) ) = sendLocation(chatId, location.latitude, location.longitude, disableNotification, protectContent, allowSendingWithoutReply, replyToMessageId, replyMarkup)
/** /**
* @param replyMarkup Some of [KeyboardMarkup]. See [dev.inmo.tgbotapi.extensions.utils.types.buttons.replyKeyboard] or * @param replyMarkup Some of [KeyboardMarkup]. See [dev.inmo.tgbotapi.extensions.utils.types.buttons.replyKeyboard] or
@@ -133,9 +143,10 @@ suspend fun TelegramBot.sendStaticLocation(
longitude: Double, longitude: Double,
disableNotification: Boolean = false, disableNotification: Boolean = false,
protectContent: Boolean = false, protectContent: Boolean = false,
allowSendingWithoutReply: Boolean? = null,
replyToMessageId: MessageIdentifier? = null, replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null replyMarkup: KeyboardMarkup? = null
) = sendLocation(chat.id, latitude, longitude, disableNotification, protectContent, replyToMessageId, replyMarkup) ) = sendLocation(chat.id, latitude, longitude, disableNotification, protectContent, allowSendingWithoutReply, replyToMessageId, replyMarkup)
/** /**
* @param replyMarkup Some of [KeyboardMarkup]. See [dev.inmo.tgbotapi.extensions.utils.types.buttons.replyKeyboard] or * @param replyMarkup Some of [KeyboardMarkup]. See [dev.inmo.tgbotapi.extensions.utils.types.buttons.replyKeyboard] or
@@ -146,6 +157,7 @@ suspend fun TelegramBot.sendStaticLocation(
location: StaticLocation, location: StaticLocation,
disableNotification: Boolean = false, disableNotification: Boolean = false,
protectContent: Boolean = false, protectContent: Boolean = false,
allowSendingWithoutReply: Boolean? = null,
replyToMessageId: MessageIdentifier? = null, replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null replyMarkup: KeyboardMarkup? = null
) = sendLocation(chat.id, location.latitude, location.longitude, disableNotification, protectContent, replyToMessageId, replyMarkup) ) = sendLocation(chat.id, location.latitude, location.longitude, disableNotification, protectContent, allowSendingWithoutReply, replyToMessageId, replyMarkup)

View File

@@ -6,8 +6,8 @@ import dev.inmo.tgbotapi.types.ChatIdentifier
import dev.inmo.tgbotapi.types.InputMedia.* import dev.inmo.tgbotapi.types.InputMedia.*
import dev.inmo.tgbotapi.types.MessageIdentifier import dev.inmo.tgbotapi.types.MessageIdentifier
import dev.inmo.tgbotapi.types.chat.abstracts.Chat import dev.inmo.tgbotapi.types.chat.abstracts.Chat
import dev.inmo.tgbotapi.types.message.content.abstracts.MediaGroupContent import dev.inmo.tgbotapi.types.message.content.media.MediaGroupContent
import dev.inmo.tgbotapi.types.message.content.abstracts.VisualMediaGroupContent import dev.inmo.tgbotapi.types.message.content.media.VisualMediaGroupContent
import dev.inmo.tgbotapi.types.message.content.media.AudioContent import dev.inmo.tgbotapi.types.message.content.media.AudioContent
import dev.inmo.tgbotapi.types.message.content.media.DocumentContent import dev.inmo.tgbotapi.types.message.content.media.DocumentContent
import dev.inmo.tgbotapi.utils.RiskFeature import dev.inmo.tgbotapi.utils.RiskFeature

View File

@@ -11,12 +11,15 @@ import dev.inmo.tgbotapi.types.message.abstracts.CommonMessage
import dev.inmo.tgbotapi.types.message.content.* import dev.inmo.tgbotapi.types.message.content.*
import dev.inmo.tgbotapi.types.message.content.abstracts.* import dev.inmo.tgbotapi.types.message.content.abstracts.*
import dev.inmo.tgbotapi.types.message.content.media.* import dev.inmo.tgbotapi.types.message.content.media.*
import dev.inmo.tgbotapi.types.message.content.media.AudioMediaGroupContent
import dev.inmo.tgbotapi.types.message.content.media.DocumentMediaGroupContent
import dev.inmo.tgbotapi.types.message.content.media.MediaGroupContent
import dev.inmo.tgbotapi.types.message.content.media.VisualMediaGroupContent
import dev.inmo.tgbotapi.types.message.payments.InvoiceContent import dev.inmo.tgbotapi.types.message.payments.InvoiceContent
import dev.inmo.tgbotapi.types.update.MediaGroupUpdates.SentMediaGroupUpdate import dev.inmo.tgbotapi.types.update.MediaGroupUpdates.SentMediaGroupUpdate
import dev.inmo.tgbotapi.types.update.abstracts.BaseSentMessageUpdate import dev.inmo.tgbotapi.types.update.abstracts.BaseSentMessageUpdate
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.toList import kotlinx.coroutines.flow.toList
import kotlin.reflect.KClass
typealias CommonMessageToContentMapper<T> = suspend CommonMessage<T>.() -> T? typealias CommonMessageToContentMapper<T> = suspend CommonMessage<T>.() -> T?
@@ -198,6 +201,14 @@ suspend fun BehaviourContext.waitVisualMediaGroupContent(
filter: SimpleFilter<CommonMessage<VisualMediaGroupContent>>? = null, filter: SimpleFilter<CommonMessage<VisualMediaGroupContent>>? = null,
mapper: CommonMessageToContentMapper<VisualMediaGroupContent>? = null mapper: CommonMessageToContentMapper<VisualMediaGroupContent>? = null
) = waitContent(count, initRequest, includeMediaGroups, errorFactory, filter, mapper) ) = waitContent(count, initRequest, includeMediaGroups, errorFactory, filter, mapper)
suspend fun BehaviourContext.waitTextedMediaContent(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
count: Int = 1,
includeMediaGroups: Boolean = true,
filter: SimpleFilter<CommonMessage<TextedMediaContent>>? = null,
mapper: CommonMessageToContentMapper<TextedMediaContent>? = null
) = waitContent(count, initRequest, includeMediaGroups, errorFactory, filter, mapper)
suspend fun BehaviourContext.waitAnimation( suspend fun BehaviourContext.waitAnimation(
initRequest: Request<*>? = null, initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }, errorFactory: NullableRequestBuilder<*> = { null },

View File

@@ -12,6 +12,10 @@ import dev.inmo.tgbotapi.types.message.abstracts.MediaGroupMessage
import dev.inmo.tgbotapi.types.message.content.* import dev.inmo.tgbotapi.types.message.content.*
import dev.inmo.tgbotapi.types.message.content.abstracts.* import dev.inmo.tgbotapi.types.message.content.abstracts.*
import dev.inmo.tgbotapi.types.message.content.media.* import dev.inmo.tgbotapi.types.message.content.media.*
import dev.inmo.tgbotapi.types.message.content.media.AudioMediaGroupContent
import dev.inmo.tgbotapi.types.message.content.media.DocumentMediaGroupContent
import dev.inmo.tgbotapi.types.message.content.media.MediaGroupContent
import dev.inmo.tgbotapi.types.message.content.media.VisualMediaGroupContent
import dev.inmo.tgbotapi.types.message.payments.InvoiceContent import dev.inmo.tgbotapi.types.message.payments.InvoiceContent
import dev.inmo.tgbotapi.types.update.abstracts.BaseEditMessageUpdate import dev.inmo.tgbotapi.types.update.abstracts.BaseEditMessageUpdate
import kotlinx.coroutines.flow.toList import kotlinx.coroutines.flow.toList
@@ -173,6 +177,14 @@ suspend fun BehaviourContext.waitEditedVisualMediaGroupContent(
filter: SimpleFilter<CommonMessage<VisualMediaGroupContent>>? = null, filter: SimpleFilter<CommonMessage<VisualMediaGroupContent>>? = null,
mapper: CommonMessageToContentMapper<VisualMediaGroupContent>? = null mapper: CommonMessageToContentMapper<VisualMediaGroupContent>? = null
) = waitEditedContent(count, initRequest, includeMediaGroups, errorFactory, filter, mapper) ) = waitEditedContent(count, initRequest, includeMediaGroups, errorFactory, filter, mapper)
suspend fun BehaviourContext.waitEditedTextedMediaContent(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
count: Int = 1,
includeMediaGroups: Boolean = true,
filter: SimpleFilter<CommonMessage<TextedMediaContent>>? = null,
mapper: CommonMessageToContentMapper<TextedMediaContent>? = null
) = waitEditedContent(count, initRequest, includeMediaGroups, errorFactory, filter, mapper)
suspend fun BehaviourContext.waitEditedAnimation( suspend fun BehaviourContext.waitEditedAnimation(
initRequest: Request<*>? = null, initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }, errorFactory: NullableRequestBuilder<*> = { null },

View File

@@ -5,8 +5,11 @@ import dev.inmo.tgbotapi.extensions.utils.asSentMediaGroupUpdate
import dev.inmo.tgbotapi.requests.abstracts.Request import dev.inmo.tgbotapi.requests.abstracts.Request
import dev.inmo.tgbotapi.types.message.abstracts.MediaGroupMessage import dev.inmo.tgbotapi.types.message.abstracts.MediaGroupMessage
import dev.inmo.tgbotapi.types.message.content.abstracts.* import dev.inmo.tgbotapi.types.message.content.abstracts.*
import dev.inmo.tgbotapi.types.message.content.media.PhotoContent import dev.inmo.tgbotapi.types.message.content.media.*
import dev.inmo.tgbotapi.types.message.content.media.VideoContent import dev.inmo.tgbotapi.types.message.content.media.AudioMediaGroupContent
import dev.inmo.tgbotapi.types.message.content.media.DocumentMediaGroupContent
import dev.inmo.tgbotapi.types.message.content.media.MediaGroupContent
import dev.inmo.tgbotapi.types.message.content.media.VisualMediaGroupContent
import dev.inmo.tgbotapi.utils.PreviewFeature import dev.inmo.tgbotapi.utils.PreviewFeature
import kotlinx.coroutines.flow.take import kotlinx.coroutines.flow.take
import kotlinx.coroutines.flow.toList import kotlinx.coroutines.flow.toList

View File

@@ -14,6 +14,8 @@ import dev.inmo.tgbotapi.types.message.abstracts.CommonMessage
import dev.inmo.tgbotapi.types.message.content.* import dev.inmo.tgbotapi.types.message.content.*
import dev.inmo.tgbotapi.types.message.content.abstracts.* import dev.inmo.tgbotapi.types.message.content.abstracts.*
import dev.inmo.tgbotapi.types.message.content.media.* import dev.inmo.tgbotapi.types.message.content.media.*
import dev.inmo.tgbotapi.types.message.content.media.AudioMediaGroupContent
import dev.inmo.tgbotapi.types.message.content.media.DocumentMediaGroupContent
import dev.inmo.tgbotapi.types.message.payments.InvoiceContent import dev.inmo.tgbotapi.types.message.payments.InvoiceContent
import dev.inmo.tgbotapi.types.update.MediaGroupUpdates.SentMediaGroupUpdate import dev.inmo.tgbotapi.types.update.MediaGroupUpdates.SentMediaGroupUpdate
import dev.inmo.tgbotapi.types.update.abstracts.BaseSentMessageUpdate import dev.inmo.tgbotapi.types.update.abstracts.BaseSentMessageUpdate
@@ -326,6 +328,30 @@ suspend fun <BC : BehaviourContext> BC.onDocumentMediaGroupContent(
scenarioReceiver scenarioReceiver
) )
/**
* @param initialFilter This filter will be called to remove unnecessary data BEFORE [scenarioReceiver] call
* @param subcontextUpdatesFilter This filter will be applied to each update inside of [scenarioReceiver]. For example,
* this filter will be used if you will call [dev.inmo.tgbotapi.extensions.behaviour_builder.expectations.waitContentMessage].
* Use [dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContextAndTwoTypesReceiver] function to create your own.
* Use [dev.inmo.tgbotapi.extensions.behaviour_builder.utils.plus] or [dev.inmo.tgbotapi.extensions.behaviour_builder.utils.times]
* to combinate several filters
* @param [markerFactory] Will be used to identify different "stream". [scenarioReceiver] will be called synchronously
* in one "stream". Output of [markerFactory] will be used as a key for "stream"
* @param scenarioReceiver Main callback which will be used to handle incoming data if [initialFilter] will pass that
* data
*/
suspend fun <BC : BehaviourContext> BC.onTextedMediaContent(
initialFilter: CommonMessageFilter<TextedMediaContent>? = null,
subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, CommonMessage<TextedMediaContent>, Update> = MessageFilterByChat,
markerFactory: MarkerFactory<in CommonMessage<TextedMediaContent>, Any> = ByChatMessageMarkerFactory,
scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, CommonMessage<TextedMediaContent>>
) = onContent(
initialFilter,
subcontextUpdatesFilter,
markerFactory,
scenarioReceiver
)
/** /**
* @param initialFilter This filter will be called to remove unnecessary data BEFORE [scenarioReceiver] call * @param initialFilter This filter will be called to remove unnecessary data BEFORE [scenarioReceiver] call
* @param subcontextUpdatesFilter This filter will be applied to each update inside of [scenarioReceiver]. For example, * @param subcontextUpdatesFilter This filter will be applied to each update inside of [scenarioReceiver]. For example,

View File

@@ -27,6 +27,8 @@ import dev.inmo.tgbotapi.types.message.abstracts.CommonMessage
import dev.inmo.tgbotapi.types.message.content.* import dev.inmo.tgbotapi.types.message.content.*
import dev.inmo.tgbotapi.types.message.content.abstracts.* import dev.inmo.tgbotapi.types.message.content.abstracts.*
import dev.inmo.tgbotapi.types.message.content.media.* import dev.inmo.tgbotapi.types.message.content.media.*
import dev.inmo.tgbotapi.types.message.content.media.AudioMediaGroupContent
import dev.inmo.tgbotapi.types.message.content.media.DocumentMediaGroupContent
import dev.inmo.tgbotapi.types.message.payments.InvoiceContent import dev.inmo.tgbotapi.types.message.payments.InvoiceContent
import dev.inmo.tgbotapi.types.update.abstracts.BaseEditMessageUpdate import dev.inmo.tgbotapi.types.update.abstracts.BaseEditMessageUpdate
import dev.inmo.tgbotapi.types.update.abstracts.Update import dev.inmo.tgbotapi.types.update.abstracts.Update
@@ -262,6 +264,30 @@ suspend fun <BC : BehaviourContext> BC.onEditedDocumentMediaGroupContent(
scenarioReceiver scenarioReceiver
) )
/**
* @param initialFilter This filter will be called to remove unnecessary data BEFORE [scenarioReceiver] call
* @param subcontextUpdatesFilter This filter will be applied to each update inside of [scenarioReceiver]. For example,
* this filter will be used if you will call [dev.inmo.tgbotapi.extensions.behaviour_builder.expectations.waitContentMessage].
* Use [dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContextAndTwoTypesReceiver] function to create your own.
* Use [dev.inmo.tgbotapi.extensions.behaviour_builder.utils.plus] or [dev.inmo.tgbotapi.extensions.behaviour_builder.utils.times]
* to combinate several filters
* @param [markerFactory] Will be used to identify different "stream". [scenarioReceiver] will be called synchronously
* in one "stream". Output of [markerFactory] will be used as a key for "stream"
* @param scenarioReceiver Main callback which will be used to handle incoming data if [initialFilter] will pass that
* data
*/
suspend fun <BC : BehaviourContext> BC.onEditedTextedMediaContent(
initialFilter: CommonMessageFilter<TextedMediaContent>? = null,
subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, CommonMessage<TextedMediaContent>, Update> = MessageFilterByChat,
markerFactory: MarkerFactory<in CommonMessage<TextedMediaContent>, Any> = ByChatMessageMarkerFactory,
scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, CommonMessage<TextedMediaContent>>
)= onEditedContent(
initialFilter,
subcontextUpdatesFilter,
markerFactory,
scenarioReceiver
)
/** /**
* @param initialFilter This filter will be called to remove unnecessary data BEFORE [scenarioReceiver] call * @param initialFilter This filter will be called to remove unnecessary data BEFORE [scenarioReceiver] call
* @param subcontextUpdatesFilter This filter will be applied to each update inside of [scenarioReceiver]. For example, * @param subcontextUpdatesFilter This filter will be applied to each update inside of [scenarioReceiver]. For example,

View File

@@ -9,9 +9,11 @@ import dev.inmo.tgbotapi.extensions.behaviour_builder.utils.marker_factories.ByC
import dev.inmo.tgbotapi.extensions.behaviour_builder.utils.marker_factories.MarkerFactory import dev.inmo.tgbotapi.extensions.behaviour_builder.utils.marker_factories.MarkerFactory
import dev.inmo.tgbotapi.extensions.utils.asSentMediaGroupUpdate import dev.inmo.tgbotapi.extensions.utils.asSentMediaGroupUpdate
import dev.inmo.tgbotapi.types.message.abstracts.MediaGroupMessage import dev.inmo.tgbotapi.types.message.abstracts.MediaGroupMessage
import dev.inmo.tgbotapi.types.message.content.abstracts.* import dev.inmo.tgbotapi.types.message.content.media.*
import dev.inmo.tgbotapi.types.message.content.media.PhotoContent import dev.inmo.tgbotapi.types.message.content.media.AudioMediaGroupContent
import dev.inmo.tgbotapi.types.message.content.media.VideoContent import dev.inmo.tgbotapi.types.message.content.media.DocumentMediaGroupContent
import dev.inmo.tgbotapi.types.message.content.media.MediaGroupContent
import dev.inmo.tgbotapi.types.message.content.media.VisualMediaGroupContent
import dev.inmo.tgbotapi.types.update.abstracts.Update import dev.inmo.tgbotapi.types.update.abstracts.Update
import dev.inmo.tgbotapi.utils.PreviewFeature import dev.inmo.tgbotapi.utils.PreviewFeature

View File

@@ -8,8 +8,8 @@ import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.InputMedia.* import dev.inmo.tgbotapi.types.InputMedia.*
import dev.inmo.tgbotapi.types.message.abstracts.MediaGroupMessage import dev.inmo.tgbotapi.types.message.abstracts.MediaGroupMessage
import dev.inmo.tgbotapi.types.message.abstracts.TelegramBotAPIMessageDeserializeOnlySerializerClass import dev.inmo.tgbotapi.types.message.abstracts.TelegramBotAPIMessageDeserializeOnlySerializerClass
import dev.inmo.tgbotapi.types.message.content.abstracts.MediaGroupContent import dev.inmo.tgbotapi.types.message.content.media.MediaGroupContent
import dev.inmo.tgbotapi.types.message.content.abstracts.VisualMediaGroupContent import dev.inmo.tgbotapi.types.message.content.media.VisualMediaGroupContent
import dev.inmo.tgbotapi.types.message.content.media.AudioContent import dev.inmo.tgbotapi.types.message.content.media.AudioContent
import dev.inmo.tgbotapi.types.message.content.media.DocumentContent import dev.inmo.tgbotapi.types.message.content.media.DocumentContent
import dev.inmo.tgbotapi.utils.* import dev.inmo.tgbotapi.utils.*

View File

@@ -20,11 +20,11 @@ internal data class RawMessageEntity(
internal fun RawMessageEntity.asTextSource( internal fun RawMessageEntity.asTextSource(
source: String, source: String,
subParts: TextSourcesList subParts: List<Pair<Int, TextSource>>
): TextSource { ): TextSource {
val sourceSubstring: String = source.substring(range) val sourceSubstring: String = source.substring(range)
val subPartsWithRegulars by lazy { val subPartsWithRegulars by lazy {
subParts.fillWithRegulars(sourceSubstring) subParts.map { (it.first - offset) to it.second }.fillWithRegulars(sourceSubstring)
} }
return when (type) { return when (type) {
"mention" -> MentionTextSource(sourceSubstring, subPartsWithRegulars) "mention" -> MentionTextSource(sourceSubstring, subPartsWithRegulars)
@@ -58,16 +58,14 @@ private inline operator fun <T : Comparable<T>> ClosedRange<T>.contains(other: C
return start <= other.start && endInclusive >= other.endInclusive return start <= other.start && endInclusive >= other.endInclusive
} }
internal fun TextSourcesList.fillWithRegulars(source: String): TextSourcesList { internal fun List<Pair<Int, TextSource>>.fillWithRegulars(source: String): TextSourcesList {
var index = 0 var index = 0
val result = mutableListOf<TextSource>() val result = mutableListOf<TextSource>()
for (i in 0 until size) { for (i in indices) {
val textSource = get(i) val (offset, textSource) = get(i)
val thisSourceInStart = source.startsWith(textSource.source, index) if (offset - index > 0) {
if (!thisSourceInStart) { result.add(regular(source.substring(index, offset)))
val regularEndIndex = source.indexOf(textSource.source, index) index = offset
result.add(regular(source.substring(index, regularEndIndex)))
index = regularEndIndex
} }
result.add(textSource) result.add(textSource)
index += textSource.source.length index += textSource.source.length
@@ -83,9 +81,9 @@ internal fun TextSourcesList.fillWithRegulars(source: String): TextSourcesList {
private fun createTextSources( private fun createTextSources(
originalFullString: String, originalFullString: String,
entities: RawMessageEntities entities: RawMessageEntities
): TextSourcesList { ): List<Pair<Int, TextSource>> {
val mutableEntities = entities.toMutableList().apply { sortBy { it.offset } } val mutableEntities = entities.toMutableList().apply { sortBy { it.offset } }
val resultList = mutableListOf<TextSource>() val resultList = mutableListOf<Pair<Int, TextSource>>()
while (mutableEntities.isNotEmpty()) { while (mutableEntities.isNotEmpty()) {
var parent = mutableEntities.removeFirst() var parent = mutableEntities.removeFirst()
@@ -129,7 +127,7 @@ private fun createTextSources(
emptyList() emptyList()
} }
resultList.add( resultList.add(
parent.asTextSource( parent.offset to parent.asTextSource(
originalFullString, originalFullString,
subtextSources subtextSources
) )

View File

@@ -4,6 +4,7 @@ import dev.inmo.tgbotapi.requests.abstracts.FileId
import dev.inmo.tgbotapi.types.FileUniqueId import dev.inmo.tgbotapi.types.FileUniqueId
import dev.inmo.tgbotapi.types.fileUniqueIdField import dev.inmo.tgbotapi.types.fileUniqueIdField
import dev.inmo.tgbotapi.types.files.abstracts.* import dev.inmo.tgbotapi.types.files.abstracts.*
import dev.inmo.tgbotapi.types.message.content.media.DocumentContent
import dev.inmo.tgbotapi.utils.MimeType import dev.inmo.tgbotapi.utils.MimeType
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@@ -24,11 +25,15 @@ data class DocumentFile(
) : TelegramMediaFile, MimedMediaFile, ThumbedMediaFile, CustomNamedMediaFile ) : TelegramMediaFile, MimedMediaFile, ThumbedMediaFile, CustomNamedMediaFile
@Suppress("NOTHING_TO_INLINE") @Suppress("NOTHING_TO_INLINE")
inline fun TelegramMediaFile.asDocumentFile() = DocumentFile( inline fun TelegramMediaFile.asDocumentFile() = if (this is DocumentFile) {
fileId, this
fileUniqueId, } else {
fileSize, DocumentFile(
(this as? ThumbedMediaFile) ?.thumb, fileId,
(this as? MimedMediaFile) ?.mimeType, fileUniqueId,
(this as? CustomNamedMediaFile) ?.fileName fileSize,
) (this as? ThumbedMediaFile) ?.thumb,
(this as? MimedMediaFile) ?.mimeType,
(this as? CustomNamedMediaFile) ?.fileName
)
}

View File

@@ -7,7 +7,7 @@ import dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup
import dev.inmo.tgbotapi.types.chat.abstracts.Chat import dev.inmo.tgbotapi.types.chat.abstracts.Chat
import dev.inmo.tgbotapi.types.message.abstracts.MediaGroupMessage import dev.inmo.tgbotapi.types.message.abstracts.MediaGroupMessage
import dev.inmo.tgbotapi.types.message.abstracts.Message import dev.inmo.tgbotapi.types.message.abstracts.Message
import dev.inmo.tgbotapi.types.message.content.abstracts.MediaGroupContent import dev.inmo.tgbotapi.types.message.content.media.MediaGroupContent
data class ChannelMediaGroupMessage<T : MediaGroupContent>( data class ChannelMediaGroupMessage<T : MediaGroupContent>(
override val messageId: MessageIdentifier, override val messageId: MessageIdentifier,

View File

@@ -5,7 +5,7 @@ import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup import dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup
import dev.inmo.tgbotapi.types.chat.abstracts.Chat import dev.inmo.tgbotapi.types.chat.abstracts.Chat
import dev.inmo.tgbotapi.types.message.abstracts.* import dev.inmo.tgbotapi.types.message.abstracts.*
import dev.inmo.tgbotapi.types.message.content.abstracts.MediaGroupContent import dev.inmo.tgbotapi.types.message.content.media.MediaGroupContent
data class CommonMediaGroupMessage<T : MediaGroupContent>( data class CommonMediaGroupMessage<T : MediaGroupContent>(
override val messageId: MessageIdentifier, override val messageId: MessageIdentifier,

View File

@@ -1,7 +1,7 @@
package dev.inmo.tgbotapi.types.message.abstracts package dev.inmo.tgbotapi.types.message.abstracts
import dev.inmo.tgbotapi.types.MediaGroupIdentifier import dev.inmo.tgbotapi.types.MediaGroupIdentifier
import dev.inmo.tgbotapi.types.message.content.abstracts.MediaGroupContent import dev.inmo.tgbotapi.types.message.content.media.MediaGroupContent
interface MediaGroupMessage<T : MediaGroupContent> : CommonMessage<T> { interface MediaGroupMessage<T : MediaGroupContent> : CommonMessage<T> {
val mediaGroupId: MediaGroupIdentifier val mediaGroupId: MediaGroupIdentifier

View File

@@ -0,0 +1,4 @@
package dev.inmo.tgbotapi.types.message.content.abstracts
@Deprecated("This class has been moved to the other package", ReplaceWith("AudioMediaGroupContent", "dev.inmo.tgbotapi.types.message.content.media.AudioMediaGroupContent"))
typealias AudioMediaGroupContent = dev.inmo.tgbotapi.types.message.content.media.AudioMediaGroupContent

View File

@@ -0,0 +1,4 @@
package dev.inmo.tgbotapi.types.message.content.abstracts
@Deprecated("This class has been moved to the other package", ReplaceWith("DocumentMediaGroupContent", "dev.inmo.tgbotapi.types.message.content.media.DocumentMediaGroupContent"))
typealias DocumentMediaGroupContent = dev.inmo.tgbotapi.types.message.content.media.DocumentMediaGroupContent

View File

@@ -1,18 +1,4 @@
package dev.inmo.tgbotapi.types.message.content.abstracts package dev.inmo.tgbotapi.types.message.content.abstracts
import dev.inmo.tgbotapi.CommonAbstracts.TextedInput @Deprecated("This class has been moved to the other package", ReplaceWith("MediaGroupContent", "dev.inmo.tgbotapi.types.message.content.media.MediaGroupContent"))
import dev.inmo.tgbotapi.types.InputMedia.* typealias MediaGroupContent = dev.inmo.tgbotapi.types.message.content.media.MediaGroupContent
interface MediaGroupContent : MediaContent, TextedInput {
fun toMediaGroupMemberInputMedia(): MediaGroupMemberInputMedia
}
interface VisualMediaGroupContent : MediaGroupContent {
override fun toMediaGroupMemberInputMedia(): VisualMediaGroupMemberInputMedia
}
interface AudioMediaGroupContent : MediaGroupContent {
override fun toMediaGroupMemberInputMedia(): AudioMediaGroupMemberInputMedia
}
interface DocumentMediaGroupContent : MediaGroupContent {
override fun toMediaGroupMemberInputMedia(): DocumentMediaGroupMemberInputMedia
}

View File

@@ -0,0 +1,4 @@
package dev.inmo.tgbotapi.types.message.content.abstracts
@Deprecated("This class has been moved to the other package", ReplaceWith("VisualMediaGroupContent", "dev.inmo.tgbotapi.types.message.content.media.VisualMediaGroupContent"))
typealias VisualMediaGroupContent = dev.inmo.tgbotapi.types.message.content.media.VisualMediaGroupContent

View File

@@ -20,7 +20,7 @@ data class AnimationContent(
val includedDocument: DocumentFile?, val includedDocument: DocumentFile?,
override val text: String?, override val text: String?,
override val textSources: TextSourcesList = emptyList() override val textSources: TextSourcesList = emptyList()
) : MediaContent, TextedInput { ) : TextedMediaContent {
override fun createResend( override fun createResend(
chatId: ChatIdentifier, chatId: ChatIdentifier,
disableNotification: Boolean, disableNotification: Boolean,

View File

@@ -10,7 +10,6 @@ import dev.inmo.tgbotapi.types.MessageIdentifier
import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup
import dev.inmo.tgbotapi.types.files.AudioFile import dev.inmo.tgbotapi.types.files.AudioFile
import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage
import dev.inmo.tgbotapi.types.message.content.abstracts.AudioMediaGroupContent
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@Serializable @Serializable

View File

@@ -0,0 +1,10 @@
package dev.inmo.tgbotapi.types.message.content.media
import dev.inmo.tgbotapi.types.InputMedia.AudioMediaGroupMemberInputMedia
import dev.inmo.tgbotapi.types.files.AudioFile
interface AudioMediaGroupContent : MediaGroupContent {
override val media: AudioFile
override fun toMediaGroupMemberInputMedia(): AudioMediaGroupMemberInputMedia
}

View File

@@ -12,7 +12,6 @@ import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup
import dev.inmo.tgbotapi.types.files.DocumentFile import dev.inmo.tgbotapi.types.files.DocumentFile
import dev.inmo.tgbotapi.types.files.asDocumentFile import dev.inmo.tgbotapi.types.files.asDocumentFile
import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage
import dev.inmo.tgbotapi.types.message.content.abstracts.DocumentMediaGroupContent
import dev.inmo.tgbotapi.types.message.content.abstracts.MediaContent import dev.inmo.tgbotapi.types.message.content.abstracts.MediaContent
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable

View File

@@ -0,0 +1,10 @@
package dev.inmo.tgbotapi.types.message.content.media
import dev.inmo.tgbotapi.types.InputMedia.*
import dev.inmo.tgbotapi.types.files.DocumentFile
interface DocumentMediaGroupContent : MediaGroupContent {
override val media: DocumentFile
override fun toMediaGroupMemberInputMedia(): DocumentMediaGroupMemberInputMedia
}

View File

@@ -0,0 +1,7 @@
package dev.inmo.tgbotapi.types.message.content.media
import dev.inmo.tgbotapi.types.InputMedia.MediaGroupMemberInputMedia
interface MediaGroupContent : TextedMediaContent {
fun toMediaGroupMemberInputMedia(): MediaGroupMemberInputMedia
}

View File

@@ -11,7 +11,6 @@ import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup
import dev.inmo.tgbotapi.types.files.* import dev.inmo.tgbotapi.types.files.*
import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage
import dev.inmo.tgbotapi.types.message.content.abstracts.MediaCollectionContent import dev.inmo.tgbotapi.types.message.content.abstracts.MediaCollectionContent
import dev.inmo.tgbotapi.types.message.content.abstracts.VisualMediaGroupContent
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@Serializable @Serializable

View File

@@ -0,0 +1,6 @@
package dev.inmo.tgbotapi.types.message.content.media
import dev.inmo.tgbotapi.CommonAbstracts.TextedInput
import dev.inmo.tgbotapi.types.message.content.abstracts.MediaContent
sealed interface TextedMediaContent : MediaContent, TextedInput

View File

@@ -10,7 +10,6 @@ import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup
import dev.inmo.tgbotapi.types.files.VideoFile import dev.inmo.tgbotapi.types.files.VideoFile
import dev.inmo.tgbotapi.types.files.toInputMediaVideo import dev.inmo.tgbotapi.types.files.toInputMediaVideo
import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage
import dev.inmo.tgbotapi.types.message.content.abstracts.VisualMediaGroupContent
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@Serializable @Serializable

View File

@@ -0,0 +1,7 @@
package dev.inmo.tgbotapi.types.message.content.media
import dev.inmo.tgbotapi.types.InputMedia.VisualMediaGroupMemberInputMedia
interface VisualMediaGroupContent : MediaGroupContent {
override fun toMediaGroupMemberInputMedia(): VisualMediaGroupMemberInputMedia
}

View File

@@ -18,7 +18,7 @@ data class VoiceContent(
override val media: VoiceFile, override val media: VoiceFile,
override val text: String? = null, override val text: String? = null,
override val textSources: TextSourcesList = emptyList() override val textSources: TextSourcesList = emptyList()
) : MediaContent, TextedInput { ) : TextedMediaContent {
override fun createResend( override fun createResend(
chatId: ChatIdentifier, chatId: ChatIdentifier,
disableNotification: Boolean, disableNotification: Boolean,

View File

@@ -2,7 +2,7 @@ package dev.inmo.tgbotapi.types.update.MediaGroupUpdates
import dev.inmo.tgbotapi.types.UpdateIdentifier import dev.inmo.tgbotapi.types.UpdateIdentifier
import dev.inmo.tgbotapi.types.message.abstracts.MediaGroupMessage import dev.inmo.tgbotapi.types.message.abstracts.MediaGroupMessage
import dev.inmo.tgbotapi.types.message.content.abstracts.MediaGroupContent import dev.inmo.tgbotapi.types.message.content.media.MediaGroupContent
import dev.inmo.tgbotapi.types.update.abstracts.BaseMessageUpdate import dev.inmo.tgbotapi.types.update.abstracts.BaseMessageUpdate
data class ChannelPostMediaGroupUpdate( data class ChannelPostMediaGroupUpdate(

View File

@@ -2,7 +2,7 @@ package dev.inmo.tgbotapi.types.update.MediaGroupUpdates
import dev.inmo.tgbotapi.types.UpdateIdentifier import dev.inmo.tgbotapi.types.UpdateIdentifier
import dev.inmo.tgbotapi.types.message.abstracts.MediaGroupMessage import dev.inmo.tgbotapi.types.message.abstracts.MediaGroupMessage
import dev.inmo.tgbotapi.types.message.content.abstracts.MediaGroupContent import dev.inmo.tgbotapi.types.message.content.media.MediaGroupContent
import dev.inmo.tgbotapi.types.update.EditChannelPostUpdate import dev.inmo.tgbotapi.types.update.EditChannelPostUpdate
data class EditChannelPostMediaGroupUpdate( data class EditChannelPostMediaGroupUpdate(

View File

@@ -2,7 +2,7 @@ package dev.inmo.tgbotapi.types.update.MediaGroupUpdates
import dev.inmo.tgbotapi.types.UpdateIdentifier import dev.inmo.tgbotapi.types.UpdateIdentifier
import dev.inmo.tgbotapi.types.message.abstracts.MediaGroupMessage import dev.inmo.tgbotapi.types.message.abstracts.MediaGroupMessage
import dev.inmo.tgbotapi.types.message.content.abstracts.MediaGroupContent import dev.inmo.tgbotapi.types.message.content.media.MediaGroupContent
import dev.inmo.tgbotapi.types.update.EditMessageUpdate import dev.inmo.tgbotapi.types.update.EditMessageUpdate
data class EditMessageMediaGroupUpdate( data class EditMessageMediaGroupUpdate(

View File

@@ -1,7 +1,7 @@
package dev.inmo.tgbotapi.types.update.MediaGroupUpdates package dev.inmo.tgbotapi.types.update.MediaGroupUpdates
import dev.inmo.tgbotapi.types.message.abstracts.MediaGroupMessage import dev.inmo.tgbotapi.types.message.abstracts.MediaGroupMessage
import dev.inmo.tgbotapi.types.message.content.abstracts.MediaGroupContent import dev.inmo.tgbotapi.types.message.content.media.MediaGroupContent
import dev.inmo.tgbotapi.types.update.abstracts.* import dev.inmo.tgbotapi.types.update.abstracts.*
/** /**

View File

@@ -2,7 +2,7 @@ package dev.inmo.tgbotapi.types.update.MediaGroupUpdates
import dev.inmo.tgbotapi.types.UpdateIdentifier import dev.inmo.tgbotapi.types.UpdateIdentifier
import dev.inmo.tgbotapi.types.message.abstracts.MediaGroupMessage import dev.inmo.tgbotapi.types.message.abstracts.MediaGroupMessage
import dev.inmo.tgbotapi.types.message.content.abstracts.MediaGroupContent import dev.inmo.tgbotapi.types.message.content.media.MediaGroupContent
import dev.inmo.tgbotapi.types.update.abstracts.BaseMessageUpdate import dev.inmo.tgbotapi.types.update.abstracts.BaseMessageUpdate
data class MessageMediaGroupUpdate( data class MessageMediaGroupUpdate(

View File

@@ -2,34 +2,69 @@ package dev.inmo.tgbotapi.utils
import dev.inmo.tgbotapi.types.buttons.Matrix import dev.inmo.tgbotapi.types.buttons.Matrix
/**
* @see dev.inmo.tgbotapi.extensions.utils.types.buttons.InlineKeyboardRowBuilder
* @see dev.inmo.tgbotapi.extensions.utils.types.buttons.ReplyKeyboardRowBuilder
*/
@Deprecated("This functionality will be removed soon")
fun <T> row(block: RowBuilder<T>.() -> Unit): List<T> { fun <T> row(block: RowBuilder<T>.() -> Unit): List<T> {
return RowBuilder<T>().also(block).row return RowBuilder<T>().also(block).row
} }
/**
* @see dev.inmo.tgbotapi.extensions.utils.types.buttons.InlineKeyboardRowBuilder
* @see dev.inmo.tgbotapi.extensions.utils.types.buttons.ReplyKeyboardRowBuilder
*/
@Deprecated("This functionality will be removed soon")
fun <T> MatrixBuilder<T>.row(block: RowBuilder<T>.() -> Unit) { fun <T> MatrixBuilder<T>.row(block: RowBuilder<T>.() -> Unit) {
add(RowBuilder<T>().also(block).row) add(RowBuilder<T>().also(block).row)
} }
/**
* @see dev.inmo.tgbotapi.extensions.utils.types.buttons.InlineKeyboardRowBuilder
* @see dev.inmo.tgbotapi.extensions.utils.types.buttons.ReplyKeyboardRowBuilder
*/
@Deprecated("This functionality will be removed soon")
fun <T> MatrixBuilder<T>.row(vararg elements: T) { fun <T> MatrixBuilder<T>.row(vararg elements: T) {
add(elements.toList()) add(elements.toList())
} }
/**
* @see dev.inmo.tgbotapi.extensions.utils.types.buttons.InlineKeyboardBuilder
* @see dev.inmo.tgbotapi.extensions.utils.types.buttons.ReplyKeyboardBuilder
*/
@Deprecated("This functionality will be removed soon")
fun <T> matrix(block: MatrixBuilder<T>.() -> Unit): Matrix<T> { fun <T> matrix(block: MatrixBuilder<T>.() -> Unit): Matrix<T> {
return MatrixBuilder<T>().also(block).matrix return MatrixBuilder<T>().also(block).matrix
} }
/**
* @see dev.inmo.tgbotapi.extensions.utils.types.buttons.InlineKeyboardBuilder
* @see dev.inmo.tgbotapi.extensions.utils.types.buttons.ReplyKeyboardBuilder
*/
@Deprecated("This functionality will be removed soon")
fun <T> flatMatrix(block: RowBuilder<T>.() -> Unit): Matrix<T> { fun <T> flatMatrix(block: RowBuilder<T>.() -> Unit): Matrix<T> {
return MatrixBuilder<T>().apply { return MatrixBuilder<T>().apply {
row(block) row(block)
}.matrix }.matrix
} }
/**
* @see dev.inmo.tgbotapi.extensions.utils.types.buttons.InlineKeyboardBuilder
* @see dev.inmo.tgbotapi.extensions.utils.types.buttons.ReplyKeyboardBuilder
*/
@Deprecated("This functionality will be removed soon")
fun <T> flatMatrix(vararg elements: T): Matrix<T> { fun <T> flatMatrix(vararg elements: T): Matrix<T> {
return MatrixBuilder<T>().apply { return MatrixBuilder<T>().apply {
row { elements.forEach { +it } } row { elements.forEach { +it } }
}.matrix }.matrix
} }
/**
* @see dev.inmo.tgbotapi.extensions.utils.types.buttons.InlineKeyboardRowBuilder
* @see dev.inmo.tgbotapi.extensions.utils.types.buttons.ReplyKeyboardRowBuilder
*/
@Deprecated("This functionality will be removed soon")
operator fun <T> RowBuilder<T>.plus(t: T) = add(t) operator fun <T> RowBuilder<T>.plus(t: T) = add(t)
open class RowBuilder<T> { open class RowBuilder<T> {

View File

@@ -3,43 +3,43 @@ package dev.inmo.tgbotapi.types.MessageEntity
import dev.inmo.tgbotapi.types.MessageEntity.textsources.* 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?) 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?\\) *_is_ ~__simple__~* ||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" const val formattedHtmlText = "It (is?) <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",
3, 9,
9 9
), ),
RawMessageEntity( RawMessageEntity(
"italic", "italic",
3, 9,
2 2
), ),
RawMessageEntity( RawMessageEntity(
"strikethrough", "strikethrough",
6, 12,
6 6
), ),
RawMessageEntity( RawMessageEntity(
"underline", "underline",
6, 12,
6 6
), ),
RawMessageEntity( RawMessageEntity(
"spoiler", "spoiler",
13, 19,
11 11
), ),
RawMessageEntity( RawMessageEntity(
"hashtag", "hashtag",
30, 36,
4 4
), ),
RawMessageEntity( RawMessageEntity(
"mention", "mention",
39, 45,
8 8
) )
) )

View File

@@ -2,8 +2,7 @@ package dev.inmo.tgbotapi.types.MessageEntity
import dev.inmo.tgbotapi.extensions.utils.formatting.* import dev.inmo.tgbotapi.extensions.utils.formatting.*
import dev.inmo.tgbotapi.types.MessageEntity.textsources.* import dev.inmo.tgbotapi.types.MessageEntity.textsources.*
import kotlin.test.Test import kotlin.test.*
import kotlin.test.assertEquals
class StringFormattingTests { class StringFormattingTests {
@Test @Test
@@ -38,7 +37,7 @@ class StringFormattingTests {
@Test @Test
fun testThatCreatingOfStringWithSimpleDSLWorksCorrectly() { fun testThatCreatingOfStringWithSimpleDSLWorksCorrectly() {
val sources: TextSourcesList = regular("It ") + val sources: TextSourcesList = regular("It (is?) ") +
bold(italic("is") + bold(italic("is") +
" " + " " +
strikethrough(underline("simple"))) + strikethrough(underline("simple"))) +
@@ -53,4 +52,43 @@ class StringFormattingTests {
assertEquals(formattedV2Text, sources.toMarkdownV2Texts().first()) assertEquals(formattedV2Text, sources.toMarkdownV2Texts().first())
assertEquals(formattedHtmlText, sources.toHtmlTexts().first()) assertEquals(formattedHtmlText, sources.toHtmlTexts().first())
} }
@Test
fun testForRepeatingWordsInOneSentenceWithTheSecondOneFormatted() {
val sourceText = "link link"
val messageEntities = listOf(
RawMessageEntity("bold", 5, 4),
RawMessageEntity("text_link", 6, 2, "google.com")
)
val textSources = messageEntities.asTextSources(sourceText)
val (regular, bold) = textSources
assertTrue(regular is RegularTextSource)
assertTrue(bold is BoldTextSource)
assertTrue(regular.source == "link ")
assertTrue(bold.source == "link")
assertTrue((bold.subsources[0] as? RegularTextSource) ?.source == "l")
assertTrue((bold.subsources[1] as? TextLinkTextSource) ?.source == "in")
assertTrue((bold.subsources[1] as? TextLinkTextSource) ?.url == "google.com")
assertTrue((bold.subsources[2] as? RegularTextSource) ?.source == "k")
assertTrue(bold.subsources.size == 3)
assertTrue(textSources.size == 2)
}
@Test
fun testForRepeatingWordsInOneSentenceWithTheSecondOneFormattedInsideOfFormatting() {
val sourceText = "text"
val messageEntities = listOf(
RawMessageEntity("bold", 0, 4),
RawMessageEntity("text_link", 3, 1, "google.com")
)
val textSources = messageEntities.asTextSources(sourceText)
val (bold) = textSources
assertTrue(bold is BoldTextSource)
assertTrue(bold.source == "text")
assertTrue((bold.subsources[0] as? RegularTextSource) ?.source == "tex")
assertTrue((bold.subsources[1] as? TextLinkTextSource) ?.source == "t")
assertTrue((bold.subsources[1] as? TextLinkTextSource) ?.url == "google.com")
assertTrue(bold.subsources.size == 2)
assertTrue(textSources.size == 1)
}
} }

View File

@@ -43,6 +43,10 @@ import dev.inmo.tgbotapi.types.message.abstracts.*
import dev.inmo.tgbotapi.types.message.content.* import dev.inmo.tgbotapi.types.message.content.*
import dev.inmo.tgbotapi.types.message.content.abstracts.* import dev.inmo.tgbotapi.types.message.content.abstracts.*
import dev.inmo.tgbotapi.types.message.content.media.* import dev.inmo.tgbotapi.types.message.content.media.*
import dev.inmo.tgbotapi.types.message.content.media.AudioMediaGroupContent
import dev.inmo.tgbotapi.types.message.content.media.DocumentMediaGroupContent
import dev.inmo.tgbotapi.types.message.content.media.MediaGroupContent
import dev.inmo.tgbotapi.types.message.content.media.VisualMediaGroupContent
import dev.inmo.tgbotapi.types.message.payments.InvoiceContent import dev.inmo.tgbotapi.types.message.payments.InvoiceContent
import dev.inmo.tgbotapi.types.message.payments.SuccessfulPaymentEvent import dev.inmo.tgbotapi.types.message.payments.SuccessfulPaymentEvent
import dev.inmo.tgbotapi.types.passport.* import dev.inmo.tgbotapi.types.passport.*
@@ -2671,6 +2675,17 @@ inline fun ResendableContent.asMediaCollectionContent(): MediaCollectionContent<
inline fun ResendableContent.requireMediaCollectionContent(): MediaCollectionContent<TelegramMediaFile> = inline fun ResendableContent.requireMediaCollectionContent(): MediaCollectionContent<TelegramMediaFile> =
this as MediaCollectionContent<TelegramMediaFile> this as MediaCollectionContent<TelegramMediaFile>
@PreviewFeature
inline fun <T> ResendableContent.whenTextedMediaContent(block: (TextedMediaContent) -> T) = asTextedMediaContent() ?.let(block)
@PreviewFeature
inline fun ResendableContent.asTextedMediaContent(): TextedMediaContent? =
this as? TextedMediaContent
@PreviewFeature
inline fun ResendableContent.requireTextedMediaContent(): TextedMediaContent =
this as TextedMediaContent
@PreviewFeature @PreviewFeature
inline fun <T> ResendableContent.whenMediaContent(block: (MediaContent) -> T) = asMediaContent() ?.let(block) inline fun <T> ResendableContent.whenMediaContent(block: (MediaContent) -> T) = asMediaContent() ?.let(block)

View File

@@ -4,6 +4,7 @@ package dev.inmo.tgbotapi.extensions.utils
import dev.inmo.tgbotapi.types.message.abstracts.* import dev.inmo.tgbotapi.types.message.abstracts.*
import dev.inmo.tgbotapi.types.message.content.abstracts.* import dev.inmo.tgbotapi.types.message.content.abstracts.*
import dev.inmo.tgbotapi.types.message.content.media.MediaGroupContent
inline fun <reified T : MessageContent> ContentMessage<*>.withContent() = if (content is T) { this as ContentMessage<T> } else { null } inline fun <reified T : MessageContent> ContentMessage<*>.withContent() = if (content is T) { this as ContentMessage<T> } else { null }
inline fun <reified T : MessageContent> ContentMessage<*>.requireWithContent() = withContent<T>()!! inline fun <reified T : MessageContent> ContentMessage<*>.requireWithContent() = withContent<T>()!!

View File

@@ -8,6 +8,8 @@ import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage
import dev.inmo.tgbotapi.types.message.content.* import dev.inmo.tgbotapi.types.message.content.*
import dev.inmo.tgbotapi.types.message.content.abstracts.* import dev.inmo.tgbotapi.types.message.content.abstracts.*
import dev.inmo.tgbotapi.types.message.content.media.* import dev.inmo.tgbotapi.types.message.content.media.*
import dev.inmo.tgbotapi.types.message.content.media.MediaGroupContent
import dev.inmo.tgbotapi.types.message.content.media.VisualMediaGroupContent
import dev.inmo.tgbotapi.types.message.payments.InvoiceContent import dev.inmo.tgbotapi.types.message.payments.InvoiceContent
import dev.inmo.tgbotapi.types.update.MediaGroupUpdates.SentMediaGroupUpdate import dev.inmo.tgbotapi.types.update.MediaGroupUpdates.SentMediaGroupUpdate
import dev.inmo.tgbotapi.types.update.abstracts.BaseSentMessageUpdate import dev.inmo.tgbotapi.types.update.abstracts.BaseSentMessageUpdate

View File

@@ -5,7 +5,7 @@ import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.chat.abstracts.Chat import dev.inmo.tgbotapi.types.chat.abstracts.Chat
import dev.inmo.tgbotapi.types.message.ForwardInfo import dev.inmo.tgbotapi.types.message.ForwardInfo
import dev.inmo.tgbotapi.types.message.abstracts.* import dev.inmo.tgbotapi.types.message.abstracts.*
import dev.inmo.tgbotapi.types.message.content.abstracts.MediaGroupContent import dev.inmo.tgbotapi.types.message.content.media.MediaGroupContent
import dev.inmo.tgbotapi.types.update.MediaGroupUpdates.SentMediaGroupUpdate import dev.inmo.tgbotapi.types.update.MediaGroupUpdates.SentMediaGroupUpdate
val List<CommonMessage<out MediaGroupContent>>.forwardInfo: ForwardInfo? val List<CommonMessage<out MediaGroupContent>>.forwardInfo: ForwardInfo?

View File

@@ -15,6 +15,7 @@ import dev.inmo.tgbotapi.types.update.abstracts.Update
import dev.inmo.tgbotapi.updateshandlers.* import dev.inmo.tgbotapi.updateshandlers.*
import dev.inmo.tgbotapi.utils.* import dev.inmo.tgbotapi.utils.*
import io.ktor.client.features.HttpRequestTimeoutException import io.ktor.client.features.HttpRequestTimeoutException
import io.ktor.utils.io.CancellationException
import kotlinx.coroutines.* import kotlinx.coroutines.*
import kotlinx.coroutines.flow.* import kotlinx.coroutines.flow.*
@@ -89,6 +90,29 @@ fun TelegramBot.startGettingOfUpdatesByLongPolling(
updatesReceiver updatesReceiver
) )
/**
* @return [kotlinx.coroutines.flow.Flow] which will emit updates to the collector while they will be accumulated. Works
* the same as [longPollingFlow], but it will cancel the flow after the first one [HttpRequestTimeoutException]
*/
fun TelegramBot.createAccumulatedUpdatesRetrieverFlow(
avoidInlineQueries: Boolean = false,
avoidCallbackQueries: Boolean = false,
exceptionsHandler: ExceptionHandler<Unit>? = null,
allowedUpdates: List<String>? = null
): Flow<Update> = longPollingFlow(
timeoutSeconds = 0,
exceptionsHandler = {
if (it is HttpRequestTimeoutException) {
throw CancellationException("Cancel due to absence of new updates")
} else {
exceptionsHandler ?.invoke(it)
}
},
allowedUpdates = allowedUpdates
).filter {
!(it is InlineQueryUpdate && avoidInlineQueries || it is CallbackQueryUpdate && avoidCallbackQueries)
}
fun TelegramBot.retrieveAccumulatedUpdates( fun TelegramBot.retrieveAccumulatedUpdates(
avoidInlineQueries: Boolean = false, avoidInlineQueries: Boolean = false,
avoidCallbackQueries: Boolean = false, avoidCallbackQueries: Boolean = false,
@@ -96,51 +120,15 @@ fun TelegramBot.retrieveAccumulatedUpdates(
exceptionsHandler: (ExceptionHandler<Unit>)? = null, exceptionsHandler: (ExceptionHandler<Unit>)? = null,
allowedUpdates: List<String>? = null, allowedUpdates: List<String>? = null,
updatesReceiver: UpdateReceiver<Update> updatesReceiver: UpdateReceiver<Update>
): Job = scope.launch { ): Job = createAccumulatedUpdatesRetrieverFlow(
safelyWithoutExceptions { avoidInlineQueries,
startGettingOfUpdatesByLongPolling( avoidCallbackQueries,
0, exceptionsHandler,
CoroutineScope(coroutineContext + SupervisorJob()), allowedUpdates
{ ).subscribeSafelyWithoutExceptions(
if (it is HttpRequestTimeoutException) { scope.LinkedSupervisorScope()
throw CancellationException("Cancel due to absence of new updates") ) {
} else { updatesReceiver(it)
exceptionsHandler ?.invoke(it)
}
},
allowedUpdates
) {
when {
it is InlineQueryUpdate && avoidInlineQueries ||
it is CallbackQueryUpdate && avoidCallbackQueries -> return@startGettingOfUpdatesByLongPolling
else -> updatesReceiver(it)
}
}.join()
}
}
/**
* @return [kotlinx.coroutines.flow.Flow] which will emit updates to the collector while they will be accumulated. Works
* the same as [retrieveAccumulatedUpdates], but pass [kotlinx.coroutines.flow.FlowCollector.emit] as a callback
*/
fun TelegramBot.createAccumulatedUpdatesRetrieverFlow(
avoidInlineQueries: Boolean = false,
avoidCallbackQueries: Boolean = false,
exceptionsHandler: ExceptionHandler<Unit>? = null,
allowedUpdates: List<String>? = null
): Flow<Update> = channelFlow {
val parentContext = kotlin.coroutines.coroutineContext
channel.apply {
retrieveAccumulatedUpdates(
avoidInlineQueries,
avoidCallbackQueries,
CoroutineScope(parentContext),
exceptionsHandler,
allowedUpdates,
::send
).join()
close()
}
} }
fun TelegramBot.retrieveAccumulatedUpdates( fun TelegramBot.retrieveAccumulatedUpdates(
@@ -149,9 +137,30 @@ fun TelegramBot.retrieveAccumulatedUpdates(
avoidCallbackQueries: Boolean = false, avoidCallbackQueries: Boolean = false,
scope: CoroutineScope = CoroutineScope(Dispatchers.Default), scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
exceptionsHandler: ExceptionHandler<Unit>? = null exceptionsHandler: ExceptionHandler<Unit>? = null
) = flowsUpdatesFilter.run { ) = retrieveAccumulatedUpdates(
retrieveAccumulatedUpdates(avoidInlineQueries, avoidCallbackQueries, scope, exceptionsHandler, allowedUpdates, asUpdateReceiver) avoidInlineQueries,
} avoidCallbackQueries,
scope,
exceptionsHandler,
flowsUpdatesFilter.allowedUpdates,
flowsUpdatesFilter.asUpdateReceiver
)
suspend fun TelegramBot.flushAccumulatedUpdates(
avoidInlineQueries: Boolean = false,
avoidCallbackQueries: Boolean = false,
scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
allowedUpdates: List<String>? = null,
exceptionsHandler: ExceptionHandler<Unit>? = null,
updatesReceiver: UpdateReceiver<Update> = {}
) = retrieveAccumulatedUpdates(
avoidInlineQueries,
avoidCallbackQueries,
scope,
exceptionsHandler,
allowedUpdates,
updatesReceiver
).join()
/** /**
* Will [startGettingOfUpdatesByLongPolling] using incoming [flowsUpdatesFilter]. It is assumed that you ALREADY CONFIGURE * Will [startGettingOfUpdatesByLongPolling] using incoming [flowsUpdatesFilter]. It is assumed that you ALREADY CONFIGURE