1
0
mirror of https://github.com/InsanusMokrassar/TelegramBotAPI.git synced 2025-11-16 12:00:18 +00:00

Compare commits

..

34 Commits

Author SHA1 Message Date
8dd3eefd15 Update CHANGELOG.md 2023-02-28 19:59:23 +06:00
b72d4da8f0 Update libs.versions.toml 2023-02-28 19:57:11 +06:00
ebd023669d start 6.0.1 2023-02-28 19:55:29 +06:00
f7be4e557e Merge pull request #726 from InsanusMokrassar/6.0.0
6.0.0
2023-02-28 13:27:41 +06:00
ec434c6af4 fill changelog with dependencies updates 2023-02-27 22:42:28 +06:00
0398590de6 update microutils version to release one 2023-02-27 22:40:26 +06:00
9ef1b54ada *.link renames 2023-02-27 22:32:08 +06:00
c30ce5c803 revert gradle wrapper version 2023-02-27 20:10:45 +06:00
c0a50bccb0 update publish.gradle and gradle wrapper version 2023-02-27 18:40:01 +06:00
e0cd7dc512 TelegramBot.resend 2023-02-27 18:27:23 +06:00
6ff621b428 Add triggers and waiters for VisualMediaGroupPartContent 2023-02-27 18:10:33 +06:00
964a61749c update dependencies 2023-02-27 17:57:32 +06:00
17930091ac start 6.0.0 2023-02-27 17:55:49 +06:00
2271beadfb Update README.md 2023-02-24 15:31:33 +06:00
44c48a8462 Add files via upload 2023-02-24 15:30:36 +06:00
4d35f89ad1 Merge pull request #722 from InsanusMokrassar/5.2.1
5.2.1
2023-02-21 21:44:53 +06:00
174706b189 changelog fill and callback query improvements 2023-02-19 18:35:36 +06:00
fe17312bb5 Update LiveFlowLocation.kt 2023-02-17 15:50:49 +06:00
d8b5789cd2 5.2.1 2023-02-17 15:48:02 +06:00
f27d0916db Merge pull request #721 from InsanusMokrassar/5.2.0
hotfix in LiveFlowLocation (5.2.0)
2023-02-17 15:42:17 +06:00
fa0a2818a0 hotfix in LiveFlowLocation 2023-02-17 15:40:49 +06:00
2d3fe45389 Merge pull request #720 from InsanusMokrassar/5.2.0
5.2.0
2023-02-17 15:36:27 +06:00
02b5d282d3 now it is possible to handle send content message in handleLiveLocation 2023-02-17 15:31:40 +06:00
7795bc2b50 LiveLocationProvider#message now is public, but as value instead of variable 2023-02-17 15:28:41 +06:00
a95365a691 update microutils up to 0.16.10 2023-02-17 14:03:00 +06:00
07082bf896 start 5.2.0 2023-02-17 14:02:18 +06:00
6a3fc47f62 Merge pull request #717 from InsanusMokrassar/5.1.1
5.1.1
2023-02-17 14:01:21 +06:00
1c94e86b40 small improvements 2023-02-13 12:06:28 +06:00
0416b200b8 fixes :) 2023-02-13 12:03:23 +06:00
48c4e90912 fixes 2023-02-13 12:00:09 +06:00
5fc88e89b9 Fixes in content waiting expectators 2023-02-13 11:49:36 +06:00
dad42cf939 makeUserLink 2023-02-13 11:16:49 +06:00
041c3ecc1b start 5.1.1 2023-02-11 18:57:46 +06:00
103dd949ce Merge pull request #712 from InsanusMokrassar/5.1.0
5.1.0
2023-02-06 14:08:03 +06:00
22 changed files with 493 additions and 123 deletions

View File

@@ -1,5 +1,47 @@
# TelegramBotAPI changelog
## 6.0.1
* `Versions`:
* `Ktor`: `2.2.3` -> `2.2.4`
* `MicroUtils`: `0.17.0` -> `0.17.1`
## 6.0.0
* `Versions`:
* `Kotlin`: `1.7.22` -> `1.8.10`
* `MicroUtils`: `0.16.10` -> `0.17.0`
* `Serialization`: `1.4.1` -> `1.5.0`
* `uuid`: `0.6.0` -> `0.7.0`
* `Core`:
* `*.link` extensions have been deprecated with renaming to avoid collisions with `link` methods
* `API`:
* Add `TelegramBot.resend` methods
* `BehaviourBuilder`:
* Add triggers and waiters for `VisualMediaGroupPartContent`
* `Utils`:
* `*.link` extensions have been deprecated with renaming to avoid collisions with `link` methods
## 5.2.1
* `Core`:
* All the `CallbackQuery`es now will receive `CommonUser` instead of `User` due inability of bots to trigger any
inline interaction with others bots
* `API`:
* Now `sentMessageFlow` will take each sent message in `handleLiveLocation`
## 5.2.0
* `Versions`:
* `MicroUtils`: `0.16.8` -> `0.16.10`
## 5.1.1
* `Core`:
* Add opportunity to get user link with `makeUserLink`
* `BehaviourBuilder`:
* Fixes in content waiting expectators
## 5.1.0
[Bot API 6.5](https://core.telegram.org/bots/api-changelog#february-3-2023) support

View File

@@ -5,10 +5,10 @@
| Useful repos | [![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/) |
| Misc | [![Awesome Kotlin Badge](https://kotlin.link/awesome-kotlin.svg)](https://github.com/KotlinBy/awesome-kotlin) [![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) |
<!--- [![Telegram Channel](./resources/tg_channel_qr.jpg)](https://t.me/InMoTelegramBotAPI) --->
<!--- [![Telegram Channel](./resources/tg_channel_qr.jpg)](https://t.me/ktgbotapi) --->
<p align="center">
<a href="https://t.me/InMoTelegramBotAPI">
<a href="https://t.me/ktgbotapi">
<img src="./resources/tg_channel_qr.jpg">
</a>
</p>

View File

@@ -6,4 +6,4 @@ kotlin.incremental=true
kotlin.incremental.js=true
library_group=dev.inmo
library_version=5.1.0
library_version=6.0.1

View File

@@ -1,19 +1,19 @@
[versions]
kotlin = "1.7.22"
kotlin-serialization = "1.4.1"
kotlin = "1.8.10"
kotlin-serialization = "1.5.0"
kotlin-coroutines = "1.6.4"
javax-activation = "1.1.1"
korlibs = "3.4.0"
uuid = "0.6.0"
ktor = "2.2.3"
uuid = "0.7.0"
ktor = "2.2.4"
ksp = "1.7.22-1.0.8"
ksp = "1.8.10-1.0.9"
kotlin-poet = "1.12.0"
microutils = "0.16.8"
microutils = "0.17.1"
github-release-plugin = "2.4.1"
dokka = "1.7.20"

View File

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

View File

@@ -1,7 +1,8 @@
apply plugin: 'maven-publish'
task javadocsJar(type: Jar) {
classifier = 'javadoc'
archiveClassifier.convention("javadoc")
archiveClassifier.set("javadoc")
}
publishing {
@@ -19,22 +20,22 @@ publishing {
}
developers {
developer {
id = "InsanusMokrassar"
name = "Ovsiannikov Aleksei"
email = "ovsyannikov.alexey95@gmail.com"
}
}
licenses {
license {
name = "Apache Software License 2.0"
url = "https://github.com/InsanusMokrassar/TelegramBotAPI/blob/master/LICENSE"
}
}
}
repositories {
@@ -42,55 +43,55 @@ publishing {
maven {
name = "GithubPackages"
url = uri("https://maven.pkg.github.com/InsanusMokrassar/TelegramBotAPI")
credentials {
username = project.hasProperty('GITHUBPACKAGES_USER') ? project.property('GITHUBPACKAGES_USER') : System.getenv('GITHUBPACKAGES_USER')
password = project.hasProperty('GITHUBPACKAGES_PASSWORD') ? project.property('GITHUBPACKAGES_PASSWORD') : System.getenv('GITHUBPACKAGES_PASSWORD')
}
}
}
if (project.hasProperty('GITEA_TOKEN') || System.getenv('GITEA_TOKEN') != null) {
maven {
name = "Gitea"
url = uri("https://git.inmo.dev/api/packages/InsanusMokrassar/maven")
credentials(HttpHeaderCredentials) {
name = "Authorization"
value = project.hasProperty('GITEA_TOKEN') ? project.property('GITEA_TOKEN') : System.getenv('GITEA_TOKEN')
}
authentication {
header(HttpHeaderAuthentication)
}
}
}
if ((project.hasProperty('SONATYPE_USER') || System.getenv('SONATYPE_USER') != null) && (project.hasProperty('SONATYPE_PASSWORD') || System.getenv('SONATYPE_PASSWORD') != null)) {
maven {
name = "sonatype"
url = uri("https://oss.sonatype.org/service/local/staging/deploy/maven2/")
credentials {
username = project.hasProperty('SONATYPE_USER') ? project.property('SONATYPE_USER') : System.getenv('SONATYPE_USER')
password = project.hasProperty('SONATYPE_PASSWORD') ? project.property('SONATYPE_PASSWORD') : System.getenv('SONATYPE_PASSWORD')
}
}
}
}
}
}
if (project.hasProperty("signing.gnupg.keyName")) {
apply plugin: 'signing'
signing {
useGpgCmd()
sign publishing.publications
}
task signAll {
tasks.withType(Sign).forEach {
dependsOn(it)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 593 KiB

After

Width:  |  Height:  |  Size: 448 KiB

View File

@@ -6,7 +6,6 @@ import dev.inmo.tgbotapi.abstracts.*
import dev.inmo.tgbotapi.abstracts.types.WithReplyMarkup
import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.extensions.api.edit.edit
import dev.inmo.tgbotapi.extensions.api.edit.location.live.editLiveLocation
import dev.inmo.tgbotapi.extensions.api.send.send
import dev.inmo.tgbotapi.extensions.api.send.sendLiveLocation
import dev.inmo.tgbotapi.types.*
@@ -17,6 +16,7 @@ import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage
import dev.inmo.tgbotapi.types.message.content.LocationContent
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.FlowCollector
import kotlinx.coroutines.flow.map
import kotlinx.serialization.Serializable
import kotlin.js.JsName
@@ -45,7 +45,8 @@ suspend fun TelegramBot.handleLiveLocation(
disableNotification: Boolean = false,
protectContent: Boolean = false,
replyToMessageId: MessageId? = null,
allowSendingWithoutReply: Boolean? = null
allowSendingWithoutReply: Boolean? = null,
sentMessageFlow: FlowCollector<ContentMessage<LocationContent>>? = null
) {
var currentLiveLocationMessage: ContentMessage<LocationContent>? = null
val updateMessageJob = CoroutineScope(currentCoroutineContext().LinkedSupervisorJob()).launchSafelyWithoutExceptions(start = CoroutineStart.LAZY) {
@@ -73,7 +74,9 @@ suspend fun TelegramBot.handleLiveLocation(
replyToMessageId,
allowSendingWithoutReply,
it.replyMarkup
)
).also {
sentMessageFlow ?.emit(it)
}
} else {
edit(
capturedLiveLocationMessage,
@@ -83,7 +86,9 @@ suspend fun TelegramBot.handleLiveLocation(
it.heading,
it.proximityAlertRadius,
it.replyMarkup
)
).also {
sentMessageFlow ?.emit(it)
}
}
}
}
@@ -102,7 +107,8 @@ suspend fun TelegramBot.handleLiveLocation(
disableNotification: Boolean = false,
protectContent: Boolean = false,
replyToMessageId: MessageId? = null,
allowSendingWithoutReply: Boolean? = null
allowSendingWithoutReply: Boolean? = null,
sentMessageFlow: FlowCollector<ContentMessage<LocationContent>>? = null
) {
handleLiveLocation(
chatId,
@@ -121,7 +127,8 @@ suspend fun TelegramBot.handleLiveLocation(
disableNotification,
protectContent,
replyToMessageId,
allowSendingWithoutReply
allowSendingWithoutReply,
sentMessageFlow
)
}
@@ -139,7 +146,8 @@ suspend fun TelegramBot.handleLiveLocation(
disableNotification: Boolean = false,
protectContent: Boolean = false,
replyToMessageId: MessageId? = null,
allowSendingWithoutReply: Boolean? = null
allowSendingWithoutReply: Boolean? = null,
sentMessageFlow: FlowCollector<ContentMessage<LocationContent>>? = null
) {
handleLiveLocation(
chatId,
@@ -154,6 +162,7 @@ suspend fun TelegramBot.handleLiveLocation(
disableNotification,
protectContent,
replyToMessageId,
allowSendingWithoutReply
allowSendingWithoutReply,
sentMessageFlow
)
}

View File

@@ -2,15 +2,22 @@ package dev.inmo.tgbotapi.extensions.api
import com.soywiz.klock.DateTime
import com.soywiz.klock.TimeSpan
import dev.inmo.micro_utils.coroutines.LinkedSupervisorJob
import dev.inmo.micro_utils.coroutines.launchSafelyWithoutExceptions
import dev.inmo.tgbotapi.abstracts.types.WithReplyMarkup
import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.extensions.api.edit.edit
import dev.inmo.tgbotapi.extensions.api.edit.location.live.editLiveLocation
import dev.inmo.tgbotapi.extensions.api.edit.location.live.stopLiveLocation
import dev.inmo.tgbotapi.extensions.api.send.send
import dev.inmo.tgbotapi.extensions.api.send.sendLiveLocation
import dev.inmo.tgbotapi.requests.send.SendLiveLocation
import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup
import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup
import dev.inmo.tgbotapi.types.chat.Chat
import dev.inmo.tgbotapi.types.location.LiveLocation
import dev.inmo.tgbotapi.types.location.Location
import dev.inmo.tgbotapi.types.location.StaticLocation
import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage
import dev.inmo.tgbotapi.types.message.abstracts.Message
@@ -18,7 +25,15 @@ import dev.inmo.tgbotapi.types.message.content.LocationContent
import dev.inmo.tgbotapi.utils.extensions.threadIdOrNull
import io.ktor.utils.io.core.Closeable
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.CoroutineStart
import kotlinx.coroutines.currentCoroutineContext
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import kotlin.js.JsName
import kotlin.jvm.JvmName
import kotlin.math.ceil
val defaultLivePeriodDelayMillis = (livePeriodLimit.last - 60L) * 1000L
@@ -45,7 +60,8 @@ class LiveLocationProvider internal constructor(
private set
get() = field || leftUntilCloseMillis.millisecondsLong < 0L
private var message: ContentMessage<LocationContent> = initMessage
var message: ContentMessage<LocationContent> = initMessage
private set
val lastLocation: LiveLocation
get() = message.content.location as LiveLocation

View File

@@ -0,0 +1,108 @@
package dev.inmo.tgbotapi.extensions.api.send
import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.types.ChatIdentifier
import dev.inmo.tgbotapi.types.MessageId
import dev.inmo.tgbotapi.types.MessageThreadId
import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup
import dev.inmo.tgbotapi.types.chat.Chat
import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage
import dev.inmo.tgbotapi.types.message.content.MessageContent
import dev.inmo.tgbotapi.types.threadId
/**
* This method will send [content] to the [chatId] as is
*/
suspend inline fun <T : MessageContent> TelegramBot.resend(
chatId: ChatIdentifier,
content: T,
messageThreadId: MessageThreadId? = chatId.threadId,
disableNotification: Boolean = false,
protectContent: Boolean = false,
replyToMessageId: MessageId? = null,
allowSendingWithoutReply: Boolean? = null,
replyMarkup: KeyboardMarkup? = null
) = execute(
content.createResend(
chatId = chatId,
messageThreadId = messageThreadId,
disableNotification = disableNotification,
protectContent = protectContent,
replyToMessageId = replyToMessageId,
allowSendingWithoutReply = allowSendingWithoutReply,
replyMarkup = replyMarkup
)
) as ContentMessage<T>
/**
* This method will send [content] to the [chatId] as is
*/
suspend inline fun <T : MessageContent> TelegramBot.resend(
chat: Chat,
content: T,
messageThreadId: MessageThreadId? = chat.id.threadId,
disableNotification: Boolean = false,
protectContent: Boolean = false,
replyToMessageId: MessageId? = null,
allowSendingWithoutReply: Boolean? = null,
replyMarkup: KeyboardMarkup? = null
) = resend(
chatId = chat.id,
content = content,
messageThreadId = messageThreadId,
disableNotification = disableNotification,
protectContent = protectContent,
replyToMessageId = replyToMessageId,
allowSendingWithoutReply = allowSendingWithoutReply,
replyMarkup = replyMarkup
)
/**
* This method will send [message] content to the [chatId]. In difference with [copyMessage], this method will use
* native methods for data sending (like [dev.inmo.tgbotapi.extensions.api.send.media.sendPhoto] if inoming content is
* [dev.inmo.tgbotapi.types.message.content.PhotoContent])
*/
suspend inline fun <T : MessageContent> TelegramBot.resend(
chatId: ChatIdentifier,
message: ContentMessage<T>,
messageThreadId: MessageThreadId? = chatId.threadId,
disableNotification: Boolean = false,
protectContent: Boolean = false,
replyToMessageId: MessageId? = null,
allowSendingWithoutReply: Boolean? = null,
replyMarkup: KeyboardMarkup? = null
) = resend(
chatId = chatId,
content = message.content,
messageThreadId = messageThreadId,
disableNotification = disableNotification,
protectContent = protectContent,
replyToMessageId = replyToMessageId,
allowSendingWithoutReply = allowSendingWithoutReply,
replyMarkup = replyMarkup
)
/**
* This method will send [message] content to the [chat]. In difference with [copyMessage], this method will use
* native methods for data sending (like [dev.inmo.tgbotapi.extensions.api.send.media.sendPhoto] if inoming content is
* [dev.inmo.tgbotapi.types.message.content.PhotoContent])
*/
suspend inline fun <T : MessageContent> TelegramBot.resend(
chat: Chat,
message: ContentMessage<T>,
messageThreadId: MessageThreadId? = chat.id.threadId,
disableNotification: Boolean = false,
protectContent: Boolean = false,
replyToMessageId: MessageId? = null,
allowSendingWithoutReply: Boolean? = null,
replyMarkup: KeyboardMarkup? = null
) = resend(
chatId = chat.id,
message = message,
messageThreadId = messageThreadId,
disableNotification = disableNotification,
protectContent = protectContent,
replyToMessageId = replyToMessageId,
allowSendingWithoutReply = allowSendingWithoutReply,
replyMarkup = replyMarkup
)

View File

@@ -16,119 +16,180 @@ typealias CommonMessageToContentMapper<T> = suspend CommonMessage<T>.() -> T?
@RiskFeature(lowLevelRiskFeatureMessage)
suspend inline fun <reified O : MessageContent> BehaviourContext.waitContent(
initRequest: Request<*>? = null,
includeMediaGroups: Boolean = true,
noinline errorFactory: NullableRequestBuilder<*> = { null }
): Flow<O> = waitContentMessage<O>(initRequest, includeMediaGroups, errorFactory).map { it.content }
): Flow<O> = waitContentMessage<O>(initRequest, errorFactory).map { it.content }
@Deprecated(
includeMediaGroupsDeprecationMessage,
ReplaceWith("waitAnyContent(initRequest, errorFactory)", "dev.inmo.tgbotapi.extensions.behaviour_builder.expectations.waitAnyContent")
)
suspend fun BehaviourContext.waitContent(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
includeMediaGroups: Boolean = true
) = waitContent<MessageContent>(initRequest, includeMediaGroups, errorFactory)
includeMediaGroups: Boolean
) = waitContent<MessageContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitAnyContent(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }
) = waitContent<MessageContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitContact(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }
) = waitContent<ContactContent>(initRequest, false, errorFactory)
) = waitContent<ContactContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitDice(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }
) = waitContent<DiceContent>(initRequest, false, errorFactory)
) = waitContent<DiceContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitGame(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }
) = waitContent<GameContent>(initRequest, false, errorFactory)
) = waitContent<GameContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitLocation(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }
) = waitContent<LocationContent>(initRequest, false, errorFactory)
) = waitContent<LocationContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitLiveLocation(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }
) = waitContent<LiveLocationContent>(initRequest, false, errorFactory)
) = waitContent<LiveLocationContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitStaticLocation(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }
) = waitContent<StaticLocationContent>(initRequest, false, errorFactory)
) = waitContent<StaticLocationContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitPoll(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }
) = waitContent<PollContent>(initRequest, false, errorFactory)
) = waitContent<PollContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitText(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }
) = waitContent<TextContent>(initRequest, false, errorFactory)
) = waitContent<TextContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitVenue(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }
) = waitContent<VenueContent>(initRequest, false, errorFactory)
) = waitContent<VenueContent>(initRequest, errorFactory)
@Deprecated(includeMediaGroupsDeprecationMessage)
suspend fun BehaviourContext.waitAudioMediaGroupContent(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
includeMediaGroups: Boolean = true
) = waitContent<AudioMediaGroupPartContent>(initRequest, includeMediaGroups, errorFactory)
includeMediaGroups: Boolean
) = waitContent<AudioMediaGroupPartContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitAudioMediaGroupContent(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
) = waitContent<AudioMediaGroupPartContent>(initRequest, errorFactory)
@Deprecated(includeMediaGroupsDeprecationMessage)
suspend fun BehaviourContext.waitDocumentMediaGroupContent(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
includeMediaGroups: Boolean = true
) = waitContent<DocumentMediaGroupPartContent>(initRequest, includeMediaGroups, errorFactory)
includeMediaGroups: Boolean
) = waitContent<DocumentMediaGroupPartContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitDocumentMediaGroupContent(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }
) = waitContent<DocumentMediaGroupPartContent>(initRequest, errorFactory)
@Deprecated(includeMediaGroupsDeprecationMessage)
suspend fun BehaviourContext.waitMedia(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
includeMediaGroups: Boolean = false
) = waitContent<MediaContent>(initRequest, includeMediaGroups, errorFactory)
includeMediaGroups: Boolean
) = waitContent<MediaContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitMedia(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }
) = waitContent<MediaContent>(initRequest, errorFactory)
@Deprecated(includeMediaGroupsDeprecationMessage)
suspend fun BehaviourContext.waitAnyMediaGroupContent(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
includeMediaGroups: Boolean = true
) = waitContent<MediaGroupPartContent>(initRequest, includeMediaGroups, errorFactory)
includeMediaGroups: Boolean
) = waitContent<MediaGroupPartContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitAnyMediaGroupContent(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
) = waitContent<MediaGroupPartContent>(initRequest, errorFactory)
@Deprecated(includeMediaGroupsDeprecationMessage)
suspend fun BehaviourContext.waitVisualMediaGroupContent(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
includeMediaGroups: Boolean = true
) = waitContent<VisualMediaGroupPartContent>(initRequest, includeMediaGroups, errorFactory)
includeMediaGroups: Boolean
) = waitContent<VisualMediaGroupPartContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitVisualMediaGroupContent(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
) = waitContent<VisualMediaGroupPartContent>(initRequest, errorFactory)
@Deprecated(includeMediaGroupsDeprecationMessage)
suspend fun BehaviourContext.waitTextedMediaContent(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
includeMediaGroups: Boolean = true
) = waitContent<TextedMediaContent>(initRequest, includeMediaGroups, errorFactory)
includeMediaGroups: Boolean
) = waitContent<TextedMediaContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitTextedMediaContent(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
) = waitContent<TextedMediaContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitAnimation(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }
) = waitContent<AnimationContent>(initRequest, false, errorFactory)
) = waitContent<AnimationContent>(initRequest, errorFactory)
@Deprecated(includeMediaGroupsDeprecationMessage)
suspend fun BehaviourContext.waitAudio(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
includeMediaGroups: Boolean = false
) = waitContent<AudioContent>(initRequest, includeMediaGroups, errorFactory)
includeMediaGroups: Boolean
) = waitContent<AudioContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitAudio(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
) = waitContent<AudioContent>(initRequest, errorFactory)
@Deprecated(includeMediaGroupsDeprecationMessage)
suspend fun BehaviourContext.waitDocument(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
includeMediaGroups: Boolean = false
) = waitContent<DocumentContent>(initRequest, includeMediaGroups, errorFactory)
includeMediaGroups: Boolean
) = waitContent<DocumentContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitDocument(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
) = waitContent<DocumentContent>(initRequest, errorFactory)
@Deprecated(includeMediaGroupsDeprecationMessage)
suspend fun BehaviourContext.waitPhoto(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
includeMediaGroups: Boolean = false
) = waitContent<PhotoContent>(initRequest, includeMediaGroups, errorFactory)
includeMediaGroups: Boolean
) = waitContent<PhotoContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitPhoto(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
) = waitContent<PhotoContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitSticker(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }
) = waitContent<StickerContent>(initRequest, false, errorFactory)
) = waitContent<StickerContent>(initRequest, errorFactory)
@Deprecated(includeMediaGroupsDeprecationMessage)
suspend fun BehaviourContext.waitVideo(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
includeMediaGroups: Boolean = false
) = waitContent<VideoContent>(initRequest, includeMediaGroups, errorFactory)
includeMediaGroups: Boolean
) = waitContent<VideoContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitVideo(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }
) = waitContent<VideoContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitVideoNote(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }
) = waitContent<VideoNoteContent>(initRequest, false, errorFactory)
) = waitContent<VideoNoteContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitVoice(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }
) = waitContent<VoiceContent>(initRequest, false, errorFactory)
) = waitContent<VoiceContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitInvoice(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }
) = waitContent<InvoiceContent>(initRequest, false, errorFactory)
) = waitContent<InvoiceContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitVisualContent(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }
) = waitContent<VisualMediaGroupPartContent>(initRequest, errorFactory)

View File

@@ -13,17 +13,20 @@ import dev.inmo.tgbotapi.utils.RiskFeature
import dev.inmo.tgbotapi.utils.lowLevelRiskFeatureMessage
import kotlinx.coroutines.flow.Flow
const val includeMediaGroupsDeprecationMessage = "includeMediaGroups is deprecated and its usage will not lead to any changes"
typealias CommonMessageToCommonMessageMapper<T> = suspend CommonMessage<T>.() -> CommonMessage<T>?
@RiskFeature(lowLevelRiskFeatureMessage)
suspend inline fun <reified O : MessageContent> BehaviourContext.waitContentMessage(
initRequest: Request<*>? = null,
includeMediaGroups: Boolean = true,
noinline errorFactory: NullableRequestBuilder<*> = { null }
): Flow<CommonMessage<O>> = expectFlow(
initRequest,
errorFactory
) {
if (it !is BaseSentMessageUpdate) {
return@expectFlow emptyList()
}
listOfNotNull((it.data as? CommonMessage<*>) ?.withContent<O>())
}
@@ -44,114 +47,177 @@ internal inline fun <reified T : MessageContent> contentMessageConverter(
if (content is T) this as CommonMessage<T> else null
}
@Deprecated(
includeMediaGroupsDeprecationMessage,
ReplaceWith("waitAnyContentMessage(initRequest, errorFactory)", "dev.inmo.tgbotapi.extensions.behaviour_builder.expectations.waitAnyContentMessage")
)
suspend fun BehaviourContext.waitContentMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
includeMediaGroups: Boolean = true
) = waitContentMessage<MessageContent>(initRequest, includeMediaGroups, errorFactory)
includeMediaGroups: Boolean
) = waitContentMessage<MessageContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitAnyContentMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
) = waitContentMessage<MessageContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitContactMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }
) = waitContentMessage<ContactContent>(initRequest, false, errorFactory)
) = waitContentMessage<ContactContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitDiceMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }
) = waitContentMessage<DiceContent>(initRequest, false, errorFactory)
) = waitContentMessage<DiceContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitGameMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }
) = waitContentMessage<GameContent>(initRequest, false, errorFactory)
) = waitContentMessage<GameContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitLocationMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }
) = waitContentMessage<LocationContent>(initRequest, false, errorFactory)
) = waitContentMessage<LocationContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitLiveLocationMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }
) = waitContentMessage<LiveLocationContent>(initRequest, false, errorFactory)
) = waitContentMessage<LiveLocationContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitStaticLocationMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }
) = waitContentMessage<StaticLocationContent>(initRequest, false, errorFactory)
) = waitContentMessage<StaticLocationContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitPollMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }
) = waitContentMessage<PollContent>(initRequest, false, errorFactory)
) = waitContentMessage<PollContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitTextMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }
) = waitContentMessage<TextContent>(initRequest, false, errorFactory)
) = waitContentMessage<TextContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitVenueMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }
) = waitContentMessage<VenueContent>(initRequest, false, errorFactory)
) = waitContentMessage<VenueContent>(initRequest, errorFactory)
@Deprecated(includeMediaGroupsDeprecationMessage)
suspend fun BehaviourContext.waitAudioMediaGroupContentMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
includeMediaGroups: Boolean = true
) = waitContentMessage<AudioMediaGroupPartContent>(initRequest, includeMediaGroups, errorFactory)
includeMediaGroups: Boolean
) = waitContentMessage<AudioMediaGroupPartContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitAudioMediaGroupContentMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }
) = waitContentMessage<AudioMediaGroupPartContent>(initRequest, errorFactory)
@Deprecated(includeMediaGroupsDeprecationMessage)
suspend fun BehaviourContext.waitDocumentMediaGroupContentMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
includeMediaGroups: Boolean = true
) = waitContentMessage<DocumentMediaGroupPartContent>(initRequest, includeMediaGroups, errorFactory)
includeMediaGroups: Boolean
) = waitContentMessage<DocumentMediaGroupPartContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitDocumentMediaGroupContentMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }
) = waitContentMessage<DocumentMediaGroupPartContent>(initRequest, errorFactory)
@Deprecated(includeMediaGroupsDeprecationMessage)
suspend fun BehaviourContext.waitMediaMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
includeMediaGroups: Boolean = false
) = waitContentMessage<MediaContent>(initRequest, includeMediaGroups, errorFactory)
includeMediaGroups: Boolean
) = waitContentMessage<MediaContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitMediaMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }
) = waitContentMessage<MediaContent>(initRequest, errorFactory)
@Deprecated(includeMediaGroupsDeprecationMessage)
suspend fun BehaviourContext.waitAnyMediaGroupContentMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
includeMediaGroups: Boolean = true
) = waitContentMessage<MediaGroupPartContent>(initRequest, includeMediaGroups, errorFactory)
includeMediaGroups: Boolean
) = waitContentMessage<MediaGroupPartContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitAnyMediaGroupContentMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }
) = waitContentMessage<MediaGroupPartContent>(initRequest, errorFactory)
@Deprecated(includeMediaGroupsDeprecationMessage)
suspend fun BehaviourContext.waitVisualMediaGroupContentMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
includeMediaGroups: Boolean = true
) = waitContentMessage<VisualMediaGroupPartContent>(initRequest, includeMediaGroups, errorFactory)
includeMediaGroups: Boolean
) = waitContentMessage<VisualMediaGroupPartContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitVisualMediaGroupContentMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }
) = waitContentMessage<VisualMediaGroupPartContent>(initRequest, errorFactory)
@Deprecated(includeMediaGroupsDeprecationMessage)
suspend fun BehaviourContext.waitTextedMediaContentMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
includeMediaGroups: Boolean = true
) = waitContentMessage<TextedMediaContent>(initRequest, includeMediaGroups, errorFactory)
includeMediaGroups: Boolean
) = waitContentMessage<TextedMediaContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitTextedMediaContentMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }
) = waitContentMessage<TextedMediaContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitAnimationMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }
) = waitContentMessage<AnimationContent>(initRequest, false, errorFactory)
) = waitContentMessage<AnimationContent>(initRequest, errorFactory)
@Deprecated(includeMediaGroupsDeprecationMessage)
suspend fun BehaviourContext.waitAudioMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
includeMediaGroups: Boolean = false
) = waitContentMessage<AudioContent>(initRequest, includeMediaGroups, errorFactory)
includeMediaGroups: Boolean
) = waitContentMessage<AudioContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitAudioMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }
) = waitContentMessage<AudioContent>(initRequest, errorFactory)
@Deprecated(includeMediaGroupsDeprecationMessage)
suspend fun BehaviourContext.waitDocumentMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
includeMediaGroups: Boolean = false
) = waitContentMessage<DocumentContent>(initRequest, includeMediaGroups, errorFactory)
includeMediaGroups: Boolean
) = waitContentMessage<DocumentContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitDocumentMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }
) = waitContentMessage<DocumentContent>(initRequest, errorFactory)
@Deprecated(includeMediaGroupsDeprecationMessage)
suspend fun BehaviourContext.waitPhotoMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
includeMediaGroups: Boolean = false
) = waitContentMessage<PhotoContent>(initRequest, includeMediaGroups, errorFactory)
includeMediaGroups: Boolean
) = waitContentMessage<PhotoContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitPhotoMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }
) = waitContentMessage<PhotoContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitStickerMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }
) = waitContentMessage<StickerContent>(initRequest, false, errorFactory)
) = waitContentMessage<StickerContent>(initRequest, errorFactory)
@Deprecated(includeMediaGroupsDeprecationMessage)
suspend fun BehaviourContext.waitVideoMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
includeMediaGroups: Boolean = false
) = waitContentMessage<VideoContent>(initRequest, includeMediaGroups, errorFactory)
includeMediaGroups: Boolean
) = waitContentMessage<VideoContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitVideoMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }
) = waitContentMessage<VideoContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitVideoNoteMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }
) = waitContentMessage<VideoNoteContent>(initRequest, false, errorFactory)
) = waitContentMessage<VideoNoteContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitVoiceMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }
) = waitContentMessage<VoiceContent>(initRequest, false, errorFactory)
) = waitContentMessage<VoiceContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitInvoiceMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }
) = waitContentMessage<InvoiceContent>(initRequest, false, errorFactory)
) = waitContentMessage<InvoiceContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitVisualContentMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }
) = waitContentMessage<VisualMediaGroupPartContent>(initRequest, errorFactory)

View File

@@ -607,3 +607,27 @@ suspend fun <BC : BehaviourContext> BC.onInvoice(
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.onVisualContent(
initialFilter: CommonMessageFilter<VisualMediaGroupPartContent>? = null,
subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, VisualMediaGroupMessage, Update> = MessageFilterByChat,
markerFactory: MarkerFactory<in VisualMediaGroupMessage, Any> = ByChatMessageMarkerFactory,
scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, VisualMediaGroupMessage>
) = onContentMessageWithType(
initialFilter,
subcontextUpdatesFilter,
markerFactory,
scenarioReceiver
)

View File

@@ -14,6 +14,7 @@ import kotlinx.serialization.json.longOrNull
import kotlin.jvm.JvmInline
const val internalLinkBeginning = "https://t.me"
const val internalUserLinkBeginning = "tg://user?id="
@Serializable(ChatIdentifierSerializer::class)
@ClassCastsIncluded
@@ -66,15 +67,18 @@ fun IdChatIdentifier.toChatWithThreadId(threadId: MessageThreadId) = IdChatIdent
*/
@Warning("This API have restrictions in Telegram System")
val Identifier.userLink: String
get() = "tg://user?id=$this"
get() = "$internalUserLinkBeginning$this"
/**
* https://core.telegram.org/bots/api#formatting-options
*/
@Warning("This API have restrictions in Telegram System")
val UserId.userLink: String
get() = chatId.userLink
val User.link: String
val User.userLink: String
get() = id.userLink
@Deprecated("Deprecated due to the conflicts in name", ReplaceWith("this.userLink", "dev.inmo.tgbotapi.types.userLink"))
val User.link: String
get() = userLink
typealias UserId = ChatId

View File

@@ -2,16 +2,18 @@ package dev.inmo.tgbotapi.types.queries.callback
import dev.inmo.tgbotapi.abstracts.FromUser
import dev.inmo.tgbotapi.types.CallbackQueryIdentifier
import dev.inmo.tgbotapi.types.chat.CommonUser
import dev.inmo.tgbotapi.types.chat.User
sealed interface CallbackQuery : FromUser {
val id: CallbackQueryIdentifier
val chatInstance: String
override val from: CommonUser
}
data class UnknownCallbackQueryType(
override val id: CallbackQueryIdentifier,
override val from: User,
override val from: CommonUser,
override val chatInstance: String,
val raw: String
) : CallbackQuery

View File

@@ -1,11 +1,14 @@
package dev.inmo.tgbotapi.types.queries.callback
import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.chat.CommonUser
import dev.inmo.tgbotapi.types.chat.User
import kotlinx.serialization.Serializable
@Serializable
data class InlineMessageIdDataCallbackQuery(
override val id: CallbackQueryIdentifier,
override val from: User,
override val from: CommonUser,
override val chatInstance: String,
override val inlineMessageId: InlineMessageIdentifier,
override val data: String

View File

@@ -1,11 +1,12 @@
package dev.inmo.tgbotapi.types.queries.callback
import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.chat.CommonUser
import dev.inmo.tgbotapi.types.chat.User
data class InlineMessageIdGameShortNameCallbackQuery(
override val id: CallbackQueryIdentifier,
override val from: User,
override val from: CommonUser,
override val chatInstance: String,
override val inlineMessageId: InlineMessageIdentifier,
override val gameShortName: String

View File

@@ -1,13 +1,14 @@
package dev.inmo.tgbotapi.types.queries.callback
import dev.inmo.tgbotapi.types.CallbackQueryIdentifier
import dev.inmo.tgbotapi.types.chat.CommonUser
import dev.inmo.tgbotapi.types.chat.User
import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage
import dev.inmo.tgbotapi.types.message.content.MessageContent
data class MessageDataCallbackQuery(
override val id: CallbackQueryIdentifier,
override val from: User,
override val from: CommonUser,
override val chatInstance: String,
override val message: ContentMessage<MessageContent>,
override val data: String

View File

@@ -1,13 +1,14 @@
package dev.inmo.tgbotapi.types.queries.callback
import dev.inmo.tgbotapi.types.CallbackQueryIdentifier
import dev.inmo.tgbotapi.types.chat.CommonUser
import dev.inmo.tgbotapi.types.chat.User
import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage
import dev.inmo.tgbotapi.types.message.content.MessageContent
data class MessageGameShortNameCallbackQuery(
override val id: CallbackQueryIdentifier,
override val from: User,
override val from: CommonUser,
override val chatInstance: String,
override val message: ContentMessage<MessageContent>,
override val gameShortName: String

View File

@@ -1,6 +1,7 @@
package dev.inmo.tgbotapi.types.queries.callback
import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.chat.CommonUser
import dev.inmo.tgbotapi.types.chat.User
import dev.inmo.tgbotapi.types.message.abstracts.*
import dev.inmo.tgbotapi.types.message.abstracts.TelegramBotAPIMessageDeserializeOnlySerializer
@@ -13,7 +14,7 @@ internal data class RawCallbackQuery(
@SerialName(idField)
val id: CallbackQueryIdentifier,
@SerialName(fromField)
val from: User,
val from: CommonUser,
@Serializable(TelegramBotAPIMessageDeserializeOnlySerializer::class)
val message: ContentMessage<MessageContent>? = null,
@SerialName(inlineMessageIdField)

View File

@@ -1,6 +1,7 @@
package dev.inmo.tgbotapi.extensions.utils
import dev.inmo.tgbotapi.types.message.abstracts.*
import dev.inmo.tgbotapi.types.message.content.MediaGroupContent
import dev.inmo.tgbotapi.types.message.content.MessageContent
import kotlinx.coroutines.flow.*
@@ -34,3 +35,10 @@ fun <MC : MessageContent, M : ContentMessage<MC>> Flow<M>.onlySentViaBot() = map
fun <MC : MessageContent, M : ContentMessage<MC>> Flow<M>.withoutSentViaBot() = filter {
it !is PossiblySentViaBot || it.senderBot == null
}
/**
* Filter the messages and checking that incoming [ContentMessage.content] is not [MediaGroupContent]
*/
fun <MC : MessageContent, M : ContentMessage<MC>> Flow<M>.withoutMediaGroups() = filter {
it.content !is MediaGroupContent<*>
}

View File

@@ -8,6 +8,7 @@ import io.ktor.http.encodeURLQueryComponent
fun makeUsernameLink(username: String, threadId: MessageThreadId? = null) = "$internalLinkBeginning/$username${threadId ?.let { "/$it" } ?: ""}"
fun makeUserLink(userId: UserId) = userId.userLink
fun makeChatLink(identifier: Identifier, threadId: MessageThreadId? = null) = identifier.toString().replace(
linkIdRedundantPartRegex,
""
@@ -17,10 +18,16 @@ fun makeChatLink(identifier: Identifier, threadId: MessageThreadId? = null) = id
fun makeUsernameDeepLinkPrefix(username: String) = "${makeUsernameLink(username)}?start="
fun makeUsernameStartattachPrefix(username: String) = "$internalLinkBeginning/$username?startattach"
fun makeUsernameStartattachLink(username: String, data: String? = null) = "${makeUsernameStartattachPrefix(username)}${data?.let { "=$it" } ?: ""}"
inline val Username.link
inline val Username.usernameLink
get() = makeUsernameLink(usernameWithoutAt)
val IdChatIdentifier.link: String
@Deprecated("Deprecated due to the conflicts in name", ReplaceWith("this.usernameLink", "dev.inmo.tgbotapi.extensions.utils.formatting.usernameLink"))
inline val Username.link
get() = usernameLink
val IdChatIdentifier.chatLink: String
get() = makeChatLink(chatId, threadId)
@Deprecated("Deprecated due to the conflicts in name", ReplaceWith("this.chatLink", "dev.inmo.tgbotapi.extensions.utils.formatting.chatLink"))
val IdChatIdentifier.link: String
get() = chatLink
fun ChatId.link(threadId: MessageThreadId?) = makeChatLink(chatId, threadId)
inline fun Username.link(threadId: MessageThreadId?) = makeUsernameLink(usernameWithoutAt, threadId)
inline val Username.deepLinkPrefix
@@ -82,20 +89,27 @@ fun makeLinkToMessage(
/**
* @see makeLinkToMessage
*/
val Message.link: String?
val Message.messageLink: String?
get() = makeLinkToMessage(
chat,
messageId
)
/**
* @see makeLinkToMessage
*/
@Deprecated("Deprecated due to the conflicts in name", ReplaceWith("this.messageLink", "dev.inmo.tgbotapi.extensions.utils.formatting.messageLink"))
val Message.link: String?
get() = messageLink
/**
* Link which can be used as by any user to get access to [Chat]. Returns null in case when there are no
* known way to build link
*/
val Chat.link: String?
val Chat.chatLink: String?
get() {
if (this is UsernameChat) {
username ?.link ?: id.link
username ?.usernameLink ?: id.chatLink
}
if (this is ExtendedPublicChat) {
inviteLink ?.let { return it }
@@ -106,6 +120,14 @@ val Chat.link: String?
return null
}
/**
* Link which can be used as by any user to get access to [Chat]. Returns null in case when there are no
* known way to build link
*/
@Deprecated("Deprecated due to the conflicts in name", ReplaceWith("this.chatLink", "dev.inmo.tgbotapi.extensions.utils.formatting.chatLink"))
val Chat.link: String?
get() = chatLink
private const val stickerSetAddingLinkPrefix = "$internalLinkBeginning/addstickers"
val StickerSetName.stickerSetLink