mirror of
https://github.com/InsanusMokrassar/TelegramBotAPI.git
synced 2025-12-02 04:15:43 +00:00
Compare commits
80 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4e8a9dcff0 | |||
| 10eb15e172 | |||
| 0320da7614 | |||
| 7aa3ff180e | |||
| a882a212c2 | |||
| 1b15748f65 | |||
| 044fe5eadf | |||
| 9453ec37e7 | |||
| 3d0cbc2d2b | |||
| 198b551ebf | |||
| 1452e32293 | |||
| 946b7abcae | |||
| 879943622a | |||
| c0b4b523cf | |||
| 49e6e9cfe3 | |||
| ffadb6355b | |||
| 9cc402b42d | |||
| b9341f89ac | |||
| ac07f44c81 | |||
| 2e53247726 | |||
| e2dddf96a1 | |||
| ce0fceb240 | |||
| 633239961a | |||
| 8b79b15777 | |||
| a28cf5ddff | |||
| 8c2cffc8e3 | |||
| b933361258 | |||
| 383e722d07 | |||
| 3125c2fc1b | |||
| 965b8c3c50 | |||
| 94745ef373 | |||
| aee5ab564b | |||
| c70f0b65dd | |||
| 30e6f68228 | |||
| 00873a255c | |||
| 6bd423dc11 | |||
| c5ada8cea0 | |||
| 0cb3df4d1a | |||
| b22118b400 | |||
| 2006e45b57 | |||
| c091098feb | |||
| 6cf8d47cbf | |||
| 3dc4e9dda4 | |||
| 6407ad1a93 | |||
| f974e5787f | |||
| 28a9bbd310 | |||
| 599d5a51e3 | |||
| 25f8d15a4b | |||
| 66c2cb2d30 | |||
| 74fb448378 | |||
| 3417ec060f | |||
| 4f54a00003 | |||
| 4fb187da30 | |||
| 7637b6f69a | |||
| 9df9af193c | |||
| ba4b4c4b64 | |||
| fa0861b8bc | |||
| 20494e1d4a | |||
| a404008dee | |||
| 881205dd80 | |||
| 2096c44811 | |||
| 1a3da33589 | |||
| be28c9bd5d | |||
| a193ef5fd5 | |||
| 7c43d3aaa5 | |||
| e034afc75c | |||
| 08e3326d1a | |||
| 6dd1825b98 | |||
| bd4eb29fc1 | |||
| 2cc66ef13c | |||
| 9a8175d1c8 | |||
| 25285b2e8a | |||
| bb09f05d7b | |||
| da5e46e59f | |||
| a3f315a73a | |||
| 43583a885a | |||
| ec02257ecd | |||
| 29ee4a9396 | |||
| 2717cb4fc6 | |||
| 1ce2526401 |
74
CHANGELOG.md
74
CHANGELOG.md
@@ -1,5 +1,79 @@
|
||||
# TelegramBotAPI changelog
|
||||
|
||||
## 0.31.0
|
||||
|
||||
**THIS UPDATE CONTAINS BREAKING CHANGES**
|
||||
|
||||
* `Common`:
|
||||
* **ALL DEPRECATIONS CREATED SINCE 0.30.0 WERE REMOVED**
|
||||
* `Behaviour Builder`:
|
||||
* Extension `TelegramBot#buildBehaviour` have changed its return value: now it is `Job` instead of
|
||||
`FlowsUpdatesFilter`
|
||||
* `Utils`
|
||||
* New extensions `TelegramBot#longPolling` were added as new recommended way to start getting updates via long
|
||||
polling
|
||||
* Old extensions `RequestsExecutor#startGettingFlowsUpdatesByLongPolling` has been deprecated
|
||||
|
||||
## 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
|
||||
|
||||
* `Utils`:
|
||||
* Class casts has been added. Now you can write something like `message.asGroupMessage() ?.let { ... }` instead of
|
||||
`(message as? GroupMessage<*>) ?.let { ... }`
|
||||
|
||||
## 0.30.11
|
||||
|
||||
* `Common`:
|
||||
* `Version`:
|
||||
* `MicroUtils`: `0.4.11` -> `0.4.15`
|
||||
* `Klock`: `2.0.1` -> `2.0.3`
|
||||
* `Ktor`: `1.4.3` -> `1.5.0`
|
||||
* `Core`:
|
||||
* All bot actions got functions for short calling, like `recordVideo` for `RecordVideoNote`
|
||||
* All bot actions got class-cast shortcuts
|
||||
|
||||
## 0.30.10
|
||||
|
||||
* `Common`:
|
||||
* `Version`:
|
||||
* `Kotlin`: `1.4.20` -> `1.4.21`
|
||||
* `Klock`: `2.0.0` -> `2.0.1`
|
||||
* `Ktor`: `1.4.2` -> `1.4.3`
|
||||
* `MicroUtils`: `0.4.6` -> `0.4.11`
|
||||
* `API Extensions`:
|
||||
* New function `buildBot`
|
||||
|
||||
## 0.30.9
|
||||
|
||||
* `Common`:
|
||||
* `Version`:
|
||||
* `UUID`: `0.2.2` -> `0.2.3`
|
||||
* `Coroutines`: `1.4.1` -> `1.4.2`
|
||||
* `MicroUtils`: `0.4.3` -> `0.4.6`
|
||||
* `Core`:
|
||||
* Add `BowlingDiceAnimationType`
|
||||
|
||||
## 0.30.8
|
||||
|
||||
* `Common`:
|
||||
* `Version`:
|
||||
* `Kotlin`: `1.4.10` -> `1.4.20`
|
||||
* `Klock`: `1.12.1` -> `2.0.0`
|
||||
* `MicroUtils`: `0.4.1` -> `0.4.3`
|
||||
|
||||
## 0.30.7
|
||||
|
||||
* `Common`:
|
||||
|
||||
16
README.md
16
README.md
@@ -3,11 +3,11 @@
|
||||
<details>
|
||||
<summary><b>I do not wanna read a lot, just give me my bot</b></summary>
|
||||
|
||||
You can simply use [this template](https://github.com/InsanusMokrassar/TelegramBotAPI-bot_template) (and button
|
||||
`Use template`) to get your copy of bot and start to code.
|
||||
|
||||
**P.S. Do not forget to look into our [minidocs](https://bookstack.inmo.dev/books/telegrambotapi/) and
|
||||
[kdocs](https://tgbotapi.inmo.dev/docs/index.html)**
|
||||
You can simply use <a href="https://github.com/InsanusMokrassar/TelegramBotAPI-bot_template">this template</a> (and button
|
||||
<a href="https://github.com/InsanusMokrassar/TelegramBotAPI-bot_template/generate">Use template</a>) to get your copy of bot and start to code.
|
||||
<p></p>
|
||||
<b>P.S. Do not forget to look into our <a href="https://bookstack.inmo.dev/books/telegrambotapi/">minidocs</a> and
|
||||
<a href="https://tgbotapi.inmo.dev/docs/index.html">kdocs</a></b>
|
||||
|
||||
</details>
|
||||
|
||||
@@ -15,8 +15,9 @@ You can simply use [this template](https://github.com/InsanusMokrassar/TelegramB
|
||||
| -------------------------------------:|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| Useful links | [](https://t.me/InMoTelegramBotAPI) [](https://github.com/InsanusMokrassar/TelegramBotAPI-bot_template/generate) [](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 | [](https://bintray.com/insanusmokrassar/TelegramBotAPI/tgbotapi.core/_latestVersion) [](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi.core) |
|
||||
| TelegramBotAPI Extensions status | [](https://bintray.com/insanusmokrassar/TelegramBotAPI/tgbotapi.extensions.api/_latestVersion) [](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi.extensions.api) |
|
||||
| TelegramBotAPI API Extensions status | [](https://bintray.com/insanusmokrassar/TelegramBotAPI/tgbotapi.extensions.api/_latestVersion) [](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi.extensions.api) |
|
||||
| TelegramBotAPI Util Extensions status | [](https://bintray.com/insanusmokrassar/TelegramBotAPI/tgbotapi.extensions.utils/_latestVersion) [](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi.extensions.utils) |
|
||||
| TelegramBotAPI Behaviour Builder Extensions status | [](https://bintray.com/insanusmokrassar/TelegramBotAPI/tgbotapi.extensions.behaviour_builder/_latestVersion) [](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi.extensions.behaviour_builder) |
|
||||
| TelegramBotAPI All status | [](https://bintray.com/insanusmokrassar/TelegramBotAPI/tgbotapi/_latestVersion) [](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
|
||||
@@ -34,6 +35,8 @@ the list of this complex currently next projects:
|
||||
`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
|
||||
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
|
||||
|
||||
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
|
||||
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 Util Extensions](tgbotapi.extensions.utils/README.md) or even
|
||||
[TelegramBotAPI Core](tgbotapi.core/README.md).
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0"?>
|
||||
<minder version="1.11.1">
|
||||
<minder version="1.11.3">
|
||||
<theme name="default" label="Default" index="-1"/>
|
||||
<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"/>
|
||||
@@ -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="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>
|
||||
<drawarea x="-320.56697591145837" y="-10.028254191080691" scale="0.75"/>
|
||||
<drawarea x="-950.47548925255796" y="-49.650554065281653" scale="0.5"/>
|
||||
<images/>
|
||||
<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"/>
|
||||
<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"/>
|
||||
</nodename>
|
||||
<nodenote></nodenote>
|
||||
<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"/>
|
||||
<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"/>
|
||||
</nodename>
|
||||
<nodenote></nodenote>
|
||||
<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"/>
|
||||
<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"/>
|
||||
</nodename>
|
||||
<nodenote></nodenote>
|
||||
</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"/>
|
||||
<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"/>
|
||||
</nodename>
|
||||
<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>
|
||||
</nodes>
|
||||
</node>
|
||||
</nodes>
|
||||
</node>
|
||||
<node id="4" posx="815.52319335937455" posy="948.04447937011719" width="329" height="213" side="top" fold="false" treesize="329" 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"/>
|
||||
<nodename posx="831.52319335937455" posy="964.04447937011719" maxwidth="394.3671875">
|
||||
<text data="tgbotapi Here included all available TelegramBotAPI libraries: * tgbotapi.core * tgbotapi.extensions.api * tgbotapi.extensions.utils">
|
||||
<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="430" nodeborderwidth="3" nodefill="false" nodemargin="11" nodepadding="5" nodefont="Roboto Mono 14" nodemarkup="true"/>
|
||||
<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 * tgbotapi.extensions.behaviour_builder">
|
||||
<color>
|
||||
<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="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="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>
|
||||
</text>
|
||||
</nodename>
|
||||
@@ -110,12 +291,17 @@
|
||||
</nodes>
|
||||
<groups/>
|
||||
<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"/>
|
||||
<title></title>
|
||||
<note></note>
|
||||
</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"/>
|
||||
<title></title>
|
||||
<note></note>
|
||||
|
||||
@@ -9,7 +9,6 @@ buildscript {
|
||||
dependencies {
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
|
||||
classpath "com.jfrog.bintray.gradle:gradle-bintray-plugin:$gradle_bintray_plugin_version"
|
||||
classpath "com.github.breadmoirai:github-release:$github_release_plugin_version"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
dokka_version=1.4.0
|
||||
dokka_version=1.4.20
|
||||
|
||||
org.gradle.jvmargs=-Xmx1024m
|
||||
|
||||
@@ -5,19 +5,18 @@ kotlin.js.generate.externals=true
|
||||
kotlin.incremental=true
|
||||
kotlin.incremental.js=true
|
||||
|
||||
kotlin_version=1.4.10
|
||||
kotlin_coroutines_version=1.4.1
|
||||
kotlin_version=1.4.21
|
||||
kotlin_coroutines_version=1.4.2
|
||||
kotlin_serialisation_runtime_version=1.0.1
|
||||
klock_version=1.12.1
|
||||
uuid_version=0.2.2
|
||||
ktor_version=1.4.2
|
||||
klock_version=2.0.3
|
||||
uuid_version=0.2.3
|
||||
ktor_version=1.5.0
|
||||
|
||||
micro_utils_version=0.4.1
|
||||
micro_utils_version=0.4.16
|
||||
|
||||
javax_activation_version=1.1.1
|
||||
|
||||
library_group=dev.inmo
|
||||
library_version=0.30.7
|
||||
library_version=0.31.0
|
||||
|
||||
gradle_bintray_plugin_version=1.8.5
|
||||
github_release_plugin_version=2.2.12
|
||||
|
||||
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8-bin.zip
|
||||
|
||||
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.extensions.api"
|
||||
include ":tgbotapi.extensions.utils"
|
||||
include ":tgbotapi.extensions.behaviour_builder"
|
||||
include ":tgbotapi"
|
||||
include ":docs"
|
||||
|
||||
@@ -8,7 +8,6 @@ buildscript {
|
||||
dependencies {
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
|
||||
classpath "com.jfrog.bintray.gradle:gradle-bintray-plugin:$gradle_bintray_plugin_version"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,59 +1,65 @@
|
||||
apply plugin: 'com.jfrog.bintray'
|
||||
apply plugin: 'maven-publish'
|
||||
|
||||
apply from: "maven.publish.gradle"
|
||||
|
||||
bintray {
|
||||
user = project.hasProperty('BINTRAY_USER') ? project.property('BINTRAY_USER') : System.getenv('BINTRAY_USER')
|
||||
key = project.hasProperty('BINTRAY_KEY') ? project.property('BINTRAY_KEY') : System.getenv('BINTRAY_KEY')
|
||||
filesSpec {
|
||||
from "${buildDir}/publications/"
|
||||
eachFile {
|
||||
String directorySubname = it.getFile().parentFile.name
|
||||
if (it.getName() == "module.json") {
|
||||
if (directorySubname == "kotlinMultiplatform") {
|
||||
it.setPath("${project.name}/${project.version}/${project.name}-${project.version}.module")
|
||||
} else {
|
||||
it.setPath("${project.name}-${directorySubname}/${project.version}/${project.name}-${directorySubname}-${project.version}.module")
|
||||
}
|
||||
} else {
|
||||
if (directorySubname == "kotlinMultiplatform" && it.getName() == "pom-default.xml") {
|
||||
it.setPath("${project.name}/${project.version}/${project.name}-${project.version}.pom")
|
||||
} else {
|
||||
it.exclude()
|
||||
}
|
||||
}
|
||||
}
|
||||
into "${project.group}".replace(".", "/")
|
||||
}
|
||||
|
||||
publish = true
|
||||
override = true
|
||||
|
||||
pkg {
|
||||
repo = "TelegramBotAPI"
|
||||
name = "${project.name}"
|
||||
vcsUrl = "https://github.com/InsanusMokrassar/TelegramBotAPI"
|
||||
licenses = ["Apache-2.0"]
|
||||
version {
|
||||
name = "${project.version}"
|
||||
released = new Date()
|
||||
vcsTag = "${project.version}"
|
||||
gpg {
|
||||
sign = true
|
||||
passphrase = project.hasProperty('signing.gnupg.passphrase') ? project.property('signing.gnupg.passphrase') : System.getenv('signing.gnupg.passphrase')
|
||||
}
|
||||
}
|
||||
}
|
||||
task javadocsJar(type: Jar) {
|
||||
classifier = 'javadoc'
|
||||
}
|
||||
|
||||
bintrayUpload.doFirst {
|
||||
publications = publishing.publications.collect {
|
||||
afterEvaluate {
|
||||
project.publishing.publications.all {
|
||||
// rename artifacts
|
||||
groupId "${project.group}"
|
||||
if (it.name.contains('kotlinMultiplatform')) {
|
||||
null
|
||||
artifactId = "${project.name}"
|
||||
} else {
|
||||
it.name
|
||||
artifactId = "${project.name}-$name"
|
||||
}
|
||||
} - null
|
||||
}
|
||||
}
|
||||
|
||||
bintrayUpload.dependsOn publishToMavenLocal
|
||||
publishing {
|
||||
publications.all {
|
||||
artifact javadocsJar
|
||||
|
||||
pom {
|
||||
description = "Library for Object-Oriented and type-safe work with Telegram Bot API"
|
||||
name = "Telegram Bot API Core"
|
||||
url = "https://insanusmokrassar.github.io/TelegramBotAPI"
|
||||
|
||||
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')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
package dev.inmo.tgbotapi.CommonAbstracts
|
||||
|
||||
import dev.inmo.tgbotapi.types.ParseMode.ParseMode
|
||||
import dev.inmo.tgbotapi.utils.internal.fullListOfSubSource
|
||||
|
||||
interface Captioned {
|
||||
val caption: String?
|
||||
@@ -13,8 +12,7 @@ interface CaptionedOutput : Captioned {
|
||||
|
||||
interface CaptionedInput : Captioned {
|
||||
/**
|
||||
* Not full list of entities. This list WILL NOT contain [TextPart]s with [dev.inmo.tgbotapi.types.MessageEntity.textsources.RegularTextSource]
|
||||
* @see [CaptionedInput.fullEntitiesList]
|
||||
* Full list of entities. This list WILL contain [TextPart]s with [dev.inmo.tgbotapi.types.MessageEntity.textsources.RegularTextSource]
|
||||
*/
|
||||
val captionEntities: List<TextPart>
|
||||
}
|
||||
@@ -25,10 +23,3 @@ interface CaptionedInput : Captioned {
|
||||
*/
|
||||
val CaptionedInput.textSources
|
||||
get() = captionEntities.justTextSources()
|
||||
|
||||
/**
|
||||
* Convert its [CaptionedInput.captionEntities] to list of [dev.inmo.tgbotapi.CommonAbstracts.TextSource]
|
||||
* with [dev.inmo.tgbotapi.types.MessageEntity.textsources.RegularTextSource]
|
||||
*/
|
||||
@Deprecated("Currently list of entities already full. This method is redundant")
|
||||
fun CaptionedInput.fullEntitiesList(): TextSourcesList = caption ?.fullListOfSubSource(captionEntities) ?.map { it.source } ?: emptyList()
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package dev.inmo.tgbotapi.CommonAbstracts
|
||||
|
||||
import dev.inmo.tgbotapi.types.ParseMode.ParseMode
|
||||
import dev.inmo.tgbotapi.utils.internal.fullListOfSubSource
|
||||
|
||||
interface Explained {
|
||||
val explanation: String?
|
||||
@@ -19,8 +18,7 @@ interface ExplainedOutput : ParsableExplainedOutput, EntitiesExplainedOutput
|
||||
|
||||
interface ExplainedInput : Explained {
|
||||
/**
|
||||
* Not full list of entities. This list WILL NOT contain [TextPart]s with [dev.inmo.tgbotapi.types.MessageEntity.textsources.RegularTextSource]
|
||||
* @see [ExplainedInput.fullEntitiesList]
|
||||
* Full list of entities. This list WILL contain [TextPart]s with [dev.inmo.tgbotapi.types.MessageEntity.textsources.RegularTextSource]
|
||||
*/
|
||||
val explanationEntities: List<TextPart>
|
||||
}
|
||||
@@ -31,10 +29,3 @@ interface ExplainedInput : Explained {
|
||||
*/
|
||||
val ExplainedInput.textSources
|
||||
get() = explanationEntities.justTextSources()
|
||||
|
||||
/**
|
||||
* Convert its [ExplainedInput.explanationEntities] to list of [dev.inmo.tgbotapi.CommonAbstracts.TextSource]
|
||||
* with [dev.inmo.tgbotapi.types.MessageEntity.textsources.RegularTextSource]
|
||||
*/
|
||||
@Deprecated("Currently list of entities already full. This method is redundant")
|
||||
fun ExplainedInput.fullEntitiesList(): TextSourcesList = explanation ?.fullListOfSubSource(explanationEntities) ?.map { it.source } ?: emptyList()
|
||||
|
||||
@@ -8,10 +8,6 @@ import dev.inmo.tgbotapi.types.textLength
|
||||
const val DirectInvocationOfTextSourceConstructor = "It is strongly not recommended to use constructors directly instead of factory methods"
|
||||
|
||||
typealias TextSourcesList = List<TextSource>
|
||||
@Deprecated("All lists of TextSource in public API now are full. So, this typealias is redundant")
|
||||
typealias FullTextSourcesList = List<TextSource>
|
||||
@Deprecated("All lists of TextPart in public API now are full. So, this typealias is redundant")
|
||||
typealias FullTextPartsList = List<TextPart>
|
||||
|
||||
interface TextSource {
|
||||
val markdown: String
|
||||
@@ -21,16 +17,6 @@ interface TextSource {
|
||||
|
||||
val asText: String
|
||||
get() = source
|
||||
|
||||
@Deprecated("Rename", ReplaceWith("markdown"))
|
||||
val asMarkdownSource: String
|
||||
get() = markdown
|
||||
@Deprecated("Rename", ReplaceWith("markdownV2"))
|
||||
val asMarkdownV2Source: String
|
||||
get() = markdownV2
|
||||
@Deprecated("Rename", ReplaceWith("html"))
|
||||
val asHtmlSource: String
|
||||
get() = html
|
||||
}
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
@@ -43,13 +29,7 @@ inline operator fun TextSource.plus(text: String) = listOf(this, regular(text))
|
||||
inline operator fun List<TextSource>.plus(text: String) = this + regular(text)
|
||||
|
||||
interface MultilevelTextSource : TextSource {
|
||||
@Deprecated("Will be removed in near major release")
|
||||
val textParts: List<TextPart>
|
||||
get() = textParts(0)
|
||||
val subsources: List<TextSource>
|
||||
@Deprecated("Will be removed in near major release", ReplaceWith("subsources"))
|
||||
val textSources: List<TextSource>
|
||||
get() = subsources
|
||||
}
|
||||
|
||||
data class TextPart(
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package dev.inmo.tgbotapi.CommonAbstracts
|
||||
|
||||
import dev.inmo.tgbotapi.types.ParseMode.ParseMode
|
||||
import dev.inmo.tgbotapi.utils.internal.fullListOfSubSource
|
||||
|
||||
interface Texted {
|
||||
val text: String?
|
||||
@@ -19,22 +18,18 @@ interface TextedOutput : ParsableOutput, EntitiesOutput
|
||||
|
||||
interface TextedInput : Texted {
|
||||
/**
|
||||
* Not full list of entities. This list WILL NOT contain [TextPart]s with [dev.inmo.tgbotapi.types.MessageEntity.textsources.RegularTextSource]
|
||||
* @see [CaptionedInput.fullEntitiesList]
|
||||
* 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
|
||||
*/
|
||||
val textEntities: List<TextPart>
|
||||
}
|
||||
|
||||
/**
|
||||
* Full list of [TextSource] built from source[TextedInput.textEntities]
|
||||
*
|
||||
* @see TextedInput.textEntities
|
||||
* @see justTextSources
|
||||
*/
|
||||
val TextedInput.textSources
|
||||
get() = textEntities.justTextSources()
|
||||
|
||||
/**
|
||||
* Convert its [TextedInput.textEntities] to list of [dev.inmo.tgbotapi.CommonAbstracts.TextSource]
|
||||
* with [dev.inmo.tgbotapi.types.MessageEntity.textsources.RegularTextSource]
|
||||
*/
|
||||
@Deprecated("Currently list of entities already full. This method is redundant")
|
||||
fun TextedInput.fullEntitiesList(): TextSourcesList = text ?.fullListOfSubSource(textEntities) ?.map { it.source } ?: emptyList()
|
||||
|
||||
@@ -5,7 +5,8 @@ import dev.inmo.tgbotapi.bot.BaseRequestsExecutor
|
||||
import dev.inmo.tgbotapi.bot.Ktor.base.*
|
||||
import dev.inmo.tgbotapi.bot.TelegramBot
|
||||
import dev.inmo.tgbotapi.bot.exceptions.newRequestException
|
||||
import dev.inmo.tgbotapi.bot.settings.limiters.*
|
||||
import dev.inmo.tgbotapi.bot.settings.limiters.ExceptionsOnlyLimiter
|
||||
import dev.inmo.tgbotapi.bot.settings.limiters.RequestLimiter
|
||||
import dev.inmo.tgbotapi.requests.abstracts.Request
|
||||
import dev.inmo.tgbotapi.types.Response
|
||||
import dev.inmo.tgbotapi.utils.*
|
||||
@@ -67,7 +68,7 @@ class KtorRequestsExecutor(
|
||||
return safely(
|
||||
{ e ->
|
||||
throw if (e is ClientRequestException) {
|
||||
val content = e.response ?.readText() ?: throw e
|
||||
val content = e.response.readText()
|
||||
val responseObject = jsonFormatter.decodeFromString(Response.serializer(), content)
|
||||
newRequestException(
|
||||
responseObject,
|
||||
|
||||
@@ -6,7 +6,6 @@ import dev.inmo.tgbotapi.bot.exceptions.newRequestException
|
||||
import dev.inmo.tgbotapi.requests.GetUpdates
|
||||
import dev.inmo.tgbotapi.requests.abstracts.Request
|
||||
import dev.inmo.tgbotapi.types.Response
|
||||
import dev.inmo.tgbotapi.types.RetryAfterError
|
||||
import dev.inmo.tgbotapi.utils.TelegramAPIUrlsKeeper
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.client.call.receive
|
||||
@@ -14,7 +13,6 @@ import io.ktor.client.features.timeout
|
||||
import io.ktor.client.request.*
|
||||
import io.ktor.client.statement.HttpResponse
|
||||
import io.ktor.http.ContentType
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlin.collections.set
|
||||
|
||||
|
||||
@@ -25,10 +25,9 @@ object MultipartRequestCallFactory : AbstractRequestCallFactory() {
|
||||
Headers.build {
|
||||
append(HttpHeaders.ContentType, value.mimeType)
|
||||
append(HttpHeaders.ContentDisposition, "filename=${value.fileId}")
|
||||
}
|
||||
) {
|
||||
value.file.asInput()
|
||||
}
|
||||
},
|
||||
block = value.file::input
|
||||
)
|
||||
is FileId -> append(key, value.fileId)
|
||||
else -> append(key, value.toString())
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
package dev.inmo.tgbotapi.bot.exceptions
|
||||
|
||||
import com.soywiz.klock.DateTime
|
||||
import dev.inmo.tgbotapi.types.*
|
||||
import dev.inmo.tgbotapi.types.Response
|
||||
import dev.inmo.tgbotapi.types.RetryAfterError
|
||||
import io.ktor.utils.io.errors.IOException
|
||||
|
||||
fun newRequestException(
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
package dev.inmo.tgbotapi.bot.settings.limiters
|
||||
|
||||
import com.soywiz.klock.DateTime
|
||||
import dev.inmo.micro_utils.coroutines.*
|
||||
import dev.inmo.tgbotapi.types.MilliSeconds
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.sync.Semaphore
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.Transient
|
||||
import kotlin.coroutines.Continuation
|
||||
import kotlin.math.roundToLong
|
||||
|
||||
private fun now(): Long = DateTime.nowUnixLong()
|
||||
|
||||
@@ -2,11 +2,13 @@ package dev.inmo.tgbotapi.bot.settings.limiters
|
||||
|
||||
import dev.inmo.micro_utils.coroutines.safely
|
||||
import dev.inmo.tgbotapi.bot.exceptions.TooMuchRequestsException
|
||||
import dev.inmo.tgbotapi.types.*
|
||||
import dev.inmo.tgbotapi.types.MilliSeconds
|
||||
import dev.inmo.tgbotapi.types.RetryAfterError
|
||||
import io.ktor.client.features.ClientRequestException
|
||||
import io.ktor.http.HttpStatusCode
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.first
|
||||
|
||||
/**
|
||||
* This limiter will limit requests only after getting a [RetryAfterError] or [ClientRequestException] with
|
||||
@@ -60,6 +62,3 @@ class ExceptionsOnlyLimiter(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated("Renamed", ReplaceWith("ExceptionsOnlyLimiter", "dev.inmo.tgbotapi.bot.settings.limiters.ExceptionsOnlyLimiter"))
|
||||
typealias EmptyLimiter = ExceptionsOnlyLimiter
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package dev.inmo.tgbotapi.bot.settings.limiters
|
||||
|
||||
import dev.inmo.micro_utils.coroutines.*
|
||||
import dev.inmo.micro_utils.coroutines.actor
|
||||
import dev.inmo.micro_utils.coroutines.safely
|
||||
import dev.inmo.tgbotapi.types.MilliSeconds
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.Transient
|
||||
import kotlin.coroutines.*
|
||||
|
||||
@@ -2,10 +2,7 @@ package dev.inmo.tgbotapi.requests.chat.modify
|
||||
|
||||
import dev.inmo.tgbotapi.CommonAbstracts.types.ChatRequest
|
||||
import dev.inmo.tgbotapi.requests.abstracts.SimpleRequest
|
||||
import dev.inmo.tgbotapi.types.ChatIdentifier
|
||||
import dev.inmo.tgbotapi.types.MessageIdentifier
|
||||
import dev.inmo.tgbotapi.types.chatIdField
|
||||
import dev.inmo.tgbotapi.types.messageIdField
|
||||
import dev.inmo.tgbotapi.types.*
|
||||
import kotlinx.serialization.*
|
||||
import kotlinx.serialization.builtins.serializer
|
||||
|
||||
|
||||
@@ -9,8 +9,6 @@ import dev.inmo.tgbotapi.types.MessageEntity.*
|
||||
import dev.inmo.tgbotapi.types.ParseMode.ParseMode
|
||||
import dev.inmo.tgbotapi.types.ParseMode.parseModeField
|
||||
import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup
|
||||
import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage
|
||||
import dev.inmo.tgbotapi.types.message.abstracts.TelegramBotAPIMessageDeserializationStrategyClass
|
||||
import kotlinx.serialization.*
|
||||
|
||||
fun CopyMessage(
|
||||
|
||||
@@ -87,7 +87,7 @@ fun Poll.createRequest(
|
||||
correctOptionId,
|
||||
isAnonymous,
|
||||
isClosed,
|
||||
fullEntitiesList(),
|
||||
textSources,
|
||||
scheduledCloseInfo,
|
||||
disableNotification,
|
||||
replyToMessageId,
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
package dev.inmo.tgbotapi.requests.webhook
|
||||
|
||||
import dev.inmo.tgbotapi.requests.abstracts.*
|
||||
import dev.inmo.tgbotapi.requests.send.media.base.*
|
||||
import dev.inmo.tgbotapi.requests.send.media.base.DataRequest
|
||||
import dev.inmo.tgbotapi.requests.send.media.base.MultipartRequestImpl
|
||||
import dev.inmo.tgbotapi.types.*
|
||||
import kotlinx.serialization.*
|
||||
import kotlinx.serialization.builtins.serializer
|
||||
|
||||
@@ -61,10 +61,7 @@ val inlineQueryAnswerResultsLimit = 0 .. 50
|
||||
|
||||
val customTitleLength = 0 .. 16
|
||||
|
||||
val dartsAndCubeDiceResultLimit = 1 .. 6
|
||||
@Deprecated("Renamed", ReplaceWith("dartsAndCubeDiceResultLimit", "dev.inmo.tgbotapi.types.dartsAndCubeDiceResultLimit"))
|
||||
val diceResultLimit
|
||||
get() = dartsAndCubeDiceResultLimit
|
||||
val dartsCubeAndBowlingDiceResultLimit = 1 .. 6
|
||||
val basketballAndFootballDiceResultLimit = 1 .. 5
|
||||
val slotMachineDiceResultLimit = 1 .. 64
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult.abstracts.results.audio
|
||||
|
||||
import dev.inmo.tgbotapi.CommonAbstracts.CaptionedOutput
|
||||
import dev.inmo.tgbotapi.CommonAbstracts.TextedOutput
|
||||
import dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult.abstracts.InlineQueryResult
|
||||
import dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult.abstracts.WithInputMessageContentInlineQueryResult
|
||||
@@ -8,10 +7,5 @@ import dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult.abstracts.WithInp
|
||||
const val inlineQueryResultAudioType = "audio"
|
||||
|
||||
interface InlineQueryResultAudioCommon : InlineQueryResult,
|
||||
CaptionedOutput,
|
||||
TextedOutput,
|
||||
WithInputMessageContentInlineQueryResult {
|
||||
@Deprecated("Will be removed in next major release")
|
||||
override val caption: String?
|
||||
get() = text
|
||||
}
|
||||
WithInputMessageContentInlineQueryResult
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult.abstracts.results.document
|
||||
|
||||
import dev.inmo.tgbotapi.CommonAbstracts.CaptionedOutput
|
||||
import dev.inmo.tgbotapi.CommonAbstracts.TextedOutput
|
||||
import dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult.abstracts.*
|
||||
|
||||
@@ -9,10 +8,5 @@ const val inlineQueryResultDocumentType = "document"
|
||||
interface InlineQueryResultDocumentCommon : InlineQueryResult,
|
||||
TitledInlineQueryResult,
|
||||
DescribedInlineQueryResult,
|
||||
CaptionedOutput,
|
||||
TextedOutput,
|
||||
WithInputMessageContentInlineQueryResult {
|
||||
@Deprecated("Will be removed in next major release")
|
||||
override val caption: String?
|
||||
get() = text
|
||||
}
|
||||
WithInputMessageContentInlineQueryResult
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult.abstracts.results.gif
|
||||
|
||||
import dev.inmo.tgbotapi.CommonAbstracts.CaptionedOutput
|
||||
import dev.inmo.tgbotapi.CommonAbstracts.TextedOutput
|
||||
import dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult.abstracts.*
|
||||
|
||||
@@ -8,10 +7,5 @@ const val inlineQueryResultGifType = "gif"
|
||||
|
||||
interface InlineQueryResultGifCommon : InlineQueryResult,
|
||||
OptionallyTitledInlineQueryResult,
|
||||
CaptionedOutput,
|
||||
TextedOutput,
|
||||
WithInputMessageContentInlineQueryResult {
|
||||
@Deprecated("Will be removed in next major release")
|
||||
override val caption: String?
|
||||
get() = text
|
||||
}
|
||||
WithInputMessageContentInlineQueryResult
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult.abstracts.results.mpeg4gif
|
||||
|
||||
import dev.inmo.tgbotapi.CommonAbstracts.CaptionedOutput
|
||||
import dev.inmo.tgbotapi.CommonAbstracts.TextedOutput
|
||||
import dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult.abstracts.*
|
||||
|
||||
@@ -8,10 +7,5 @@ const val inlineQueryResultMpeg4GifType = "mpeg4_gif"
|
||||
|
||||
interface InlineQueryResultMpeg4GifCommon : InlineQueryResult,
|
||||
OptionallyTitledInlineQueryResult,
|
||||
CaptionedOutput,
|
||||
TextedOutput,
|
||||
WithInputMessageContentInlineQueryResult {
|
||||
@Deprecated("Will be removed in next major release")
|
||||
override val caption: String?
|
||||
get() = text
|
||||
}
|
||||
WithInputMessageContentInlineQueryResult
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult.abstracts.results.photo
|
||||
|
||||
import dev.inmo.tgbotapi.CommonAbstracts.CaptionedOutput
|
||||
import dev.inmo.tgbotapi.CommonAbstracts.TextedOutput
|
||||
import dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult.abstracts.*
|
||||
|
||||
@@ -9,10 +8,5 @@ const val inlineQueryResultPhotoType = "photo"
|
||||
interface InlineQueryResultPhotoCommon : InlineQueryResult,
|
||||
OptionallyTitledInlineQueryResult,
|
||||
DescribedInlineQueryResult,
|
||||
CaptionedOutput,
|
||||
TextedOutput,
|
||||
WithInputMessageContentInlineQueryResult {
|
||||
@Deprecated("Will be removed in next major release")
|
||||
override val caption: String?
|
||||
get() = text
|
||||
}
|
||||
WithInputMessageContentInlineQueryResult
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult.abstracts.results.video
|
||||
|
||||
import dev.inmo.tgbotapi.CommonAbstracts.CaptionedOutput
|
||||
import dev.inmo.tgbotapi.CommonAbstracts.TextedOutput
|
||||
import dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult.abstracts.*
|
||||
|
||||
@@ -9,10 +8,5 @@ const val inlineQueryResultVideoType = "video"
|
||||
interface InlineQueryResultVideoCommon : InlineQueryResult,
|
||||
TitledInlineQueryResult,
|
||||
DescribedInlineQueryResult,
|
||||
CaptionedOutput,
|
||||
TextedOutput,
|
||||
WithInputMessageContentInlineQueryResult {
|
||||
@Deprecated("Will be removed in next major release")
|
||||
override val caption: String?
|
||||
get() = text
|
||||
}
|
||||
WithInputMessageContentInlineQueryResult
|
||||
|
||||
@@ -1,17 +1,11 @@
|
||||
package dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult.abstracts.results.voice
|
||||
|
||||
import dev.inmo.tgbotapi.CommonAbstracts.CaptionedOutput
|
||||
import dev.inmo.tgbotapi.CommonAbstracts.TextedOutput
|
||||
import dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult.abstracts.*
|
||||
|
||||
const val inlineQueryResultVoiceType = "voice"
|
||||
|
||||
interface InlineQueryResultVoiceCommon : InlineQueryResult,
|
||||
CaptionedOutput,
|
||||
TextedOutput,
|
||||
WithInputMessageContentInlineQueryResult,
|
||||
TitledInlineQueryResult {
|
||||
@Deprecated("Will be removed in next major release")
|
||||
override val caption: String?
|
||||
get() = text
|
||||
}
|
||||
TitledInlineQueryResult
|
||||
|
||||
@@ -37,10 +37,7 @@ data class InputTextMessageContent internal constructor(
|
||||
private val rawEntities: List<RawMessageEntity>? = null,
|
||||
@SerialName(disableWebPagePreviewField)
|
||||
override val disableWebPagePreview: Boolean? = null
|
||||
) : CaptionedOutput, TextedOutput, DisableWebPagePreview, InputMessageContent {
|
||||
@Deprecated("Will be removed in next major release")
|
||||
override val caption: String?
|
||||
get() = text
|
||||
) : TextedOutput, DisableWebPagePreview, InputMessageContent {
|
||||
override val entities: List<TextSource>? by lazy {
|
||||
rawEntities ?.asTextParts(text) ?.justTextSources()
|
||||
}
|
||||
|
||||
@@ -3,9 +3,6 @@ package dev.inmo.tgbotapi.types.InputMedia
|
||||
import dev.inmo.tgbotapi.requests.abstracts.InputFile
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Deprecated("Will be removed due to redundancy for end-side users")
|
||||
fun String.toInputMediaFileAttachmentName() = "attach://$this"
|
||||
|
||||
@Serializable(InputMediaSerializer::class)
|
||||
interface InputMedia {
|
||||
val type: String
|
||||
|
||||
@@ -42,16 +42,12 @@ data class InputMediaAnimation internal constructor(
|
||||
override val height: Int? = null,
|
||||
override val duration: Long? = null,
|
||||
override val thumb: InputFile? = null
|
||||
) : InputMedia, SizedInputMedia, DuratedInputMedia, ThumbedInputMedia, TextedOutput, CaptionedOutput {
|
||||
) : InputMedia, SizedInputMedia, DuratedInputMedia, ThumbedInputMedia, TextedOutput {
|
||||
override val type: String = "animation"
|
||||
override val entities: List<TextSource>? by lazy {
|
||||
rawEntities ?.asTextParts(text ?: return@lazy null) ?.justTextSources()
|
||||
}
|
||||
|
||||
@Deprecated("Will be removed in next major release")
|
||||
override val caption: String?
|
||||
get() = text
|
||||
|
||||
@SerialName(mediaField)
|
||||
override val media: String
|
||||
init { media = file.fileIdToSend } // crutch until js compiling will be fixed
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package dev.inmo.tgbotapi.types.InputMedia
|
||||
|
||||
import dev.inmo.tgbotapi.CommonAbstracts.CaptionedOutput
|
||||
import dev.inmo.tgbotapi.CommonAbstracts.TextedOutput
|
||||
import kotlinx.serialization.*
|
||||
import kotlinx.serialization.json.Json
|
||||
@@ -16,10 +15,7 @@ internal fun <T> T.buildArguments(withSerializer: SerializationStrategy<T>) = ar
|
||||
)
|
||||
|
||||
@Serializable(MediaGroupMemberInputMediaSerializer::class)
|
||||
interface MediaGroupMemberInputMedia : InputMedia, CaptionedOutput, TextedOutput {
|
||||
@Deprecated("Will be removed in next major release")
|
||||
override val caption: String?
|
||||
get() = text
|
||||
interface MediaGroupMemberInputMedia : InputMedia, TextedOutput {
|
||||
fun serialize(format: StringFormat): String
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package dev.inmo.tgbotapi.types.InputMedia
|
||||
|
||||
import dev.inmo.tgbotapi.requests.abstracts.*
|
||||
import dev.inmo.tgbotapi.requests.abstracts.InputFile
|
||||
|
||||
interface ThumbedInputMedia : InputMedia {
|
||||
val thumb: InputFile?
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
package dev.inmo.tgbotapi.types.MessageEntity.textsources
|
||||
|
||||
import dev.inmo.tgbotapi.CommonAbstracts.*
|
||||
import dev.inmo.tgbotapi.utils.*
|
||||
import dev.inmo.tgbotapi.utils.RiskFeature
|
||||
import dev.inmo.tgbotapi.utils.internal.*
|
||||
import dev.inmo.tgbotapi.utils.internal.boldMarkdown
|
||||
import dev.inmo.tgbotapi.utils.internal.boldMarkdownV2
|
||||
|
||||
/**
|
||||
* @see bold
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
package dev.inmo.tgbotapi.types.MessageEntity.textsources
|
||||
|
||||
import dev.inmo.tgbotapi.CommonAbstracts.*
|
||||
import dev.inmo.tgbotapi.utils.*
|
||||
import dev.inmo.tgbotapi.CommonAbstracts.DirectInvocationOfTextSourceConstructor
|
||||
import dev.inmo.tgbotapi.CommonAbstracts.TextSource
|
||||
import dev.inmo.tgbotapi.utils.RiskFeature
|
||||
import dev.inmo.tgbotapi.utils.internal.*
|
||||
import dev.inmo.tgbotapi.utils.internal.commandMarkdown
|
||||
import dev.inmo.tgbotapi.utils.internal.commandMarkdownV2
|
||||
|
||||
private val commandRegex = Regex("[/!][^@\\s]*")
|
||||
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
package dev.inmo.tgbotapi.types.MessageEntity.textsources
|
||||
|
||||
import dev.inmo.tgbotapi.CommonAbstracts.*
|
||||
import dev.inmo.tgbotapi.utils.*
|
||||
import dev.inmo.tgbotapi.utils.RiskFeature
|
||||
import dev.inmo.tgbotapi.utils.internal.*
|
||||
import dev.inmo.tgbotapi.utils.internal.cashTagMarkdown
|
||||
import dev.inmo.tgbotapi.utils.internal.cashTagMarkdownV2
|
||||
|
||||
/**
|
||||
* @see cashTag
|
||||
|
||||
@@ -2,10 +2,8 @@ package dev.inmo.tgbotapi.types.MessageEntity.textsources
|
||||
|
||||
import dev.inmo.tgbotapi.CommonAbstracts.DirectInvocationOfTextSourceConstructor
|
||||
import dev.inmo.tgbotapi.CommonAbstracts.TextSource
|
||||
import dev.inmo.tgbotapi.utils.*
|
||||
import dev.inmo.tgbotapi.utils.RiskFeature
|
||||
import dev.inmo.tgbotapi.utils.internal.*
|
||||
import dev.inmo.tgbotapi.utils.internal.codeMarkdown
|
||||
import dev.inmo.tgbotapi.utils.internal.codeMarkdownV2
|
||||
|
||||
/**
|
||||
* @see code
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
package dev.inmo.tgbotapi.types.MessageEntity.textsources
|
||||
|
||||
import dev.inmo.tgbotapi.CommonAbstracts.*
|
||||
import dev.inmo.tgbotapi.utils.*
|
||||
import dev.inmo.tgbotapi.utils.RiskFeature
|
||||
import dev.inmo.tgbotapi.utils.internal.*
|
||||
import dev.inmo.tgbotapi.utils.internal.emailMarkdown
|
||||
import dev.inmo.tgbotapi.utils.internal.emailMarkdownV2
|
||||
|
||||
/**
|
||||
* @see email
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
package dev.inmo.tgbotapi.types.MessageEntity.textsources
|
||||
|
||||
import dev.inmo.tgbotapi.CommonAbstracts.*
|
||||
import dev.inmo.tgbotapi.utils.*
|
||||
import dev.inmo.tgbotapi.utils.RiskFeature
|
||||
import dev.inmo.tgbotapi.utils.internal.*
|
||||
import dev.inmo.tgbotapi.utils.internal.hashTagMarkdown
|
||||
import dev.inmo.tgbotapi.utils.internal.hashTagMarkdownV2
|
||||
|
||||
/**
|
||||
* @see hashtag
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
package dev.inmo.tgbotapi.types.MessageEntity.textsources
|
||||
|
||||
import dev.inmo.tgbotapi.CommonAbstracts.*
|
||||
import dev.inmo.tgbotapi.utils.*
|
||||
import dev.inmo.tgbotapi.utils.RiskFeature
|
||||
import dev.inmo.tgbotapi.utils.internal.*
|
||||
import dev.inmo.tgbotapi.utils.internal.italicMarkdown
|
||||
import dev.inmo.tgbotapi.utils.internal.italicMarkdownV2
|
||||
|
||||
/**
|
||||
* @see italic
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
package dev.inmo.tgbotapi.types.MessageEntity.textsources
|
||||
|
||||
import dev.inmo.tgbotapi.CommonAbstracts.*
|
||||
import dev.inmo.tgbotapi.utils.*
|
||||
import dev.inmo.tgbotapi.utils.RiskFeature
|
||||
import dev.inmo.tgbotapi.utils.internal.*
|
||||
import dev.inmo.tgbotapi.utils.internal.mentionMarkdown
|
||||
import dev.inmo.tgbotapi.utils.internal.mentionMarkdownV2
|
||||
|
||||
private val String.withoutCommercialAt
|
||||
get() = if (startsWith("@")) {
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
package dev.inmo.tgbotapi.types.MessageEntity.textsources
|
||||
|
||||
import dev.inmo.tgbotapi.CommonAbstracts.*
|
||||
import dev.inmo.tgbotapi.utils.*
|
||||
import dev.inmo.tgbotapi.utils.RiskFeature
|
||||
import dev.inmo.tgbotapi.utils.internal.*
|
||||
import dev.inmo.tgbotapi.utils.internal.phoneMarkdown
|
||||
import dev.inmo.tgbotapi.utils.internal.phoneMarkdownV2
|
||||
|
||||
/**
|
||||
* @see phone
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
package dev.inmo.tgbotapi.types.MessageEntity.textsources
|
||||
|
||||
import dev.inmo.tgbotapi.CommonAbstracts.*
|
||||
import dev.inmo.tgbotapi.utils.*
|
||||
import dev.inmo.tgbotapi.CommonAbstracts.DirectInvocationOfTextSourceConstructor
|
||||
import dev.inmo.tgbotapi.CommonAbstracts.TextSource
|
||||
import dev.inmo.tgbotapi.utils.RiskFeature
|
||||
import dev.inmo.tgbotapi.utils.internal.*
|
||||
import dev.inmo.tgbotapi.utils.internal.preMarkdown
|
||||
import dev.inmo.tgbotapi.utils.internal.preMarkdownV2
|
||||
|
||||
/**
|
||||
* @see pre
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
package dev.inmo.tgbotapi.types.MessageEntity.textsources
|
||||
|
||||
import dev.inmo.tgbotapi.CommonAbstracts.*
|
||||
import dev.inmo.tgbotapi.utils.*
|
||||
import dev.inmo.tgbotapi.CommonAbstracts.DirectInvocationOfTextSourceConstructor
|
||||
import dev.inmo.tgbotapi.CommonAbstracts.TextSource
|
||||
import dev.inmo.tgbotapi.utils.RiskFeature
|
||||
import dev.inmo.tgbotapi.utils.internal.*
|
||||
import dev.inmo.tgbotapi.utils.internal.regularMarkdown
|
||||
import dev.inmo.tgbotapi.utils.internal.regularMarkdownV2
|
||||
|
||||
/**
|
||||
* @see regular
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
package dev.inmo.tgbotapi.types.MessageEntity.textsources
|
||||
|
||||
import dev.inmo.tgbotapi.CommonAbstracts.*
|
||||
import dev.inmo.tgbotapi.utils.*
|
||||
import dev.inmo.tgbotapi.utils.RiskFeature
|
||||
import dev.inmo.tgbotapi.utils.internal.*
|
||||
import dev.inmo.tgbotapi.utils.internal.strikethroughMarkdown
|
||||
import dev.inmo.tgbotapi.utils.internal.strikethroughMarkdownV2
|
||||
|
||||
/**
|
||||
* @see strikethrough
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
package dev.inmo.tgbotapi.types.MessageEntity.textsources
|
||||
|
||||
import dev.inmo.tgbotapi.CommonAbstracts.*
|
||||
import dev.inmo.tgbotapi.utils.*
|
||||
import dev.inmo.tgbotapi.CommonAbstracts.DirectInvocationOfTextSourceConstructor
|
||||
import dev.inmo.tgbotapi.CommonAbstracts.TextSource
|
||||
import dev.inmo.tgbotapi.utils.RiskFeature
|
||||
import dev.inmo.tgbotapi.utils.internal.*
|
||||
import dev.inmo.tgbotapi.utils.internal.linkMarkdown
|
||||
import dev.inmo.tgbotapi.utils.internal.linkMarkdownV2
|
||||
|
||||
/**
|
||||
* @see link
|
||||
|
||||
@@ -2,10 +2,8 @@ package dev.inmo.tgbotapi.types.MessageEntity.textsources
|
||||
|
||||
import dev.inmo.tgbotapi.CommonAbstracts.*
|
||||
import dev.inmo.tgbotapi.types.User
|
||||
import dev.inmo.tgbotapi.utils.*
|
||||
import dev.inmo.tgbotapi.utils.RiskFeature
|
||||
import dev.inmo.tgbotapi.utils.internal.*
|
||||
import dev.inmo.tgbotapi.utils.internal.textMentionMarkdown
|
||||
import dev.inmo.tgbotapi.utils.internal.textMentionMarkdownV2
|
||||
|
||||
/**
|
||||
* @see mention
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
package dev.inmo.tgbotapi.types.MessageEntity.textsources
|
||||
|
||||
import dev.inmo.tgbotapi.CommonAbstracts.*
|
||||
import dev.inmo.tgbotapi.utils.*
|
||||
import dev.inmo.tgbotapi.CommonAbstracts.DirectInvocationOfTextSourceConstructor
|
||||
import dev.inmo.tgbotapi.CommonAbstracts.TextSource
|
||||
import dev.inmo.tgbotapi.utils.RiskFeature
|
||||
import dev.inmo.tgbotapi.utils.internal.*
|
||||
import dev.inmo.tgbotapi.utils.internal.linkMarkdown
|
||||
import dev.inmo.tgbotapi.utils.internal.linkMarkdownV2
|
||||
|
||||
/**
|
||||
* @see link
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
package dev.inmo.tgbotapi.types.MessageEntity.textsources
|
||||
|
||||
import dev.inmo.tgbotapi.CommonAbstracts.*
|
||||
import dev.inmo.tgbotapi.utils.*
|
||||
import dev.inmo.tgbotapi.utils.RiskFeature
|
||||
import dev.inmo.tgbotapi.utils.internal.*
|
||||
import dev.inmo.tgbotapi.utils.internal.underlineMarkdown
|
||||
import dev.inmo.tgbotapi.utils.internal.underlineMarkdownV2
|
||||
|
||||
/**
|
||||
* @see underline
|
||||
|
||||
@@ -42,6 +42,9 @@ internal object BotActionSerializer: KSerializer<BotAction> {
|
||||
object TypingAction : BotAction() {
|
||||
override val actionName: String = "typing"
|
||||
}
|
||||
inline val typing
|
||||
get() = TypingAction
|
||||
inline fun BotAction.asTyping() = this as? TypingAction
|
||||
|
||||
/**
|
||||
* Will notify user that bot is uploading some photo
|
||||
@@ -50,6 +53,9 @@ object TypingAction : BotAction() {
|
||||
object UploadPhotoAction : BotAction() {
|
||||
override val actionName: String = "upload_photo"
|
||||
}
|
||||
inline val uploadPhoto
|
||||
get() = UploadPhotoAction
|
||||
inline fun BotAction.asUploadPhoto() = this as? UploadPhotoAction
|
||||
|
||||
/**
|
||||
* Will notify user that bot is recording some video
|
||||
@@ -58,6 +64,9 @@ object UploadPhotoAction : BotAction() {
|
||||
object RecordVideoAction : BotAction() {
|
||||
override val actionName: String = "record_video"
|
||||
}
|
||||
inline val recordVideo
|
||||
get() = RecordVideoAction
|
||||
inline fun BotAction.asRecordVideo() = this as? RecordVideoAction
|
||||
|
||||
/**
|
||||
* Will notify user that bot is uploading some photo
|
||||
@@ -66,6 +75,9 @@ object RecordVideoAction : BotAction() {
|
||||
object UploadVideoAction : BotAction() {
|
||||
override val actionName: String = "upload_video"
|
||||
}
|
||||
inline val uploadVideo
|
||||
get() = UploadVideoAction
|
||||
inline fun BotAction.asUploadVideo() = this as? UploadVideoAction
|
||||
|
||||
/**
|
||||
* Will notify user that bot is recording some audio
|
||||
@@ -74,6 +86,9 @@ object UploadVideoAction : BotAction() {
|
||||
object RecordAudioAction : BotAction() {
|
||||
override val actionName: String = "record_audio"
|
||||
}
|
||||
inline val recordAudio
|
||||
get() = RecordAudioAction
|
||||
inline fun BotAction.asRecordAudio() = this as? RecordAudioAction
|
||||
|
||||
/**
|
||||
* Will notify user that bot is uploading some audio
|
||||
@@ -82,6 +97,9 @@ object RecordAudioAction : BotAction() {
|
||||
object UploadAudioAction : BotAction() {
|
||||
override val actionName: String = "upload_audio"
|
||||
}
|
||||
inline val uploadAudio
|
||||
get() = UploadAudioAction
|
||||
inline fun BotAction.asUploadAudio() = this as? UploadAudioAction
|
||||
|
||||
/**
|
||||
* Will notify user that bot is uploading some document
|
||||
@@ -90,6 +108,9 @@ object UploadAudioAction : BotAction() {
|
||||
object UploadDocumentAction : BotAction() {
|
||||
override val actionName: String = "upload_document"
|
||||
}
|
||||
inline val uploadDocument
|
||||
get() = UploadDocumentAction
|
||||
inline fun BotAction.asUploadDocument() = this as? UploadDocumentAction
|
||||
|
||||
/**
|
||||
* Will notify user that bot is trying to find location
|
||||
@@ -98,6 +119,9 @@ object UploadDocumentAction : BotAction() {
|
||||
object FindLocationAction : BotAction() {
|
||||
override val actionName: String = "find_location"
|
||||
}
|
||||
inline val findLocation
|
||||
get() = FindLocationAction
|
||||
inline fun BotAction.asFindLocation() = this as? FindLocationAction
|
||||
|
||||
/**
|
||||
* Will notify user that bot is recording video note
|
||||
@@ -106,6 +130,9 @@ object FindLocationAction : BotAction() {
|
||||
object RecordVideoNoteAction : BotAction() {
|
||||
override val actionName: String = "record_video_note"
|
||||
}
|
||||
inline val recordVideoNote
|
||||
get() = RecordVideoNoteAction
|
||||
inline fun BotAction.asRecordVideoNote() = this as? RecordVideoNoteAction
|
||||
|
||||
/**
|
||||
* Will notify user that bot is uploading video note
|
||||
@@ -114,3 +141,6 @@ object RecordVideoNoteAction : BotAction() {
|
||||
object UploadVideoNoteAction : BotAction() {
|
||||
override val actionName: String = "upload_video_note"
|
||||
}
|
||||
inline val uploadVideoNote
|
||||
get() = UploadVideoNoteAction
|
||||
inline fun BotAction.asUploadVideoNote() = this as? UploadVideoNoteAction
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package dev.inmo.tgbotapi.types.chat.abstracts
|
||||
|
||||
import dev.inmo.tgbotapi.types.ChatId
|
||||
import dev.inmo.tgbotapi.types.UserId
|
||||
import dev.inmo.tgbotapi.types.chat.PreviewChatSerializer
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@@ -15,13 +15,13 @@ sealed class DiceAnimationType {
|
||||
object CubeDiceAnimationType : DiceAnimationType() {
|
||||
override val emoji: String = "\uD83C\uDFB2"
|
||||
override val valueLimits: IntRange
|
||||
get() = dartsAndCubeDiceResultLimit
|
||||
get() = dartsCubeAndBowlingDiceResultLimit
|
||||
}
|
||||
@Serializable(DiceAnimationTypeSerializer::class)
|
||||
object DartsDiceAnimationType : DiceAnimationType() {
|
||||
override val emoji: String = "\uD83C\uDFAF"
|
||||
override val valueLimits: IntRange
|
||||
get() = dartsAndCubeDiceResultLimit
|
||||
get() = dartsCubeAndBowlingDiceResultLimit
|
||||
}
|
||||
@Serializable(DiceAnimationTypeSerializer::class)
|
||||
object BasketballDiceAnimationType : DiceAnimationType() {
|
||||
@@ -36,6 +36,12 @@ object FootballDiceAnimationType : DiceAnimationType() {
|
||||
get() = basketballAndFootballDiceResultLimit
|
||||
}
|
||||
@Serializable(DiceAnimationTypeSerializer::class)
|
||||
object BowlingDiceAnimationType : DiceAnimationType() {
|
||||
override val emoji: String = "\uD83C\uDFB3"
|
||||
override val valueLimits: IntRange
|
||||
get() = dartsCubeAndBowlingDiceResultLimit
|
||||
}
|
||||
@Serializable(DiceAnimationTypeSerializer::class)
|
||||
object SlotMachineDiceAnimationType : DiceAnimationType() {
|
||||
override val emoji: String = "\uD83C\uDFB0"
|
||||
override val valueLimits: IntRange
|
||||
@@ -59,6 +65,7 @@ internal object DiceAnimationTypeSerializer : KSerializer<DiceAnimationType> {
|
||||
BasketballDiceAnimationType.emoji -> BasketballDiceAnimationType
|
||||
SlotMachineDiceAnimationType.emoji -> SlotMachineDiceAnimationType
|
||||
FootballDiceAnimationType.emoji -> FootballDiceAnimationType
|
||||
BowlingDiceAnimationType.emoji -> BowlingDiceAnimationType
|
||||
else -> CustomDiceAnimationType(type)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import com.soywiz.klock.DateTime
|
||||
import dev.inmo.tgbotapi.types.MessageIdentifier
|
||||
import dev.inmo.tgbotapi.types.chat.abstracts.ChannelChat
|
||||
import dev.inmo.tgbotapi.types.message.ChatEvents.abstracts.ChannelEvent
|
||||
import dev.inmo.tgbotapi.types.message.ChatEvents.abstracts.GroupEvent
|
||||
import dev.inmo.tgbotapi.types.message.abstracts.ChatEventMessage
|
||||
|
||||
data class ChannelEventMessage<T : ChannelEvent>(
|
||||
|
||||
@@ -20,6 +20,3 @@ data class ChannelMessageImpl<T: MessageContent>(
|
||||
override val senderBot: CommonBot?,
|
||||
override val authorSignature: AuthorSignature?
|
||||
) : ChannelMessage<T>
|
||||
|
||||
@Deprecated("Renamed", ReplaceWith("ChannelMessageImpl", "dev.inmo.tgbotapi.types.message.ChannelMessageImpl"))
|
||||
typealias ChannelMessage<T> = ChannelMessageImpl<T>
|
||||
|
||||
@@ -7,9 +7,6 @@ import dev.inmo.tgbotapi.types.chat.abstracts.GroupChat
|
||||
import dev.inmo.tgbotapi.types.message.ChatEvents.abstracts.GroupEvent
|
||||
import dev.inmo.tgbotapi.types.message.abstracts.GroupEventMessage
|
||||
|
||||
@Deprecated("Renamed", ReplaceWith("CommonGroupEventMessage"))
|
||||
typealias GroupEventMessage = CommonGroupEventMessage<*>
|
||||
|
||||
data class CommonGroupEventMessage<T : GroupEvent>(
|
||||
override val messageId: MessageIdentifier,
|
||||
override val user: User,
|
||||
|
||||
@@ -4,13 +4,9 @@ import com.soywiz.klock.DateTime
|
||||
import dev.inmo.tgbotapi.types.MessageIdentifier
|
||||
import dev.inmo.tgbotapi.types.User
|
||||
import dev.inmo.tgbotapi.types.chat.abstracts.SupergroupChat
|
||||
import dev.inmo.tgbotapi.types.message.ChatEvents.abstracts.GroupEvent
|
||||
import dev.inmo.tgbotapi.types.message.ChatEvents.abstracts.SupergroupEvent
|
||||
import dev.inmo.tgbotapi.types.message.abstracts.SupergroupEventMessage
|
||||
|
||||
@Deprecated("Renamed", ReplaceWith("CommonSupergroupEventMessage"))
|
||||
typealias SupergroupEventMessage = CommonSupergroupEventMessage<*>
|
||||
|
||||
data class CommonSupergroupEventMessage<T : SupergroupEvent>(
|
||||
override val messageId: MessageIdentifier,
|
||||
override val user: User,
|
||||
|
||||
@@ -22,6 +22,3 @@ data class PrivateMessageImpl<T: MessageContent>(
|
||||
override val senderBot: CommonBot?,
|
||||
val paymentInfo: SuccessfulPaymentInfo?
|
||||
) : PrivateMessage<T>
|
||||
|
||||
@Deprecated("Renamed", ReplaceWith("PrivateMessageImpl", "dev.inmo.tgbotapi.types.message.PrivateMessageImpl"))
|
||||
typealias CommonMessageImpl<T> = PrivateMessageImpl<T>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package dev.inmo.tgbotapi.types.message.content
|
||||
|
||||
import dev.inmo.tgbotapi.CommonAbstracts.*
|
||||
import dev.inmo.tgbotapi.CommonAbstracts.TextPart
|
||||
import dev.inmo.tgbotapi.CommonAbstracts.TextedInput
|
||||
import dev.inmo.tgbotapi.requests.abstracts.Request
|
||||
import dev.inmo.tgbotapi.requests.send.SendTextMessage
|
||||
import dev.inmo.tgbotapi.types.ChatIdentifier
|
||||
@@ -10,17 +11,11 @@ import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup
|
||||
import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage
|
||||
import dev.inmo.tgbotapi.types.message.content.abstracts.MessageContent
|
||||
import dev.inmo.tgbotapi.utils.internal.*
|
||||
import dev.inmo.tgbotapi.utils.internal.fullListOfSubSource
|
||||
import dev.inmo.tgbotapi.utils.internal.toMarkdownTexts
|
||||
|
||||
data class TextContent(
|
||||
override val text: String,
|
||||
override val textEntities: List<TextPart> = emptyList()
|
||||
) : MessageContent, TextedInput {
|
||||
@Deprecated("Has been renamed", ReplaceWith("textEntities"))
|
||||
val entities: List<TextPart>
|
||||
get() = textEntities
|
||||
|
||||
override fun createResend(
|
||||
chatId: ChatIdentifier,
|
||||
disableNotification: Boolean,
|
||||
@@ -77,10 +72,3 @@ data class TextContent(
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert its [TextContent.entities] to list of [dev.inmo.tgbotapi.CommonAbstracts.TextSource]
|
||||
* with [dev.inmo.tgbotapi.types.MessageEntity.textsources.RegularTextSource]
|
||||
*/
|
||||
@Deprecated("Useless due to the fact that currently every message contains full list of sources")
|
||||
fun TextContent.fullEntitiesList(): TextSourcesList = text.fullListOfSubSource(entities).map { it.source }
|
||||
|
||||
@@ -14,6 +14,14 @@ class FlowsUpdatesFilter(
|
||||
private val updatesSharedFlow = MutableSharedFlow<Update>(extraBufferCapacity = broadcastChannelsSize)
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
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>
|
||||
get() = ALL_UPDATES_LIST
|
||||
|
||||
@@ -18,6 +18,7 @@ package dev.inmo.tgbotapi.utils
|
||||
)
|
||||
annotation class PreviewFeature
|
||||
|
||||
const val lowLevelRiskFeatureMessage = "This method is low-level and not recommended to direct use"
|
||||
@RequiresOptIn(
|
||||
"This feature can work unstable and may have some restrictions in Telegram System",
|
||||
RequiresOptIn.Level.WARNING
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
package dev.inmo.tgbotapi.utils
|
||||
|
||||
import dev.inmo.micro_utils.coroutines.ExceptionHandler
|
||||
import dev.inmo.micro_utils.coroutines.safely
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.supervisorScope
|
||||
|
||||
|
||||
@Deprecated("In future will be used typealias from micro_utils", ReplaceWith("ExceptionHandler", "dev.inmo.micro_utils.coroutines.ExceptionHandler"))
|
||||
typealias ExceptionHandler<T> = ExceptionHandler<T>
|
||||
/**
|
||||
* It will run [block] inside of [supervisorScope] to avoid problems with catching of exceptions
|
||||
*
|
||||
* @param [onException] Will be called when happen exception inside of [block]. By default will throw exception - this
|
||||
* exception will be available for catching
|
||||
*/
|
||||
@Deprecated("In future will be used typealias from micro_utils", ReplaceWith("safely", "dev.inmo.micro_utils.coroutines.safely"))
|
||||
suspend inline fun <T> handleSafely(
|
||||
noinline onException: ExceptionHandler<T> = { throw it },
|
||||
noinline block: suspend CoroutineScope.() -> T
|
||||
): T = safely(onException, block)
|
||||
@@ -5,19 +5,40 @@ import io.ktor.utils.io.core.ByteReadPacket
|
||||
import io.ktor.utils.io.core.Input
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
/**
|
||||
* Information about file for [StorageFile]
|
||||
*
|
||||
* @param contentType Raw type like "application/json"
|
||||
* @param fileName This filename will be used in telegram system as name of file
|
||||
*/
|
||||
@Serializable
|
||||
data class StorageFileInfo(
|
||||
val contentType: String,
|
||||
val fileName: String
|
||||
) {
|
||||
/**
|
||||
* This methods is required for random generation of name for keeping warranties about unique file name
|
||||
*/
|
||||
fun generateCustomName() = "${uuid4()}.${fileName.fileExtension}"
|
||||
}
|
||||
|
||||
/**
|
||||
* Contains info about file, which potentially can be sent to telegram system.
|
||||
*
|
||||
* @param storageFileInfo Information about this file
|
||||
* @param inputSource Lambda which able to allocate [Input] for uploading/manipulating data
|
||||
*
|
||||
* @see StorageFileInfo
|
||||
* @see asStorageFile
|
||||
*/
|
||||
data class StorageFile(
|
||||
val storageFileInfo: StorageFileInfo,
|
||||
private val inputSource: () -> Input
|
||||
) {
|
||||
fun asInput() = inputSource()
|
||||
val input: Input
|
||||
get() = inputSource()
|
||||
@Deprecated("This method will be fully replaced with input property", ReplaceWith("input"))
|
||||
fun asInput() = input
|
||||
}
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
@@ -31,5 +52,8 @@ inline fun StorageFile(
|
||||
ByteReadPacket(bytes)
|
||||
}
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE", "unused")
|
||||
inline fun ByteArray.asStorageFile(fileName: String, mimeType: MimeType) = StorageFile(fileName, this, mimeType)
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
package dev.inmo.tgbotapi.utils.internal
|
||||
|
||||
import dev.inmo.tgbotapi.types.MediaGroupIdentifier
|
||||
import dev.inmo.tgbotapi.types.message.abstracts.MediaGroupMessage
|
||||
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
|
||||
|
||||
private inline val Pair<MediaGroupMessage, *>.message
|
||||
get() = first
|
||||
|
||||
internal fun List<BaseMessageUpdate>.convertWithMediaGroupUpdates(): List<Update> {
|
||||
val resultUpdates = mutableListOf<Update>()
|
||||
val mediaGroups = mutableMapOf<MediaGroupIdentifier, MutableList<BaseMessageUpdate>>()
|
||||
for (update in this) {
|
||||
val asEditMediaGroupMessage = update.toEditMediaGroupUpdate()
|
||||
if (asEditMediaGroupMessage != null) {
|
||||
resultUpdates.add(asEditMediaGroupMessage)
|
||||
} else {
|
||||
val data = update.data
|
||||
if (data is MediaGroupMessage) {
|
||||
(mediaGroups[data.mediaGroupId] ?: mutableListOf<BaseMessageUpdate>().also { mediaGroups[data.mediaGroupId] = it }).add(update)
|
||||
} else {
|
||||
resultUpdates.add(update)
|
||||
}
|
||||
}
|
||||
}
|
||||
mediaGroups.values.map {
|
||||
it.toSentMediaGroupUpdate() ?.let { mediaGroupUpdate ->
|
||||
resultUpdates.add(mediaGroupUpdate)
|
||||
}
|
||||
}
|
||||
return resultUpdates.sortedBy { it.updateId }
|
||||
}
|
||||
|
||||
internal fun List<BaseMessageUpdate>.toSentMediaGroupUpdate(): SentMediaGroupUpdate? = (this as? SentMediaGroupUpdate) ?: let {
|
||||
if (isEmpty()) {
|
||||
return@let null
|
||||
}
|
||||
val resultList = sortedBy { it.updateId }
|
||||
when (first()) {
|
||||
is MessageUpdate -> MessageMediaGroupUpdate(resultList)
|
||||
is ChannelPostUpdate -> ChannelPostMediaGroupUpdate(resultList)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
internal fun BaseMessageUpdate.toEditMediaGroupUpdate(): EditMediaGroupUpdate? = (this as? EditMediaGroupUpdate) ?: let {
|
||||
when (this) {
|
||||
is EditMessageUpdate -> EditMessageMediaGroupUpdate(this)
|
||||
is EditChannelPostUpdate -> EditChannelPostMediaGroupUpdate(this)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,6 @@ import dev.inmo.tgbotapi.CommonAbstracts.*
|
||||
import dev.inmo.tgbotapi.types.*
|
||||
import dev.inmo.tgbotapi.types.ParseMode.*
|
||||
import dev.inmo.tgbotapi.types.message.content.TextContent
|
||||
import dev.inmo.tgbotapi.types.message.content.fullEntitiesList
|
||||
|
||||
internal fun createFormattedText(
|
||||
entities: TextSourcesList,
|
||||
@@ -56,13 +55,7 @@ internal fun TextSourcesList.toMarkdownTexts(): List<String> = createMarkdownTex
|
||||
this,
|
||||
textLength.last
|
||||
)
|
||||
internal fun TextContent.toMarkdownTexts(): List<String> = fullEntitiesList().toMarkdownTexts()
|
||||
|
||||
internal fun TextSourcesList.toMarkdownExplanations(): List<String> = createMarkdownText(
|
||||
this,
|
||||
explanationLimit.last
|
||||
)
|
||||
internal fun ExplainedInput.toMarkdownExplanations(): List<String> = fullEntitiesList().toMarkdownTexts()
|
||||
internal fun TextContent.toMarkdownTexts(): List<String> = textSources.toMarkdownTexts()
|
||||
|
||||
|
||||
internal fun createMarkdownV2Text(
|
||||
@@ -74,19 +67,13 @@ internal fun TextSourcesList.toMarkdownV2Captions(): List<String> = createMarkdo
|
||||
this,
|
||||
captionLength.last
|
||||
)
|
||||
internal fun CaptionedInput.toMarkdownV2Captions(): List<String> = fullEntitiesList().toMarkdownV2Captions()
|
||||
internal fun CaptionedInput.toMarkdownV2Captions(): List<String> = textSources.toMarkdownV2Captions()
|
||||
|
||||
internal fun TextSourcesList.toMarkdownV2Texts(): List<String> = createMarkdownV2Text(
|
||||
this,
|
||||
textLength.last
|
||||
)
|
||||
internal fun TextContent.toMarkdownV2Texts(): List<String> = fullEntitiesList().toMarkdownV2Texts()
|
||||
|
||||
internal fun TextSourcesList.toMarkdownV2Explanations(): List<String> = createMarkdownV2Text(
|
||||
this,
|
||||
explanationLimit.last
|
||||
)
|
||||
internal fun ExplainedInput.toMarkdownV2Explanations(): List<String> = fullEntitiesList().toMarkdownV2Texts()
|
||||
internal fun TextContent.toMarkdownV2Texts(): List<String> = textSources.toMarkdownV2Texts()
|
||||
|
||||
|
||||
internal fun createHtmlText(
|
||||
@@ -98,12 +85,12 @@ internal fun TextSourcesList.toHtmlCaptions(): List<String> = createHtmlText(
|
||||
this,
|
||||
captionLength.last
|
||||
)
|
||||
internal fun CaptionedInput.toHtmlCaptions(): List<String> = fullEntitiesList().toHtmlCaptions()
|
||||
internal fun CaptionedInput.toHtmlCaptions(): List<String> = textSources.toHtmlCaptions()
|
||||
|
||||
internal fun TextSourcesList.toHtmlTexts(): List<String> = createHtmlText(
|
||||
this,
|
||||
textLength.last
|
||||
)
|
||||
internal fun TextContent.toHtmlTexts(): List<String> = fullEntitiesList().toHtmlTexts()
|
||||
internal fun TextContent.toHtmlTexts(): List<String> = textSources.toHtmlTexts()
|
||||
|
||||
|
||||
|
||||
@@ -148,8 +148,3 @@ internal fun MultilevelTextSource.hashTagHTML(): String = optionalPrefix("#") +
|
||||
|
||||
internal fun MultilevelTextSource.phoneMarkdownV2(): String = subsources.joinSubSourcesMarkdownV2()
|
||||
internal fun MultilevelTextSource.phoneHTML(): String = subsources.joinSubSourcesHtml()
|
||||
|
||||
|
||||
internal fun MultilevelTextSource.commandMarkdownV2(): String = optionalPrefix("/") + subsources.joinSubSourcesMarkdownV2()
|
||||
internal fun MultilevelTextSource.commandHTML(): String = optionalPrefix("/") + subsources.joinSubSourcesHtml()
|
||||
|
||||
|
||||
@@ -99,12 +99,10 @@ private inline fun String.hashTag(adapt: String.() -> String): String = if (star
|
||||
}
|
||||
|
||||
internal fun String.textMentionMarkdown(userId: UserId): String = linkMarkdown(userId.link)
|
||||
internal fun String.textMentionMarkdownV2(userId: UserId): String = linkMarkdownV2(userId.link)
|
||||
|
||||
internal fun String.mentionMarkdown(): String = mention(String::toMarkdown)
|
||||
|
||||
internal fun String.hashTagMarkdown(): String = hashTag(String::toMarkdown)
|
||||
internal fun String.hashTagHTML(): String = hashTag(String::toHtml)
|
||||
|
||||
internal fun String.phoneMarkdown(): String = toMarkdown()
|
||||
|
||||
@@ -136,14 +134,6 @@ internal infix fun Pair<String, String>.link(parseMode: ParseMode): String = whe
|
||||
is MarkdownV2 -> first.linkMarkdownV2(second)
|
||||
}
|
||||
|
||||
|
||||
internal infix fun String.command(parseMode: ParseMode): String = when (parseMode) {
|
||||
is HTML -> commandHTML()
|
||||
is Markdown -> commandMarkdown()
|
||||
is MarkdownV2 -> commandMarkdownV2()
|
||||
}
|
||||
|
||||
|
||||
internal infix fun String.underline(parseMode: ParseMode): String = when (parseMode) {
|
||||
is HTML -> underlineHTML()
|
||||
is Markdown -> underlineMarkdown()
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package dev.inmo.tgbotapi.types.MessageEntity
|
||||
|
||||
import dev.inmo.tgbotapi.CommonAbstracts.TextSource
|
||||
import dev.inmo.tgbotapi.types.MessageEntity.textsources.*
|
||||
import dev.inmo.tgbotapi.CommonAbstracts.plus
|
||||
import dev.inmo.tgbotapi.types.MessageEntity.textsources.*
|
||||
import dev.inmo.tgbotapi.utils.internal.*
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
@@ -3,7 +3,8 @@ package dev.inmo.tgbotapi.types.MessageEntity
|
||||
import dev.inmo.tgbotapi.CommonAbstracts.justTextSources
|
||||
import dev.inmo.tgbotapi.utils.internal.toHtmlTexts
|
||||
import dev.inmo.tgbotapi.utils.internal.toMarkdownV2Texts
|
||||
import kotlin.test.*
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class TextPartsCreatingTests {
|
||||
@Test
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
package dev.inmo.tgbotapi.requests.abstracts
|
||||
|
||||
import dev.inmo.tgbotapi.utils.MimeType
|
||||
import dev.inmo.tgbotapi.utils.StorageFile
|
||||
import java.io.File
|
||||
import java.io.InputStream
|
||||
|
||||
fun File.toInputFile() = if (exists()) {
|
||||
MultipartFile(
|
||||
|
||||
@@ -2,7 +2,6 @@ package dev.inmo.tgbotapi.utils
|
||||
|
||||
import io.ktor.utils.io.streams.asInput
|
||||
import java.io.File
|
||||
import java.io.InputStream
|
||||
import java.nio.file.Files
|
||||
|
||||
fun StorageFile(
|
||||
|
||||
@@ -8,7 +8,6 @@ buildscript {
|
||||
dependencies {
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
|
||||
classpath "com.jfrog.bintray.gradle:gradle-bintray-plugin:$gradle_bintray_plugin_version"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
apply plugin: 'maven-publish'
|
||||
|
||||
task javadocsJar(type: Jar) {
|
||||
classifier = 'javadoc'
|
||||
}
|
||||
|
||||
afterEvaluate {
|
||||
project.publishing.publications.all {
|
||||
// rename artifacts
|
||||
groupId "${project.group}"
|
||||
if (it.name.contains('kotlinMultiplatform')) {
|
||||
artifactId = "${project.name}"
|
||||
} else {
|
||||
artifactId = "${project.name}-$name"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications.all {
|
||||
artifact javadocsJar
|
||||
|
||||
pom {
|
||||
description = "API extensions which provide work with RequestsExecutor of TelegramBotAPI almost like it is described in original Telegram Bot API reference"
|
||||
name = "Telegram Bot API Extensions for API"
|
||||
url = "https://insanusmokrassar.github.io/TelegramBotAPI/TelegramBotAPI-extensions-api"
|
||||
|
||||
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"
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,59 +1,65 @@
|
||||
apply plugin: 'com.jfrog.bintray'
|
||||
apply plugin: 'maven-publish'
|
||||
|
||||
apply from: "maven.publish.gradle"
|
||||
|
||||
bintray {
|
||||
user = project.hasProperty('BINTRAY_USER') ? project.property('BINTRAY_USER') : System.getenv('BINTRAY_USER')
|
||||
key = project.hasProperty('BINTRAY_KEY') ? project.property('BINTRAY_KEY') : System.getenv('BINTRAY_KEY')
|
||||
filesSpec {
|
||||
from "${buildDir}/publications/"
|
||||
eachFile {
|
||||
String directorySubname = it.getFile().parentFile.name
|
||||
if (it.getName() == "module.json") {
|
||||
if (directorySubname == "kotlinMultiplatform") {
|
||||
it.setPath("${project.name}/${project.version}/${project.name}-${project.version}.module")
|
||||
} else {
|
||||
it.setPath("${project.name}-${directorySubname}/${project.version}/${project.name}-${directorySubname}-${project.version}.module")
|
||||
}
|
||||
} else {
|
||||
if (directorySubname == "kotlinMultiplatform" && it.getName() == "pom-default.xml") {
|
||||
it.setPath("${project.name}/${project.version}/${project.name}-${project.version}.pom")
|
||||
} else {
|
||||
it.exclude()
|
||||
}
|
||||
}
|
||||
}
|
||||
into "${project.group}".replace(".", "/")
|
||||
}
|
||||
|
||||
publish = true
|
||||
override = true
|
||||
|
||||
pkg {
|
||||
repo = "TelegramBotAPI"
|
||||
name = "${project.name}"
|
||||
vcsUrl = "https://github.com/InsanusMokrassar/TelegramBotAPI"
|
||||
licenses = ["Apache-2.0"]
|
||||
version {
|
||||
name = "${project.version}"
|
||||
released = new Date()
|
||||
vcsTag = "${project.version}"
|
||||
gpg {
|
||||
sign = true
|
||||
passphrase = project.hasProperty('signing.gnupg.passphrase') ? project.property('signing.gnupg.passphrase') : System.getenv('signing.gnupg.passphrase')
|
||||
}
|
||||
}
|
||||
}
|
||||
task javadocsJar(type: Jar) {
|
||||
classifier = 'javadoc'
|
||||
}
|
||||
|
||||
bintrayUpload.doFirst {
|
||||
publications = publishing.publications.collect {
|
||||
afterEvaluate {
|
||||
project.publishing.publications.all {
|
||||
// rename artifacts
|
||||
groupId "${project.group}"
|
||||
if (it.name.contains('kotlinMultiplatform')) {
|
||||
null
|
||||
artifactId = "${project.name}"
|
||||
} else {
|
||||
it.name
|
||||
artifactId = "${project.name}-$name"
|
||||
}
|
||||
} - null
|
||||
}
|
||||
}
|
||||
|
||||
bintrayUpload.dependsOn publishToMavenLocal
|
||||
publishing {
|
||||
publications.all {
|
||||
artifact javadocsJar
|
||||
|
||||
pom {
|
||||
description = "API extensions which provide work with RequestsExecutor of TelegramBotAPI almost like it is described in original Telegram Bot API reference"
|
||||
name = "Telegram Bot API Extensions for API"
|
||||
url = "https://insanusmokrassar.github.io/TelegramBotAPI/TelegramBotAPI-extensions-api"
|
||||
|
||||
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')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package dev.inmo.tgbotapi.extensions.api
|
||||
|
||||
import dev.inmo.tgbotapi.bot.TelegramBot
|
||||
import dev.inmo.tgbotapi.utils.TelegramAPIUrlsKeeper
|
||||
import dev.inmo.tgbotapi.utils.telegramBotAPIDefaultUrl
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.client.HttpClientConfig
|
||||
import io.ktor.client.engine.*
|
||||
@@ -36,10 +37,11 @@ data class BotBuilder internal constructor(
|
||||
* @return Created by [telegramBotWithCustomClientConfig] function [TelegramBot]. This executor will be preconfigured using [token] and
|
||||
* [block]
|
||||
*/
|
||||
fun telegramBot(
|
||||
fun buildBot(
|
||||
token: String,
|
||||
apiUrl: String = telegramBotAPIDefaultUrl,
|
||||
block: BotBuilder.() -> Unit
|
||||
): TelegramBot = telegramBot(
|
||||
TelegramAPIUrlsKeeper(token),
|
||||
) = telegramBot(
|
||||
TelegramAPIUrlsKeeper(token, apiUrl),
|
||||
BotBuilder().apply(block).createHttpClient()
|
||||
)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package dev.inmo.tgbotapi.extensions.api
|
||||
|
||||
import dev.inmo.tgbotapi.bot.Ktor.KtorRequestsExecutorBuilder
|
||||
import dev.inmo.tgbotapi.bot.Ktor.telegramBot
|
||||
import dev.inmo.tgbotapi.bot.TelegramBot
|
||||
import dev.inmo.tgbotapi.utils.TelegramAPIUrlsKeeper
|
||||
import dev.inmo.tgbotapi.utils.telegramBotAPIDefaultUrl
|
||||
@@ -8,23 +8,13 @@ import io.ktor.client.HttpClient
|
||||
import io.ktor.client.HttpClientConfig
|
||||
import io.ktor.client.engine.*
|
||||
|
||||
/**
|
||||
* Allows to create bot using bot [urlsKeeper]
|
||||
*/
|
||||
@Deprecated("Replaced in core", ReplaceWith("telegramBot", "dev.inmo.tgbotapi.bot.Ktor.telegramBot"))
|
||||
fun telegramBot(
|
||||
urlsKeeper: TelegramAPIUrlsKeeper
|
||||
): TelegramBot = dev.inmo.tgbotapi.bot.Ktor.telegramBot(
|
||||
urlsKeeper
|
||||
)
|
||||
|
||||
/**
|
||||
* Allows to create bot using bot [urlsKeeper] and already prepared [client]
|
||||
*/
|
||||
fun telegramBot(
|
||||
urlsKeeper: TelegramAPIUrlsKeeper,
|
||||
client: HttpClient
|
||||
): TelegramBot = dev.inmo.tgbotapi.bot.Ktor.telegramBot(urlsKeeper) {
|
||||
): TelegramBot = telegramBot(urlsKeeper) {
|
||||
this.client = client
|
||||
}
|
||||
|
||||
@@ -69,16 +59,6 @@ inline fun telegramBot(
|
||||
HttpClient(clientConfig)
|
||||
)
|
||||
|
||||
/**
|
||||
* Allows to create bot using bot [token], [apiUrl] (for custom api servers) and already prepared [client]
|
||||
*/
|
||||
@Deprecated("Replaced in core", ReplaceWith("telegramBot", "dev.inmo.tgbotapi.bot.Ktor.telegramBot"))
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
inline fun telegramBot(
|
||||
token: String,
|
||||
apiUrl: String = telegramBotAPIDefaultUrl
|
||||
): TelegramBot = dev.inmo.tgbotapi.bot.Ktor.telegramBot(token, apiUrl)
|
||||
|
||||
/**
|
||||
* Allows to create bot using bot [token], [apiUrl] (for custom api servers) and already prepared [client]
|
||||
*/
|
||||
@@ -130,37 +110,3 @@ inline fun telegramBot(
|
||||
TelegramAPIUrlsKeeper(token, apiUrl),
|
||||
clientConfig
|
||||
)
|
||||
|
||||
/**
|
||||
* Allows to create bot using bot [urlsKeeper] and specify [HttpClientEngine] by passing [clientEngine] param and optionally
|
||||
* configure [HttpClient] using [clientConfig]
|
||||
*/
|
||||
@Deprecated("Will be removed in next releases", ReplaceWith("telegramBot", "dev.inmo.tgbotapi.extensions.api.telegramBot"))
|
||||
fun telegramBotWithCustomClientConfig(
|
||||
urlsKeeper: TelegramAPIUrlsKeeper,
|
||||
clientEngine: HttpClientEngine,
|
||||
clientConfig: HttpClientConfig<*>.() -> Unit
|
||||
): TelegramBot = telegramBot(
|
||||
urlsKeeper,
|
||||
HttpClient(clientEngine, clientConfig)
|
||||
)
|
||||
|
||||
/**
|
||||
* Allows to create bot using bot [urlsKeeper] and optionally configure [HttpClient] using [clientConfig]
|
||||
*/
|
||||
@Deprecated("Will be removed in next releases", ReplaceWith("telegramBot", "dev.inmo.tgbotapi.extensions.api.telegramBot"))
|
||||
fun telegramBotWithCustomClientConfig(
|
||||
urlsKeeper: TelegramAPIUrlsKeeper,
|
||||
clientConfig: HttpClientConfig<*>.() -> Unit
|
||||
): TelegramBot = telegramBot(
|
||||
urlsKeeper,
|
||||
HttpClient(clientConfig)
|
||||
)
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
@Deprecated("Renamed", ReplaceWith("telegramBot", "dev.inmo.tgbotapi.extensions.api.telegramBot"))
|
||||
inline fun telegramBotWithCustomClientConfig(
|
||||
token: String,
|
||||
apiUrl: String = telegramBotAPIDefaultUrl,
|
||||
noinline clientConfig: HttpClientConfig<*>.() -> Unit
|
||||
) = telegramBot(token, apiUrl = apiUrl, clientConfig = clientConfig)
|
||||
|
||||
@@ -5,7 +5,6 @@ import dev.inmo.tgbotapi.requests.chat.modify.UnpinChatMessage
|
||||
import dev.inmo.tgbotapi.types.ChatIdentifier
|
||||
import dev.inmo.tgbotapi.types.MessageIdentifier
|
||||
import dev.inmo.tgbotapi.types.chat.abstracts.Chat
|
||||
import dev.inmo.tgbotapi.types.chat.abstracts.PublicChat
|
||||
import dev.inmo.tgbotapi.types.message.abstracts.Message
|
||||
|
||||
suspend fun TelegramBot.unpinChatMessage(
|
||||
|
||||
@@ -2,12 +2,7 @@ package dev.inmo.tgbotapi.extensions.api.send
|
||||
|
||||
import dev.inmo.tgbotapi.bot.TelegramBot
|
||||
import dev.inmo.tgbotapi.requests.send.SendVenue
|
||||
import dev.inmo.tgbotapi.types.ChatIdentifier
|
||||
import dev.inmo.tgbotapi.types.FoursquareId
|
||||
import dev.inmo.tgbotapi.types.FoursquareType
|
||||
import dev.inmo.tgbotapi.types.GooglePlaceId
|
||||
import dev.inmo.tgbotapi.types.GooglePlaceType
|
||||
import dev.inmo.tgbotapi.types.MessageIdentifier
|
||||
import dev.inmo.tgbotapi.types.*
|
||||
import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup
|
||||
import dev.inmo.tgbotapi.types.chat.abstracts.Chat
|
||||
import dev.inmo.tgbotapi.types.location.StaticLocation
|
||||
|
||||
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"}]}}
|
||||
@@ -3,6 +3,9 @@ apply plugin: 'maven-publish'
|
||||
task javadocsJar(type: Jar) {
|
||||
classifier = 'javadoc'
|
||||
}
|
||||
task sourceJar (type : Jar) {
|
||||
classifier = 'sources'
|
||||
}
|
||||
|
||||
afterEvaluate {
|
||||
project.publishing.publications.all {
|
||||
@@ -10,6 +13,7 @@ afterEvaluate {
|
||||
groupId "${project.group}"
|
||||
if (it.name.contains('kotlinMultiplatform')) {
|
||||
artifactId = "${project.name}"
|
||||
artifact sourceJar
|
||||
} else {
|
||||
artifactId = "${project.name}-$name"
|
||||
}
|
||||
@@ -21,9 +25,9 @@ publishing {
|
||||
artifact javadocsJar
|
||||
|
||||
pom {
|
||||
description = "Library for Object-Oriented and type-safe work with Telegram Bot API"
|
||||
name = "Telegram Bot API Core"
|
||||
url = "https://insanusmokrassar.github.io/TelegramBotAPI"
|
||||
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"
|
||||
@@ -49,5 +53,17 @@ publishing {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
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,54 @@
|
||||
package dev.inmo.tgbotapi.extensions.behaviour_builder
|
||||
|
||||
import dev.inmo.tgbotapi.bot.TelegramBot
|
||||
import dev.inmo.tgbotapi.extensions.utils.updates.retrieving.longPolling
|
||||
import dev.inmo.tgbotapi.extensions.utils.updates.retrieving.startGettingOfUpdatesByLongPolling
|
||||
import dev.inmo.tgbotapi.updateshandlers.FlowsUpdatesFilter
|
||||
import dev.inmo.tgbotapi.utils.PreviewFeature
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
|
||||
/**
|
||||
* Use this method in case you wish to make some additional actions with [flowUpdatesFilter].
|
||||
*
|
||||
* **WARNING** This method WILL NOT launch any listening of updates. Use something like
|
||||
* [startGettingOfUpdatesByLongPolling] or tools for work with webhooks
|
||||
*
|
||||
* @see [BehaviourContext]
|
||||
* @see startGettingOfUpdatesByLongPolling
|
||||
*/
|
||||
@PreviewFeature
|
||||
suspend fun TelegramBot.buildBehaviour(
|
||||
scope: CoroutineScope,
|
||||
flowUpdatesFilter: FlowsUpdatesFilter,
|
||||
block: BehaviourContextReceiver<Unit>
|
||||
) {
|
||||
BehaviourContext(
|
||||
this,
|
||||
scope,
|
||||
flowUpdatesFilter
|
||||
).block()
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this method to build bot behaviour and run it via long polling. In case you wish to get [FlowsUpdatesFilter] for
|
||||
* additional manipulations, you must provide external [FlowsUpdatesFilter] in other [buildBehaviour] function.
|
||||
*
|
||||
* @see buildBehaviour
|
||||
* @see BehaviourContext
|
||||
* @see startGettingOfUpdatesByLongPolling
|
||||
*/
|
||||
@PreviewFeature
|
||||
suspend fun TelegramBot.buildBehaviour(
|
||||
scope: CoroutineScope,
|
||||
block: BehaviourContextReceiver<Unit>
|
||||
) = FlowsUpdatesFilter().let {
|
||||
buildBehaviour(
|
||||
scope,
|
||||
it,
|
||||
block
|
||||
)
|
||||
longPolling(
|
||||
it,
|
||||
scope = scope
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
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
|
||||
|
||||
/**
|
||||
* This class contains all necessary tools for work with bots and especially for [buildBehaviour]
|
||||
*
|
||||
* @param scope This param will be used for creating of some subscriptions inside of methods, updates listening and
|
||||
* different other things in context of working with [CoroutineScope] and coroutines.
|
||||
* @param flowsUpdatesFilter This parameter will be used to subscribe on different types of update
|
||||
*/
|
||||
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,124 @@
|
||||
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 dev.inmo.tgbotapi.utils.lowLevelRiskFeatureMessage
|
||||
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(lowLevelRiskFeatureMessage)
|
||||
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(lowLevelRiskFeatureMessage)
|
||||
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,196 @@
|
||||
@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.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.asSentMediaGroupUpdate
|
||||
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,75 @@
|
||||
@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.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.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)
|
||||
|
||||
@@ -8,7 +8,6 @@ buildscript {
|
||||
dependencies {
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
|
||||
classpath "com.jfrog.bintray.gradle:gradle-bintray-plugin:$gradle_bintray_plugin_version"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user