From c5ada8cea00e12b2a9563524edcd2e2c5b8b159d Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Wed, 6 Jan 2021 15:41:27 +0600 Subject: [PATCH 01/66] start 0.30.13 --- CHANGELOG.md | 2 ++ gradle.properties | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f7077cac42..3653f96666 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ # TelegramBotAPI changelog +## 0.30.13 + ## 0.30.12 * `Utils`: diff --git a/gradle.properties b/gradle.properties index cba108e2dc..9da4219833 100644 --- a/gradle.properties +++ b/gradle.properties @@ -17,6 +17,6 @@ micro_utils_version=0.4.15 javax_activation_version=1.1.1 library_group=dev.inmo -library_version=0.30.12 +library_version=0.30.13 github_release_plugin_version=2.2.12 From 6bd423dc116aa4f87c8853524a0b2b6803585ae9 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Wed, 6 Jan 2021 19:05:48 +0600 Subject: [PATCH 02/66] class casts for ResendableContent and TextSource --- CHANGELOG.md | 4 + .../tgbotapi/extensions/utils/ClassCasts.kt | 202 ++++++++++++++++++ 2 files changed, 206 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3653f96666..6adfae5c17 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## 0.30.13 +* `Utils`: + * Extensions for `ResendableContent` has been added + * Extensions for `TextSource` has been added + ## 0.30.12 * `Utils`: diff --git a/tgbotapi.extensions.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/ClassCasts.kt b/tgbotapi.extensions.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/ClassCasts.kt index 4ce0fb76a7..86ce5a165c 100644 --- a/tgbotapi.extensions.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/ClassCasts.kt +++ b/tgbotapi.extensions.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/ClassCasts.kt @@ -40,6 +40,48 @@ import dev.inmo.tgbotapi.types.update.* import dev.inmo.tgbotapi.types.update.MediaGroupUpdates.* import dev.inmo.tgbotapi.types.update.abstracts.* import dev.inmo.tgbotapi.utils.PreviewFeature +import dev.inmo.tgbotapi.types.message.content.abstracts.ResendableContent +import dev.inmo.tgbotapi.types.message.content.ContactContent +import dev.inmo.tgbotapi.types.message.content.DiceContent +import dev.inmo.tgbotapi.types.message.content.GameContent +import dev.inmo.tgbotapi.types.message.content.LocationContent +import dev.inmo.tgbotapi.types.message.content.PollContent +import dev.inmo.tgbotapi.types.message.content.TextContent +import dev.inmo.tgbotapi.types.message.content.VenueContent +import dev.inmo.tgbotapi.types.message.content.abstracts.AudioMediaGroupContent +import dev.inmo.tgbotapi.types.message.content.abstracts.DocumentMediaGroupContent +import dev.inmo.tgbotapi.types.message.content.abstracts.MediaCollectionContent +import dev.inmo.tgbotapi.types.files.abstracts.TelegramMediaFile +import dev.inmo.tgbotapi.types.message.content.abstracts.MediaContent +import dev.inmo.tgbotapi.types.message.content.abstracts.MediaGroupContent +import dev.inmo.tgbotapi.types.message.content.abstracts.VisualMediaGroupContent +import dev.inmo.tgbotapi.types.message.content.media.AnimationContent +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.PhotoContent +import dev.inmo.tgbotapi.types.message.content.media.StickerContent +import dev.inmo.tgbotapi.types.message.content.media.VideoContent +import dev.inmo.tgbotapi.types.message.content.media.VideoNoteContent +import dev.inmo.tgbotapi.types.message.content.media.VoiceContent +import dev.inmo.tgbotapi.types.message.payments.InvoiceContent +import dev.inmo.tgbotapi.CommonAbstracts.TextSource +import dev.inmo.tgbotapi.CommonAbstracts.MultilevelTextSource +import dev.inmo.tgbotapi.types.MessageEntity.textsources.BoldTextSource +import dev.inmo.tgbotapi.types.MessageEntity.textsources.BotCommandTextSource +import dev.inmo.tgbotapi.types.MessageEntity.textsources.CashTagTextSource +import dev.inmo.tgbotapi.types.MessageEntity.textsources.CodeTextSource +import dev.inmo.tgbotapi.types.MessageEntity.textsources.EMailTextSource +import dev.inmo.tgbotapi.types.MessageEntity.textsources.HashTagTextSource +import dev.inmo.tgbotapi.types.MessageEntity.textsources.ItalicTextSource +import dev.inmo.tgbotapi.types.MessageEntity.textsources.MentionTextSource +import dev.inmo.tgbotapi.types.MessageEntity.textsources.PhoneNumberTextSource +import dev.inmo.tgbotapi.types.MessageEntity.textsources.PreTextSource +import dev.inmo.tgbotapi.types.MessageEntity.textsources.RegularTextSource +import dev.inmo.tgbotapi.types.MessageEntity.textsources.StrikethroughTextSource +import dev.inmo.tgbotapi.types.MessageEntity.textsources.TextLinkTextSource +import dev.inmo.tgbotapi.types.MessageEntity.textsources.TextMentionTextSource +import dev.inmo.tgbotapi.types.MessageEntity.textsources.URLTextSource +import dev.inmo.tgbotapi.types.MessageEntity.textsources.UnderlineTextSource @PreviewFeature inline fun Chat.asBot(): Bot? = this as? Bot @@ -753,3 +795,163 @@ inline fun Poll.requireRegularPoll(): RegularPoll = this as RegularPoll inline fun Poll.asUnknownPollType(): UnknownPollType? = this as? UnknownPollType @PreviewFeature inline fun Poll.requireUnknownPollType(): UnknownPollType = this as UnknownPollType +@PreviewFeature +inline fun ResendableContent.asContactContent(): ContactContent? = this as? ContactContent +@PreviewFeature +inline fun ResendableContent.requireContactContent(): ContactContent = this as ContactContent +@PreviewFeature +inline fun ResendableContent.asDiceContent(): DiceContent? = this as? DiceContent +@PreviewFeature +inline fun ResendableContent.requireDiceContent(): DiceContent = this as DiceContent +@PreviewFeature +inline fun ResendableContent.asGameContent(): GameContent? = this as? GameContent +@PreviewFeature +inline fun ResendableContent.requireGameContent(): GameContent = this as GameContent +@PreviewFeature +inline fun ResendableContent.asLocationContent(): LocationContent? = this as? LocationContent +@PreviewFeature +inline fun ResendableContent.requireLocationContent(): LocationContent = this as LocationContent +@PreviewFeature +inline fun ResendableContent.asPollContent(): PollContent? = this as? PollContent +@PreviewFeature +inline fun ResendableContent.requirePollContent(): PollContent = this as PollContent +@PreviewFeature +inline fun ResendableContent.asTextContent(): TextContent? = this as? TextContent +@PreviewFeature +inline fun ResendableContent.requireTextContent(): TextContent = this as TextContent +@PreviewFeature +inline fun ResendableContent.asVenueContent(): VenueContent? = this as? VenueContent +@PreviewFeature +inline fun ResendableContent.requireVenueContent(): VenueContent = this as VenueContent +@PreviewFeature +inline fun ResendableContent.asAudioMediaGroupContent(): AudioMediaGroupContent? = this as? AudioMediaGroupContent +@PreviewFeature +inline fun ResendableContent.requireAudioMediaGroupContent(): AudioMediaGroupContent = this as AudioMediaGroupContent +@PreviewFeature +inline fun ResendableContent.asDocumentMediaGroupContent(): DocumentMediaGroupContent? = this as? DocumentMediaGroupContent +@PreviewFeature +inline fun ResendableContent.requireDocumentMediaGroupContent(): DocumentMediaGroupContent = this as DocumentMediaGroupContent +@PreviewFeature +inline fun ResendableContent.asMediaCollectionContent(): MediaCollectionContent? = this as? MediaCollectionContent +@PreviewFeature +inline fun ResendableContent.requireMediaCollectionContent(): MediaCollectionContent = this as MediaCollectionContent +@PreviewFeature +inline fun ResendableContent.asMediaContent(): MediaContent? = this as? MediaContent +@PreviewFeature +inline fun ResendableContent.requireMediaContent(): MediaContent = this as MediaContent +@PreviewFeature +inline fun ResendableContent.asMediaGroupContent(): MediaGroupContent? = this as? MediaGroupContent +@PreviewFeature +inline fun ResendableContent.requireMediaGroupContent(): MediaGroupContent = this as MediaGroupContent +@PreviewFeature +inline fun ResendableContent.asMessageContent(): MessageContent? = this as? MessageContent +@PreviewFeature +inline fun ResendableContent.requireMessageContent(): MessageContent = this as MessageContent +@PreviewFeature +inline fun ResendableContent.asVisualMediaGroupContent(): VisualMediaGroupContent? = this as? VisualMediaGroupContent +@PreviewFeature +inline fun ResendableContent.requireVisualMediaGroupContent(): VisualMediaGroupContent = this as VisualMediaGroupContent +@PreviewFeature +inline fun ResendableContent.asAnimationContent(): AnimationContent? = this as? AnimationContent +@PreviewFeature +inline fun ResendableContent.requireAnimationContent(): AnimationContent = this as AnimationContent +@PreviewFeature +inline fun ResendableContent.asAudioContent(): AudioContent? = this as? AudioContent +@PreviewFeature +inline fun ResendableContent.requireAudioContent(): AudioContent = this as AudioContent +@PreviewFeature +inline fun ResendableContent.asDocumentContent(): DocumentContent? = this as? DocumentContent +@PreviewFeature +inline fun ResendableContent.requireDocumentContent(): DocumentContent = this as DocumentContent +@PreviewFeature +inline fun ResendableContent.asPhotoContent(): PhotoContent? = this as? PhotoContent +@PreviewFeature +inline fun ResendableContent.requirePhotoContent(): PhotoContent = this as PhotoContent +@PreviewFeature +inline fun ResendableContent.asStickerContent(): StickerContent? = this as? StickerContent +@PreviewFeature +inline fun ResendableContent.requireStickerContent(): StickerContent = this as StickerContent +@PreviewFeature +inline fun ResendableContent.asVideoContent(): VideoContent? = this as? VideoContent +@PreviewFeature +inline fun ResendableContent.requireVideoContent(): VideoContent = this as VideoContent +@PreviewFeature +inline fun ResendableContent.asVideoNoteContent(): VideoNoteContent? = this as? VideoNoteContent +@PreviewFeature +inline fun ResendableContent.requireVideoNoteContent(): VideoNoteContent = this as VideoNoteContent +@PreviewFeature +inline fun ResendableContent.asVoiceContent(): VoiceContent? = this as? VoiceContent +@PreviewFeature +inline fun ResendableContent.requireVoiceContent(): VoiceContent = this as VoiceContent +@PreviewFeature +inline fun ResendableContent.asInvoiceContent(): InvoiceContent? = this as? InvoiceContent +@PreviewFeature +inline fun ResendableContent.requireInvoiceContent(): InvoiceContent = this as InvoiceContent +@PreviewFeature +inline fun TextSource.asMultilevelTextSource(): MultilevelTextSource? = this as? MultilevelTextSource +@PreviewFeature +inline fun TextSource.requireMultilevelTextSource(): MultilevelTextSource = this as MultilevelTextSource +@PreviewFeature +inline fun TextSource.asBoldTextSource(): BoldTextSource? = this as? BoldTextSource +@PreviewFeature +inline fun TextSource.requireBoldTextSource(): BoldTextSource = this as BoldTextSource +@PreviewFeature +inline fun TextSource.asBotCommandTextSource(): BotCommandTextSource? = this as? BotCommandTextSource +@PreviewFeature +inline fun TextSource.requireBotCommandTextSource(): BotCommandTextSource = this as BotCommandTextSource +@PreviewFeature +inline fun TextSource.asCashTagTextSource(): CashTagTextSource? = this as? CashTagTextSource +@PreviewFeature +inline fun TextSource.requireCashTagTextSource(): CashTagTextSource = this as CashTagTextSource +@PreviewFeature +inline fun TextSource.asCodeTextSource(): CodeTextSource? = this as? CodeTextSource +@PreviewFeature +inline fun TextSource.requireCodeTextSource(): CodeTextSource = this as CodeTextSource +@PreviewFeature +inline fun TextSource.asEMailTextSource(): EMailTextSource? = this as? EMailTextSource +@PreviewFeature +inline fun TextSource.requireEMailTextSource(): EMailTextSource = this as EMailTextSource +@PreviewFeature +inline fun TextSource.asHashTagTextSource(): HashTagTextSource? = this as? HashTagTextSource +@PreviewFeature +inline fun TextSource.requireHashTagTextSource(): HashTagTextSource = this as HashTagTextSource +@PreviewFeature +inline fun TextSource.asItalicTextSource(): ItalicTextSource? = this as? ItalicTextSource +@PreviewFeature +inline fun TextSource.requireItalicTextSource(): ItalicTextSource = this as ItalicTextSource +@PreviewFeature +inline fun TextSource.asMentionTextSource(): MentionTextSource? = this as? MentionTextSource +@PreviewFeature +inline fun TextSource.requireMentionTextSource(): MentionTextSource = this as MentionTextSource +@PreviewFeature +inline fun TextSource.asPhoneNumberTextSource(): PhoneNumberTextSource? = this as? PhoneNumberTextSource +@PreviewFeature +inline fun TextSource.requirePhoneNumberTextSource(): PhoneNumberTextSource = this as PhoneNumberTextSource +@PreviewFeature +inline fun TextSource.asPreTextSource(): PreTextSource? = this as? PreTextSource +@PreviewFeature +inline fun TextSource.requirePreTextSource(): PreTextSource = this as PreTextSource +@PreviewFeature +inline fun TextSource.asRegularTextSource(): RegularTextSource? = this as? RegularTextSource +@PreviewFeature +inline fun TextSource.requireRegularTextSource(): RegularTextSource = this as RegularTextSource +@PreviewFeature +inline fun TextSource.asStrikethroughTextSource(): StrikethroughTextSource? = this as? StrikethroughTextSource +@PreviewFeature +inline fun TextSource.requireStrikethroughTextSource(): StrikethroughTextSource = this as StrikethroughTextSource +@PreviewFeature +inline fun TextSource.asTextLinkTextSource(): TextLinkTextSource? = this as? TextLinkTextSource +@PreviewFeature +inline fun TextSource.requireTextLinkTextSource(): TextLinkTextSource = this as TextLinkTextSource +@PreviewFeature +inline fun TextSource.asTextMentionTextSource(): TextMentionTextSource? = this as? TextMentionTextSource +@PreviewFeature +inline fun TextSource.requireTextMentionTextSource(): TextMentionTextSource = this as TextMentionTextSource +@PreviewFeature +inline fun TextSource.asURLTextSource(): URLTextSource? = this as? URLTextSource +@PreviewFeature +inline fun TextSource.requireURLTextSource(): URLTextSource = this as URLTextSource +@PreviewFeature +inline fun TextSource.asUnderlineTextSource(): UnderlineTextSource? = this as? UnderlineTextSource +@PreviewFeature +inline fun TextSource.requireUnderlineTextSource(): UnderlineTextSource = this as UnderlineTextSource From 00873a255ca3f9821f06755468776a1547299ab1 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Wed, 6 Jan 2021 23:06:48 +0600 Subject: [PATCH 03/66] preview state of steps --- settings.gradle | 1 + .../inmo/tgbotapi/CommonAbstracts/Texted.kt | 6 +- tgbotapi.extensions.steps/README.md | 1 + tgbotapi.extensions.steps/build.gradle | 48 +++++ .../mpp_publish_template.kpsb | 1 + tgbotapi.extensions.steps/publish.gradle | 69 +++++++ .../tgbotapi/extensions/steps/Scenario.kt | 16 ++ .../extensions/steps/ScenarioBuilders.kt | 17 ++ .../extensions/steps/expectations/Base.kt | 80 ++++++++ .../steps/expectations/WaitContent.kt | 175 ++++++++++++++++++ .../triggers_handling/CommandHandling.kt | 37 ++++ 11 files changed, 450 insertions(+), 1 deletion(-) create mode 100644 tgbotapi.extensions.steps/README.md create mode 100644 tgbotapi.extensions.steps/build.gradle create mode 100644 tgbotapi.extensions.steps/mpp_publish_template.kpsb create mode 100644 tgbotapi.extensions.steps/publish.gradle create mode 100644 tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/Scenario.kt create mode 100644 tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/ScenarioBuilders.kt create mode 100644 tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/expectations/Base.kt create mode 100644 tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/expectations/WaitContent.kt create mode 100644 tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/triggers_handling/CommandHandling.kt diff --git a/settings.gradle b/settings.gradle index f765964ad9..9ef11db508 100644 --- a/settings.gradle +++ b/settings.gradle @@ -8,5 +8,6 @@ pluginManagement { include ":tgbotapi.core" include ":tgbotapi.extensions.api" include ":tgbotapi.extensions.utils" +include ":tgbotapi.extensions.steps" include ":tgbotapi" include ":docs" diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/CommonAbstracts/Texted.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/CommonAbstracts/Texted.kt index 4ff32e73de..afd4ac6dec 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/CommonAbstracts/Texted.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/CommonAbstracts/Texted.kt @@ -19,13 +19,17 @@ interface TextedOutput : ParsableOutput, EntitiesOutput interface TextedInput : Texted { /** - * Not full list of entities. This list WILL NOT contain [TextPart]s with [dev.inmo.tgbotapi.types.MessageEntity.textsources.RegularTextSource] + * Here must be full list of entities. This list must contains [TextPart]s with + * [dev.inmo.tgbotapi.types.MessageEntity.textsources.RegularTextSource] in case if source text contains parts of + * regular text * @see [CaptionedInput.fullEntitiesList] */ val textEntities: List } /** + * Full list of [TextSource] built from source[TextedInput.textEntities] + * * @see TextedInput.textEntities * @see justTextSources */ diff --git a/tgbotapi.extensions.steps/README.md b/tgbotapi.extensions.steps/README.md new file mode 100644 index 0000000000..1d7622f9eb --- /dev/null +++ b/tgbotapi.extensions.steps/README.md @@ -0,0 +1 @@ +# TelegramBotAPI Steps Extensions diff --git a/tgbotapi.extensions.steps/build.gradle b/tgbotapi.extensions.steps/build.gradle new file mode 100644 index 0000000000..c8bd96a0f6 --- /dev/null +++ b/tgbotapi.extensions.steps/build.gradle @@ -0,0 +1,48 @@ +buildscript { + repositories { + mavenLocal() + jcenter() + mavenCentral() + } + + dependencies { + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version" + } +} + +plugins { + id "org.jetbrains.kotlin.multiplatform" + id "org.jetbrains.kotlin.plugin.serialization" +} + +project.version = "$library_version" +project.group = "$library_group" + +apply from: "publish.gradle" + +repositories { + mavenLocal() + jcenter() + mavenCentral() + maven { url "https://kotlin.bintray.com/kotlinx" } +} + +kotlin { + jvm() + js(BOTH) { + browser() + nodejs() + } + + sourceSets { + commonMain { + dependencies { + implementation kotlin('stdlib') + api project(":tgbotapi.core") + api project(":tgbotapi.extensions.utils") + api project(":tgbotapi.extensions.api") + } + } + } +} diff --git a/tgbotapi.extensions.steps/mpp_publish_template.kpsb b/tgbotapi.extensions.steps/mpp_publish_template.kpsb new file mode 100644 index 0000000000..4cd88bd29b --- /dev/null +++ b/tgbotapi.extensions.steps/mpp_publish_template.kpsb @@ -0,0 +1 @@ +{"bintrayConfig":{"repo":"TelegramBotAPI","packageName":"${project.name}","packageVcs":"https://github.com/InsanusMokrassar/TelegramBotAPI","autoPublish":true,"overridePublish":true},"licenses":[{"id":"Apache-2.0","title":"Apache Software License 2.0","url":"https://github.com/InsanusMokrassar/TelegramBotAPI/blob/master/LICENSE"}],"mavenConfig":{"name":"Telegram Bot API Steps Extensions","description":"These extensions project contains tools for simple interaction with chats","url":"https://insanusmokrassar.github.io/TelegramBotAPI/tgbotapi.extensions.steps","vcsUrl":"https://github.com/insanusmokrassar/TelegramBotAPI.git","developers":[{"id":"InsanusMokrassar","name":"Ovsiannikov Aleksei","eMail":"ovsyannikov.alexey95@gmail.com"}]}} \ No newline at end of file diff --git a/tgbotapi.extensions.steps/publish.gradle b/tgbotapi.extensions.steps/publish.gradle new file mode 100644 index 0000000000..00c1e2ab01 --- /dev/null +++ b/tgbotapi.extensions.steps/publish.gradle @@ -0,0 +1,69 @@ +apply plugin: 'maven-publish' + +task javadocsJar(type: Jar) { + classifier = 'javadoc' +} +task sourceJar (type : Jar) { + classifier = 'sources' +} + +afterEvaluate { + project.publishing.publications.all { + // rename artifacts + groupId "${project.group}" + if (it.name.contains('kotlinMultiplatform')) { + artifactId = "${project.name}" + artifact sourceJar + } else { + artifactId = "${project.name}-$name" + } + } +} + +publishing { + publications.all { + artifact javadocsJar + + pom { + description = "These extensions project contains tools for simple interaction with chats" + name = "Telegram Bot API Steps Extensions" + url = "https://insanusmokrassar.github.io/TelegramBotAPI/tgbotapi.extensions.steps" + + scm { + developerConnection = "scm:git:[fetch=]https://github.com/insanusmokrassar/TelegramBotAPI.git[push=]https://github.com/insanusmokrassar/TelegramBotAPI.git" + url = "https://github.com/insanusmokrassar/TelegramBotAPI.git" + } + + 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 { + maven { + name = "bintray" + url = uri("https://api.bintray.com/maven/${project.hasProperty('BINTRAY_USER') ? project.property('BINTRAY_USER') : System.getenv('BINTRAY_USER')}/TelegramBotAPI/${project.name}/;publish=1;override=1") + credentials { + username = project.hasProperty('BINTRAY_USER') ? project.property('BINTRAY_USER') : System.getenv('BINTRAY_USER') + password = project.hasProperty('BINTRAY_KEY') ? project.property('BINTRAY_KEY') : System.getenv('BINTRAY_KEY') + } + } + } + + } +} \ No newline at end of file diff --git a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/Scenario.kt b/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/Scenario.kt new file mode 100644 index 0000000000..9524c459d1 --- /dev/null +++ b/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/Scenario.kt @@ -0,0 +1,16 @@ +package dev.inmo.tgbotapi.extensions.steps + +import dev.inmo.tgbotapi.bot.TelegramBot +import dev.inmo.tgbotapi.updateshandlers.FlowsUpdatesFilter +import kotlinx.coroutines.CoroutineScope + +typealias ScenarioReceiver = suspend Scenario.() -> T +typealias ScenarioAndTypeReceiver = suspend Scenario.(I) -> T + +data class Scenario( + val bot: TelegramBot, + val flowsUpdatesFilter: FlowsUpdatesFilter, + val scope: CoroutineScope +) + + diff --git a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/ScenarioBuilders.kt b/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/ScenarioBuilders.kt new file mode 100644 index 0000000000..c5a1001dbd --- /dev/null +++ b/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/ScenarioBuilders.kt @@ -0,0 +1,17 @@ +package dev.inmo.tgbotapi.extensions.steps + +import dev.inmo.tgbotapi.bot.TelegramBot +import dev.inmo.tgbotapi.updateshandlers.FlowsUpdatesFilter +import kotlinx.coroutines.CoroutineScope + +suspend fun TelegramBot.buildScenarios( + scope: CoroutineScope, + flowUpdatesFilter: FlowsUpdatesFilter = FlowsUpdatesFilter(), + block: ScenarioReceiver +) { + Scenario( + this, + flowUpdatesFilter, + scope + ).block() +} diff --git a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/expectations/Base.kt b/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/expectations/Base.kt new file mode 100644 index 0000000000..63162ef7e5 --- /dev/null +++ b/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/expectations/Base.kt @@ -0,0 +1,80 @@ +package dev.inmo.tgbotapi.extensions.steps.expectations + +import dev.inmo.micro_utils.coroutines.safelyWithoutExceptions +import dev.inmo.tgbotapi.bot.TelegramBot +import dev.inmo.tgbotapi.extensions.steps.Scenario +import dev.inmo.tgbotapi.extensions.steps.ScenarioReceiver +import dev.inmo.tgbotapi.requests.abstracts.Request +import dev.inmo.tgbotapi.types.update.abstracts.Update +import dev.inmo.tgbotapi.updateshandlers.FlowsUpdatesFilter +import dev.inmo.tgbotapi.utils.RiskFeature +import kotlinx.coroutines.* +import kotlinx.coroutines.flow.* + +private val cancelledByFilterException = CancellationException("Cancelled by filter precreatedException") + +typealias RequestBuilder = suspend (Update) -> Request +typealias NullableRequestBuilder = suspend (Update) -> Request? + +@RiskFeature("This method is not very comfortable to use and too low-level. It is recommended to use methods which already included into library") +suspend fun FlowsUpdatesFilter.expectFlow( + bot: TelegramBot, + initRequest: Request<*>? = null, + count: Int? = null, + errorFactory: NullableRequestBuilder<*> = { null }, + cancelRequestFactory: NullableRequestBuilder<*> = { null }, + cancelTrigger: suspend (Update) -> Boolean = { cancelRequestFactory(it) != null }, + filter: suspend (Update) -> T? +): Flow { + val flow = allUpdatesFlow.mapNotNull { + val result = safelyWithoutExceptions { filter(it) } + if (result == null) { + if (cancelTrigger(it)) { + cancelRequestFactory(it) ?.also { + safelyWithoutExceptions { bot.execute(it) } + throw cancelledByFilterException + } + } + errorFactory(it) ?.also { errorRequest -> + safelyWithoutExceptions { bot.execute(errorRequest) } + } + null + } else { + result + } + } + val result = if (count == null) { + flow + } else { + flow.take(count) + } + initRequest ?.also { safelyWithoutExceptions { bot.execute(initRequest) } } + return result +} + +suspend fun Scenario.expectFlow( + initRequest: Request<*>? = null, + count: Int? = null, + errorFactory: NullableRequestBuilder<*> = { null }, + cancelRequestFactory: NullableRequestBuilder<*> = { null }, + cancelTrigger: suspend (Update) -> Boolean = { cancelRequestFactory(it) != null }, + filter: suspend (Update) -> T? +) = flowsUpdatesFilter.expectFlow(bot, initRequest, count, errorFactory, cancelRequestFactory, cancelTrigger, filter) + +@RiskFeature("This method is not very comfortable to use and too low-level. It is recommended to use methods which already included into library") +suspend fun FlowsUpdatesFilter.expectOne( + bot: TelegramBot, + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null }, + cancelRequestFactory: NullableRequestBuilder<*> = { null }, + cancelTrigger: suspend (Update) -> Boolean = { cancelRequestFactory(it) != null }, + filter: suspend (Update) -> T?, +): T = expectFlow(bot, initRequest, 1, errorFactory, cancelRequestFactory, cancelTrigger, filter).first() + +suspend fun Scenario.expectOne( + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null }, + cancelRequestFactory: NullableRequestBuilder<*> = { null }, + cancelTrigger: suspend (Update) -> Boolean = { cancelRequestFactory(it) != null }, + filter: suspend (Update) -> T? +) = flowsUpdatesFilter.expectOne(bot, initRequest, errorFactory, cancelRequestFactory, cancelTrigger, filter) diff --git a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/expectations/WaitContent.kt b/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/expectations/WaitContent.kt new file mode 100644 index 0000000000..928856fe5b --- /dev/null +++ b/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/expectations/WaitContent.kt @@ -0,0 +1,175 @@ +package dev.inmo.tgbotapi.extensions.steps.expectations + +import dev.inmo.tgbotapi.extensions.steps.Scenario +import dev.inmo.tgbotapi.extensions.utils.* +import dev.inmo.tgbotapi.requests.abstracts.Request +import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage +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.payments.InvoiceContent +import kotlinx.coroutines.flow.toList + +typealias ContentMessageToContentMapper = suspend ContentMessage.() -> T? + +private suspend fun Scenario.waitContentMessage( + count: Int = 1, + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null }, + mapper: suspend ContentMessage.() -> O? +): List = expectFlow( + initRequest, + count, + errorFactory +) { + it.asMessageUpdate() ?.data ?.asContentMessage() ?.mapper() +}.toList().toList() + +private suspend inline fun Scenario.waitContent( + count: Int = 1, + initRequest: Request<*>? = null, + noinline errorFactory: NullableRequestBuilder<*> = { null }, + noinline filter: (suspend (ContentMessage) -> T?)? = null +) : List = waitContentMessage( + count, + initRequest, + errorFactory +) { + if (content is T) { + val message = (this as ContentMessage) + if (filter == null) { + message.content + } else { + filter(message) + } + } else { + null + } +} + +suspend fun Scenario.waitContact( + count: Int = 1, + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null }, + filter: ContentMessageToContentMapper? = null +) = waitContent(count, initRequest, errorFactory, filter) +suspend fun Scenario.waitDice( + count: Int = 1, + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null }, + filter: ContentMessageToContentMapper? = null +) = waitContent(count, initRequest, errorFactory, filter) +suspend fun Scenario.waitGame( + count: Int = 1, + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null }, + filter: ContentMessageToContentMapper? = null +) = waitContent(count, initRequest, errorFactory, filter) +suspend fun Scenario.waitLocation( + count: Int = 1, + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null }, + filter: ContentMessageToContentMapper? = null +) = waitContent(count, initRequest, errorFactory, filter) +suspend fun Scenario.waitPoll( + count: Int = 1, + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null }, + filter: ContentMessageToContentMapper? = null +) = waitContent(count, initRequest, errorFactory, filter) +suspend fun Scenario.waitText( + count: Int = 1, + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null }, + filter: ContentMessageToContentMapper? = null +) = waitContent(count, initRequest, errorFactory, filter) +suspend fun Scenario.waitVenue( + count: Int = 1, + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null }, + filter: ContentMessageToContentMapper? = null +) = waitContent(count, initRequest, errorFactory, filter) +suspend fun Scenario.waitAudioMediaGroup( + count: Int = 1, + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null }, + filter: ContentMessageToContentMapper? = null +) = waitContent(count, initRequest, errorFactory, filter) +suspend fun Scenario.waitDocumentMediaGroup( + count: Int = 1, + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null }, + filter: ContentMessageToContentMapper? = null +) = waitContent(count, initRequest, errorFactory, filter) +suspend fun Scenario.waitMedia( + count: Int = 1, + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null }, + filter: ContentMessageToContentMapper? = null +) = waitContent(count, initRequest, errorFactory, filter) +suspend fun Scenario.waitMediaGroup( + count: Int = 1, + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null }, + filter: ContentMessageToContentMapper? = null +) = waitContent(count, initRequest, errorFactory, filter) +suspend fun Scenario.waitVisualMediaGroup( + count: Int = 1, + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null }, + filter: ContentMessageToContentMapper? = null +) = waitContent(count, initRequest, errorFactory, filter) +suspend fun Scenario.waitAnimation( + count: Int = 1, + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null }, + filter: ContentMessageToContentMapper? = null +) = waitContent(count, initRequest, errorFactory, filter) +suspend fun Scenario.waitAudio( + count: Int = 1, + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null }, + filter: ContentMessageToContentMapper? = null +) = waitContent(count, initRequest, errorFactory, filter) +suspend fun Scenario.waitDocument( + count: Int = 1, + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null }, + filter: ContentMessageToContentMapper? = null +) = waitContent(count, initRequest, errorFactory, filter) +suspend fun Scenario.waitPhoto( + count: Int = 1, + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null }, + filter: ContentMessageToContentMapper? = null +) = waitContent(count, initRequest, errorFactory, filter) +suspend fun Scenario.waitSticker( + count: Int = 1, + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null }, + filter: ContentMessageToContentMapper? = null +) = waitContent(count, initRequest, errorFactory, filter) +suspend fun Scenario.waitVideo( + count: Int = 1, + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null }, + filter: ContentMessageToContentMapper? = null +) = waitContent(count, initRequest, errorFactory, filter) +suspend fun Scenario.waitVideoNote( + count: Int = 1, + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null }, + filter: ContentMessageToContentMapper? = null +) = waitContent(count, initRequest, errorFactory, filter) +suspend fun Scenario.waitVoice( + count: Int = 1, + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null }, + filter: ContentMessageToContentMapper? = null +) = waitContent(count, initRequest, errorFactory, filter) +suspend fun Scenario.waitInvoice( + count: Int = 1, + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null }, + filter: ContentMessageToContentMapper? = null +) = waitContent(count, initRequest, errorFactory, filter) diff --git a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/triggers_handling/CommandHandling.kt b/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/triggers_handling/CommandHandling.kt new file mode 100644 index 0000000000..ed12c1daa9 --- /dev/null +++ b/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/triggers_handling/CommandHandling.kt @@ -0,0 +1,37 @@ +package dev.inmo.tgbotapi.extensions.steps.triggers_handling + +import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions +import dev.inmo.tgbotapi.CommonAbstracts.textSources +import dev.inmo.tgbotapi.extensions.steps.* +import dev.inmo.tgbotapi.extensions.steps.expectations.expectFlow +import dev.inmo.tgbotapi.extensions.utils.* +import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage +import dev.inmo.tgbotapi.types.message.content.TextContent + +suspend fun Scenario.command( + commandRegex: Regex, + requireOnlyCommandInMessage: Boolean = true, + scenarioReceiver: ScenarioAndTypeReceiver> +) { + flowsUpdatesFilter.expectFlow(bot) { + it.asMessageUpdate() ?.data ?.asContentMessage() ?.let { message -> + message.content.asTextContent() ?.let { + val textSources = it.textSources + val sizeRequirement = if (requireOnlyCommandInMessage) { + textSources.size == 1 + } else { + true + } + if (sizeRequirement && textSources.any { commandRegex.matches(it.asBotCommandTextSource() ?.command ?: return@any false) }) { + message as ContentMessage + } else { + null + } + } + } + }.subscribeSafelyWithoutExceptions(scope) { + scenarioReceiver(it) + } +} + + From 30e6f682287a5fbd2b10476f627f55352dddfbda Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Wed, 6 Jan 2021 23:21:33 +0600 Subject: [PATCH 04/66] small update of scenarios --- .../tgbotapi/extensions/steps/Scenario.kt | 6 ++--- .../extensions/steps/ScenarioBuilders.kt | 23 ++++++++++++++++--- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/Scenario.kt b/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/Scenario.kt index 9524c459d1..9d34dee99f 100644 --- a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/Scenario.kt +++ b/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/Scenario.kt @@ -9,8 +9,6 @@ typealias ScenarioAndTypeReceiver = suspend Scenario.(I) -> T data class Scenario( val bot: TelegramBot, - val flowsUpdatesFilter: FlowsUpdatesFilter, - val scope: CoroutineScope + val scope: CoroutineScope, + val flowsUpdatesFilter: FlowsUpdatesFilter = FlowsUpdatesFilter() ) - - diff --git a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/ScenarioBuilders.kt b/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/ScenarioBuilders.kt index c5a1001dbd..23cdbb4bd5 100644 --- a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/ScenarioBuilders.kt +++ b/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/ScenarioBuilders.kt @@ -1,17 +1,34 @@ package dev.inmo.tgbotapi.extensions.steps import dev.inmo.tgbotapi.bot.TelegramBot +import dev.inmo.tgbotapi.extensions.utils.updates.retrieving.startGettingFlowsUpdatesByLongPolling +import dev.inmo.tgbotapi.extensions.utils.updates.retrieving.startGettingOfUpdatesByLongPolling import dev.inmo.tgbotapi.updateshandlers.FlowsUpdatesFilter import kotlinx.coroutines.CoroutineScope suspend fun TelegramBot.buildScenarios( scope: CoroutineScope, - flowUpdatesFilter: FlowsUpdatesFilter = FlowsUpdatesFilter(), + flowUpdatesFilter: FlowsUpdatesFilter, block: ScenarioReceiver ) { Scenario( this, - flowUpdatesFilter, - scope + scope, + flowUpdatesFilter ).block() } + +suspend fun TelegramBot.buildScenarios( + scope: CoroutineScope, + block: ScenarioReceiver +) = FlowsUpdatesFilter().also { + buildScenarios( + scope, + it, + block + ) + startGettingOfUpdatesByLongPolling( + updatesFilter = it, + scope = scope + ) +} From c70f0b65dd1d0f9e98822ca54084bc232ebb0636 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Thu, 7 Jan 2021 12:45:30 +0600 Subject: [PATCH 05/66] add content triggers and update command --- .../triggers_handling/CommandHandling.kt | 38 ++-- .../triggers_handling/ContentTriggers.kt | 176 ++++++++++++++++++ 2 files changed, 194 insertions(+), 20 deletions(-) create mode 100644 tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/triggers_handling/ContentTriggers.kt diff --git a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/triggers_handling/CommandHandling.kt b/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/triggers_handling/CommandHandling.kt index ed12c1daa9..06c49f1b51 100644 --- a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/triggers_handling/CommandHandling.kt +++ b/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/triggers_handling/CommandHandling.kt @@ -1,5 +1,6 @@ package dev.inmo.tgbotapi.extensions.steps.triggers_handling +import dev.inmo.micro_utils.coroutines.safelyWithoutExceptions import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions import dev.inmo.tgbotapi.CommonAbstracts.textSources import dev.inmo.tgbotapi.extensions.steps.* @@ -7,31 +8,28 @@ import dev.inmo.tgbotapi.extensions.steps.expectations.expectFlow import dev.inmo.tgbotapi.extensions.utils.* import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage import dev.inmo.tgbotapi.types.message.content.TextContent +import dev.inmo.tgbotapi.updateshandlers.FlowsUpdatesFilter +import kotlinx.coroutines.Job +import kotlinx.coroutines.flow.filter suspend fun Scenario.command( commandRegex: Regex, requireOnlyCommandInMessage: Boolean = true, + includeFilterByChatInSubScenario: Boolean = true, scenarioReceiver: ScenarioAndTypeReceiver> -) { - flowsUpdatesFilter.expectFlow(bot) { - it.asMessageUpdate() ?.data ?.asContentMessage() ?.let { message -> - message.content.asTextContent() ?.let { - val textSources = it.textSources - val sizeRequirement = if (requireOnlyCommandInMessage) { - textSources.size == 1 - } else { - true - } - if (sizeRequirement && textSources.any { commandRegex.matches(it.asBotCommandTextSource() ?.command ?: return@any false) }) { - message as ContentMessage - } else { - null - } - } +): Job = onText( + includeFilterByChatInSubScenario, + { message -> + val content = message.content + val textSources = content.textSources + val sizeRequirement = if (requireOnlyCommandInMessage) { + textSources.size == 1 + } else { + true } - }.subscribeSafelyWithoutExceptions(scope) { - scenarioReceiver(it) - } -} + sizeRequirement && textSources.any { commandRegex.matches(it.asBotCommandTextSource() ?.command ?: return@any false) } + }, + scenarioReceiver +) diff --git a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/triggers_handling/ContentTriggers.kt b/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/triggers_handling/ContentTriggers.kt new file mode 100644 index 0000000000..a789c28686 --- /dev/null +++ b/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/triggers_handling/ContentTriggers.kt @@ -0,0 +1,176 @@ +package dev.inmo.tgbotapi.extensions.steps.triggers_handling + + +import dev.inmo.micro_utils.coroutines.safelyWithoutExceptions +import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions +import dev.inmo.tgbotapi.extensions.steps.Scenario +import dev.inmo.tgbotapi.extensions.steps.ScenarioAndTypeReceiver +import dev.inmo.tgbotapi.extensions.steps.expectations.expectFlow +import dev.inmo.tgbotapi.extensions.utils.* +import dev.inmo.tgbotapi.types.files.abstracts.TelegramMediaFile +import dev.inmo.tgbotapi.types.message.content.TextContent +import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage +import dev.inmo.tgbotapi.types.message.content.ContactContent +import dev.inmo.tgbotapi.types.message.content.abstracts.MessageContent +import dev.inmo.tgbotapi.updateshandlers.FlowsUpdatesFilter +import kotlinx.coroutines.flow.filter +import dev.inmo.tgbotapi.types.message.content.DiceContent +import dev.inmo.tgbotapi.types.message.content.GameContent +import dev.inmo.tgbotapi.types.message.content.LocationContent +import dev.inmo.tgbotapi.types.message.content.PollContent +import dev.inmo.tgbotapi.types.message.content.VenueContent +import dev.inmo.tgbotapi.types.message.content.abstracts.AudioMediaGroupContent +import dev.inmo.tgbotapi.types.message.content.abstracts.DocumentMediaGroupContent +import dev.inmo.tgbotapi.types.message.content.abstracts.MediaCollectionContent +import dev.inmo.tgbotapi.types.message.content.abstracts.MediaContent +import dev.inmo.tgbotapi.types.message.content.abstracts.MediaGroupContent +import dev.inmo.tgbotapi.types.message.content.abstracts.VisualMediaGroupContent +import dev.inmo.tgbotapi.types.message.content.media.AnimationContent +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.PhotoContent +import dev.inmo.tgbotapi.types.message.content.media.StickerContent +import dev.inmo.tgbotapi.types.message.content.media.VideoContent +import dev.inmo.tgbotapi.types.message.content.media.VideoNoteContent +import dev.inmo.tgbotapi.types.message.content.media.VoiceContent +import dev.inmo.tgbotapi.types.message.payments.InvoiceContent + + +internal suspend inline fun Scenario.onContent( + includeFilterByChatInSubScenario: Boolean = true, + noinline additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, + noinline scenarioReceiver: ScenarioAndTypeReceiver> +) = flowsUpdatesFilter.expectFlow(bot) { + it.asMessageUpdate() ?.data ?.asContentMessage() ?.let { message -> + if (message.content is T) { + val adaptedMessage = message as ContentMessage + if (additionalFilter == null || additionalFilter(adaptedMessage)) adaptedMessage else null + } else { + null + } + } +}.subscribeSafelyWithoutExceptions(scope) { triggerMessage -> + val (jobToCancel, scenario) = if (includeFilterByChatInSubScenario) { + val subFilter = FlowsUpdatesFilter() + val subScenario = copy(flowsUpdatesFilter = subFilter) + + flowsUpdatesFilter.allUpdatesFlow.filter { + it.asMessageUpdate() ?.data ?.let { it.chat.id.chatId == triggerMessage.chat.id.chatId } == true + }.subscribeSafelyWithoutExceptions(scope, subFilter.asUpdateReceiver) to subScenario + } else { + null to this + } + safelyWithoutExceptions { scenario.scenarioReceiver(triggerMessage) } + jobToCancel ?.cancel() +} + +suspend fun Scenario.onContact( + includeFilterByChatInSubScenario: Boolean = true, + additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, + scenarioReceiver: ScenarioAndTypeReceiver> +) = onContent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) +suspend fun Scenario.onDice( + includeFilterByChatInSubScenario: Boolean = true, + additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, + scenarioReceiver: ScenarioAndTypeReceiver> +) = onContent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) +suspend fun Scenario.onGame( + includeFilterByChatInSubScenario: Boolean = true, + additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, + scenarioReceiver: ScenarioAndTypeReceiver> +) = onContent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) +suspend fun Scenario.onLocation( + includeFilterByChatInSubScenario: Boolean = true, + additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, + scenarioReceiver: ScenarioAndTypeReceiver> +) = onContent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) +suspend fun Scenario.onPoll( + includeFilterByChatInSubScenario: Boolean = true, + additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, + scenarioReceiver: ScenarioAndTypeReceiver> +) = onContent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) +suspend fun Scenario.onText( + includeFilterByChatInSubScenario: Boolean = true, + additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, + scenarioReceiver: ScenarioAndTypeReceiver> +) = onContent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) +suspend fun Scenario.onVenue( + includeFilterByChatInSubScenario: Boolean = true, + additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, + scenarioReceiver: ScenarioAndTypeReceiver> +) = onContent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) +suspend fun Scenario.onAudioMediaGroup( + includeFilterByChatInSubScenario: Boolean = true, + additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, + scenarioReceiver: ScenarioAndTypeReceiver> +) = onContent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) +suspend fun Scenario.onDocumentMediaGroup( + includeFilterByChatInSubScenario: Boolean = true, + additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, + scenarioReceiver: ScenarioAndTypeReceiver> +) = onContent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) +suspend fun Scenario.onMediaCollection( + includeFilterByChatInSubScenario: Boolean = true, + additionalFilter: (suspend (ContentMessage>) -> Boolean)? = null, + scenarioReceiver: ScenarioAndTypeReceiver>> +) = onContent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) +suspend fun Scenario.onMedia( + includeFilterByChatInSubScenario: Boolean = true, + additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, + scenarioReceiver: ScenarioAndTypeReceiver> +) = onContent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) +suspend fun Scenario.onMediaGroup( + includeFilterByChatInSubScenario: Boolean = true, + additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, + scenarioReceiver: ScenarioAndTypeReceiver> +) = onContent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) +suspend fun Scenario.onVisualMediaGroup( + includeFilterByChatInSubScenario: Boolean = true, + additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, + scenarioReceiver: ScenarioAndTypeReceiver> +) = onContent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) +suspend fun Scenario.onAnimation( + includeFilterByChatInSubScenario: Boolean = true, + additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, + scenarioReceiver: ScenarioAndTypeReceiver> +) = onContent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) +suspend fun Scenario.onAudio( + includeFilterByChatInSubScenario: Boolean = true, + additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, + scenarioReceiver: ScenarioAndTypeReceiver> +) = onContent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) +suspend fun Scenario.onDocument( + includeFilterByChatInSubScenario: Boolean = true, + additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, + scenarioReceiver: ScenarioAndTypeReceiver> +) = onContent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) +suspend fun Scenario.onPhoto( + includeFilterByChatInSubScenario: Boolean = true, + additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, + scenarioReceiver: ScenarioAndTypeReceiver> +) = onContent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) +suspend fun Scenario.onSticker( + includeFilterByChatInSubScenario: Boolean = true, + additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, + scenarioReceiver: ScenarioAndTypeReceiver> +) = onContent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) +suspend fun Scenario.onVideo( + includeFilterByChatInSubScenario: Boolean = true, + additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, + scenarioReceiver: ScenarioAndTypeReceiver> +) = onContent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) +suspend fun Scenario.onVideoNote( + includeFilterByChatInSubScenario: Boolean = true, + additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, + scenarioReceiver: ScenarioAndTypeReceiver> +) = onContent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) +suspend fun Scenario.onVoice( + includeFilterByChatInSubScenario: Boolean = true, + additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, + scenarioReceiver: ScenarioAndTypeReceiver> +) = onContent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) +suspend fun Scenario.onInvoice( + includeFilterByChatInSubScenario: Boolean = true, + additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, + scenarioReceiver: ScenarioAndTypeReceiver> +) = onContent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) From aee5ab564b11b55ec3c237cd6883f905b93cfd9e Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Thu, 7 Jan 2021 12:45:54 +0600 Subject: [PATCH 06/66] optimize imports --- .../extensions/steps/ScenarioBuilders.kt | 1 - .../extensions/steps/expectations/Base.kt | 3 +- .../steps/expectations/WaitContent.kt | 3 +- .../triggers_handling/CommandHandling.kt | 5 ---- .../triggers_handling/ContentTriggers.kt | 30 ++++--------------- 5 files changed, 9 insertions(+), 33 deletions(-) diff --git a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/ScenarioBuilders.kt b/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/ScenarioBuilders.kt index 23cdbb4bd5..a15f6a9a10 100644 --- a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/ScenarioBuilders.kt +++ b/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/ScenarioBuilders.kt @@ -1,7 +1,6 @@ package dev.inmo.tgbotapi.extensions.steps import dev.inmo.tgbotapi.bot.TelegramBot -import dev.inmo.tgbotapi.extensions.utils.updates.retrieving.startGettingFlowsUpdatesByLongPolling import dev.inmo.tgbotapi.extensions.utils.updates.retrieving.startGettingOfUpdatesByLongPolling import dev.inmo.tgbotapi.updateshandlers.FlowsUpdatesFilter import kotlinx.coroutines.CoroutineScope diff --git a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/expectations/Base.kt b/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/expectations/Base.kt index 63162ef7e5..a52284dcc1 100644 --- a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/expectations/Base.kt +++ b/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/expectations/Base.kt @@ -3,12 +3,11 @@ package dev.inmo.tgbotapi.extensions.steps.expectations import dev.inmo.micro_utils.coroutines.safelyWithoutExceptions import dev.inmo.tgbotapi.bot.TelegramBot import dev.inmo.tgbotapi.extensions.steps.Scenario -import dev.inmo.tgbotapi.extensions.steps.ScenarioReceiver import dev.inmo.tgbotapi.requests.abstracts.Request import dev.inmo.tgbotapi.types.update.abstracts.Update import dev.inmo.tgbotapi.updateshandlers.FlowsUpdatesFilter import dev.inmo.tgbotapi.utils.RiskFeature -import kotlinx.coroutines.* +import kotlinx.coroutines.CancellationException import kotlinx.coroutines.flow.* private val cancelledByFilterException = CancellationException("Cancelled by filter precreatedException") diff --git a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/expectations/WaitContent.kt b/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/expectations/WaitContent.kt index 928856fe5b..3538e829b8 100644 --- a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/expectations/WaitContent.kt +++ b/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/expectations/WaitContent.kt @@ -1,7 +1,8 @@ package dev.inmo.tgbotapi.extensions.steps.expectations import dev.inmo.tgbotapi.extensions.steps.Scenario -import dev.inmo.tgbotapi.extensions.utils.* +import dev.inmo.tgbotapi.extensions.utils.asContentMessage +import dev.inmo.tgbotapi.extensions.utils.asMessageUpdate import dev.inmo.tgbotapi.requests.abstracts.Request import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage import dev.inmo.tgbotapi.types.message.content.* diff --git a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/triggers_handling/CommandHandling.kt b/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/triggers_handling/CommandHandling.kt index 06c49f1b51..a730143072 100644 --- a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/triggers_handling/CommandHandling.kt +++ b/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/triggers_handling/CommandHandling.kt @@ -1,16 +1,11 @@ package dev.inmo.tgbotapi.extensions.steps.triggers_handling -import dev.inmo.micro_utils.coroutines.safelyWithoutExceptions -import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions import dev.inmo.tgbotapi.CommonAbstracts.textSources import dev.inmo.tgbotapi.extensions.steps.* -import dev.inmo.tgbotapi.extensions.steps.expectations.expectFlow import dev.inmo.tgbotapi.extensions.utils.* import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage import dev.inmo.tgbotapi.types.message.content.TextContent -import dev.inmo.tgbotapi.updateshandlers.FlowsUpdatesFilter import kotlinx.coroutines.Job -import kotlinx.coroutines.flow.filter suspend fun Scenario.command( commandRegex: Regex, diff --git a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/triggers_handling/ContentTriggers.kt b/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/triggers_handling/ContentTriggers.kt index a789c28686..bdcd80fbee 100644 --- a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/triggers_handling/ContentTriggers.kt +++ b/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/triggers_handling/ContentTriggers.kt @@ -6,34 +6,16 @@ import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions import dev.inmo.tgbotapi.extensions.steps.Scenario import dev.inmo.tgbotapi.extensions.steps.ScenarioAndTypeReceiver import dev.inmo.tgbotapi.extensions.steps.expectations.expectFlow -import dev.inmo.tgbotapi.extensions.utils.* +import dev.inmo.tgbotapi.extensions.utils.asContentMessage +import dev.inmo.tgbotapi.extensions.utils.asMessageUpdate import dev.inmo.tgbotapi.types.files.abstracts.TelegramMediaFile -import dev.inmo.tgbotapi.types.message.content.TextContent import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage -import dev.inmo.tgbotapi.types.message.content.ContactContent -import dev.inmo.tgbotapi.types.message.content.abstracts.MessageContent +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.payments.InvoiceContent import dev.inmo.tgbotapi.updateshandlers.FlowsUpdatesFilter import kotlinx.coroutines.flow.filter -import dev.inmo.tgbotapi.types.message.content.DiceContent -import dev.inmo.tgbotapi.types.message.content.GameContent -import dev.inmo.tgbotapi.types.message.content.LocationContent -import dev.inmo.tgbotapi.types.message.content.PollContent -import dev.inmo.tgbotapi.types.message.content.VenueContent -import dev.inmo.tgbotapi.types.message.content.abstracts.AudioMediaGroupContent -import dev.inmo.tgbotapi.types.message.content.abstracts.DocumentMediaGroupContent -import dev.inmo.tgbotapi.types.message.content.abstracts.MediaCollectionContent -import dev.inmo.tgbotapi.types.message.content.abstracts.MediaContent -import dev.inmo.tgbotapi.types.message.content.abstracts.MediaGroupContent -import dev.inmo.tgbotapi.types.message.content.abstracts.VisualMediaGroupContent -import dev.inmo.tgbotapi.types.message.content.media.AnimationContent -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.PhotoContent -import dev.inmo.tgbotapi.types.message.content.media.StickerContent -import dev.inmo.tgbotapi.types.message.content.media.VideoContent -import dev.inmo.tgbotapi.types.message.content.media.VideoNoteContent -import dev.inmo.tgbotapi.types.message.content.media.VoiceContent -import dev.inmo.tgbotapi.types.message.payments.InvoiceContent internal suspend inline fun Scenario.onContent( From 94745ef373f74515b919a30065417585621a4d17 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Thu, 7 Jan 2021 16:01:25 +0600 Subject: [PATCH 07/66] add docs to base expectations --- .../extensions/steps/expectations/Base.kt | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/expectations/Base.kt b/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/expectations/Base.kt index a52284dcc1..63b081f9e9 100644 --- a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/expectations/Base.kt +++ b/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/expectations/Base.kt @@ -15,6 +15,17 @@ private val cancelledByFilterException = CancellationException("Cancelled by fil typealias RequestBuilder = suspend (Update) -> Request typealias NullableRequestBuilder = suspend (Update) -> Request? +/** + * @param initRequest If not null, this request will be sent by [bot] before returning value + * @param count If set, result [Flow] will return [count] elements on each [Flow.collect] + * @param errorFactory If set, this factory will be used to produce requests in case when user have sent incorrect data + * @param cancelRequestFactory If set, this factory will be used to produce requests in case when it is required to say + * user that chain of scenario has been cancelled + * @param cancelTrigger When this trigger returns true, chain is cancelled + * @param filter It is main param, which will be called on each update. When it return not null, result will be returned + * as is, but when it returns null, then will be called [cancelTrigger] (if it will return true - [cancelRequestFactory] + * will be called too), [errorFactory] and then will be returned null + */ @RiskFeature("This method is not very comfortable to use and too low-level. It is recommended to use methods which already included into library") suspend fun FlowsUpdatesFilter.expectFlow( bot: TelegramBot, @@ -51,6 +62,17 @@ suspend fun FlowsUpdatesFilter.expectFlow( return result } +/** + * @param initRequest If not null, this request will be sent by [bot] before returning value + * @param count If set, result [Flow] will return [count] elements on each [Flow.collect] + * @param errorFactory If set, this factory will be used to produce requests in case when user have sent incorrect data + * @param cancelRequestFactory If set, this factory will be used to produce requests in case when it is required to say + * user that chain of scenario has been cancelled + * @param cancelTrigger When this trigger returns true, chain is cancelled + * @param filter It is main param, which will be called on each update. When it return not null, result will be returned + * as is, but when it returns null, then will be called [cancelTrigger] (if it will return true - [cancelRequestFactory] + * will be called too), [errorFactory] and then will be returned null + */ suspend fun Scenario.expectFlow( initRequest: Request<*>? = null, count: Int? = null, @@ -60,6 +82,16 @@ suspend fun Scenario.expectFlow( filter: suspend (Update) -> T? ) = flowsUpdatesFilter.expectFlow(bot, initRequest, count, errorFactory, cancelRequestFactory, cancelTrigger, filter) +/** + * @param initRequest If not null, this request will be sent by [bot] before returning value + * @param errorFactory If set, this factory will be used to produce requests in case when user have sent incorrect data + * @param cancelRequestFactory If set, this factory will be used to produce requests in case when it is required to say + * user that chain of scenario has been cancelled + * @param cancelTrigger When this trigger returns true, chain is cancelled + * @param filter It is main param, which will be called on each update. When it return not null, result will be returned + * as is, but when it returns null, then will be called [cancelTrigger] (if it will return true - [cancelRequestFactory] + * will be called too), [errorFactory] and then will be returned null + */ @RiskFeature("This method is not very comfortable to use and too low-level. It is recommended to use methods which already included into library") suspend fun FlowsUpdatesFilter.expectOne( bot: TelegramBot, @@ -70,6 +102,16 @@ suspend fun FlowsUpdatesFilter.expectOne( filter: suspend (Update) -> T?, ): T = expectFlow(bot, initRequest, 1, errorFactory, cancelRequestFactory, cancelTrigger, filter).first() +/** + * @param initRequest If not null, this request will be sent by [bot] before returning value + * @param errorFactory If set, this factory will be used to produce requests in case when user have sent incorrect data + * @param cancelRequestFactory If set, this factory will be used to produce requests in case when it is required to say + * user that chain of scenario has been cancelled + * @param cancelTrigger When this trigger returns true, chain is cancelled + * @param filter It is main param, which will be called on each update. When it return not null, result will be returned + * as is, but when it returns null, then will be called [cancelTrigger] (if it will return true - [cancelRequestFactory] + * will be called too), [errorFactory] and then will be returned null + */ suspend fun Scenario.expectOne( initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, From 965b8c3c505851f81e05fa8705e4344ca2d06701 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Thu, 7 Jan 2021 17:24:58 +0600 Subject: [PATCH 08/66] add chat event triggers and expectations in steps --- .../steps/expectations/WaitContent.kt | 5 +- .../steps/expectations/WaitEventAction.kt | 144 ++++++++++++++++++ .../steps/triggers_handling/EventTriggers.kt | 125 +++++++++++++++ tgbotapi/build.gradle | 1 + 4 files changed, 274 insertions(+), 1 deletion(-) create mode 100644 tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/expectations/WaitEventAction.kt create mode 100644 tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/triggers_handling/EventTriggers.kt diff --git a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/expectations/WaitContent.kt b/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/expectations/WaitContent.kt index 3538e829b8..20e15bbcb6 100644 --- a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/expectations/WaitContent.kt +++ b/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/expectations/WaitContent.kt @@ -1,3 +1,5 @@ +@file:Suppress("unused") + package dev.inmo.tgbotapi.extensions.steps.expectations import dev.inmo.tgbotapi.extensions.steps.Scenario @@ -30,13 +32,14 @@ private suspend inline fun Scenario.waitContent( count: Int = 1, initRequest: Request<*>? = null, noinline errorFactory: NullableRequestBuilder<*> = { null }, - noinline filter: (suspend (ContentMessage) -> T?)? = null + noinline filter: ContentMessageToContentMapper? = null ) : List = waitContentMessage( count, initRequest, errorFactory ) { if (content is T) { + @Suppress("UNCHECKED_CAST") val message = (this as ContentMessage) if (filter == null) { message.content diff --git a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/expectations/WaitEventAction.kt b/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/expectations/WaitEventAction.kt new file mode 100644 index 0000000000..b96a999eed --- /dev/null +++ b/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/expectations/WaitEventAction.kt @@ -0,0 +1,144 @@ +@file:Suppress("unused") + +package dev.inmo.tgbotapi.extensions.steps.expectations + +import dev.inmo.tgbotapi.extensions.steps.Scenario +import dev.inmo.tgbotapi.extensions.utils.* +import dev.inmo.tgbotapi.requests.abstracts.Request +import dev.inmo.tgbotapi.types.message.ChatEvents.* +import dev.inmo.tgbotapi.types.message.ChatEvents.abstracts.* +import dev.inmo.tgbotapi.types.message.abstracts.ChatEventMessage +import dev.inmo.tgbotapi.types.message.content.ContactContent +import kotlinx.coroutines.flow.toList + +typealias EventMessageToEventMapper = suspend ChatEventMessage.() -> T? + +private suspend fun Scenario.waitEventMessages( + count: Int = 1, + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null }, + mapper: suspend ChatEventMessage.() -> O? +): List = expectFlow( + initRequest, + count, + errorFactory +) { + it.asMessageUpdate() ?.data ?.asChatEventMessage() ?.mapper() +}.toList().toList() + + +private suspend inline fun Scenario.waitEvents( + count: Int = 1, + initRequest: Request<*>? = null, + noinline errorFactory: NullableRequestBuilder<*> = { null }, + noinline filter: EventMessageToEventMapper? = null +) : List = waitEventMessages( + count, + initRequest, + errorFactory +) { + if (chatEvent is T) { + @Suppress("UNCHECKED_CAST") + val message = (this as ChatEventMessage) + if (filter == null) { + message.chatEvent + } else { + filter(message) + } + } else { + null + } +} + +suspend fun Scenario.waitChannelEvents( + count: Int = 1, + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null }, + filter: EventMessageToEventMapper? = null +) = waitEvents(count, initRequest, errorFactory, filter) + +suspend fun Scenario.waitChatEvents( + count: Int = 1, + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null }, + filter: EventMessageToEventMapper? = null +) = waitEvents(count, initRequest, errorFactory, filter) +suspend fun Scenario.waitCommonEvents( + count: Int = 1, + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null }, + filter: EventMessageToEventMapper? = null +) = waitEvents(count, initRequest, errorFactory, filter) +suspend fun Scenario.waitGroupEvents( + count: Int = 1, + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null }, + filter: EventMessageToEventMapper? = null +) = waitEvents(count, initRequest, errorFactory, filter) +suspend fun Scenario.waitSupergroupEvents( + count: Int = 1, + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null }, + filter: EventMessageToEventMapper? = null +) = waitEvents(count, initRequest, errorFactory, filter) + +suspend fun Scenario.waitChannelChatCreatedEvents( + count: Int = 1, + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null }, + filter: EventMessageToEventMapper? = null +) = waitEvents(count, initRequest, errorFactory, filter) +suspend fun Scenario.waitDeleteChatPhotoEvents( + count: Int = 1, + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null }, + filter: EventMessageToEventMapper? = null +) = waitEvents(count, initRequest, errorFactory, filter) +suspend fun Scenario.waitGroupChatCreatedEvents( + count: Int = 1, + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null }, + filter: EventMessageToEventMapper? = null +) = waitEvents(count, initRequest, errorFactory, filter) +suspend fun Scenario.waitLeftChatMemberEvents( + count: Int = 1, + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null }, + filter: EventMessageToEventMapper? = null +) = waitEvents(count, initRequest, errorFactory, filter) +suspend fun Scenario.waitNewChatPhotoEvents( + count: Int = 1, + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null }, + filter: EventMessageToEventMapper? = null +) = waitEvents(count, initRequest, errorFactory, filter) +suspend fun Scenario.waitNewChatMembersEvents( + count: Int = 1, + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null }, + filter: EventMessageToEventMapper? = null +) = waitEvents(count, initRequest, errorFactory, filter) +suspend fun Scenario.waitNewChatTitleEvents( + count: Int = 1, + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null }, + filter: EventMessageToEventMapper? = null +) = waitEvents(count, initRequest, errorFactory, filter) +suspend fun Scenario.waitPinnedMessageEvents( + count: Int = 1, + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null }, + filter: EventMessageToEventMapper? = null +) = waitEvents(count, initRequest, errorFactory, filter) +suspend fun Scenario.waitProximityAlertTriggeredEvents( + count: Int = 1, + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null }, + filter: EventMessageToEventMapper? = null +) = waitEvents(count, initRequest, errorFactory, filter) +suspend fun Scenario.waitSupergroupChatCreatedEvents( + count: Int = 1, + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null }, + filter: EventMessageToEventMapper? = null +) = waitEvents(count, initRequest, errorFactory, filter) diff --git a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/triggers_handling/EventTriggers.kt b/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/triggers_handling/EventTriggers.kt new file mode 100644 index 0000000000..a5117355b9 --- /dev/null +++ b/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/triggers_handling/EventTriggers.kt @@ -0,0 +1,125 @@ +package dev.inmo.tgbotapi.extensions.steps.triggers_handling + + +import dev.inmo.micro_utils.coroutines.safelyWithoutExceptions +import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions +import dev.inmo.tgbotapi.extensions.steps.Scenario +import dev.inmo.tgbotapi.extensions.steps.ScenarioAndTypeReceiver +import dev.inmo.tgbotapi.extensions.steps.expectations.expectFlow +import dev.inmo.tgbotapi.extensions.utils.* +import dev.inmo.tgbotapi.types.files.abstracts.TelegramMediaFile +import dev.inmo.tgbotapi.types.message.ChatEvents.* +import dev.inmo.tgbotapi.types.message.ChatEvents.abstracts.* +import dev.inmo.tgbotapi.types.message.abstracts.ChatEventMessage +import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage +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.payments.InvoiceContent +import dev.inmo.tgbotapi.updateshandlers.FlowsUpdatesFilter +import kotlinx.coroutines.flow.filter + +internal suspend inline fun Scenario.onEvent( + includeFilterByChatInSubScenario: Boolean = true, + noinline additionalFilter: (suspend (ChatEventMessage) -> Boolean)? = null, + noinline scenarioReceiver: ScenarioAndTypeReceiver> +) = flowsUpdatesFilter.expectFlow(bot) { + it.asMessageUpdate() ?.data ?.asChatEventMessage() ?.let { message -> + if (message.chatEvent is T) { + val adaptedMessage = message as ChatEventMessage + if (additionalFilter == null || additionalFilter(adaptedMessage)) adaptedMessage else null + } else { + null + } + } +}.subscribeSafelyWithoutExceptions(scope) { triggerMessage -> + val (jobToCancel, scenario) = if (includeFilterByChatInSubScenario) { + val subFilter = FlowsUpdatesFilter() + val subScenario = copy(flowsUpdatesFilter = subFilter) + + flowsUpdatesFilter.allUpdatesFlow.filter { + it.asMessageUpdate() ?.data ?.let { it.chat.id.chatId == triggerMessage.chat.id.chatId } == true + }.subscribeSafelyWithoutExceptions(scope, subFilter.asUpdateReceiver) to subScenario + } else { + null to this + } + safelyWithoutExceptions { scenario.scenarioReceiver(triggerMessage) } + jobToCancel ?.cancel() +} + +suspend fun Scenario.onChannelEvent( + includeFilterByChatInSubScenario: Boolean = true, + additionalFilter: (suspend (ChatEventMessage) -> Boolean)? = null, + scenarioReceiver: ScenarioAndTypeReceiver> +) = onEvent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) +suspend fun Scenario.onChatEvent( + includeFilterByChatInSubScenario: Boolean = true, + additionalFilter: (suspend (ChatEventMessage) -> Boolean)? = null, + scenarioReceiver: ScenarioAndTypeReceiver> +) = onEvent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) +suspend fun Scenario.onCommonEvent( + includeFilterByChatInSubScenario: Boolean = true, + additionalFilter: (suspend (ChatEventMessage) -> Boolean)? = null, + scenarioReceiver: ScenarioAndTypeReceiver> +) = onEvent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) +suspend fun Scenario.onGroupEvent( + includeFilterByChatInSubScenario: Boolean = true, + additionalFilter: (suspend (ChatEventMessage) -> Boolean)? = null, + scenarioReceiver: ScenarioAndTypeReceiver> +) = onEvent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) +suspend fun Scenario.onSupergroupEvent( + includeFilterByChatInSubScenario: Boolean = true, + additionalFilter: (suspend (ChatEventMessage) -> Boolean)? = null, + scenarioReceiver: ScenarioAndTypeReceiver> +) = onEvent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) + +suspend fun Scenario.onChannelChatCreated( + includeFilterByChatInSubScenario: Boolean = true, + additionalFilter: (suspend (ChatEventMessage) -> Boolean)? = null, + scenarioReceiver: ScenarioAndTypeReceiver> +) = onEvent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) +suspend fun Scenario.onDeleteChatPhoto( + includeFilterByChatInSubScenario: Boolean = true, + additionalFilter: (suspend (ChatEventMessage) -> Boolean)? = null, + scenarioReceiver: ScenarioAndTypeReceiver> +) = onEvent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) +suspend fun Scenario.onGroupChatCreated( + includeFilterByChatInSubScenario: Boolean = true, + additionalFilter: (suspend (ChatEventMessage) -> Boolean)? = null, + scenarioReceiver: ScenarioAndTypeReceiver> +) = onEvent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) +suspend fun Scenario.onLeftChatMember( + includeFilterByChatInSubScenario: Boolean = true, + additionalFilter: (suspend (ChatEventMessage) -> Boolean)? = null, + scenarioReceiver: ScenarioAndTypeReceiver> +) = onEvent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) +suspend fun Scenario.onNewChatMembers( + includeFilterByChatInSubScenario: Boolean = true, + additionalFilter: (suspend (ChatEventMessage) -> Boolean)? = null, + scenarioReceiver: ScenarioAndTypeReceiver> +) = onEvent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) +suspend fun Scenario.onNewChatPhoto( + includeFilterByChatInSubScenario: Boolean = true, + additionalFilter: (suspend (ChatEventMessage) -> Boolean)? = null, + scenarioReceiver: ScenarioAndTypeReceiver> +) = onEvent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) +suspend fun Scenario.onNewChatTitle( + includeFilterByChatInSubScenario: Boolean = true, + additionalFilter: (suspend (ChatEventMessage) -> Boolean)? = null, + scenarioReceiver: ScenarioAndTypeReceiver> +) = onEvent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) +suspend fun Scenario.onPinnedMessage( + includeFilterByChatInSubScenario: Boolean = true, + additionalFilter: (suspend (ChatEventMessage) -> Boolean)? = null, + scenarioReceiver: ScenarioAndTypeReceiver> +) = onEvent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) +suspend fun Scenario.onProximityAlertTriggered( + includeFilterByChatInSubScenario: Boolean = true, + additionalFilter: (suspend (ChatEventMessage) -> Boolean)? = null, + scenarioReceiver: ScenarioAndTypeReceiver> +) = onEvent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) +suspend fun Scenario.onSupergroupChatCreated( + includeFilterByChatInSubScenario: Boolean = true, + additionalFilter: (suspend (ChatEventMessage) -> Boolean)? = null, + scenarioReceiver: ScenarioAndTypeReceiver> +) = onEvent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) diff --git a/tgbotapi/build.gradle b/tgbotapi/build.gradle index 36ee69d99c..b033b525c2 100644 --- a/tgbotapi/build.gradle +++ b/tgbotapi/build.gradle @@ -42,6 +42,7 @@ kotlin { api project(":tgbotapi.core") api project(":tgbotapi.extensions.api") api project(":tgbotapi.extensions.utils") + api project(":tgbotapi.extensions.steps") } } } From 3125c2fc1baffd4b7addc7bb7746fcd91069aaf6 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Thu, 7 Jan 2021 17:57:08 +0600 Subject: [PATCH 09/66] add callback query expectations and triggers --- .../steps/expectations/WaitCallbackQuery.kt | 107 ++++++++++++++++++ .../CallbackQueryTriggers.kt | 91 +++++++++++++++ .../triggers_handling/ContentTriggers.kt | 4 +- .../steps/triggers_handling/EventTriggers.kt | 4 +- .../utils/extensions/UpdateChatRetriever.kt | 26 +++++ 5 files changed, 230 insertions(+), 2 deletions(-) create mode 100644 tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/expectations/WaitCallbackQuery.kt create mode 100644 tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/triggers_handling/CallbackQueryTriggers.kt create mode 100644 tgbotapi.extensions.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/extensions/UpdateChatRetriever.kt diff --git a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/expectations/WaitCallbackQuery.kt b/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/expectations/WaitCallbackQuery.kt new file mode 100644 index 0000000000..18716f49d7 --- /dev/null +++ b/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/expectations/WaitCallbackQuery.kt @@ -0,0 +1,107 @@ +@file:Suppress("unused") + +package dev.inmo.tgbotapi.extensions.steps.expectations + +import dev.inmo.tgbotapi.extensions.steps.Scenario +import dev.inmo.tgbotapi.extensions.utils.* +import dev.inmo.tgbotapi.requests.abstracts.Request +import dev.inmo.tgbotapi.types.CallbackQuery.* +import dev.inmo.tgbotapi.types.message.ChatEvents.* +import dev.inmo.tgbotapi.types.message.ChatEvents.abstracts.* +import dev.inmo.tgbotapi.types.message.abstracts.ChatEventMessage +import dev.inmo.tgbotapi.types.message.content.ContactContent +import dev.inmo.tgbotapi.types.update.CallbackQueryUpdate +import kotlinx.coroutines.flow.toList + +typealias CallbackQueryMapper = T.() -> T? + +private suspend fun Scenario.waitCallbackQueries( + count: Int = 1, + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null }, + mapper: suspend CallbackQuery.() -> O? +): List = expectFlow( + initRequest, + count, + errorFactory +) { + it.asCallbackQueryUpdate() ?.data ?.mapper() +}.toList().toList() + + +private suspend inline fun Scenario.waitEvents( + count: Int = 1, + initRequest: Request<*>? = null, + noinline errorFactory: NullableRequestBuilder<*> = { null }, + noinline filter: CallbackQueryMapper? = null +) : List = waitCallbackQueries( + count, + initRequest, + errorFactory +) { + if (this is T) { + if (filter == null) { + this + } else { + filter(this) + } + } else { + null + } +} + + +suspend fun Scenario.waitDataCallbackQuery( + count: Int = 1, + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null }, + filter: CallbackQueryMapper? = null +) = waitEvents(count, initRequest, errorFactory, filter) +suspend fun Scenario.waitGameShortNameCallbackQuery( + count: Int = 1, + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null }, + filter: CallbackQueryMapper? = null +) = waitEvents(count, initRequest, errorFactory, filter) +suspend fun Scenario.waitInlineMessageIdCallbackQuery( + count: Int = 1, + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null }, + filter: CallbackQueryMapper? = null +) = waitEvents(count, initRequest, errorFactory, filter) +suspend fun Scenario.waitInlineMessageIdDataCallbackQuery( + count: Int = 1, + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null }, + filter: CallbackQueryMapper? = null +) = waitEvents(count, initRequest, errorFactory, filter) +suspend fun Scenario.waitInlineMessageIdGameShortNameCallbackQuery( + count: Int = 1, + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null }, + filter: CallbackQueryMapper? = null +) = waitEvents(count, initRequest, errorFactory, filter) +suspend fun Scenario.waitMessageCallbackQuery( + count: Int = 1, + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null }, + filter: CallbackQueryMapper? = null +) = waitEvents(count, initRequest, errorFactory, filter) +suspend fun Scenario.waitMessageDataCallbackQuery( + count: Int = 1, + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null }, + filter: CallbackQueryMapper? = null +) = waitEvents(count, initRequest, errorFactory, filter) +suspend fun Scenario.waitMessageGameShortNameCallbackQuery( + count: Int = 1, + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null }, + filter: CallbackQueryMapper? = null +) = waitEvents(count, initRequest, errorFactory, filter) +suspend fun Scenario.waitUnknownCallbackQuery( + count: Int = 1, + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null }, + filter: CallbackQueryMapper? = null +) = waitEvents(count, initRequest, errorFactory, filter) diff --git a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/triggers_handling/CallbackQueryTriggers.kt b/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/triggers_handling/CallbackQueryTriggers.kt new file mode 100644 index 0000000000..1e9f97dc9b --- /dev/null +++ b/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/triggers_handling/CallbackQueryTriggers.kt @@ -0,0 +1,91 @@ +package dev.inmo.tgbotapi.extensions.steps.triggers_handling + + +import dev.inmo.micro_utils.coroutines.safelyWithoutExceptions +import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions +import dev.inmo.tgbotapi.extensions.steps.Scenario +import dev.inmo.tgbotapi.extensions.steps.ScenarioAndTypeReceiver +import dev.inmo.tgbotapi.extensions.steps.expectations.expectFlow +import dev.inmo.tgbotapi.extensions.utils.* +import dev.inmo.tgbotapi.extensions.utils.extensions.sourceChat +import dev.inmo.tgbotapi.types.CallbackQuery.* +import dev.inmo.tgbotapi.types.message.ChatEvents.* +import dev.inmo.tgbotapi.types.message.ChatEvents.abstracts.* +import dev.inmo.tgbotapi.updateshandlers.FlowsUpdatesFilter +import kotlinx.coroutines.flow.filter + +internal suspend inline fun Scenario.onCallbackQuery( + includeFilterByChatInSubScenario: Boolean = true, + noinline additionalFilter: (suspend (T) -> Boolean)? = null, + noinline scenarioReceiver: ScenarioAndTypeReceiver +) = flowsUpdatesFilter.expectFlow(bot) { + it.asCallbackQueryUpdate() ?.data ?.let { query -> + if (query is T) { + if (additionalFilter == null || additionalFilter(query)) query else null + } else { + null + } + } +}.subscribeSafelyWithoutExceptions(scope) { triggerQuery -> + val (jobToCancel, scenario) = if (includeFilterByChatInSubScenario) { + val subFilter = FlowsUpdatesFilter() + val subScenario = copy(flowsUpdatesFilter = subFilter) + + flowsUpdatesFilter.allUpdatesFlow.filter { + val chat = it.sourceChat() ?: return@filter false + chat.id.chatId == triggerQuery.user.id.chatId + }.subscribeSafelyWithoutExceptions(scope, subFilter.asUpdateReceiver) to subScenario + } else { + null to this + } + safelyWithoutExceptions { scenario.scenarioReceiver(triggerQuery) } + jobToCancel ?.cancel() +} + + +suspend fun Scenario.onDataCallbackQuery( + includeFilterByChatInSubScenario: Boolean = true, + additionalFilter: (suspend (DataCallbackQuery) -> Boolean)? = null, + scenarioReceiver: ScenarioAndTypeReceiver +) = onCallbackQuery(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) + +suspend fun Scenario.onGameShortNameCallbackQuery( + includeFilterByChatInSubScenario: Boolean = true, + additionalFilter: (suspend (GameShortNameCallbackQuery) -> Boolean)? = null, + scenarioReceiver: ScenarioAndTypeReceiver +) = onCallbackQuery(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) +suspend fun Scenario.onInlineMessageIdCallbackQuery( + includeFilterByChatInSubScenario: Boolean = true, + additionalFilter: (suspend (InlineMessageIdCallbackQuery) -> Boolean)? = null, + scenarioReceiver: ScenarioAndTypeReceiver +) = onCallbackQuery(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) +suspend fun Scenario.onInlineMessageIdDataCallbackQuery( + includeFilterByChatInSubScenario: Boolean = true, + additionalFilter: (suspend (InlineMessageIdDataCallbackQuery) -> Boolean)? = null, + scenarioReceiver: ScenarioAndTypeReceiver +) = onCallbackQuery(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) +suspend fun Scenario.onInlineMessageIdGameShortNameCallbackQuery( + includeFilterByChatInSubScenario: Boolean = true, + additionalFilter: (suspend (InlineMessageIdGameShortNameCallbackQuery) -> Boolean)? = null, + scenarioReceiver: ScenarioAndTypeReceiver +) = onCallbackQuery(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) +suspend fun Scenario.onMessageCallbackQuery( + includeFilterByChatInSubScenario: Boolean = true, + additionalFilter: (suspend (MessageCallbackQuery) -> Boolean)? = null, + scenarioReceiver: ScenarioAndTypeReceiver +) = onCallbackQuery(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) +suspend fun Scenario.onMessageDataCallbackQuery( + includeFilterByChatInSubScenario: Boolean = true, + additionalFilter: (suspend (MessageDataCallbackQuery) -> Boolean)? = null, + scenarioReceiver: ScenarioAndTypeReceiver +) = onCallbackQuery(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) +suspend fun Scenario.onMessageGameShortNameCallbackQuery( + includeFilterByChatInSubScenario: Boolean = true, + additionalFilter: (suspend (MessageGameShortNameCallbackQuery) -> Boolean)? = null, + scenarioReceiver: ScenarioAndTypeReceiver +) = onCallbackQuery(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) +suspend fun Scenario.onUnknownCallbackQueryType( + includeFilterByChatInSubScenario: Boolean = true, + additionalFilter: (suspend (UnknownCallbackQueryType) -> Boolean)? = null, + scenarioReceiver: ScenarioAndTypeReceiver +) = onCallbackQuery(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) diff --git a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/triggers_handling/ContentTriggers.kt b/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/triggers_handling/ContentTriggers.kt index bdcd80fbee..9bb3a49bb9 100644 --- a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/triggers_handling/ContentTriggers.kt +++ b/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/triggers_handling/ContentTriggers.kt @@ -8,6 +8,7 @@ import dev.inmo.tgbotapi.extensions.steps.ScenarioAndTypeReceiver import dev.inmo.tgbotapi.extensions.steps.expectations.expectFlow import dev.inmo.tgbotapi.extensions.utils.asContentMessage import dev.inmo.tgbotapi.extensions.utils.asMessageUpdate +import dev.inmo.tgbotapi.extensions.utils.extensions.sourceChat import dev.inmo.tgbotapi.types.files.abstracts.TelegramMediaFile import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage import dev.inmo.tgbotapi.types.message.content.* @@ -37,7 +38,8 @@ internal suspend inline fun Scenario.onContent( val subScenario = copy(flowsUpdatesFilter = subFilter) flowsUpdatesFilter.allUpdatesFlow.filter { - it.asMessageUpdate() ?.data ?.let { it.chat.id.chatId == triggerMessage.chat.id.chatId } == true + val chat = it.sourceChat() ?: return@filter false + chat.id.chatId == triggerMessage.chat.id.chatId }.subscribeSafelyWithoutExceptions(scope, subFilter.asUpdateReceiver) to subScenario } else { null to this diff --git a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/triggers_handling/EventTriggers.kt b/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/triggers_handling/EventTriggers.kt index a5117355b9..e447a0d842 100644 --- a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/triggers_handling/EventTriggers.kt +++ b/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/triggers_handling/EventTriggers.kt @@ -7,6 +7,7 @@ import dev.inmo.tgbotapi.extensions.steps.Scenario import dev.inmo.tgbotapi.extensions.steps.ScenarioAndTypeReceiver import dev.inmo.tgbotapi.extensions.steps.expectations.expectFlow import dev.inmo.tgbotapi.extensions.utils.* +import dev.inmo.tgbotapi.extensions.utils.extensions.sourceChat import dev.inmo.tgbotapi.types.files.abstracts.TelegramMediaFile import dev.inmo.tgbotapi.types.message.ChatEvents.* import dev.inmo.tgbotapi.types.message.ChatEvents.abstracts.* @@ -38,7 +39,8 @@ internal suspend inline fun Scenario.onEvent( val subScenario = copy(flowsUpdatesFilter = subFilter) flowsUpdatesFilter.allUpdatesFlow.filter { - it.asMessageUpdate() ?.data ?.let { it.chat.id.chatId == triggerMessage.chat.id.chatId } == true + val chat = it.sourceChat() ?: return@filter false + chat.id.chatId == triggerMessage.chat.id.chatId }.subscribeSafelyWithoutExceptions(scope, subFilter.asUpdateReceiver) to subScenario } else { null to this diff --git a/tgbotapi.extensions.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/extensions/UpdateChatRetriever.kt b/tgbotapi.extensions.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/extensions/UpdateChatRetriever.kt new file mode 100644 index 0000000000..153cbe2600 --- /dev/null +++ b/tgbotapi.extensions.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/extensions/UpdateChatRetriever.kt @@ -0,0 +1,26 @@ +package dev.inmo.tgbotapi.extensions.utils.extensions + +import dev.inmo.tgbotapi.extensions.utils.shortcuts.chat +import dev.inmo.tgbotapi.types.chat.abstracts.Chat +import dev.inmo.tgbotapi.types.update.* +import dev.inmo.tgbotapi.types.update.MediaGroupUpdates.* +import dev.inmo.tgbotapi.types.update.abstracts.BaseMessageUpdate +import dev.inmo.tgbotapi.types.update.abstracts.Update +import dev.inmo.tgbotapi.utils.PreviewFeature + +@PreviewFeature +fun Update.sourceChat(): Chat? = when (this) { + is MediaGroupUpdate -> when (this) { + is SentMediaGroupUpdate -> data.chat + is EditMediaGroupUpdate -> data.chat + else -> null + } + is BaseMessageUpdate -> data.chat + is InlineQueryUpdate -> data.from + is ChosenInlineResultUpdate -> data.user + is CallbackQueryUpdate -> data.user + is PreCheckoutQueryUpdate -> data.user + is PollAnswerUpdate -> data.user + is ShippingQueryUpdate -> data.user + else -> null +} From 383e722d0773337c957268409490fc01b954ca85 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Thu, 7 Jan 2021 18:11:01 +0600 Subject: [PATCH 10/66] rename scenario to behaviour context --- ...enarioBuilders.kt => BehaviourBuilders.kt} | 12 +- .../{Scenario.kt => BehaviourContext.kt} | 6 +- .../extensions/steps/expectations/Base.kt | 6 +- .../steps/expectations/WaitCallbackQuery.kt | 29 ++- .../steps/expectations/WaitContent.kt | 48 ++--- .../steps/expectations/WaitEventAction.kt | 37 ++-- .../CallbackQueryTriggers.kt | 88 ++++---- .../triggers_handling/CommandHandling.kt | 15 +- .../triggers_handling/ContentTriggers.kt | 192 +++++++++--------- .../steps/triggers_handling/EventTriggers.kt | 139 +++++++------ 10 files changed, 284 insertions(+), 288 deletions(-) rename tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/{ScenarioBuilders.kt => BehaviourBuilders.kt} (75%) rename tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/{Scenario.kt => BehaviourContext.kt} (63%) diff --git a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/ScenarioBuilders.kt b/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/BehaviourBuilders.kt similarity index 75% rename from tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/ScenarioBuilders.kt rename to tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/BehaviourBuilders.kt index a15f6a9a10..269586e649 100644 --- a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/ScenarioBuilders.kt +++ b/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/BehaviourBuilders.kt @@ -5,23 +5,23 @@ import dev.inmo.tgbotapi.extensions.utils.updates.retrieving.startGettingOfUpdat import dev.inmo.tgbotapi.updateshandlers.FlowsUpdatesFilter import kotlinx.coroutines.CoroutineScope -suspend fun TelegramBot.buildScenarios( +suspend fun TelegramBot.buildBehaviour( scope: CoroutineScope, flowUpdatesFilter: FlowsUpdatesFilter, - block: ScenarioReceiver + block: BehaviourContextReceiver ) { - Scenario( + BehaviourContext( this, scope, flowUpdatesFilter ).block() } -suspend fun TelegramBot.buildScenarios( +suspend fun TelegramBot.buildBehaviour( scope: CoroutineScope, - block: ScenarioReceiver + block: BehaviourContextReceiver ) = FlowsUpdatesFilter().also { - buildScenarios( + buildBehaviour( scope, it, block diff --git a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/Scenario.kt b/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/BehaviourContext.kt similarity index 63% rename from tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/Scenario.kt rename to tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/BehaviourContext.kt index 9d34dee99f..935455e6f2 100644 --- a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/Scenario.kt +++ b/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/BehaviourContext.kt @@ -4,10 +4,10 @@ import dev.inmo.tgbotapi.bot.TelegramBot import dev.inmo.tgbotapi.updateshandlers.FlowsUpdatesFilter import kotlinx.coroutines.CoroutineScope -typealias ScenarioReceiver = suspend Scenario.() -> T -typealias ScenarioAndTypeReceiver = suspend Scenario.(I) -> T +typealias BehaviourContextReceiver = suspend BehaviourContext.() -> T +typealias BehaviourContextAndTypeReceiver = suspend BehaviourContext.(I) -> T -data class Scenario( +data class BehaviourContext( val bot: TelegramBot, val scope: CoroutineScope, val flowsUpdatesFilter: FlowsUpdatesFilter = FlowsUpdatesFilter() diff --git a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/expectations/Base.kt b/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/expectations/Base.kt index 63b081f9e9..7317ae0841 100644 --- a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/expectations/Base.kt +++ b/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/expectations/Base.kt @@ -2,7 +2,7 @@ package dev.inmo.tgbotapi.extensions.steps.expectations import dev.inmo.micro_utils.coroutines.safelyWithoutExceptions import dev.inmo.tgbotapi.bot.TelegramBot -import dev.inmo.tgbotapi.extensions.steps.Scenario +import dev.inmo.tgbotapi.extensions.steps.BehaviourContext import dev.inmo.tgbotapi.requests.abstracts.Request import dev.inmo.tgbotapi.types.update.abstracts.Update import dev.inmo.tgbotapi.updateshandlers.FlowsUpdatesFilter @@ -73,7 +73,7 @@ suspend fun FlowsUpdatesFilter.expectFlow( * as is, but when it returns null, then will be called [cancelTrigger] (if it will return true - [cancelRequestFactory] * will be called too), [errorFactory] and then will be returned null */ -suspend fun Scenario.expectFlow( +suspend fun BehaviourContext.expectFlow( initRequest: Request<*>? = null, count: Int? = null, errorFactory: NullableRequestBuilder<*> = { null }, @@ -112,7 +112,7 @@ suspend fun FlowsUpdatesFilter.expectOne( * as is, but when it returns null, then will be called [cancelTrigger] (if it will return true - [cancelRequestFactory] * will be called too), [errorFactory] and then will be returned null */ -suspend fun Scenario.expectOne( +suspend fun BehaviourContext.expectOne( initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, cancelRequestFactory: NullableRequestBuilder<*> = { null }, diff --git a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/expectations/WaitCallbackQuery.kt b/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/expectations/WaitCallbackQuery.kt index 18716f49d7..0aa468d436 100644 --- a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/expectations/WaitCallbackQuery.kt +++ b/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/expectations/WaitCallbackQuery.kt @@ -2,20 +2,15 @@ package dev.inmo.tgbotapi.extensions.steps.expectations -import dev.inmo.tgbotapi.extensions.steps.Scenario +import dev.inmo.tgbotapi.extensions.steps.BehaviourContext import dev.inmo.tgbotapi.extensions.utils.* import dev.inmo.tgbotapi.requests.abstracts.Request import dev.inmo.tgbotapi.types.CallbackQuery.* -import dev.inmo.tgbotapi.types.message.ChatEvents.* -import dev.inmo.tgbotapi.types.message.ChatEvents.abstracts.* -import dev.inmo.tgbotapi.types.message.abstracts.ChatEventMessage -import dev.inmo.tgbotapi.types.message.content.ContactContent -import dev.inmo.tgbotapi.types.update.CallbackQueryUpdate import kotlinx.coroutines.flow.toList typealias CallbackQueryMapper = T.() -> T? -private suspend fun Scenario.waitCallbackQueries( +private suspend fun BehaviourContext.waitCallbackQueries( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, @@ -29,7 +24,7 @@ private suspend fun Scenario.waitCallbackQueries( }.toList().toList() -private suspend inline fun Scenario.waitEvents( +private suspend inline fun BehaviourContext.waitEvents( count: Int = 1, initRequest: Request<*>? = null, noinline errorFactory: NullableRequestBuilder<*> = { null }, @@ -51,55 +46,55 @@ private suspend inline fun Scenario.waitEvents( } -suspend fun Scenario.waitDataCallbackQuery( +suspend fun BehaviourContext.waitDataCallbackQuery( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, filter: CallbackQueryMapper? = null ) = waitEvents(count, initRequest, errorFactory, filter) -suspend fun Scenario.waitGameShortNameCallbackQuery( +suspend fun BehaviourContext.waitGameShortNameCallbackQuery( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, filter: CallbackQueryMapper? = null ) = waitEvents(count, initRequest, errorFactory, filter) -suspend fun Scenario.waitInlineMessageIdCallbackQuery( +suspend fun BehaviourContext.waitInlineMessageIdCallbackQuery( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, filter: CallbackQueryMapper? = null ) = waitEvents(count, initRequest, errorFactory, filter) -suspend fun Scenario.waitInlineMessageIdDataCallbackQuery( +suspend fun BehaviourContext.waitInlineMessageIdDataCallbackQuery( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, filter: CallbackQueryMapper? = null ) = waitEvents(count, initRequest, errorFactory, filter) -suspend fun Scenario.waitInlineMessageIdGameShortNameCallbackQuery( +suspend fun BehaviourContext.waitInlineMessageIdGameShortNameCallbackQuery( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, filter: CallbackQueryMapper? = null ) = waitEvents(count, initRequest, errorFactory, filter) -suspend fun Scenario.waitMessageCallbackQuery( +suspend fun BehaviourContext.waitMessageCallbackQuery( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, filter: CallbackQueryMapper? = null ) = waitEvents(count, initRequest, errorFactory, filter) -suspend fun Scenario.waitMessageDataCallbackQuery( +suspend fun BehaviourContext.waitMessageDataCallbackQuery( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, filter: CallbackQueryMapper? = null ) = waitEvents(count, initRequest, errorFactory, filter) -suspend fun Scenario.waitMessageGameShortNameCallbackQuery( +suspend fun BehaviourContext.waitMessageGameShortNameCallbackQuery( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, filter: CallbackQueryMapper? = null ) = waitEvents(count, initRequest, errorFactory, filter) -suspend fun Scenario.waitUnknownCallbackQuery( +suspend fun BehaviourContext.waitUnknownCallbackQuery( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, diff --git a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/expectations/WaitContent.kt b/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/expectations/WaitContent.kt index 20e15bbcb6..b1b5ef71db 100644 --- a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/expectations/WaitContent.kt +++ b/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/expectations/WaitContent.kt @@ -2,7 +2,7 @@ package dev.inmo.tgbotapi.extensions.steps.expectations -import dev.inmo.tgbotapi.extensions.steps.Scenario +import dev.inmo.tgbotapi.extensions.steps.BehaviourContext import dev.inmo.tgbotapi.extensions.utils.asContentMessage import dev.inmo.tgbotapi.extensions.utils.asMessageUpdate import dev.inmo.tgbotapi.requests.abstracts.Request @@ -15,7 +15,7 @@ import kotlinx.coroutines.flow.toList typealias ContentMessageToContentMapper = suspend ContentMessage.() -> T? -private suspend fun Scenario.waitContentMessage( +private suspend fun BehaviourContext.waitContentMessage( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, @@ -28,7 +28,7 @@ private suspend fun Scenario.waitContentMessage( it.asMessageUpdate() ?.data ?.asContentMessage() ?.mapper() }.toList().toList() -private suspend inline fun Scenario.waitContent( +private suspend inline fun BehaviourContext.waitContent( count: Int = 1, initRequest: Request<*>? = null, noinline errorFactory: NullableRequestBuilder<*> = { null }, @@ -51,127 +51,127 @@ private suspend inline fun Scenario.waitContent( } } -suspend fun Scenario.waitContact( +suspend fun BehaviourContext.waitContact( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, filter: ContentMessageToContentMapper? = null ) = waitContent(count, initRequest, errorFactory, filter) -suspend fun Scenario.waitDice( +suspend fun BehaviourContext.waitDice( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, filter: ContentMessageToContentMapper? = null ) = waitContent(count, initRequest, errorFactory, filter) -suspend fun Scenario.waitGame( +suspend fun BehaviourContext.waitGame( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, filter: ContentMessageToContentMapper? = null ) = waitContent(count, initRequest, errorFactory, filter) -suspend fun Scenario.waitLocation( +suspend fun BehaviourContext.waitLocation( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, filter: ContentMessageToContentMapper? = null ) = waitContent(count, initRequest, errorFactory, filter) -suspend fun Scenario.waitPoll( +suspend fun BehaviourContext.waitPoll( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, filter: ContentMessageToContentMapper? = null ) = waitContent(count, initRequest, errorFactory, filter) -suspend fun Scenario.waitText( +suspend fun BehaviourContext.waitText( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, filter: ContentMessageToContentMapper? = null ) = waitContent(count, initRequest, errorFactory, filter) -suspend fun Scenario.waitVenue( +suspend fun BehaviourContext.waitVenue( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, filter: ContentMessageToContentMapper? = null ) = waitContent(count, initRequest, errorFactory, filter) -suspend fun Scenario.waitAudioMediaGroup( +suspend fun BehaviourContext.waitAudioMediaGroup( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, filter: ContentMessageToContentMapper? = null ) = waitContent(count, initRequest, errorFactory, filter) -suspend fun Scenario.waitDocumentMediaGroup( +suspend fun BehaviourContext.waitDocumentMediaGroup( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, filter: ContentMessageToContentMapper? = null ) = waitContent(count, initRequest, errorFactory, filter) -suspend fun Scenario.waitMedia( +suspend fun BehaviourContext.waitMedia( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, filter: ContentMessageToContentMapper? = null ) = waitContent(count, initRequest, errorFactory, filter) -suspend fun Scenario.waitMediaGroup( +suspend fun BehaviourContext.waitMediaGroup( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, filter: ContentMessageToContentMapper? = null ) = waitContent(count, initRequest, errorFactory, filter) -suspend fun Scenario.waitVisualMediaGroup( +suspend fun BehaviourContext.waitVisualMediaGroup( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, filter: ContentMessageToContentMapper? = null ) = waitContent(count, initRequest, errorFactory, filter) -suspend fun Scenario.waitAnimation( +suspend fun BehaviourContext.waitAnimation( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, filter: ContentMessageToContentMapper? = null ) = waitContent(count, initRequest, errorFactory, filter) -suspend fun Scenario.waitAudio( +suspend fun BehaviourContext.waitAudio( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, filter: ContentMessageToContentMapper? = null ) = waitContent(count, initRequest, errorFactory, filter) -suspend fun Scenario.waitDocument( +suspend fun BehaviourContext.waitDocument( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, filter: ContentMessageToContentMapper? = null ) = waitContent(count, initRequest, errorFactory, filter) -suspend fun Scenario.waitPhoto( +suspend fun BehaviourContext.waitPhoto( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, filter: ContentMessageToContentMapper? = null ) = waitContent(count, initRequest, errorFactory, filter) -suspend fun Scenario.waitSticker( +suspend fun BehaviourContext.waitSticker( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, filter: ContentMessageToContentMapper? = null ) = waitContent(count, initRequest, errorFactory, filter) -suspend fun Scenario.waitVideo( +suspend fun BehaviourContext.waitVideo( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, filter: ContentMessageToContentMapper? = null ) = waitContent(count, initRequest, errorFactory, filter) -suspend fun Scenario.waitVideoNote( +suspend fun BehaviourContext.waitVideoNote( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, filter: ContentMessageToContentMapper? = null ) = waitContent(count, initRequest, errorFactory, filter) -suspend fun Scenario.waitVoice( +suspend fun BehaviourContext.waitVoice( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, filter: ContentMessageToContentMapper? = null ) = waitContent(count, initRequest, errorFactory, filter) -suspend fun Scenario.waitInvoice( +suspend fun BehaviourContext.waitInvoice( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, diff --git a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/expectations/WaitEventAction.kt b/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/expectations/WaitEventAction.kt index b96a999eed..61cfc69f74 100644 --- a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/expectations/WaitEventAction.kt +++ b/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/expectations/WaitEventAction.kt @@ -2,18 +2,17 @@ package dev.inmo.tgbotapi.extensions.steps.expectations -import dev.inmo.tgbotapi.extensions.steps.Scenario +import dev.inmo.tgbotapi.extensions.steps.BehaviourContext import dev.inmo.tgbotapi.extensions.utils.* import dev.inmo.tgbotapi.requests.abstracts.Request import dev.inmo.tgbotapi.types.message.ChatEvents.* import dev.inmo.tgbotapi.types.message.ChatEvents.abstracts.* import dev.inmo.tgbotapi.types.message.abstracts.ChatEventMessage -import dev.inmo.tgbotapi.types.message.content.ContactContent import kotlinx.coroutines.flow.toList typealias EventMessageToEventMapper = suspend ChatEventMessage.() -> T? -private suspend fun Scenario.waitEventMessages( +private suspend fun BehaviourContext.waitEventMessages( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, @@ -27,7 +26,7 @@ private suspend fun Scenario.waitEventMessages( }.toList().toList() -private suspend inline fun Scenario.waitEvents( +private suspend inline fun BehaviourContext.waitEvents( count: Int = 1, initRequest: Request<*>? = null, noinline errorFactory: NullableRequestBuilder<*> = { null }, @@ -50,93 +49,93 @@ private suspend inline fun Scenario.waitEvents( } } -suspend fun Scenario.waitChannelEvents( +suspend fun BehaviourContext.waitChannelEvents( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, filter: EventMessageToEventMapper? = null ) = waitEvents(count, initRequest, errorFactory, filter) -suspend fun Scenario.waitChatEvents( +suspend fun BehaviourContext.waitChatEvents( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, filter: EventMessageToEventMapper? = null ) = waitEvents(count, initRequest, errorFactory, filter) -suspend fun Scenario.waitCommonEvents( +suspend fun BehaviourContext.waitCommonEvents( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, filter: EventMessageToEventMapper? = null ) = waitEvents(count, initRequest, errorFactory, filter) -suspend fun Scenario.waitGroupEvents( +suspend fun BehaviourContext.waitGroupEvents( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, filter: EventMessageToEventMapper? = null ) = waitEvents(count, initRequest, errorFactory, filter) -suspend fun Scenario.waitSupergroupEvents( +suspend fun BehaviourContext.waitSupergroupEvents( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, filter: EventMessageToEventMapper? = null ) = waitEvents(count, initRequest, errorFactory, filter) -suspend fun Scenario.waitChannelChatCreatedEvents( +suspend fun BehaviourContext.waitChannelChatCreatedEvents( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, filter: EventMessageToEventMapper? = null ) = waitEvents(count, initRequest, errorFactory, filter) -suspend fun Scenario.waitDeleteChatPhotoEvents( +suspend fun BehaviourContext.waitDeleteChatPhotoEvents( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, filter: EventMessageToEventMapper? = null ) = waitEvents(count, initRequest, errorFactory, filter) -suspend fun Scenario.waitGroupChatCreatedEvents( +suspend fun BehaviourContext.waitGroupChatCreatedEvents( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, filter: EventMessageToEventMapper? = null ) = waitEvents(count, initRequest, errorFactory, filter) -suspend fun Scenario.waitLeftChatMemberEvents( +suspend fun BehaviourContext.waitLeftChatMemberEvents( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, filter: EventMessageToEventMapper? = null ) = waitEvents(count, initRequest, errorFactory, filter) -suspend fun Scenario.waitNewChatPhotoEvents( +suspend fun BehaviourContext.waitNewChatPhotoEvents( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, filter: EventMessageToEventMapper? = null ) = waitEvents(count, initRequest, errorFactory, filter) -suspend fun Scenario.waitNewChatMembersEvents( +suspend fun BehaviourContext.waitNewChatMembersEvents( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, filter: EventMessageToEventMapper? = null ) = waitEvents(count, initRequest, errorFactory, filter) -suspend fun Scenario.waitNewChatTitleEvents( +suspend fun BehaviourContext.waitNewChatTitleEvents( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, filter: EventMessageToEventMapper? = null ) = waitEvents(count, initRequest, errorFactory, filter) -suspend fun Scenario.waitPinnedMessageEvents( +suspend fun BehaviourContext.waitPinnedMessageEvents( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, filter: EventMessageToEventMapper? = null ) = waitEvents(count, initRequest, errorFactory, filter) -suspend fun Scenario.waitProximityAlertTriggeredEvents( +suspend fun BehaviourContext.waitProximityAlertTriggeredEvents( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, filter: EventMessageToEventMapper? = null ) = waitEvents(count, initRequest, errorFactory, filter) -suspend fun Scenario.waitSupergroupChatCreatedEvents( +suspend fun BehaviourContext.waitSupergroupChatCreatedEvents( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, diff --git a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/triggers_handling/CallbackQueryTriggers.kt b/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/triggers_handling/CallbackQueryTriggers.kt index 1e9f97dc9b..9896dff146 100644 --- a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/triggers_handling/CallbackQueryTriggers.kt +++ b/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/triggers_handling/CallbackQueryTriggers.kt @@ -3,8 +3,8 @@ package dev.inmo.tgbotapi.extensions.steps.triggers_handling import dev.inmo.micro_utils.coroutines.safelyWithoutExceptions import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions -import dev.inmo.tgbotapi.extensions.steps.Scenario -import dev.inmo.tgbotapi.extensions.steps.ScenarioAndTypeReceiver +import dev.inmo.tgbotapi.extensions.steps.BehaviourContext +import dev.inmo.tgbotapi.extensions.steps.BehaviourContextAndTypeReceiver import dev.inmo.tgbotapi.extensions.steps.expectations.expectFlow import dev.inmo.tgbotapi.extensions.utils.* import dev.inmo.tgbotapi.extensions.utils.extensions.sourceChat @@ -14,10 +14,10 @@ import dev.inmo.tgbotapi.types.message.ChatEvents.abstracts.* import dev.inmo.tgbotapi.updateshandlers.FlowsUpdatesFilter import kotlinx.coroutines.flow.filter -internal suspend inline fun Scenario.onCallbackQuery( - includeFilterByChatInSubScenario: Boolean = true, +internal suspend inline fun BehaviourContext.onCallbackQuery( + includeFilterByChatInBehaviourSubContext: Boolean = true, noinline additionalFilter: (suspend (T) -> Boolean)? = null, - noinline scenarioReceiver: ScenarioAndTypeReceiver + noinline scenarioReceiver: BehaviourContextAndTypeReceiver ) = flowsUpdatesFilter.expectFlow(bot) { it.asCallbackQueryUpdate() ?.data ?.let { query -> if (query is T) { @@ -27,14 +27,14 @@ internal suspend inline fun Scenario.onCallbackQuery } } }.subscribeSafelyWithoutExceptions(scope) { triggerQuery -> - val (jobToCancel, scenario) = if (includeFilterByChatInSubScenario) { + val (jobToCancel, scenario) = if (includeFilterByChatInBehaviourSubContext) { val subFilter = FlowsUpdatesFilter() - val subScenario = copy(flowsUpdatesFilter = subFilter) + val subBehaviourContext = copy(flowsUpdatesFilter = subFilter) flowsUpdatesFilter.allUpdatesFlow.filter { val chat = it.sourceChat() ?: return@filter false chat.id.chatId == triggerQuery.user.id.chatId - }.subscribeSafelyWithoutExceptions(scope, subFilter.asUpdateReceiver) to subScenario + }.subscribeSafelyWithoutExceptions(scope, subFilter.asUpdateReceiver) to subBehaviourContext } else { null to this } @@ -43,49 +43,49 @@ internal suspend inline fun Scenario.onCallbackQuery } -suspend fun Scenario.onDataCallbackQuery( - includeFilterByChatInSubScenario: Boolean = true, +suspend fun BehaviourContext.onDataCallbackQuery( + includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (DataCallbackQuery) -> Boolean)? = null, - scenarioReceiver: ScenarioAndTypeReceiver -) = onCallbackQuery(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) + scenarioReceiver: BehaviourContextAndTypeReceiver +) = onCallbackQuery(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) -suspend fun Scenario.onGameShortNameCallbackQuery( - includeFilterByChatInSubScenario: Boolean = true, +suspend fun BehaviourContext.onGameShortNameCallbackQuery( + includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (GameShortNameCallbackQuery) -> Boolean)? = null, - scenarioReceiver: ScenarioAndTypeReceiver -) = onCallbackQuery(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) -suspend fun Scenario.onInlineMessageIdCallbackQuery( - includeFilterByChatInSubScenario: Boolean = true, + scenarioReceiver: BehaviourContextAndTypeReceiver +) = onCallbackQuery(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) +suspend fun BehaviourContext.onInlineMessageIdCallbackQuery( + includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (InlineMessageIdCallbackQuery) -> Boolean)? = null, - scenarioReceiver: ScenarioAndTypeReceiver -) = onCallbackQuery(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) -suspend fun Scenario.onInlineMessageIdDataCallbackQuery( - includeFilterByChatInSubScenario: Boolean = true, + scenarioReceiver: BehaviourContextAndTypeReceiver +) = onCallbackQuery(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) +suspend fun BehaviourContext.onInlineMessageIdDataCallbackQuery( + includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (InlineMessageIdDataCallbackQuery) -> Boolean)? = null, - scenarioReceiver: ScenarioAndTypeReceiver -) = onCallbackQuery(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) -suspend fun Scenario.onInlineMessageIdGameShortNameCallbackQuery( - includeFilterByChatInSubScenario: Boolean = true, + scenarioReceiver: BehaviourContextAndTypeReceiver +) = onCallbackQuery(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) +suspend fun BehaviourContext.onInlineMessageIdGameShortNameCallbackQuery( + includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (InlineMessageIdGameShortNameCallbackQuery) -> Boolean)? = null, - scenarioReceiver: ScenarioAndTypeReceiver -) = onCallbackQuery(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) -suspend fun Scenario.onMessageCallbackQuery( - includeFilterByChatInSubScenario: Boolean = true, + scenarioReceiver: BehaviourContextAndTypeReceiver +) = onCallbackQuery(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) +suspend fun BehaviourContext.onMessageCallbackQuery( + includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (MessageCallbackQuery) -> Boolean)? = null, - scenarioReceiver: ScenarioAndTypeReceiver -) = onCallbackQuery(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) -suspend fun Scenario.onMessageDataCallbackQuery( - includeFilterByChatInSubScenario: Boolean = true, + scenarioReceiver: BehaviourContextAndTypeReceiver +) = onCallbackQuery(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) +suspend fun BehaviourContext.onMessageDataCallbackQuery( + includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (MessageDataCallbackQuery) -> Boolean)? = null, - scenarioReceiver: ScenarioAndTypeReceiver -) = onCallbackQuery(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) -suspend fun Scenario.onMessageGameShortNameCallbackQuery( - includeFilterByChatInSubScenario: Boolean = true, + scenarioReceiver: BehaviourContextAndTypeReceiver +) = onCallbackQuery(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) +suspend fun BehaviourContext.onMessageGameShortNameCallbackQuery( + includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (MessageGameShortNameCallbackQuery) -> Boolean)? = null, - scenarioReceiver: ScenarioAndTypeReceiver -) = onCallbackQuery(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) -suspend fun Scenario.onUnknownCallbackQueryType( - includeFilterByChatInSubScenario: Boolean = true, + scenarioReceiver: BehaviourContextAndTypeReceiver +) = onCallbackQuery(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) +suspend fun BehaviourContext.onUnknownCallbackQueryType( + includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (UnknownCallbackQueryType) -> Boolean)? = null, - scenarioReceiver: ScenarioAndTypeReceiver -) = onCallbackQuery(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) + scenarioReceiver: BehaviourContextAndTypeReceiver +) = onCallbackQuery(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) diff --git a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/triggers_handling/CommandHandling.kt b/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/triggers_handling/CommandHandling.kt index a730143072..f257208f3d 100644 --- a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/triggers_handling/CommandHandling.kt +++ b/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/triggers_handling/CommandHandling.kt @@ -7,13 +7,13 @@ import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage import dev.inmo.tgbotapi.types.message.content.TextContent import kotlinx.coroutines.Job -suspend fun Scenario.command( +suspend fun BehaviourContext.command( commandRegex: Regex, requireOnlyCommandInMessage: Boolean = true, - includeFilterByChatInSubScenario: Boolean = true, - scenarioReceiver: ScenarioAndTypeReceiver> + includeFilterByChatInBehaviourSubContext: Boolean = true, + scenarioReceiver: BehaviourContextAndTypeReceiver> ): Job = onText( - includeFilterByChatInSubScenario, + includeFilterByChatInBehaviourSubContext, { message -> val content = message.content val textSources = content.textSources @@ -27,4 +27,9 @@ suspend fun Scenario.command( scenarioReceiver ) - +suspend inline fun BehaviourContext.onCommand( + commandRegex: Regex, + requireOnlyCommandInMessage: Boolean = true, + includeFilterByChatInBehaviourSubContext: Boolean = true, + noinline scenarioReceiver: BehaviourContextAndTypeReceiver> +): Job = command(commandRegex, requireOnlyCommandInMessage, includeFilterByChatInBehaviourSubContext, scenarioReceiver) diff --git a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/triggers_handling/ContentTriggers.kt b/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/triggers_handling/ContentTriggers.kt index 9bb3a49bb9..75209b1436 100644 --- a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/triggers_handling/ContentTriggers.kt +++ b/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/triggers_handling/ContentTriggers.kt @@ -3,8 +3,8 @@ package dev.inmo.tgbotapi.extensions.steps.triggers_handling import dev.inmo.micro_utils.coroutines.safelyWithoutExceptions import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions -import dev.inmo.tgbotapi.extensions.steps.Scenario -import dev.inmo.tgbotapi.extensions.steps.ScenarioAndTypeReceiver +import dev.inmo.tgbotapi.extensions.steps.BehaviourContext +import dev.inmo.tgbotapi.extensions.steps.BehaviourContextAndTypeReceiver import dev.inmo.tgbotapi.extensions.steps.expectations.expectFlow import dev.inmo.tgbotapi.extensions.utils.asContentMessage import dev.inmo.tgbotapi.extensions.utils.asMessageUpdate @@ -19,10 +19,10 @@ import dev.inmo.tgbotapi.updateshandlers.FlowsUpdatesFilter import kotlinx.coroutines.flow.filter -internal suspend inline fun Scenario.onContent( - includeFilterByChatInSubScenario: Boolean = true, +internal suspend inline fun BehaviourContext.onContent( + includeFilterByChatInBehaviourSubContext: Boolean = true, noinline additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, - noinline scenarioReceiver: ScenarioAndTypeReceiver> + noinline scenarioReceiver: BehaviourContextAndTypeReceiver> ) = flowsUpdatesFilter.expectFlow(bot) { it.asMessageUpdate() ?.data ?.asContentMessage() ?.let { message -> if (message.content is T) { @@ -33,14 +33,14 @@ internal suspend inline fun Scenario.onContent( } } }.subscribeSafelyWithoutExceptions(scope) { triggerMessage -> - val (jobToCancel, scenario) = if (includeFilterByChatInSubScenario) { + val (jobToCancel, scenario) = if (includeFilterByChatInBehaviourSubContext) { val subFilter = FlowsUpdatesFilter() - val subScenario = copy(flowsUpdatesFilter = subFilter) + val subBehaviourContext = copy(flowsUpdatesFilter = subFilter) flowsUpdatesFilter.allUpdatesFlow.filter { val chat = it.sourceChat() ?: return@filter false chat.id.chatId == triggerMessage.chat.id.chatId - }.subscribeSafelyWithoutExceptions(scope, subFilter.asUpdateReceiver) to subScenario + }.subscribeSafelyWithoutExceptions(scope, subFilter.asUpdateReceiver) to subBehaviourContext } else { null to this } @@ -48,113 +48,113 @@ internal suspend inline fun Scenario.onContent( jobToCancel ?.cancel() } -suspend fun Scenario.onContact( - includeFilterByChatInSubScenario: Boolean = true, +suspend fun BehaviourContext.onContact( + includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, - scenarioReceiver: ScenarioAndTypeReceiver> -) = onContent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) -suspend fun Scenario.onDice( - includeFilterByChatInSubScenario: Boolean = true, + scenarioReceiver: BehaviourContextAndTypeReceiver> +) = onContent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) +suspend fun BehaviourContext.onDice( + includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, - scenarioReceiver: ScenarioAndTypeReceiver> -) = onContent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) -suspend fun Scenario.onGame( - includeFilterByChatInSubScenario: Boolean = true, + scenarioReceiver: BehaviourContextAndTypeReceiver> +) = onContent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) +suspend fun BehaviourContext.onGame( + includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, - scenarioReceiver: ScenarioAndTypeReceiver> -) = onContent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) -suspend fun Scenario.onLocation( - includeFilterByChatInSubScenario: Boolean = true, + scenarioReceiver: BehaviourContextAndTypeReceiver> +) = onContent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) +suspend fun BehaviourContext.onLocation( + includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, - scenarioReceiver: ScenarioAndTypeReceiver> -) = onContent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) -suspend fun Scenario.onPoll( - includeFilterByChatInSubScenario: Boolean = true, + scenarioReceiver: BehaviourContextAndTypeReceiver> +) = onContent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) +suspend fun BehaviourContext.onPoll( + includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, - scenarioReceiver: ScenarioAndTypeReceiver> -) = onContent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) -suspend fun Scenario.onText( - includeFilterByChatInSubScenario: Boolean = true, + scenarioReceiver: BehaviourContextAndTypeReceiver> +) = onContent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) +suspend fun BehaviourContext.onText( + includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, - scenarioReceiver: ScenarioAndTypeReceiver> -) = onContent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) -suspend fun Scenario.onVenue( - includeFilterByChatInSubScenario: Boolean = true, + scenarioReceiver: BehaviourContextAndTypeReceiver> +) = onContent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) +suspend fun BehaviourContext.onVenue( + includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, - scenarioReceiver: ScenarioAndTypeReceiver> -) = onContent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) -suspend fun Scenario.onAudioMediaGroup( - includeFilterByChatInSubScenario: Boolean = true, + scenarioReceiver: BehaviourContextAndTypeReceiver> +) = onContent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) +suspend fun BehaviourContext.onAudioMediaGroup( + includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, - scenarioReceiver: ScenarioAndTypeReceiver> -) = onContent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) -suspend fun Scenario.onDocumentMediaGroup( - includeFilterByChatInSubScenario: Boolean = true, + scenarioReceiver: BehaviourContextAndTypeReceiver> +) = onContent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) +suspend fun BehaviourContext.onDocumentMediaGroup( + includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, - scenarioReceiver: ScenarioAndTypeReceiver> -) = onContent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) -suspend fun Scenario.onMediaCollection( - includeFilterByChatInSubScenario: Boolean = true, + scenarioReceiver: BehaviourContextAndTypeReceiver> +) = onContent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) +suspend fun BehaviourContext.onMediaCollection( + includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (ContentMessage>) -> Boolean)? = null, - scenarioReceiver: ScenarioAndTypeReceiver>> -) = onContent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) -suspend fun Scenario.onMedia( - includeFilterByChatInSubScenario: Boolean = true, + scenarioReceiver: BehaviourContextAndTypeReceiver>> +) = onContent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) +suspend fun BehaviourContext.onMedia( + includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, - scenarioReceiver: ScenarioAndTypeReceiver> -) = onContent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) -suspend fun Scenario.onMediaGroup( - includeFilterByChatInSubScenario: Boolean = true, + scenarioReceiver: BehaviourContextAndTypeReceiver> +) = onContent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) +suspend fun BehaviourContext.onMediaGroup( + includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, - scenarioReceiver: ScenarioAndTypeReceiver> -) = onContent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) -suspend fun Scenario.onVisualMediaGroup( - includeFilterByChatInSubScenario: Boolean = true, + scenarioReceiver: BehaviourContextAndTypeReceiver> +) = onContent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) +suspend fun BehaviourContext.onVisualMediaGroup( + includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, - scenarioReceiver: ScenarioAndTypeReceiver> -) = onContent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) -suspend fun Scenario.onAnimation( - includeFilterByChatInSubScenario: Boolean = true, + scenarioReceiver: BehaviourContextAndTypeReceiver> +) = onContent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) +suspend fun BehaviourContext.onAnimation( + includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, - scenarioReceiver: ScenarioAndTypeReceiver> -) = onContent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) -suspend fun Scenario.onAudio( - includeFilterByChatInSubScenario: Boolean = true, + scenarioReceiver: BehaviourContextAndTypeReceiver> +) = onContent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) +suspend fun BehaviourContext.onAudio( + includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, - scenarioReceiver: ScenarioAndTypeReceiver> -) = onContent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) -suspend fun Scenario.onDocument( - includeFilterByChatInSubScenario: Boolean = true, + scenarioReceiver: BehaviourContextAndTypeReceiver> +) = onContent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) +suspend fun BehaviourContext.onDocument( + includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, - scenarioReceiver: ScenarioAndTypeReceiver> -) = onContent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) -suspend fun Scenario.onPhoto( - includeFilterByChatInSubScenario: Boolean = true, + scenarioReceiver: BehaviourContextAndTypeReceiver> +) = onContent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) +suspend fun BehaviourContext.onPhoto( + includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, - scenarioReceiver: ScenarioAndTypeReceiver> -) = onContent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) -suspend fun Scenario.onSticker( - includeFilterByChatInSubScenario: Boolean = true, + scenarioReceiver: BehaviourContextAndTypeReceiver> +) = onContent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) +suspend fun BehaviourContext.onSticker( + includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, - scenarioReceiver: ScenarioAndTypeReceiver> -) = onContent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) -suspend fun Scenario.onVideo( - includeFilterByChatInSubScenario: Boolean = true, + scenarioReceiver: BehaviourContextAndTypeReceiver> +) = onContent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) +suspend fun BehaviourContext.onVideo( + includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, - scenarioReceiver: ScenarioAndTypeReceiver> -) = onContent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) -suspend fun Scenario.onVideoNote( - includeFilterByChatInSubScenario: Boolean = true, + scenarioReceiver: BehaviourContextAndTypeReceiver> +) = onContent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) +suspend fun BehaviourContext.onVideoNote( + includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, - scenarioReceiver: ScenarioAndTypeReceiver> -) = onContent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) -suspend fun Scenario.onVoice( - includeFilterByChatInSubScenario: Boolean = true, + scenarioReceiver: BehaviourContextAndTypeReceiver> +) = onContent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) +suspend fun BehaviourContext.onVoice( + includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, - scenarioReceiver: ScenarioAndTypeReceiver> -) = onContent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) -suspend fun Scenario.onInvoice( - includeFilterByChatInSubScenario: Boolean = true, + scenarioReceiver: BehaviourContextAndTypeReceiver> +) = onContent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) +suspend fun BehaviourContext.onInvoice( + includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, - scenarioReceiver: ScenarioAndTypeReceiver> -) = onContent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) + scenarioReceiver: BehaviourContextAndTypeReceiver> +) = onContent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) diff --git a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/triggers_handling/EventTriggers.kt b/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/triggers_handling/EventTriggers.kt index e447a0d842..db46c07ac6 100644 --- a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/triggers_handling/EventTriggers.kt +++ b/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/triggers_handling/EventTriggers.kt @@ -3,27 +3,24 @@ package dev.inmo.tgbotapi.extensions.steps.triggers_handling import dev.inmo.micro_utils.coroutines.safelyWithoutExceptions import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions -import dev.inmo.tgbotapi.extensions.steps.Scenario -import dev.inmo.tgbotapi.extensions.steps.ScenarioAndTypeReceiver +import dev.inmo.tgbotapi.extensions.steps.BehaviourContext +import dev.inmo.tgbotapi.extensions.steps.BehaviourContextAndTypeReceiver import dev.inmo.tgbotapi.extensions.steps.expectations.expectFlow import dev.inmo.tgbotapi.extensions.utils.* import dev.inmo.tgbotapi.extensions.utils.extensions.sourceChat -import dev.inmo.tgbotapi.types.files.abstracts.TelegramMediaFile import dev.inmo.tgbotapi.types.message.ChatEvents.* import dev.inmo.tgbotapi.types.message.ChatEvents.abstracts.* import dev.inmo.tgbotapi.types.message.abstracts.ChatEventMessage -import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage 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.payments.InvoiceContent import dev.inmo.tgbotapi.updateshandlers.FlowsUpdatesFilter import kotlinx.coroutines.flow.filter -internal suspend inline fun Scenario.onEvent( - includeFilterByChatInSubScenario: Boolean = true, +internal suspend inline fun BehaviourContext.onEvent( + includeFilterByChatInBehaviourSubContext: Boolean = true, noinline additionalFilter: (suspend (ChatEventMessage) -> Boolean)? = null, - noinline scenarioReceiver: ScenarioAndTypeReceiver> + noinline scenarioReceiver: BehaviourContextAndTypeReceiver> ) = flowsUpdatesFilter.expectFlow(bot) { it.asMessageUpdate() ?.data ?.asChatEventMessage() ?.let { message -> if (message.chatEvent is T) { @@ -34,14 +31,14 @@ internal suspend inline fun Scenario.onEvent( } } }.subscribeSafelyWithoutExceptions(scope) { triggerMessage -> - val (jobToCancel, scenario) = if (includeFilterByChatInSubScenario) { + val (jobToCancel, scenario) = if (includeFilterByChatInBehaviourSubContext) { val subFilter = FlowsUpdatesFilter() - val subScenario = copy(flowsUpdatesFilter = subFilter) + val subBehaviourContext = copy(flowsUpdatesFilter = subFilter) flowsUpdatesFilter.allUpdatesFlow.filter { val chat = it.sourceChat() ?: return@filter false chat.id.chatId == triggerMessage.chat.id.chatId - }.subscribeSafelyWithoutExceptions(scope, subFilter.asUpdateReceiver) to subScenario + }.subscribeSafelyWithoutExceptions(scope, subFilter.asUpdateReceiver) to subBehaviourContext } else { null to this } @@ -49,79 +46,79 @@ internal suspend inline fun Scenario.onEvent( jobToCancel ?.cancel() } -suspend fun Scenario.onChannelEvent( - includeFilterByChatInSubScenario: Boolean = true, +suspend fun BehaviourContext.onChannelEvent( + includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (ChatEventMessage) -> Boolean)? = null, - scenarioReceiver: ScenarioAndTypeReceiver> -) = onEvent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) -suspend fun Scenario.onChatEvent( - includeFilterByChatInSubScenario: Boolean = true, + scenarioReceiver: BehaviourContextAndTypeReceiver> +) = onEvent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) +suspend fun BehaviourContext.onChatEvent( + includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (ChatEventMessage) -> Boolean)? = null, - scenarioReceiver: ScenarioAndTypeReceiver> -) = onEvent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) -suspend fun Scenario.onCommonEvent( - includeFilterByChatInSubScenario: Boolean = true, + scenarioReceiver: BehaviourContextAndTypeReceiver> +) = onEvent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) +suspend fun BehaviourContext.onCommonEvent( + includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (ChatEventMessage) -> Boolean)? = null, - scenarioReceiver: ScenarioAndTypeReceiver> -) = onEvent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) -suspend fun Scenario.onGroupEvent( - includeFilterByChatInSubScenario: Boolean = true, + scenarioReceiver: BehaviourContextAndTypeReceiver> +) = onEvent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) +suspend fun BehaviourContext.onGroupEvent( + includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (ChatEventMessage) -> Boolean)? = null, - scenarioReceiver: ScenarioAndTypeReceiver> -) = onEvent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) -suspend fun Scenario.onSupergroupEvent( - includeFilterByChatInSubScenario: Boolean = true, + scenarioReceiver: BehaviourContextAndTypeReceiver> +) = onEvent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) +suspend fun BehaviourContext.onSupergroupEvent( + includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (ChatEventMessage) -> Boolean)? = null, - scenarioReceiver: ScenarioAndTypeReceiver> -) = onEvent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) + scenarioReceiver: BehaviourContextAndTypeReceiver> +) = onEvent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) -suspend fun Scenario.onChannelChatCreated( - includeFilterByChatInSubScenario: Boolean = true, +suspend fun BehaviourContext.onChannelChatCreated( + includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (ChatEventMessage) -> Boolean)? = null, - scenarioReceiver: ScenarioAndTypeReceiver> -) = onEvent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) -suspend fun Scenario.onDeleteChatPhoto( - includeFilterByChatInSubScenario: Boolean = true, + scenarioReceiver: BehaviourContextAndTypeReceiver> +) = onEvent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) +suspend fun BehaviourContext.onDeleteChatPhoto( + includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (ChatEventMessage) -> Boolean)? = null, - scenarioReceiver: ScenarioAndTypeReceiver> -) = onEvent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) -suspend fun Scenario.onGroupChatCreated( - includeFilterByChatInSubScenario: Boolean = true, + scenarioReceiver: BehaviourContextAndTypeReceiver> +) = onEvent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) +suspend fun BehaviourContext.onGroupChatCreated( + includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (ChatEventMessage) -> Boolean)? = null, - scenarioReceiver: ScenarioAndTypeReceiver> -) = onEvent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) -suspend fun Scenario.onLeftChatMember( - includeFilterByChatInSubScenario: Boolean = true, + scenarioReceiver: BehaviourContextAndTypeReceiver> +) = onEvent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) +suspend fun BehaviourContext.onLeftChatMember( + includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (ChatEventMessage) -> Boolean)? = null, - scenarioReceiver: ScenarioAndTypeReceiver> -) = onEvent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) -suspend fun Scenario.onNewChatMembers( - includeFilterByChatInSubScenario: Boolean = true, + scenarioReceiver: BehaviourContextAndTypeReceiver> +) = onEvent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) +suspend fun BehaviourContext.onNewChatMembers( + includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (ChatEventMessage) -> Boolean)? = null, - scenarioReceiver: ScenarioAndTypeReceiver> -) = onEvent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) -suspend fun Scenario.onNewChatPhoto( - includeFilterByChatInSubScenario: Boolean = true, + scenarioReceiver: BehaviourContextAndTypeReceiver> +) = onEvent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) +suspend fun BehaviourContext.onNewChatPhoto( + includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (ChatEventMessage) -> Boolean)? = null, - scenarioReceiver: ScenarioAndTypeReceiver> -) = onEvent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) -suspend fun Scenario.onNewChatTitle( - includeFilterByChatInSubScenario: Boolean = true, + scenarioReceiver: BehaviourContextAndTypeReceiver> +) = onEvent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) +suspend fun BehaviourContext.onNewChatTitle( + includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (ChatEventMessage) -> Boolean)? = null, - scenarioReceiver: ScenarioAndTypeReceiver> -) = onEvent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) -suspend fun Scenario.onPinnedMessage( - includeFilterByChatInSubScenario: Boolean = true, + scenarioReceiver: BehaviourContextAndTypeReceiver> +) = onEvent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) +suspend fun BehaviourContext.onPinnedMessage( + includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (ChatEventMessage) -> Boolean)? = null, - scenarioReceiver: ScenarioAndTypeReceiver> -) = onEvent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) -suspend fun Scenario.onProximityAlertTriggered( - includeFilterByChatInSubScenario: Boolean = true, + scenarioReceiver: BehaviourContextAndTypeReceiver> +) = onEvent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) +suspend fun BehaviourContext.onProximityAlertTriggered( + includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (ChatEventMessage) -> Boolean)? = null, - scenarioReceiver: ScenarioAndTypeReceiver> -) = onEvent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) -suspend fun Scenario.onSupergroupChatCreated( - includeFilterByChatInSubScenario: Boolean = true, + scenarioReceiver: BehaviourContextAndTypeReceiver> +) = onEvent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) +suspend fun BehaviourContext.onSupergroupChatCreated( + includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (ChatEventMessage) -> Boolean)? = null, - scenarioReceiver: ScenarioAndTypeReceiver> -) = onEvent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver) + scenarioReceiver: BehaviourContextAndTypeReceiver> +) = onEvent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) From b93336125885b1220fc5b8e56479875fa6388347 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Thu, 7 Jan 2021 18:12:37 +0600 Subject: [PATCH 11/66] optimize imports in steps --- .../extensions/steps/expectations/WaitCallbackQuery.kt | 2 +- .../tgbotapi/extensions/steps/expectations/WaitEventAction.kt | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/expectations/WaitCallbackQuery.kt b/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/expectations/WaitCallbackQuery.kt index 0aa468d436..bf0e4e4bce 100644 --- a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/expectations/WaitCallbackQuery.kt +++ b/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/expectations/WaitCallbackQuery.kt @@ -3,7 +3,7 @@ package dev.inmo.tgbotapi.extensions.steps.expectations import dev.inmo.tgbotapi.extensions.steps.BehaviourContext -import dev.inmo.tgbotapi.extensions.utils.* +import dev.inmo.tgbotapi.extensions.utils.asCallbackQueryUpdate import dev.inmo.tgbotapi.requests.abstracts.Request import dev.inmo.tgbotapi.types.CallbackQuery.* import kotlinx.coroutines.flow.toList diff --git a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/expectations/WaitEventAction.kt b/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/expectations/WaitEventAction.kt index 61cfc69f74..7cadcbd40b 100644 --- a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/expectations/WaitEventAction.kt +++ b/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/expectations/WaitEventAction.kt @@ -3,7 +3,8 @@ package dev.inmo.tgbotapi.extensions.steps.expectations import dev.inmo.tgbotapi.extensions.steps.BehaviourContext -import dev.inmo.tgbotapi.extensions.utils.* +import dev.inmo.tgbotapi.extensions.utils.asChatEventMessage +import dev.inmo.tgbotapi.extensions.utils.asMessageUpdate import dev.inmo.tgbotapi.requests.abstracts.Request import dev.inmo.tgbotapi.types.message.ChatEvents.* import dev.inmo.tgbotapi.types.message.ChatEvents.abstracts.* From 8c2cffc8e33ee6f14f805c8c2229a773d6beee5d Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Thu, 7 Jan 2021 18:17:50 +0600 Subject: [PATCH 12/66] rename steps subproject to behaviour_builder --- settings.gradle | 2 +- .../README.md | 0 .../build.gradle | 0 .../mpp_publish_template.kpsb | 0 .../publish.gradle | 0 .../extensions/behaviour_builder}/BehaviourBuilders.kt | 2 +- .../extensions/behaviour_builder}/BehaviourContext.kt | 2 +- .../extensions/behaviour_builder}/expectations/Base.kt | 4 ++-- .../behaviour_builder}/expectations/WaitCallbackQuery.kt | 4 ++-- .../behaviour_builder}/expectations/WaitContent.kt | 4 ++-- .../behaviour_builder}/expectations/WaitEventAction.kt | 4 ++-- .../triggers_handling/CallbackQueryTriggers.kt | 8 ++++---- .../triggers_handling/CommandHandling.kt | 4 ++-- .../triggers_handling/ContentTriggers.kt | 8 ++++---- .../behaviour_builder}/triggers_handling/EventTriggers.kt | 8 ++++---- tgbotapi/build.gradle | 2 +- 16 files changed, 26 insertions(+), 26 deletions(-) rename {tgbotapi.extensions.steps => tgbotapi.extensions.behaviour_builder}/README.md (100%) rename {tgbotapi.extensions.steps => tgbotapi.extensions.behaviour_builder}/build.gradle (100%) rename {tgbotapi.extensions.steps => tgbotapi.extensions.behaviour_builder}/mpp_publish_template.kpsb (100%) rename {tgbotapi.extensions.steps => tgbotapi.extensions.behaviour_builder}/publish.gradle (100%) rename {tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps => tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder}/BehaviourBuilders.kt (93%) rename {tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps => tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder}/BehaviourContext.kt (89%) rename {tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps => tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder}/expectations/Base.kt (97%) rename {tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps => tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder}/expectations/WaitCallbackQuery.kt (96%) rename {tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps => tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder}/expectations/WaitContent.kt (98%) rename {tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps => tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder}/expectations/WaitEventAction.kt (97%) rename {tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps => tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder}/triggers_handling/CallbackQueryTriggers.kt (94%) rename {tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps => tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder}/triggers_handling/CommandHandling.kt (91%) rename {tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps => tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder}/triggers_handling/ContentTriggers.kt (97%) rename {tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps => tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder}/triggers_handling/EventTriggers.kt (96%) diff --git a/settings.gradle b/settings.gradle index 9ef11db508..5ac47a3651 100644 --- a/settings.gradle +++ b/settings.gradle @@ -8,6 +8,6 @@ pluginManagement { include ":tgbotapi.core" include ":tgbotapi.extensions.api" include ":tgbotapi.extensions.utils" -include ":tgbotapi.extensions.steps" +include ":tgbotapi.extensions.behaviour_builder" include ":tgbotapi" include ":docs" diff --git a/tgbotapi.extensions.steps/README.md b/tgbotapi.extensions.behaviour_builder/README.md similarity index 100% rename from tgbotapi.extensions.steps/README.md rename to tgbotapi.extensions.behaviour_builder/README.md diff --git a/tgbotapi.extensions.steps/build.gradle b/tgbotapi.extensions.behaviour_builder/build.gradle similarity index 100% rename from tgbotapi.extensions.steps/build.gradle rename to tgbotapi.extensions.behaviour_builder/build.gradle diff --git a/tgbotapi.extensions.steps/mpp_publish_template.kpsb b/tgbotapi.extensions.behaviour_builder/mpp_publish_template.kpsb similarity index 100% rename from tgbotapi.extensions.steps/mpp_publish_template.kpsb rename to tgbotapi.extensions.behaviour_builder/mpp_publish_template.kpsb diff --git a/tgbotapi.extensions.steps/publish.gradle b/tgbotapi.extensions.behaviour_builder/publish.gradle similarity index 100% rename from tgbotapi.extensions.steps/publish.gradle rename to tgbotapi.extensions.behaviour_builder/publish.gradle diff --git a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/BehaviourBuilders.kt b/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourBuilders.kt similarity index 93% rename from tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/BehaviourBuilders.kt rename to tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourBuilders.kt index 269586e649..8138d6db72 100644 --- a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/BehaviourBuilders.kt +++ b/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourBuilders.kt @@ -1,4 +1,4 @@ -package dev.inmo.tgbotapi.extensions.steps +package dev.inmo.tgbotapi.extensions.behaviour_builder import dev.inmo.tgbotapi.bot.TelegramBot import dev.inmo.tgbotapi.extensions.utils.updates.retrieving.startGettingOfUpdatesByLongPolling diff --git a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/BehaviourContext.kt b/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourContext.kt similarity index 89% rename from tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/BehaviourContext.kt rename to tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourContext.kt index 935455e6f2..57f0e112fc 100644 --- a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/BehaviourContext.kt +++ b/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourContext.kt @@ -1,4 +1,4 @@ -package dev.inmo.tgbotapi.extensions.steps +package dev.inmo.tgbotapi.extensions.behaviour_builder import dev.inmo.tgbotapi.bot.TelegramBot import dev.inmo.tgbotapi.updateshandlers.FlowsUpdatesFilter diff --git a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/expectations/Base.kt b/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/Base.kt similarity index 97% rename from tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/expectations/Base.kt rename to tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/Base.kt index 7317ae0841..7ce3c98fda 100644 --- a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/expectations/Base.kt +++ b/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/Base.kt @@ -1,8 +1,8 @@ -package dev.inmo.tgbotapi.extensions.steps.expectations +package dev.inmo.tgbotapi.extensions.behaviour_builder.expectations import dev.inmo.micro_utils.coroutines.safelyWithoutExceptions import dev.inmo.tgbotapi.bot.TelegramBot -import dev.inmo.tgbotapi.extensions.steps.BehaviourContext +import dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContext import dev.inmo.tgbotapi.requests.abstracts.Request import dev.inmo.tgbotapi.types.update.abstracts.Update import dev.inmo.tgbotapi.updateshandlers.FlowsUpdatesFilter diff --git a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/expectations/WaitCallbackQuery.kt b/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/WaitCallbackQuery.kt similarity index 96% rename from tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/expectations/WaitCallbackQuery.kt rename to tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/WaitCallbackQuery.kt index bf0e4e4bce..e856bcf7ee 100644 --- a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/expectations/WaitCallbackQuery.kt +++ b/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/WaitCallbackQuery.kt @@ -1,8 +1,8 @@ @file:Suppress("unused") -package dev.inmo.tgbotapi.extensions.steps.expectations +package dev.inmo.tgbotapi.extensions.behaviour_builder.expectations -import dev.inmo.tgbotapi.extensions.steps.BehaviourContext +import dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContext import dev.inmo.tgbotapi.extensions.utils.asCallbackQueryUpdate import dev.inmo.tgbotapi.requests.abstracts.Request import dev.inmo.tgbotapi.types.CallbackQuery.* diff --git a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/expectations/WaitContent.kt b/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/WaitContent.kt similarity index 98% rename from tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/expectations/WaitContent.kt rename to tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/WaitContent.kt index b1b5ef71db..059cc75466 100644 --- a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/expectations/WaitContent.kt +++ b/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/WaitContent.kt @@ -1,8 +1,8 @@ @file:Suppress("unused") -package dev.inmo.tgbotapi.extensions.steps.expectations +package dev.inmo.tgbotapi.extensions.behaviour_builder.expectations -import dev.inmo.tgbotapi.extensions.steps.BehaviourContext +import dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContext import dev.inmo.tgbotapi.extensions.utils.asContentMessage import dev.inmo.tgbotapi.extensions.utils.asMessageUpdate import dev.inmo.tgbotapi.requests.abstracts.Request diff --git a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/expectations/WaitEventAction.kt b/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/WaitEventAction.kt similarity index 97% rename from tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/expectations/WaitEventAction.kt rename to tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/WaitEventAction.kt index 7cadcbd40b..b4f67e1a35 100644 --- a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/expectations/WaitEventAction.kt +++ b/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/WaitEventAction.kt @@ -1,8 +1,8 @@ @file:Suppress("unused") -package dev.inmo.tgbotapi.extensions.steps.expectations +package dev.inmo.tgbotapi.extensions.behaviour_builder.expectations -import dev.inmo.tgbotapi.extensions.steps.BehaviourContext +import dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContext import dev.inmo.tgbotapi.extensions.utils.asChatEventMessage import dev.inmo.tgbotapi.extensions.utils.asMessageUpdate import dev.inmo.tgbotapi.requests.abstracts.Request diff --git a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/triggers_handling/CallbackQueryTriggers.kt b/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/triggers_handling/CallbackQueryTriggers.kt similarity index 94% rename from tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/triggers_handling/CallbackQueryTriggers.kt rename to tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/triggers_handling/CallbackQueryTriggers.kt index 9896dff146..139e2a1f75 100644 --- a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/triggers_handling/CallbackQueryTriggers.kt +++ b/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/triggers_handling/CallbackQueryTriggers.kt @@ -1,11 +1,11 @@ -package dev.inmo.tgbotapi.extensions.steps.triggers_handling +package dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling import dev.inmo.micro_utils.coroutines.safelyWithoutExceptions import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions -import dev.inmo.tgbotapi.extensions.steps.BehaviourContext -import dev.inmo.tgbotapi.extensions.steps.BehaviourContextAndTypeReceiver -import dev.inmo.tgbotapi.extensions.steps.expectations.expectFlow +import dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContext +import dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContextAndTypeReceiver +import dev.inmo.tgbotapi.extensions.behaviour_builder.expectations.expectFlow import dev.inmo.tgbotapi.extensions.utils.* import dev.inmo.tgbotapi.extensions.utils.extensions.sourceChat import dev.inmo.tgbotapi.types.CallbackQuery.* diff --git a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/triggers_handling/CommandHandling.kt b/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/triggers_handling/CommandHandling.kt similarity index 91% rename from tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/triggers_handling/CommandHandling.kt rename to tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/triggers_handling/CommandHandling.kt index f257208f3d..4ee2f89bee 100644 --- a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/triggers_handling/CommandHandling.kt +++ b/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/triggers_handling/CommandHandling.kt @@ -1,7 +1,7 @@ -package dev.inmo.tgbotapi.extensions.steps.triggers_handling +package dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling import dev.inmo.tgbotapi.CommonAbstracts.textSources -import dev.inmo.tgbotapi.extensions.steps.* +import dev.inmo.tgbotapi.extensions.behaviour_builder.* import dev.inmo.tgbotapi.extensions.utils.* import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage import dev.inmo.tgbotapi.types.message.content.TextContent diff --git a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/triggers_handling/ContentTriggers.kt b/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/triggers_handling/ContentTriggers.kt similarity index 97% rename from tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/triggers_handling/ContentTriggers.kt rename to tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/triggers_handling/ContentTriggers.kt index 75209b1436..451f9dad4f 100644 --- a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/triggers_handling/ContentTriggers.kt +++ b/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/triggers_handling/ContentTriggers.kt @@ -1,11 +1,11 @@ -package dev.inmo.tgbotapi.extensions.steps.triggers_handling +package dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling import dev.inmo.micro_utils.coroutines.safelyWithoutExceptions import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions -import dev.inmo.tgbotapi.extensions.steps.BehaviourContext -import dev.inmo.tgbotapi.extensions.steps.BehaviourContextAndTypeReceiver -import dev.inmo.tgbotapi.extensions.steps.expectations.expectFlow +import dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContext +import dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContextAndTypeReceiver +import dev.inmo.tgbotapi.extensions.behaviour_builder.expectations.expectFlow import dev.inmo.tgbotapi.extensions.utils.asContentMessage import dev.inmo.tgbotapi.extensions.utils.asMessageUpdate import dev.inmo.tgbotapi.extensions.utils.extensions.sourceChat diff --git a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/triggers_handling/EventTriggers.kt b/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/triggers_handling/EventTriggers.kt similarity index 96% rename from tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/triggers_handling/EventTriggers.kt rename to tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/triggers_handling/EventTriggers.kt index db46c07ac6..9befcde684 100644 --- a/tgbotapi.extensions.steps/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/steps/triggers_handling/EventTriggers.kt +++ b/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/triggers_handling/EventTriggers.kt @@ -1,11 +1,11 @@ -package dev.inmo.tgbotapi.extensions.steps.triggers_handling +package dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling import dev.inmo.micro_utils.coroutines.safelyWithoutExceptions import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions -import dev.inmo.tgbotapi.extensions.steps.BehaviourContext -import dev.inmo.tgbotapi.extensions.steps.BehaviourContextAndTypeReceiver -import dev.inmo.tgbotapi.extensions.steps.expectations.expectFlow +import dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContext +import dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContextAndTypeReceiver +import dev.inmo.tgbotapi.extensions.behaviour_builder.expectations.expectFlow import dev.inmo.tgbotapi.extensions.utils.* import dev.inmo.tgbotapi.extensions.utils.extensions.sourceChat import dev.inmo.tgbotapi.types.message.ChatEvents.* diff --git a/tgbotapi/build.gradle b/tgbotapi/build.gradle index b033b525c2..29cf75b274 100644 --- a/tgbotapi/build.gradle +++ b/tgbotapi/build.gradle @@ -42,7 +42,7 @@ kotlin { api project(":tgbotapi.core") api project(":tgbotapi.extensions.api") api project(":tgbotapi.extensions.utils") - api project(":tgbotapi.extensions.steps") + api project(":tgbotapi.extensions.behaviour_builder") } } } From a28cf5ddff4091d2447b07e35b8673b87d456736 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Thu, 7 Jan 2021 18:20:23 +0600 Subject: [PATCH 13/66] now BehaviourContext is UpdateFilterm TelegramBot and CoroutineScope --- .../tgbotapi/extensions/behaviour_builder/BehaviourContext.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourContext.kt b/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourContext.kt index 57f0e112fc..093148c19c 100644 --- a/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourContext.kt +++ b/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourContext.kt @@ -2,6 +2,7 @@ package dev.inmo.tgbotapi.extensions.behaviour_builder import dev.inmo.tgbotapi.bot.TelegramBot import dev.inmo.tgbotapi.updateshandlers.FlowsUpdatesFilter +import dev.inmo.tgbotapi.updateshandlers.UpdatesFilter import kotlinx.coroutines.CoroutineScope typealias BehaviourContextReceiver = suspend BehaviourContext.() -> T @@ -11,4 +12,4 @@ data class BehaviourContext( val bot: TelegramBot, val scope: CoroutineScope, val flowsUpdatesFilter: FlowsUpdatesFilter = FlowsUpdatesFilter() -) +) : UpdatesFilter by flowsUpdatesFilter, TelegramBot by bot, CoroutineScope by scope From 8b79b15777d833ed2e5d643e207c97a19867b12b Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Thu, 7 Jan 2021 19:01:02 +0600 Subject: [PATCH 14/66] FlowsUpdatesFilter#allUpdatesWithoutMediaGroupsGroupingFlow --- CHANGELOG.md | 3 +++ .../inmo/tgbotapi/updateshandlers/FlowsUpdatesFilter.kt | 8 ++++++++ 2 files changed, 11 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6adfae5c17..3b9cab7453 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ ## 0.30.13 +* `Core`: + * New variable `FlowsUpdatesFilter#allUpdatesWithoutMediaGroupsGroupingFlow` which will contains updates without + `SentMediaGroupUpdate` * `Utils`: * Extensions for `ResendableContent` has been added * Extensions for `TextSource` has been added diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/updateshandlers/FlowsUpdatesFilter.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/updateshandlers/FlowsUpdatesFilter.kt index 1e8adcf5f0..ddf006e887 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/updateshandlers/FlowsUpdatesFilter.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/updateshandlers/FlowsUpdatesFilter.kt @@ -14,6 +14,14 @@ class FlowsUpdatesFilter( private val updatesSharedFlow = MutableSharedFlow(extraBufferCapacity = broadcastChannelsSize) @Suppress("MemberVisibilityCanBePrivate") val allUpdatesFlow: Flow = updatesSharedFlow.asSharedFlow() + @Suppress("MemberVisibilityCanBePrivate") + val allUpdatesWithoutMediaGroupsGroupingFlow: Flow = updatesSharedFlow.flatMapConcat { + (if (it is SentMediaGroupUpdate) { + it.origins + } else { + listOf(it) + }).asFlow() + } override val allowedUpdates: List get() = ALL_UPDATES_LIST From 633239961ab7c48d9e10b33abb6888025d3f9c21 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Thu, 7 Jan 2021 19:02:35 +0600 Subject: [PATCH 15/66] update FlowsUsh --- .../tgbotapi/updateshandlers/FlowsUpdatesFilter.kt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/updateshandlers/FlowsUpdatesFilter.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/updateshandlers/FlowsUpdatesFilter.kt index ddf006e887..e44d863dd5 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/updateshandlers/FlowsUpdatesFilter.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/updateshandlers/FlowsUpdatesFilter.kt @@ -16,11 +16,11 @@ class FlowsUpdatesFilter( val allUpdatesFlow: Flow = updatesSharedFlow.asSharedFlow() @Suppress("MemberVisibilityCanBePrivate") val allUpdatesWithoutMediaGroupsGroupingFlow: Flow = updatesSharedFlow.flatMapConcat { - (if (it is SentMediaGroupUpdate) { - it.origins - } else { - listOf(it) - }).asFlow() + when (it) { + is SentMediaGroupUpdate -> it.origins.asFlow() + is EditMediaGroupUpdate -> flowOf(it.origin) + else -> flowOf(it) + } } override val allowedUpdates: List From ce0fceb240384f9c874f99f3b86254b9bbb05732 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Fri, 8 Jan 2021 00:22:19 +0600 Subject: [PATCH 16/66] include media groups --- .../behaviour_builder/expectations/Base.kt | 18 +++--- .../expectations/WaitCallbackQuery.kt | 2 +- .../expectations/WaitContent.kt | 56 ++++++++++------- .../expectations/WaitEventAction.kt | 2 +- .../CallbackQueryTriggers.kt | 2 +- .../triggers_handling/ContentTriggers.kt | 62 +++++++++++-------- .../triggers_handling/EventTriggers.kt | 2 +- 7 files changed, 83 insertions(+), 61 deletions(-) diff --git a/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/Base.kt b/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/Base.kt index 7ce3c98fda..d1cc0925c3 100644 --- a/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/Base.kt +++ b/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/Base.kt @@ -34,11 +34,11 @@ suspend fun FlowsUpdatesFilter.expectFlow( errorFactory: NullableRequestBuilder<*> = { null }, cancelRequestFactory: NullableRequestBuilder<*> = { null }, cancelTrigger: suspend (Update) -> Boolean = { cancelRequestFactory(it) != null }, - filter: suspend (Update) -> T? + filter: suspend (Update) -> List ): Flow { - val flow = allUpdatesFlow.mapNotNull { + val flow = allUpdatesFlow.flatMapConcat { val result = safelyWithoutExceptions { filter(it) } - if (result == null) { + (if (result == null || result.isEmpty()) { if (cancelTrigger(it)) { cancelRequestFactory(it) ?.also { safelyWithoutExceptions { bot.execute(it) } @@ -48,10 +48,10 @@ suspend fun FlowsUpdatesFilter.expectFlow( errorFactory(it) ?.also { errorRequest -> safelyWithoutExceptions { bot.execute(errorRequest) } } - null + emptyList() } else { result - } + }).asFlow() } val result = if (count == null) { flow @@ -79,7 +79,7 @@ suspend fun BehaviourContext.expectFlow( errorFactory: NullableRequestBuilder<*> = { null }, cancelRequestFactory: NullableRequestBuilder<*> = { null }, cancelTrigger: suspend (Update) -> Boolean = { cancelRequestFactory(it) != null }, - filter: suspend (Update) -> T? + filter: suspend (Update) -> List ) = flowsUpdatesFilter.expectFlow(bot, initRequest, count, errorFactory, cancelRequestFactory, cancelTrigger, filter) /** @@ -99,8 +99,10 @@ suspend fun FlowsUpdatesFilter.expectOne( errorFactory: NullableRequestBuilder<*> = { null }, cancelRequestFactory: NullableRequestBuilder<*> = { null }, cancelTrigger: suspend (Update) -> Boolean = { cancelRequestFactory(it) != null }, - filter: suspend (Update) -> T?, -): T = expectFlow(bot, initRequest, 1, errorFactory, cancelRequestFactory, cancelTrigger, filter).first() + filter: suspend (Update) -> T? +): T = expectFlow(bot, initRequest, 1, errorFactory, cancelRequestFactory, cancelTrigger) { + listOfNotNull(filter.invoke(it)) +}.first() /** * @param initRequest If not null, this request will be sent by [bot] before returning value diff --git a/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/WaitCallbackQuery.kt b/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/WaitCallbackQuery.kt index e856bcf7ee..5676bb0054 100644 --- a/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/WaitCallbackQuery.kt +++ b/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/WaitCallbackQuery.kt @@ -20,7 +20,7 @@ private suspend fun BehaviourContext.waitCallbackQueries( count, errorFactory ) { - it.asCallbackQueryUpdate() ?.data ?.mapper() + it.asCallbackQueryUpdate() ?.data ?.mapper().let(::listOfNotNull) }.toList().toList() diff --git a/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/WaitContent.kt b/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/WaitContent.kt index 059cc75466..0b9e5a6df4 100644 --- a/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/WaitContent.kt +++ b/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/WaitContent.kt @@ -3,10 +3,10 @@ package dev.inmo.tgbotapi.extensions.behaviour_builder.expectations import dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContext -import dev.inmo.tgbotapi.extensions.utils.asContentMessage -import dev.inmo.tgbotapi.extensions.utils.asMessageUpdate +import dev.inmo.tgbotapi.extensions.utils.* import dev.inmo.tgbotapi.requests.abstracts.Request import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage +import dev.inmo.tgbotapi.types.message.abstracts.MediaGroupMessage import dev.inmo.tgbotapi.types.message.content.* import dev.inmo.tgbotapi.types.message.content.abstracts.* import dev.inmo.tgbotapi.types.message.content.media.* @@ -18,6 +18,7 @@ typealias ContentMessageToContentMapper = suspend ContentMessage.() -> T? private suspend fun BehaviourContext.waitContentMessage( count: Int = 1, initRequest: Request<*>? = null, + includeMediaGroups: Boolean = true, errorFactory: NullableRequestBuilder<*> = { null }, mapper: suspend ContentMessage.() -> O? ): List = expectFlow( @@ -25,17 +26,24 @@ private suspend fun BehaviourContext.waitContentMessage( count, errorFactory ) { - it.asMessageUpdate() ?.data ?.asContentMessage() ?.mapper() + if (includeMediaGroups) { + it.asSentMediaGroupUpdate() ?.data ?.mapNotNull { + (it as ContentMessage).mapper() + } ?.let { return@expectFlow it } + } + it.asMessageUpdate() ?.data ?.asContentMessage() ?.mapper().let(::listOfNotNull) }.toList().toList() private suspend inline fun BehaviourContext.waitContent( count: Int = 1, initRequest: Request<*>? = null, + includeMediaGroups: Boolean = true, noinline errorFactory: NullableRequestBuilder<*> = { null }, noinline filter: ContentMessageToContentMapper? = null ) : List = waitContentMessage( count, initRequest, + includeMediaGroups, errorFactory ) { if (content is T) { @@ -56,124 +64,124 @@ suspend fun BehaviourContext.waitContact( initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, filter: ContentMessageToContentMapper? = null -) = waitContent(count, initRequest, errorFactory, filter) +) = waitContent(count, initRequest, false, errorFactory, filter) suspend fun BehaviourContext.waitDice( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, filter: ContentMessageToContentMapper? = null -) = waitContent(count, initRequest, errorFactory, filter) +) = waitContent(count, initRequest, false, errorFactory, filter) suspend fun BehaviourContext.waitGame( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, filter: ContentMessageToContentMapper? = null -) = waitContent(count, initRequest, errorFactory, filter) +) = waitContent(count, initRequest, false, errorFactory, filter) suspend fun BehaviourContext.waitLocation( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, filter: ContentMessageToContentMapper? = null -) = waitContent(count, initRequest, errorFactory, filter) +) = waitContent(count, initRequest, false, errorFactory, filter) suspend fun BehaviourContext.waitPoll( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, filter: ContentMessageToContentMapper? = null -) = waitContent(count, initRequest, errorFactory, filter) +) = waitContent(count, initRequest, false, errorFactory, filter) suspend fun BehaviourContext.waitText( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, filter: ContentMessageToContentMapper? = null -) = waitContent(count, initRequest, errorFactory, filter) +) = waitContent(count, initRequest, false, errorFactory, filter) suspend fun BehaviourContext.waitVenue( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, filter: ContentMessageToContentMapper? = null -) = waitContent(count, initRequest, errorFactory, filter) +) = waitContent(count, initRequest, false, errorFactory, filter) suspend fun BehaviourContext.waitAudioMediaGroup( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, filter: ContentMessageToContentMapper? = null -) = waitContent(count, initRequest, errorFactory, filter) +) = waitContent(count, initRequest, true, errorFactory, filter) suspend fun BehaviourContext.waitDocumentMediaGroup( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, filter: ContentMessageToContentMapper? = null -) = waitContent(count, initRequest, errorFactory, filter) +) = waitContent(count, initRequest, true, errorFactory, filter) suspend fun BehaviourContext.waitMedia( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, filter: ContentMessageToContentMapper? = null -) = waitContent(count, initRequest, errorFactory, filter) +) = waitContent(count, initRequest, true, errorFactory, filter) suspend fun BehaviourContext.waitMediaGroup( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, filter: ContentMessageToContentMapper? = null -) = waitContent(count, initRequest, errorFactory, filter) +) = waitContent(count, initRequest, true, errorFactory, filter) suspend fun BehaviourContext.waitVisualMediaGroup( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, filter: ContentMessageToContentMapper? = null -) = waitContent(count, initRequest, errorFactory, filter) +) = waitContent(count, initRequest, true, errorFactory, filter) suspend fun BehaviourContext.waitAnimation( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, filter: ContentMessageToContentMapper? = null -) = waitContent(count, initRequest, errorFactory, filter) +) = waitContent(count, initRequest, false, errorFactory, filter) suspend fun BehaviourContext.waitAudio( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, filter: ContentMessageToContentMapper? = null -) = waitContent(count, initRequest, errorFactory, filter) +) = waitContent(count, initRequest, true, errorFactory, filter) suspend fun BehaviourContext.waitDocument( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, filter: ContentMessageToContentMapper? = null -) = waitContent(count, initRequest, errorFactory, filter) +) = waitContent(count, initRequest, true, errorFactory, filter) suspend fun BehaviourContext.waitPhoto( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, filter: ContentMessageToContentMapper? = null -) = waitContent(count, initRequest, errorFactory, filter) +) = waitContent(count, initRequest, true, errorFactory, filter) suspend fun BehaviourContext.waitSticker( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, filter: ContentMessageToContentMapper? = null -) = waitContent(count, initRequest, errorFactory, filter) +) = waitContent(count, initRequest, false, errorFactory, filter) suspend fun BehaviourContext.waitVideo( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, filter: ContentMessageToContentMapper? = null -) = waitContent(count, initRequest, errorFactory, filter) +) = waitContent(count, initRequest, true, errorFactory, filter) suspend fun BehaviourContext.waitVideoNote( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, filter: ContentMessageToContentMapper? = null -) = waitContent(count, initRequest, errorFactory, filter) +) = waitContent(count, initRequest, false, errorFactory, filter) suspend fun BehaviourContext.waitVoice( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, filter: ContentMessageToContentMapper? = null -) = waitContent(count, initRequest, errorFactory, filter) +) = waitContent(count, initRequest, true, errorFactory, filter) suspend fun BehaviourContext.waitInvoice( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, filter: ContentMessageToContentMapper? = null -) = waitContent(count, initRequest, errorFactory, filter) +) = waitContent(count, initRequest, false, errorFactory, filter) diff --git a/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/WaitEventAction.kt b/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/WaitEventAction.kt index b4f67e1a35..e9ee547eb7 100644 --- a/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/WaitEventAction.kt +++ b/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/WaitEventAction.kt @@ -23,7 +23,7 @@ private suspend fun BehaviourContext.waitEventMessages( count, errorFactory ) { - it.asMessageUpdate() ?.data ?.asChatEventMessage() ?.mapper() + it.asMessageUpdate() ?.data ?.asChatEventMessage() ?.mapper().let(::listOfNotNull) }.toList().toList() diff --git a/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/triggers_handling/CallbackQueryTriggers.kt b/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/triggers_handling/CallbackQueryTriggers.kt index 139e2a1f75..5432c7fa58 100644 --- a/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/triggers_handling/CallbackQueryTriggers.kt +++ b/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/triggers_handling/CallbackQueryTriggers.kt @@ -25,7 +25,7 @@ internal suspend inline fun BehaviourContext.onCallb } else { null } - } + }.let(::listOfNotNull) }.subscribeSafelyWithoutExceptions(scope) { triggerQuery -> val (jobToCancel, scenario) = if (includeFilterByChatInBehaviourSubContext) { val subFilter = FlowsUpdatesFilter() diff --git a/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/triggers_handling/ContentTriggers.kt b/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/triggers_handling/ContentTriggers.kt index 451f9dad4f..deab6df207 100644 --- a/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/triggers_handling/ContentTriggers.kt +++ b/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/triggers_handling/ContentTriggers.kt @@ -6,8 +6,7 @@ import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions import dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContext import dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContextAndTypeReceiver import dev.inmo.tgbotapi.extensions.behaviour_builder.expectations.expectFlow -import dev.inmo.tgbotapi.extensions.utils.asContentMessage -import dev.inmo.tgbotapi.extensions.utils.asMessageUpdate +import dev.inmo.tgbotapi.extensions.utils.* import dev.inmo.tgbotapi.extensions.utils.extensions.sourceChat import dev.inmo.tgbotapi.types.files.abstracts.TelegramMediaFile import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage @@ -21,9 +20,22 @@ import kotlinx.coroutines.flow.filter internal suspend inline fun BehaviourContext.onContent( includeFilterByChatInBehaviourSubContext: Boolean = true, + includeMediaGroups: Boolean = true, noinline additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, noinline scenarioReceiver: BehaviourContextAndTypeReceiver> ) = flowsUpdatesFilter.expectFlow(bot) { + if (includeMediaGroups) { + it.asSentMediaGroupUpdate() ?.data ?.mapNotNull { + if (it.content is T) { + val adaptedMessage = it as ContentMessage + if (additionalFilter == null || additionalFilter(adaptedMessage)) adaptedMessage else null + } else { + null + } + } ?.let { + return@expectFlow it + } + } it.asMessageUpdate() ?.data ?.asContentMessage() ?.let { message -> if (message.content is T) { val adaptedMessage = message as ContentMessage @@ -31,7 +43,7 @@ internal suspend inline fun BehaviourContext.onCont } else { null } - } + }.let(::listOfNotNull) }.subscribeSafelyWithoutExceptions(scope) { triggerMessage -> val (jobToCancel, scenario) = if (includeFilterByChatInBehaviourSubContext) { val subFilter = FlowsUpdatesFilter() @@ -52,109 +64,109 @@ suspend fun BehaviourContext.onContact( includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, scenarioReceiver: BehaviourContextAndTypeReceiver> -) = onContent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) +) = onContent(includeFilterByChatInBehaviourSubContext, false, additionalFilter, scenarioReceiver) suspend fun BehaviourContext.onDice( includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, scenarioReceiver: BehaviourContextAndTypeReceiver> -) = onContent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) +) = onContent(includeFilterByChatInBehaviourSubContext, false, additionalFilter, scenarioReceiver) suspend fun BehaviourContext.onGame( includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, scenarioReceiver: BehaviourContextAndTypeReceiver> -) = onContent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) +) = onContent(includeFilterByChatInBehaviourSubContext, false, additionalFilter, scenarioReceiver) suspend fun BehaviourContext.onLocation( includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, scenarioReceiver: BehaviourContextAndTypeReceiver> -) = onContent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) +) = onContent(includeFilterByChatInBehaviourSubContext, false, additionalFilter, scenarioReceiver) suspend fun BehaviourContext.onPoll( includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, scenarioReceiver: BehaviourContextAndTypeReceiver> -) = onContent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) +) = onContent(includeFilterByChatInBehaviourSubContext, false, additionalFilter, scenarioReceiver) suspend fun BehaviourContext.onText( includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, scenarioReceiver: BehaviourContextAndTypeReceiver> -) = onContent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) +) = onContent(includeFilterByChatInBehaviourSubContext, false, additionalFilter, scenarioReceiver) suspend fun BehaviourContext.onVenue( includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, scenarioReceiver: BehaviourContextAndTypeReceiver> -) = onContent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) +) = onContent(includeFilterByChatInBehaviourSubContext, false, additionalFilter, scenarioReceiver) suspend fun BehaviourContext.onAudioMediaGroup( includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, scenarioReceiver: BehaviourContextAndTypeReceiver> -) = onContent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) +) = onContent(includeFilterByChatInBehaviourSubContext, true, additionalFilter, scenarioReceiver) suspend fun BehaviourContext.onDocumentMediaGroup( includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, scenarioReceiver: BehaviourContextAndTypeReceiver> -) = onContent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) +) = onContent(includeFilterByChatInBehaviourSubContext, true, additionalFilter, scenarioReceiver) suspend fun BehaviourContext.onMediaCollection( includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (ContentMessage>) -> Boolean)? = null, scenarioReceiver: BehaviourContextAndTypeReceiver>> -) = onContent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) +) = onContent(includeFilterByChatInBehaviourSubContext, true, additionalFilter, scenarioReceiver) suspend fun BehaviourContext.onMedia( includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, scenarioReceiver: BehaviourContextAndTypeReceiver> -) = onContent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) +) = onContent(includeFilterByChatInBehaviourSubContext, true, additionalFilter, scenarioReceiver) suspend fun BehaviourContext.onMediaGroup( includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, scenarioReceiver: BehaviourContextAndTypeReceiver> -) = onContent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) +) = onContent(includeFilterByChatInBehaviourSubContext, true, additionalFilter, scenarioReceiver) suspend fun BehaviourContext.onVisualMediaGroup( includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, scenarioReceiver: BehaviourContextAndTypeReceiver> -) = onContent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) +) = onContent(includeFilterByChatInBehaviourSubContext, true, additionalFilter, scenarioReceiver) suspend fun BehaviourContext.onAnimation( includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, scenarioReceiver: BehaviourContextAndTypeReceiver> -) = onContent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) +) = onContent(includeFilterByChatInBehaviourSubContext, false, additionalFilter, scenarioReceiver) suspend fun BehaviourContext.onAudio( includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, scenarioReceiver: BehaviourContextAndTypeReceiver> -) = onContent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) +) = onContent(includeFilterByChatInBehaviourSubContext, true, additionalFilter, scenarioReceiver) suspend fun BehaviourContext.onDocument( includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, scenarioReceiver: BehaviourContextAndTypeReceiver> -) = onContent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) +) = onContent(includeFilterByChatInBehaviourSubContext, true, additionalFilter, scenarioReceiver) suspend fun BehaviourContext.onPhoto( includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, scenarioReceiver: BehaviourContextAndTypeReceiver> -) = onContent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) +) = onContent(includeFilterByChatInBehaviourSubContext, true, additionalFilter, scenarioReceiver) suspend fun BehaviourContext.onSticker( includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, scenarioReceiver: BehaviourContextAndTypeReceiver> -) = onContent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) +) = onContent(includeFilterByChatInBehaviourSubContext, false, additionalFilter, scenarioReceiver) suspend fun BehaviourContext.onVideo( includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, scenarioReceiver: BehaviourContextAndTypeReceiver> -) = onContent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) +) = onContent(includeFilterByChatInBehaviourSubContext, true, additionalFilter, scenarioReceiver) suspend fun BehaviourContext.onVideoNote( includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, scenarioReceiver: BehaviourContextAndTypeReceiver> -) = onContent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) +) = onContent(includeFilterByChatInBehaviourSubContext, false, additionalFilter, scenarioReceiver) suspend fun BehaviourContext.onVoice( includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, scenarioReceiver: BehaviourContextAndTypeReceiver> -) = onContent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) +) = onContent(includeFilterByChatInBehaviourSubContext, false, additionalFilter, scenarioReceiver) suspend fun BehaviourContext.onInvoice( includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, scenarioReceiver: BehaviourContextAndTypeReceiver> -) = onContent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) +) = onContent(includeFilterByChatInBehaviourSubContext, false, additionalFilter, scenarioReceiver) diff --git a/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/triggers_handling/EventTriggers.kt b/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/triggers_handling/EventTriggers.kt index 9befcde684..c3a9d1b0da 100644 --- a/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/triggers_handling/EventTriggers.kt +++ b/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/triggers_handling/EventTriggers.kt @@ -29,7 +29,7 @@ internal suspend inline fun BehaviourContext.onEvent( } else { null } - } + }.let(::listOfNotNull) }.subscribeSafelyWithoutExceptions(scope) { triggerMessage -> val (jobToCancel, scenario) = if (includeFilterByChatInBehaviourSubContext) { val subFilter = FlowsUpdatesFilter() From e2dddf96a1cb5eb72cb550e78ee0f272885dcae1 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Fri, 8 Jan 2021 00:30:29 +0600 Subject: [PATCH 17/66] several small additions --- .../behaviour_builder/triggers_handling/ContentTriggers.kt | 4 ++++ .../behaviour_builder/triggers_handling/MediaGroupTriggers.kt | 2 ++ 2 files changed, 6 insertions(+) create mode 100644 tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/triggers_handling/MediaGroupTriggers.kt diff --git a/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/triggers_handling/ContentTriggers.kt b/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/triggers_handling/ContentTriggers.kt index deab6df207..5dee1c8736 100644 --- a/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/triggers_handling/ContentTriggers.kt +++ b/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/triggers_handling/ContentTriggers.kt @@ -1,3 +1,5 @@ +@file:Suppress("unused", "UNCHECKED_CAST") + package dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling @@ -15,9 +17,11 @@ import dev.inmo.tgbotapi.types.message.content.abstracts.* import dev.inmo.tgbotapi.types.message.content.media.* import dev.inmo.tgbotapi.types.message.payments.InvoiceContent import dev.inmo.tgbotapi.updateshandlers.FlowsUpdatesFilter +import dev.inmo.tgbotapi.utils.PreviewFeature import kotlinx.coroutines.flow.filter +@PreviewFeature internal suspend inline fun BehaviourContext.onContent( includeFilterByChatInBehaviourSubContext: Boolean = true, includeMediaGroups: Boolean = true, diff --git a/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/triggers_handling/MediaGroupTriggers.kt b/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/triggers_handling/MediaGroupTriggers.kt new file mode 100644 index 0000000000..4adff39c3f --- /dev/null +++ b/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/triggers_handling/MediaGroupTriggers.kt @@ -0,0 +1,2 @@ +package dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling + From 2e53247726305c197d292220cdcb178747f54b2b Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Fri, 8 Jan 2021 10:22:29 +0600 Subject: [PATCH 18/66] now content waiters and triggers may have set up manually parameter "includeMediaGroups" --- .../expectations/WaitContent.kt | 29 ++++++++++++------- .../triggers_handling/ContentTriggers.kt | 27 +++++++++++------ 2 files changed, 37 insertions(+), 19 deletions(-) diff --git a/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/WaitContent.kt b/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/WaitContent.kt index 0b9e5a6df4..5432251eb3 100644 --- a/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/WaitContent.kt +++ b/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/WaitContent.kt @@ -105,32 +105,37 @@ suspend fun BehaviourContext.waitAudioMediaGroup( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, + includeMediaGroups: Boolean = true, filter: ContentMessageToContentMapper? = null -) = waitContent(count, initRequest, true, errorFactory, filter) +) = waitContent(count, initRequest, includeMediaGroups, errorFactory, filter) suspend fun BehaviourContext.waitDocumentMediaGroup( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, + includeMediaGroups: Boolean = true, filter: ContentMessageToContentMapper? = null -) = waitContent(count, initRequest, true, errorFactory, filter) +) = waitContent(count, initRequest, includeMediaGroups, errorFactory, filter) suspend fun BehaviourContext.waitMedia( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, + includeMediaGroups: Boolean = true, filter: ContentMessageToContentMapper? = null -) = waitContent(count, initRequest, true, errorFactory, filter) +) = waitContent(count, initRequest, includeMediaGroups, errorFactory, filter) suspend fun BehaviourContext.waitMediaGroup( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, + includeMediaGroups: Boolean = true, filter: ContentMessageToContentMapper? = null -) = waitContent(count, initRequest, true, errorFactory, filter) +) = waitContent(count, initRequest, includeMediaGroups, errorFactory, filter) suspend fun BehaviourContext.waitVisualMediaGroup( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, + includeMediaGroups: Boolean = true, filter: ContentMessageToContentMapper? = null -) = waitContent(count, initRequest, true, errorFactory, filter) +) = waitContent(count, initRequest, includeMediaGroups, errorFactory, filter) suspend fun BehaviourContext.waitAnimation( count: Int = 1, initRequest: Request<*>? = null, @@ -141,20 +146,23 @@ suspend fun BehaviourContext.waitAudio( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, + includeMediaGroups: Boolean = true, filter: ContentMessageToContentMapper? = null -) = waitContent(count, initRequest, true, errorFactory, filter) +) = waitContent(count, initRequest, includeMediaGroups, errorFactory, filter) suspend fun BehaviourContext.waitDocument( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, + includeMediaGroups: Boolean = true, filter: ContentMessageToContentMapper? = null -) = waitContent(count, initRequest, true, errorFactory, filter) +) = waitContent(count, initRequest, includeMediaGroups, errorFactory, filter) suspend fun BehaviourContext.waitPhoto( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, + includeMediaGroups: Boolean = true, filter: ContentMessageToContentMapper? = null -) = waitContent(count, initRequest, true, errorFactory, filter) +) = waitContent(count, initRequest, includeMediaGroups, errorFactory, filter) suspend fun BehaviourContext.waitSticker( count: Int = 1, initRequest: Request<*>? = null, @@ -165,8 +173,9 @@ suspend fun BehaviourContext.waitVideo( count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, + includeMediaGroups: Boolean = true, filter: ContentMessageToContentMapper? = null -) = waitContent(count, initRequest, true, errorFactory, filter) +) = waitContent(count, initRequest, includeMediaGroups, errorFactory, filter) suspend fun BehaviourContext.waitVideoNote( count: Int = 1, initRequest: Request<*>? = null, @@ -178,7 +187,7 @@ suspend fun BehaviourContext.waitVoice( initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, filter: ContentMessageToContentMapper? = null -) = waitContent(count, initRequest, true, errorFactory, filter) +) = waitContent(count, initRequest, false, errorFactory, filter) suspend fun BehaviourContext.waitInvoice( count: Int = 1, initRequest: Request<*>? = null, diff --git a/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/triggers_handling/ContentTriggers.kt b/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/triggers_handling/ContentTriggers.kt index 5dee1c8736..d5245022da 100644 --- a/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/triggers_handling/ContentTriggers.kt +++ b/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/triggers_handling/ContentTriggers.kt @@ -106,29 +106,34 @@ suspend fun BehaviourContext.onAudioMediaGroup( ) = onContent(includeFilterByChatInBehaviourSubContext, true, additionalFilter, scenarioReceiver) suspend fun BehaviourContext.onDocumentMediaGroup( includeFilterByChatInBehaviourSubContext: Boolean = true, + includeMediaGroups: Boolean = true, additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, scenarioReceiver: BehaviourContextAndTypeReceiver> -) = onContent(includeFilterByChatInBehaviourSubContext, true, additionalFilter, scenarioReceiver) +) = onContent(includeFilterByChatInBehaviourSubContext, includeMediaGroups, additionalFilter, scenarioReceiver) suspend fun BehaviourContext.onMediaCollection( includeFilterByChatInBehaviourSubContext: Boolean = true, + includeMediaGroups: Boolean = true, additionalFilter: (suspend (ContentMessage>) -> Boolean)? = null, scenarioReceiver: BehaviourContextAndTypeReceiver>> -) = onContent(includeFilterByChatInBehaviourSubContext, true, additionalFilter, scenarioReceiver) +) = onContent(includeFilterByChatInBehaviourSubContext, includeMediaGroups, additionalFilter, scenarioReceiver) suspend fun BehaviourContext.onMedia( includeFilterByChatInBehaviourSubContext: Boolean = true, + includeMediaGroups: Boolean = true, additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, scenarioReceiver: BehaviourContextAndTypeReceiver> -) = onContent(includeFilterByChatInBehaviourSubContext, true, additionalFilter, scenarioReceiver) +) = onContent(includeFilterByChatInBehaviourSubContext, includeMediaGroups, additionalFilter, scenarioReceiver) suspend fun BehaviourContext.onMediaGroup( includeFilterByChatInBehaviourSubContext: Boolean = true, + includeMediaGroups: Boolean = true, additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, scenarioReceiver: BehaviourContextAndTypeReceiver> -) = onContent(includeFilterByChatInBehaviourSubContext, true, additionalFilter, scenarioReceiver) +) = onContent(includeFilterByChatInBehaviourSubContext, includeMediaGroups, additionalFilter, scenarioReceiver) suspend fun BehaviourContext.onVisualMediaGroup( includeFilterByChatInBehaviourSubContext: Boolean = true, + includeMediaGroups: Boolean = true, additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, scenarioReceiver: BehaviourContextAndTypeReceiver> -) = onContent(includeFilterByChatInBehaviourSubContext, true, additionalFilter, scenarioReceiver) +) = onContent(includeFilterByChatInBehaviourSubContext, includeMediaGroups, additionalFilter, scenarioReceiver) suspend fun BehaviourContext.onAnimation( includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, @@ -136,19 +141,22 @@ suspend fun BehaviourContext.onAnimation( ) = onContent(includeFilterByChatInBehaviourSubContext, false, additionalFilter, scenarioReceiver) suspend fun BehaviourContext.onAudio( includeFilterByChatInBehaviourSubContext: Boolean = true, + includeMediaGroups: Boolean = true, additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, scenarioReceiver: BehaviourContextAndTypeReceiver> -) = onContent(includeFilterByChatInBehaviourSubContext, true, additionalFilter, scenarioReceiver) +) = onContent(includeFilterByChatInBehaviourSubContext, includeMediaGroups, additionalFilter, scenarioReceiver) suspend fun BehaviourContext.onDocument( includeFilterByChatInBehaviourSubContext: Boolean = true, + includeMediaGroups: Boolean = true, additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, scenarioReceiver: BehaviourContextAndTypeReceiver> -) = onContent(includeFilterByChatInBehaviourSubContext, true, additionalFilter, scenarioReceiver) +) = onContent(includeFilterByChatInBehaviourSubContext, includeMediaGroups, additionalFilter, scenarioReceiver) suspend fun BehaviourContext.onPhoto( includeFilterByChatInBehaviourSubContext: Boolean = true, + includeMediaGroups: Boolean = true, additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, scenarioReceiver: BehaviourContextAndTypeReceiver> -) = onContent(includeFilterByChatInBehaviourSubContext, true, additionalFilter, scenarioReceiver) +) = onContent(includeFilterByChatInBehaviourSubContext, includeMediaGroups, additionalFilter, scenarioReceiver) suspend fun BehaviourContext.onSticker( includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, @@ -156,9 +164,10 @@ suspend fun BehaviourContext.onSticker( ) = onContent(includeFilterByChatInBehaviourSubContext, false, additionalFilter, scenarioReceiver) suspend fun BehaviourContext.onVideo( includeFilterByChatInBehaviourSubContext: Boolean = true, + includeMediaGroups: Boolean = true, additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, scenarioReceiver: BehaviourContextAndTypeReceiver> -) = onContent(includeFilterByChatInBehaviourSubContext, true, additionalFilter, scenarioReceiver) +) = onContent(includeFilterByChatInBehaviourSubContext, includeMediaGroups, additionalFilter, scenarioReceiver) suspend fun BehaviourContext.onVideoNote( includeFilterByChatInBehaviourSubContext: Boolean = true, additionalFilter: (suspend (ContentMessage) -> Boolean)? = null, From ac07f44c81ad74cbd5bc3092c0fe69db9f72fad4 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Fri, 8 Jan 2021 10:29:29 +0600 Subject: [PATCH 19/66] change public signature of waiters --- .../expectations/WaitCallbackQuery.kt | 18 ++++---- .../expectations/WaitContent.kt | 42 +++++++++---------- .../expectations/WaitEventAction.kt | 36 ++++++++-------- 3 files changed, 48 insertions(+), 48 deletions(-) diff --git a/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/WaitCallbackQuery.kt b/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/WaitCallbackQuery.kt index 5676bb0054..e9e70a84c6 100644 --- a/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/WaitCallbackQuery.kt +++ b/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/WaitCallbackQuery.kt @@ -47,56 +47,56 @@ private suspend inline fun BehaviourContext.waitEven suspend fun BehaviourContext.waitDataCallbackQuery( - count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, + count: Int = 1, filter: CallbackQueryMapper? = null ) = waitEvents(count, initRequest, errorFactory, filter) suspend fun BehaviourContext.waitGameShortNameCallbackQuery( - count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, + count: Int = 1, filter: CallbackQueryMapper? = null ) = waitEvents(count, initRequest, errorFactory, filter) suspend fun BehaviourContext.waitInlineMessageIdCallbackQuery( - count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, + count: Int = 1, filter: CallbackQueryMapper? = null ) = waitEvents(count, initRequest, errorFactory, filter) suspend fun BehaviourContext.waitInlineMessageIdDataCallbackQuery( - count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, + count: Int = 1, filter: CallbackQueryMapper? = null ) = waitEvents(count, initRequest, errorFactory, filter) suspend fun BehaviourContext.waitInlineMessageIdGameShortNameCallbackQuery( - count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, + count: Int = 1, filter: CallbackQueryMapper? = null ) = waitEvents(count, initRequest, errorFactory, filter) suspend fun BehaviourContext.waitMessageCallbackQuery( - count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, + count: Int = 1, filter: CallbackQueryMapper? = null ) = waitEvents(count, initRequest, errorFactory, filter) suspend fun BehaviourContext.waitMessageDataCallbackQuery( - count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, + count: Int = 1, filter: CallbackQueryMapper? = null ) = waitEvents(count, initRequest, errorFactory, filter) suspend fun BehaviourContext.waitMessageGameShortNameCallbackQuery( - count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, + count: Int = 1, filter: CallbackQueryMapper? = null ) = waitEvents(count, initRequest, errorFactory, filter) suspend fun BehaviourContext.waitUnknownCallbackQuery( - count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, + count: Int = 1, filter: CallbackQueryMapper? = null ) = waitEvents(count, initRequest, errorFactory, filter) diff --git a/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/WaitContent.kt b/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/WaitContent.kt index 5432251eb3..d78868e2bc 100644 --- a/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/WaitContent.kt +++ b/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/WaitContent.kt @@ -60,137 +60,137 @@ private suspend inline fun BehaviourContext.waitCon } suspend fun BehaviourContext.waitContact( - count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, + count: Int = 1, filter: ContentMessageToContentMapper? = null ) = waitContent(count, initRequest, false, errorFactory, filter) suspend fun BehaviourContext.waitDice( - count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, + count: Int = 1, filter: ContentMessageToContentMapper? = null ) = waitContent(count, initRequest, false, errorFactory, filter) suspend fun BehaviourContext.waitGame( - count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, + count: Int = 1, filter: ContentMessageToContentMapper? = null ) = waitContent(count, initRequest, false, errorFactory, filter) suspend fun BehaviourContext.waitLocation( - count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, + count: Int = 1, filter: ContentMessageToContentMapper? = null ) = waitContent(count, initRequest, false, errorFactory, filter) suspend fun BehaviourContext.waitPoll( - count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, + count: Int = 1, filter: ContentMessageToContentMapper? = null ) = waitContent(count, initRequest, false, errorFactory, filter) suspend fun BehaviourContext.waitText( - count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, + count: Int = 1, filter: ContentMessageToContentMapper? = null ) = waitContent(count, initRequest, false, errorFactory, filter) suspend fun BehaviourContext.waitVenue( - count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, + count: Int = 1, filter: ContentMessageToContentMapper? = null ) = waitContent(count, initRequest, false, errorFactory, filter) suspend fun BehaviourContext.waitAudioMediaGroup( - count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, + count: Int = 1, includeMediaGroups: Boolean = true, filter: ContentMessageToContentMapper? = null ) = waitContent(count, initRequest, includeMediaGroups, errorFactory, filter) suspend fun BehaviourContext.waitDocumentMediaGroup( - count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, + count: Int = 1, includeMediaGroups: Boolean = true, filter: ContentMessageToContentMapper? = null ) = waitContent(count, initRequest, includeMediaGroups, errorFactory, filter) suspend fun BehaviourContext.waitMedia( - count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, + count: Int = 1, includeMediaGroups: Boolean = true, filter: ContentMessageToContentMapper? = null ) = waitContent(count, initRequest, includeMediaGroups, errorFactory, filter) suspend fun BehaviourContext.waitMediaGroup( - count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, + count: Int = 1, includeMediaGroups: Boolean = true, filter: ContentMessageToContentMapper? = null ) = waitContent(count, initRequest, includeMediaGroups, errorFactory, filter) suspend fun BehaviourContext.waitVisualMediaGroup( - count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, + count: Int = 1, includeMediaGroups: Boolean = true, filter: ContentMessageToContentMapper? = null ) = waitContent(count, initRequest, includeMediaGroups, errorFactory, filter) suspend fun BehaviourContext.waitAnimation( - count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, + count: Int = 1, filter: ContentMessageToContentMapper? = null ) = waitContent(count, initRequest, false, errorFactory, filter) suspend fun BehaviourContext.waitAudio( - count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, + count: Int = 1, includeMediaGroups: Boolean = true, filter: ContentMessageToContentMapper? = null ) = waitContent(count, initRequest, includeMediaGroups, errorFactory, filter) suspend fun BehaviourContext.waitDocument( - count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, + count: Int = 1, includeMediaGroups: Boolean = true, filter: ContentMessageToContentMapper? = null ) = waitContent(count, initRequest, includeMediaGroups, errorFactory, filter) suspend fun BehaviourContext.waitPhoto( - count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, + count: Int = 1, includeMediaGroups: Boolean = true, filter: ContentMessageToContentMapper? = null ) = waitContent(count, initRequest, includeMediaGroups, errorFactory, filter) suspend fun BehaviourContext.waitSticker( - count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, + count: Int = 1, filter: ContentMessageToContentMapper? = null ) = waitContent(count, initRequest, false, errorFactory, filter) suspend fun BehaviourContext.waitVideo( - count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, + count: Int = 1, includeMediaGroups: Boolean = true, filter: ContentMessageToContentMapper? = null ) = waitContent(count, initRequest, includeMediaGroups, errorFactory, filter) suspend fun BehaviourContext.waitVideoNote( - count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, + count: Int = 1, filter: ContentMessageToContentMapper? = null ) = waitContent(count, initRequest, false, errorFactory, filter) suspend fun BehaviourContext.waitVoice( - count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, + count: Int = 1, filter: ContentMessageToContentMapper? = null ) = waitContent(count, initRequest, false, errorFactory, filter) suspend fun BehaviourContext.waitInvoice( - count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, + count: Int = 1, filter: ContentMessageToContentMapper? = null ) = waitContent(count, initRequest, false, errorFactory, filter) diff --git a/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/WaitEventAction.kt b/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/WaitEventAction.kt index e9ee547eb7..0093fa5111 100644 --- a/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/WaitEventAction.kt +++ b/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/WaitEventAction.kt @@ -14,9 +14,9 @@ import kotlinx.coroutines.flow.toList typealias EventMessageToEventMapper = suspend ChatEventMessage.() -> T? private suspend fun BehaviourContext.waitEventMessages( - count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, + count: Int = 1, mapper: suspend ChatEventMessage.() -> O? ): List = expectFlow( initRequest, @@ -33,9 +33,9 @@ private suspend inline fun BehaviourContext.waitEvents( noinline errorFactory: NullableRequestBuilder<*> = { null }, noinline filter: EventMessageToEventMapper? = null ) : List = waitEventMessages( - count, initRequest, - errorFactory + errorFactory, + count ) { if (chatEvent is T) { @Suppress("UNCHECKED_CAST") @@ -51,94 +51,94 @@ private suspend inline fun BehaviourContext.waitEvents( } suspend fun BehaviourContext.waitChannelEvents( - count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, + count: Int = 1, filter: EventMessageToEventMapper? = null ) = waitEvents(count, initRequest, errorFactory, filter) suspend fun BehaviourContext.waitChatEvents( - count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, + count: Int = 1, filter: EventMessageToEventMapper? = null ) = waitEvents(count, initRequest, errorFactory, filter) suspend fun BehaviourContext.waitCommonEvents( - count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, + count: Int = 1, filter: EventMessageToEventMapper? = null ) = waitEvents(count, initRequest, errorFactory, filter) suspend fun BehaviourContext.waitGroupEvents( - count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, + count: Int = 1, filter: EventMessageToEventMapper? = null ) = waitEvents(count, initRequest, errorFactory, filter) suspend fun BehaviourContext.waitSupergroupEvents( - count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, + count: Int = 1, filter: EventMessageToEventMapper? = null ) = waitEvents(count, initRequest, errorFactory, filter) suspend fun BehaviourContext.waitChannelChatCreatedEvents( - count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, + count: Int = 1, filter: EventMessageToEventMapper? = null ) = waitEvents(count, initRequest, errorFactory, filter) suspend fun BehaviourContext.waitDeleteChatPhotoEvents( - count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, + count: Int = 1, filter: EventMessageToEventMapper? = null ) = waitEvents(count, initRequest, errorFactory, filter) suspend fun BehaviourContext.waitGroupChatCreatedEvents( - count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, + count: Int = 1, filter: EventMessageToEventMapper? = null ) = waitEvents(count, initRequest, errorFactory, filter) suspend fun BehaviourContext.waitLeftChatMemberEvents( - count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, + count: Int = 1, filter: EventMessageToEventMapper? = null ) = waitEvents(count, initRequest, errorFactory, filter) suspend fun BehaviourContext.waitNewChatPhotoEvents( - count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, + count: Int = 1, filter: EventMessageToEventMapper? = null ) = waitEvents(count, initRequest, errorFactory, filter) suspend fun BehaviourContext.waitNewChatMembersEvents( - count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, + count: Int = 1, filter: EventMessageToEventMapper? = null ) = waitEvents(count, initRequest, errorFactory, filter) suspend fun BehaviourContext.waitNewChatTitleEvents( - count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, + count: Int = 1, filter: EventMessageToEventMapper? = null ) = waitEvents(count, initRequest, errorFactory, filter) suspend fun BehaviourContext.waitPinnedMessageEvents( - count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, + count: Int = 1, filter: EventMessageToEventMapper? = null ) = waitEvents(count, initRequest, errorFactory, filter) suspend fun BehaviourContext.waitProximityAlertTriggeredEvents( - count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, + count: Int = 1, filter: EventMessageToEventMapper? = null ) = waitEvents(count, initRequest, errorFactory, filter) suspend fun BehaviourContext.waitSupergroupChatCreatedEvents( - count: Int = 1, initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, + count: Int = 1, filter: EventMessageToEventMapper? = null ) = waitEvents(count, initRequest, errorFactory, filter) From b9341f89ac6221576227193980080d6a81ef6e37 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Fri, 8 Jan 2021 11:02:18 +0600 Subject: [PATCH 20/66] add media groups triggers and waiters --- .../expectations/WaitMediaGroup.kt | 61 +++++++++++++++ .../triggers_handling/MediaGroupTriggers.kt | 75 +++++++++++++++++++ 2 files changed, 136 insertions(+) create mode 100644 tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/WaitMediaGroup.kt diff --git a/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/WaitMediaGroup.kt b/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/WaitMediaGroup.kt new file mode 100644 index 0000000000..f3ac40ad09 --- /dev/null +++ b/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/WaitMediaGroup.kt @@ -0,0 +1,61 @@ +package dev.inmo.tgbotapi.extensions.behaviour_builder.expectations + +import dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContext +import dev.inmo.tgbotapi.extensions.utils.* +import dev.inmo.tgbotapi.requests.abstracts.Request +import dev.inmo.tgbotapi.types.message.abstracts.MediaGroupMessage +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.VideoContent +import dev.inmo.tgbotapi.utils.PreviewFeature +import kotlinx.coroutines.flow.take +import kotlinx.coroutines.flow.toList + +@PreviewFeature +internal suspend inline fun BehaviourContext.onMediaGroup( + count: Int = 1, + initRequest: Request<*>? = null, + noinline errorFactory: NullableRequestBuilder<*> = { null }, + noinline filter: (suspend (List) -> Boolean)? = null +) = flowsUpdatesFilter.expectFlow(bot, initRequest, count, errorFactory) { update -> + update.asSentMediaGroupUpdate() ?.data ?.let { mediaGroup -> + if (mediaGroup.all { message -> message.content is T } && (filter == null || filter(mediaGroup))) { + listOf( + mediaGroup.map { it.content as T } + ) + } else { + null + } + } ?: emptyList() +}.take(count).toList() + +suspend fun BehaviourContext.waitPlaylist( + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null }, + count: Int = 1, + filter: (suspend (List) -> Boolean)? = null +) = onMediaGroup(count, initRequest, errorFactory, filter) +suspend fun BehaviourContext.waitDocumentsGroup( + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null }, + count: Int = 1, + filter: (suspend (List) -> Boolean)? = null +) = onMediaGroup(count, initRequest, errorFactory, filter) +suspend fun BehaviourContext.waitVisualGallery( + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null }, + count: Int = 1, + filter: (suspend (List) -> Boolean)? = null +) = onMediaGroup(count, initRequest, errorFactory, filter) +suspend fun BehaviourContext.waitPhotoGallery( + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null }, + count: Int = 1, + filter: (suspend (List) -> Boolean)? = null +) = onMediaGroup(count, initRequest, errorFactory, filter) +suspend fun BehaviourContext.waitVideoGallery( + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null }, + count: Int = 1, + filter: (suspend (List) -> Boolean)? = null +) = onMediaGroup(count, initRequest, errorFactory, filter) diff --git a/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/triggers_handling/MediaGroupTriggers.kt b/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/triggers_handling/MediaGroupTriggers.kt index 4adff39c3f..c3120c1a3c 100644 --- a/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/triggers_handling/MediaGroupTriggers.kt +++ b/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/triggers_handling/MediaGroupTriggers.kt @@ -1,2 +1,77 @@ +@file:Suppress("unused") + package dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling +import dev.inmo.micro_utils.coroutines.safelyWithoutExceptions +import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions +import dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContext +import dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContextAndTypeReceiver +import dev.inmo.tgbotapi.extensions.behaviour_builder.expectations.expectFlow +import dev.inmo.tgbotapi.extensions.utils.* +import dev.inmo.tgbotapi.extensions.utils.extensions.sourceChat +import dev.inmo.tgbotapi.extensions.utils.shortcuts.chat +import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage +import dev.inmo.tgbotapi.types.message.abstracts.MediaGroupMessage +import dev.inmo.tgbotapi.types.message.content.ContactContent +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.VideoContent +import dev.inmo.tgbotapi.updateshandlers.FlowsUpdatesFilter +import dev.inmo.tgbotapi.utils.PreviewFeature +import kotlinx.coroutines.flow.filter + +@PreviewFeature +internal suspend inline fun BehaviourContext.onMediaGroup( + includeFilterByChatInBehaviourSubContext: Boolean = true, + noinline additionalFilter: (suspend (List) -> Boolean)? = null, + noinline scenarioReceiver: BehaviourContextAndTypeReceiver> +) = flowsUpdatesFilter.expectFlow(bot) { update -> + update.asSentMediaGroupUpdate() ?.data ?.let { mediaGroup -> + if (mediaGroup.all { message -> message.content is T } && (additionalFilter == null || additionalFilter(mediaGroup))) { + listOf(mediaGroup) + } else { + null + } + } ?: emptyList() +}.subscribeSafelyWithoutExceptions(scope) { mediaGroup -> + val (jobToCancel, scenario) = if (includeFilterByChatInBehaviourSubContext) { + val subFilter = FlowsUpdatesFilter() + val subBehaviourContext = copy(flowsUpdatesFilter = subFilter) + + flowsUpdatesFilter.allUpdatesFlow.filter { + val chat = it.sourceChat() ?: return@filter false + chat.id.chatId == mediaGroup.chat!!.id.chatId + }.subscribeSafelyWithoutExceptions(scope, subFilter.asUpdateReceiver) to subBehaviourContext + } else { + null to this + } + safelyWithoutExceptions { scenario.scenarioReceiver(mediaGroup) } + jobToCancel ?.cancel() +} + +suspend fun BehaviourContext.onPlaylist( + includeFilterByChatInBehaviourSubContext: Boolean = true, + additionalFilter: (suspend (List) -> Boolean)? = null, + scenarioReceiver: BehaviourContextAndTypeReceiver> +) = onMediaGroup(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) +suspend fun BehaviourContext.onDocumentsGroup( + includeFilterByChatInBehaviourSubContext: Boolean = true, + additionalFilter: (suspend (List) -> Boolean)? = null, + scenarioReceiver: BehaviourContextAndTypeReceiver> +) = onMediaGroup(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) +suspend fun BehaviourContext.onVisualGallery( + includeFilterByChatInBehaviourSubContext: Boolean = true, + additionalFilter: (suspend (List) -> Boolean)? = null, + scenarioReceiver: BehaviourContextAndTypeReceiver> +) = onMediaGroup(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) +suspend fun BehaviourContext.onPhotoGallery( + includeFilterByChatInBehaviourSubContext: Boolean = true, + additionalFilter: (suspend (List) -> Boolean)? = null, + scenarioReceiver: BehaviourContextAndTypeReceiver> +) = onMediaGroup(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) +suspend fun BehaviourContext.onVideoGallery( + includeFilterByChatInBehaviourSubContext: Boolean = true, + additionalFilter: (suspend (List) -> Boolean)? = null, + scenarioReceiver: BehaviourContextAndTypeReceiver> +) = onMediaGroup(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) + From 9cc402b42d9ea70feb6585b5406dc0fda953f8c0 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Fri, 8 Jan 2021 16:28:00 +0600 Subject: [PATCH 21/66] ContentMessage -> CommonMessage in behaviour_builder, fill readme of behaviour_builder and update projects schema --- TelegramBotAPI.minder | 47 +- .../TelegramBotAPI-libraries-hierarchy.svg | 1083 +++++++++-------- .../README.md | 63 +- .../build.gradle | 2 - .../expectations/WaitContent.kt | 63 +- .../triggers_handling/CommandHandling.kt | 6 +- .../triggers_handling/ContentTriggers.kt | 101 +- .../triggers_handling/MediaGroupTriggers.kt | 2 +- tgbotapi/README.md | 1 + 9 files changed, 779 insertions(+), 589 deletions(-) diff --git a/TelegramBotAPI.minder b/TelegramBotAPI.minder index fc9d92ae8b..6f585a56e0 100644 --- a/TelegramBotAPI.minder +++ b/TelegramBotAPI.minder @@ -1,6 +1,6 @@ - - + +