1
0
mirror of https://github.com/InsanusMokrassar/TelegramBotAPI.git synced 2025-12-28 08:59:27 +00:00

Compare commits

...

57 Commits

Author SHA1 Message Date
efd1c8f83a add additional onDataCallbackQuery variants with regex filters 2022-04-26 13:22:00 +06:00
7e57a0e4e0 revert update of microutils version 2022-04-26 13:07:16 +06:00
6b977e67d0 Revert "add telegram update handler"
This reverts commit ab5937449c.
2022-04-26 13:05:56 +06:00
ab5937449c add telegram update handler 2022-04-25 22:28:35 +06:00
61d3131bf2 update micro_utils 2022-04-25 21:58:25 +06:00
048f244449 update microutils 2022-04-25 21:19:49 +06:00
6ebf4ff652 fixes in MessageContent#serializationModule 2022-04-25 21:19:08 +06:00
b4c41d7dd8 start 0.38.15 2022-04-24 18:39:07 +06:00
930507ab80 Merge pull request #568 from InsanusMokrassar/0.38.14
0.38.14
2022-04-23 12:43:02 +06:00
56d3628dd3 add support of menu buttons 2022-04-23 12:39:14 +06:00
56d7853f68 update defaults in telegramBot factories 2022-04-23 12:34:38 +06:00
0a27d9bf28 add shortcuts for telegram and webApp in webapps 2022-04-23 12:34:26 +06:00
c74df3960c fixes in viewport changed events 2022-04-23 12:34:13 +06:00
f4b080cb45 now WebAppData is data class 2022-04-23 12:34:05 +06:00
350b77f6ff add webAppButton overload with url as string 2022-04-23 12:33:56 +06:00
955e14f67c add trigger and expectation for WebAppData 2022-04-23 12:33:45 +06:00
ae88b7d94d fix dokka 2022-04-23 12:33:34 +06:00
88c62bd51c add checking of data in web app 2022-04-23 12:33:23 +06:00
705bcbe352 webapps 2022-04-23 12:32:39 +06:00
ffcc149c40 update info about supported telegram bot api version 2022-04-23 12:31:37 +06:00
402d91f9f2 add support of SentWebAppMessage 2022-04-23 12:31:22 +06:00
c19bccc7d1 add support of WebAppInfo 2022-04-23 12:30:35 +06:00
2c71377058 voice(_c/C)hat* -> video(_c/C)hat* renames 2022-04-23 12:30:15 +06:00
12d2c05110 add support of WebhookInfo#lastSynchronizationErrorDate 2022-04-23 12:28:40 +06:00
ddf46c1afd add support of ChatAdministratorRights 2022-04-23 12:27:24 +06:00
dd0a8b99c7 add WebAppData 2022-04-23 12:26:28 +06:00
75fb72936f fix of 563 2022-04-23 12:25:39 +06:00
1a6a010446 start 0.38.14 2022-04-23 12:24:52 +06:00
4c7bfe99c0 Merge pull request #567 from InsanusMokrassar/renovate/github_release_plugin_version
Update dependency com.github.breadmoirai:github-release to v2.3.7
2022-04-20 20:13:28 +06:00
Renovate Bot
1e4b8d405e Update dependency com.github.breadmoirai:github-release to v2.3.7 2022-04-19 00:27:10 +00:00
007112e67a Merge pull request #559 from InsanusMokrassar/0.38.13
0.38.13
2022-04-17 00:26:23 +06:00
a87c21273d BehaviourContext#on*Message extensions 2022-04-17 00:22:00 +06:00
ff2d1615da replace TODO for pipelineStepsHolder with default realization 2022-04-16 23:58:24 +06:00
08ef146daa Update gradle.properties 2022-04-13 23:12:32 +06:00
a404a6c59c fixes in DownloadFIleChannelRequestCallFactory 2022-04-11 21:56:47 +06:00
1089c716f3 deprecate StorageFileInfo 2022-04-11 21:00:56 +06:00
81ad55b19f add KtorPipelineStepsHolder#onRequestReturnResult 2022-04-11 14:41:02 +06:00
863c872f35 start to add pipelines and fix mention creation 2022-04-11 12:46:33 +06:00
ece6a917ed start 0.38.13 2022-04-11 11:59:37 +06:00
12248aa702 Merge pull request #555 from InsanusMokrassar/0.38.12
0.38.12
2022-04-09 12:24:57 +06:00
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
121 changed files with 2408 additions and 346 deletions

View File

@@ -1,5 +1,46 @@
# TelegramBotAPI changelog # TelegramBotAPI changelog
## 0.38.15
* `Common`:
* `Version`:
* `MicroUtils`: `0.9.20` -> `0.9.24`
* `Core`:
* Fixes in `MessageContent#serializationModule`
* `BehaviourBuilder`:
* Add triggers for `DataCallbackQuery` and subtypes with regex checking of data
## 0.38.14
__This update contains including of [Telegram Bot API 6.0](https://core.telegram.org/bots/api-changelog#april-16-2022)__
* `Core`:
* Constructor of `UnknownInlineKeyboardButton` is not internal and can be created with any `json`
* `WebApps`:
* Created 🎉
## 0.38.13
* `Core`:
* Fixes in `mention` creation
* Deprecate `StorageFileInfo`
* `BehaviourBuilder`:
* In the expectations a lot of `on*Message` extensions have been added (like `onContentMessage`). These extensions could be useful when with the `Content` its message info is important
## 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 ## 0.38.11
* `Common`: * `Common`:

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-6.0-blue)](https://core.telegram.org/bots/api-changelog#april-16-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

@@ -40,11 +40,17 @@ kotlin {
dependencies { dependencies {
implementation kotlin('stdlib') implementation kotlin('stdlib')
rootProject.subprojects.forEach { api project(":tgbotapi.core")
if (it != project) { api project(":tgbotapi.api")
api it api project(":tgbotapi.utils")
} api project(":tgbotapi.behaviour_builder")
} api project(":tgbotapi.behaviour_builder.fsm")
api project(":tgbotapi")
}
}
jsMain {
dependencies {
api project(":tgbotapi.webapps")
} }
} }
} }

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.7.0 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.17 micro_utils_version=0.9.24
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.11 library_version=0.38.15
github_release_plugin_version=2.2.12 github_release_plugin_version=2.3.7

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

@@ -21,4 +21,5 @@ include ":tgbotapi.extensions.utils"
include ":tgbotapi.extensions.behaviour_builder" include ":tgbotapi.extensions.behaviour_builder"
include ":tgbotapi.extensions.behaviour_builder.fsm" include ":tgbotapi.extensions.behaviour_builder.fsm"
include ":tgbotapi" include ":tgbotapi"
include ":tgbotapi.webapps"
include ":docs" include ":docs"

View File

@@ -13,7 +13,7 @@ import io.ktor.client.engine.*
*/ */
fun telegramBot( fun telegramBot(
urlsKeeper: TelegramAPIUrlsKeeper, urlsKeeper: TelegramAPIUrlsKeeper,
client: HttpClient client: HttpClient = HttpClient()
): TelegramBot = telegramBot(urlsKeeper) { ): TelegramBot = telegramBot(urlsKeeper) {
this.client = client this.client = client
} }
@@ -66,7 +66,7 @@ inline fun telegramBot(
inline fun telegramBot( inline fun telegramBot(
token: String, token: String,
apiUrl: String = telegramBotAPIDefaultUrl, apiUrl: String = telegramBotAPIDefaultUrl,
client: HttpClient client: HttpClient = HttpClient()
): TelegramBot = telegramBot(TelegramAPIUrlsKeeper(token, apiUrl), client) ): TelegramBot = telegramBot(TelegramAPIUrlsKeeper(token, apiUrl), client)
@Suppress("NOTHING_TO_INLINE") @Suppress("NOTHING_TO_INLINE")

View File

@@ -0,0 +1,16 @@
package dev.inmo.tgbotapi.extensions.api.answers
import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.requests.answers.AnswerWebAppQuery
import dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult.abstracts.InlineQueryResult
import dev.inmo.tgbotapi.types.WebAppQueryId
suspend fun TelegramBot.answerWebAppQuery(
webAppQueryId: WebAppQueryId,
result: InlineQueryResult
) = execute(AnswerWebAppQuery(webAppQueryId, result))
suspend fun TelegramBot.answer(
webAppQueryId: WebAppQueryId,
result: InlineQueryResult
) = execute(AnswerWebAppQuery(webAppQueryId, result))

View File

@@ -0,0 +1,13 @@
package dev.inmo.tgbotapi.extensions.api.bot
import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.requests.bot.ClearMyDefaultAdministratorRights
import dev.inmo.tgbotapi.types.ChatAdministratorRightsImpl
suspend fun TelegramBot.clearMyDefaultAdministratorRights(
forChannels: Boolean? = null
) = execute(ClearMyDefaultAdministratorRights(forChannels))
suspend fun TelegramBot.clearMyDefaultAdministratorRightsForChannels() = clearMyDefaultAdministratorRights(forChannels = true)
suspend fun TelegramBot.clearMyDefaultAdministratorRightsForGroupsAndSupergroups() = clearMyDefaultAdministratorRights(forChannels = false)

View File

@@ -0,0 +1,12 @@
package dev.inmo.tgbotapi.extensions.api.bot
import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.requests.bot.GetMyDefaultAdministratorRights
suspend fun TelegramBot.getMyDefaultAdministratorRights(
forChannels: Boolean? = null
) = execute(GetMyDefaultAdministratorRights(forChannels))
suspend fun TelegramBot.getMyDefaultAdministratorRightsForChannels() = getMyDefaultAdministratorRights(forChannels = true)
suspend fun TelegramBot.getMyDefaultAdministratorRightsForGroupsAndSupergroups() = getMyDefaultAdministratorRights(forChannels = false)

View File

@@ -0,0 +1,18 @@
package dev.inmo.tgbotapi.extensions.api.bot
import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.requests.bot.SetMyDefaultAdministratorRights
import dev.inmo.tgbotapi.types.ChatAdministratorRightsImpl
suspend fun TelegramBot.setMyDefaultAdministratorRights(
rights: ChatAdministratorRightsImpl,
forChannels: Boolean? = null
) = execute(SetMyDefaultAdministratorRights(rights, forChannels))
suspend fun TelegramBot.setMyDefaultAdministratorRightsForChannels(
rights: ChatAdministratorRightsImpl
) = setMyDefaultAdministratorRights(rights, forChannels = true)
suspend fun TelegramBot.setMyDefaultAdministratorRightsForGroupsAndSupergroups(
rights: ChatAdministratorRightsImpl
) = setMyDefaultAdministratorRights(rights, forChannels = false)

View File

@@ -0,0 +1,15 @@
package dev.inmo.tgbotapi.extensions.api.chat.get
import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.requests.chat.get.GetChatMenuButton
import dev.inmo.tgbotapi.requests.chat.modify.*
import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.chat.abstracts.PrivateChat
suspend fun TelegramBot.getChatMenuButton(
chatId: ChatId
) = execute(GetChatMenuButton(chatId))
suspend fun TelegramBot.getChatMenuButton(
chat: PrivateChat
) = getChatMenuButton(chat.id)

View File

@@ -0,0 +1,8 @@
package dev.inmo.tgbotapi.extensions.api.chat.get
import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.requests.chat.get.GetDefaultChatMenuButton
import dev.inmo.tgbotapi.requests.chat.modify.SetDefaultChatMenuButton
import dev.inmo.tgbotapi.types.MenuButton
suspend fun TelegramBot.getDefaultChatMenuButton() = execute(GetDefaultChatMenuButton)

View File

@@ -18,7 +18,7 @@ suspend fun TelegramBot.promoteChatMember(
canRestrictMembers: Boolean? = null, canRestrictMembers: Boolean? = null,
canPinMessages: Boolean? = null, canPinMessages: Boolean? = null,
canPromoteMembers: Boolean? = null, canPromoteMembers: Boolean? = null,
canManageVoiceChats: Boolean? = null, canManageVideoChats: Boolean? = null,
canManageChat: Boolean? canManageChat: Boolean?
) = execute( ) = execute(
PromoteChatMember( PromoteChatMember(
@@ -34,7 +34,7 @@ suspend fun TelegramBot.promoteChatMember(
canRestrictMembers, canRestrictMembers,
canPinMessages, canPinMessages,
canPromoteMembers, canPromoteMembers,
canManageVoiceChats, canManageVideoChats,
canManageChat canManageChat
) )
) )
@@ -52,7 +52,7 @@ suspend fun TelegramBot.promoteChatMember(
canRestrictMembers: Boolean? = null, canRestrictMembers: Boolean? = null,
canPinMessages: Boolean? = null, canPinMessages: Boolean? = null,
canPromoteMembers: Boolean? = null, canPromoteMembers: Boolean? = null,
canManageVoiceChats: Boolean? = null, canManageVideoChats: Boolean? = null,
canManageChat: Boolean? = null canManageChat: Boolean? = null
) = promoteChatMember( ) = promoteChatMember(
chat.id, chat.id,
@@ -67,7 +67,7 @@ suspend fun TelegramBot.promoteChatMember(
canRestrictMembers, canRestrictMembers,
canPinMessages, canPinMessages,
canPromoteMembers, canPromoteMembers,
canManageVoiceChats, canManageVideoChats,
canManageChat canManageChat
) )
@@ -84,7 +84,7 @@ suspend fun TelegramBot.promoteChatMember(
canRestrictMembers: Boolean? = null, canRestrictMembers: Boolean? = null,
canPinMessages: Boolean? = null, canPinMessages: Boolean? = null,
canPromoteMembers: Boolean? = null, canPromoteMembers: Boolean? = null,
canManageVoiceChats: Boolean? = null, canManageVideoChats: Boolean? = null,
canManageChat: Boolean? = null canManageChat: Boolean? = null
) = promoteChatMember( ) = promoteChatMember(
chatId, chatId,
@@ -99,7 +99,7 @@ suspend fun TelegramBot.promoteChatMember(
canRestrictMembers, canRestrictMembers,
canPinMessages, canPinMessages,
canPromoteMembers, canPromoteMembers,
canManageVoiceChats, canManageVideoChats,
canManageChat canManageChat
) )
@@ -116,7 +116,7 @@ suspend fun TelegramBot.promoteChatMember(
canRestrictMembers: Boolean? = null, canRestrictMembers: Boolean? = null,
canPinMessages: Boolean? = null, canPinMessages: Boolean? = null,
canPromoteMembers: Boolean? = null, canPromoteMembers: Boolean? = null,
canManageVoiceChats: Boolean? = null, canManageVideoChats: Boolean? = null,
canManageChat: Boolean? = null canManageChat: Boolean? = null
) = promoteChatMember( ) = promoteChatMember(
chat.id, chat.id,
@@ -131,6 +131,6 @@ suspend fun TelegramBot.promoteChatMember(
canRestrictMembers, canRestrictMembers,
canPinMessages, canPinMessages,
canPromoteMembers, canPromoteMembers,
canManageVoiceChats, canManageVideoChats,
canManageChat canManageChat
) )

View File

@@ -0,0 +1,16 @@
package dev.inmo.tgbotapi.extensions.api.chat.modify
import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.requests.chat.modify.*
import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.chat.abstracts.PrivateChat
suspend fun TelegramBot.setChatMenuButton(
chatId: ChatId,
menuButton: MenuButton
) = execute(SetChatMenuButton(chatId, menuButton))
suspend fun TelegramBot.setChatMenuButton(
chat: PrivateChat,
menuButton: MenuButton
) = setChatMenuButton(chat.id, menuButton)

View File

@@ -0,0 +1,9 @@
package dev.inmo.tgbotapi.extensions.api.chat.modify
import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.requests.chat.modify.SetDefaultChatMenuButton
import dev.inmo.tgbotapi.types.MenuButton
suspend fun TelegramBot.setDefaultChatMenuButton(
menuButton: MenuButton
) = execute(SetDefaultChatMenuButton(menuButton))

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
@@ -24,7 +25,7 @@ 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.*
import dev.inmo.tgbotapi.types.message.content.abstracts.MessageContent import dev.inmo.tgbotapi.types.message.content.abstracts.MessageContent
import dev.inmo.tgbotapi.types.passport.encrypted.PassportFile 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.*
@@ -1061,6 +1062,14 @@ suspend fun TelegramBot.reply(
allowSendingWithoutReply = allowSendingWithoutReply, allowSendingWithoutReply = allowSendingWithoutReply,
replyMarkup = replyMarkup replyMarkup = replyMarkup
) )
is PhotoSize -> reply(
to = to,
photoSize = mediaFile,
disableNotification = disableNotification,
protectContent = protectContent,
allowSendingWithoutReply = allowSendingWithoutReply,
replyMarkup = replyMarkup
)
else -> reply( else -> reply(
to = to, to = to,
document = mediaFile.asDocumentFile(), document = mediaFile.asDocumentFile(),
@@ -1071,3 +1080,144 @@ suspend fun TelegramBot.reply(
) )
} }
} }
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

@@ -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

@@ -26,7 +26,7 @@ internal inline fun <BC, T, I1, I2> CustomBehaviourContextAndTwoTypesReceiver<BC
): CustomBehaviourContextAndTypeReceiver<BC, T, I2> = { invoke(this, i1, it) } ): CustomBehaviourContextAndTypeReceiver<BC, T, I2> = { invoke(this, i1, it) }
/** /**
* This class contains all necessary tools for work with bots and especially for [buildBehaviour] * This class contains all necessary tools for work with bots and especially [buildBehaviour]
* *
* @see DefaultBehaviourContext * @see DefaultBehaviourContext
*/ */

View File

@@ -11,16 +11,19 @@ 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?
private suspend fun <O> BehaviourContext.waitCommonMessage( private suspend fun <O> BehaviourContext.waitCommonContent(
count: Int = 1, count: Int = 1,
initRequest: Request<*>? = null, initRequest: Request<*>? = null,
includeMediaGroups: Boolean = true, includeMediaGroups: Boolean = true,
@@ -74,7 +77,7 @@ private suspend inline fun <reified T : MessageContent> BehaviourContext.waitCon
noinline errorFactory: NullableRequestBuilder<*> = { null }, noinline errorFactory: NullableRequestBuilder<*> = { null },
noinline filter: SimpleFilter<CommonMessage<T>>? = null, noinline filter: SimpleFilter<CommonMessage<T>>? = null,
noinline mapper: CommonMessageToContentMapper<T>? = null noinline mapper: CommonMessageToContentMapper<T>? = null
) : List<T> = waitCommonMessage<T>( ) : List<T> = waitCommonContent<T>(
count, count,
initRequest, initRequest,
includeMediaGroups, includeMediaGroups,
@@ -87,7 +90,8 @@ private suspend inline fun <reified T : MessageContent> BehaviourContext.waitCon
contentConverter(mapper) contentConverter(mapper)
).toList() ).toList()
suspend fun BehaviourContext.waitContentMessage(
suspend fun BehaviourContext.waitContent(
initRequest: Request<*>? = null, initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }, errorFactory: NullableRequestBuilder<*> = { null },
count: Int = 1, count: Int = 1,
@@ -198,6 +202,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

@@ -0,0 +1,281 @@
@file:Suppress("unused")
package dev.inmo.tgbotapi.extensions.behaviour_builder.expectations
import dev.inmo.micro_utils.coroutines.safelyWithoutExceptions
import dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContext
import dev.inmo.tgbotapi.extensions.behaviour_builder.utils.SimpleFilter
import dev.inmo.tgbotapi.extensions.utils.withContent
import dev.inmo.tgbotapi.requests.abstracts.Request
import dev.inmo.tgbotapi.types.message.abstracts.CommonMessage
import dev.inmo.tgbotapi.types.message.content.*
import dev.inmo.tgbotapi.types.message.content.abstracts.*
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.update.MediaGroupUpdates.SentMediaGroupUpdate
import dev.inmo.tgbotapi.types.update.abstracts.BaseSentMessageUpdate
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.toList
typealias CommonMessageToCommonMessageMapper<T> = suspend CommonMessage<T>.() -> CommonMessage<T>?
internal suspend fun <O : MessageContent> BehaviourContext.waitCommonMessage(
count: Int = 1,
initRequest: Request<*>? = null,
includeMediaGroups: Boolean = true,
errorFactory: NullableRequestBuilder<*> = { null },
filter: SimpleFilter<CommonMessage<MessageContent>>? = null,
mapper: suspend CommonMessage<MessageContent>.() -> CommonMessage<O>?
): Flow<CommonMessage<O>> = expectFlow(
initRequest,
count,
errorFactory
) {
val messages = when (it) {
is SentMediaGroupUpdate -> {
if (includeMediaGroups) {
it.data.map { it as CommonMessage<MessageContent> }
} else {
emptyList()
}
}
is BaseSentMessageUpdate -> listOf(it.data)
else -> return@expectFlow emptyList()
}
messages.mapNotNull { message ->
val asCommonMessage = message as CommonMessage<MessageContent>
if (filter == null || filter(asCommonMessage)) {
asCommonMessage.mapper()
} else {
null
}
}
}
internal inline fun <reified T : MessageContent> contentMessageConverter(
noinline mapper: CommonMessageToCommonMessageMapper<T>? = null
): suspend CommonMessage<MessageContent>.() -> CommonMessage<T>? = mapper ?.let {
{
if (content is T) {
@Suppress("UNCHECKED_CAST")
val message = (this as CommonMessage<T>)
safelyWithoutExceptions { mapper(message) }
} else {
null
}
}
} ?: {
@Suppress("UNCHECKED_CAST")
if (content is T) this as CommonMessage<T> else null
}
private suspend inline fun <reified T : MessageContent> BehaviourContext.waitContentMessage(
count: Int = 1,
initRequest: Request<*>? = null,
includeMediaGroups: Boolean = true,
noinline errorFactory: NullableRequestBuilder<*> = { null },
noinline filter: SimpleFilter<CommonMessage<T>>? = null,
noinline mapper: CommonMessageToCommonMessageMapper<T>? = null
) : List<CommonMessage<T>> = waitCommonMessage<T>(
count,
initRequest,
includeMediaGroups,
errorFactory,
filter ?.let {
{
it.withContent<T>() ?.let { filter(it) } == true
}
},
contentMessageConverter(mapper)
).toList()
suspend fun BehaviourContext.waitContentMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
count: Int = 1,
includeMediaGroups: Boolean = true,
filter: SimpleFilter<CommonMessage<MessageContent>>? = null,
mapper: CommonMessageToCommonMessageMapper<MessageContent>? = null
) = waitContentMessage(count, initRequest, includeMediaGroups, errorFactory, filter, mapper)
suspend fun BehaviourContext.waitContactMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
count: Int = 1,
filter: SimpleFilter<CommonMessage<ContactContent>>? = null,
mapper: CommonMessageToCommonMessageMapper<ContactContent>? = null
) = waitContentMessage(count, initRequest, false, errorFactory, filter, mapper)
suspend fun BehaviourContext.waitDiceMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
count: Int = 1,
filter: SimpleFilter<CommonMessage<DiceContent>>? = null,
mapper: CommonMessageToCommonMessageMapper<DiceContent>? = null
) = waitContentMessage(count, initRequest, false, errorFactory, filter, mapper)
suspend fun BehaviourContext.waitGameMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
count: Int = 1,
filter: SimpleFilter<CommonMessage<GameContent>>? = null,
mapper: CommonMessageToCommonMessageMapper<GameContent>? = null
) = waitContentMessage(count, initRequest, false, errorFactory, filter, mapper)
suspend fun BehaviourContext.waitLocationMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
count: Int = 1,
filter: SimpleFilter<CommonMessage<LocationContent>>? = null,
mapper: CommonMessageToCommonMessageMapper<LocationContent>? = null
) = waitContentMessage(count, initRequest, false, errorFactory, filter, mapper)
suspend fun BehaviourContext.waitLiveLocationMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
count: Int = 1,
filter: SimpleFilter<CommonMessage<LiveLocationContent>>? = null,
mapper: CommonMessageToCommonMessageMapper<LiveLocationContent>? = null
) = waitContentMessage(count, initRequest, false, errorFactory, filter, mapper)
suspend fun BehaviourContext.waitStaticLocationMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
count: Int = 1,
filter: SimpleFilter<CommonMessage<StaticLocationContent>>? = null,
mapper: CommonMessageToCommonMessageMapper<StaticLocationContent>? = null
) = waitContentMessage(count, initRequest, false, errorFactory, filter, mapper)
suspend fun BehaviourContext.waitPollMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
count: Int = 1,
filter: SimpleFilter<CommonMessage<PollContent>>? = null,
mapper: CommonMessageToCommonMessageMapper<PollContent>? = null
) = waitContentMessage(count, initRequest, false, errorFactory, filter, mapper)
suspend fun BehaviourContext.waitTextMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
count: Int = 1,
filter: SimpleFilter<CommonMessage<TextContent>>? = null,
mapper: CommonMessageToCommonMessageMapper<TextContent>? = null
) = waitContentMessage(count, initRequest, false, errorFactory, filter, mapper)
suspend fun BehaviourContext.waitVenueMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
count: Int = 1,
filter: SimpleFilter<CommonMessage<VenueContent>>? = null,
mapper: CommonMessageToCommonMessageMapper<VenueContent>? = null
) = waitContentMessage(count, initRequest, false, errorFactory, filter, mapper)
suspend fun BehaviourContext.waitAudioMediaGroupContentMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
count: Int = 1,
includeMediaGroups: Boolean = true,
filter: SimpleFilter<CommonMessage<AudioMediaGroupContent>>? = null,
mapper: CommonMessageToCommonMessageMapper<AudioMediaGroupContent>? = null
) = waitContentMessage(count, initRequest, includeMediaGroups, errorFactory, filter, mapper)
suspend fun BehaviourContext.waitDocumentMediaGroupContentMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
count: Int = 1,
includeMediaGroups: Boolean = true,
filter: SimpleFilter<CommonMessage<DocumentMediaGroupContent>>? = null,
mapper: CommonMessageToCommonMessageMapper<DocumentMediaGroupContent>? = null
) = waitContentMessage(count, initRequest, includeMediaGroups, errorFactory, filter, mapper)
suspend fun BehaviourContext.waitMediaMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
count: Int = 1,
includeMediaGroups: Boolean = false,
filter: SimpleFilter<CommonMessage<MediaContent>>? = null,
mapper: CommonMessageToCommonMessageMapper<MediaContent>? = null
) = waitContentMessage(count, initRequest, includeMediaGroups, errorFactory, filter, mapper)
suspend fun BehaviourContext.waitAnyMediaGroupContentMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
count: Int = 1,
includeMediaGroups: Boolean = true,
filter: SimpleFilter<CommonMessage<MediaGroupContent>>? = null,
mapper: CommonMessageToCommonMessageMapper<MediaGroupContent>? = null
) = waitContentMessage(count, initRequest, includeMediaGroups, errorFactory, filter, mapper)
suspend fun BehaviourContext.waitVisualMediaGroupContentMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
count: Int = 1,
includeMediaGroups: Boolean = true,
filter: SimpleFilter<CommonMessage<VisualMediaGroupContent>>? = null,
mapper: CommonMessageToCommonMessageMapper<VisualMediaGroupContent>? = null
) = waitContentMessage(count, initRequest, includeMediaGroups, errorFactory, filter, mapper)
suspend fun BehaviourContext.waitTextedMediaContentMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
count: Int = 1,
includeMediaGroups: Boolean = true,
filter: SimpleFilter<CommonMessage<TextedMediaContent>>? = null,
mapper: CommonMessageToCommonMessageMapper<TextedMediaContent>? = null
) = waitContentMessage(count, initRequest, includeMediaGroups, errorFactory, filter, mapper)
suspend fun BehaviourContext.waitAnimationMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
count: Int = 1,
filter: SimpleFilter<CommonMessage<AnimationContent>>? = null,
mapper: CommonMessageToCommonMessageMapper<AnimationContent>? = null
) = waitContentMessage(count, initRequest, false, errorFactory, filter, mapper)
suspend fun BehaviourContext.waitAudioMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
count: Int = 1,
includeMediaGroups: Boolean = false,
filter: SimpleFilter<CommonMessage<AudioContent>>? = null,
mapper: CommonMessageToCommonMessageMapper<AudioContent>? = null
) = waitContentMessage(count, initRequest, includeMediaGroups, errorFactory, filter, mapper)
suspend fun BehaviourContext.waitDocumentMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
count: Int = 1,
includeMediaGroups: Boolean = false,
filter: SimpleFilter<CommonMessage<DocumentContent>>? = null,
mapper: CommonMessageToCommonMessageMapper<DocumentContent>? = null
) = waitContentMessage(count, initRequest, includeMediaGroups, errorFactory, filter, mapper)
suspend fun BehaviourContext.waitPhotoMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
count: Int = 1,
includeMediaGroups: Boolean = false,
filter: SimpleFilter<CommonMessage<PhotoContent>>? = null,
mapper: CommonMessageToCommonMessageMapper<PhotoContent>? = null
) = waitContentMessage(count, initRequest, includeMediaGroups, errorFactory, filter, mapper)
suspend fun BehaviourContext.waitStickerMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
count: Int = 1,
filter: SimpleFilter<CommonMessage<StickerContent>>? = null,
mapper: CommonMessageToCommonMessageMapper<StickerContent>? = null
) = waitContentMessage(count, initRequest, false, errorFactory, filter, mapper)
suspend fun BehaviourContext.waitVideoMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
count: Int = 1,
includeMediaGroups: Boolean = false,
filter: SimpleFilter<CommonMessage<VideoContent>>? = null,
mapper: CommonMessageToCommonMessageMapper<VideoContent>? = null
) = waitContentMessage(count, initRequest, includeMediaGroups, errorFactory, filter, mapper)
suspend fun BehaviourContext.waitVideoNoteMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
count: Int = 1,
filter: SimpleFilter<CommonMessage<VideoNoteContent>>? = null,
mapper: CommonMessageToCommonMessageMapper<VideoNoteContent>? = null
) = waitContentMessage(count, initRequest, false, errorFactory, filter, mapper)
suspend fun BehaviourContext.waitVoiceMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
count: Int = 1,
filter: SimpleFilter<CommonMessage<VoiceContent>>? = null,
mapper: CommonMessageToCommonMessageMapper<VoiceContent>? = null
) = waitContentMessage(count, initRequest, false, errorFactory, filter, mapper)
suspend fun BehaviourContext.waitInvoiceMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
count: Int = 1,
filter: SimpleFilter<CommonMessage<InvoiceContent>>? = null,
mapper: CommonMessageToCommonMessageMapper<InvoiceContent>? = null
) = waitContentMessage(count, initRequest, false, errorFactory, filter, mapper)

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

@@ -10,6 +10,7 @@ import dev.inmo.tgbotapi.requests.abstracts.Request
import dev.inmo.tgbotapi.types.message.ChatEvents.* import dev.inmo.tgbotapi.types.message.ChatEvents.*
import dev.inmo.tgbotapi.types.message.ChatEvents.abstracts.* import dev.inmo.tgbotapi.types.message.ChatEvents.abstracts.*
import dev.inmo.tgbotapi.types.message.ChatEvents.voice.* import dev.inmo.tgbotapi.types.message.ChatEvents.voice.*
import dev.inmo.tgbotapi.types.message.PrivateEventMessage
import dev.inmo.tgbotapi.types.message.abstracts.ChatEventMessage import dev.inmo.tgbotapi.types.message.abstracts.ChatEventMessage
import dev.inmo.tgbotapi.types.message.payments.SuccessfulPaymentEvent import dev.inmo.tgbotapi.types.message.payments.SuccessfulPaymentEvent
import kotlinx.coroutines.flow.toList import kotlinx.coroutines.flow.toList
@@ -89,33 +90,66 @@ suspend fun BehaviourContext.waitChatEvents(
mapper: EventMessageToEventMapper<ChatEvent>? = null mapper: EventMessageToEventMapper<ChatEvent>? = null
) = waitEvents(count, initRequest, errorFactory, filter, mapper) ) = waitEvents(count, initRequest, errorFactory, filter, mapper)
@Deprecated("Renamed as Video instead of Voice")
suspend fun BehaviourContext.waitVoiceChatEvents( suspend fun BehaviourContext.waitVoiceChatEvents(
initRequest: Request<*>? = null, initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }, errorFactory: NullableRequestBuilder<*> = { null },
count: Int = 1, count: Int = 1,
filter: SimpleFilter<ChatEventMessage<VoiceChatEvent>>? = null, filter: SimpleFilter<ChatEventMessage<VideoChatEvent>>? = null,
mapper: EventMessageToEventMapper<VoiceChatEvent>? = null mapper: EventMessageToEventMapper<VideoChatEvent>? = null
) = waitEvents(count, initRequest, errorFactory, filter, mapper) ) = waitEvents(count, initRequest, errorFactory, filter, mapper)
@Deprecated("Renamed as Video instead of Voice")
suspend fun BehaviourContext.waitVoiceChatStartedEvents( suspend fun BehaviourContext.waitVoiceChatStartedEvents(
initRequest: Request<*>? = null, initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }, errorFactory: NullableRequestBuilder<*> = { null },
count: Int = 1, count: Int = 1,
filter: SimpleFilter<ChatEventMessage<VoiceChatStarted>>? = null, filter: SimpleFilter<ChatEventMessage<VideoChatStarted>>? = null,
mapper: EventMessageToEventMapper<VoiceChatStarted>? = null mapper: EventMessageToEventMapper<VideoChatStarted>? = null
) = waitEvents(count, initRequest, errorFactory, filter, mapper) ) = waitEvents(count, initRequest, errorFactory, filter, mapper)
@Deprecated("Renamed as Video instead of Voice")
suspend fun BehaviourContext.waitVoiceChatEndedEvents( suspend fun BehaviourContext.waitVoiceChatEndedEvents(
initRequest: Request<*>? = null, initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }, errorFactory: NullableRequestBuilder<*> = { null },
count: Int = 1, count: Int = 1,
filter: SimpleFilter<ChatEventMessage<VoiceChatEnded>>? = null, filter: SimpleFilter<ChatEventMessage<VideoChatEnded>>? = null,
mapper: EventMessageToEventMapper<VoiceChatEnded>? = null mapper: EventMessageToEventMapper<VideoChatEnded>? = null
) = waitEvents(count, initRequest, errorFactory, filter, mapper) ) = waitEvents(count, initRequest, errorFactory, filter, mapper)
@Deprecated("Renamed as Video instead of Voice")
suspend fun BehaviourContext.waitVoiceChatParticipantsInvitedEvents( suspend fun BehaviourContext.waitVoiceChatParticipantsInvitedEvents(
initRequest: Request<*>? = null, initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }, errorFactory: NullableRequestBuilder<*> = { null },
count: Int = 1, count: Int = 1,
filter: SimpleFilter<ChatEventMessage<VoiceChatParticipantsInvited>>? = null, filter: SimpleFilter<ChatEventMessage<VideoChatParticipantsInvited>>? = null,
mapper: EventMessageToEventMapper<VoiceChatParticipantsInvited>? = null mapper: EventMessageToEventMapper<VideoChatParticipantsInvited>? = null
) = waitEvents(count, initRequest, errorFactory, filter, mapper)
suspend fun BehaviourContext.waitVideoChatEvents(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
count: Int = 1,
filter: SimpleFilter<ChatEventMessage<VideoChatEvent>>? = null,
mapper: EventMessageToEventMapper<VideoChatEvent>? = null
) = waitEvents(count, initRequest, errorFactory, filter, mapper)
suspend fun BehaviourContext.waitVideoChatStartedEvents(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
count: Int = 1,
filter: SimpleFilter<ChatEventMessage<VideoChatStarted>>? = null,
mapper: EventMessageToEventMapper<VideoChatStarted>? = null
) = waitEvents(count, initRequest, errorFactory, filter, mapper)
suspend fun BehaviourContext.waitVideoChatEndedEvents(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
count: Int = 1,
filter: SimpleFilter<ChatEventMessage<VideoChatEnded>>? = null,
mapper: EventMessageToEventMapper<VideoChatEnded>? = null
) = waitEvents(count, initRequest, errorFactory, filter, mapper)
suspend fun BehaviourContext.waitVideoChatParticipantsInvitedEvents(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
count: Int = 1,
filter: SimpleFilter<ChatEventMessage<VideoChatParticipantsInvited>>? = null,
mapper: EventMessageToEventMapper<VideoChatParticipantsInvited>? = null
) = waitEvents(count, initRequest, errorFactory, filter, mapper) ) = waitEvents(count, initRequest, errorFactory, filter, mapper)
suspend fun BehaviourContext.waitMessageAutoDeleteTimerChangedEvents( suspend fun BehaviourContext.waitMessageAutoDeleteTimerChangedEvents(
@@ -241,3 +275,10 @@ suspend fun BehaviourContext.waitUserLoggedInEvents(
filter: SimpleFilter<ChatEventMessage<UserLoggedIn>>? = null, filter: SimpleFilter<ChatEventMessage<UserLoggedIn>>? = null,
mapper: EventMessageToEventMapper<UserLoggedIn>? = null mapper: EventMessageToEventMapper<UserLoggedIn>? = null
) = waitEvents(count, initRequest, errorFactory, filter, mapper) ) = waitEvents(count, initRequest, errorFactory, filter, mapper)
suspend fun BehaviourContext.waitWebAppDataEvents(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
count: Int = 1,
filter: SimpleFilter<PrivateEventMessage<WebAppData>>? = null,
mapper: EventMessageToEventMapper<WebAppData>? = null
) = waitEvents(count, initRequest, errorFactory, filter ?.let { { it is PrivateEventMessage && filter(it) } }, mapper)

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

@@ -7,6 +7,7 @@ import dev.inmo.tgbotapi.extensions.behaviour_builder.filters.CallbackQueryFilte
import dev.inmo.tgbotapi.extensions.behaviour_builder.utils.SimpleFilter import dev.inmo.tgbotapi.extensions.behaviour_builder.utils.SimpleFilter
import dev.inmo.tgbotapi.extensions.behaviour_builder.utils.marker_factories.ByUserCallbackQueryMarkerFactory import dev.inmo.tgbotapi.extensions.behaviour_builder.utils.marker_factories.ByUserCallbackQueryMarkerFactory
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.behaviour_builder.utils.plus
import dev.inmo.tgbotapi.extensions.utils.asCallbackQueryUpdate import dev.inmo.tgbotapi.extensions.utils.asCallbackQueryUpdate
import dev.inmo.tgbotapi.types.CallbackQuery.* import dev.inmo.tgbotapi.types.CallbackQuery.*
import dev.inmo.tgbotapi.types.update.abstracts.Update import dev.inmo.tgbotapi.types.update.abstracts.Update
@@ -44,6 +45,62 @@ suspend fun <BC : BehaviourContext> BC.onDataCallbackQuery(
scenarioReceiver scenarioReceiver
) )
/**
* @param dataRegex Will be used with [initialFilter] as [initialFilter] for upstream [onDataCallbackQuery] to filter
* [DataCallbackQuery] with [DataCallbackQuery.data] [String.matches] to [dataRegex]
* @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.onDataCallbackQuery(
dataRegex: Regex,
initialFilter: SimpleFilter<DataCallbackQuery>? = null,
subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, DataCallbackQuery, Update>? = CallbackQueryFilterByUser,
markerFactory: MarkerFactory<in DataCallbackQuery, Any> = ByUserCallbackQueryMarkerFactory,
scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, DataCallbackQuery>
) = onDataCallbackQuery(
initialFilter = initialFilter + {
it.data.matches(dataRegex)
},
subcontextUpdatesFilter,
markerFactory,
scenarioReceiver
)
/**
* @param data Will be converted to [Regex] via its constructor and pass it to upstream [onDataCallbackQuery]
* @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.onDataCallbackQuery(
data: String,
initialFilter: SimpleFilter<DataCallbackQuery>? = null,
subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, DataCallbackQuery, Update>? = CallbackQueryFilterByUser,
markerFactory: MarkerFactory<in DataCallbackQuery, Any> = ByUserCallbackQueryMarkerFactory,
scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, DataCallbackQuery>
) = onDataCallbackQuery(
Regex(data),
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,
@@ -116,6 +173,62 @@ suspend fun <BC : BehaviourContext> BC.onInlineMessageIdDataCallbackQuery(
scenarioReceiver scenarioReceiver
) )
/**
* @param dataRegex Will be used with [initialFilter] as [initialFilter] for upstream [onInlineMessageIdDataCallbackQuery]
* to filter [InlineMessageIdDataCallbackQuery] with [InlineMessageIdDataCallbackQuery.data] [String.matches] to [dataRegex]
* @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.onInlineMessageIdDataCallbackQuery(
dataRegex: Regex,
initialFilter: SimpleFilter<InlineMessageIdDataCallbackQuery>? = null,
subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, InlineMessageIdDataCallbackQuery, Update>? = CallbackQueryFilterByUser,
markerFactory: MarkerFactory<in InlineMessageIdDataCallbackQuery, Any> = ByUserCallbackQueryMarkerFactory,
scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, InlineMessageIdDataCallbackQuery>
) = onInlineMessageIdDataCallbackQuery(
initialFilter = initialFilter + {
it.data.matches(dataRegex)
},
subcontextUpdatesFilter,
markerFactory,
scenarioReceiver
)
/**
* @param data Will be converted to [Regex] via its constructor and pass it to upstream [onInlineMessageIdDataCallbackQuery]
* @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.onInlineMessageIdDataCallbackQuery(
data: String,
initialFilter: SimpleFilter<InlineMessageIdDataCallbackQuery>? = null,
subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, InlineMessageIdDataCallbackQuery, Update>? = CallbackQueryFilterByUser,
markerFactory: MarkerFactory<in InlineMessageIdDataCallbackQuery, Any> = ByUserCallbackQueryMarkerFactory,
scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, InlineMessageIdDataCallbackQuery>
) = onInlineMessageIdDataCallbackQuery(
Regex(data),
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,
@@ -188,6 +301,62 @@ suspend fun <BC : BehaviourContext> BC.onMessageDataCallbackQuery(
scenarioReceiver scenarioReceiver
) )
/**
* @param dataRegex Will be used with [initialFilter] as [initialFilter] for upstream [onMessageDataCallbackQuery] to filter
* [MessageDataCallbackQuery] with [MessageDataCallbackQuery.data] [String.matches] to [dataRegex]
* @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.onMessageDataCallbackQuery(
dataRegex: Regex,
initialFilter: SimpleFilter<MessageDataCallbackQuery>? = null,
subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, MessageDataCallbackQuery, Update>? = CallbackQueryFilterByUser,
markerFactory: MarkerFactory<in MessageDataCallbackQuery, Any> = ByUserCallbackQueryMarkerFactory,
scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, MessageDataCallbackQuery>
) = onMessageDataCallbackQuery(
initialFilter = initialFilter + {
it.data.matches(dataRegex)
},
subcontextUpdatesFilter,
markerFactory,
scenarioReceiver
)
/**
* @param data Will be converted to [Regex] via its constructor and pass it to upstream [onMessageDataCallbackQuery]
* @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.onMessageDataCallbackQuery(
data: String,
initialFilter: SimpleFilter<MessageDataCallbackQuery>? = null,
subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, MessageDataCallbackQuery, Update>? = CallbackQueryFilterByUser,
markerFactory: MarkerFactory<in MessageDataCallbackQuery, Any> = ByUserCallbackQueryMarkerFactory,
scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, MessageDataCallbackQuery>
) = onMessageDataCallbackQuery(
Regex(data),
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

@@ -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
@@ -22,7 +24,7 @@ import dev.inmo.tgbotapi.types.update.abstracts.Update
typealias CommonMessageFilter<T> = SimpleFilter<CommonMessage<T>> typealias CommonMessageFilter<T> = SimpleFilter<CommonMessage<T>>
inline fun <T : MessageContent> CommonMessageFilter(noinline block: CommonMessageFilter<T>) = block inline fun <T : MessageContent> CommonMessageFilter(noinline block: CommonMessageFilter<T>) = block
internal suspend inline fun <BC : BehaviourContext, reified T : MessageContent> BC.onContent( internal suspend inline fun <BC : BehaviourContext, reified T : MessageContent> BC.onContentMessageWithType(
noinline initialFilter: CommonMessageFilter<T>? = null, noinline initialFilter: CommonMessageFilter<T>? = null,
noinline subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, CommonMessage<T>, Update>? = MessageFilterByChat, noinline subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, CommonMessage<T>, Update>? = MessageFilterByChat,
markerFactory: MarkerFactory<in CommonMessage<T>, Any> = ByChatMessageMarkerFactory, markerFactory: MarkerFactory<in CommonMessage<T>, Any> = ByChatMessageMarkerFactory,
@@ -55,7 +57,7 @@ suspend fun <BC : BehaviourContext> BC.onContentMessage(
subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, CommonMessage<MessageContent>, Update> = MessageFilterByChat, subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, CommonMessage<MessageContent>, Update> = MessageFilterByChat,
markerFactory: MarkerFactory<in CommonMessage<MessageContent>, Any> = ByChatMessageMarkerFactory, markerFactory: MarkerFactory<in CommonMessage<MessageContent>, Any> = ByChatMessageMarkerFactory,
scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, CommonMessage<MessageContent>> scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, CommonMessage<MessageContent>>
) = onContent( ) = onContentMessageWithType(
initialFilter, initialFilter,
subcontextUpdatesFilter, subcontextUpdatesFilter,
markerFactory, markerFactory,
@@ -79,7 +81,7 @@ suspend fun <BC : BehaviourContext> BC.onContact(
subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, CommonMessage<ContactContent>, Update> = MessageFilterByChat, subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, CommonMessage<ContactContent>, Update> = MessageFilterByChat,
markerFactory: MarkerFactory<in CommonMessage<ContactContent>, Any> = ByChatMessageMarkerFactory, markerFactory: MarkerFactory<in CommonMessage<ContactContent>, Any> = ByChatMessageMarkerFactory,
scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, CommonMessage<ContactContent>> scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, CommonMessage<ContactContent>>
) = onContent( ) = onContentMessageWithType(
initialFilter, initialFilter,
subcontextUpdatesFilter, subcontextUpdatesFilter,
markerFactory, markerFactory,
@@ -103,7 +105,7 @@ suspend fun <BC : BehaviourContext> BC.onDice(
subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, CommonMessage<DiceContent>, Update> = MessageFilterByChat, subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, CommonMessage<DiceContent>, Update> = MessageFilterByChat,
markerFactory: MarkerFactory<in CommonMessage<DiceContent>, Any> = ByChatMessageMarkerFactory, markerFactory: MarkerFactory<in CommonMessage<DiceContent>, Any> = ByChatMessageMarkerFactory,
scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, CommonMessage<DiceContent>> scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, CommonMessage<DiceContent>>
) = onContent( ) = onContentMessageWithType(
initialFilter, initialFilter,
subcontextUpdatesFilter, subcontextUpdatesFilter,
markerFactory, markerFactory,
@@ -127,7 +129,7 @@ suspend fun <BC : BehaviourContext> BC.onGame(
subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, CommonMessage<GameContent>, Update> = MessageFilterByChat, subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, CommonMessage<GameContent>, Update> = MessageFilterByChat,
markerFactory: MarkerFactory<in CommonMessage<GameContent>, Any> = ByChatMessageMarkerFactory, markerFactory: MarkerFactory<in CommonMessage<GameContent>, Any> = ByChatMessageMarkerFactory,
scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, CommonMessage<GameContent>> scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, CommonMessage<GameContent>>
) = onContent( ) = onContentMessageWithType(
initialFilter, initialFilter,
subcontextUpdatesFilter, subcontextUpdatesFilter,
markerFactory, markerFactory,
@@ -151,7 +153,7 @@ suspend fun <BC : BehaviourContext> BC.onLocation(
subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, CommonMessage<LocationContent>, Update> = MessageFilterByChat, subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, CommonMessage<LocationContent>, Update> = MessageFilterByChat,
markerFactory: MarkerFactory<in CommonMessage<LocationContent>, Any> = ByChatMessageMarkerFactory, markerFactory: MarkerFactory<in CommonMessage<LocationContent>, Any> = ByChatMessageMarkerFactory,
scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, CommonMessage<LocationContent>> scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, CommonMessage<LocationContent>>
) = onContent( ) = onContentMessageWithType(
initialFilter, initialFilter,
subcontextUpdatesFilter, subcontextUpdatesFilter,
markerFactory, markerFactory,
@@ -175,7 +177,7 @@ suspend fun <BC : BehaviourContext> BC.onLiveLocation(
subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, CommonMessage<LiveLocationContent>, Update> = MessageFilterByChat, subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, CommonMessage<LiveLocationContent>, Update> = MessageFilterByChat,
markerFactory: MarkerFactory<in CommonMessage<LiveLocationContent>, Any> = ByChatMessageMarkerFactory, markerFactory: MarkerFactory<in CommonMessage<LiveLocationContent>, Any> = ByChatMessageMarkerFactory,
scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, CommonMessage<LiveLocationContent>> scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, CommonMessage<LiveLocationContent>>
) = onContent( ) = onContentMessageWithType(
initialFilter, initialFilter,
subcontextUpdatesFilter, subcontextUpdatesFilter,
markerFactory, markerFactory,
@@ -199,7 +201,7 @@ suspend fun <BC : BehaviourContext> BC.onStaticLocation(
subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, CommonMessage<StaticLocationContent>, Update> = MessageFilterByChat, subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, CommonMessage<StaticLocationContent>, Update> = MessageFilterByChat,
markerFactory: MarkerFactory<in CommonMessage<StaticLocationContent>, Any> = ByChatMessageMarkerFactory, markerFactory: MarkerFactory<in CommonMessage<StaticLocationContent>, Any> = ByChatMessageMarkerFactory,
scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, CommonMessage<StaticLocationContent>> scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, CommonMessage<StaticLocationContent>>
) = onContent( ) = onContentMessageWithType(
initialFilter, initialFilter,
subcontextUpdatesFilter, subcontextUpdatesFilter,
markerFactory, markerFactory,
@@ -223,7 +225,7 @@ suspend fun <BC : BehaviourContext> BC.onPoll(
subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, CommonMessage<PollContent>, Update> = MessageFilterByChat, subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, CommonMessage<PollContent>, Update> = MessageFilterByChat,
markerFactory: MarkerFactory<in CommonMessage<PollContent>, Any> = ByChatMessageMarkerFactory, markerFactory: MarkerFactory<in CommonMessage<PollContent>, Any> = ByChatMessageMarkerFactory,
scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, CommonMessage<PollContent>> scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, CommonMessage<PollContent>>
) = onContent( ) = onContentMessageWithType(
initialFilter, initialFilter,
subcontextUpdatesFilter, subcontextUpdatesFilter,
markerFactory, markerFactory,
@@ -247,7 +249,7 @@ suspend fun <BC : BehaviourContext> BC.onText(
subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, CommonMessage<TextContent>, Update> = MessageFilterByChat, subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, CommonMessage<TextContent>, Update> = MessageFilterByChat,
markerFactory: MarkerFactory<in CommonMessage<TextContent>, Any> = ByChatMessageMarkerFactory, markerFactory: MarkerFactory<in CommonMessage<TextContent>, Any> = ByChatMessageMarkerFactory,
scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, CommonMessage<TextContent>> scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, CommonMessage<TextContent>>
) = onContent( ) = onContentMessageWithType(
initialFilter, initialFilter,
subcontextUpdatesFilter, subcontextUpdatesFilter,
markerFactory, markerFactory,
@@ -271,7 +273,7 @@ suspend fun <BC : BehaviourContext> BC.onVenue(
subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, CommonMessage<VenueContent>, Update> = MessageFilterByChat, subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, CommonMessage<VenueContent>, Update> = MessageFilterByChat,
markerFactory: MarkerFactory<in CommonMessage<VenueContent>, Any> = ByChatMessageMarkerFactory, markerFactory: MarkerFactory<in CommonMessage<VenueContent>, Any> = ByChatMessageMarkerFactory,
scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, CommonMessage<VenueContent>> scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, CommonMessage<VenueContent>>
) = onContent( ) = onContentMessageWithType(
initialFilter, initialFilter,
subcontextUpdatesFilter, subcontextUpdatesFilter,
markerFactory, markerFactory,
@@ -295,7 +297,7 @@ suspend fun <BC : BehaviourContext> BC.onAudioMediaGroup(
subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, CommonMessage<AudioMediaGroupContent>, Update> = MessageFilterByChat, subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, CommonMessage<AudioMediaGroupContent>, Update> = MessageFilterByChat,
markerFactory: MarkerFactory<in CommonMessage<AudioMediaGroupContent>, Any> = ByChatMessageMarkerFactory, markerFactory: MarkerFactory<in CommonMessage<AudioMediaGroupContent>, Any> = ByChatMessageMarkerFactory,
scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, CommonMessage<AudioMediaGroupContent>> scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, CommonMessage<AudioMediaGroupContent>>
) = onContent( ) = onContentMessageWithType(
initialFilter, initialFilter,
subcontextUpdatesFilter, subcontextUpdatesFilter,
markerFactory, markerFactory,
@@ -319,7 +321,31 @@ suspend fun <BC : BehaviourContext> BC.onDocumentMediaGroupContent(
subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, CommonMessage<DocumentMediaGroupContent>, Update> = MessageFilterByChat, subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, CommonMessage<DocumentMediaGroupContent>, Update> = MessageFilterByChat,
markerFactory: MarkerFactory<in CommonMessage<DocumentMediaGroupContent>, Any> = ByChatMessageMarkerFactory, markerFactory: MarkerFactory<in CommonMessage<DocumentMediaGroupContent>, Any> = ByChatMessageMarkerFactory,
scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, CommonMessage<DocumentMediaGroupContent>> scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, CommonMessage<DocumentMediaGroupContent>>
) = onContent( ) = onContentMessageWithType(
initialFilter,
subcontextUpdatesFilter,
markerFactory,
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>>
) = onContentMessageWithType(
initialFilter, initialFilter,
subcontextUpdatesFilter, subcontextUpdatesFilter,
markerFactory, markerFactory,
@@ -343,7 +369,7 @@ suspend fun <BC : BehaviourContext> BC.onMediaCollection(
subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, CommonMessage<MediaCollectionContent<TelegramMediaFile>>, Update> = MessageFilterByChat, subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, CommonMessage<MediaCollectionContent<TelegramMediaFile>>, Update> = MessageFilterByChat,
markerFactory: MarkerFactory<in CommonMessage<MediaCollectionContent<TelegramMediaFile>>, Any> = ByChatMessageMarkerFactory, markerFactory: MarkerFactory<in CommonMessage<MediaCollectionContent<TelegramMediaFile>>, Any> = ByChatMessageMarkerFactory,
scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, CommonMessage<MediaCollectionContent<TelegramMediaFile>>> scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, CommonMessage<MediaCollectionContent<TelegramMediaFile>>>
) = onContent( ) = onContentMessageWithType(
initialFilter, initialFilter,
subcontextUpdatesFilter, subcontextUpdatesFilter,
markerFactory, markerFactory,
@@ -367,7 +393,7 @@ suspend fun <BC : BehaviourContext> BC.onMedia(
subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, CommonMessage<MediaContent>, Update> = MessageFilterByChat, subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, CommonMessage<MediaContent>, Update> = MessageFilterByChat,
markerFactory: MarkerFactory<in CommonMessage<MediaContent>, Any> = ByChatMessageMarkerFactory, markerFactory: MarkerFactory<in CommonMessage<MediaContent>, Any> = ByChatMessageMarkerFactory,
scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, CommonMessage<MediaContent>> scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, CommonMessage<MediaContent>>
) = onContent( ) = onContentMessageWithType(
initialFilter, initialFilter,
subcontextUpdatesFilter, subcontextUpdatesFilter,
markerFactory, markerFactory,
@@ -391,7 +417,7 @@ suspend fun <BC : BehaviourContext> BC.onAnimation(
subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, CommonMessage<AnimationContent>, Update> = MessageFilterByChat, subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, CommonMessage<AnimationContent>, Update> = MessageFilterByChat,
markerFactory: MarkerFactory<in CommonMessage<AnimationContent>, Any> = ByChatMessageMarkerFactory, markerFactory: MarkerFactory<in CommonMessage<AnimationContent>, Any> = ByChatMessageMarkerFactory,
scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, CommonMessage<AnimationContent>> scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, CommonMessage<AnimationContent>>
) = onContent( ) = onContentMessageWithType(
initialFilter, initialFilter,
subcontextUpdatesFilter, subcontextUpdatesFilter,
markerFactory, markerFactory,
@@ -415,7 +441,7 @@ suspend fun <BC : BehaviourContext> BC.onAudio(
subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, CommonMessage<AudioContent>, Update> = MessageFilterByChat, subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, CommonMessage<AudioContent>, Update> = MessageFilterByChat,
markerFactory: MarkerFactory<in CommonMessage<AudioContent>, Any> = ByChatMessageMarkerFactory, markerFactory: MarkerFactory<in CommonMessage<AudioContent>, Any> = ByChatMessageMarkerFactory,
scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, CommonMessage<AudioContent>> scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, CommonMessage<AudioContent>>
) = onContent( ) = onContentMessageWithType(
initialFilter, initialFilter,
subcontextUpdatesFilter, subcontextUpdatesFilter,
markerFactory, markerFactory,
@@ -439,7 +465,7 @@ suspend fun <BC : BehaviourContext> BC.onDocument(
subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, CommonMessage<DocumentContent>, Update> = MessageFilterByChat, subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, CommonMessage<DocumentContent>, Update> = MessageFilterByChat,
markerFactory: MarkerFactory<in CommonMessage<DocumentContent>, Any> = ByChatMessageMarkerFactory, markerFactory: MarkerFactory<in CommonMessage<DocumentContent>, Any> = ByChatMessageMarkerFactory,
scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, CommonMessage<DocumentContent>> scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, CommonMessage<DocumentContent>>
) = onContent( ) = onContentMessageWithType(
initialFilter, initialFilter,
subcontextUpdatesFilter, subcontextUpdatesFilter,
markerFactory, markerFactory,
@@ -463,7 +489,7 @@ suspend fun <BC : BehaviourContext> BC.onPhoto(
subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, CommonMessage<PhotoContent>, Update> = MessageFilterByChat, subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, CommonMessage<PhotoContent>, Update> = MessageFilterByChat,
markerFactory: MarkerFactory<in CommonMessage<PhotoContent>, Any> = ByChatMessageMarkerFactory, markerFactory: MarkerFactory<in CommonMessage<PhotoContent>, Any> = ByChatMessageMarkerFactory,
scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, CommonMessage<PhotoContent>> scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, CommonMessage<PhotoContent>>
) = onContent( ) = onContentMessageWithType(
initialFilter, initialFilter,
subcontextUpdatesFilter, subcontextUpdatesFilter,
markerFactory, markerFactory,
@@ -487,7 +513,7 @@ suspend fun <BC : BehaviourContext> BC.onSticker(
subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, CommonMessage<StickerContent>, Update> = MessageFilterByChat, subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, CommonMessage<StickerContent>, Update> = MessageFilterByChat,
markerFactory: MarkerFactory<in CommonMessage<StickerContent>, Any> = ByChatMessageMarkerFactory, markerFactory: MarkerFactory<in CommonMessage<StickerContent>, Any> = ByChatMessageMarkerFactory,
scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, CommonMessage<StickerContent>> scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, CommonMessage<StickerContent>>
) = onContent( ) = onContentMessageWithType(
initialFilter, initialFilter,
subcontextUpdatesFilter, subcontextUpdatesFilter,
markerFactory, markerFactory,
@@ -511,7 +537,7 @@ suspend fun <BC : BehaviourContext> BC.onVideo(
subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, CommonMessage<VideoContent>, Update> = MessageFilterByChat, subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, CommonMessage<VideoContent>, Update> = MessageFilterByChat,
markerFactory: MarkerFactory<in CommonMessage<VideoContent>, Any> = ByChatMessageMarkerFactory, markerFactory: MarkerFactory<in CommonMessage<VideoContent>, Any> = ByChatMessageMarkerFactory,
scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, CommonMessage<VideoContent>> scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, CommonMessage<VideoContent>>
) = onContent( ) = onContentMessageWithType(
initialFilter, initialFilter,
subcontextUpdatesFilter, subcontextUpdatesFilter,
markerFactory, markerFactory,
@@ -535,7 +561,7 @@ suspend fun <BC : BehaviourContext> BC.onVideoNote(
subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, CommonMessage<VideoNoteContent>, Update> = MessageFilterByChat, subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, CommonMessage<VideoNoteContent>, Update> = MessageFilterByChat,
markerFactory: MarkerFactory<in CommonMessage<VideoNoteContent>, Any> = ByChatMessageMarkerFactory, markerFactory: MarkerFactory<in CommonMessage<VideoNoteContent>, Any> = ByChatMessageMarkerFactory,
scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, CommonMessage<VideoNoteContent>> scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, CommonMessage<VideoNoteContent>>
) = onContent( ) = onContentMessageWithType(
initialFilter, initialFilter,
subcontextUpdatesFilter, subcontextUpdatesFilter,
markerFactory, markerFactory,
@@ -559,7 +585,7 @@ suspend fun <BC : BehaviourContext> BC.onVoice(
subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, CommonMessage<VoiceContent>, Update> = MessageFilterByChat, subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, CommonMessage<VoiceContent>, Update> = MessageFilterByChat,
markerFactory: MarkerFactory<in CommonMessage<VoiceContent>, Any> = ByChatMessageMarkerFactory, markerFactory: MarkerFactory<in CommonMessage<VoiceContent>, Any> = ByChatMessageMarkerFactory,
scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, CommonMessage<VoiceContent>> scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, CommonMessage<VoiceContent>>
) = onContent( ) = onContentMessageWithType(
initialFilter, initialFilter,
subcontextUpdatesFilter, subcontextUpdatesFilter,
markerFactory, markerFactory,
@@ -583,7 +609,7 @@ suspend fun <BC : BehaviourContext> BC.onInvoice(
subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, CommonMessage<InvoiceContent>, Update> = MessageFilterByChat, subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, CommonMessage<InvoiceContent>, Update> = MessageFilterByChat,
markerFactory: MarkerFactory<in CommonMessage<InvoiceContent>, Any> = ByChatMessageMarkerFactory, markerFactory: MarkerFactory<in CommonMessage<InvoiceContent>, Any> = ByChatMessageMarkerFactory,
scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, CommonMessage<InvoiceContent>> scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, CommonMessage<InvoiceContent>>
) = onContent( ) = onContentMessageWithType(
initialFilter, initialFilter,
subcontextUpdatesFilter, subcontextUpdatesFilter,
markerFactory, markerFactory,

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

@@ -12,6 +12,7 @@ import dev.inmo.tgbotapi.extensions.utils.asChatEventMessage
import dev.inmo.tgbotapi.types.message.ChatEvents.* import dev.inmo.tgbotapi.types.message.ChatEvents.*
import dev.inmo.tgbotapi.types.message.ChatEvents.abstracts.* import dev.inmo.tgbotapi.types.message.ChatEvents.abstracts.*
import dev.inmo.tgbotapi.types.message.ChatEvents.voice.* import dev.inmo.tgbotapi.types.message.ChatEvents.voice.*
import dev.inmo.tgbotapi.types.message.PrivateEventMessage
import dev.inmo.tgbotapi.types.message.abstracts.ChatEventMessage import dev.inmo.tgbotapi.types.message.abstracts.ChatEventMessage
import dev.inmo.tgbotapi.types.message.payments.SuccessfulPaymentEvent import dev.inmo.tgbotapi.types.message.payments.SuccessfulPaymentEvent
import dev.inmo.tgbotapi.types.update.abstracts.Update import dev.inmo.tgbotapi.types.update.abstracts.Update
@@ -94,11 +95,12 @@ suspend fun <BC : BehaviourContext> BC.onChatEvent(
* @param scenarioReceiver Main callback which will be used to handle incoming data if [initialFilter] will pass that * @param scenarioReceiver Main callback which will be used to handle incoming data if [initialFilter] will pass that
* data * data
*/ */
@Deprecated("Renamed as Video instead of Voice")
suspend fun <BC : BehaviourContext> BC.onVoiceChatEvent( suspend fun <BC : BehaviourContext> BC.onVoiceChatEvent(
initialFilter: SimpleFilter<ChatEventMessage<VoiceChatEvent>>? = null, initialFilter: SimpleFilter<ChatEventMessage<VideoChatEvent>>? = null,
subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, ChatEventMessage<VoiceChatEvent>, Update>? = MessageFilterByChat, subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, ChatEventMessage<VideoChatEvent>, Update>? = MessageFilterByChat,
markerFactory: MarkerFactory<in ChatEventMessage<VoiceChatEvent>, Any> = ByChatMessageMarkerFactory, markerFactory: MarkerFactory<in ChatEventMessage<VideoChatEvent>, Any> = ByChatMessageMarkerFactory,
scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, ChatEventMessage<VoiceChatEvent>> scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, ChatEventMessage<VideoChatEvent>>
) = onEvent(initialFilter, subcontextUpdatesFilter, markerFactory, scenarioReceiver) ) = onEvent(initialFilter, subcontextUpdatesFilter, markerFactory, scenarioReceiver)
/** /**
@@ -113,11 +115,12 @@ suspend fun <BC : BehaviourContext> BC.onVoiceChatEvent(
* @param scenarioReceiver Main callback which will be used to handle incoming data if [initialFilter] will pass that * @param scenarioReceiver Main callback which will be used to handle incoming data if [initialFilter] will pass that
* data * data
*/ */
@Deprecated("Renamed as Video instead of Voice")
suspend fun <BC : BehaviourContext> BC.onVoiceChatStartedEvent( suspend fun <BC : BehaviourContext> BC.onVoiceChatStartedEvent(
initialFilter: SimpleFilter<ChatEventMessage<VoiceChatStarted>>? = null, initialFilter: SimpleFilter<ChatEventMessage<VideoChatStarted>>? = null,
subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, ChatEventMessage<VoiceChatStarted>, Update>? = MessageFilterByChat, subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, ChatEventMessage<VideoChatStarted>, Update>? = MessageFilterByChat,
markerFactory: MarkerFactory<in ChatEventMessage<VoiceChatStarted>, Any> = ByChatMessageMarkerFactory, markerFactory: MarkerFactory<in ChatEventMessage<VideoChatStarted>, Any> = ByChatMessageMarkerFactory,
scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, ChatEventMessage<VoiceChatStarted>> scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, ChatEventMessage<VideoChatStarted>>
) = onEvent(initialFilter, subcontextUpdatesFilter, markerFactory, scenarioReceiver) ) = onEvent(initialFilter, subcontextUpdatesFilter, markerFactory, scenarioReceiver)
/** /**
@@ -132,11 +135,12 @@ suspend fun <BC : BehaviourContext> BC.onVoiceChatStartedEvent(
* @param scenarioReceiver Main callback which will be used to handle incoming data if [initialFilter] will pass that * @param scenarioReceiver Main callback which will be used to handle incoming data if [initialFilter] will pass that
* data * data
*/ */
@Deprecated("Renamed as Video instead of Voice")
suspend fun <BC : BehaviourContext> BC.onVoiceChatEndedEvent( suspend fun <BC : BehaviourContext> BC.onVoiceChatEndedEvent(
initialFilter: SimpleFilter<ChatEventMessage<VoiceChatEnded>>? = null, initialFilter: SimpleFilter<ChatEventMessage<VideoChatEnded>>? = null,
subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, ChatEventMessage<VoiceChatEnded>, Update>? = MessageFilterByChat, subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, ChatEventMessage<VideoChatEnded>, Update>? = MessageFilterByChat,
markerFactory: MarkerFactory<in ChatEventMessage<VoiceChatEnded>, Any> = ByChatMessageMarkerFactory, markerFactory: MarkerFactory<in ChatEventMessage<VideoChatEnded>, Any> = ByChatMessageMarkerFactory,
scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, ChatEventMessage<VoiceChatEnded>> scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, ChatEventMessage<VideoChatEnded>>
) = onEvent(initialFilter, subcontextUpdatesFilter, markerFactory, scenarioReceiver) ) = onEvent(initialFilter, subcontextUpdatesFilter, markerFactory, scenarioReceiver)
/** /**
@@ -151,11 +155,88 @@ suspend fun <BC : BehaviourContext> BC.onVoiceChatEndedEvent(
* @param scenarioReceiver Main callback which will be used to handle incoming data if [initialFilter] will pass that * @param scenarioReceiver Main callback which will be used to handle incoming data if [initialFilter] will pass that
* data * data
*/ */
@Deprecated("Renamed as Video instead of Voice")
suspend fun <BC : BehaviourContext> BC.onVoiceChatParticipantsInvitedEvent( suspend fun <BC : BehaviourContext> BC.onVoiceChatParticipantsInvitedEvent(
initialFilter: SimpleFilter<ChatEventMessage<VoiceChatParticipantsInvited>>? = null, initialFilter: SimpleFilter<ChatEventMessage<VideoChatParticipantsInvited>>? = null,
subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, ChatEventMessage<VoiceChatParticipantsInvited>, Update>? = MessageFilterByChat, subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, ChatEventMessage<VideoChatParticipantsInvited>, Update>? = MessageFilterByChat,
markerFactory: MarkerFactory<in ChatEventMessage<VoiceChatParticipantsInvited>, Any> = ByChatMessageMarkerFactory, markerFactory: MarkerFactory<in ChatEventMessage<VideoChatParticipantsInvited>, Any> = ByChatMessageMarkerFactory,
scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, ChatEventMessage<VoiceChatParticipantsInvited>> scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, ChatEventMessage<VideoChatParticipantsInvited>>
) = onEvent(initialFilter, subcontextUpdatesFilter, markerFactory, 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.onVideoChatEvent(
initialFilter: SimpleFilter<ChatEventMessage<VideoChatEvent>>? = null,
subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, ChatEventMessage<VideoChatEvent>, Update>? = MessageFilterByChat,
markerFactory: MarkerFactory<in ChatEventMessage<VideoChatEvent>, Any> = ByChatMessageMarkerFactory,
scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, ChatEventMessage<VideoChatEvent>>
) = onEvent(initialFilter, subcontextUpdatesFilter, markerFactory, 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.onVideoChatStartedEvent(
initialFilter: SimpleFilter<ChatEventMessage<VideoChatStarted>>? = null,
subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, ChatEventMessage<VideoChatStarted>, Update>? = MessageFilterByChat,
markerFactory: MarkerFactory<in ChatEventMessage<VideoChatStarted>, Any> = ByChatMessageMarkerFactory,
scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, ChatEventMessage<VideoChatStarted>>
) = onEvent(initialFilter, subcontextUpdatesFilter, markerFactory, 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.onVideoChatEndedEvent(
initialFilter: SimpleFilter<ChatEventMessage<VideoChatEnded>>? = null,
subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, ChatEventMessage<VideoChatEnded>, Update>? = MessageFilterByChat,
markerFactory: MarkerFactory<in ChatEventMessage<VideoChatEnded>, Any> = ByChatMessageMarkerFactory,
scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, ChatEventMessage<VideoChatEnded>>
) = onEvent(initialFilter, subcontextUpdatesFilter, markerFactory, 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.onVideoChatParticipantsInvitedEvent(
initialFilter: SimpleFilter<ChatEventMessage<VideoChatParticipantsInvited>>? = null,
subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, ChatEventMessage<VideoChatParticipantsInvited>, Update>? = MessageFilterByChat,
markerFactory: MarkerFactory<in ChatEventMessage<VideoChatParticipantsInvited>, Any> = ByChatMessageMarkerFactory,
scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, ChatEventMessage<VideoChatParticipantsInvited>>
) = onEvent(initialFilter, subcontextUpdatesFilter, markerFactory, scenarioReceiver) ) = onEvent(initialFilter, subcontextUpdatesFilter, markerFactory, scenarioReceiver)
/** /**
@@ -483,3 +564,30 @@ suspend fun <BC : BehaviourContext> BC.onUserLoggedIn(
markerFactory: MarkerFactory<in ChatEventMessage<UserLoggedIn>, Any> = ByChatMessageMarkerFactory, markerFactory: MarkerFactory<in ChatEventMessage<UserLoggedIn>, Any> = ByChatMessageMarkerFactory,
scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, ChatEventMessage<UserLoggedIn>> scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, ChatEventMessage<UserLoggedIn>>
) = onEvent(initialFilter, subcontextUpdatesFilter, markerFactory, scenarioReceiver) ) = onEvent(initialFilter, subcontextUpdatesFilter, markerFactory, 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.onWebAppData(
initialFilter: SimpleFilter<PrivateEventMessage<WebAppData>>? = null,
subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, PrivateEventMessage<WebAppData>, Update>? = MessageFilterByChat,
markerFactory: MarkerFactory<in ChatEventMessage<WebAppData>, Any> = ByChatMessageMarkerFactory,
scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, PrivateEventMessage<WebAppData>>
) = onEvent(
initialFilter ?.let { { it is PrivateEventMessage<WebAppData> && initialFilter(it) } },
subcontextUpdatesFilter ?.let { { it: ChatEventMessage<WebAppData>, update: Update -> it is PrivateEventMessage<WebAppData> && subcontextUpdatesFilter(it, update) } },
markerFactory
) {
if (it is PrivateEventMessage<WebAppData>) {
scenarioReceiver(it)
}
}

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

@@ -28,16 +28,20 @@ fun <T> SimpleFilter<T>.listNone() = SimpleFilter<Iterable<T>> {
/** /**
* Makes an AND (&&) operation between [this] and [other] * Makes an AND (&&) operation between [this] and [other]
*/ */
operator fun <T> SimpleFilter<T>.times(other: SimpleFilter<T>): SimpleFilter<T> = { operator fun <T> SimpleFilter<T>?.times(other: SimpleFilter<T>): SimpleFilter<T> = this ?.let {
this(it) && other(it) {
} this(it) && other(it)
}
} ?: other
/** /**
* Makes an OR (||) operation between [this] and [other] * Makes an OR (||) operation between [this] and [other]
*/ */
operator fun <T> SimpleFilter<T>.plus(other: SimpleFilter<T>): SimpleFilter<T> = { operator fun <T> SimpleFilter<T>?.plus(other: SimpleFilter<T>): SimpleFilter<T> = this ?.let {
this(it) || other(it) {
} this(it) || other(it)
}
} ?: other
/** /**
* Reverse results of [this] * Reverse results of [this]

View File

@@ -2,6 +2,6 @@ package dev.inmo.tgbotapi.CommonAbstracts.types
import dev.inmo.tgbotapi.types.ChatIdentifier import dev.inmo.tgbotapi.types.ChatIdentifier
interface ChatRequest { interface ChatRequest : OptionalChatRequest {
val chatId: ChatIdentifier override val chatId: ChatIdentifier
} }

View File

@@ -0,0 +1,7 @@
package dev.inmo.tgbotapi.CommonAbstracts.types
import dev.inmo.tgbotapi.types.ChatIdentifier
interface OptionalChatRequest {
val chatId: ChatIdentifier?
}

View File

@@ -1,5 +1,6 @@
package dev.inmo.tgbotapi.bot.Ktor package dev.inmo.tgbotapi.bot.Ktor
import dev.inmo.micro_utils.common.Optional
import dev.inmo.tgbotapi.requests.abstracts.Request import dev.inmo.tgbotapi.requests.abstracts.Request
import dev.inmo.tgbotapi.utils.TelegramAPIUrlsKeeper import dev.inmo.tgbotapi.utils.TelegramAPIUrlsKeeper
import io.ktor.client.HttpClient import io.ktor.client.HttpClient

View File

@@ -5,6 +5,7 @@ import dev.inmo.tgbotapi.bot.BaseRequestsExecutor
import dev.inmo.tgbotapi.bot.Ktor.base.* import dev.inmo.tgbotapi.bot.Ktor.base.*
import dev.inmo.tgbotapi.bot.TelegramBot import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.bot.exceptions.newRequestException import dev.inmo.tgbotapi.bot.exceptions.newRequestException
import dev.inmo.tgbotapi.bot.ktor.KtorPipelineStepsHolder
import dev.inmo.tgbotapi.bot.settings.limiters.ExceptionsOnlyLimiter import dev.inmo.tgbotapi.bot.settings.limiters.ExceptionsOnlyLimiter
import dev.inmo.tgbotapi.bot.settings.limiters.RequestLimiter import dev.inmo.tgbotapi.bot.settings.limiters.RequestLimiter
import dev.inmo.tgbotapi.requests.abstracts.Request import dev.inmo.tgbotapi.requests.abstracts.Request
@@ -15,33 +16,6 @@ import io.ktor.client.features.*
import io.ktor.client.statement.readText import io.ktor.client.statement.readText
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
class KtorRequestsExecutorBuilder(
var telegramAPIUrlsKeeper: TelegramAPIUrlsKeeper
) {
var client: HttpClient = HttpClient()
var callsFactories: List<KtorCallFactory> = emptyList()
var excludeDefaultFactories: Boolean = false
var requestsLimiter: RequestLimiter = ExceptionsOnlyLimiter()
var jsonFormatter: Json = nonstrictJsonFormat
fun build() = KtorRequestsExecutor(telegramAPIUrlsKeeper, client, callsFactories, excludeDefaultFactories, requestsLimiter, jsonFormatter)
}
inline fun telegramBot(
telegramAPIUrlsKeeper: TelegramAPIUrlsKeeper,
crossinline builder: KtorRequestsExecutorBuilder.() -> Unit = {}
): TelegramBot = KtorRequestsExecutorBuilder(telegramAPIUrlsKeeper).apply(builder).build()
/**
* Shortcut for [telegramBot]
*/
@Suppress("NOTHING_TO_INLINE")
inline fun telegramBot(
token: String,
apiUrl: String = telegramBotAPIDefaultUrl,
crossinline builder: KtorRequestsExecutorBuilder.() -> Unit = {}
): TelegramBot = telegramBot(TelegramAPIUrlsKeeper(token, apiUrl), builder)
@RiskFeature @RiskFeature
fun createTelegramBotDefaultKtorCallRequestsFactories() = listOf( fun createTelegramBotDefaultKtorCallRequestsFactories() = listOf(
SimpleRequestCallFactory(), SimpleRequestCallFactory(),
@@ -56,7 +30,8 @@ class KtorRequestsExecutor(
callsFactories: List<KtorCallFactory> = emptyList(), callsFactories: List<KtorCallFactory> = emptyList(),
excludeDefaultFactories: Boolean = false, excludeDefaultFactories: Boolean = false,
private val requestsLimiter: RequestLimiter = ExceptionsOnlyLimiter(), private val requestsLimiter: RequestLimiter = ExceptionsOnlyLimiter(),
private val jsonFormatter: Json = nonstrictJsonFormat private val jsonFormatter: Json = nonstrictJsonFormat,
private val pipelineStepsHolder: KtorPipelineStepsHolder = KtorPipelineStepsHolder
) : BaseRequestsExecutor(telegramAPIUrlsKeeper) { ) : BaseRequestsExecutor(telegramAPIUrlsKeeper) {
private val callsFactories: List<KtorCallFactory> = callsFactories.run { private val callsFactories: List<KtorCallFactory> = callsFactories.run {
if (!excludeDefaultFactories) { if (!excludeDefaultFactories) {
@@ -73,37 +48,51 @@ class KtorRequestsExecutor(
} }
override suspend fun <T : Any> execute(request: Request<T>): T { override suspend fun <T : Any> execute(request: Request<T>): T {
return safely( return runCatching {
{ e -> safely(
throw if (e is ClientRequestException) { { e ->
val content = e.response.readText() pipelineStepsHolder.onRequestException(request, e) ?.let { return@safely it }
val responseObject = jsonFormatter.decodeFromString(Response.serializer(), content)
newRequestException(
responseObject,
content,
"Can't get result object from $content"
)
} else {
e
}
}
) {
requestsLimiter.limit {
var result: T? = null
for (potentialFactory in callsFactories) {
result = potentialFactory.makeCall(
client,
telegramAPIUrlsKeeper,
request,
jsonFormatter
)
if (result != null) {
break
}
}
result ?: error("Can't execute request: $request") throw if (e is ClientRequestException) {
val content = e.response.readText()
val responseObject = jsonFormatter.decodeFromString(Response.serializer(), content)
newRequestException(
responseObject,
content,
"Can't get result object from $content"
)
} else {
e
}
}
) {
pipelineStepsHolder.onBeforeSearchCallFactory(request, callsFactories)
requestsLimiter.limit {
var result: T? = null
lateinit var factoryHandledRequest: KtorCallFactory
for (potentialFactory in callsFactories) {
pipelineStepsHolder.onBeforeCallFactoryMakeCall(request, potentialFactory)
result = potentialFactory.makeCall(
client,
telegramAPIUrlsKeeper,
request,
jsonFormatter
)
result = pipelineStepsHolder.onAfterCallFactoryMakeCall(result, request, potentialFactory)
if (result != null) {
factoryHandledRequest = potentialFactory
break
}
}
result ?.let {
pipelineStepsHolder.onRequestResultPresented(it, request, factoryHandledRequest, callsFactories)
} ?: pipelineStepsHolder.onRequestResultAbsent(request, callsFactories) ?: error("Can't execute request: $request")
}
} }
}.let {
pipelineStepsHolder.onRequestReturnResult(it, request, callsFactories)
} }
} }
@@ -111,3 +100,30 @@ class KtorRequestsExecutor(
client.close() client.close()
} }
} }
class KtorRequestsExecutorBuilder(
var telegramAPIUrlsKeeper: TelegramAPIUrlsKeeper
) {
var client: HttpClient = HttpClient()
var callsFactories: List<KtorCallFactory> = emptyList()
var excludeDefaultFactories: Boolean = false
var requestsLimiter: RequestLimiter = ExceptionsOnlyLimiter()
var jsonFormatter: Json = nonstrictJsonFormat
fun build() = KtorRequestsExecutor(telegramAPIUrlsKeeper, client, callsFactories, excludeDefaultFactories, requestsLimiter, jsonFormatter)
}
inline fun telegramBot(
telegramAPIUrlsKeeper: TelegramAPIUrlsKeeper,
builder: KtorRequestsExecutorBuilder.() -> Unit = {}
): TelegramBot = KtorRequestsExecutorBuilder(telegramAPIUrlsKeeper).apply(builder).build()
/**
* Shortcut for [telegramBot]
*/
@Suppress("NOTHING_TO_INLINE")
inline fun telegramBot(
token: String,
apiUrl: String = telegramBotAPIDefaultUrl,
builder: KtorRequestsExecutorBuilder.() -> Unit = {}
): TelegramBot = telegramBot(TelegramAPIUrlsKeeper(token, apiUrl), builder)

View File

@@ -1,6 +1,6 @@
package dev.inmo.tgbotapi.bot.Ktor.base package dev.inmo.tgbotapi.bot.Ktor.base
import dev.inmo.micro_utils.coroutines.launchSafelyWithoutExceptions import dev.inmo.micro_utils.coroutines.*
import dev.inmo.tgbotapi.bot.Ktor.KtorCallFactory import dev.inmo.tgbotapi.bot.Ktor.KtorCallFactory
import dev.inmo.tgbotapi.requests.DownloadFileStream import dev.inmo.tgbotapi.requests.DownloadFileStream
import dev.inmo.tgbotapi.requests.abstracts.Request import dev.inmo.tgbotapi.requests.abstracts.Request
@@ -25,13 +25,16 @@ object DownloadFileChannelRequestCallFactory : KtorCallFactory {
val fullUrl = urlsKeeper.createFileLinkUrl(it.filePath) val fullUrl = urlsKeeper.createFileLinkUrl(it.filePath)
ByteReadChannelAllocator { ByteReadChannelAllocator {
val scope = CoroutineScope(coroutineContext) val scope = CoroutineScope(currentCoroutineContext() + SupervisorJob())
val outChannel = ByteChannel() val outChannel = ByteChannel()
scope.launchSafelyWithoutExceptions { scope.launch {
client.get<HttpStatement>(fullUrl).execute { httpResponse -> runCatchingSafely {
val channel: ByteReadChannel = httpResponse.receive() client.get<HttpStatement>(fullUrl).execute { httpResponse ->
channel.copyAndClose(outChannel) val channel: ByteReadChannel = httpResponse.receive()
channel.copyAndClose(outChannel)
}
} }
scope.cancel()
} }
outChannel outChannel
} as T } as T

View File

@@ -0,0 +1,75 @@
package dev.inmo.tgbotapi.bot.ktor
import dev.inmo.tgbotapi.bot.Ktor.KtorCallFactory
import dev.inmo.tgbotapi.requests.abstracts.Request
interface KtorPipelineStepsHolder {
/**
* Will be called when any exception will happen due to the [request] handling. If returns value - that value
* will be returned from [dev.inmo.tgbotapi.bot.RequestsExecutor.execute] instead
*/
suspend fun <T: Any> onRequestException(
request: Request<T>,
t: Throwable
): T? = null
/**
* Will always be called before requests executor will check all [callsFactories] for an opportunity to make call of
* [request]
*/
suspend fun onBeforeSearchCallFactory(
request: Request<*>,
callsFactories: List<KtorCallFactory>
) {}
/**
* Will always be called before [potentialFactory] will try to make [request]
*/
suspend fun onBeforeCallFactoryMakeCall(
request: Request<*>,
potentialFactory: KtorCallFactory
) {}
/**
* Will always be called after [potentialFactory] has tried to make [request] and got some [result]. If returns
* value - that value will be returned from [dev.inmo.tgbotapi.bot.RequestsExecutor.execute] instead
*/
suspend fun <T: Any> onAfterCallFactoryMakeCall(
result: T?,
request: Request<T>,
potentialFactory: KtorCallFactory
): T? = result
/**
* Will be called when [resultCallFactory] is the [KtorCallFactory] from [callsFactories] which has successfully
* handled [request] and returned [result]. If returns value - that value will be returned from
* [dev.inmo.tgbotapi.bot.RequestsExecutor.execute] instead
*/
suspend fun <T: Any> onRequestResultPresented(
result: T,
request: Request<T>,
resultCallFactory: KtorCallFactory,
callsFactories: List<KtorCallFactory>
): T? = result
/**
* Will be called when there is no [KtorCallFactory] from [callsFactories] which may handle [request]. If returns
* value - that value will be returned from [dev.inmo.tgbotapi.bot.RequestsExecutor.execute] instead
*/
suspend fun <T: Any> onRequestResultAbsent(
request: Request<T>,
callsFactories: List<KtorCallFactory>
): T? = null
/**
* This step will be called when the [result] has been retrieved (or exception has happened). If returns value -
* that value will be returned from [dev.inmo.tgbotapi.bot.RequestsExecutor.execute] instead
*/
suspend fun <T: Any> onRequestReturnResult(
result: Result<T>,
request: Request<T>,
callsFactories: List<KtorCallFactory>
): T = result.getOrThrow()
companion object : KtorPipelineStepsHolder
}

View File

@@ -61,9 +61,9 @@ object InputFileSerializer : KSerializer<InputFile> {
@Serializable(InputFileSerializer::class) @Serializable(InputFileSerializer::class)
data class MultipartFile ( data class MultipartFile (
val file: StorageFile, val file: StorageFile,
val filename: String = file.storageFileInfo.fileName val filename: String = file.fileName
) : InputFile() { ) : InputFile() {
override val fileId: String = file.storageFileInfo.generateCustomName() override val fileId: String = file.generateCustomName()
} }
@Suppress("NOTHING_TO_INLINE", "unused") @Suppress("NOTHING_TO_INLINE", "unused")

View File

@@ -0,0 +1,21 @@
package dev.inmo.tgbotapi.requests.answers
import dev.inmo.tgbotapi.requests.abstracts.SimpleRequest
import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult.abstracts.InlineQueryResult
import dev.inmo.tgbotapi.types.webapps.query.SentWebAppMessage
import kotlinx.serialization.*
@Serializable
data class AnswerWebAppQuery(
@SerialName(webAppQueryIdField)
val webAppQueryId: WebAppQueryId,
@SerialName(resultField)
val result: InlineQueryResult
) : SimpleRequest<SentWebAppMessage> {
override fun method(): String = "answerWebAppQuery"
override val resultDeserializer: DeserializationStrategy<SentWebAppMessage>
get() = SentWebAppMessage.serializer()
override val requestSerializer: SerializationStrategy<*>
get() = serializer()
}

View File

@@ -0,0 +1,18 @@
package dev.inmo.tgbotapi.requests.bot
import dev.inmo.tgbotapi.requests.abstracts.SimpleRequest
import dev.inmo.tgbotapi.types.*
import kotlinx.serialization.*
import kotlinx.serialization.builtins.serializer
@Serializable
class ClearMyDefaultAdministratorRights(
@SerialName(forChannelsField)
val forChannels: Boolean? = null
) : SimpleRequest<Boolean> {
override fun method(): String = "setMyDefaultAdministratorRights"
override val resultDeserializer: DeserializationStrategy<Boolean>
get() = Boolean.serializer()
override val requestSerializer: SerializationStrategy<*>
get() = serializer()
}

View File

@@ -0,0 +1,23 @@
package dev.inmo.tgbotapi.requests.bot
import dev.inmo.tgbotapi.requests.abstracts.SimpleRequest
import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.ChatMember.AdministratorChatMemberImpl
import kotlinx.serialization.*
@Serializable
data class GetMyDefaultAdministratorRights(
@SerialName(forChannelsField)
val forChannels: Boolean? = null
) : SimpleRequest<AdministratorChatMemberImpl> {
override fun method(): String = "getMyDefaultAdministratorRights"
override val resultDeserializer: DeserializationStrategy<AdministratorChatMemberImpl>
get() = AdministratorChatMemberImpl.serializer()
override val requestSerializer: SerializationStrategy<*>
get() = serializer()
companion object {
val ForChannels = GetMyDefaultAdministratorRights(true)
val ForGroups = GetMyDefaultAdministratorRights(false)
}
}

View File

@@ -0,0 +1,20 @@
package dev.inmo.tgbotapi.requests.bot
import dev.inmo.tgbotapi.requests.abstracts.SimpleRequest
import dev.inmo.tgbotapi.types.*
import kotlinx.serialization.*
import kotlinx.serialization.builtins.serializer
@Serializable
class SetMyDefaultAdministratorRights(
@SerialName(rightsField)
val rights: ChatAdministratorRightsImpl,
@SerialName(forChannelsField)
val forChannels: Boolean? = null
) : SimpleRequest<Boolean> {
override fun method(): String = "setMyDefaultAdministratorRights"
override val resultDeserializer: DeserializationStrategy<Boolean>
get() = Boolean.serializer()
override val requestSerializer: SerializationStrategy<*>
get() = serializer()
}

View File

@@ -0,0 +1,21 @@
package dev.inmo.tgbotapi.requests.chat.get
import dev.inmo.tgbotapi.CommonAbstracts.types.ChatRequest
import dev.inmo.tgbotapi.requests.abstracts.SimpleRequest
import dev.inmo.tgbotapi.types.*
import kotlinx.serialization.*
import kotlinx.serialization.builtins.serializer
@Serializable
data class GetChatMenuButton(
@SerialName(chatIdField)
override val chatId: ChatIdentifier
) : ChatRequest, SimpleRequest<MenuButton> {
override val requestSerializer: SerializationStrategy<*>
get() = serializer()
override fun method(): String = GetDefaultChatMenuButton.method()
override val resultDeserializer: DeserializationStrategy<MenuButton>
get() = MenuButtonSerializer
}

View File

@@ -0,0 +1,21 @@
package dev.inmo.tgbotapi.requests.chat.get
import dev.inmo.tgbotapi.CommonAbstracts.types.ChatRequest
import dev.inmo.tgbotapi.CommonAbstracts.types.OptionalChatRequest
import dev.inmo.tgbotapi.requests.abstracts.SimpleRequest
import dev.inmo.tgbotapi.types.*
import kotlinx.serialization.*
import kotlinx.serialization.builtins.serializer
@Serializable
object GetDefaultChatMenuButton : OptionalChatRequest, SimpleRequest<MenuButton> {
override val chatId: ChatIdentifier?
get() = null
override val requestSerializer: SerializationStrategy<*>
get() = serializer()
override fun method(): String = "getChatMenuButton"
override val resultDeserializer: DeserializationStrategy<MenuButton>
get() = MenuButtonSerializer
}

View File

@@ -32,8 +32,8 @@ data class PromoteChatMember(
private val canPinMessages: Boolean? = null, private val canPinMessages: Boolean? = null,
@SerialName(canPromoteMembersField) @SerialName(canPromoteMembersField)
private val canPromoteMembers: Boolean? = null, private val canPromoteMembers: Boolean? = null,
@SerialName(canManageVoiceChatsField) @SerialName(canManageVideoChatsField)
private val canManageVoiceChats: Boolean? = null, private val canManageVideoChats: Boolean? = null,
@SerialName(canManageChatField) @SerialName(canManageChatField)
private val canManageChat: Boolean? = null private val canManageChat: Boolean? = null
) : ChatMemberRequest<Boolean>, UntilDate { ) : ChatMemberRequest<Boolean>, UntilDate {

View File

@@ -0,0 +1,24 @@
package dev.inmo.tgbotapi.requests.chat.modify
import dev.inmo.tgbotapi.CommonAbstracts.types.ChatRequest
import dev.inmo.tgbotapi.requests.abstracts.SimpleRequest
import dev.inmo.tgbotapi.types.*
import kotlinx.serialization.*
import kotlinx.serialization.builtins.serializer
@Serializable
data class SetChatMenuButton(
@SerialName(chatIdField)
override val chatId: ChatIdentifier,
@Serializable(MenuButtonSerializer::class)
@SerialName(menuButtonField)
val menuButton: MenuButton
) : ChatRequest, SimpleRequest<Boolean> {
override val requestSerializer: SerializationStrategy<*>
get() = serializer()
override fun method(): String = SetDefaultChatMenuButton.method()
override val resultDeserializer: DeserializationStrategy<Boolean>
get() = Boolean.serializer()
}

View File

@@ -0,0 +1,25 @@
package dev.inmo.tgbotapi.requests.chat.modify
import dev.inmo.tgbotapi.requests.abstracts.SimpleRequest
import dev.inmo.tgbotapi.types.*
import kotlinx.serialization.*
import kotlinx.serialization.builtins.serializer
@Serializable
data class SetDefaultChatMenuButton(
@Serializable(MenuButtonSerializer::class)
@SerialName(menuButtonField)
val menuButton: MenuButton
) : SimpleRequest<Boolean> {
override val requestSerializer: SerializationStrategy<*>
get() = serializer()
override fun method(): String = Companion.method()
override val resultDeserializer: DeserializationStrategy<Boolean>
get() = Boolean.serializer()
companion object {
fun method() = "setChatMenuButton"
}
}

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

@@ -0,0 +1,31 @@
package dev.inmo.tgbotapi.types
import dev.inmo.tgbotapi.types.ChatMember.abstracts.ChatAdministratorRights
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@Serializable
data class ChatAdministratorRightsImpl(
@SerialName(canChangeInfoField)
override val canChangeInfo: Boolean = false,
@SerialName(canPostMessagesField)
override val canPostMessages: Boolean = false,
@SerialName(canEditMessagesField)
override val canEditMessages: Boolean = false,
@SerialName(canDeleteMessagesField)
override val canRemoveMessages: Boolean = false,
@SerialName(canInviteUsersField)
override val canInviteUsers: Boolean = false,
@SerialName(canRestrictMembersField)
override val canRestrictMembers: Boolean = false,
@SerialName(canPinMessagesField)
override val canPinMessages: Boolean = false,
@SerialName(canPromoteMembersField)
override val canPromoteMembers: Boolean = false,
@SerialName(canManageVideoChatsField)
override val canManageVideoChats: Boolean = false,
@SerialName(canManageChatField)
override val canManageChat: Boolean = false,
@SerialName(isAnonymousField)
override val isAnonymous: Boolean = false
) : ChatAdministratorRights

View File

@@ -26,8 +26,8 @@ data class AdministratorChatMemberImpl(
override val canPinMessages: Boolean = false, override val canPinMessages: Boolean = false,
@SerialName(canPromoteMembersField) @SerialName(canPromoteMembersField)
override val canPromoteMembers: Boolean = false, override val canPromoteMembers: Boolean = false,
@SerialName(canManageVoiceChatsField) @SerialName(canManageVideoChatsField)
override val canManageVoiceChats: Boolean = false, override val canManageVideoChats: Boolean = false,
@SerialName(canManageChatField) @SerialName(canManageChatField)
override val canManageChat: Boolean = false, override val canManageChat: Boolean = false,
@SerialName(isAnonymousField) @SerialName(isAnonymousField)

View File

@@ -31,7 +31,7 @@ data class CreatorChatMember(
@Transient @Transient
override val canPromoteMembers: Boolean = true override val canPromoteMembers: Boolean = true
@Transient @Transient
override val canManageVoiceChats: Boolean = true override val canManageVideoChats: Boolean = true
@Transient @Transient
override val canManageChat: Boolean = true override val canManageChat: Boolean = true
@SerialName(statusField) @SerialName(statusField)

View File

@@ -8,17 +8,12 @@ import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder import kotlinx.serialization.encoding.Encoder
@Serializable(AdministratorChatMemberSerializer::class) @Serializable(AdministratorChatMemberSerializer::class)
interface AdministratorChatMember : SpecialRightsChatMember { interface AdministratorChatMember : SpecialRightsChatMember, ChatAdministratorRights {
val canBeEdited: Boolean val canBeEdited: Boolean
val canPostMessages: Boolean
val canEditMessages: Boolean
val canRemoveMessages: Boolean
val canRestrictMembers: Boolean
val canPromoteMembers: Boolean
val canManageVoiceChats: Boolean
val canManageChat: Boolean
val isAnonymous: Boolean
val customTitle: String? val customTitle: String?
val canManageVoiceChats: Boolean
get() = canManageVideoChats
} }
@RiskFeature @RiskFeature

View File

@@ -0,0 +1,18 @@
package dev.inmo.tgbotapi.types.ChatMember.abstracts
sealed interface SpecialChatAdministratorRights {
val canChangeInfo: Boolean
val canInviteUsers: Boolean
val canPinMessages: Boolean
}
interface ChatAdministratorRights : SpecialChatAdministratorRights {
val isAnonymous: Boolean
val canManageChat: Boolean
val canRemoveMessages: Boolean
val canManageVideoChats: Boolean
val canRestrictMembers: Boolean
val canPromoteMembers: Boolean
val canPostMessages: Boolean
val canEditMessages: Boolean
}

View File

@@ -3,8 +3,4 @@ package dev.inmo.tgbotapi.types.ChatMember.abstracts
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@Serializable(ChatMemberSerializer::class) @Serializable(ChatMemberSerializer::class)
interface SpecialRightsChatMember : ChatMember { interface SpecialRightsChatMember : ChatMember, SpecialChatAdministratorRights
val canChangeInfo: Boolean
val canInviteUsers: Boolean
val canPinMessages: Boolean
}

View File

@@ -27,6 +27,7 @@ typealias FoursquareType = String
typealias GooglePlaceId = String typealias GooglePlaceId = String
typealias GooglePlaceType = String typealias GooglePlaceType = String
typealias MembersLimit = Int typealias MembersLimit = Int
typealias WebAppQueryId = String
typealias Seconds = Int typealias Seconds = Int
typealias MilliSeconds = Long typealias MilliSeconds = Long
@@ -133,6 +134,7 @@ const val inlineMessageIdField = "inline_message_id"
const val callbackDataField = "callback_data" const val callbackDataField = "callback_data"
const val callbackGameField = "callback_game" const val callbackGameField = "callback_game"
const val callbackQueryIdField = "callback_query_id" const val callbackQueryIdField = "callback_query_id"
const val webAppQueryIdField = "web_app_query_id"
const val inlineQueryIdField = "inline_query_id" const val inlineQueryIdField = "inline_query_id"
const val inlineKeyboardField = "inline_keyboard" const val inlineKeyboardField = "inline_keyboard"
const val showAlertField = "show_alert" const val showAlertField = "show_alert"
@@ -154,6 +156,7 @@ const val dropPendingUpdatesField = "drop_pending_updates"
const val hasCustomCertificateField = "has_custom_certificate" const val hasCustomCertificateField = "has_custom_certificate"
const val pendingUpdateCountField = "pending_update_count" const val pendingUpdateCountField = "pending_update_count"
const val lastErrorDateField = "last_error_date" const val lastErrorDateField = "last_error_date"
const val lastSynchronizationErrorDateField = "last_synchronization_error_date"
const val lastErrorMessageField = "last_error_message" const val lastErrorMessageField = "last_error_message"
const val votesCountField = "voter_count" const val votesCountField = "voter_count"
const val isClosedField = "is_closed" const val isClosedField = "is_closed"
@@ -263,6 +266,9 @@ const val canRestrictMembersField = "can_restrict_members"
const val canPinMessagesField = "can_pin_messages" const val canPinMessagesField = "can_pin_messages"
const val canPromoteMembersField = "can_promote_members" const val canPromoteMembersField = "can_promote_members"
const val canManageVoiceChatsField = "can_manage_voice_chats" const val canManageVoiceChatsField = "can_manage_voice_chats"
const val canManageVideoChatsField = "can_manage_video_chats"
const val rightsField = "rights"
const val forChannelsField = "for_channels"
const val canManageChatField = "can_manage_chat" const val canManageChatField = "can_manage_chat"
const val pngStickerField = "png_sticker" const val pngStickerField = "png_sticker"
const val tgsStickerField = "tgs_sticker" const val tgsStickerField = "tgs_sticker"
@@ -313,6 +319,7 @@ const val pricesField = "prices"
const val payloadField = "payload" const val payloadField = "payload"
const val vcardField = "vcard" const val vcardField = "vcard"
const val resultsField = "results" const val resultsField = "results"
const val resultField = "result"
const val certificateField = "certificate" const val certificateField = "certificate"
const val questionField = "question" const val questionField = "question"
const val optionsField = "options" const val optionsField = "options"
@@ -430,3 +437,7 @@ const val bankStatementField = "bank_statement"
const val rentalAgreementField = "rental_agreement" const val rentalAgreementField = "rental_agreement"
const val passportRegistrationField = "passport_registration" const val passportRegistrationField = "passport_registration"
const val temporaryRegistrationField = "temporary_registration" const val temporaryRegistrationField = "temporary_registration"
const val buttonTextField = "button_text"
const val webAppField = "web_app"
const val menuButtonField = "menu_button"

View File

@@ -0,0 +1,122 @@
package dev.inmo.tgbotapi.types
import dev.inmo.tgbotapi.types.webapps.WebAppInfo
import dev.inmo.tgbotapi.utils.RiskFeature
import kotlinx.serialization.*
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import kotlinx.serialization.json.*
@Serializable(MenuButtonSerializer::class)
sealed interface MenuButton {
@Required
val type: String
@Serializable
object Commands : MenuButton {
@Required
override val type: String
get() = "commands"
}
@Serializable
data class WebApp(
val text: String,
@SerialName(webAppField)
val webApp: WebAppInfo
) : MenuButton {
@Required
override val type: String
get() = Companion.type
companion object {
val type: String
get() = "web_app"
}
}
@Serializable
object Default : MenuButton {
@Required
override val type: String
get() = "default"
}
@Serializable
@RiskFeature
data class Unknown (
override val type: String,
val rawJson: JsonElement
) : MenuButton
companion object {
fun serializer(): KSerializer<MenuButton> = MenuButtonSerializer
}
}
@Serializable
internal data class MenuButtonSurrogate(
val type: String,
val text: String? = null,
@SerialName(webAppField)
val webApp: WebAppInfo? = null,
val srcJsonElement: JsonElement? = null
)
@Serializer(MenuButton::class)
object MenuButtonSerializer : KSerializer<MenuButton> {
override val descriptor: SerialDescriptor
get() = MenuButtonSurrogate.serializer().descriptor
override fun deserialize(decoder: Decoder): MenuButton {
val surrogate = if (decoder is JsonDecoder) {
val json = JsonElement.serializer().deserialize(decoder)
runCatching {
decoder.json.decodeFromJsonElement(MenuButtonSurrogate.serializer(), json)
}.onFailure {
return MenuButton.Unknown(
runCatching { json.jsonObject[typeField] ?.jsonPrimitive ?.content }.getOrNull() ?: "",
json
)
}.getOrThrow().copy(
srcJsonElement = json
)
} else {
MenuButtonSurrogate.serializer().deserialize(decoder)
}
return when (surrogate.type) {
MenuButton.Commands.type -> MenuButton.Commands
MenuButton.Default.type -> MenuButton.Default
MenuButton.WebApp.type -> if (surrogate.text != null && surrogate.webApp != null) {
MenuButton.WebApp(surrogate.text, surrogate.webApp)
} else {
null
}
else -> null
} ?: MenuButton.Unknown(
surrogate.type,
surrogate.srcJsonElement ?: buildJsonObject { }
)
}
override fun serialize(encoder: Encoder, value: MenuButton) {
encoder.encodeSerializableValue(
MenuButtonSurrogate.serializer(),
when (value) {
MenuButton.Default,
MenuButton.Commands -> MenuButtonSurrogate(value.type)
is MenuButton.WebApp -> MenuButtonSurrogate(value.type, value.text, value.webApp)
is MenuButton.Unknown -> {
encoder.encodeSerializableValue(
JsonElement.serializer(),
value.rawJson
)
return
}
}
)
}
}

View File

@@ -33,7 +33,12 @@ inline fun mention(parts: TextSourcesList, id: Identifier) = mention(parts, User
@Suppress("NOTHING_TO_INLINE") @Suppress("NOTHING_TO_INLINE")
inline fun Identifier.mention(parts: TextSourcesList) = mention(parts, this) inline fun Identifier.mention(parts: TextSourcesList) = mention(parts, this)
@Suppress("NOTHING_TO_INLINE") @Suppress("NOTHING_TO_INLINE")
inline fun mention(user: User, vararg parts: TextSource) = mention(parts.toList(), user) inline fun mention(user: User, vararg parts: TextSource) = mention(
textSourcesOrElseTextSource(parts.toList()) {
RegularTextSource("${user.lastName} ${user.firstName}")
},
user
)
@Suppress("NOTHING_TO_INLINE") @Suppress("NOTHING_TO_INLINE")
inline fun mention(text: String, user: User) = mention(user, regular(text)) inline fun mention(text: String, user: User) = mention(user, regular(text))
@Suppress("NOTHING_TO_INLINE") @Suppress("NOTHING_TO_INLINE")

View File

@@ -0,0 +1,17 @@
package dev.inmo.tgbotapi.types.MessageEntity.textsources
import dev.inmo.tgbotapi.utils.RiskFeature
import kotlin.js.JsName
import kotlin.jvm.JvmName
@RiskFeature
inline fun textSourcesOrElse(
textSources: TextSourcesList,
block: () -> TextSourcesList
): TextSourcesList = textSources.takeIf { it.isNotEmpty() } ?: block()
@RiskFeature
inline fun textSourcesOrElseTextSource(
textSources: TextSourcesList,
block: () -> TextSource
): TextSourcesList = textSources.takeIf { it.isNotEmpty() } ?: listOf(block())

View File

@@ -16,6 +16,8 @@ data class WebhookInfo(
val allowedUpdates: List<String> = ALL_UPDATES_LIST, val allowedUpdates: List<String> = ALL_UPDATES_LIST,
@SerialName(lastErrorDateField) @SerialName(lastErrorDateField)
val lastErrorDate: TelegramDate? = null, val lastErrorDate: TelegramDate? = null,
@SerialName(lastSynchronizationErrorDateField)
val lastSynchronizationErrorDate: TelegramDate? = null,
@SerialName(lastErrorMessageField) @SerialName(lastErrorMessageField)
val lastErrorMessage: String? = null val lastErrorMessage: String? = null
) { ) {

View File

@@ -2,8 +2,9 @@ package dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons
import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.games.CallbackGame import dev.inmo.tgbotapi.types.games.CallbackGame
import dev.inmo.tgbotapi.types.webapps.WebAppInfo
import kotlinx.serialization.* import kotlinx.serialization.*
import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.*
/** /**
* Some button of [dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup]. See inheritors and visit * Some button of [dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup]. See inheritors and visit
@@ -15,10 +16,14 @@ sealed interface InlineKeyboardButton {
} }
@Serializable @Serializable
data class UnknownInlineKeyboardButton internal constructor( data class UnknownInlineKeyboardButton (
override val text: String,
val rawData: JsonElement val rawData: JsonElement
) : InlineKeyboardButton ) : InlineKeyboardButton {
override val text: String
get() = runCatching {
rawData.jsonObject[textField] ?.jsonPrimitive ?.content
}.getOrNull() ?: ""
}
/** /**
* This type of button must always be the first button in the first row. Visit * This type of button must always be the first button in the first row. Visit
@@ -116,3 +121,14 @@ data class URLInlineKeyboardButton(
@SerialName(urlField) @SerialName(urlField)
val url: String val url: String
) : InlineKeyboardButton ) : InlineKeyboardButton
/**
* Button with [WebAppInfo]. Web App will be launched when the button is pressed. The Web App will be able to send a
* `web_app_data` service message. **Available in private chats only**.
*/
@Serializable
data class WebAppInlineKeyboardButton(
override val text: String,
@SerialName(webAppField)
val webApp: WebAppInfo
) : InlineKeyboardButton

View File

@@ -37,7 +37,7 @@ object InlineKeyboardButtonSerializer : KSerializer<InlineKeyboardButton> {
return (json as? JsonObject) ?.let { resolveSerializer(it) } ?.let { return (json as? JsonObject) ?.let { resolveSerializer(it) } ?.let {
nonstrictJsonFormat.decodeFromJsonElement(it, json) nonstrictJsonFormat.decodeFromJsonElement(it, json)
} ?: UnknownInlineKeyboardButton("", json) } ?: UnknownInlineKeyboardButton(json)
} }
override fun serialize(encoder: Encoder, value: InlineKeyboardButton) { override fun serialize(encoder: Encoder, value: InlineKeyboardButton) {
@@ -48,6 +48,7 @@ object InlineKeyboardButtonSerializer : KSerializer<InlineKeyboardButton> {
is SwitchInlineQueryInlineKeyboardButton -> SwitchInlineQueryInlineKeyboardButton.serializer().serialize(encoder, value) is SwitchInlineQueryInlineKeyboardButton -> SwitchInlineQueryInlineKeyboardButton.serializer().serialize(encoder, value)
is SwitchInlineQueryCurrentChatInlineKeyboardButton -> SwitchInlineQueryCurrentChatInlineKeyboardButton.serializer().serialize(encoder, value) is SwitchInlineQueryCurrentChatInlineKeyboardButton -> SwitchInlineQueryCurrentChatInlineKeyboardButton.serializer().serialize(encoder, value)
is URLInlineKeyboardButton -> URLInlineKeyboardButton.serializer().serialize(encoder, value) is URLInlineKeyboardButton -> URLInlineKeyboardButton.serializer().serialize(encoder, value)
is WebAppInlineKeyboardButton -> WebAppInlineKeyboardButton.serializer().serialize(encoder, value)
is CallbackGameInlineKeyboardButton -> CallbackGameInlineKeyboardButton.serializer().serialize(encoder, value) is CallbackGameInlineKeyboardButton -> CallbackGameInlineKeyboardButton.serializer().serialize(encoder, value)
is UnknownInlineKeyboardButton -> JsonElement.serializer().serialize(encoder, value.rawData) is UnknownInlineKeyboardButton -> JsonElement.serializer().serialize(encoder, value.rawData)
} }

View File

@@ -1,6 +1,7 @@
package dev.inmo.tgbotapi.types.buttons package dev.inmo.tgbotapi.types.buttons
import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.webapps.WebAppInfo
import dev.inmo.tgbotapi.utils.RiskFeature import dev.inmo.tgbotapi.utils.RiskFeature
import dev.inmo.tgbotapi.utils.nonstrictJsonFormat import dev.inmo.tgbotapi.utils.nonstrictJsonFormat
import kotlinx.serialization.* import kotlinx.serialization.*
@@ -63,10 +64,22 @@ data class RequestLocationKeyboardButton(
override val text: String override val text: String
) : KeyboardButton { ) : KeyboardButton {
@SerialName(requestLocationField) @SerialName(requestLocationField)
@EncodeDefault @Required
val requestLocation: Boolean = true val requestLocation: Boolean = true
} }
/**
* Private chats only. Description of the Web App that will be launched when the user presses the button. The Web App
* will be able to send an arbitrary message on behalf of the user using the method `answerWebAppQuery`. Available only
* in private chats between a user and the bot.
*/
@Serializable
data class WebAppKeyboardButton(
override val text: String,
@SerialName(webAppField)
val webApp: WebAppInfo
) : KeyboardButton
/** /**
* Private chats only. When user will tap on this button, he will be asked for the poll with [requestPoll] options. You will be able * Private chats only. When user will tap on this button, he will be asked for the poll with [requestPoll] options. You will be able
* to catch this poll in updates and data using [dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onPoll] in * to catch this poll in updates and data using [dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onPoll] in
@@ -97,6 +110,13 @@ object KeyboardButtonSerializer : KSerializer<KeyboardButton> {
asJson is JsonObject && asJson[requestLocationField] != null -> RequestLocationKeyboardButton( asJson is JsonObject && asJson[requestLocationField] != null -> RequestLocationKeyboardButton(
asJson[textField]!!.jsonPrimitive.content asJson[textField]!!.jsonPrimitive.content
) )
asJson is JsonObject && asJson[webAppField] != null -> WebAppKeyboardButton(
asJson[textField]!!.jsonPrimitive.content,
nonstrictJsonFormat.decodeFromJsonElement(
WebAppInfo.serializer(),
asJson[webAppField]!!
)
)
asJson is JsonObject && asJson[requestPollField] != null -> RequestPollKeyboardButton( asJson is JsonObject && asJson[requestPollField] != null -> RequestPollKeyboardButton(
asJson[textField]!!.jsonPrimitive.content, asJson[textField]!!.jsonPrimitive.content,
nonstrictJsonFormat.decodeFromJsonElement( nonstrictJsonFormat.decodeFromJsonElement(
@@ -119,6 +139,7 @@ object KeyboardButtonSerializer : KSerializer<KeyboardButton> {
when (value) { when (value) {
is RequestContactKeyboardButton -> RequestContactKeyboardButton.serializer().serialize(encoder, value) is RequestContactKeyboardButton -> RequestContactKeyboardButton.serializer().serialize(encoder, value)
is RequestLocationKeyboardButton -> RequestLocationKeyboardButton.serializer().serialize(encoder, value) is RequestLocationKeyboardButton -> RequestLocationKeyboardButton.serializer().serialize(encoder, value)
is WebAppKeyboardButton -> WebAppKeyboardButton.serializer().serialize(encoder, value)
is RequestPollKeyboardButton -> RequestPollKeyboardButton.serializer().serialize(encoder, value) is RequestPollKeyboardButton -> RequestPollKeyboardButton.serializer().serialize(encoder, value)
is SimpleKeyboardButton -> encoder.encodeString(value.text) is SimpleKeyboardButton -> encoder.encodeString(value.text)
is UnknownKeyboardButton -> JsonElement.serializer().serialize(encoder, nonstrictJsonFormat.parseToJsonElement(value.raw)) is UnknownKeyboardButton -> JsonElement.serializer().serialize(encoder, nonstrictJsonFormat.parseToJsonElement(value.raw))

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

@@ -0,0 +1,15 @@
package dev.inmo.tgbotapi.types.message.ChatEvents
import dev.inmo.tgbotapi.types.buttonTextField
import dev.inmo.tgbotapi.types.dataField
import dev.inmo.tgbotapi.types.message.ChatEvents.abstracts.PrivateEvent
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@Serializable
data class WebAppData(
@SerialName(dataField)
val data: String,
@SerialName(buttonTextField)
val buttonText: String
) : PrivateEvent

View File

@@ -0,0 +1,8 @@
package dev.inmo.tgbotapi.types.message.ChatEvents.abstracts
import dev.inmo.tgbotapi.types.message.ChatEvents.voice.VideoChatScheduled
interface VideoChatEvent : PublicChatEvent
@Deprecated("Renamed", ReplaceWith("VideoChatEvent", "dev.inmo.tgbotapi.types.message.ChatEvents.voice.VideoChatEvent"))
typealias VoiceChatEvent = VideoChatEvent

View File

@@ -1,3 +0,0 @@
package dev.inmo.tgbotapi.types.message.ChatEvents.abstracts
interface VoiceChatEvent : PublicChatEvent

View File

@@ -4,15 +4,18 @@ import com.soywiz.klock.TimeSpan
import com.soywiz.klock.seconds import com.soywiz.klock.seconds
import dev.inmo.tgbotapi.types.Seconds import dev.inmo.tgbotapi.types.Seconds
import dev.inmo.tgbotapi.types.durationField import dev.inmo.tgbotapi.types.durationField
import dev.inmo.tgbotapi.types.message.ChatEvents.abstracts.VoiceChatEvent import dev.inmo.tgbotapi.types.message.ChatEvents.abstracts.VideoChatEvent
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@Serializable @Serializable
data class VoiceChatEnded( data class VideoChatEnded(
@SerialName(durationField) @SerialName(durationField)
val duration: Seconds val duration: Seconds
) : VoiceChatEvent { ) : VideoChatEvent {
val timeSpan: TimeSpan val timeSpan: TimeSpan
get() = TimeSpan(duration.seconds.milliseconds) get() = TimeSpan(duration.seconds.milliseconds)
} }
@Deprecated("Renamed", ReplaceWith("VideoChatEnded", "dev.inmo.tgbotapi.types.message.ChatEvents.voice.VideoChatEnded"))
typealias VoiceChatEnded = VideoChatEnded

View File

@@ -0,0 +1,16 @@
package dev.inmo.tgbotapi.types.message.ChatEvents.voice
import dev.inmo.tgbotapi.types.User
import dev.inmo.tgbotapi.types.message.ChatEvents.abstracts.VideoChatEvent
import dev.inmo.tgbotapi.types.usersField
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@Serializable
data class VideoChatParticipantsInvited(
@SerialName(usersField)
val users: List<User> = emptyList()
) : VideoChatEvent
@Deprecated("Renamed", ReplaceWith("VideoChatParticipantsInvited", "dev.inmo.tgbotapi.types.message.ChatEvents.voice.VideoChatParticipantsInvited"))
typealias VoiceChatParticipantsInvited = VideoChatParticipantsInvited

View File

@@ -1,13 +1,16 @@
package dev.inmo.tgbotapi.types.message.ChatEvents.voice package dev.inmo.tgbotapi.types.message.ChatEvents.voice
import dev.inmo.tgbotapi.types.TelegramDate import dev.inmo.tgbotapi.types.TelegramDate
import dev.inmo.tgbotapi.types.message.ChatEvents.abstracts.VoiceChatEvent import dev.inmo.tgbotapi.types.message.ChatEvents.abstracts.VideoChatEvent
import dev.inmo.tgbotapi.types.startDateField import dev.inmo.tgbotapi.types.startDateField
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@Serializable @Serializable
data class VoiceChatScheduled( data class VideoChatScheduled(
@SerialName(startDateField) @SerialName(startDateField)
val startDate: TelegramDate val startDate: TelegramDate
) : VoiceChatEvent ) : VideoChatEvent
@Deprecated("Renamed", ReplaceWith("VideoChatScheduled", "dev.inmo.tgbotapi.types.message.ChatEvents.voice.VideoChatScheduled"))
typealias VoiceChatScheduled = VideoChatScheduled

View File

@@ -0,0 +1,10 @@
package dev.inmo.tgbotapi.types.message.ChatEvents.voice
import dev.inmo.tgbotapi.types.message.ChatEvents.abstracts.VideoChatEvent
import kotlinx.serialization.Serializable
@Serializable
object VideoChatStarted : VideoChatEvent
@Deprecated("Renamed", ReplaceWith("VideoChatStarted", "dev.inmo.tgbotapi.types.message.ChatEvents.voice.VideoChatStarted"))
typealias VoiceChatStarted = VideoChatStarted

View File

@@ -1,13 +0,0 @@
package dev.inmo.tgbotapi.types.message.ChatEvents.voice
import dev.inmo.tgbotapi.types.User
import dev.inmo.tgbotapi.types.message.ChatEvents.abstracts.VoiceChatEvent
import dev.inmo.tgbotapi.types.usersField
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@Serializable
data class VoiceChatParticipantsInvited(
@SerialName(usersField)
val users: List<User> = emptyList()
) : VoiceChatEvent

View File

@@ -1,7 +0,0 @@
package dev.inmo.tgbotapi.types.message.ChatEvents.voice
import dev.inmo.tgbotapi.types.message.ChatEvents.abstracts.VoiceChatEvent
import kotlinx.serialization.Serializable
@Serializable
object VoiceChatStarted : VoiceChatEvent

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

@@ -84,10 +84,10 @@ internal data class RawMessage(
private val successful_payment: SuccessfulPayment? = null, private val successful_payment: SuccessfulPayment? = null,
// Voice Chat Service Messages // Voice Chat Service Messages
private val voice_chat_scheduled: VoiceChatScheduled? = null, private val video_chat_scheduled: VideoChatScheduled? = null,
private val voice_chat_started: VoiceChatStarted? = null, private val video_chat_started: VideoChatStarted? = null,
private val voice_chat_ended: VoiceChatEnded? = null, private val video_chat_ended: VideoChatEnded? = null,
private val voice_chat_participants_invited: VoiceChatParticipantsInvited? = null, private val video_chat_participants_invited: VideoChatParticipantsInvited? = null,
// AutoDelete Message time changed // AutoDelete Message time changed
private val message_auto_delete_timer_changed: MessageAutoDeleteTimerChanged? = null, private val message_auto_delete_timer_changed: MessageAutoDeleteTimerChanged? = null,
@@ -95,6 +95,9 @@ internal data class RawMessage(
// login property // login property
private val connected_website: String? = null, private val connected_website: String? = null,
// login property
private val web_app_data: WebAppData? = null,
// passport property // passport property
private val passport_data: PassportData? = null, private val passport_data: PassportData? = null,
private val proximity_alert_triggered: ProximityAlertTriggered? = null, private val proximity_alert_triggered: ProximityAlertTriggered? = null,
@@ -183,11 +186,11 @@ internal data class RawMessage(
left_chat_member != null -> LeftChatMember(left_chat_member) left_chat_member != null -> LeftChatMember(left_chat_member)
new_chat_title != null -> NewChatTitle(new_chat_title) new_chat_title != null -> NewChatTitle(new_chat_title)
new_chat_photo != null -> NewChatPhoto(new_chat_photo.toList()) new_chat_photo != null -> NewChatPhoto(new_chat_photo.toList())
voice_chat_started != null -> voice_chat_started video_chat_started != null -> video_chat_started
voice_chat_scheduled != null -> voice_chat_scheduled video_chat_scheduled != null -> video_chat_scheduled
message_auto_delete_timer_changed != null -> message_auto_delete_timer_changed message_auto_delete_timer_changed != null -> message_auto_delete_timer_changed
voice_chat_ended != null -> voice_chat_ended video_chat_ended != null -> video_chat_ended
voice_chat_participants_invited != null -> voice_chat_participants_invited video_chat_participants_invited != null -> video_chat_participants_invited
delete_chat_photo -> DeleteChatPhoto() delete_chat_photo -> DeleteChatPhoto()
group_chat_created -> GroupChatCreated( group_chat_created -> GroupChatCreated(
migrate_to_chat_id migrate_to_chat_id
@@ -203,6 +206,7 @@ internal data class RawMessage(
proximity_alert_triggered != null -> proximity_alert_triggered proximity_alert_triggered != null -> proximity_alert_triggered
successful_payment != null -> SuccessfulPaymentEvent(successful_payment) successful_payment != null -> SuccessfulPaymentEvent(successful_payment)
connected_website != null -> UserLoggedIn(connected_website) connected_website != null -> UserLoggedIn(connected_website)
web_app_data != null -> web_app_data
else -> null else -> null
} }
} }

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

@@ -20,8 +20,7 @@ interface MessageContent: ResendableContent {
subclass(DiceContent::class) subclass(DiceContent::class)
subclass(TextContent::class) subclass(TextContent::class)
subclass(LiveLocationContent::class) subclass(LocationContent::class, LocationContentSerializer)
subclass(StaticLocationContent::class)
subclass(PhotoContent::class) subclass(PhotoContent::class)
subclass(VideoContent::class) subclass(VideoContent::class)

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

@@ -0,0 +1,11 @@
package dev.inmo.tgbotapi.types.webapps
import dev.inmo.tgbotapi.types.urlField
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@Serializable
data class WebAppInfo(
@SerialName(urlField)
val url: String
)

View File

@@ -0,0 +1,9 @@
package dev.inmo.tgbotapi.types.webapps.query
import dev.inmo.tgbotapi.types.InlineMessageIdentifier
import kotlinx.serialization.Serializable
@Serializable
data class SentWebAppMessage(
val inlineMessageId: InlineMessageIdentifier? = null
)

View File

@@ -1,6 +1,8 @@
package dev.inmo.tgbotapi.utils package dev.inmo.tgbotapi.utils
import com.benasher44.uuid.uuid4 import com.benasher44.uuid.uuid4
import dev.inmo.micro_utils.common.MPPFile
import dev.inmo.micro_utils.common.filename
import io.ktor.utils.io.* import io.ktor.utils.io.*
import io.ktor.utils.io.core.ByteReadPacket import io.ktor.utils.io.core.ByteReadPacket
import io.ktor.utils.io.core.Input import io.ktor.utils.io.core.Input
@@ -13,6 +15,7 @@ import kotlinx.serialization.Serializable
* @param fileName This filename will be used in telegram system as name of file * @param fileName This filename will be used in telegram system as name of file
*/ */
@Serializable @Serializable
@Deprecated("Will be removed soon")
data class StorageFileInfo( data class StorageFileInfo(
val fileName: String val fileName: String
) { ) {
@@ -25,18 +28,35 @@ data class StorageFileInfo(
/** /**
* Contains info about file, which potentially can be sent to telegram system. * Contains info about file, which potentially can be sent to telegram system.
* *
* @param storageFileInfo Information about this file * @param fileName Filename
* @param inputSource Lambda which able to allocate [Input] for uploading/manipulating data * @param inputSource Lambda which able to allocate [Input] for uploading/manipulating data
* *
* @see StorageFileInfo * @see StorageFileInfo
* @see asStorageFile * @see asStorageFile
*/ */
data class StorageFile( data class StorageFile(
val storageFileInfo: StorageFileInfo, val fileName: String,
private val inputSource: () -> Input private val inputSource: () -> Input
) { ) {
val input: Input val input: Input
get() = inputSource() get() = inputSource()
@Deprecated("This field will be removed soon. Use fileName instead of StorageFileInfo")
val storageFileInfo: StorageFileInfo
get() = StorageFileInfo(fileName)
/**
* This methods is required for random generation of name for keeping warranties about unique file name
*/
fun generateCustomName() = "${uuid4()}.${fileName.fileExtension}"
@Deprecated("This constructor will be removed soon. Use constructor with fileName instead of StorageFileInfo")
constructor(
storageFileInfo: StorageFileInfo,
inputSource: () -> Input
) : this(
storageFileInfo.fileName,
inputSource
)
} }
@Suppress("NOTHING_TO_INLINE") @Suppress("NOTHING_TO_INLINE")
@@ -44,7 +64,7 @@ inline fun StorageFile(
fileName: String, fileName: String,
bytes: ByteArray bytes: ByteArray
) = StorageFile( ) = StorageFile(
StorageFileInfo(fileName) fileName
) { ) {
ByteReadPacket(bytes) ByteReadPacket(bytes)
} }
@@ -54,8 +74,8 @@ suspend inline fun StorageFile(
fileName: String, fileName: String,
byteReadChannel: ByteReadChannel byteReadChannel: ByteReadChannel
) = StorageFile( ) = StorageFile(
StorageFileInfo(fileName), fileName,
byteReadChannel.asInput().let { { it } } inputSource = byteReadChannel.asInput().let { { it } }
) )
@Suppress("NOTHING_TO_INLINE", "unused") @Suppress("NOTHING_TO_INLINE", "unused")

Some files were not shown because too many files have changed in this diff Show More