mirror of
https://github.com/InsanusMokrassar/TelegramBotAPI.git
synced 2024-11-26 03:58:44 +00:00
commit
879943622a
14
CHANGELOG.md
14
CHANGELOG.md
@ -1,5 +1,19 @@
|
|||||||
# TelegramBotAPI changelog
|
# TelegramBotAPI changelog
|
||||||
|
|
||||||
|
## 0.30.13
|
||||||
|
|
||||||
|
* `Common`:
|
||||||
|
* `Version`:
|
||||||
|
* `MicroUtils`: `0.4.15` -> `0.4.16`
|
||||||
|
* `Core`:
|
||||||
|
* New variable `FlowsUpdatesFilter#allUpdatesWithoutMediaGroupsGroupingFlow` which will contains updates without
|
||||||
|
`SentMediaGroupUpdate`
|
||||||
|
* `Utils`:
|
||||||
|
* Extensions for `ResendableContent` has been added
|
||||||
|
* Extensions for `TextSource` has been added
|
||||||
|
* `Behaviour Builder`:
|
||||||
|
* Project has been created :)
|
||||||
|
|
||||||
## 0.30.12
|
## 0.30.12
|
||||||
|
|
||||||
* `Utils`:
|
* `Utils`:
|
||||||
|
@ -15,8 +15,9 @@ You can simply use <a href="https://github.com/InsanusMokrassar/TelegramBotAPI-b
|
|||||||
| -------------------------------------:|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
| -------------------------------------:|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||||
| Useful links | [![Chat in Telegram](badges/chat.svg)](https://t.me/InMoTelegramBotAPI) [![Create bot](badges/template.svg)](https://github.com/InsanusMokrassar/TelegramBotAPI-bot_template/generate) [![KDocs](badges/kdocs.svg)](https://tgbotapi.inmo.dev/docs/index.html) [Examples](https://github.com/InsanusMokrassar/TelegramBotAPI-examples/), [Mini tutorial](https://bookstack.inmo.dev/books/telegrambotapi/chapter/introduction-tutorial) |
|
| Useful links | [![Chat in Telegram](badges/chat.svg)](https://t.me/InMoTelegramBotAPI) [![Create bot](badges/template.svg)](https://github.com/InsanusMokrassar/TelegramBotAPI-bot_template/generate) [![KDocs](badges/kdocs.svg)](https://tgbotapi.inmo.dev/docs/index.html) [Examples](https://github.com/InsanusMokrassar/TelegramBotAPI-examples/), [Mini tutorial](https://bookstack.inmo.dev/books/telegrambotapi/chapter/introduction-tutorial) |
|
||||||
| TelegramBotAPI Core status | [![Download](https://api.bintray.com/packages/insanusmokrassar/TelegramBotAPI/tgbotapi.core/images/download.svg)](https://bintray.com/insanusmokrassar/TelegramBotAPI/tgbotapi.core/_latestVersion) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi.core/badge.svg)](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi.core) |
|
| TelegramBotAPI Core status | [![Download](https://api.bintray.com/packages/insanusmokrassar/TelegramBotAPI/tgbotapi.core/images/download.svg)](https://bintray.com/insanusmokrassar/TelegramBotAPI/tgbotapi.core/_latestVersion) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi.core/badge.svg)](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi.core) |
|
||||||
| TelegramBotAPI Extensions status | [![Download](https://api.bintray.com/packages/insanusmokrassar/TelegramBotAPI/tgbotapi.extensions.api/images/download.svg)](https://bintray.com/insanusmokrassar/TelegramBotAPI/tgbotapi.extensions.api/_latestVersion) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi.extensions.api/badge.svg)](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi.extensions.api) |
|
| TelegramBotAPI API Extensions status | [![Download](https://api.bintray.com/packages/insanusmokrassar/TelegramBotAPI/tgbotapi.extensions.api/images/download.svg)](https://bintray.com/insanusmokrassar/TelegramBotAPI/tgbotapi.extensions.api/_latestVersion) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi.extensions.api/badge.svg)](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi.extensions.api) |
|
||||||
| TelegramBotAPI Util Extensions status | [![Download](https://api.bintray.com/packages/insanusmokrassar/TelegramBotAPI/tgbotapi.extensions.utils/images/download.svg)](https://bintray.com/insanusmokrassar/TelegramBotAPI/tgbotapi.extensions.utils/_latestVersion) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi.extensions.utils/badge.svg)](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi.extensions.utils) |
|
| TelegramBotAPI Util Extensions status | [![Download](https://api.bintray.com/packages/insanusmokrassar/TelegramBotAPI/tgbotapi.extensions.utils/images/download.svg)](https://bintray.com/insanusmokrassar/TelegramBotAPI/tgbotapi.extensions.utils/_latestVersion) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi.extensions.utils/badge.svg)](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi.extensions.utils) |
|
||||||
|
| TelegramBotAPI Behaviour Builder Extensions status | [![Download](https://api.bintray.com/packages/insanusmokrassar/TelegramBotAPI/tgbotapi.extensions.behaviour_builder/images/download.svg)](https://bintray.com/insanusmokrassar/TelegramBotAPI/tgbotapi.extensions.behaviour_builder/_latestVersion) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi.extensions.behaviour_builder/badge.svg)](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi.extensions.behaviour_builder) |
|
||||||
| TelegramBotAPI All status | [![Download](https://api.bintray.com/packages/insanusmokrassar/TelegramBotAPI/tgbotapi/images/download.svg)](https://bintray.com/insanusmokrassar/TelegramBotAPI/tgbotapi/_latestVersion) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi/badge.svg)](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi) |
|
| TelegramBotAPI All status | [![Download](https://api.bintray.com/packages/insanusmokrassar/TelegramBotAPI/tgbotapi/images/download.svg)](https://bintray.com/insanusmokrassar/TelegramBotAPI/tgbotapi/_latestVersion) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi/badge.svg)](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi) |
|
||||||
|
|
||||||
**At the time of publication of version `0.28.0` there are errors in serialization plugins like
|
**At the time of publication of version `0.28.0` there are errors in serialization plugins like
|
||||||
@ -34,6 +35,8 @@ the list of this complex currently next projects:
|
|||||||
`RequestsExecutor`), which allows to use the core library in more pleasant way
|
`RequestsExecutor`), which allows to use the core library in more pleasant way
|
||||||
* [TelegramBotAPI Util Extensions](tgbotapi.extensions.utils/README.md) - contains extensions for more comfortable
|
* [TelegramBotAPI Util Extensions](tgbotapi.extensions.utils/README.md) - contains extensions for more comfortable
|
||||||
work with commands, updates and other different things
|
work with commands, updates and other different things
|
||||||
|
* [TelegramBotAPI Behaviour Builder Extensions](tgbotapi.extensions.behaviour_builder/README.md) - builder for
|
||||||
|
step-by-step handling of bot behaviour in more comfortable manner
|
||||||
* [TelegramBotAPI](tgbotapi/README.md) - concentration of all previously mentioned libraries
|
* [TelegramBotAPI](tgbotapi/README.md) - concentration of all previously mentioned libraries
|
||||||
|
|
||||||
Most part of some specific solves or unuseful
|
Most part of some specific solves or unuseful
|
||||||
@ -88,6 +91,7 @@ kotlin {
|
|||||||
|
|
||||||
In most cases, the most simple way will be to implement [TelegramBotAPI](tgbotapi/README.md) - it contains
|
In most cases, the most simple way will be to implement [TelegramBotAPI](tgbotapi/README.md) - it contains
|
||||||
all necessary tools for comfort usage of this library. If you want to exclude some libraries, you can implement just
|
all necessary tools for comfort usage of this library. If you want to exclude some libraries, you can implement just
|
||||||
|
[TelegramBotAPI BehaviourBuilder Extensions](tgbotapi.extensions.behaviour_builder/README.md),
|
||||||
[TelegramBotAPI API Extensions](tgbotapi.extensions.api/README.md),
|
[TelegramBotAPI API Extensions](tgbotapi.extensions.api/README.md),
|
||||||
[TelegramBotAPI Util Extensions](tgbotapi.extensions.utils/README.md) or even
|
[TelegramBotAPI Util Extensions](tgbotapi.extensions.utils/README.md) or even
|
||||||
[TelegramBotAPI Core](tgbotapi.core/README.md).
|
[TelegramBotAPI Core](tgbotapi.core/README.md).
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
<minder version="1.11.1">
|
<minder version="1.11.3">
|
||||||
<theme name="default" label="Default" index="-1"/>
|
<theme name="default" label="Default" index="-1"/>
|
||||||
<styles>
|
<styles>
|
||||||
<style level="0" isset="true" branchmargin="100" linktype="curved" linkwidth="5" linkarrow="true" linkdash="solid" nodeborder="bracket" nodewidth="200" nodeborderwidth="3" nodefill="false" nodemargin="11" nodepadding="5" nodefont="Roboto Mono 14" nodemarkup="true" connectiondash="dotted" connectionlwidth="2" connectionarrow="fromto" connectionpadding="3" connectionfont="Sans 10" connectiontwidth="100"/>
|
<style level="0" isset="true" branchmargin="100" linktype="curved" linkwidth="5" linkarrow="true" linkdash="solid" nodeborder="bracket" nodewidth="200" nodeborderwidth="3" nodefill="false" nodemargin="11" nodepadding="5" nodefont="Roboto Mono 14" nodemarkup="true" connectiondash="dotted" connectionlwidth="2" connectionarrow="fromto" connectionpadding="3" connectionfont="Sans 10" connectiontwidth="100"/>
|
||||||
@ -14,45 +14,54 @@
|
|||||||
<style level="9" isset="true" branchmargin="100" linktype="curved" linkwidth="5" linkarrow="true" linkdash="solid" nodeborder="bracket" nodewidth="200" nodeborderwidth="3" nodefill="false" nodemargin="11" nodepadding="5" nodefont="Roboto Mono 14" nodemarkup="true" connectiondash="dotted" connectionlwidth="2" connectionarrow="fromto" connectionpadding="3" connectionfont="Sans 10" connectiontwidth="100"/>
|
<style level="9" isset="true" branchmargin="100" linktype="curved" linkwidth="5" linkarrow="true" linkdash="solid" nodeborder="bracket" nodewidth="200" nodeborderwidth="3" nodefill="false" nodemargin="11" nodepadding="5" nodefont="Roboto Mono 14" nodemarkup="true" connectiondash="dotted" connectionlwidth="2" connectionarrow="fromto" connectionpadding="3" connectionfont="Sans 10" connectiontwidth="100"/>
|
||||||
<style level="10" isset="true" branchmargin="100" linktype="curved" linkwidth="5" linkarrow="true" linkdash="solid" nodeborder="bracket" nodewidth="200" nodeborderwidth="3" nodefill="false" nodemargin="11" nodepadding="5" nodefont="Roboto Mono 14" nodemarkup="true" connectiondash="dotted" connectionlwidth="2" connectionarrow="fromto" connectionpadding="3" connectionfont="Sans 10" connectiontwidth="100"/>
|
<style level="10" isset="true" branchmargin="100" linktype="curved" linkwidth="5" linkarrow="true" linkdash="solid" nodeborder="bracket" nodewidth="200" nodeborderwidth="3" nodefill="false" nodemargin="11" nodepadding="5" nodefont="Roboto Mono 14" nodemarkup="true" connectiondash="dotted" connectionlwidth="2" connectionarrow="fromto" connectionpadding="3" connectionfont="Sans 10" connectiontwidth="100"/>
|
||||||
</styles>
|
</styles>
|
||||||
<drawarea x="-320.56697591145837" y="-10.028254191080691" scale="0.75"/>
|
<drawarea x="-950.47548925255796" y="-49.650554065281653" scale="0.5"/>
|
||||||
<images/>
|
<images/>
|
||||||
<nodes>
|
<nodes>
|
||||||
<node id="0" posx="748.88964843749955" posy="119.42341613769531" width="472" height="168" side="top" fold="false" treesize="603" layout="Downwards" group="false">
|
<node id="0" posx="1378.798161778599" posy="159.04571601189673" width="472" height="168" side="top" fold="false" treesize="743" layout="Downwards" group="false">
|
||||||
<style branchmargin="100" linktype="curved" linkwidth="5" linkarrow="true" linkdash="solid" nodeborder="bracket" nodewidth="439" nodeborderwidth="3" nodefill="false" nodemargin="11" nodepadding="5" nodefont="Roboto Mono 14" nodemarkup="true"/>
|
<style branchmargin="100" linktype="curved" linkwidth="5" linkarrow="true" linkdash="solid" nodeborder="bracket" nodewidth="439" nodeborderwidth="3" nodefill="false" nodemargin="11" nodepadding="5" nodefont="Roboto Mono 14" nodemarkup="true"/>
|
||||||
<nodename posx="764.88964843749955" posy="135.42341613769531" maxwidth="488.96484375">
|
<nodename posx="1394.798161778599" posy="175.04571601189673" maxwidth="488.96484375">
|
||||||
<text data="tgbotapi.core Root project with API. It is not recommended to use its requests directly and better to use at least tgbotapi.extensions.api"/>
|
<text data="tgbotapi.core Root project with API. It is not recommended to use its requests directly and better to use at least tgbotapi.extensions.api"/>
|
||||||
</nodename>
|
</nodename>
|
||||||
<nodenote></nodenote>
|
<nodenote></nodenote>
|
||||||
<nodes>
|
<nodes>
|
||||||
<node id="1" posx="781.88964843749955" posy="387.42341613769531" width="406" height="145" side="bottom" fold="false" treesize="603" color="#68b723" colorroot="true" layout="Downwards" group="false">
|
<node id="1" posx="1411.798161778599" posy="427.04571601189673" width="406" height="145" side="bottom" fold="false" treesize="743" color="#68b723" colorroot="true" layout="Downwards" group="false">
|
||||||
<style branchmargin="100" linktype="curved" linkwidth="5" linkarrow="true" linkdash="solid" nodeborder="none" nodewidth="394" nodeborderwidth="3" nodefill="false" nodemargin="11" nodepadding="5" nodefont="Roboto Mono 14" nodemarkup="true"/>
|
<style branchmargin="100" linktype="curved" linkwidth="5" linkarrow="true" linkdash="solid" nodeborder="none" nodewidth="394" nodeborderwidth="3" nodefill="false" nodemargin="11" nodepadding="5" nodefont="Roboto Mono 14" nodemarkup="true"/>
|
||||||
<nodename posx="797.88964843749955" posy="403.42341613769531" maxwidth="419.451171875">
|
<nodename posx="1427.798161778599" posy="443.04571601189673" maxwidth="419.451171875">
|
||||||
<text data="TelegramBotAPI extensions Family of projects which are fully based on TelegramBotAPI and extend its functionality"/>
|
<text data="TelegramBotAPI extensions Family of projects which are fully based on TelegramBotAPI and extend its functionality"/>
|
||||||
</nodename>
|
</nodename>
|
||||||
<nodenote></nodenote>
|
<nodenote></nodenote>
|
||||||
<nodes>
|
<nodes>
|
||||||
<node id="2" posx="683.38964843749955" posy="632.42341613769531" width="296" height="191" side="bottom" fold="false" treesize="296" color="#68b723" colorroot="true" layout="Downwards" group="false">
|
<node id="2" posx="1247.298161778599" posy="672.04571601189673" width="296" height="191" side="bottom" fold="false" treesize="296" color="#68b723" colorroot="true" layout="Downwards" group="false">
|
||||||
<style branchmargin="100" linktype="curved" linkwidth="5" linkarrow="true" linkdash="solid" nodeborder="bracket" nodewidth="203" nodeborderwidth="3" nodefill="false" nodemargin="11" nodepadding="5" nodefont="Roboto Mono 14" nodemarkup="true"/>
|
<style branchmargin="100" linktype="curved" linkwidth="5" linkarrow="true" linkdash="solid" nodeborder="bracket" nodewidth="203" nodeborderwidth="3" nodefill="false" nodemargin="11" nodepadding="5" nodefont="Roboto Mono 14" nodemarkup="true"/>
|
||||||
<nodename posx="699.38964843749955" posy="648.42341613769531" maxwidth="295.90315755208337">
|
<nodename posx="1263.298161778599" posy="688.04571601189673" maxwidth="295.90315755208337">
|
||||||
<text data="tgbotapi.extensions.api Extensions project for make requests more look like in the Telegram Bot API and give opportunity to use it's easier"/>
|
<text data="tgbotapi.extensions.api Extensions project for make requests more look like in the Telegram Bot API and give opportunity to use it's easier"/>
|
||||||
</nodename>
|
</nodename>
|
||||||
<nodenote></nodenote>
|
<nodenote></nodenote>
|
||||||
</node>
|
</node>
|
||||||
<node id="3" posx="979.38964843749955" posy="632.42341613769531" width="307" height="168" side="bottom" fold="false" treesize="307" color="#68b723" colorroot="true" layout="Downwards" group="false">
|
<node id="3" posx="1609.298161778599" posy="672.04571601189673" width="307" height="168" side="bottom" fold="false" treesize="439" color="#68b723" colorroot="true" layout="Downwards" group="false">
|
||||||
<style branchmargin="100" linktype="curved" linkwidth="5" linkarrow="true" linkdash="solid" nodeborder="bracket" nodewidth="286" nodeborderwidth="3" nodefill="false" nodemargin="11" nodepadding="5" nodefont="Roboto Mono 14" nodemarkup="true"/>
|
<style branchmargin="100" linktype="curved" linkwidth="5" linkarrow="true" linkdash="solid" nodeborder="bracket" nodewidth="286" nodeborderwidth="3" nodefill="false" nodemargin="11" nodepadding="5" nodefont="Roboto Mono 14" nodemarkup="true"/>
|
||||||
<nodename posx="995.38964843749955" posy="648.42341613769531" maxwidth="299.252197265625">
|
<nodename posx="1625.298161778599" posy="688.04571601189673" maxwidth="299.252197265625">
|
||||||
<text data="tgbotapi.extensions.utils Extensions project with utils things which will make easier different operations"/>
|
<text data="tgbotapi.extensions.utils Extensions project with utils things which will make easier different operations"/>
|
||||||
</nodename>
|
</nodename>
|
||||||
<nodenote></nodenote>
|
<nodenote></nodenote>
|
||||||
|
<nodes>
|
||||||
|
<node id="4" posx="1543.298161778599" posy="940.04571601189673" width="439" height="122" side="bottom" fold="false" treesize="439" color="#68b723" colorroot="false" layout="Downwards" group="false">
|
||||||
|
<style branchmargin="100" linktype="curved" linkwidth="5" linkarrow="true" linkdash="solid" nodeborder="bracket" nodewidth="387" nodeborderwidth="3" nodefill="false" nodemargin="11" nodepadding="5" nodefont="Roboto Mono 14" nodemarkup="true"/>
|
||||||
|
<nodename posx="1559.298161778599" posy="956.04571601189673" maxwidth="408.97932942708348">
|
||||||
|
<text data="tgbotapi.extensions.behaviour_builder Extension project for building bot behaviour via special dsl"/>
|
||||||
|
</nodename>
|
||||||
|
<nodenote></nodenote>
|
||||||
|
</node>
|
||||||
|
</nodes>
|
||||||
</node>
|
</node>
|
||||||
</nodes>
|
</nodes>
|
||||||
</node>
|
</node>
|
||||||
</nodes>
|
</nodes>
|
||||||
</node>
|
</node>
|
||||||
<node id="4" posx="815.52319335937455" posy="948.04447937011719" width="329" height="213" side="top" fold="false" treesize="329" layout="Downwards" group="false">
|
<node id="5" posx="1391.8445078072455" posy="1155.6062730594231" width="461" height="236" side="bottom" fold="false" treesize="461" layout="Downwards" group="false">
|
||||||
<style branchmargin="100" linktype="curved" linkwidth="5" linkarrow="true" linkdash="solid" nodeborder="bracket" nodewidth="388" nodeborderwidth="3" nodefill="false" nodemargin="11" nodepadding="5" nodefont="Roboto Mono 14" nodemarkup="true"/>
|
<style branchmargin="100" linktype="curved" linkwidth="5" linkarrow="true" linkdash="solid" nodeborder="bracket" nodewidth="430" nodeborderwidth="3" nodefill="false" nodemargin="11" nodepadding="5" nodefont="Roboto Mono 14" nodemarkup="true"/>
|
||||||
<nodename posx="831.52319335937455" posy="964.04447937011719" maxwidth="394.3671875">
|
<nodename posx="1407.8445078072455" posy="1171.6062730594231" maxwidth="453.885498046875">
|
||||||
<text data="tgbotapi Here included all available TelegramBotAPI libraries: * tgbotapi.core * tgbotapi.extensions.api * tgbotapi.extensions.utils">
|
<text data="tgbotapi Here included all available TelegramBotAPI libraries: * tgbotapi.core * tgbotapi.extensions.api * tgbotapi.extensions.utils * tgbotapi.extensions.behaviour_builder">
|
||||||
<color>
|
<color>
|
||||||
<range start="67" end="68" extra="rgb(255,0,0)"/>
|
<range start="67" end="68" extra="rgb(255,0,0)"/>
|
||||||
<range start="67" end="68" extra="rgb(255,0,0)"/>
|
<range start="67" end="68" extra="rgb(255,0,0)"/>
|
||||||
@ -70,6 +79,94 @@
|
|||||||
<range start="67" end="68" extra="rgb(255,0,0)"/>
|
<range start="67" end="68" extra="rgb(255,0,0)"/>
|
||||||
<range start="67" end="68" extra="rgb(255,0,0)"/>
|
<range start="67" end="68" extra="rgb(255,0,0)"/>
|
||||||
<range start="67" end="68" extra="rgb(255,0,0)"/>
|
<range start="67" end="68" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="67" end="68" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="67" end="68" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="67" end="68" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="67" end="68" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="67" end="68" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="67" end="68" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="67" end="68" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="67" end="68" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="67" end="68" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="67" end="68" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="67" end="68" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="67" end="68" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="67" end="68" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="67" end="68" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="67" end="68" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="67" end="68" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="67" end="68" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="67" end="68" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="67" end="68" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="67" end="68" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="67" end="68" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="67" end="68" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="67" end="68" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="67" end="68" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="67" end="68" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="67" end="68" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="67" end="68" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="67" end="68" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="67" end="68" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="67" end="68" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="67" end="68" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="67" end="68" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="67" end="68" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="67" end="68" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="67" end="68" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="67" end="68" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="67" end="68" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="67" end="68" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="67" end="68" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="67" end="68" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="67" end="68" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="67" end="68" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="67" end="68" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="67" end="68" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="84" end="85" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="84" end="85" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="84" end="85" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="84" end="85" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="84" end="85" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="84" end="85" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="84" end="85" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="84" end="85" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="84" end="85" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="84" end="85" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="84" end="85" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="84" end="85" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="84" end="85" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="84" end="85" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="84" end="85" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="84" end="85" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="84" end="85" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="84" end="85" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="84" end="85" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="84" end="85" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="84" end="85" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="84" end="85" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="84" end="85" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="84" end="85" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="84" end="85" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="84" end="85" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="84" end="85" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="84" end="85" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="84" end="85" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="84" end="85" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="84" end="85" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="84" end="85" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="84" end="85" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="84" end="85" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="84" end="85" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="84" end="85" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="84" end="85" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="84" end="85" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="84" end="85" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="84" end="85" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="84" end="85" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="84" end="85" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="84" end="85" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="84" end="85" extra="rgb(255,0,0)"/>
|
||||||
<range start="84" end="85" extra="rgb(255,0,0)"/>
|
<range start="84" end="85" extra="rgb(255,0,0)"/>
|
||||||
<range start="84" end="85" extra="rgb(255,0,0)"/>
|
<range start="84" end="85" extra="rgb(255,0,0)"/>
|
||||||
<range start="84" end="85" extra="rgb(255,0,0)"/>
|
<range start="84" end="85" extra="rgb(255,0,0)"/>
|
||||||
@ -102,6 +199,90 @@
|
|||||||
<range start="111" end="112" extra="rgb(255,0,0)"/>
|
<range start="111" end="112" extra="rgb(255,0,0)"/>
|
||||||
<range start="111" end="112" extra="rgb(255,0,0)"/>
|
<range start="111" end="112" extra="rgb(255,0,0)"/>
|
||||||
<range start="111" end="112" extra="rgb(255,0,0)"/>
|
<range start="111" end="112" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="111" end="112" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="111" end="112" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="111" end="112" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="111" end="112" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="111" end="112" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="111" end="112" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="111" end="112" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="111" end="112" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="111" end="112" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="111" end="112" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="111" end="112" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="111" end="112" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="111" end="112" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="111" end="112" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="111" end="112" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="111" end="112" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="111" end="112" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="111" end="112" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="111" end="112" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="111" end="112" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="111" end="112" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="111" end="112" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="111" end="112" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="111" end="112" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="111" end="112" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="111" end="112" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="111" end="112" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="111" end="112" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="111" end="112" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="111" end="112" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="111" end="112" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="111" end="112" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="111" end="112" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="111" end="112" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="111" end="112" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="111" end="112" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="111" end="112" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="111" end="112" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="111" end="112" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="111" end="112" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="111" end="112" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="111" end="112" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="111" end="112" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="111" end="112" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="139" end="140" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="139" end="140" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="139" end="140" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="139" end="140" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="139" end="140" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="139" end="140" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="139" end="140" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="139" end="140" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="139" end="140" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="139" end="140" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="139" end="140" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="139" end="140" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="139" end="140" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="139" end="140" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="139" end="140" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="139" end="140" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="139" end="140" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="139" end="140" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="139" end="140" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="139" end="140" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="139" end="140" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="139" end="140" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="139" end="140" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="139" end="140" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="139" end="140" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="139" end="140" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="139" end="140" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="139" end="140" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="139" end="140" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="139" end="140" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="139" end="140" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="139" end="140" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="139" end="140" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="139" end="140" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="139" end="140" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="139" end="140" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="139" end="140" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="139" end="140" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="139" end="140" extra="rgb(255,0,0)"/>
|
||||||
|
<range start="139" end="140" extra="rgb(255,0,0)"/>
|
||||||
</color>
|
</color>
|
||||||
</text>
|
</text>
|
||||||
</nodename>
|
</nodename>
|
||||||
@ -110,12 +291,17 @@
|
|||||||
</nodes>
|
</nodes>
|
||||||
<groups/>
|
<groups/>
|
||||||
<connections>
|
<connections>
|
||||||
<connection from_id="2" to_id="4" drag_x="905.70642089843705" drag_y="891.23394775390625" color="#777777">
|
<connection from_id="2" to_id="5" drag_x="1475.8213347929195" drag_y="1014.8259945356604" color="#777777">
|
||||||
<style connectiondash="dotted" connectionlwidth="2" connectionarrow="fromto" connectionpadding="3" connectionfont="Sans 10" connectiontwidth="100"/>
|
<style connectiondash="dotted" connectionlwidth="2" connectionarrow="fromto" connectionpadding="3" connectionfont="Sans 10" connectiontwidth="100"/>
|
||||||
<title></title>
|
<title></title>
|
||||||
<note></note>
|
<note></note>
|
||||||
</connection>
|
</connection>
|
||||||
<connection from_id="3" to_id="4" drag_x="1056.456420898437" drag_y="885.48394775390625" color="#777777">
|
<connection from_id="4" to_id="5" drag_x="1691.5447998046875" drag_y="1107.00439453125" color="#777777">
|
||||||
|
<style connectiondash="dotted" connectionlwidth="2" connectionarrow="fromto" connectionpadding="3" connectionfont="Sans 10" connectiontwidth="100"/>
|
||||||
|
<title></title>
|
||||||
|
<note></note>
|
||||||
|
</connection>
|
||||||
|
<connection from_id="3" to_id="5" drag_x="1483.48876953125" drag_y="896.18115234375">
|
||||||
<style connectiondash="dotted" connectionlwidth="2" connectionarrow="fromto" connectionpadding="3" connectionfont="Sans 10" connectiontwidth="100"/>
|
<style connectiondash="dotted" connectionlwidth="2" connectionarrow="fromto" connectionpadding="3" connectionfont="Sans 10" connectiontwidth="100"/>
|
||||||
<title></title>
|
<title></title>
|
||||||
<note></note>
|
<note></note>
|
||||||
|
@ -12,11 +12,11 @@ klock_version=2.0.3
|
|||||||
uuid_version=0.2.3
|
uuid_version=0.2.3
|
||||||
ktor_version=1.5.0
|
ktor_version=1.5.0
|
||||||
|
|
||||||
micro_utils_version=0.4.15
|
micro_utils_version=0.4.16
|
||||||
|
|
||||||
javax_activation_version=1.1.1
|
javax_activation_version=1.1.1
|
||||||
|
|
||||||
library_group=dev.inmo
|
library_group=dev.inmo
|
||||||
library_version=0.30.12
|
library_version=0.30.13
|
||||||
|
|
||||||
github_release_plugin_version=2.2.12
|
github_release_plugin_version=2.2.12
|
||||||
|
File diff suppressed because it is too large
Load Diff
Before Width: | Height: | Size: 80 KiB After Width: | Height: | Size: 89 KiB |
@ -8,5 +8,6 @@ pluginManagement {
|
|||||||
include ":tgbotapi.core"
|
include ":tgbotapi.core"
|
||||||
include ":tgbotapi.extensions.api"
|
include ":tgbotapi.extensions.api"
|
||||||
include ":tgbotapi.extensions.utils"
|
include ":tgbotapi.extensions.utils"
|
||||||
|
include ":tgbotapi.extensions.behaviour_builder"
|
||||||
include ":tgbotapi"
|
include ":tgbotapi"
|
||||||
include ":docs"
|
include ":docs"
|
||||||
|
@ -19,13 +19,17 @@ interface TextedOutput : ParsableOutput, EntitiesOutput
|
|||||||
|
|
||||||
interface TextedInput : Texted {
|
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]
|
* @see [CaptionedInput.fullEntitiesList]
|
||||||
*/
|
*/
|
||||||
val textEntities: List<TextPart>
|
val textEntities: List<TextPart>
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Full list of [TextSource] built from source[TextedInput.textEntities]
|
||||||
|
*
|
||||||
* @see TextedInput.textEntities
|
* @see TextedInput.textEntities
|
||||||
* @see justTextSources
|
* @see justTextSources
|
||||||
*/
|
*/
|
||||||
|
@ -14,6 +14,14 @@ class FlowsUpdatesFilter(
|
|||||||
private val updatesSharedFlow = MutableSharedFlow<Update>(extraBufferCapacity = broadcastChannelsSize)
|
private val updatesSharedFlow = MutableSharedFlow<Update>(extraBufferCapacity = broadcastChannelsSize)
|
||||||
@Suppress("MemberVisibilityCanBePrivate")
|
@Suppress("MemberVisibilityCanBePrivate")
|
||||||
val allUpdatesFlow: Flow<Update> = updatesSharedFlow.asSharedFlow()
|
val allUpdatesFlow: Flow<Update> = updatesSharedFlow.asSharedFlow()
|
||||||
|
@Suppress("MemberVisibilityCanBePrivate")
|
||||||
|
val allUpdatesWithoutMediaGroupsGroupingFlow: Flow<Update> = updatesSharedFlow.flatMapConcat {
|
||||||
|
when (it) {
|
||||||
|
is SentMediaGroupUpdate -> it.origins.asFlow()
|
||||||
|
is EditMediaGroupUpdate -> flowOf(it.origin)
|
||||||
|
else -> flowOf(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override val allowedUpdates: List<String>
|
override val allowedUpdates: List<String>
|
||||||
get() = ALL_UPDATES_LIST
|
get() = ALL_UPDATES_LIST
|
||||||
|
62
tgbotapi.extensions.behaviour_builder/README.md
Normal file
62
tgbotapi.extensions.behaviour_builder/README.md
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
# TelegramBotAPI Behaviour Builder Extensions
|
||||||
|
|
||||||
|
This extension was created to make it more simple to build bot steps handling. Usually, you must use something like:
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
val bot = telegramBot(TOKEN)
|
||||||
|
bot.startGettingFlowsUpdatesByLongPolling {
|
||||||
|
messagesFlow.subscribeSafelyWithoutExceptions {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
// here I already tired to write this example 😫
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This library offer other way to do a lot of routine in more simple way:
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
telegramBot(token) {
|
||||||
|
onCommand("start".regex) {
|
||||||
|
execute(SendTextMessage(it.chat.id, "This bot can ...")) // replaceable with reply(it, "This bot can ...") when you are using `tgbotapi.extensions.api`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Triggers
|
||||||
|
|
||||||
|
In terminology of this project the `Triggers` are things which have no initial message, may have own filter for incoming
|
||||||
|
messages and filter messages for context which will be used in subcontext. Full syntax with `onText` as an example:
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
telegramBot(TOKEN) {
|
||||||
|
onText(
|
||||||
|
includeFilterByChatInBehaviourSubContext = true, // if false - last lambda will receive all messages instead of filtered by chat messages
|
||||||
|
additionalFilter = { message: CommonMessage<TextContent> ->
|
||||||
|
// here you may check incoming message for any requirements before it will be passed to the main lambda
|
||||||
|
}
|
||||||
|
) { message: CommonMessage<TextContent> -> // this here is `BehaviourContext`
|
||||||
|
// here put your actions and additional waiters
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Waiters
|
||||||
|
|
||||||
|
Waiters targeted to get some content "here and now", they must be used inside some trigger main lambda:
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
telegramBot(TOKEN) {
|
||||||
|
onCommand("start") { message: CommonMessage<TextContent> ->
|
||||||
|
val userPhotos = waitPhoto(
|
||||||
|
SendTextMessage(it.chat.id, "Ok, send me some photo, please"), // init request, can be any `Request` object
|
||||||
|
{ update: Update -> // That is update which is NOT passed requirements. In current context we expect some photo, but received something else
|
||||||
|
SendTextMessage(it.chat.id, "Excuse me, but I can accept only photos") // it could be null
|
||||||
|
},
|
||||||
|
2, // some count of photos
|
||||||
|
includeMediaGroups = true, // if false, messages related to some media group will be skipped and recognized as incorrect
|
||||||
|
) { message: CommonMessate<PhotoContent> -> // this method is optional and you can use it in case you want to add some additional requirements checks
|
||||||
|
message.content // return null if message didn't passed requirements
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
46
tgbotapi.extensions.behaviour_builder/build.gradle
Normal file
46
tgbotapi.extensions.behaviour_builder/build.gradle
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
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.extensions.utils")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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":"This 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"}]}}
|
69
tgbotapi.extensions.behaviour_builder/publish.gradle
Normal file
69
tgbotapi.extensions.behaviour_builder/publish.gradle
Normal file
@ -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 = "This 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')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
package dev.inmo.tgbotapi.extensions.behaviour_builder
|
||||||
|
|
||||||
|
import dev.inmo.tgbotapi.bot.TelegramBot
|
||||||
|
import dev.inmo.tgbotapi.extensions.utils.updates.retrieving.startGettingOfUpdatesByLongPolling
|
||||||
|
import dev.inmo.tgbotapi.updateshandlers.FlowsUpdatesFilter
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
|
||||||
|
suspend fun TelegramBot.buildBehaviour(
|
||||||
|
scope: CoroutineScope,
|
||||||
|
flowUpdatesFilter: FlowsUpdatesFilter,
|
||||||
|
block: BehaviourContextReceiver<Unit>
|
||||||
|
) {
|
||||||
|
BehaviourContext(
|
||||||
|
this,
|
||||||
|
scope,
|
||||||
|
flowUpdatesFilter
|
||||||
|
).block()
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun TelegramBot.buildBehaviour(
|
||||||
|
scope: CoroutineScope,
|
||||||
|
block: BehaviourContextReceiver<Unit>
|
||||||
|
) = FlowsUpdatesFilter().also {
|
||||||
|
buildBehaviour(
|
||||||
|
scope,
|
||||||
|
it,
|
||||||
|
block
|
||||||
|
)
|
||||||
|
startGettingOfUpdatesByLongPolling(
|
||||||
|
updatesFilter = it,
|
||||||
|
scope = scope
|
||||||
|
)
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
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<T> = suspend BehaviourContext.() -> T
|
||||||
|
typealias BehaviourContextAndTypeReceiver<T, I> = suspend BehaviourContext.(I) -> T
|
||||||
|
|
||||||
|
data class BehaviourContext(
|
||||||
|
val bot: TelegramBot,
|
||||||
|
val scope: CoroutineScope,
|
||||||
|
val flowsUpdatesFilter: FlowsUpdatesFilter = FlowsUpdatesFilter()
|
||||||
|
) : UpdatesFilter by flowsUpdatesFilter, TelegramBot by bot, CoroutineScope by scope
|
@ -0,0 +1,123 @@
|
|||||||
|
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.behaviour_builder.BehaviourContext
|
||||||
|
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.CancellationException
|
||||||
|
import kotlinx.coroutines.flow.*
|
||||||
|
|
||||||
|
private val cancelledByFilterException = CancellationException("Cancelled by filter precreatedException")
|
||||||
|
|
||||||
|
typealias RequestBuilder<T> = suspend (Update) -> Request<T>
|
||||||
|
typealias NullableRequestBuilder<T> = suspend (Update) -> Request<T>?
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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 <T> 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) -> List<T>
|
||||||
|
): Flow<T> {
|
||||||
|
val flow = allUpdatesFlow.flatMapConcat {
|
||||||
|
val result = safelyWithoutExceptions { filter(it) }
|
||||||
|
(if (result == null || result.isEmpty()) {
|
||||||
|
if (cancelTrigger(it)) {
|
||||||
|
cancelRequestFactory(it) ?.also {
|
||||||
|
safelyWithoutExceptions { bot.execute(it) }
|
||||||
|
throw cancelledByFilterException
|
||||||
|
}
|
||||||
|
}
|
||||||
|
errorFactory(it) ?.also { errorRequest ->
|
||||||
|
safelyWithoutExceptions { bot.execute(errorRequest) }
|
||||||
|
}
|
||||||
|
emptyList()
|
||||||
|
} else {
|
||||||
|
result
|
||||||
|
}).asFlow()
|
||||||
|
}
|
||||||
|
val result = if (count == null) {
|
||||||
|
flow
|
||||||
|
} else {
|
||||||
|
flow.take(count)
|
||||||
|
}
|
||||||
|
initRequest ?.also { safelyWithoutExceptions { bot.execute(initRequest) } }
|
||||||
|
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 <T> BehaviourContext.expectFlow(
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
count: Int? = null,
|
||||||
|
errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
cancelRequestFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
cancelTrigger: suspend (Update) -> Boolean = { cancelRequestFactory(it) != null },
|
||||||
|
filter: suspend (Update) -> List<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 <T> 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) {
|
||||||
|
listOfNotNull(filter.invoke(it))
|
||||||
|
}.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 <T> BehaviourContext.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)
|
@ -0,0 +1,102 @@
|
|||||||
|
@file:Suppress("unused")
|
||||||
|
|
||||||
|
package dev.inmo.tgbotapi.extensions.behaviour_builder.expectations
|
||||||
|
|
||||||
|
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.*
|
||||||
|
import kotlinx.coroutines.flow.toList
|
||||||
|
|
||||||
|
typealias CallbackQueryMapper<T> = T.() -> T?
|
||||||
|
|
||||||
|
private suspend fun <O> BehaviourContext.waitCallbackQueries(
|
||||||
|
count: Int = 1,
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
mapper: suspend CallbackQuery.() -> O?
|
||||||
|
): List<O> = expectFlow(
|
||||||
|
initRequest,
|
||||||
|
count,
|
||||||
|
errorFactory
|
||||||
|
) {
|
||||||
|
it.asCallbackQueryUpdate() ?.data ?.mapper().let(::listOfNotNull)
|
||||||
|
}.toList().toList()
|
||||||
|
|
||||||
|
|
||||||
|
private suspend inline fun <reified T : CallbackQuery> BehaviourContext.waitEvents(
|
||||||
|
count: Int = 1,
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
noinline errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
noinline filter: CallbackQueryMapper<T>? = null
|
||||||
|
) : List<T> = waitCallbackQueries<T>(
|
||||||
|
count,
|
||||||
|
initRequest,
|
||||||
|
errorFactory
|
||||||
|
) {
|
||||||
|
if (this is T) {
|
||||||
|
if (filter == null) {
|
||||||
|
this
|
||||||
|
} else {
|
||||||
|
filter(this)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
suspend fun BehaviourContext.waitDataCallbackQuery(
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
count: Int = 1,
|
||||||
|
filter: CallbackQueryMapper<DataCallbackQuery>? = null
|
||||||
|
) = waitEvents(count, initRequest, errorFactory, filter)
|
||||||
|
suspend fun BehaviourContext.waitGameShortNameCallbackQuery(
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
count: Int = 1,
|
||||||
|
filter: CallbackQueryMapper<GameShortNameCallbackQuery>? = null
|
||||||
|
) = waitEvents(count, initRequest, errorFactory, filter)
|
||||||
|
suspend fun BehaviourContext.waitInlineMessageIdCallbackQuery(
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
count: Int = 1,
|
||||||
|
filter: CallbackQueryMapper<InlineMessageIdCallbackQuery>? = null
|
||||||
|
) = waitEvents(count, initRequest, errorFactory, filter)
|
||||||
|
suspend fun BehaviourContext.waitInlineMessageIdDataCallbackQuery(
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
count: Int = 1,
|
||||||
|
filter: CallbackQueryMapper<InlineMessageIdDataCallbackQuery>? = null
|
||||||
|
) = waitEvents(count, initRequest, errorFactory, filter)
|
||||||
|
suspend fun BehaviourContext.waitInlineMessageIdGameShortNameCallbackQuery(
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
count: Int = 1,
|
||||||
|
filter: CallbackQueryMapper<InlineMessageIdGameShortNameCallbackQuery>? = null
|
||||||
|
) = waitEvents(count, initRequest, errorFactory, filter)
|
||||||
|
suspend fun BehaviourContext.waitMessageCallbackQuery(
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
count: Int = 1,
|
||||||
|
filter: CallbackQueryMapper<MessageCallbackQuery>? = null
|
||||||
|
) = waitEvents(count, initRequest, errorFactory, filter)
|
||||||
|
suspend fun BehaviourContext.waitMessageDataCallbackQuery(
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
count: Int = 1,
|
||||||
|
filter: CallbackQueryMapper<MessageDataCallbackQuery>? = null
|
||||||
|
) = waitEvents(count, initRequest, errorFactory, filter)
|
||||||
|
suspend fun BehaviourContext.waitMessageGameShortNameCallbackQuery(
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
count: Int = 1,
|
||||||
|
filter: CallbackQueryMapper<MessageGameShortNameCallbackQuery>? = null
|
||||||
|
) = waitEvents(count, initRequest, errorFactory, filter)
|
||||||
|
suspend fun BehaviourContext.waitUnknownCallbackQuery(
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
count: Int = 1,
|
||||||
|
filter: CallbackQueryMapper<UnknownCallbackQueryType>? = null
|
||||||
|
) = waitEvents(count, initRequest, errorFactory, filter)
|
@ -0,0 +1,197 @@
|
|||||||
|
@file:Suppress("unused")
|
||||||
|
|
||||||
|
package dev.inmo.tgbotapi.extensions.behaviour_builder.expectations
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.coroutines.safelyWithoutExceptions
|
||||||
|
import dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContext
|
||||||
|
import dev.inmo.tgbotapi.extensions.utils.*
|
||||||
|
import dev.inmo.tgbotapi.requests.abstracts.Request
|
||||||
|
import dev.inmo.tgbotapi.types.message.abstracts.CommonMessage
|
||||||
|
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.*
|
||||||
|
import dev.inmo.tgbotapi.types.message.payments.InvoiceContent
|
||||||
|
import kotlinx.coroutines.flow.toList
|
||||||
|
|
||||||
|
typealias CommonMessageToContentMapper<T> = suspend CommonMessage<T>.() -> T?
|
||||||
|
|
||||||
|
private suspend fun <O> BehaviourContext.waitCommonMessage(
|
||||||
|
count: Int = 1,
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
includeMediaGroups: Boolean = true,
|
||||||
|
errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
mapper: suspend CommonMessage<MessageContent>.() -> O?
|
||||||
|
): List<O> = expectFlow(
|
||||||
|
initRequest,
|
||||||
|
count,
|
||||||
|
errorFactory
|
||||||
|
) {
|
||||||
|
if (includeMediaGroups) {
|
||||||
|
it.asSentMediaGroupUpdate() ?.data ?.mapNotNull {
|
||||||
|
(it as CommonMessage<MessageContent>).mapper()
|
||||||
|
} ?.let { return@expectFlow it }
|
||||||
|
}
|
||||||
|
it.asMessageUpdate() ?.data ?.asCommonMessage() ?.mapper().let(::listOfNotNull)
|
||||||
|
}.toList().toList()
|
||||||
|
|
||||||
|
private suspend inline fun <reified T : MessageContent> BehaviourContext.waitContent(
|
||||||
|
count: Int = 1,
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
includeMediaGroups: Boolean = true,
|
||||||
|
noinline errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
noinline filter: CommonMessageToContentMapper<T>? = null
|
||||||
|
) : List<T> = waitCommonMessage<T>(
|
||||||
|
count,
|
||||||
|
initRequest,
|
||||||
|
includeMediaGroups,
|
||||||
|
errorFactory
|
||||||
|
) {
|
||||||
|
if (content is T) {
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
val message = (this as CommonMessage<T>)
|
||||||
|
if (filter == null) {
|
||||||
|
message.content
|
||||||
|
} else {
|
||||||
|
safelyWithoutExceptions { filter(message) }
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun BehaviourContext.waitContact(
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
count: Int = 1,
|
||||||
|
filter: CommonMessageToContentMapper<ContactContent>? = null
|
||||||
|
) = waitContent(count, initRequest, false, errorFactory, filter)
|
||||||
|
suspend fun BehaviourContext.waitDice(
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
count: Int = 1,
|
||||||
|
filter: CommonMessageToContentMapper<DiceContent>? = null
|
||||||
|
) = waitContent(count, initRequest, false, errorFactory, filter)
|
||||||
|
suspend fun BehaviourContext.waitGame(
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
count: Int = 1,
|
||||||
|
filter: CommonMessageToContentMapper<GameContent>? = null
|
||||||
|
) = waitContent(count, initRequest, false, errorFactory, filter)
|
||||||
|
suspend fun BehaviourContext.waitLocation(
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
count: Int = 1,
|
||||||
|
filter: CommonMessageToContentMapper<LocationContent>? = null
|
||||||
|
) = waitContent(count, initRequest, false, errorFactory, filter)
|
||||||
|
suspend fun BehaviourContext.waitPoll(
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
count: Int = 1,
|
||||||
|
filter: CommonMessageToContentMapper<PollContent>? = null
|
||||||
|
) = waitContent(count, initRequest, false, errorFactory, filter)
|
||||||
|
suspend fun BehaviourContext.waitText(
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
count: Int = 1,
|
||||||
|
filter: CommonMessageToContentMapper<TextContent>? = null
|
||||||
|
) = waitContent(count, initRequest, false, errorFactory, filter)
|
||||||
|
suspend fun BehaviourContext.waitVenue(
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
count: Int = 1,
|
||||||
|
filter: CommonMessageToContentMapper<VenueContent>? = null
|
||||||
|
) = waitContent(count, initRequest, false, errorFactory, filter)
|
||||||
|
suspend fun BehaviourContext.waitAudioMediaGroup(
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
count: Int = 1,
|
||||||
|
includeMediaGroups: Boolean = true,
|
||||||
|
filter: CommonMessageToContentMapper<AudioMediaGroupContent>? = null
|
||||||
|
) = waitContent(count, initRequest, includeMediaGroups, errorFactory, filter)
|
||||||
|
suspend fun BehaviourContext.waitDocumentMediaGroup(
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
count: Int = 1,
|
||||||
|
includeMediaGroups: Boolean = true,
|
||||||
|
filter: CommonMessageToContentMapper<DocumentMediaGroupContent>? = null
|
||||||
|
) = waitContent(count, initRequest, includeMediaGroups, errorFactory, filter)
|
||||||
|
suspend fun BehaviourContext.waitMedia(
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
count: Int = 1,
|
||||||
|
includeMediaGroups: Boolean = true,
|
||||||
|
filter: CommonMessageToContentMapper<MediaContent>? = null
|
||||||
|
) = waitContent(count, initRequest, includeMediaGroups, errorFactory, filter)
|
||||||
|
suspend fun BehaviourContext.waitMediaGroup(
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
count: Int = 1,
|
||||||
|
includeMediaGroups: Boolean = true,
|
||||||
|
filter: CommonMessageToContentMapper<MediaGroupContent>? = null
|
||||||
|
) = waitContent(count, initRequest, includeMediaGroups, errorFactory, filter)
|
||||||
|
suspend fun BehaviourContext.waitVisualMediaGroup(
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
count: Int = 1,
|
||||||
|
includeMediaGroups: Boolean = true,
|
||||||
|
filter: CommonMessageToContentMapper<VisualMediaGroupContent>? = null
|
||||||
|
) = waitContent(count, initRequest, includeMediaGroups, errorFactory, filter)
|
||||||
|
suspend fun BehaviourContext.waitAnimation(
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
count: Int = 1,
|
||||||
|
filter: CommonMessageToContentMapper<AnimationContent>? = null
|
||||||
|
) = waitContent(count, initRequest, false, errorFactory, filter)
|
||||||
|
suspend fun BehaviourContext.waitAudio(
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
count: Int = 1,
|
||||||
|
includeMediaGroups: Boolean = true,
|
||||||
|
filter: CommonMessageToContentMapper<AudioContent>? = null
|
||||||
|
) = waitContent(count, initRequest, includeMediaGroups, errorFactory, filter)
|
||||||
|
suspend fun BehaviourContext.waitDocument(
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
count: Int = 1,
|
||||||
|
includeMediaGroups: Boolean = true,
|
||||||
|
filter: CommonMessageToContentMapper<DocumentContent>? = null
|
||||||
|
) = waitContent(count, initRequest, includeMediaGroups, errorFactory, filter)
|
||||||
|
suspend fun BehaviourContext.waitPhoto(
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
count: Int = 1,
|
||||||
|
includeMediaGroups: Boolean = true,
|
||||||
|
filter: CommonMessageToContentMapper<PhotoContent>? = null
|
||||||
|
) = waitContent(count, initRequest, includeMediaGroups, errorFactory, filter)
|
||||||
|
suspend fun BehaviourContext.waitSticker(
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
count: Int = 1,
|
||||||
|
filter: CommonMessageToContentMapper<StickerContent>? = null
|
||||||
|
) = waitContent(count, initRequest, false, errorFactory, filter)
|
||||||
|
suspend fun BehaviourContext.waitVideo(
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
count: Int = 1,
|
||||||
|
includeMediaGroups: Boolean = true,
|
||||||
|
filter: CommonMessageToContentMapper<VideoContent>? = null
|
||||||
|
) = waitContent(count, initRequest, includeMediaGroups, errorFactory, filter)
|
||||||
|
suspend fun BehaviourContext.waitVideoNote(
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
count: Int = 1,
|
||||||
|
filter: CommonMessageToContentMapper<VideoNoteContent>? = null
|
||||||
|
) = waitContent(count, initRequest, false, errorFactory, filter)
|
||||||
|
suspend fun BehaviourContext.waitVoice(
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
count: Int = 1,
|
||||||
|
filter: CommonMessageToContentMapper<VoiceContent>? = null
|
||||||
|
) = waitContent(count, initRequest, false, errorFactory, filter)
|
||||||
|
suspend fun BehaviourContext.waitInvoice(
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
count: Int = 1,
|
||||||
|
filter: CommonMessageToContentMapper<InvoiceContent>? = null
|
||||||
|
) = waitContent(count, initRequest, false, errorFactory, filter)
|
@ -0,0 +1,144 @@
|
|||||||
|
@file:Suppress("unused")
|
||||||
|
|
||||||
|
package dev.inmo.tgbotapi.extensions.behaviour_builder.expectations
|
||||||
|
|
||||||
|
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
|
||||||
|
import dev.inmo.tgbotapi.types.message.ChatEvents.*
|
||||||
|
import dev.inmo.tgbotapi.types.message.ChatEvents.abstracts.*
|
||||||
|
import dev.inmo.tgbotapi.types.message.abstracts.ChatEventMessage
|
||||||
|
import kotlinx.coroutines.flow.toList
|
||||||
|
|
||||||
|
typealias EventMessageToEventMapper<T> = suspend ChatEventMessage<T>.() -> T?
|
||||||
|
|
||||||
|
private suspend fun <O> BehaviourContext.waitEventMessages(
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
count: Int = 1,
|
||||||
|
mapper: suspend ChatEventMessage<ChatEvent>.() -> O?
|
||||||
|
): List<O> = expectFlow(
|
||||||
|
initRequest,
|
||||||
|
count,
|
||||||
|
errorFactory
|
||||||
|
) {
|
||||||
|
it.asMessageUpdate() ?.data ?.asChatEventMessage() ?.mapper().let(::listOfNotNull)
|
||||||
|
}.toList().toList()
|
||||||
|
|
||||||
|
|
||||||
|
private suspend inline fun <reified T : ChatEvent> BehaviourContext.waitEvents(
|
||||||
|
count: Int = 1,
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
noinline errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
noinline filter: EventMessageToEventMapper<T>? = null
|
||||||
|
) : List<T> = waitEventMessages<T>(
|
||||||
|
initRequest,
|
||||||
|
errorFactory,
|
||||||
|
count
|
||||||
|
) {
|
||||||
|
if (chatEvent is T) {
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
val message = (this as ChatEventMessage<T>)
|
||||||
|
if (filter == null) {
|
||||||
|
message.chatEvent
|
||||||
|
} else {
|
||||||
|
filter(message)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun BehaviourContext.waitChannelEvents(
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
count: Int = 1,
|
||||||
|
filter: EventMessageToEventMapper<ChannelEvent>? = null
|
||||||
|
) = waitEvents(count, initRequest, errorFactory, filter)
|
||||||
|
|
||||||
|
suspend fun BehaviourContext.waitChatEvents(
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
count: Int = 1,
|
||||||
|
filter: EventMessageToEventMapper<ChatEvent>? = null
|
||||||
|
) = waitEvents(count, initRequest, errorFactory, filter)
|
||||||
|
suspend fun BehaviourContext.waitCommonEvents(
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
count: Int = 1,
|
||||||
|
filter: EventMessageToEventMapper<CommonEvent>? = null
|
||||||
|
) = waitEvents(count, initRequest, errorFactory, filter)
|
||||||
|
suspend fun BehaviourContext.waitGroupEvents(
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
count: Int = 1,
|
||||||
|
filter: EventMessageToEventMapper<GroupEvent>? = null
|
||||||
|
) = waitEvents(count, initRequest, errorFactory, filter)
|
||||||
|
suspend fun BehaviourContext.waitSupergroupEvents(
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
count: Int = 1,
|
||||||
|
filter: EventMessageToEventMapper<SupergroupEvent>? = null
|
||||||
|
) = waitEvents(count, initRequest, errorFactory, filter)
|
||||||
|
|
||||||
|
suspend fun BehaviourContext.waitChannelChatCreatedEvents(
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
count: Int = 1,
|
||||||
|
filter: EventMessageToEventMapper<ChannelChatCreated>? = null
|
||||||
|
) = waitEvents(count, initRequest, errorFactory, filter)
|
||||||
|
suspend fun BehaviourContext.waitDeleteChatPhotoEvents(
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
count: Int = 1,
|
||||||
|
filter: EventMessageToEventMapper<DeleteChatPhoto>? = null
|
||||||
|
) = waitEvents(count, initRequest, errorFactory, filter)
|
||||||
|
suspend fun BehaviourContext.waitGroupChatCreatedEvents(
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
count: Int = 1,
|
||||||
|
filter: EventMessageToEventMapper<GroupChatCreated>? = null
|
||||||
|
) = waitEvents(count, initRequest, errorFactory, filter)
|
||||||
|
suspend fun BehaviourContext.waitLeftChatMemberEvents(
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
count: Int = 1,
|
||||||
|
filter: EventMessageToEventMapper<LeftChatMember>? = null
|
||||||
|
) = waitEvents(count, initRequest, errorFactory, filter)
|
||||||
|
suspend fun BehaviourContext.waitNewChatPhotoEvents(
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
count: Int = 1,
|
||||||
|
filter: EventMessageToEventMapper<NewChatPhoto>? = null
|
||||||
|
) = waitEvents(count, initRequest, errorFactory, filter)
|
||||||
|
suspend fun BehaviourContext.waitNewChatMembersEvents(
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
count: Int = 1,
|
||||||
|
filter: EventMessageToEventMapper<NewChatMembers>? = null
|
||||||
|
) = waitEvents(count, initRequest, errorFactory, filter)
|
||||||
|
suspend fun BehaviourContext.waitNewChatTitleEvents(
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
count: Int = 1,
|
||||||
|
filter: EventMessageToEventMapper<NewChatTitle>? = null
|
||||||
|
) = waitEvents(count, initRequest, errorFactory, filter)
|
||||||
|
suspend fun BehaviourContext.waitPinnedMessageEvents(
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
count: Int = 1,
|
||||||
|
filter: EventMessageToEventMapper<PinnedMessage>? = null
|
||||||
|
) = waitEvents(count, initRequest, errorFactory, filter)
|
||||||
|
suspend fun BehaviourContext.waitProximityAlertTriggeredEvents(
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
count: Int = 1,
|
||||||
|
filter: EventMessageToEventMapper<ProximityAlertTriggered>? = null
|
||||||
|
) = waitEvents(count, initRequest, errorFactory, filter)
|
||||||
|
suspend fun BehaviourContext.waitSupergroupChatCreatedEvents(
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
count: Int = 1,
|
||||||
|
filter: EventMessageToEventMapper<SupergroupChatCreated>? = null
|
||||||
|
) = waitEvents(count, initRequest, errorFactory, filter)
|
@ -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 <reified T : MediaGroupContent> BehaviourContext.onMediaGroup(
|
||||||
|
count: Int = 1,
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
noinline errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
noinline filter: (suspend (List<MediaGroupMessage>) -> 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<MediaGroupMessage>) -> Boolean)? = null
|
||||||
|
) = onMediaGroup<AudioMediaGroupContent>(count, initRequest, errorFactory, filter)
|
||||||
|
suspend fun BehaviourContext.waitDocumentsGroup(
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
count: Int = 1,
|
||||||
|
filter: (suspend (List<MediaGroupMessage>) -> Boolean)? = null
|
||||||
|
) = onMediaGroup<DocumentMediaGroupContent>(count, initRequest, errorFactory, filter)
|
||||||
|
suspend fun BehaviourContext.waitVisualGallery(
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
count: Int = 1,
|
||||||
|
filter: (suspend (List<MediaGroupMessage>) -> Boolean)? = null
|
||||||
|
) = onMediaGroup<VisualMediaGroupContent>(count, initRequest, errorFactory, filter)
|
||||||
|
suspend fun BehaviourContext.waitPhotoGallery(
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
count: Int = 1,
|
||||||
|
filter: (suspend (List<MediaGroupMessage>) -> Boolean)? = null
|
||||||
|
) = onMediaGroup<PhotoContent>(count, initRequest, errorFactory, filter)
|
||||||
|
suspend fun BehaviourContext.waitVideoGallery(
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
count: Int = 1,
|
||||||
|
filter: (suspend (List<MediaGroupMessage>) -> Boolean)? = null
|
||||||
|
) = onMediaGroup<VideoContent>(count, initRequest, errorFactory, filter)
|
@ -0,0 +1,91 @@
|
|||||||
|
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.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 <reified T : CallbackQuery> BehaviourContext.onCallbackQuery(
|
||||||
|
includeFilterByChatInBehaviourSubContext: Boolean = true,
|
||||||
|
noinline additionalFilter: (suspend (T) -> Boolean)? = null,
|
||||||
|
noinline scenarioReceiver: BehaviourContextAndTypeReceiver<Unit, T>
|
||||||
|
) = flowsUpdatesFilter.expectFlow(bot) {
|
||||||
|
it.asCallbackQueryUpdate() ?.data ?.let { query ->
|
||||||
|
if (query is T) {
|
||||||
|
if (additionalFilter == null || additionalFilter(query)) query else null
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}.let(::listOfNotNull)
|
||||||
|
}.subscribeSafelyWithoutExceptions(scope) { triggerQuery ->
|
||||||
|
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 == triggerQuery.user.id.chatId
|
||||||
|
}.subscribeSafelyWithoutExceptions(scope, subFilter.asUpdateReceiver) to subBehaviourContext
|
||||||
|
} else {
|
||||||
|
null to this
|
||||||
|
}
|
||||||
|
safelyWithoutExceptions { scenario.scenarioReceiver(triggerQuery) }
|
||||||
|
jobToCancel ?.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
suspend fun BehaviourContext.onDataCallbackQuery(
|
||||||
|
includeFilterByChatInBehaviourSubContext: Boolean = true,
|
||||||
|
additionalFilter: (suspend (DataCallbackQuery) -> Boolean)? = null,
|
||||||
|
scenarioReceiver: BehaviourContextAndTypeReceiver<Unit, DataCallbackQuery>
|
||||||
|
) = onCallbackQuery(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver)
|
||||||
|
|
||||||
|
suspend fun BehaviourContext.onGameShortNameCallbackQuery(
|
||||||
|
includeFilterByChatInBehaviourSubContext: Boolean = true,
|
||||||
|
additionalFilter: (suspend (GameShortNameCallbackQuery) -> Boolean)? = null,
|
||||||
|
scenarioReceiver: BehaviourContextAndTypeReceiver<Unit, GameShortNameCallbackQuery>
|
||||||
|
) = onCallbackQuery(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver)
|
||||||
|
suspend fun BehaviourContext.onInlineMessageIdCallbackQuery(
|
||||||
|
includeFilterByChatInBehaviourSubContext: Boolean = true,
|
||||||
|
additionalFilter: (suspend (InlineMessageIdCallbackQuery) -> Boolean)? = null,
|
||||||
|
scenarioReceiver: BehaviourContextAndTypeReceiver<Unit, InlineMessageIdCallbackQuery>
|
||||||
|
) = onCallbackQuery(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver)
|
||||||
|
suspend fun BehaviourContext.onInlineMessageIdDataCallbackQuery(
|
||||||
|
includeFilterByChatInBehaviourSubContext: Boolean = true,
|
||||||
|
additionalFilter: (suspend (InlineMessageIdDataCallbackQuery) -> Boolean)? = null,
|
||||||
|
scenarioReceiver: BehaviourContextAndTypeReceiver<Unit, InlineMessageIdDataCallbackQuery>
|
||||||
|
) = onCallbackQuery(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver)
|
||||||
|
suspend fun BehaviourContext.onInlineMessageIdGameShortNameCallbackQuery(
|
||||||
|
includeFilterByChatInBehaviourSubContext: Boolean = true,
|
||||||
|
additionalFilter: (suspend (InlineMessageIdGameShortNameCallbackQuery) -> Boolean)? = null,
|
||||||
|
scenarioReceiver: BehaviourContextAndTypeReceiver<Unit, InlineMessageIdGameShortNameCallbackQuery>
|
||||||
|
) = onCallbackQuery(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver)
|
||||||
|
suspend fun BehaviourContext.onMessageCallbackQuery(
|
||||||
|
includeFilterByChatInBehaviourSubContext: Boolean = true,
|
||||||
|
additionalFilter: (suspend (MessageCallbackQuery) -> Boolean)? = null,
|
||||||
|
scenarioReceiver: BehaviourContextAndTypeReceiver<Unit, MessageCallbackQuery>
|
||||||
|
) = onCallbackQuery(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver)
|
||||||
|
suspend fun BehaviourContext.onMessageDataCallbackQuery(
|
||||||
|
includeFilterByChatInBehaviourSubContext: Boolean = true,
|
||||||
|
additionalFilter: (suspend (MessageDataCallbackQuery) -> Boolean)? = null,
|
||||||
|
scenarioReceiver: BehaviourContextAndTypeReceiver<Unit, MessageDataCallbackQuery>
|
||||||
|
) = onCallbackQuery(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver)
|
||||||
|
suspend fun BehaviourContext.onMessageGameShortNameCallbackQuery(
|
||||||
|
includeFilterByChatInBehaviourSubContext: Boolean = true,
|
||||||
|
additionalFilter: (suspend (MessageGameShortNameCallbackQuery) -> Boolean)? = null,
|
||||||
|
scenarioReceiver: BehaviourContextAndTypeReceiver<Unit, MessageGameShortNameCallbackQuery>
|
||||||
|
) = onCallbackQuery(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver)
|
||||||
|
suspend fun BehaviourContext.onUnknownCallbackQueryType(
|
||||||
|
includeFilterByChatInBehaviourSubContext: Boolean = true,
|
||||||
|
additionalFilter: (suspend (UnknownCallbackQueryType) -> Boolean)? = null,
|
||||||
|
scenarioReceiver: BehaviourContextAndTypeReceiver<Unit, UnknownCallbackQueryType>
|
||||||
|
) = onCallbackQuery(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver)
|
@ -0,0 +1,35 @@
|
|||||||
|
package dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling
|
||||||
|
|
||||||
|
import dev.inmo.tgbotapi.CommonAbstracts.textSources
|
||||||
|
import dev.inmo.tgbotapi.extensions.behaviour_builder.*
|
||||||
|
import dev.inmo.tgbotapi.extensions.utils.*
|
||||||
|
import dev.inmo.tgbotapi.types.message.abstracts.CommonMessage
|
||||||
|
import dev.inmo.tgbotapi.types.message.content.TextContent
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
|
||||||
|
suspend fun BehaviourContext.command(
|
||||||
|
commandRegex: Regex,
|
||||||
|
requireOnlyCommandInMessage: Boolean = true,
|
||||||
|
includeFilterByChatInBehaviourSubContext: Boolean = true,
|
||||||
|
scenarioReceiver: BehaviourContextAndTypeReceiver<Unit, CommonMessage<TextContent>>
|
||||||
|
): Job = onText(
|
||||||
|
includeFilterByChatInBehaviourSubContext,
|
||||||
|
{ message ->
|
||||||
|
val content = message.content
|
||||||
|
val textSources = content.textSources
|
||||||
|
val sizeRequirement = if (requireOnlyCommandInMessage) {
|
||||||
|
textSources.size == 1
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
sizeRequirement && textSources.any { commandRegex.matches(it.asBotCommandTextSource() ?.command ?: return@any false) }
|
||||||
|
},
|
||||||
|
scenarioReceiver
|
||||||
|
)
|
||||||
|
|
||||||
|
suspend inline fun BehaviourContext.onCommand(
|
||||||
|
commandRegex: Regex,
|
||||||
|
requireOnlyCommandInMessage: Boolean = true,
|
||||||
|
includeFilterByChatInBehaviourSubContext: Boolean = true,
|
||||||
|
noinline scenarioReceiver: BehaviourContextAndTypeReceiver<Unit, CommonMessage<TextContent>>
|
||||||
|
): Job = command(commandRegex, requireOnlyCommandInMessage, includeFilterByChatInBehaviourSubContext, scenarioReceiver)
|
@ -0,0 +1,186 @@
|
|||||||
|
@file:Suppress("unused", "UNCHECKED_CAST")
|
||||||
|
|
||||||
|
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.types.files.abstracts.TelegramMediaFile
|
||||||
|
import dev.inmo.tgbotapi.types.message.abstracts.CommonMessage
|
||||||
|
import dev.inmo.tgbotapi.types.message.content.*
|
||||||
|
import dev.inmo.tgbotapi.types.message.content.abstracts.*
|
||||||
|
import dev.inmo.tgbotapi.types.message.content.media.*
|
||||||
|
import dev.inmo.tgbotapi.types.message.payments.InvoiceContent
|
||||||
|
import dev.inmo.tgbotapi.updateshandlers.FlowsUpdatesFilter
|
||||||
|
import dev.inmo.tgbotapi.utils.PreviewFeature
|
||||||
|
import kotlinx.coroutines.flow.filter
|
||||||
|
|
||||||
|
typealias CommonMessageFilter<T> = (suspend (CommonMessage<T>) -> Boolean)
|
||||||
|
|
||||||
|
@PreviewFeature
|
||||||
|
internal suspend inline fun <reified T : MessageContent> BehaviourContext.onContent(
|
||||||
|
includeFilterByChatInBehaviourSubContext: Boolean = true,
|
||||||
|
includeMediaGroups: Boolean = true,
|
||||||
|
noinline additionalFilter: CommonMessageFilter<T>? = null,
|
||||||
|
noinline scenarioReceiver: BehaviourContextAndTypeReceiver<Unit, CommonMessage<T>>
|
||||||
|
) = flowsUpdatesFilter.expectFlow(bot) {
|
||||||
|
if (includeMediaGroups) {
|
||||||
|
it.asSentMediaGroupUpdate() ?.data ?.mapNotNull {
|
||||||
|
if (it.content is T) {
|
||||||
|
val adaptedMessage = it as CommonMessage<T>
|
||||||
|
if (additionalFilter == null || additionalFilter(adaptedMessage)) adaptedMessage else null
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
} ?.let {
|
||||||
|
return@expectFlow it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
it.asMessageUpdate() ?.data ?.asCommonMessage() ?.let { message ->
|
||||||
|
if (message.content is T) {
|
||||||
|
val adaptedMessage = message as CommonMessage<T>
|
||||||
|
if (additionalFilter == null || additionalFilter(adaptedMessage)) adaptedMessage else null
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}.let(::listOfNotNull)
|
||||||
|
}.subscribeSafelyWithoutExceptions(scope) { triggerMessage ->
|
||||||
|
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 == triggerMessage.chat.id.chatId
|
||||||
|
}.subscribeSafelyWithoutExceptions(scope, subFilter.asUpdateReceiver) to subBehaviourContext
|
||||||
|
} else {
|
||||||
|
null to this
|
||||||
|
}
|
||||||
|
safelyWithoutExceptions { scenario.scenarioReceiver(triggerMessage) }
|
||||||
|
jobToCancel ?.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun BehaviourContext.onContact(
|
||||||
|
includeFilterByChatInBehaviourSubContext: Boolean = true,
|
||||||
|
additionalFilter: CommonMessageFilter<ContactContent>? = null,
|
||||||
|
scenarioReceiver: BehaviourContextAndTypeReceiver<Unit, CommonMessage<ContactContent>>
|
||||||
|
) = onContent(includeFilterByChatInBehaviourSubContext, false, additionalFilter, scenarioReceiver)
|
||||||
|
suspend fun BehaviourContext.onDice(
|
||||||
|
includeFilterByChatInBehaviourSubContext: Boolean = true,
|
||||||
|
additionalFilter: CommonMessageFilter<DiceContent>? = null,
|
||||||
|
scenarioReceiver: BehaviourContextAndTypeReceiver<Unit, CommonMessage<DiceContent>>
|
||||||
|
) = onContent(includeFilterByChatInBehaviourSubContext, false, additionalFilter, scenarioReceiver)
|
||||||
|
suspend fun BehaviourContext.onGame(
|
||||||
|
includeFilterByChatInBehaviourSubContext: Boolean = true,
|
||||||
|
additionalFilter: CommonMessageFilter<GameContent>? = null,
|
||||||
|
scenarioReceiver: BehaviourContextAndTypeReceiver<Unit, CommonMessage<GameContent>>
|
||||||
|
) = onContent(includeFilterByChatInBehaviourSubContext, false, additionalFilter, scenarioReceiver)
|
||||||
|
suspend fun BehaviourContext.onLocation(
|
||||||
|
includeFilterByChatInBehaviourSubContext: Boolean = true,
|
||||||
|
additionalFilter: CommonMessageFilter<LocationContent>? = null,
|
||||||
|
scenarioReceiver: BehaviourContextAndTypeReceiver<Unit, CommonMessage<LocationContent>>
|
||||||
|
) = onContent(includeFilterByChatInBehaviourSubContext, false, additionalFilter, scenarioReceiver)
|
||||||
|
suspend fun BehaviourContext.onPoll(
|
||||||
|
includeFilterByChatInBehaviourSubContext: Boolean = true,
|
||||||
|
additionalFilter: CommonMessageFilter<PollContent>? = null,
|
||||||
|
scenarioReceiver: BehaviourContextAndTypeReceiver<Unit, CommonMessage<PollContent>>
|
||||||
|
) = onContent(includeFilterByChatInBehaviourSubContext, false, additionalFilter, scenarioReceiver)
|
||||||
|
suspend fun BehaviourContext.onText(
|
||||||
|
includeFilterByChatInBehaviourSubContext: Boolean = true,
|
||||||
|
additionalFilter: CommonMessageFilter<TextContent>? = null,
|
||||||
|
scenarioReceiver: BehaviourContextAndTypeReceiver<Unit, CommonMessage<TextContent>>
|
||||||
|
) = onContent(includeFilterByChatInBehaviourSubContext, false, additionalFilter, scenarioReceiver)
|
||||||
|
suspend fun BehaviourContext.onVenue(
|
||||||
|
includeFilterByChatInBehaviourSubContext: Boolean = true,
|
||||||
|
additionalFilter: CommonMessageFilter<VenueContent>? = null,
|
||||||
|
scenarioReceiver: BehaviourContextAndTypeReceiver<Unit, CommonMessage<VenueContent>>
|
||||||
|
) = onContent(includeFilterByChatInBehaviourSubContext, false, additionalFilter, scenarioReceiver)
|
||||||
|
suspend fun BehaviourContext.onAudioMediaGroup(
|
||||||
|
includeFilterByChatInBehaviourSubContext: Boolean = true,
|
||||||
|
additionalFilter: CommonMessageFilter<AudioMediaGroupContent>? = null,
|
||||||
|
scenarioReceiver: BehaviourContextAndTypeReceiver<Unit, CommonMessage<AudioMediaGroupContent>>
|
||||||
|
) = onContent(includeFilterByChatInBehaviourSubContext, true, additionalFilter, scenarioReceiver)
|
||||||
|
suspend fun BehaviourContext.onDocumentMediaGroup(
|
||||||
|
includeFilterByChatInBehaviourSubContext: Boolean = true,
|
||||||
|
includeMediaGroups: Boolean = true,
|
||||||
|
additionalFilter: CommonMessageFilter<DocumentMediaGroupContent>? = null,
|
||||||
|
scenarioReceiver: BehaviourContextAndTypeReceiver<Unit, CommonMessage<DocumentMediaGroupContent>>
|
||||||
|
) = onContent(includeFilterByChatInBehaviourSubContext, includeMediaGroups, additionalFilter, scenarioReceiver)
|
||||||
|
suspend fun BehaviourContext.onMediaCollection(
|
||||||
|
includeFilterByChatInBehaviourSubContext: Boolean = true,
|
||||||
|
includeMediaGroups: Boolean = true,
|
||||||
|
additionalFilter: (suspend (CommonMessage<MediaCollectionContent<TelegramMediaFile>>) -> Boolean)? = null,
|
||||||
|
scenarioReceiver: BehaviourContextAndTypeReceiver<Unit, CommonMessage<MediaCollectionContent<TelegramMediaFile>>>
|
||||||
|
) = onContent(includeFilterByChatInBehaviourSubContext, includeMediaGroups, additionalFilter, scenarioReceiver)
|
||||||
|
suspend fun BehaviourContext.onMedia(
|
||||||
|
includeFilterByChatInBehaviourSubContext: Boolean = true,
|
||||||
|
includeMediaGroups: Boolean = true,
|
||||||
|
additionalFilter: CommonMessageFilter<MediaContent>? = null,
|
||||||
|
scenarioReceiver: BehaviourContextAndTypeReceiver<Unit, CommonMessage<MediaContent>>
|
||||||
|
) = onContent(includeFilterByChatInBehaviourSubContext, includeMediaGroups, additionalFilter, scenarioReceiver)
|
||||||
|
suspend fun BehaviourContext.onMediaGroup(
|
||||||
|
includeFilterByChatInBehaviourSubContext: Boolean = true,
|
||||||
|
includeMediaGroups: Boolean = true,
|
||||||
|
additionalFilter: CommonMessageFilter<MediaGroupContent>? = null,
|
||||||
|
scenarioReceiver: BehaviourContextAndTypeReceiver<Unit, CommonMessage<MediaGroupContent>>
|
||||||
|
) = onContent(includeFilterByChatInBehaviourSubContext, includeMediaGroups, additionalFilter, scenarioReceiver)
|
||||||
|
suspend fun BehaviourContext.onVisualMediaGroup(
|
||||||
|
includeFilterByChatInBehaviourSubContext: Boolean = true,
|
||||||
|
includeMediaGroups: Boolean = true,
|
||||||
|
additionalFilter: CommonMessageFilter<VisualMediaGroupContent>? = null,
|
||||||
|
scenarioReceiver: BehaviourContextAndTypeReceiver<Unit, CommonMessage<VisualMediaGroupContent>>
|
||||||
|
) = onContent(includeFilterByChatInBehaviourSubContext, includeMediaGroups, additionalFilter, scenarioReceiver)
|
||||||
|
suspend fun BehaviourContext.onAnimation(
|
||||||
|
includeFilterByChatInBehaviourSubContext: Boolean = true,
|
||||||
|
additionalFilter: CommonMessageFilter<AnimationContent>? = null,
|
||||||
|
scenarioReceiver: BehaviourContextAndTypeReceiver<Unit, CommonMessage<AnimationContent>>
|
||||||
|
) = onContent(includeFilterByChatInBehaviourSubContext, false, additionalFilter, scenarioReceiver)
|
||||||
|
suspend fun BehaviourContext.onAudio(
|
||||||
|
includeFilterByChatInBehaviourSubContext: Boolean = true,
|
||||||
|
includeMediaGroups: Boolean = true,
|
||||||
|
additionalFilter: CommonMessageFilter<AudioContent>? = null,
|
||||||
|
scenarioReceiver: BehaviourContextAndTypeReceiver<Unit, CommonMessage<AudioContent>>
|
||||||
|
) = onContent(includeFilterByChatInBehaviourSubContext, includeMediaGroups, additionalFilter, scenarioReceiver)
|
||||||
|
suspend fun BehaviourContext.onDocument(
|
||||||
|
includeFilterByChatInBehaviourSubContext: Boolean = true,
|
||||||
|
includeMediaGroups: Boolean = true,
|
||||||
|
additionalFilter: CommonMessageFilter<DocumentContent>? = null,
|
||||||
|
scenarioReceiver: BehaviourContextAndTypeReceiver<Unit, CommonMessage<DocumentContent>>
|
||||||
|
) = onContent(includeFilterByChatInBehaviourSubContext, includeMediaGroups, additionalFilter, scenarioReceiver)
|
||||||
|
suspend fun BehaviourContext.onPhoto(
|
||||||
|
includeFilterByChatInBehaviourSubContext: Boolean = true,
|
||||||
|
includeMediaGroups: Boolean = true,
|
||||||
|
additionalFilter: CommonMessageFilter<PhotoContent>? = null,
|
||||||
|
scenarioReceiver: BehaviourContextAndTypeReceiver<Unit, CommonMessage<PhotoContent>>
|
||||||
|
) = onContent(includeFilterByChatInBehaviourSubContext, includeMediaGroups, additionalFilter, scenarioReceiver)
|
||||||
|
suspend fun BehaviourContext.onSticker(
|
||||||
|
includeFilterByChatInBehaviourSubContext: Boolean = true,
|
||||||
|
additionalFilter: CommonMessageFilter<StickerContent>? = null,
|
||||||
|
scenarioReceiver: BehaviourContextAndTypeReceiver<Unit, CommonMessage<StickerContent>>
|
||||||
|
) = onContent(includeFilterByChatInBehaviourSubContext, false, additionalFilter, scenarioReceiver)
|
||||||
|
suspend fun BehaviourContext.onVideo(
|
||||||
|
includeFilterByChatInBehaviourSubContext: Boolean = true,
|
||||||
|
includeMediaGroups: Boolean = true,
|
||||||
|
additionalFilter: CommonMessageFilter<VideoContent>? = null,
|
||||||
|
scenarioReceiver: BehaviourContextAndTypeReceiver<Unit, CommonMessage<VideoContent>>
|
||||||
|
) = onContent(includeFilterByChatInBehaviourSubContext, includeMediaGroups, additionalFilter, scenarioReceiver)
|
||||||
|
suspend fun BehaviourContext.onVideoNote(
|
||||||
|
includeFilterByChatInBehaviourSubContext: Boolean = true,
|
||||||
|
additionalFilter: CommonMessageFilter<VideoNoteContent>? = null,
|
||||||
|
scenarioReceiver: BehaviourContextAndTypeReceiver<Unit, CommonMessage<VideoNoteContent>>
|
||||||
|
) = onContent(includeFilterByChatInBehaviourSubContext, false, additionalFilter, scenarioReceiver)
|
||||||
|
suspend fun BehaviourContext.onVoice(
|
||||||
|
includeFilterByChatInBehaviourSubContext: Boolean = true,
|
||||||
|
additionalFilter: CommonMessageFilter<VoiceContent>? = null,
|
||||||
|
scenarioReceiver: BehaviourContextAndTypeReceiver<Unit, CommonMessage<VoiceContent>>
|
||||||
|
) = onContent(includeFilterByChatInBehaviourSubContext, false, additionalFilter, scenarioReceiver)
|
||||||
|
suspend fun BehaviourContext.onInvoice(
|
||||||
|
includeFilterByChatInBehaviourSubContext: Boolean = true,
|
||||||
|
additionalFilter: CommonMessageFilter<InvoiceContent>? = null,
|
||||||
|
scenarioReceiver: BehaviourContextAndTypeReceiver<Unit, CommonMessage<InvoiceContent>>
|
||||||
|
) = onContent(includeFilterByChatInBehaviourSubContext, false, additionalFilter, scenarioReceiver)
|
@ -0,0 +1,124 @@
|
|||||||
|
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.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.*
|
||||||
|
import dev.inmo.tgbotapi.types.message.content.abstracts.*
|
||||||
|
import dev.inmo.tgbotapi.types.message.content.media.*
|
||||||
|
import dev.inmo.tgbotapi.updateshandlers.FlowsUpdatesFilter
|
||||||
|
import kotlinx.coroutines.flow.filter
|
||||||
|
|
||||||
|
internal suspend inline fun <reified T : ChatEvent> BehaviourContext.onEvent(
|
||||||
|
includeFilterByChatInBehaviourSubContext: Boolean = true,
|
||||||
|
noinline additionalFilter: (suspend (ChatEventMessage<T>) -> Boolean)? = null,
|
||||||
|
noinline scenarioReceiver: BehaviourContextAndTypeReceiver<Unit, ChatEventMessage<T>>
|
||||||
|
) = flowsUpdatesFilter.expectFlow(bot) {
|
||||||
|
it.asMessageUpdate() ?.data ?.asChatEventMessage() ?.let { message ->
|
||||||
|
if (message.chatEvent is T) {
|
||||||
|
val adaptedMessage = message as ChatEventMessage<T>
|
||||||
|
if (additionalFilter == null || additionalFilter(adaptedMessage)) adaptedMessage else null
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}.let(::listOfNotNull)
|
||||||
|
}.subscribeSafelyWithoutExceptions(scope) { triggerMessage ->
|
||||||
|
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 == triggerMessage.chat.id.chatId
|
||||||
|
}.subscribeSafelyWithoutExceptions(scope, subFilter.asUpdateReceiver) to subBehaviourContext
|
||||||
|
} else {
|
||||||
|
null to this
|
||||||
|
}
|
||||||
|
safelyWithoutExceptions { scenario.scenarioReceiver(triggerMessage) }
|
||||||
|
jobToCancel ?.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun BehaviourContext.onChannelEvent(
|
||||||
|
includeFilterByChatInBehaviourSubContext: Boolean = true,
|
||||||
|
additionalFilter: (suspend (ChatEventMessage<ChannelEvent>) -> Boolean)? = null,
|
||||||
|
scenarioReceiver: BehaviourContextAndTypeReceiver<Unit, ChatEventMessage<ChannelEvent>>
|
||||||
|
) = onEvent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver)
|
||||||
|
suspend fun BehaviourContext.onChatEvent(
|
||||||
|
includeFilterByChatInBehaviourSubContext: Boolean = true,
|
||||||
|
additionalFilter: (suspend (ChatEventMessage<ChatEvent>) -> Boolean)? = null,
|
||||||
|
scenarioReceiver: BehaviourContextAndTypeReceiver<Unit, ChatEventMessage<ChatEvent>>
|
||||||
|
) = onEvent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver)
|
||||||
|
suspend fun BehaviourContext.onCommonEvent(
|
||||||
|
includeFilterByChatInBehaviourSubContext: Boolean = true,
|
||||||
|
additionalFilter: (suspend (ChatEventMessage<CommonEvent>) -> Boolean)? = null,
|
||||||
|
scenarioReceiver: BehaviourContextAndTypeReceiver<Unit, ChatEventMessage<CommonEvent>>
|
||||||
|
) = onEvent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver)
|
||||||
|
suspend fun BehaviourContext.onGroupEvent(
|
||||||
|
includeFilterByChatInBehaviourSubContext: Boolean = true,
|
||||||
|
additionalFilter: (suspend (ChatEventMessage<GroupEvent>) -> Boolean)? = null,
|
||||||
|
scenarioReceiver: BehaviourContextAndTypeReceiver<Unit, ChatEventMessage<GroupEvent>>
|
||||||
|
) = onEvent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver)
|
||||||
|
suspend fun BehaviourContext.onSupergroupEvent(
|
||||||
|
includeFilterByChatInBehaviourSubContext: Boolean = true,
|
||||||
|
additionalFilter: (suspend (ChatEventMessage<SupergroupEvent>) -> Boolean)? = null,
|
||||||
|
scenarioReceiver: BehaviourContextAndTypeReceiver<Unit, ChatEventMessage<SupergroupEvent>>
|
||||||
|
) = onEvent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver)
|
||||||
|
|
||||||
|
suspend fun BehaviourContext.onChannelChatCreated(
|
||||||
|
includeFilterByChatInBehaviourSubContext: Boolean = true,
|
||||||
|
additionalFilter: (suspend (ChatEventMessage<ChannelChatCreated>) -> Boolean)? = null,
|
||||||
|
scenarioReceiver: BehaviourContextAndTypeReceiver<Unit, ChatEventMessage<ChannelChatCreated>>
|
||||||
|
) = onEvent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver)
|
||||||
|
suspend fun BehaviourContext.onDeleteChatPhoto(
|
||||||
|
includeFilterByChatInBehaviourSubContext: Boolean = true,
|
||||||
|
additionalFilter: (suspend (ChatEventMessage<DeleteChatPhoto>) -> Boolean)? = null,
|
||||||
|
scenarioReceiver: BehaviourContextAndTypeReceiver<Unit, ChatEventMessage<DeleteChatPhoto>>
|
||||||
|
) = onEvent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver)
|
||||||
|
suspend fun BehaviourContext.onGroupChatCreated(
|
||||||
|
includeFilterByChatInBehaviourSubContext: Boolean = true,
|
||||||
|
additionalFilter: (suspend (ChatEventMessage<GroupChatCreated>) -> Boolean)? = null,
|
||||||
|
scenarioReceiver: BehaviourContextAndTypeReceiver<Unit, ChatEventMessage<GroupChatCreated>>
|
||||||
|
) = onEvent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver)
|
||||||
|
suspend fun BehaviourContext.onLeftChatMember(
|
||||||
|
includeFilterByChatInBehaviourSubContext: Boolean = true,
|
||||||
|
additionalFilter: (suspend (ChatEventMessage<LeftChatMember>) -> Boolean)? = null,
|
||||||
|
scenarioReceiver: BehaviourContextAndTypeReceiver<Unit, ChatEventMessage<LeftChatMember>>
|
||||||
|
) = onEvent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver)
|
||||||
|
suspend fun BehaviourContext.onNewChatMembers(
|
||||||
|
includeFilterByChatInBehaviourSubContext: Boolean = true,
|
||||||
|
additionalFilter: (suspend (ChatEventMessage<NewChatMembers>) -> Boolean)? = null,
|
||||||
|
scenarioReceiver: BehaviourContextAndTypeReceiver<Unit, ChatEventMessage<NewChatMembers>>
|
||||||
|
) = onEvent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver)
|
||||||
|
suspend fun BehaviourContext.onNewChatPhoto(
|
||||||
|
includeFilterByChatInBehaviourSubContext: Boolean = true,
|
||||||
|
additionalFilter: (suspend (ChatEventMessage<NewChatPhoto>) -> Boolean)? = null,
|
||||||
|
scenarioReceiver: BehaviourContextAndTypeReceiver<Unit, ChatEventMessage<NewChatPhoto>>
|
||||||
|
) = onEvent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver)
|
||||||
|
suspend fun BehaviourContext.onNewChatTitle(
|
||||||
|
includeFilterByChatInBehaviourSubContext: Boolean = true,
|
||||||
|
additionalFilter: (suspend (ChatEventMessage<NewChatTitle>) -> Boolean)? = null,
|
||||||
|
scenarioReceiver: BehaviourContextAndTypeReceiver<Unit, ChatEventMessage<NewChatTitle>>
|
||||||
|
) = onEvent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver)
|
||||||
|
suspend fun BehaviourContext.onPinnedMessage(
|
||||||
|
includeFilterByChatInBehaviourSubContext: Boolean = true,
|
||||||
|
additionalFilter: (suspend (ChatEventMessage<PinnedMessage>) -> Boolean)? = null,
|
||||||
|
scenarioReceiver: BehaviourContextAndTypeReceiver<Unit, ChatEventMessage<PinnedMessage>>
|
||||||
|
) = onEvent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver)
|
||||||
|
suspend fun BehaviourContext.onProximityAlertTriggered(
|
||||||
|
includeFilterByChatInBehaviourSubContext: Boolean = true,
|
||||||
|
additionalFilter: (suspend (ChatEventMessage<ProximityAlertTriggered>) -> Boolean)? = null,
|
||||||
|
scenarioReceiver: BehaviourContextAndTypeReceiver<Unit, ChatEventMessage<ProximityAlertTriggered>>
|
||||||
|
) = onEvent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver)
|
||||||
|
suspend fun BehaviourContext.onSupergroupChatCreated(
|
||||||
|
includeFilterByChatInBehaviourSubContext: Boolean = true,
|
||||||
|
additionalFilter: (suspend (ChatEventMessage<SupergroupChatCreated>) -> Boolean)? = null,
|
||||||
|
scenarioReceiver: BehaviourContextAndTypeReceiver<Unit, ChatEventMessage<SupergroupChatCreated>>
|
||||||
|
) = onEvent(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver)
|
@ -0,0 +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.CommonMessage
|
||||||
|
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 <reified T : MediaGroupContent> BehaviourContext.onMediaGroup(
|
||||||
|
includeFilterByChatInBehaviourSubContext: Boolean = true,
|
||||||
|
noinline additionalFilter: (suspend (List<MediaGroupMessage>) -> Boolean)? = null,
|
||||||
|
noinline scenarioReceiver: BehaviourContextAndTypeReceiver<Unit, List<MediaGroupMessage>>
|
||||||
|
) = 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<MediaGroupMessage>) -> Boolean)? = null,
|
||||||
|
scenarioReceiver: BehaviourContextAndTypeReceiver<Unit, List<MediaGroupMessage>>
|
||||||
|
) = onMediaGroup<AudioMediaGroupContent>(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver)
|
||||||
|
suspend fun BehaviourContext.onDocumentsGroup(
|
||||||
|
includeFilterByChatInBehaviourSubContext: Boolean = true,
|
||||||
|
additionalFilter: (suspend (List<MediaGroupMessage>) -> Boolean)? = null,
|
||||||
|
scenarioReceiver: BehaviourContextAndTypeReceiver<Unit, List<MediaGroupMessage>>
|
||||||
|
) = onMediaGroup<DocumentMediaGroupContent>(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver)
|
||||||
|
suspend fun BehaviourContext.onVisualGallery(
|
||||||
|
includeFilterByChatInBehaviourSubContext: Boolean = true,
|
||||||
|
additionalFilter: (suspend (List<MediaGroupMessage>) -> Boolean)? = null,
|
||||||
|
scenarioReceiver: BehaviourContextAndTypeReceiver<Unit, List<MediaGroupMessage>>
|
||||||
|
) = onMediaGroup<VisualMediaGroupContent>(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver)
|
||||||
|
suspend fun BehaviourContext.onPhotoGallery(
|
||||||
|
includeFilterByChatInBehaviourSubContext: Boolean = true,
|
||||||
|
additionalFilter: (suspend (List<MediaGroupMessage>) -> Boolean)? = null,
|
||||||
|
scenarioReceiver: BehaviourContextAndTypeReceiver<Unit, List<MediaGroupMessage>>
|
||||||
|
) = onMediaGroup<PhotoContent>(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver)
|
||||||
|
suspend fun BehaviourContext.onVideoGallery(
|
||||||
|
includeFilterByChatInBehaviourSubContext: Boolean = true,
|
||||||
|
additionalFilter: (suspend (List<MediaGroupMessage>) -> Boolean)? = null,
|
||||||
|
scenarioReceiver: BehaviourContextAndTypeReceiver<Unit, List<MediaGroupMessage>>
|
||||||
|
) = onMediaGroup<VideoContent>(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver)
|
||||||
|
|
@ -40,6 +40,48 @@ import dev.inmo.tgbotapi.types.update.*
|
|||||||
import dev.inmo.tgbotapi.types.update.MediaGroupUpdates.*
|
import dev.inmo.tgbotapi.types.update.MediaGroupUpdates.*
|
||||||
import dev.inmo.tgbotapi.types.update.abstracts.*
|
import dev.inmo.tgbotapi.types.update.abstracts.*
|
||||||
import dev.inmo.tgbotapi.utils.PreviewFeature
|
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
|
@PreviewFeature
|
||||||
inline fun Chat.asBot(): Bot? = this as? Bot
|
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
|
inline fun Poll.asUnknownPollType(): UnknownPollType? = this as? UnknownPollType
|
||||||
@PreviewFeature
|
@PreviewFeature
|
||||||
inline fun Poll.requireUnknownPollType(): UnknownPollType = this as UnknownPollType
|
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<TelegramMediaFile>? = this as? MediaCollectionContent<TelegramMediaFile>
|
||||||
|
@PreviewFeature
|
||||||
|
inline fun ResendableContent.requireMediaCollectionContent(): MediaCollectionContent<TelegramMediaFile> = this as MediaCollectionContent<TelegramMediaFile>
|
||||||
|
@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
|
||||||
|
@ -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
|
||||||
|
}
|
@ -5,6 +5,7 @@ Concentration of all TelegramBotAPI libraries:
|
|||||||
* [TelegramBotAPI Core](../tgbotapi.core/README.md)
|
* [TelegramBotAPI Core](../tgbotapi.core/README.md)
|
||||||
* [TelegramBotAPI Extensions](../tgbotapi.extensions.api/README.md)
|
* [TelegramBotAPI Extensions](../tgbotapi.extensions.api/README.md)
|
||||||
* [TelegramBotAPI Util Extensions](../tgbotapi.extensions.utils/README.md)
|
* [TelegramBotAPI Util Extensions](../tgbotapi.extensions.utils/README.md)
|
||||||
|
* [TelegramBotAPI Behaviour Builder Extensions](../tgbotapi.extensions.behaviour_builder/README.md)
|
||||||
|
|
||||||
## Implementation
|
## Implementation
|
||||||
|
|
||||||
|
@ -42,6 +42,7 @@ kotlin {
|
|||||||
api project(":tgbotapi.core")
|
api project(":tgbotapi.core")
|
||||||
api project(":tgbotapi.extensions.api")
|
api project(":tgbotapi.extensions.api")
|
||||||
api project(":tgbotapi.extensions.utils")
|
api project(":tgbotapi.extensions.utils")
|
||||||
|
api project(":tgbotapi.extensions.behaviour_builder")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user