1
0
mirror of https://github.com/InsanusMokrassar/TelegramBotAPI.git synced 2026-07-01 15:45:31 +00:00

Compare commits

..

33 Commits

Author SHA1 Message Date
renovate[bot]
6fc794c229 Update kotlin to v2.4.0 2026-07-01 12:02:09 +00:00
c7761fd294 Merge pull request #1053 from InsanusMokrassar/35.1.0
35.1.0
2026-07-01 18:01:07 +06:00
0e9f9111eb Update dependencies and migrate to Gradle 9 / Dokka v2
Dependency bumps: Kotlin 2.3.20->2.3.21, Coroutines 1.10.2->1.11.0,
Ktor 3.4.2->3.5.1, KSP 2.3.6->2.3.9, MicroUtils 0.29.2->0.30.0,
Dokka 2.0.0->2.2.0, Versions plugin 0.53.0->0.54.0, NMCP 1.4.4->1.6.0.

Gradle wrapper 8.13->9.6.1 with build-script fixes for Gradle 9:
Project.exec() -> providers.exec(), tasks.whenTaskAdded -> tasks.configureEach.

Dokka migrated to the Dokka Gradle Plugin v2. The docs module is now
included as the KDocs aggregator (dokka {} DSL with sourceRoots, new URI,
ProcessIsolation heap for the generator worker), excluded from binary
compatibility validation, and the kdocs workflow runs :docs:dokkaGenerate.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 17:54:13 +06:00
763b07fc3c start 35.1.0 2026-07-01 16:08:25 +06:00
481a3b4ff1 Merge pull request #1052 from InsanusMokrassar/35.0.0
35.0.0
2026-07-01 15:43:02 +06:00
fc764d1f95 add note about support of telegram bot api 10.1 and fix changelogs 2026-07-01 15:42:11 +06:00
68987feabb improve richblocks api and let rich message content to be correctly resendable if there are no any media block inside 2026-07-01 14:25:39 +06:00
5341b2eccf apiDump 2026-07-01 13:27:09 +06:00
7e4efcd645 rewrite RichMessageContent.createResend onto sending of simple rich message 2026-07-01 12:52:55 +06:00
390770ca80 refactor/fixes in rich parts 2026-07-01 12:46:16 +06:00
b054f3d1b5 Revert "Modify markdown function to add newlines"
This reverts commit 3a05a88d4f.
2026-07-01 11:25:43 +06:00
3a05a88d4f Modify markdown function to add newlines 2026-07-01 01:16:36 +06:00
edad79ace8 Add HELPERS rules: work in main worktree, one subagent per subtask
Document two working rules: all work must be done in the normal (main)
worktree rather than a separate `.claude/worktrees` worktree, and a prompt
that lists several subtasks must run each subtask as its own subagent.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 22:33:33 +06:00
c3495d8817 Add HELPERS rule preferring members over when-dispatch extensions
Document that a property/method which can live on an interface/class must be
declared there and overridden per implementation, instead of a common
extension that dispatches with a when over every subtype; shared logic goes
into a companion-object function or an internal top-level helper.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 22:01:20 +06:00
88a54350df Rename RichText source to rawText and move it into members
Replace the RichText.source extension property (a when over every subtype)
with a rawText member declared on RichText and implemented directly by each
inheritor: RichTextPlain.rawText = text, the wrapping entities delegate to
text.rawText, and custom emoji / mathematical expression / anchor fall back
to their own representation. Update the RichBlockPreformatted and media
markdown builders and the formatting tests accordingly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 21:59:18 +06:00
8acd7453a6 Move rich markdown and html bodies into companion objects
For every RichText and RichBlock type the markdown and html rendering now
lives in companion-object functions taking the relevant fields, and the
property overrides are plain value initializers that reuse those functions
(e.g. RichTextEmailAddress.markdown(text, emailAddress)). Class-specific
render helpers (list, table, map, block quotation, details open attribute)
move into the matching companions; helpers shared across several types
(credit cite, media and media container rendering) stay internal top-level
functions.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 21:41:32 +06:00
e793eea943 Move RichText/RichBlock markdown and html into members
Add markdown and html as members of the RichText and RichBlock sealed
interfaces and override them in every inheritor (RichTextPlain,
RichTextGroup and all 21 RichBlock subtypes), mirroring the existing
RichTextEntity implementation. The former RichText/RichBlock.markdown
and .html extension properties (which dispatched via a when over each
subtype) are removed; the shared RichBlock render helpers become
internal so the overrides can reuse them.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 20:55:46 +06:00
6b4999095e Add rich text / rich block DSL builder
Add a type-safe Kotlin DSL for building rich messages:
* buildRichText { } - RichTextBuilder with plain() plus a function for every
  RichTextEntity (String and nested RichTextBuilder overloads where text-bearing);
* buildRichBlocks { } / buildRichTextInfo { } - RichBlocksBuilder with the
  text-bearing and container blocks (paragraph, heading, list, blockQuotation,
  details, ...), nesting RichText or further blocks per block kind;
* RichBlockListBuilder for list items.

Container blocks expose nested block/text builders; file/cell-heavy blocks (media,
table, collage, slideshow, map) are appended via add() / unary plus. A
@DslMarker (RichTextDsl) keeps the nested scopes from leaking receivers.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 17:29:47 +06:00
23578d25ef Add rich block markdown and html source builders
Add List<RichBlock>.toRichMarkdown() / toRichHtml() (and per-block RichBlock
.markdown / .html plus RichTextInfo.markdown / .html convenience) that render the
Rich Markdown style and Rich HTML style source strings for a whole rich message,
ready to feed into InputRichMessageMarkdown / InputRichMessageHTML.

All 21 block types are covered, including lists (bullet/ordered/task), tables,
block/pull quotations, details, collages, slideshows, maps and media. Media
blocks use the Telegram file_id as the source (documented), since Telegram only
accepts HTTP(S) URLs for rich media and the parsed model carries no public URL.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 17:21:19 +06:00
b5238320a5 Add tests for rich text entity markdown and html
Cover markdown and html output of all 25 RichTextEntity subtypes plus the
recursive RichText.markdown / RichText.html / RichText.source extensions
(nested groups, plain-text escaping, plain-text extraction).

Note: plainHtmlEscapesAngleBrackets asserts the current String.toHtml()
behaviour, which escapes '&' last and therefore over-escapes '<'/'>' (e.g.
"a<b" -> "a&amp;lt;b"). This matches the rest of the library's HTML output.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 17:11:14 +06:00
4cfc054526 Implement markdown and html for RichTextEntity inheritors
Add Rich Markdown style and Rich HTML style serialization for every
RichTextEntity subtype, following the Bot API rich formatting spec
(https://core.telegram.org/bots/api#rich-markdown-style and #rich-html-style).

New RichTextFormatting.kt provides:
* String.escapeRichMarkdown() escaping the rich-markdown special characters;
* RichText.source - plain unformatted text of any RichText;
* RichText.markdown / RichText.html - recursive dispatch over RichTextPlain,
  RichTextGroup and RichTextEntity so inner texts render correctly.

Each of the 25 entity types now overrides markdown and html. Auto-detected
entities (mention, hashtag, cashtag, bank card, bot command) emit their visible
text; the rest wrap inner text in the corresponding markers/tags.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 17:02:03 +06:00
1091dbdb5e Rename RichMessage -> RichTextInfo
The Telegram type backing rich-formatted message info is RichMessage, but the
class name collided conceptually with the in-progress rich-message builders.
Rename the data class (and its file) to RichTextInfo and update all references
(RawMessage, RichMessageContent, serialization test) plus the API dump.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 16:56:58 +06:00
313fcb3325 fix of sendrichmessagedraft 2026-06-29 23:37:14 +06:00
1c06ec8687 apiDump 2026-06-29 17:04:03 +06:00
9fc80fdd4d Fix RichTextBotCommand SerialName to bot_command
RichTextBotCommand.botCommand reused botCommandField ("command", shared
with BotCommand.command) but Bot API docs require "bot_command". Add
botCommandFullField = "bot_command" and switch RichTextBotCommand to it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 16:17:56 +06:00
df5018ecf5 Make ChatJoinRequestQueryResult inheritors data objects + serializable
- Approve/Decline/Queue are now data object
- each inheritor (and Unknown) annotated with the shared
  ChatJoinRequestQueryResult.Companion serializer
- companion PrimitiveSerialDescriptor serial name is "ChatJoinRequestQueryResult"

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 18:49:42 +06:00
0188c65319 Rework ChatJoinRequestQueryResult + EditChatMessageText nullable text
- ChatJoinRequestQueryResult: enum -> sealed interface (Approve/Decline/
  Queue objects + Unknown) with a companion KSerializer using a
  PrimitiveKind.STRING descriptor (encodeString/decodeString), not
  String.serializer()
- EditChatMessageText: text is now nullable per API; add EditChatMessageRichText
  factory for rich edits; widen EditTextChatMessage.text to String?

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 18:42:25 +06:00
c2b1a5d44b Add behaviour-builder coverage for receiving Rich Messages
- onRichMessage trigger (ContentTriggers)
- waitRichMessage / waitRichMessageMessage expectations
- Flow<ContentMessage<*>>.onlyRichMessageContentMessages() util

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 17:52:10 +06:00
6bdd217530 Add Bot API 10.1 Rich Messages support
Adds the full Rich Messages type system and methods:
- RichText hierarchy: RichTextPlain, RichTextGroup, RichTextEntity and all
  24 RichText* entity types, with a recursive serializer handling plain
  strings, arrays and typed objects
- RichBlock hierarchy: all 21 RichBlock* types plus RichBlockCaption,
  RichBlockTableCell and RichBlockListItem (JsonContentPolymorphic by type)
- RichMessage type and RichMessageContent message content; rich_message
  parsed in RawMessage; RichMessageContentMessage typealias
- InputRichMessage (internal constructor + InputRichMessageHTML /
  InputRichMessageMarkdown factories) and InputRichMessageContent usable as
  InputMessageContent
- SendRichMessage and SendRichMessageDraft requests with API bindings
- richMessage parameter on EditChatMessageText
- Serialization round-trip test for RichMessage/RichText/RichBlock

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 17:32:56 +06:00
f6d5b3ea71 Add Bot API 10.1 Join Request Queries support
Adds:
- ChatJoinRequestQueryId value class and ChatJoinRequest.queryId field
- ExtendedBot.supportsJoinRequestQueries (User.supports_join_request_queries)
- ExtendedChat.guardBot (ChatFullInfo.guard_bot), parsed for public chats
- AnswerChatJoinRequestQuery request + ChatJoinRequestQueryResult enum
- SendChatJoinRequestWebApp request
- answerChatJoinRequestQuery / sendChatJoinRequestWebApp TelegramBot extensions

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 17:03:26 +06:00
628e877064 Add Bot API 10.1 Polls support (Link, InputMediaLink)
Adds the Link type implementing PollMedia (the url attached to a poll
option), parses the new `link` field in PollMedia, and adds
TelegramMediaLink (InputMediaLink) usable as InputPollOptionMedia.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 16:53:59 +06:00
8ba13ea5fc start 35.0.0 2026-06-19 16:27:54 +06:00
b8e995f36d Merge pull request #1047 from InsanusMokrassar/34.0.0
34.0.0
2026-06-13 14:34:21 +06:00
62 changed files with 9292 additions and 2808 deletions

View File

@@ -12,10 +12,10 @@ jobs:
with:
java-version: 17
- name: Build
run: ./gradlew dokkaHtmlMultiModule
run: ./gradlew :docs:dokkaGenerate
- name: Publish KDocs
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./build/dokka/htmlMultiModule
publish_dir: ./docs/build/dokka/html
publish_branch: kdocs

View File

@@ -1,5 +1,58 @@
# TelegramBotAPI changelog
## 35.1.0
* `Dependencies`:
* `Kotlin`: `2.3.20` -> `2.3.21`
* `Coroutines`: `1.10.2` -> `1.11.0`
* `Ktor`: `3.4.2` -> `3.5.1`
* `KSP`: `2.3.6` -> `2.3.9`
* `MicroUtils`: `0.29.2` -> `0.30.0`
* `Dokka`: `2.0.0` -> `2.2.0`
* `Versions`: `0.53.0` -> `0.54.0`
* `NMCP`: `1.4.4` -> `1.6.0`
* `Build`:
* Updated Gradle wrapper `8.13` -> `9.6.1` and migrated build scripts to be Gradle 9 compatible (`Project.exec` -> `providers.exec`, `tasks.whenTaskAdded` -> `tasks.configureEach`)
* Migrated Dokka documentation to the Dokka Gradle Plugin v2: the `docs` module is now included in the build as the KDocs aggregator (`./gradlew :docs:dokkaGenerate`) and the `Publish KDocs` workflow was updated accordingly
## 35.0.0
**THIS UPDATE CONTAINS SUPPORT OF [TELEGRAM BOTS API 10.1](https://core.telegram.org/bots/api-changelog#june-11-2026)**
**Breaking changes**:
* `EditTextChatMessage.text` changed from `String` to `String?` (rich edits carry no text) — implementations overriding it must widen the type and readers must handle `null`
* `EditChatMessageText.text` changed from `String` to `String?`; its `textSources` is now `null` when there is no text — code reading `text` as non-null must handle `null`
* `ExtendedBot` gained the `supportsJoinRequestQueries` field inserted between `supportsGuestQueries` and `canConnectToBusiness` — positional constructor calls and `componentN` destructuring shift and must be updated
**Migration advice**: Handle nullable `text` on `EditTextChatMessage`/`EditChatMessageText`; construct `ExtendedBot` with named arguments
* `Core`:
* (`Rich Messages`) Added `RichText` (`RichTextPlain`, `RichTextGroup`, `RichTextEntity`) hierarchy with all 25 `RichText*` entity types and a recursive serializer supporting plain strings, arrays and typed objects; every `RichText` exposes `rawText`, `markdown` and `html` renderings
* (`Rich Messages`) Added `RichBlock` hierarchy with all 21 `RichBlock*` types plus `RichBlockCaption`, `RichBlockTableCell` and `RichBlockListItem`; every `RichBlock` exposes `markdown`/`html` source, the `RichBlockMedia` marker interface and `subBlocks`/`search` navigation helpers
* (`Rich Messages`) Added `RichTextInfo` type (with `markdown`/`html` source built from its blocks) and `RichMessageContent` message content; `RichMessageContent.createResend` re-sends the content (forwarded when it contains media blocks, otherwise re-built through `SendRichMessage`); parsed `rich_message` in `RawMessage`; added `RichMessageContentMessage` typealias
* (`Rich Messages`) Added `InputRichMessage` (internal constructor with `InputRichMessageHTML`/`InputRichMessageMarkdown` factories) and `InputRichMessageContent` usable as `InputMessageContent`
* (`Rich Messages`) Added Rich Messages DSL builders `buildRichText`/`RichTextBuilder`, `buildRichBlocks`/`RichBlocksBuilder`, `buildRichTextInfo` and `RichBlockListBuilder` (marked with the `@RichTextDsl` DSL marker)
* (`Rich Messages`) Added Rich Markdown/HTML source helpers `String.escapeRichMarkdown()` and `List<RichBlock>.toRichMarkdown()`/`toRichHtml()`
* (`Rich Messages`) Added `SendRichMessage` and `SendRichMessageDraft` requests
* (`Rich Messages`) Added `richMessage` parameter to `EditChatMessageText`; its `text` is now nullable (per API) and the `EditChatMessageRichText` factory builds a rich edit; widened `EditTextChatMessage.text` to nullable
* (`Polls`) Added `Link` type (`dev.inmo.tgbotapi.types.Link`) implementing `PollMedia`, carrying the `url` of a link attached to a poll option
* (`Polls`) Added `link` field parsing to `PollMedia` deserialization/serialization
* (`Polls`) Added `TelegramMediaLink` (`InputMediaLink`) implementing `InputPollOptionMedia`, usable as a poll option media
* (`Join Request Queries`) Added `ChatJoinRequestQueryId` value class and `queryId` field to `ChatJoinRequest`
* (`Join Request Queries`) Added `supportsJoinRequestQueries` flag to `ExtendedBot` (`User.supports_join_request_queries`)
* (`Join Request Queries`) Added `guardBot` field to `ExtendedChat` (`ChatFullInfo.guard_bot`), parsed for public chats
* (`Join Request Queries`) Added `AnswerChatJoinRequestQuery` request and `ChatJoinRequestQueryResult` sealed interface (`Approve`/`Decline`/`Queue`/`Unknown`) serialized as a plain string
* (`Join Request Queries`) Added `SendChatJoinRequestWebApp` request
* `API`:
* (`Rich Messages`) Added `sendRichMessage` and `sendRichMessageDraft` `TelegramBot` extensions
* (`Join Request Queries`) Added `answerChatJoinRequestQuery` and `sendChatJoinRequestWebApp` `TelegramBot` extensions
* `BehaviourBuilder`:
* (`Rich Messages`) Added `onRichMessage` trigger and `waitRichMessage`/`waitRichMessageMessage` expectations
* `Utils`:
* (`Rich Messages`) Added `Flow<ContentMessage<*>>.onlyRichMessageContentMessages()`
* (`Join Request Queries`) Added `ChatJoinRequest.query_id` raw accessor
## 34.0.0
**THIS UPDATE CONTAINS SUPPORT OF [TELEGRAM BOTS API 10.0](https://core.telegram.org/bots/api-changelog#may-8-2026)**

View File

@@ -1,4 +1,4 @@
# TelegramBotAPI [![Maven Central Version](https://img.shields.io/maven-central/v/dev.inmo/tgbotapi)](https://central.sonatype.com/artifact/dev.inmo/tgbotapi) [![Supported version](https://img.shields.io/badge/Telegram%20Bot%20API-10.0-blue)](https://core.telegram.org/bots/api-changelog#may-8-2026)
# TelegramBotAPI [![Maven Central Version](https://img.shields.io/maven-central/v/dev.inmo/tgbotapi)](https://central.sonatype.com/artifact/dev.inmo/tgbotapi) [![Supported version](https://img.shields.io/badge/Telegram%20Bot%20API-10.1-blue)](https://core.telegram.org/bots/api-changelog#june-11-2026)
| Docs | [![KDocs](https://img.shields.io/static/v1?label=Dokka&message=KDocs&color=blue&logo=kotlin)](https://tgbotapi.inmo.dev/index.html) [![Mini tutorial](https://img.shields.io/static/v1?label=Mk&message=Docs&color=blue&logo=mkdocs)](https://docs.inmo.dev/tgbotapi/index.html) |
|:----------------------:|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:|

View File

@@ -48,3 +48,15 @@ Each section can be ommited if there are no any changes in the section. In case
* `Core`:
* (`Guest mode`) // change data
```
---
When a property (or method) can be declared on an interface/class and implemented by each inheritor - it MUST be declared there and overridden per implementation. DO NOT implement such behaviour as a common extension property/function that dispatches with a `when (this)` over every subtype: those branches silently drift out of sync when new subtypes are added and are not part of the type contract. If a part of the implementation is reused across several inheritors, keep that part in a shared helper (a companion-object function of the owner, or an `internal` top-level function for logic shared between different types) and let the overrides reuse it.
---
All work MUST be performed in the normal (main) working worktree of the repository. DO NOT create or do the work inside a separate worktree (for example `.claude/worktrees/...`): commits made there leave the main checkout behind and force an extra fast-forward/pull to land the changes. If some environment forces an isolated worktree, fast-forward the main branch onto those commits and continue in the main worktree.
---
When a prompt contains a list of several subtasks, run each subtask as its own subagent (one subagent per subtask) instead of doing all of them inline in the main thread.

View File

@@ -21,6 +21,11 @@ plugins {
alias(libs.plugins.nmcp.aggregation)
}
// docs is a dokka-only aggregator module, exclude it from binary compatibility validation
apiValidation {
ignoredProjects += ["docs"]
}
if ((project.hasProperty('SONATYPE_USER') || System.getenv('SONATYPE_USER') != null) && (project.hasProperty('SONATYPE_PASSWORD') || System.getenv('SONATYPE_PASSWORD') != null)) {
nmcpAggregation {
@@ -44,7 +49,7 @@ allprojects {
mavenLocal()
}
if (it != rootProject.findProject("docs")) {
tasks.whenTaskAdded { task ->
tasks.configureEach { task ->
if(task.name == "jsLegacyBrowserTest" || task.name == "jsLegacyNodeTest") {
task.enabled = false
}
@@ -54,13 +59,9 @@ allprojects {
apply from: "./extensions.gradle"
private String getCurrentVersionChangelog() {
OutputStream changelogDataOS = new ByteArrayOutputStream()
exec {
standardOutput = changelogDataOS
return providers.exec {
commandLine './changelog_info_retriever', "$library_version", 'CHANGELOG.md'
}
return changelogDataOS.toString().trim()
}.standardOutput.asText.get().trim()
}

View File

@@ -39,14 +39,10 @@ private List<SourceDirectorySet> findSourcesWithName(String... approximateNames)
}.collect { it.kotlin }
}
Object callback = {
switch (true) {
case project.hasProperty("DOKKA_PATH"):
outputDirectory = project.property("DOKKA_PATH").toString()
break
case System.getenv("DOKKA_PATH") != null:
outputDirectory = System.getenv("DOKKA_PATH")
break
dokka {
// aggregating every module's sources into one publication needs more heap than the worker default
dokkaGeneratorIsolation = ProcessIsolation {
it.maxHeapSize.set("4g")
}
dokkaSourceSets {
@@ -55,7 +51,7 @@ Object callback = {
sourceLink {
localDirectory.set(file("../"))
remoteUrl.set(new URL("https://github.com/InsanusMokrassar/ktgbotapi"))
remoteUrl.set(new URI("https://github.com/InsanusMokrassar/ktgbotapi"))
remoteLineSuffix.set("#L")
}
}
@@ -73,6 +69,3 @@ Object callback = {
}
}
}
tasks.dokkaGfm(callback)
tasks.dokkaHtml(callback)

View File

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

View File

@@ -1,28 +1,28 @@
[versions]
kotlin = "2.3.20"
kotlin = "2.4.0"
kotlin-serialization = "1.11.0"
kotlin-coroutines = "1.10.2"
kotlin-coroutines = "1.11.0"
javax-activation = "1.1.1"
korlibs = "5.4.0"
uuid = "0.8.4"
ktor = "3.4.2"
ktor = "3.5.1"
ksp = "2.3.6"
ksp = "2.3.9"
kotlin-poet = "2.3.0"
microutils = "0.29.2"
microutils = "0.30.0"
kslog = "1.6.1"
versions = "0.53.0"
versions = "0.54.0"
github-release-plugin = "2.5.2"
dokka = "2.0.0"
dokka = "2.2.0"
validator = "0.18.1"
nmcp = "1.4.4"
nmcp = "1.6.0"
[libraries]

Binary file not shown.

View File

@@ -1,5 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-9.6.1-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip

315
gradlew vendored
View File

@@ -1,78 +1,129 @@
#!/usr/bin/env sh
#!/bin/sh
#
# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0
#
##############################################################################
##
## Gradle start up script for UN*X
##
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
MAX_FD=maximum
warn ( ) {
warn () {
echo "$*"
}
} >&2
die ( ) {
die () {
echo
echo "$*"
echo
exit 1
}
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD="$JAVA_HOME/bin/java"
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
@@ -81,92 +132,120 @@ Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
JAVACMD=java
if ! command -v java >/dev/null 2>&1
then
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Escape application args
save ( ) {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=$(save "$@")
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
die "xargs is not available"
fi
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"

78
gradlew.bat vendored
View File

@@ -1,4 +1,22 @@
@if "%DEBUG%" == "" @echo off
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@rem SPDX-License-Identifier: Apache-2.0
@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@@ -9,25 +27,29 @@
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
@@ -35,48 +57,36 @@ goto fail
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal

View File

@@ -1,11 +1,4 @@
pluginManagement {
resolutionStrategy {
eachPlugin {
if (requested.id.id == "org.jetbrains.dokka") {
useModule("org.jetbrains.dokka:dokka-gradle-plugin:${requested.version}")
}
}
}
repositories {
gradlePluginPortal()
}
@@ -19,3 +12,4 @@ include ":tgbotapi.behaviour_builder"
include ":tgbotapi.behaviour_builder.fsm"
include ":tgbotapi"
include ":tgbotapi.webapps"
include ":docs"

View File

@@ -562,6 +562,12 @@ public final class dev/inmo/tgbotapi/extensions/api/chat/get/GetForumTopicIconSt
public static final fun getForumTopicIconStickers (Ldev/inmo/tgbotapi/bot/RequestsExecutor;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
}
public final class dev/inmo/tgbotapi/extensions/api/chat/invite_links/AnswerChatJoinRequestQueryKt {
public static final fun answerChatJoinRequestQuery (Ldev/inmo/tgbotapi/bot/RequestsExecutor;Ldev/inmo/tgbotapi/types/chat/ChatJoinRequest;Ldev/inmo/tgbotapi/requests/chat/invite_links/ChatJoinRequestQueryResult;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public static final fun answerChatJoinRequestQuery (Ldev/inmo/tgbotapi/bot/RequestsExecutor;Ldev/inmo/tgbotapi/types/update/ChatJoinRequestUpdate;Ldev/inmo/tgbotapi/requests/chat/invite_links/ChatJoinRequestQueryResult;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public static final fun answerChatJoinRequestQuery-Vwi-J50 (Ldev/inmo/tgbotapi/bot/RequestsExecutor;Ljava/lang/String;Ldev/inmo/tgbotapi/requests/chat/invite_links/ChatJoinRequestQueryResult;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
}
public final class dev/inmo/tgbotapi/extensions/api/chat/invite_links/ApproveChatJoinRequestKt {
public static final fun approve (Ldev/inmo/tgbotapi/bot/RequestsExecutor;Ldev/inmo/tgbotapi/types/chat/ChatJoinRequest;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public static final fun approveChatJoinRequest (Ldev/inmo/tgbotapi/bot/RequestsExecutor;Ldev/inmo/tgbotapi/types/ChatIdentifier;Ldev/inmo/tgbotapi/types/IdChatIdentifier;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
@@ -687,6 +693,12 @@ public final class dev/inmo/tgbotapi/extensions/api/chat/invite_links/RevokeChat
public static final fun revokeChatInviteLink (Ldev/inmo/tgbotapi/bot/RequestsExecutor;Ldev/inmo/tgbotapi/types/chat/PublicChat;Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
}
public final class dev/inmo/tgbotapi/extensions/api/chat/invite_links/SendChatJoinRequestWebAppKt {
public static final fun sendChatJoinRequestWebApp (Ldev/inmo/tgbotapi/bot/RequestsExecutor;Ldev/inmo/tgbotapi/types/chat/ChatJoinRequest;Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public static final fun sendChatJoinRequestWebApp (Ldev/inmo/tgbotapi/bot/RequestsExecutor;Ldev/inmo/tgbotapi/types/update/ChatJoinRequestUpdate;Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public static final fun sendChatJoinRequestWebApp-Vwi-J50 (Ldev/inmo/tgbotapi/bot/RequestsExecutor;Ljava/lang/String;Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
}
public final class dev/inmo/tgbotapi/extensions/api/chat/members/BanChatMemberKt {
public static final fun banChatMember (Ldev/inmo/tgbotapi/bot/RequestsExecutor;Ldev/inmo/tgbotapi/types/ChatIdentifier;Ldev/inmo/tgbotapi/types/IdChatIdentifier;Ldev/inmo/tgbotapi/types/TelegramDate;Ljava/lang/Boolean;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public static final fun banChatMember (Ldev/inmo/tgbotapi/bot/RequestsExecutor;Ldev/inmo/tgbotapi/types/IdChatIdentifier;Ldev/inmo/tgbotapi/types/chat/User;Ldev/inmo/tgbotapi/types/TelegramDate;Ljava/lang/Boolean;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
@@ -1950,6 +1962,18 @@ public final class dev/inmo/tgbotapi/extensions/api/send/SendMessageKt {
public static synthetic fun sendTextMessage-kPvWKIg$default (Ldev/inmo/tgbotapi/bot/RequestsExecutor;Ldev/inmo/tgbotapi/types/chat/Chat;Ljava/lang/String;Ldev/inmo/tgbotapi/types/message/ParseMode;Ldev/inmo/tgbotapi/types/LinkPreviewOptions;Ldev/inmo/tgbotapi/types/MessageThreadId;Ldev/inmo/tgbotapi/types/DirectMessageThreadId;Ljava/lang/String;ZZZLjava/lang/String;Ldev/inmo/tgbotapi/types/message/SuggestedPostParameters;Ldev/inmo/tgbotapi/types/ReplyParameters;Ldev/inmo/tgbotapi/types/buttons/KeyboardMarkup;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object;
}
public final class dev/inmo/tgbotapi/extensions/api/send/SendRichMessageDraftKt {
public static final fun sendRichMessageDraft-tvXF6p8 (Ldev/inmo/tgbotapi/bot/RequestsExecutor;JJLdev/inmo/tgbotapi/types/rich/InputRichMessage;Ldev/inmo/tgbotapi/types/MessageThreadId;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public static synthetic fun sendRichMessageDraft-tvXF6p8$default (Ldev/inmo/tgbotapi/bot/RequestsExecutor;JJLdev/inmo/tgbotapi/types/rich/InputRichMessage;Ldev/inmo/tgbotapi/types/MessageThreadId;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object;
}
public final class dev/inmo/tgbotapi/extensions/api/send/SendRichMessageKt {
public static final fun sendRichMessage-mNzvAxs (Ldev/inmo/tgbotapi/bot/RequestsExecutor;Ldev/inmo/tgbotapi/types/ChatIdentifier;Ldev/inmo/tgbotapi/types/rich/InputRichMessage;Ldev/inmo/tgbotapi/types/MessageThreadId;Ldev/inmo/tgbotapi/types/DirectMessageThreadId;Ljava/lang/String;ZZZLjava/lang/String;Ldev/inmo/tgbotapi/types/message/SuggestedPostParameters;Ldev/inmo/tgbotapi/types/ReplyParameters;Ldev/inmo/tgbotapi/types/buttons/KeyboardMarkup;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public static final fun sendRichMessage-mNzvAxs (Ldev/inmo/tgbotapi/bot/RequestsExecutor;Ldev/inmo/tgbotapi/types/chat/Chat;Ldev/inmo/tgbotapi/types/rich/InputRichMessage;Ldev/inmo/tgbotapi/types/MessageThreadId;Ldev/inmo/tgbotapi/types/DirectMessageThreadId;Ljava/lang/String;ZZZLjava/lang/String;Ldev/inmo/tgbotapi/types/message/SuggestedPostParameters;Ldev/inmo/tgbotapi/types/ReplyParameters;Ldev/inmo/tgbotapi/types/buttons/KeyboardMarkup;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public static synthetic fun sendRichMessage-mNzvAxs$default (Ldev/inmo/tgbotapi/bot/RequestsExecutor;Ldev/inmo/tgbotapi/types/ChatIdentifier;Ldev/inmo/tgbotapi/types/rich/InputRichMessage;Ldev/inmo/tgbotapi/types/MessageThreadId;Ldev/inmo/tgbotapi/types/DirectMessageThreadId;Ljava/lang/String;ZZZLjava/lang/String;Ldev/inmo/tgbotapi/types/message/SuggestedPostParameters;Ldev/inmo/tgbotapi/types/ReplyParameters;Ldev/inmo/tgbotapi/types/buttons/KeyboardMarkup;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object;
public static synthetic fun sendRichMessage-mNzvAxs$default (Ldev/inmo/tgbotapi/bot/RequestsExecutor;Ldev/inmo/tgbotapi/types/chat/Chat;Ldev/inmo/tgbotapi/types/rich/InputRichMessage;Ldev/inmo/tgbotapi/types/MessageThreadId;Ldev/inmo/tgbotapi/types/DirectMessageThreadId;Ljava/lang/String;ZZZLjava/lang/String;Ldev/inmo/tgbotapi/types/message/SuggestedPostParameters;Ldev/inmo/tgbotapi/types/ReplyParameters;Ldev/inmo/tgbotapi/types/buttons/KeyboardMarkup;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object;
}
public final class dev/inmo/tgbotapi/extensions/api/send/SendStaticLocationKt {
public static final fun sendLocation-Z2YO6e4 (Ldev/inmo/tgbotapi/bot/RequestsExecutor;Ldev/inmo/tgbotapi/types/ChatIdentifier;DDLdev/inmo/tgbotapi/types/MessageThreadId;Ldev/inmo/tgbotapi/types/DirectMessageThreadId;Ljava/lang/String;ZZZLjava/lang/String;Ldev/inmo/tgbotapi/types/message/SuggestedPostParameters;Ldev/inmo/tgbotapi/types/ReplyParameters;Ldev/inmo/tgbotapi/types/buttons/KeyboardMarkup;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public static final fun sendLocation-Z2YO6e4 (Ldev/inmo/tgbotapi/bot/RequestsExecutor;Ldev/inmo/tgbotapi/types/chat/Chat;DDLdev/inmo/tgbotapi/types/MessageThreadId;Ldev/inmo/tgbotapi/types/DirectMessageThreadId;Ljava/lang/String;ZZZLjava/lang/String;Ldev/inmo/tgbotapi/types/message/SuggestedPostParameters;Ldev/inmo/tgbotapi/types/ReplyParameters;Ldev/inmo/tgbotapi/types/buttons/KeyboardMarkup;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;

View File

@@ -0,0 +1,28 @@
package dev.inmo.tgbotapi.extensions.api.chat.invite_links
import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.requests.chat.invite_links.AnswerChatJoinRequestQuery
import dev.inmo.tgbotapi.requests.chat.invite_links.ChatJoinRequestQueryResult
import dev.inmo.tgbotapi.types.ChatJoinRequestQueryId
import dev.inmo.tgbotapi.types.chat.ChatJoinRequest
import dev.inmo.tgbotapi.types.update.ChatJoinRequestUpdate
public suspend fun TelegramBot.answerChatJoinRequestQuery(
chatJoinRequestQueryId: ChatJoinRequestQueryId,
result: ChatJoinRequestQueryResult
): Unit = execute(AnswerChatJoinRequestQuery(chatJoinRequestQueryId, result))
public suspend fun TelegramBot.answerChatJoinRequestQuery(
chatJoinRequest: ChatJoinRequest,
result: ChatJoinRequestQueryResult
): Unit = answerChatJoinRequestQuery(
requireNotNull(chatJoinRequest.queryId) {
"ChatJoinRequest.queryId is null, this request can't be answered with answerChatJoinRequestQuery"
},
result
)
public suspend fun TelegramBot.answerChatJoinRequestQuery(
chatJoinRequestUpdate: ChatJoinRequestUpdate,
result: ChatJoinRequestQueryResult
): Unit = answerChatJoinRequestQuery(chatJoinRequestUpdate.data, result)

View File

@@ -0,0 +1,27 @@
package dev.inmo.tgbotapi.extensions.api.chat.invite_links
import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.requests.chat.invite_links.SendChatJoinRequestWebApp
import dev.inmo.tgbotapi.types.ChatJoinRequestQueryId
import dev.inmo.tgbotapi.types.chat.ChatJoinRequest
import dev.inmo.tgbotapi.types.update.ChatJoinRequestUpdate
public suspend fun TelegramBot.sendChatJoinRequestWebApp(
chatJoinRequestQueryId: ChatJoinRequestQueryId,
webAppUrl: String
): Unit = execute(SendChatJoinRequestWebApp(chatJoinRequestQueryId, webAppUrl))
public suspend fun TelegramBot.sendChatJoinRequestWebApp(
chatJoinRequest: ChatJoinRequest,
webAppUrl: String
): Unit = sendChatJoinRequestWebApp(
requireNotNull(chatJoinRequest.queryId) {
"ChatJoinRequest.queryId is null, this request can't be processed with sendChatJoinRequestWebApp"
},
webAppUrl
)
public suspend fun TelegramBot.sendChatJoinRequestWebApp(
chatJoinRequestUpdate: ChatJoinRequestUpdate,
webAppUrl: String
): Unit = sendChatJoinRequestWebApp(chatJoinRequestUpdate.data, webAppUrl)

View File

@@ -0,0 +1,70 @@
package dev.inmo.tgbotapi.extensions.api.send
import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.requests.send.SendRichMessage
import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.business_connection.BusinessConnectionId
import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup
import dev.inmo.tgbotapi.types.chat.Chat
import dev.inmo.tgbotapi.types.message.SuggestedPostParameters
import dev.inmo.tgbotapi.types.message.abstracts.ChatContentMessage
import dev.inmo.tgbotapi.types.message.content.RichMessageContent
import dev.inmo.tgbotapi.types.rich.InputRichMessage
public suspend fun TelegramBot.sendRichMessage(
chatId: ChatIdentifier,
richMessage: InputRichMessage,
threadId: MessageThreadId? = chatId.threadId,
directMessageThreadId: DirectMessageThreadId? = chatId.directMessageThreadId,
businessConnectionId: BusinessConnectionId? = chatId.businessConnectionId,
disableNotification: Boolean = false,
protectContent: Boolean = false,
allowPaidBroadcast: Boolean = false,
effectId: EffectId? = null,
suggestedPostParameters: SuggestedPostParameters? = null,
replyParameters: ReplyParameters? = null,
replyMarkup: KeyboardMarkup? = null
): ChatContentMessage<RichMessageContent> = execute(
SendRichMessage(
chatId = chatId,
richMessage = richMessage,
threadId = threadId,
directMessageThreadId = directMessageThreadId,
businessConnectionId = businessConnectionId,
disableNotification = disableNotification,
protectContent = protectContent,
allowPaidBroadcast = allowPaidBroadcast,
effectId = effectId,
suggestedPostParameters = suggestedPostParameters,
replyParameters = replyParameters,
replyMarkup = replyMarkup
)
)
public suspend fun TelegramBot.sendRichMessage(
chat: Chat,
richMessage: InputRichMessage,
threadId: MessageThreadId? = chat.id.threadId,
directMessageThreadId: DirectMessageThreadId? = chat.id.directMessageThreadId,
businessConnectionId: BusinessConnectionId? = chat.id.businessConnectionId,
disableNotification: Boolean = false,
protectContent: Boolean = false,
allowPaidBroadcast: Boolean = false,
effectId: EffectId? = null,
suggestedPostParameters: SuggestedPostParameters? = null,
replyParameters: ReplyParameters? = null,
replyMarkup: KeyboardMarkup? = null
): ChatContentMessage<RichMessageContent> = sendRichMessage(
chatId = chat.id,
richMessage = richMessage,
threadId = threadId,
directMessageThreadId = directMessageThreadId,
businessConnectionId = businessConnectionId,
disableNotification = disableNotification,
protectContent = protectContent,
allowPaidBroadcast = allowPaidBroadcast,
effectId = effectId,
suggestedPostParameters = suggestedPostParameters,
replyParameters = replyParameters,
replyMarkup = replyMarkup
)

View File

@@ -0,0 +1,21 @@
package dev.inmo.tgbotapi.extensions.api.send
import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.requests.send.SendRichMessageDraft
import dev.inmo.tgbotapi.types.ChatId
import dev.inmo.tgbotapi.types.MessageThreadId
import dev.inmo.tgbotapi.types.rich.InputRichMessage
public suspend fun TelegramBot.sendRichMessageDraft(
chatId: ChatId,
draftId: Long,
richMessage: InputRichMessage,
threadId: MessageThreadId? = chatId.threadId
): Unit = execute(
SendRichMessageDraft(
chatId = chatId,
draftId = draftId,
richMessage = richMessage,
threadId = threadId
)
)

View File

@@ -394,6 +394,8 @@ public final class dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/W
public static synthetic fun waitPhoto$default (Ldev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourContext;Ldev/inmo/tgbotapi/requests/abstracts/Request;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lkotlinx/coroutines/flow/Flow;
public static final fun waitPoll (Ldev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourContext;Ldev/inmo/tgbotapi/requests/abstracts/Request;Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/flow/Flow;
public static synthetic fun waitPoll$default (Ldev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourContext;Ldev/inmo/tgbotapi/requests/abstracts/Request;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lkotlinx/coroutines/flow/Flow;
public static final fun waitRichMessage (Ldev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourContext;Ldev/inmo/tgbotapi/requests/abstracts/Request;Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/flow/Flow;
public static synthetic fun waitRichMessage$default (Ldev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourContext;Ldev/inmo/tgbotapi/requests/abstracts/Request;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lkotlinx/coroutines/flow/Flow;
public static final fun waitStaticLocation (Ldev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourContext;Ldev/inmo/tgbotapi/requests/abstracts/Request;Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/flow/Flow;
public static synthetic fun waitStaticLocation$default (Ldev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourContext;Ldev/inmo/tgbotapi/requests/abstracts/Request;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lkotlinx/coroutines/flow/Flow;
public static final fun waitSticker (Ldev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourContext;Ldev/inmo/tgbotapi/requests/abstracts/Request;Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/flow/Flow;
@@ -467,6 +469,8 @@ public final class dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/W
public static synthetic fun waitPhotoMessage$default (Ldev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourContext;Ldev/inmo/tgbotapi/requests/abstracts/Request;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lkotlinx/coroutines/flow/Flow;
public static final fun waitPollMessage (Ldev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourContext;Ldev/inmo/tgbotapi/requests/abstracts/Request;Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/flow/Flow;
public static synthetic fun waitPollMessage$default (Ldev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourContext;Ldev/inmo/tgbotapi/requests/abstracts/Request;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lkotlinx/coroutines/flow/Flow;
public static final fun waitRichMessageMessage (Ldev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourContext;Ldev/inmo/tgbotapi/requests/abstracts/Request;Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/flow/Flow;
public static synthetic fun waitRichMessageMessage$default (Ldev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourContext;Ldev/inmo/tgbotapi/requests/abstracts/Request;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lkotlinx/coroutines/flow/Flow;
public static final fun waitStaticLocationMessage (Ldev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourContext;Ldev/inmo/tgbotapi/requests/abstracts/Request;Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/flow/Flow;
public static synthetic fun waitStaticLocationMessage$default (Ldev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourContext;Ldev/inmo/tgbotapi/requests/abstracts/Request;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lkotlinx/coroutines/flow/Flow;
public static final fun waitStickerMessage (Ldev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourContext;Ldev/inmo/tgbotapi/requests/abstracts/Request;Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/flow/Flow;
@@ -1299,6 +1303,8 @@ public final class dev/inmo/tgbotapi/extensions/behaviour_builder/triggers_handl
public static synthetic fun onPhoto$default (Ldev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourContext;Ldev/inmo/tgbotapi/extensions/behaviour_builder/utils/SimpleFilter;Lkotlin/jvm/functions/Function4;Ldev/inmo/tgbotapi/extensions/behaviour_builder/utils/marker_factories/MarkerFactory;Lkotlin/jvm/functions/Function4;Lkotlin/jvm/functions/Function3;ILjava/lang/Object;)Lkotlinx/coroutines/Job;
public static final fun onPoll (Ldev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourContext;Ldev/inmo/tgbotapi/extensions/behaviour_builder/utils/SimpleFilter;Lkotlin/jvm/functions/Function4;Ldev/inmo/tgbotapi/extensions/behaviour_builder/utils/marker_factories/MarkerFactory;Lkotlin/jvm/functions/Function4;Lkotlin/jvm/functions/Function3;)Lkotlinx/coroutines/Job;
public static synthetic fun onPoll$default (Ldev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourContext;Ldev/inmo/tgbotapi/extensions/behaviour_builder/utils/SimpleFilter;Lkotlin/jvm/functions/Function4;Ldev/inmo/tgbotapi/extensions/behaviour_builder/utils/marker_factories/MarkerFactory;Lkotlin/jvm/functions/Function4;Lkotlin/jvm/functions/Function3;ILjava/lang/Object;)Lkotlinx/coroutines/Job;
public static final fun onRichMessage (Ldev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourContext;Ldev/inmo/tgbotapi/extensions/behaviour_builder/utils/SimpleFilter;Lkotlin/jvm/functions/Function4;Ldev/inmo/tgbotapi/extensions/behaviour_builder/utils/marker_factories/MarkerFactory;Lkotlin/jvm/functions/Function4;Lkotlin/jvm/functions/Function3;)Lkotlinx/coroutines/Job;
public static synthetic fun onRichMessage$default (Ldev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourContext;Ldev/inmo/tgbotapi/extensions/behaviour_builder/utils/SimpleFilter;Lkotlin/jvm/functions/Function4;Ldev/inmo/tgbotapi/extensions/behaviour_builder/utils/marker_factories/MarkerFactory;Lkotlin/jvm/functions/Function4;Lkotlin/jvm/functions/Function3;ILjava/lang/Object;)Lkotlinx/coroutines/Job;
public static final fun onStaticLocation (Ldev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourContext;Ldev/inmo/tgbotapi/extensions/behaviour_builder/utils/SimpleFilter;Lkotlin/jvm/functions/Function4;Ldev/inmo/tgbotapi/extensions/behaviour_builder/utils/marker_factories/MarkerFactory;Lkotlin/jvm/functions/Function4;Lkotlin/jvm/functions/Function3;)Lkotlinx/coroutines/Job;
public static synthetic fun onStaticLocation$default (Ldev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourContext;Ldev/inmo/tgbotapi/extensions/behaviour_builder/utils/SimpleFilter;Lkotlin/jvm/functions/Function4;Ldev/inmo/tgbotapi/extensions/behaviour_builder/utils/marker_factories/MarkerFactory;Lkotlin/jvm/functions/Function4;Lkotlin/jvm/functions/Function3;ILjava/lang/Object;)Lkotlinx/coroutines/Job;
public static final fun onSticker (Ldev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourContext;Ldev/inmo/tgbotapi/extensions/behaviour_builder/utils/SimpleFilter;Lkotlin/jvm/functions/Function4;Ldev/inmo/tgbotapi/extensions/behaviour_builder/utils/marker_factories/MarkerFactory;Lkotlin/jvm/functions/Function4;Lkotlin/jvm/functions/Function3;)Lkotlinx/coroutines/Job;

View File

@@ -66,6 +66,10 @@ fun BehaviourContext.waitStory(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }
) = waitContent(initRequest, errorFactory).mapContent<StoryContent>()
fun BehaviourContext.waitRichMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }
) = waitContent(initRequest, errorFactory).mapContent<RichMessageContent>()
fun BehaviourContext.waitVenue(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }

View File

@@ -75,6 +75,10 @@ fun BehaviourContext.waitStoryMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }
) = waitContentMessage(initRequest, errorFactory).mapWithContent<StoryContent>()
fun BehaviourContext.waitRichMessageMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }
) = waitContentMessage(initRequest, errorFactory).mapWithContent<RichMessageContent>()
fun BehaviourContext.waitVenueMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }

View File

@@ -304,6 +304,33 @@ fun <BC : BehaviourContext> BC.onStory(
scenarioReceiver
)
/**
* @param initialFilter This filter will be called to remove unnecessary data BEFORE [scenarioReceiver] call
* @param subcontextUpdatesFilter This filter will be applied to each update inside of [scenarioReceiver]. For example,
* this filter will be used if you will call [dev.inmo.tgbotapi.extensions.behaviour_builder.expectations.waitContentMessage].
* Use [dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContextAndTwoTypesReceiver] function to create your own.
* Use [dev.inmo.tgbotapi.extensions.behaviour_builder.utils.plus] or [dev.inmo.tgbotapi.extensions.behaviour_builder.utils.times]
* to combinate several filters
* @param [markerFactory] **Pass null to handle requests fully parallel**. Will be used to identify different "stream".
* [scenarioReceiver] will be called synchronously in one "stream". Output of [markerFactory] will be used as a key for
* "stream"
* @param scenarioReceiver Main callback which will be used to handle incoming data if [initialFilter] will pass that
* data
*/
fun <BC : BehaviourContext> BC.onRichMessage(
initialFilter: CommonMessageFilter<RichMessageContent>? = CommonMessageFilterExcludeMediaGroups,
subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, RichMessageContentMessage, Update>? = MessageFilterByChat,
markerFactory: MarkerFactory<in RichMessageContentMessage, Any>? = ByChatMessageMarkerFactory,
additionalSubcontextInitialAction: CustomBehaviourContextAndTwoTypesReceiver<BC, Unit, Update, RichMessageContentMessage>? = null,
scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, RichMessageContentMessage>
) = onContentMessageWithType(
initialFilter,
subcontextUpdatesFilter,
markerFactory,
additionalSubcontextInitialAction,
scenarioReceiver
)
/**
* @param initialFilter This filter will be called to remove unnecessary data BEFORE [scenarioReceiver] call
* @param subcontextUpdatesFilter This filter will be applied to each update inside of [scenarioReceiver]. For example,

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,96 @@
package dev.inmo.tgbotapi.requests.chat.invite_links
import dev.inmo.tgbotapi.requests.abstracts.SimpleRequest
import dev.inmo.tgbotapi.types.ChatJoinRequestQueryId
import dev.inmo.tgbotapi.types.chatJoinRequestQueryIdField
import dev.inmo.tgbotapi.types.resultField
import dev.inmo.tgbotapi.utils.serializers.UnitFromBooleanSerializer
import kotlinx.serialization.DeserializationStrategy
import kotlinx.serialization.KSerializer
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.SerializationStrategy
import kotlinx.serialization.descriptors.PrimitiveKind
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
/**
* Result of an [AnswerChatJoinRequestQuery]. Serialized as a plain string.
*
* @see <a href="https://core.telegram.org/bots/api#answerchatjoinrequestquery">answerChatJoinRequestQuery</a>
*/
@Serializable(ChatJoinRequestQueryResult.Companion::class)
sealed interface ChatJoinRequestQueryResult {
val name: String
/**
* Allow the user to join the chat.
*/
@Serializable(ChatJoinRequestQueryResult.Companion::class)
data object Approve : ChatJoinRequestQueryResult {
override val name: String = "approve"
}
/**
* Disallow the user to join the chat.
*/
@Serializable(ChatJoinRequestQueryResult.Companion::class)
data object Decline : ChatJoinRequestQueryResult {
override val name: String = "decline"
}
/**
* Leave the decision to other administrators.
*/
@Serializable(ChatJoinRequestQueryResult.Companion::class)
data object Queue : ChatJoinRequestQueryResult {
override val name: String = "queue"
}
/**
* Any other result which is currently unknown to this library.
*/
@Serializable(ChatJoinRequestQueryResult.Companion::class)
data class Unknown(override val name: String) : ChatJoinRequestQueryResult
companion object : KSerializer<ChatJoinRequestQueryResult> {
override val descriptor: SerialDescriptor =
PrimitiveSerialDescriptor("ChatJoinRequestQueryResult", PrimitiveKind.STRING)
override fun serialize(encoder: Encoder, value: ChatJoinRequestQueryResult) {
encoder.encodeString(value.name)
}
override fun deserialize(decoder: Decoder): ChatJoinRequestQueryResult {
return when (val name = decoder.decodeString()) {
Approve.name -> Approve
Decline.name -> Decline
Queue.name -> Queue
else -> Unknown(name)
}
}
}
}
/**
* Use this method to process a received chat join request query.
*
* @see <a href="https://core.telegram.org/bots/api#answerchatjoinrequestquery">answerChatJoinRequestQuery</a>
*/
@Serializable
data class AnswerChatJoinRequestQuery(
@SerialName(chatJoinRequestQueryIdField)
val chatJoinRequestQueryId: ChatJoinRequestQueryId,
@SerialName(resultField)
val result: ChatJoinRequestQueryResult
) : SimpleRequest<Unit> {
override val requestSerializer: SerializationStrategy<*>
get() = serializer()
override val resultDeserializer: DeserializationStrategy<Unit>
get() = UnitFromBooleanSerializer
override fun method(): String = "answerChatJoinRequestQuery"
}

View File

@@ -0,0 +1,34 @@
package dev.inmo.tgbotapi.requests.chat.invite_links
import dev.inmo.tgbotapi.requests.abstracts.SimpleRequest
import dev.inmo.tgbotapi.types.ChatJoinRequestQueryId
import dev.inmo.tgbotapi.types.chatJoinRequestQueryIdField
import dev.inmo.tgbotapi.types.webAppUrlField
import dev.inmo.tgbotapi.utils.serializers.UnitFromBooleanSerializer
import kotlinx.serialization.DeserializationStrategy
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.SerializationStrategy
/**
* Use this method to process a received chat join request query by showing a Mini App to the user before deciding the
* outcome. Call [AnswerChatJoinRequestQuery] to resolve the join request query based on the user interaction with the
* Mini App.
*
* @see <a href="https://core.telegram.org/bots/api#sendchatjoinrequestwebapp">sendChatJoinRequestWebApp</a>
*/
@Serializable
data class SendChatJoinRequestWebApp(
@SerialName(chatJoinRequestQueryIdField)
val chatJoinRequestQueryId: ChatJoinRequestQueryId,
@SerialName(webAppUrlField)
val webAppUrl: String
) : SimpleRequest<Unit> {
override val requestSerializer: SerializationStrategy<*>
get() = serializer()
override val resultDeserializer: DeserializationStrategy<Unit>
get() = UnitFromBooleanSerializer
override fun method(): String = "sendChatJoinRequestWebApp"
}

View File

@@ -3,5 +3,5 @@ package dev.inmo.tgbotapi.requests.edit.abstracts
import dev.inmo.tgbotapi.abstracts.TextedOutput
interface EditTextChatMessage : TextedOutput {
override val text: String
override val text: String?
}

View File

@@ -13,6 +13,7 @@ import dev.inmo.tgbotapi.types.message.RawMessageEntity
import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage
import dev.inmo.tgbotapi.types.message.content.TextContent
import dev.inmo.tgbotapi.types.message.toRawMessageEntities
import dev.inmo.tgbotapi.types.rich.InputRichMessage
import dev.inmo.tgbotapi.utils.extensions.makeString
import kotlinx.serialization.*
@@ -55,6 +56,24 @@ fun EditChatMessageText(
replyMarkup
)
fun EditChatMessageRichText(
chatId: ChatIdentifier,
messageId: MessageId,
richMessage: InputRichMessage,
businessConnectionId: BusinessConnectionId? = chatId.businessConnectionId,
replyMarkup: InlineKeyboardMarkup? = null
) = EditChatMessageText(
chatId = chatId,
messageId = messageId,
text = null,
parseMode = null,
rawEntities = null,
businessConnectionId = businessConnectionId,
linkPreviewOptions = null,
replyMarkup = replyMarkup,
richMessage = richMessage
)
@ConsistentCopyVisibility
@Serializable
data class EditChatMessageText internal constructor(
@@ -63,7 +82,7 @@ data class EditChatMessageText internal constructor(
@SerialName(messageIdField)
override val messageId: MessageId,
@SerialName(textField)
override val text: String,
override val text: String? = null,
@SerialName(parseModeField)
override val parseMode: ParseMode? = null,
@SerialName(entitiesField)
@@ -73,10 +92,12 @@ data class EditChatMessageText internal constructor(
@SerialName(linkPreviewOptionsField)
override val linkPreviewOptions: LinkPreviewOptions? = null,
@SerialName(replyMarkupField)
override val replyMarkup: InlineKeyboardMarkup? = null
override val replyMarkup: InlineKeyboardMarkup? = null,
@SerialName(richMessageField)
val richMessage: InputRichMessage? = null
) : EditChatMessage<TextContent>, EditTextChatMessage, EditReplyMessage, EditLinkPreviewOptionsContainer {
override val textSources: TextSourcesList? by lazy {
rawEntities ?.asTextSources(text)
text ?.let { rawEntities ?.asTextSources(it) }
}
override fun method(): String = editMessageTextMethod

View File

@@ -0,0 +1,65 @@
package dev.inmo.tgbotapi.requests.send
import dev.inmo.tgbotapi.requests.send.abstracts.ReplyingMarkupSendMessageRequest
import dev.inmo.tgbotapi.requests.send.abstracts.SendContentMessageRequest
import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.business_connection.BusinessConnectionId
import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup
import dev.inmo.tgbotapi.types.message.*
import dev.inmo.tgbotapi.types.message.abstracts.ChatContentMessage
import dev.inmo.tgbotapi.types.message.abstracts.TelegramBotAPIMessageDeserializationStrategyClass
import dev.inmo.tgbotapi.types.message.content.RichMessageContent
import dev.inmo.tgbotapi.types.rich.InputRichMessage
import kotlinx.serialization.DeserializationStrategy
import kotlinx.serialization.EncodeDefault
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.SerializationStrategy
internal val RichMessageContentMessageResultDeserializer: DeserializationStrategy<ChatContentMessage<RichMessageContent>>
= TelegramBotAPIMessageDeserializationStrategyClass()
/**
* Use this method to send rich messages.
*
* @see <a href="https://core.telegram.org/bots/api#sendrichmessage">sendRichMessage</a>
*/
@Serializable
data class SendRichMessage(
@SerialName(chatIdField)
override val chatId: ChatIdentifier,
@SerialName(richMessageField)
val richMessage: InputRichMessage,
@OptIn(ExperimentalSerializationApi::class)
@SerialName(messageThreadIdField)
@EncodeDefault
override val threadId: MessageThreadId? = chatId.threadId,
@OptIn(ExperimentalSerializationApi::class)
@EncodeDefault
@SerialName(directMessagesTopicIdField)
override val directMessageThreadId: DirectMessageThreadId? = chatId.directMessageThreadId,
@SerialName(businessConnectionIdField)
override val businessConnectionId: BusinessConnectionId? = chatId.businessConnectionId,
@SerialName(disableNotificationField)
override val disableNotification: Boolean = false,
@SerialName(protectContentField)
override val protectContent: Boolean = false,
@SerialName(allowPaidBroadcastField)
override val allowPaidBroadcast: Boolean = false,
@SerialName(messageEffectIdField)
override val effectId: EffectId? = null,
@SerialName(suggestedPostParametersField)
override val suggestedPostParameters: SuggestedPostParameters? = null,
@SerialName(replyParametersField)
override val replyParameters: ReplyParameters? = null,
@SerialName(replyMarkupField)
override val replyMarkup: KeyboardMarkup? = null
) : SendContentMessageRequest<ChatContentMessage<RichMessageContent>>,
ReplyingMarkupSendMessageRequest<ChatContentMessage<RichMessageContent>> {
override fun method(): String = "sendRichMessage"
override val resultDeserializer: DeserializationStrategy<ChatContentMessage<RichMessageContent>>
get() = RichMessageContentMessageResultDeserializer
override val requestSerializer: SerializationStrategy<*>
get() = serializer()
}

View File

@@ -0,0 +1,51 @@
package dev.inmo.tgbotapi.requests.send
import dev.inmo.tgbotapi.requests.abstracts.SimpleRequest
import dev.inmo.tgbotapi.types.ChatId
import dev.inmo.tgbotapi.types.MessageThreadId
import dev.inmo.tgbotapi.types.chatIdField
import dev.inmo.tgbotapi.types.draftIdField
import dev.inmo.tgbotapi.types.messageThreadIdField
import dev.inmo.tgbotapi.types.richMessageField
import dev.inmo.tgbotapi.types.rich.InputRichMessage
import dev.inmo.tgbotapi.utils.serializers.UnitFromBooleanSerializer
import kotlinx.serialization.DeserializationStrategy
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.SerializationStrategy
/**
* Use this method to stream a partial rich message to a user while the message is being generated. The streamed draft is
* ephemeral and acts as a temporary 30-second preview - once the output is finalized, [SendRichMessage] must be called
* with the complete message to persist it in the user's chat.
*
* @see <a href="https://core.telegram.org/bots/api#sendrichmessagedraft">sendRichMessageDraft</a>
*/
@Serializable
data class SendRichMessageDraft(
@SerialName(chatIdField)
val chatId: ChatId,
/**
* Unique identifier of the message draft; must be non-zero. Changes to drafts with the same identifier are animated.
*/
@SerialName(draftIdField)
val draftId: Long,
@SerialName(richMessageField)
val richMessage: InputRichMessage,
@SerialName(messageThreadIdField)
val threadId: MessageThreadId? = chatId.threadId
) : SimpleRequest<Unit> {
init {
require(draftId != 0L) {
"draftId of SendRichMessageDraft must be non-zero"
}
}
override val requestSerializer: SerializationStrategy<*>
get() = serializer()
override val resultDeserializer: DeserializationStrategy<Unit>
get() = UnitFromBooleanSerializer
override fun method(): String = "sendRichMessageDraft"
}

View File

@@ -0,0 +1,19 @@
package dev.inmo.tgbotapi.types
import kotlinx.serialization.Serializable
import kotlin.jvm.JvmInline
/**
* Identifier of a join request query.
*
* @see <a href="https://core.telegram.org/bots/api#chatjoinrequest">ChatJoinRequest.query_id</a>
*/
@Serializable
@JvmInline
value class ChatJoinRequestQueryId(
val string: String
) {
override fun toString(): String {
return string
}
}

View File

@@ -463,6 +463,7 @@ const val inputMessageContentField = "input_message_content"
const val hideUrlField = "hide_url"
const val botCommandField = "command"
const val botCommandFullField = "bot_command"
const val botCommandsField = "commands"
const val scopeField = "scope"
@@ -556,6 +557,7 @@ const val stickerField = "sticker"
const val oldStickerField = "old_sticker"
const val keywordsField = "keywords"
const val urlField = "url"
const val linkField = "link"
const val addressField = "address"
const val actionField = "action"
const val positionField = "position"
@@ -567,6 +569,45 @@ const val payloadField = "payload"
const val vcardField = "vcard"
const val resultsField = "results"
const val resultField = "result"
const val guardBotField = "guard_bot"
const val supportsJoinRequestQueriesField = "supports_join_request_queries"
const val queryIdField = "query_id"
const val chatJoinRequestQueryIdField = "chat_join_request_query_id"
const val webAppUrlField = "web_app_url"
const val richMessageField = "rich_message"
const val isRtlField = "is_rtl"
const val skipEntityDetectionField = "skip_entity_detection"
const val markdownField = "markdown"
const val htmlField = "html"
const val unixTimeField = "unix_time"
const val dateTimeFormatField = "date_time_format"
const val alternativeTextField = "alternative_text"
const val expressionField = "expression"
const val emailAddressField = "email_address"
const val hashtagField = "hashtag"
const val cashtagField = "cashtag"
const val bankCardNumberField = "bank_card_number"
const val anchorNameField = "anchor_name"
const val referenceNameField = "reference_name"
const val blocksField = "blocks"
const val itemsField = "items"
const val summaryField = "summary"
const val sizeField = "size"
const val languageField = "language"
const val creditField = "credit"
const val cellsField = "cells"
const val isHeaderField = "is_header"
const val colspanField = "colspan"
const val rowspanField = "rowspan"
const val alignField = "align"
const val valignField = "valign"
const val zoomField = "zoom"
const val voiceNoteField = "voice_note"
const val hasCheckboxField = "has_checkbox"
const val isCheckedField = "is_checked"
const val isOpenField = "is_open"
const val isBorderedField = "is_bordered"
const val isStripedField = "is_striped"
const val certificateField = "certificate"
const val questionField = "question"
const val questionEntitiesField = "question_entities"

View File

@@ -0,0 +1,17 @@
package dev.inmo.tgbotapi.types.InlineQueries.InputMessageContent
import dev.inmo.tgbotapi.types.richMessageField
import dev.inmo.tgbotapi.types.rich.InputRichMessage
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
/**
* Represents the content of a rich message to be sent as the result of an inline query.
*
* @see <a href="https://core.telegram.org/bots/api#inputrichmessagecontent">InputRichMessageContent</a>
*/
@Serializable
data class InputRichMessageContent(
@SerialName(richMessageField)
val richMessage: InputRichMessage
) : InputMessageContent

View File

@@ -22,6 +22,7 @@ object InputMessageContentSerializer : KSerializer<InputMessageContent> {
is InputTextMessageContent -> InputTextMessageContent.serializer().serialize(encoder, value)
is InputVenueMessageContent -> InputVenueMessageContent.serializer().serialize(encoder, value)
is InputInvoiceMessageContent -> InputInvoiceMessageContent.serializer().serialize(encoder, value)
is InputRichMessageContent -> InputRichMessageContent.serializer().serialize(encoder, value)
}
}

View File

@@ -0,0 +1,16 @@
package dev.inmo.tgbotapi.types
import dev.inmo.tgbotapi.types.media.PollMedia
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
/**
* Represents an HTTP link.
*
* @see <a href="https://core.telegram.org/bots/api#link">Link</a>
*/
@Serializable
data class Link(
@SerialName(urlField)
val url: String
) : PollMedia

View File

@@ -24,7 +24,9 @@ data class ChatJoinRequest(
@SerialName(inviteLinkField)
val inviteLink: ChatInviteLink? = null,
@SerialName(bioField)
val bio: String? = null
val bio: String? = null,
@SerialName(queryIdField)
val queryId: ChatJoinRequestQueryId? = null
) : FromUser {
@Suppress("unused")
val dateTime: DateTime

View File

@@ -69,7 +69,9 @@ data class ExtendedChannelChatImpl(
@SerialName(maxReactionCountField)
override val maxReactionsCount: Int = 3,
@SerialName(uniqueGiftColorsField)
override val uniqueGiftColors: UniqueGiftColors? = null
override val uniqueGiftColors: UniqueGiftColors? = null,
@SerialName(guardBotField)
override val guardBot: User? = null
) : ExtendedChannelChat
@Serializable
@@ -116,7 +118,9 @@ data class ExtendedGroupChatImpl(
@SerialName(paidMessageStarCountField)
override val paidMessageStarCount: Int? = null,
@SerialName(uniqueGiftColorsField)
override val uniqueGiftColors: UniqueGiftColors? = null
override val uniqueGiftColors: UniqueGiftColors? = null,
@SerialName(guardBotField)
override val guardBot: User? = null
) : ExtendedGroupChat
@Serializable
@@ -316,7 +320,9 @@ data class ExtendedSupergroupChatImpl(
@SerialName(paidMessageStarCountField)
override val paidMessageStarCount: Int? = null,
@SerialName(uniqueGiftColorsField)
override val uniqueGiftColors: UniqueGiftColors? = null
override val uniqueGiftColors: UniqueGiftColors? = null,
@SerialName(guardBotField)
override val guardBot: User? = null
) : ExtendedSupergroupChat
@Serializable
@@ -390,7 +396,9 @@ data class ExtendedForumChatImpl(
@SerialName(paidMessageStarCountField)
override val paidMessageStarCount: Int? = null,
@SerialName(uniqueGiftColorsField)
override val uniqueGiftColors: UniqueGiftColors? = null
override val uniqueGiftColors: UniqueGiftColors? = null,
@SerialName(guardBotField)
override val guardBot: User? = null
) : ExtendedForumChat
@Serializable
@@ -467,7 +475,9 @@ data class ExtendedChannelDirectMessagesChatImpl(
@SerialName(paidMessageStarCountField)
override val paidMessageStarCount: Int? = null,
@SerialName(uniqueGiftColorsField)
override val uniqueGiftColors: UniqueGiftColors? = null
override val uniqueGiftColors: UniqueGiftColors? = null,
@SerialName(guardBotField)
override val guardBot: User? = null
) : ExtendedChannelDirectMessagesChat {
@OptIn(ExperimentalSerializationApi::class)
@SerialName(isDirectMessagesField)
@@ -495,6 +505,8 @@ data class ExtendedBot(
val supportsInlineQueries: Boolean = false,
@SerialName(supportsGuestQueriesField)
val supportsGuestQueries: Boolean = false,
@SerialName(supportsJoinRequestQueriesField)
val supportsJoinRequestQueries: Boolean = false,
@SerialName(canConnectToBusinessField)
val canConnectToBusiness: Boolean = false,
@SerialName(photoField)

View File

@@ -27,6 +27,14 @@ sealed interface ExtendedChat : Chat {
val uniqueGiftColors: UniqueGiftColors?
/**
* The bot that processes join request queries in the chat. The field is only available to chat administrators.
*
* @see <a href="https://core.telegram.org/bots/api#chatfullinfo">ChatFullInfo.guard_bot</a>
*/
val guardBot: User?
get() = null
@Deprecated(
message = "Telegram Bot API v9.0 introduced the new field, `acceptedGiftTypes`, to allow granular" +
" control over which types of gifts user, bot, or chat can accept.",

View File

@@ -27,6 +27,7 @@ object InputPollOptionMediaSerializer : KSerializer<InputPollOptionMedia> {
override fun serialize(encoder: Encoder, value: InputPollOptionMedia) {
when (value) {
is TelegramMediaAnimation -> TelegramMediaAnimation.serializer().serialize(encoder, value)
is TelegramMediaLink -> TelegramMediaLink.serializer().serialize(encoder, value)
is TelegramMediaLivePhoto -> TelegramMediaLivePhoto.serializer().serialize(encoder, value)
is TelegramMediaLocation -> TelegramMediaLocation.serializer().serialize(encoder, value)
is TelegramMediaPhoto -> TelegramMediaPhoto.serializer().serialize(encoder, value)

View File

@@ -10,6 +10,8 @@ import dev.inmo.tgbotapi.types.files.LivePhotoFile
import dev.inmo.tgbotapi.types.files.PhotoFile
import dev.inmo.tgbotapi.types.files.Sticker
import dev.inmo.tgbotapi.types.files.VideoFile
import dev.inmo.tgbotapi.types.Link
import dev.inmo.tgbotapi.types.linkField
import dev.inmo.tgbotapi.types.livePhotoField
import dev.inmo.tgbotapi.types.location.StaticLocation
import dev.inmo.tgbotapi.types.locationField
@@ -36,6 +38,8 @@ interface PollMedia : BaseTelegramMediaFile {
val audio: AudioFile? = null,
@SerialName(documentField)
val document: DocumentFile? = null,
@SerialName(linkField)
val link: Link? = null,
@SerialName(livePhotoField)
val livePhoto: LivePhotoFile? = null,
@SerialName(photoField)
@@ -61,6 +65,7 @@ interface PollMedia : BaseTelegramMediaFile {
surrogate.animation != null -> surrogate.animation
surrogate.audio != null -> surrogate.audio
surrogate.document != null -> surrogate.document
surrogate.link != null -> surrogate.link
surrogate.livePhoto != null -> surrogate.livePhoto
surrogate.photo != null -> surrogate.photo
surrogate.sticker != null -> surrogate.sticker
@@ -76,6 +81,7 @@ interface PollMedia : BaseTelegramMediaFile {
animation = value as? AnimationFile,
audio = value as? AudioFile,
document = value as? DocumentFile,
link = value as? Link,
livePhoto = value as? LivePhotoFile,
photo = value as? PhotoFile,
sticker = value as? Sticker,

View File

@@ -0,0 +1,26 @@
package dev.inmo.tgbotapi.types.media
import dev.inmo.tgbotapi.types.typeField
import dev.inmo.tgbotapi.types.urlField
import kotlinx.serialization.EncodeDefault
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
/**
* Represents an HTTP link to be sent. Can be used as [InputPollOptionMedia].
*
* @see <a href="https://core.telegram.org/bots/api#inputmedialink">InputMediaLink</a>
*/
@Serializable
data class TelegramMediaLink(
@SerialName(urlField)
val url: String,
) : InputPollOptionMedia {
@EncodeDefault
@SerialName(typeField)
override val type: String = TYPE
companion object {
const val TYPE = "link"
}
}

View File

@@ -50,6 +50,7 @@ import dev.inmo.tgbotapi.types.polls.Poll
import dev.inmo.tgbotapi.types.polls.PollOptionPersistentId
import dev.inmo.tgbotapi.types.request.ChatShared
import dev.inmo.tgbotapi.types.request.UsersShared
import dev.inmo.tgbotapi.types.rich.RichTextInfo
import dev.inmo.tgbotapi.types.stories.Story
import dev.inmo.tgbotapi.types.venue.Venue
import dev.inmo.tgbotapi.utils.isFakeTelegramUser
@@ -92,6 +93,7 @@ internal data class RawMessage(
private val caption_entities: RawMessageEntities? = null,
private val has_media_spoiler: Boolean? = null,
private val story: Story? = null,
private val rich_message: RichTextInfo? = null,
private val audio: AudioFile? = null,
private val document: DocumentFile? = null,
private val paid_media: PaidMediaInfo? = null,
@@ -230,6 +232,11 @@ internal data class RawMessage(
} ?: emptyList()
when {
rich_message != null -> RichMessageContent(
chat,
messageId,
rich_message
)
story != null -> StoryContent(
chat,
messageId,

View File

@@ -55,6 +55,7 @@ sealed interface MessageContent: ResendableContent {
subclass(StoryContent::class)
subclass(GiveawayPublicResultsContent::class)
subclass(GiveawayContent::class)
subclass(RichMessageContent::class)
additionalBuilder()
}

View File

@@ -0,0 +1,78 @@
package dev.inmo.tgbotapi.types.message.content
import dev.inmo.tgbotapi.requests.ForwardMessage
import dev.inmo.tgbotapi.requests.abstracts.Request
import dev.inmo.tgbotapi.requests.send.CopyMessage
import dev.inmo.tgbotapi.requests.send.SendRichMessage
import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.business_connection.BusinessConnectionId
import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup
import dev.inmo.tgbotapi.types.chat.Chat
import dev.inmo.tgbotapi.types.message.SuggestedPostParameters
import dev.inmo.tgbotapi.types.message.abstracts.ChatContentMessage
import dev.inmo.tgbotapi.types.rich.InputRichMessageMarkdown
import dev.inmo.tgbotapi.types.rich.RichBlock
import dev.inmo.tgbotapi.types.rich.RichBlockAudio
import dev.inmo.tgbotapi.types.rich.RichBlockMedia
import dev.inmo.tgbotapi.types.rich.RichBlockPhoto
import dev.inmo.tgbotapi.types.rich.RichBlockVideo
import dev.inmo.tgbotapi.types.rich.RichTextInfo
import dev.inmo.tgbotapi.types.rich.markdown
import dev.inmo.tgbotapi.types.rich.search
import kotlinx.serialization.Serializable
@Serializable
data class RichMessageContent(
private val chat: Chat,
private val messageId: MessageId,
val richMessage: RichTextInfo
) : MessageContent {
override fun createResend(
chatId: ChatIdentifier,
messageThreadId: MessageThreadId?,
directMessageThreadId: DirectMessageThreadId?,
businessConnectionId: BusinessConnectionId?,
disableNotification: Boolean,
protectContent: Boolean,
allowPaidBroadcast: Boolean,
effectId: EffectId?,
suggestedPostParameters: SuggestedPostParameters?,
replyParameters: ReplyParameters?,
replyMarkup: KeyboardMarkup?
): Request<ChatContentMessage<RichMessageContent>> {
val isThereMedia = richMessage.blocks.any {
it.search {
this is RichBlockMedia
} != null
}
return if (isThereMedia) {
@Suppress("UNCHECKED_CAST")
ForwardMessage(
chat.id,
toChatId = chatId,
messageId = messageId,
threadId = messageThreadId,
directMessageThreadId = directMessageThreadId,
disableNotification = disableNotification,
protectContent = protectContent,
effectId = effectId,
suggestedPostParameters = suggestedPostParameters,
) as Request<ChatContentMessage<RichMessageContent>>
} else {
SendRichMessage(
chatId = chatId,
richMessage = InputRichMessageMarkdown(richMessage.markdown, isRtl = richMessage.isRtl),
threadId = messageThreadId,
directMessageThreadId = directMessageThreadId,
businessConnectionId = businessConnectionId,
disableNotification = disableNotification,
protectContent = protectContent,
allowPaidBroadcast = allowPaidBroadcast,
effectId = effectId,
suggestedPostParameters = suggestedPostParameters,
replyParameters = replyParameters,
replyMarkup = replyMarkup
)
}
}
}

View File

@@ -13,6 +13,8 @@ typealias PollMessage = ChatContentMessage<PollContent>
typealias TextMessage = ChatContentMessage<TextContent>
typealias StoryMessage = ChatContentMessage<StoryContent>
typealias RichMessageContentMessage = ChatContentMessage<RichMessageContent>
typealias LocationMessage = ChatContentMessage<LocationContent>
typealias LiveLocationMessage = ChatContentMessage<LiveLocationContent>
typealias StaticLocationMessage = ChatContentMessage<StaticLocationContent>

View File

@@ -0,0 +1,65 @@
package dev.inmo.tgbotapi.types.rich
import dev.inmo.tgbotapi.types.htmlField
import dev.inmo.tgbotapi.types.isRtlField
import dev.inmo.tgbotapi.types.markdownField
import dev.inmo.tgbotapi.types.skipEntityDetectionField
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
/**
* Describes a rich message to be sent. Exactly one of the fields [html] or [markdown] must be used. Use the
* [InputRichMessageHTML] and [InputRichMessageMarkdown] factories to build an instance.
*
* @see <a href="https://core.telegram.org/bots/api#inputrichmessage">InputRichMessage</a>
*/
@ConsistentCopyVisibility
@Serializable
data class InputRichMessage internal constructor(
@SerialName(htmlField)
val html: String? = null,
@SerialName(markdownField)
val markdown: String? = null,
@SerialName(isRtlField)
val isRtl: Boolean? = null,
@SerialName(skipEntityDetectionField)
val skipEntityDetection: Boolean? = null
) {
init {
require((html == null) != (markdown == null)) {
"Exactly one of the fields html or markdown must be used in InputRichMessage"
}
}
}
/**
* Creates an [InputRichMessage] with the content described using HTML formatting.
*
* @see <a href="https://core.telegram.org/bots/api#inputrichmessage">InputRichMessage</a>
*/
fun InputRichMessageHTML(
html: String,
isRtl: Boolean? = null,
skipEntityDetection: Boolean? = null
): InputRichMessage = InputRichMessage(
html = html,
markdown = null,
isRtl = isRtl,
skipEntityDetection = skipEntityDetection
)
/**
* Creates an [InputRichMessage] with the content described using Markdown formatting.
*
* @see <a href="https://core.telegram.org/bots/api#inputrichmessage">InputRichMessage</a>
*/
fun InputRichMessageMarkdown(
markdown: String,
isRtl: Boolean? = null,
skipEntityDetection: Boolean? = null
): InputRichMessage = InputRichMessage(
html = null,
markdown = markdown,
isRtl = isRtl,
skipEntityDetection = skipEntityDetection
)

View File

@@ -0,0 +1,95 @@
package dev.inmo.tgbotapi.types.rich
import dev.inmo.tgbotapi.requests.abstracts.FileId
import dev.inmo.tgbotapi.types.files.TelegramMediaFile
import dev.inmo.tgbotapi.types.typeField
import dev.inmo.tgbotapi.utils.internal.ClassCastsIncluded
import kotlinx.serialization.DeserializationStrategy
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.JsonContentPolymorphicSerializer
import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.jsonObject
import kotlinx.serialization.json.jsonPrimitive
/**
* Represents a block in a rich formatted message.
*
* @see <a href="https://core.telegram.org/bots/api#richblock">RichBlock</a>
*/
@Serializable(RichBlockSerializer::class)
@ClassCastsIncluded
sealed interface RichBlock {
val type: String
/**
* [Rich Markdown style](https://core.telegram.org/bots/api#rich-markdown-style) source of this single [RichBlock].
*/
val markdown: String
/**
* [Rich HTML style](https://core.telegram.org/bots/api#rich-html-style) source of this single [RichBlock].
*/
val html: String
}
@Serializable(RichBlockSerializer::class)
sealed interface RichBlockMedia : RichBlock {
val media: TelegramMediaFile
val caption: RichBlockCaption?
}
/**
* The nested [RichBlock]s directly contained by this block, or an empty list for leaf blocks. Container blocks
* ([RichBlockList] via its [RichBlockListItem.blocks], [RichBlockBlockQuotation], [RichBlockCollage],
* [RichBlockSlideshow] and [RichBlockDetails]) expose their children here.
*/
val RichBlock.subBlocks: List<RichBlock>
get() = when (this) {
is RichBlockList -> items.flatMap { it.blocks }
is RichBlockBlockQuotation -> blocks
is RichBlockCollage -> blocks
is RichBlockSlideshow -> blocks
is RichBlockDetails -> blocks
else -> emptyList()
}
/**
* Walks this [RichBlock] and all of its [subBlocks] recursively (depth-first, this block first) and returns the first
* block for which [block] returns `true`, or `null` if none matches.
*/
fun RichBlock.search(block: RichBlock.() -> Boolean): RichBlock? {
if (block()) return this
for (child in subBlocks) {
child.search(block)?.let { return it }
}
return null
}
object RichBlockSerializer : JsonContentPolymorphicSerializer<RichBlock>(RichBlock::class) {
override fun selectDeserializer(element: JsonElement): DeserializationStrategy<RichBlock> {
return when (val type = element.jsonObject[typeField]?.jsonPrimitive?.content) {
RichBlockParagraph.TYPE -> RichBlockParagraph.serializer()
RichBlockSectionHeading.TYPE -> RichBlockSectionHeading.serializer()
RichBlockPreformatted.TYPE -> RichBlockPreformatted.serializer()
RichBlockFooter.TYPE -> RichBlockFooter.serializer()
RichBlockDivider.TYPE -> RichBlockDivider.serializer()
RichBlockMathematicalExpression.TYPE -> RichBlockMathematicalExpression.serializer()
RichBlockAnchor.TYPE -> RichBlockAnchor.serializer()
RichBlockList.TYPE -> RichBlockList.serializer()
RichBlockBlockQuotation.TYPE -> RichBlockBlockQuotation.serializer()
RichBlockPullQuotation.TYPE -> RichBlockPullQuotation.serializer()
RichBlockCollage.TYPE -> RichBlockCollage.serializer()
RichBlockSlideshow.TYPE -> RichBlockSlideshow.serializer()
RichBlockTable.TYPE -> RichBlockTable.serializer()
RichBlockDetails.TYPE -> RichBlockDetails.serializer()
RichBlockMap.TYPE -> RichBlockMap.serializer()
RichBlockAnimation.TYPE -> RichBlockAnimation.serializer()
RichBlockAudio.TYPE -> RichBlockAudio.serializer()
RichBlockPhoto.TYPE -> RichBlockPhoto.serializer()
RichBlockVideo.TYPE -> RichBlockVideo.serializer()
RichBlockVoiceNote.TYPE -> RichBlockVoiceNote.serializer()
RichBlockThinking.TYPE -> RichBlockThinking.serializer()
else -> error("Unknown RichBlock type: $type")
}
}
}

View File

@@ -0,0 +1,54 @@
package dev.inmo.tgbotapi.types.rich
/**
* Builds the [Rich Markdown style](https://core.telegram.org/bots/api#rich-markdown-style) source string for this list
* of [RichBlock]s. The resulting string may be passed to [InputRichMessageMarkdown].
*
* Media blocks ([RichBlockPhoto], [RichBlockVideo], [RichBlockAudio], [RichBlockVoiceNote] and [RichBlockAnimation]) are
* rendered using the Telegram file_id as the media source. Telegram only accepts HTTP(S) URLs for rich media, so for
* those blocks the output is a faithful structural representation rather than a directly sendable message.
*/
fun List<RichBlock>.toRichMarkdown(): String = joinToString(separator = "\n\n") { it.markdown }
/**
* Builds the [Rich HTML style](https://core.telegram.org/bots/api#rich-html-style) source string for this list of
* [RichBlock]s. The resulting string may be passed to [InputRichMessageHTML]. See [toRichMarkdown] for the media note.
*/
fun List<RichBlock>.toRichHtml(): String = joinToString(separator = "\n") { it.html }
/**
* [Rich Markdown style](https://core.telegram.org/bots/api#rich-markdown-style) source of all the [RichTextInfo.blocks].
*/
val RichTextInfo.markdown: String
get() = blocks.toRichMarkdown()
/**
* [Rich HTML style](https://core.telegram.org/bots/api#rich-html-style) source of all the [RichTextInfo.blocks].
*/
val RichTextInfo.html: String
get() = blocks.toRichHtml()
internal fun creditCiteMarkdown(credit: RichText?): String = credit?.let { "<cite>${it.markdown}</cite>" } ?: ""
internal fun creditCiteHtml(credit: RichText?): String = credit?.let { "<cite>${it.html}</cite>" } ?: ""
internal fun richMediaContainerMarkdown(tag: String, blocks: List<RichBlock>, caption: RichBlockCaption?): String {
val media = blocks.joinToString(separator = "\n") { it.markdown }
val captionPart = caption?.let { "\n<figcaption>${it.text.markdown}${creditCiteMarkdown(it.credit)}</figcaption>" } ?: ""
return "<$tag>\n\n$media$captionPart\n\n</$tag>"
}
internal fun richMediaContainerHtml(tag: String, blocks: List<RichBlock>, caption: RichBlockCaption?): String {
val media = blocks.joinToString(separator = "") { it.html }
val captionPart = caption?.let { "<figcaption>${it.text.html}${creditCiteHtml(it.credit)}</figcaption>" } ?: ""
return "<$tag>$media$captionPart</$tag>"
}
internal fun richMediaMarkdown(source: String, caption: RichBlockCaption?): String =
caption?.let { "![](" + source + " \"" + it.text.rawText + "\")" } ?: "![]($source)"
internal fun richMediaHtml(tag: String, source: String, spoiler: Boolean, selfClosing: Boolean, caption: RichBlockCaption?): String {
val spoilerAttribute = if (spoiler) " tg-spoiler" else ""
val element = if (selfClosing) "<$tag src=\"$source\"$spoilerAttribute/>" else "<$tag src=\"$source\"$spoilerAttribute></$tag>"
return caption?.let { "<figure>$element<figcaption>${it.text.html}${creditCiteHtml(it.credit)}</figcaption></figure>" } ?: element
}

View File

@@ -0,0 +1,75 @@
package dev.inmo.tgbotapi.types.rich
import dev.inmo.tgbotapi.types.alignField
import dev.inmo.tgbotapi.types.blocksField
import dev.inmo.tgbotapi.types.colspanField
import dev.inmo.tgbotapi.types.creditField
import dev.inmo.tgbotapi.types.hasCheckboxField
import dev.inmo.tgbotapi.types.isCheckedField
import dev.inmo.tgbotapi.types.isHeaderField
import dev.inmo.tgbotapi.types.labelField
import dev.inmo.tgbotapi.types.rowspanField
import dev.inmo.tgbotapi.types.textField
import dev.inmo.tgbotapi.types.typeField
import dev.inmo.tgbotapi.types.valignField
import dev.inmo.tgbotapi.types.valueField
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
/**
* Caption of a rich formatted block.
*
* @see <a href="https://core.telegram.org/bots/api#richblockcaption">RichBlockCaption</a>
*/
@Serializable
data class RichBlockCaption(
@SerialName(textField)
val text: RichText,
@SerialName(creditField)
val credit: RichText? = null
)
/**
* A cell in a [RichBlockTable].
*
* @see <a href="https://core.telegram.org/bots/api#richblocktablecell">RichBlockTableCell</a>
*/
@Serializable
data class RichBlockTableCell(
@SerialName(textField)
val text: RichText? = null,
@SerialName(isHeaderField)
val isHeader: Boolean? = null,
@SerialName(colspanField)
val colspan: Int? = null,
@SerialName(rowspanField)
val rowspan: Int? = null,
@SerialName(alignField)
val align: String,
@SerialName(valignField)
val valign: String
)
/**
* An item of a [RichBlockList].
*
* @see <a href="https://core.telegram.org/bots/api#richblocklistitem">RichBlockListItem</a>
*/
@Serializable
data class RichBlockListItem(
@SerialName(labelField)
val label: String,
@SerialName(blocksField)
val blocks: List<RichBlock>,
@SerialName(hasCheckboxField)
val hasCheckbox: Boolean? = null,
@SerialName(isCheckedField)
val isChecked: Boolean? = null,
@SerialName(valueField)
val value: Int? = null,
/**
* For ordered lists, the type of the item label; must be one of "a", "A", "i", "I" or "1".
*/
@SerialName(typeField)
val labelType: String? = null
)

View File

@@ -0,0 +1,708 @@
package dev.inmo.tgbotapi.types.rich
import dev.inmo.tgbotapi.types.animationField
import dev.inmo.tgbotapi.types.audioField
import dev.inmo.tgbotapi.types.blocksField
import dev.inmo.tgbotapi.types.captionField
import dev.inmo.tgbotapi.types.cellsField
import dev.inmo.tgbotapi.types.creditField
import dev.inmo.tgbotapi.types.expressionField
import dev.inmo.tgbotapi.types.files.AnimationFile
import dev.inmo.tgbotapi.types.files.AudioFile
import dev.inmo.tgbotapi.types.files.PhotoFile
import dev.inmo.tgbotapi.types.files.TelegramMediaFile
import dev.inmo.tgbotapi.types.files.VideoFile
import dev.inmo.tgbotapi.types.files.VoiceFile
import dev.inmo.tgbotapi.types.hasSpoilerField
import dev.inmo.tgbotapi.types.heightField
import dev.inmo.tgbotapi.types.isBorderedField
import dev.inmo.tgbotapi.types.isOpenField
import dev.inmo.tgbotapi.types.isStripedField
import dev.inmo.tgbotapi.types.itemsField
import dev.inmo.tgbotapi.types.languageField
import dev.inmo.tgbotapi.types.location.StaticLocation
import dev.inmo.tgbotapi.types.locationField
import dev.inmo.tgbotapi.types.nameField
import dev.inmo.tgbotapi.types.photoField
import dev.inmo.tgbotapi.types.sizeField
import dev.inmo.tgbotapi.types.summaryField
import dev.inmo.tgbotapi.types.textField
import dev.inmo.tgbotapi.types.typeField
import dev.inmo.tgbotapi.types.videoField
import dev.inmo.tgbotapi.types.voiceNoteField
import dev.inmo.tgbotapi.types.widthField
import dev.inmo.tgbotapi.types.zoomField
import kotlinx.serialization.EncodeDefault
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
/**
* A text paragraph.
*
* @see <a href="https://core.telegram.org/bots/api#richblockparagraph">RichBlockParagraph</a>
*/
@Serializable
data class RichBlockParagraph(
@SerialName(textField)
val text: RichText
) : RichBlock {
@EncodeDefault
@SerialName(typeField)
override val type: String = TYPE
override val markdown: String = markdown(text)
override val html: String = html(text)
companion object {
const val TYPE = "paragraph"
fun markdown(text: RichText): String = text.markdown
fun html(text: RichText): String = "<p>${text.html}</p>"
}
}
/**
* A section heading.
*
* @see <a href="https://core.telegram.org/bots/api#richblocksectionheading">RichBlockSectionHeading</a>
*/
@Serializable
data class RichBlockSectionHeading(
@SerialName(textField)
val text: RichText,
/**
* Relative size of the text font; 1-6, 1 is the largest, 6 is the smallest.
*/
@SerialName(sizeField)
val level: Int
) : RichBlock {
@EncodeDefault
@SerialName(typeField)
override val type: String = TYPE
override val markdown: String = markdown(text, level)
override val html: String = html(text, level)
companion object {
const val TYPE = "heading"
fun markdown(text: RichText, size: Int): String = "#".repeat(size) + " " + text.markdown
fun html(text: RichText, size: Int): String = "<h$size>${text.html}</h$size>"
}
}
/**
* A preformatted text block.
*
* @see <a href="https://core.telegram.org/bots/api#richblockpreformatted">RichBlockPreformatted</a>
*/
@Serializable
data class RichBlockPreformatted(
@SerialName(textField)
val text: RichText,
@SerialName(languageField)
val language: String? = null
) : RichBlock {
@EncodeDefault
@SerialName(typeField)
override val type: String = TYPE
override val markdown: String = markdown(text, language)
override val html: String = html(text, language)
companion object {
const val TYPE = "pre"
fun markdown(text: RichText, language: String?): String = "```" + (language ?: "") + "\n" + text.rawText + "\n```"
fun html(text: RichText, language: String?): String =
language?.let { "<pre><code class=\"language-$it\">${text.html}</code></pre>" } ?: "<pre>${text.html}</pre>"
}
}
/**
* A footer.
*
* @see <a href="https://core.telegram.org/bots/api#richblockfooter">RichBlockFooter</a>
*/
@Serializable
data class RichBlockFooter(
@SerialName(textField)
val text: RichText
) : RichBlock {
@EncodeDefault
@SerialName(typeField)
override val type: String = TYPE
override val markdown: String = markdown(text)
override val html: String = html(text)
companion object {
const val TYPE = "footer"
fun markdown(text: RichText): String = "<footer>${text.markdown}</footer>"
fun html(text: RichText): String = "<footer>${text.html}</footer>"
}
}
/**
* A divider.
*
* @see <a href="https://core.telegram.org/bots/api#richblockdivider">RichBlockDivider</a>
*/
@Serializable
class RichBlockDivider : RichBlock {
@EncodeDefault
@SerialName(typeField)
override val type: String = TYPE
override val markdown: String = markdown()
override val html: String = html()
override fun equals(other: Any?): Boolean = other is RichBlockDivider
override fun hashCode(): Int = TYPE.hashCode()
override fun toString(): String = "RichBlockDivider"
companion object {
const val TYPE = "divider"
fun markdown(): String = "---"
fun html(): String = "<hr/>"
}
}
/**
* A block with a mathematical expression in LaTeX format.
*
* @see <a href="https://core.telegram.org/bots/api#richblockmathematicalexpression">RichBlockMathematicalExpression</a>
*/
@Serializable
data class RichBlockMathematicalExpression(
@SerialName(expressionField)
val expression: String
) : RichBlock {
@EncodeDefault
@SerialName(typeField)
override val type: String = TYPE
override val markdown: String = markdown(expression)
override val html: String = html(expression)
companion object {
const val TYPE = "mathematical_expression"
fun markdown(expression: String): String = "\$\$" + expression + "\$\$"
fun html(expression: String): String = "<tg-math-block>$expression</tg-math-block>"
}
}
/**
* A block with an anchor.
*
* @see <a href="https://core.telegram.org/bots/api#richblockanchor">RichBlockAnchor</a>
*/
@Serializable
data class RichBlockAnchor(
@SerialName(nameField)
val name: String
) : RichBlock {
@EncodeDefault
@SerialName(typeField)
override val type: String = TYPE
override val markdown: String = markdown(name)
override val html: String = html(name)
companion object {
const val TYPE = "anchor"
fun markdown(name: String): String = "<a name=\"$name\"></a>"
fun html(name: String): String = "<a name=\"$name\"></a>"
}
}
/**
* A list of blocks.
*
* @see <a href="https://core.telegram.org/bots/api#richblocklist">RichBlockList</a>
*/
@Serializable
data class RichBlockList(
@SerialName(itemsField)
val items: List<RichBlockListItem>
) : RichBlock {
@EncodeDefault
@SerialName(typeField)
override val type: String = TYPE
override val markdown: String = markdown(items)
override val html: String = html(items)
companion object {
const val TYPE = "list"
fun markdown(items: List<RichBlockListItem>): String =
items.mapIndexed { index, item ->
val marker = when {
item.hasCheckbox == true -> if (item.isChecked == true) "- [x] " else "- [ ] "
item.labelType != null -> "${item.value ?: (index + 1)}. "
else -> "- "
}
item.blocks.toRichMarkdown().lineSequence().mapIndexed { lineIndex, line ->
if (lineIndex == 0) "$marker$line" else " $line"
}.joinToString(separator = "\n")
}.joinToString(separator = "\n")
fun html(items: List<RichBlockListItem>): String {
val ordered = items.any { it.labelType != null }
val tag = if (ordered) "ol" else "ul"
val renderedItems = items.joinToString(separator = "") { item ->
val attributes = buildString {
item.value?.let { append(" value=\"$it\"") }
item.labelType?.let { append(" type=\"$it\"") }
}
val checkbox = if (item.hasCheckbox == true) {
"<input type=\"checkbox\"${if (item.isChecked == true) " checked" else ""}>"
} else {
""
}
"<li$attributes>$checkbox${item.blocks.toRichHtml()}</li>"
}
return "<$tag>$renderedItems</$tag>"
}
}
}
/**
* A block quotation.
*
* @see <a href="https://core.telegram.org/bots/api#richblockblockquotation">RichBlockBlockQuotation</a>
*/
@Serializable
data class RichBlockBlockQuotation(
@SerialName(blocksField)
val blocks: List<RichBlock>,
@SerialName(creditField)
val credit: RichText? = null
) : RichBlock {
@EncodeDefault
@SerialName(typeField)
override val type: String = TYPE
override val markdown: String = markdown(blocks, credit)
override val html: String = html(blocks, credit)
companion object {
const val TYPE = "blockquote"
fun markdown(blocks: List<RichBlock>, credit: RichText?): String {
val quoted = blocks.toRichMarkdown().lineSequence().joinToString(separator = "\n") { line ->
if (line.isEmpty()) ">" else "> $line"
}
return quoted + (credit?.let { "\n> ${creditCiteMarkdown(it)}" } ?: "")
}
fun html(blocks: List<RichBlock>, credit: RichText?): String =
"<blockquote>${blocks.toRichHtml()}${creditCiteHtml(credit)}</blockquote>"
}
}
/**
* A quotation with centered text.
*
* @see <a href="https://core.telegram.org/bots/api#richblockpullquotation">RichBlockPullQuotation</a>
*/
@Serializable
data class RichBlockPullQuotation(
@SerialName(textField)
val text: RichText,
@SerialName(creditField)
val credit: RichText? = null
) : RichBlock {
@EncodeDefault
@SerialName(typeField)
override val type: String = TYPE
override val markdown: String = markdown(text, credit)
override val html: String = html(text, credit)
companion object {
const val TYPE = "pullquote"
fun markdown(text: RichText, credit: RichText?): String = "<aside>${text.markdown}${creditCiteMarkdown(credit)}</aside>"
fun html(text: RichText, credit: RichText?): String = "<aside>${text.html}${creditCiteHtml(credit)}</aside>"
}
}
/**
* A collage.
*
* @see <a href="https://core.telegram.org/bots/api#richblockcollage">RichBlockCollage</a>
*/
@Serializable
data class RichBlockCollage(
@SerialName(blocksField)
val blocks: List<RichBlock>,
@SerialName(captionField)
val caption: RichBlockCaption? = null
) : RichBlock {
@EncodeDefault
@SerialName(typeField)
override val type: String = TYPE
override val markdown: String = markdown(blocks, caption)
override val html: String = html(blocks, caption)
companion object {
const val TYPE = "collage"
fun markdown(blocks: List<RichBlock>, caption: RichBlockCaption?): String =
richMediaContainerMarkdown("tg-collage", blocks, caption)
fun html(blocks: List<RichBlock>, caption: RichBlockCaption?): String =
richMediaContainerHtml("tg-collage", blocks, caption)
}
}
/**
* A slideshow.
*
* @see <a href="https://core.telegram.org/bots/api#richblockslideshow">RichBlockSlideshow</a>
*/
@Serializable
data class RichBlockSlideshow(
@SerialName(blocksField)
val blocks: List<RichBlock>,
@SerialName(captionField)
val caption: RichBlockCaption? = null
) : RichBlock {
@EncodeDefault
@SerialName(typeField)
override val type: String = TYPE
override val markdown: String = markdown(blocks, caption)
override val html: String = html(blocks, caption)
companion object {
const val TYPE = "slideshow"
fun markdown(blocks: List<RichBlock>, caption: RichBlockCaption?): String =
richMediaContainerMarkdown("tg-slideshow", blocks, caption)
fun html(blocks: List<RichBlock>, caption: RichBlockCaption?): String =
richMediaContainerHtml("tg-slideshow", blocks, caption)
}
}
/**
* A table.
*
* @see <a href="https://core.telegram.org/bots/api#richblocktable">RichBlockTable</a>
*/
@Serializable
data class RichBlockTable(
@SerialName(cellsField)
val cells: List<List<RichBlockTableCell>>,
@SerialName(isBorderedField)
val isBordered: Boolean? = null,
@SerialName(isStripedField)
val isStriped: Boolean? = null,
@SerialName(captionField)
val caption: RichText? = null
) : RichBlock {
@EncodeDefault
@SerialName(typeField)
override val type: String = TYPE
override val markdown: String = markdown(cells)
override val html: String = html(cells, isBordered, isStriped, caption)
companion object {
const val TYPE = "table"
fun markdown(cells: List<List<RichBlockTableCell>>): String {
if (cells.isEmpty()) return ""
fun renderRow(row: List<RichBlockTableCell>): String =
row.joinToString(separator = " | ", prefix = "| ", postfix = " |") { it.text?.markdown ?: "" }
fun alignment(cell: RichBlockTableCell): String = when (cell.align) {
"left" -> ":---"
"center" -> ":--:"
"right" -> "---:"
else -> "---"
}
val header = cells.first()
val lines = mutableListOf(
renderRow(header),
header.joinToString(separator = " | ", prefix = "| ", postfix = " |") { alignment(it) }
)
cells.drop(1).forEach { lines.add(renderRow(it)) }
return lines.joinToString(separator = "\n")
}
fun html(cells: List<List<RichBlockTableCell>>, isBordered: Boolean?, isStriped: Boolean?, caption: RichText?): String {
val attributes = buildString {
if (isBordered == true) append(" bordered")
if (isStriped == true) append(" striped")
}
val captionPart = caption?.let { "<caption>${it.html}</caption>" } ?: ""
val rows = cells.joinToString(separator = "") { row ->
val renderedCells = row.joinToString(separator = "") { cell ->
val tag = if (cell.isHeader == true) "th" else "td"
val cellAttributes = buildString {
cell.colspan?.let { append(" colspan=\"$it\"") }
cell.rowspan?.let { append(" rowspan=\"$it\"") }
append(" align=\"${cell.align}\"")
append(" valign=\"${cell.valign}\"")
}
"<$tag$cellAttributes>${cell.text?.html ?: ""}</$tag>"
}
"<tr>$renderedCells</tr>"
}
return "<table$attributes>$captionPart$rows</table>"
}
}
}
/**
* An expandable block for details disclosure.
*
* @see <a href="https://core.telegram.org/bots/api#richblockdetails">RichBlockDetails</a>
*/
@Serializable
data class RichBlockDetails(
@SerialName(summaryField)
val summary: RichText,
@SerialName(blocksField)
val blocks: List<RichBlock>,
@SerialName(isOpenField)
val isOpen: Boolean? = null
) : RichBlock {
@EncodeDefault
@SerialName(typeField)
override val type: String = TYPE
override val markdown: String = markdown(summary, blocks, isOpen)
override val html: String = html(summary, blocks, isOpen)
companion object {
const val TYPE = "details"
fun markdown(summary: RichText, blocks: List<RichBlock>, isOpen: Boolean?): String {
val open = if (isOpen == true) " open" else ""
return "<details$open><summary>${summary.markdown}</summary>\n\n${blocks.toRichMarkdown()}\n\n</details>"
}
fun html(summary: RichText, blocks: List<RichBlock>, isOpen: Boolean?): String {
val open = if (isOpen == true) " open" else ""
return "<details$open><summary>${summary.html}</summary>${blocks.toRichHtml()}</details>"
}
}
}
/**
* A block with a map.
*
* @see <a href="https://core.telegram.org/bots/api#richblockmap">RichBlockMap</a>
*/
@Serializable
data class RichBlockMap(
@SerialName(locationField)
val location: StaticLocation,
/**
* Map zoom level; 13-20.
*/
@SerialName(zoomField)
val zoom: Int,
@SerialName(widthField)
val width: Int,
@SerialName(heightField)
val height: Int,
@SerialName(captionField)
val caption: RichBlockCaption? = null
) : RichBlock {
@EncodeDefault
@SerialName(typeField)
override val type: String = TYPE
override val markdown: String = markdown(location, zoom, caption)
override val html: String = html(location, zoom, caption)
companion object {
const val TYPE = "map"
fun markdown(location: StaticLocation, zoom: Int, caption: RichBlockCaption?): String {
val element = "<tg-map lat=\"${location.latitude}\" long=\"${location.longitude}\" zoom=\"$zoom\"/>"
return caption?.let { "<figure>$element<figcaption>${it.text.markdown}${creditCiteMarkdown(it.credit)}</figcaption></figure>" } ?: element
}
fun html(location: StaticLocation, zoom: Int, caption: RichBlockCaption?): String {
val element = "<tg-map lat=\"${location.latitude}\" long=\"${location.longitude}\" zoom=\"$zoom\"/>"
return caption?.let { "<figure>$element<figcaption>${it.text.html}${creditCiteHtml(it.credit)}</figcaption></figure>" } ?: element
}
}
}
/**
* A block with an animation.
*
* @see <a href="https://core.telegram.org/bots/api#richblockanimation">RichBlockAnimation</a>
*/
@Serializable
data class RichBlockAnimation(
@SerialName(animationField)
val animation: AnimationFile,
@SerialName(hasSpoilerField)
val hasSpoiler: Boolean? = null,
@SerialName(captionField)
override val caption: RichBlockCaption? = null
) : RichBlockMedia {
@EncodeDefault
@SerialName(typeField)
override val type: String = TYPE
override val markdown: String = markdown(animation, caption)
override val html: String = html(animation, hasSpoiler, caption)
override val media: TelegramMediaFile
get() = animation
companion object {
const val TYPE = "animation"
fun markdown(animation: AnimationFile, caption: RichBlockCaption?): String =
richMediaMarkdown(animation.fileId.fileId, caption)
fun html(animation: AnimationFile, hasSpoiler: Boolean?, caption: RichBlockCaption?): String =
richMediaHtml("video", animation.fileId.fileId, hasSpoiler == true, selfClosing = false, caption = caption)
}
}
/**
* A block with a music file.
*
* @see <a href="https://core.telegram.org/bots/api#richblockaudio">RichBlockAudio</a>
*/
@Serializable
data class RichBlockAudio(
@SerialName(audioField)
val audio: AudioFile,
@SerialName(captionField)
override val caption: RichBlockCaption? = null
) : RichBlockMedia {
@EncodeDefault
@SerialName(typeField)
override val type: String = TYPE
override val markdown: String = markdown(audio, caption)
override val html: String = html(audio, caption)
override val media: TelegramMediaFile
get() = audio
companion object {
const val TYPE = "audio"
fun markdown(audio: AudioFile, caption: RichBlockCaption?): String =
richMediaMarkdown(audio.fileId.fileId, caption)
fun html(audio: AudioFile, caption: RichBlockCaption?): String =
richMediaHtml("audio", audio.fileId.fileId, spoiler = false, selfClosing = false, caption = caption)
}
}
/**
* A block with a photo.
*
* @see <a href="https://core.telegram.org/bots/api#richblockphoto">RichBlockPhoto</a>
*/
@Serializable
data class RichBlockPhoto(
@SerialName(photoField)
val photo: PhotoFile,
@SerialName(hasSpoilerField)
val hasSpoiler: Boolean? = null,
@SerialName(captionField)
override val caption: RichBlockCaption? = null
) : RichBlockMedia {
@EncodeDefault
@SerialName(typeField)
override val type: String = TYPE
override val markdown: String = markdown(photo, caption)
override val html: String = html(photo, hasSpoiler, caption)
override val media: TelegramMediaFile
get() = photo
companion object {
const val TYPE = "photo"
fun markdown(photo: PhotoFile, caption: RichBlockCaption?): String =
richMediaMarkdown(photo.fileId.fileId, caption)
fun html(photo: PhotoFile, hasSpoiler: Boolean?, caption: RichBlockCaption?): String =
richMediaHtml("img", photo.fileId.fileId, hasSpoiler == true, selfClosing = true, caption = caption)
}
}
/**
* A block with a video.
*
* @see <a href="https://core.telegram.org/bots/api#richblockvideo">RichBlockVideo</a>
*/
@Serializable
data class RichBlockVideo(
@SerialName(videoField)
val video: VideoFile,
@SerialName(hasSpoilerField)
val hasSpoiler: Boolean? = null,
@SerialName(captionField)
override val caption: RichBlockCaption? = null
) : RichBlockMedia {
@EncodeDefault
@SerialName(typeField)
override val type: String = TYPE
override val markdown: String = markdown(video, caption)
override val html: String = html(video, hasSpoiler, caption)
override val media: TelegramMediaFile
get() = video
companion object {
const val TYPE = "video"
fun markdown(video: VideoFile, caption: RichBlockCaption?): String =
richMediaMarkdown(video.fileId.fileId, caption)
fun html(video: VideoFile, hasSpoiler: Boolean?, caption: RichBlockCaption?): String =
richMediaHtml("video", video.fileId.fileId, hasSpoiler == true, selfClosing = false, caption = caption)
}
}
/**
* A block with a voice note.
*
* @see <a href="https://core.telegram.org/bots/api#richblockvoicenote">RichBlockVoiceNote</a>
*/
@Serializable
data class RichBlockVoiceNote(
@SerialName(voiceNoteField)
val voiceNote: VoiceFile,
@SerialName(captionField)
override val caption: RichBlockCaption? = null
) : RichBlockMedia {
@EncodeDefault
@SerialName(typeField)
override val type: String = TYPE
override val markdown: String = markdown(voiceNote, caption)
override val html: String = html(voiceNote, caption)
override val media: TelegramMediaFile
get() = voiceNote
companion object {
const val TYPE = "voice_note"
fun markdown(voiceNote: VoiceFile, caption: RichBlockCaption?): String =
richMediaMarkdown(voiceNote.fileId.fileId, caption)
fun html(voiceNote: VoiceFile, caption: RichBlockCaption?): String =
richMediaHtml("audio", voiceNote.fileId.fileId, spoiler = false, selfClosing = false, caption = caption)
}
}
/**
* A block with a "Thinking…" placeholder. May be used only in sendRichMessageDraft.
*
* @see <a href="https://core.telegram.org/bots/api#richblockthinking">RichBlockThinking</a>
*/
@Serializable
data class RichBlockThinking(
@SerialName(textField)
val text: RichText
) : RichBlock {
@EncodeDefault
@SerialName(typeField)
override val type: String = TYPE
override val markdown: String = markdown(text)
override val html: String = html(text)
companion object {
const val TYPE = "thinking"
fun markdown(text: RichText): String = "<tg-thinking>${text.markdown}</tg-thinking>"
fun html(text: RichText): String = "<tg-thinking>${text.html}</tg-thinking>"
}
}

View File

@@ -0,0 +1,143 @@
package dev.inmo.tgbotapi.types.rich
import dev.inmo.tgbotapi.types.typeField
import dev.inmo.tgbotapi.utils.extensions.toHtml
import dev.inmo.tgbotapi.utils.internal.ClassCastsIncluded
import kotlinx.serialization.DeserializationStrategy
import kotlinx.serialization.KSerializer
import kotlinx.serialization.Serializable
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import kotlinx.serialization.json.*
/**
* Represents a rich formatted text. It can be either a plain text ([RichTextPlain]), a group of rich texts
* ([RichTextGroup]) or any of [RichTextEntity] subtypes.
*
* @see <a href="https://core.telegram.org/bots/api#richtext">RichText</a>
*/
@Serializable(RichTextSerializer::class)
@ClassCastsIncluded
sealed interface RichText {
/**
* Plain (unformatted) text of this [RichText]. For [RichTextEntity]s without an inner [RichText] it falls back to
* the most meaningful textual representation: alternative text for custom emojis, the expression for mathematical
* expressions and an empty string for anchors.
*/
val rawText: String
/**
* [Rich Markdown style](https://core.telegram.org/bots/api#rich-markdown-style) representation of this [RichText].
*/
val markdown: String
/**
* [Rich HTML style](https://core.telegram.org/bots/api#rich-html-style) representation of this [RichText].
*/
val html: String
}
/**
* A plain (non-formatted) part of a [RichText]. Serialized as a bare JSON string.
*/
@Serializable
data class RichTextPlain(
val text: String
) : RichText {
override val rawText: String = text
override val markdown: String = markdown(text)
override val html: String = html(text)
companion object {
fun markdown(text: String): String = text.escapeRichMarkdown()
fun html(text: String): String = text.toHtml()
}
}
/**
* A group of [RichText]s. Serialized as a JSON array.
*/
@Serializable
data class RichTextGroup(
val parts: List<RichText>
) : RichText {
override val rawText: String = parts.joinToString(separator = "") { it.rawText }
override val markdown: String = markdown(parts)
override val html: String = html(parts)
companion object {
fun markdown(parts: List<RichText>): String = parts.joinToString(separator = "") { it.markdown }
fun html(parts: List<RichText>): String = parts.joinToString(separator = "") { it.html }
}
}
/**
* Any typed (formatted) part of a [RichText]. Serialized as a JSON object with the [type] discriminator.
*/
@Serializable(RichTextEntitySerializer::class)
sealed interface RichTextEntity : RichText {
val type: String
override val markdown: String
override val html: String
}
object RichTextSerializer : KSerializer<RichText> {
override val descriptor: SerialDescriptor = JsonElement.serializer().descriptor
private fun fromJson(json: Json, element: JsonElement): RichText = when (element) {
is JsonArray -> RichTextGroup(element.map { fromJson(json, it) })
is JsonObject -> json.decodeFromJsonElement(RichTextEntitySerializer, element)
is JsonPrimitive -> RichTextPlain(element.content)
}
private fun toJson(json: Json, value: RichText): JsonElement = when (value) {
is RichTextPlain -> JsonPrimitive(value.text)
is RichTextGroup -> JsonArray(value.parts.map { toJson(json, it) })
is RichTextEntity -> json.encodeToJsonElement(RichTextEntitySerializer, value)
}
override fun deserialize(decoder: Decoder): RichText {
val input = decoder as JsonDecoder
return fromJson(input.json, input.decodeJsonElement())
}
override fun serialize(encoder: Encoder, value: RichText) {
val output = encoder as JsonEncoder
output.encodeJsonElement(toJson(output.json, value))
}
}
object RichTextEntitySerializer : JsonContentPolymorphicSerializer<RichTextEntity>(RichTextEntity::class) {
override fun selectDeserializer(element: JsonElement): DeserializationStrategy<RichTextEntity> {
return when (val type = element.jsonObject[typeField]?.jsonPrimitive?.content) {
RichTextBold.TYPE -> RichTextBold.serializer()
RichTextItalic.TYPE -> RichTextItalic.serializer()
RichTextUnderline.TYPE -> RichTextUnderline.serializer()
RichTextStrikethrough.TYPE -> RichTextStrikethrough.serializer()
RichTextSpoiler.TYPE -> RichTextSpoiler.serializer()
RichTextDateTime.TYPE -> RichTextDateTime.serializer()
RichTextTextMention.TYPE -> RichTextTextMention.serializer()
RichTextSubscript.TYPE -> RichTextSubscript.serializer()
RichTextSuperscript.TYPE -> RichTextSuperscript.serializer()
RichTextMarked.TYPE -> RichTextMarked.serializer()
RichTextCode.TYPE -> RichTextCode.serializer()
RichTextCustomEmoji.TYPE -> RichTextCustomEmoji.serializer()
RichTextMathematicalExpression.TYPE -> RichTextMathematicalExpression.serializer()
RichTextUrl.TYPE -> RichTextUrl.serializer()
RichTextEmailAddress.TYPE -> RichTextEmailAddress.serializer()
RichTextPhoneNumber.TYPE -> RichTextPhoneNumber.serializer()
RichTextBankCardNumber.TYPE -> RichTextBankCardNumber.serializer()
RichTextMention.TYPE -> RichTextMention.serializer()
RichTextHashtag.TYPE -> RichTextHashtag.serializer()
RichTextCashtag.TYPE -> RichTextCashtag.serializer()
RichTextBotCommand.TYPE -> RichTextBotCommand.serializer()
RichTextAnchor.TYPE -> RichTextAnchor.serializer()
RichTextAnchorLink.TYPE -> RichTextAnchorLink.serializer()
RichTextReference.TYPE -> RichTextReference.serializer()
RichTextReferenceLink.TYPE -> RichTextReferenceLink.serializer()
else -> error("Unknown RichTextEntity type: $type")
}
}
}

View File

@@ -0,0 +1,209 @@
package dev.inmo.tgbotapi.types.rich
import dev.inmo.tgbotapi.types.CustomEmojiId
import dev.inmo.tgbotapi.types.TelegramDate
import dev.inmo.tgbotapi.types.chat.User
/**
* [DslMarker] for the rich message builders, so the inner [RichTextBuilder], [RichBlocksBuilder] and
* [RichBlockListBuilder] scopes do not leak their receivers into each other.
*/
@DslMarker
annotation class RichTextDsl
/**
* Builder of a single [RichText]. Each call appends a part; [build] returns a [RichTextPlain]/[RichTextEntity] when there
* is exactly one part, a [RichTextGroup] otherwise.
*/
@RichTextDsl
class RichTextBuilder {
private val parts = mutableListOf<RichText>()
/** Appends an already built [RichText]. */
fun add(richText: RichText) {
parts.add(richText)
}
/** Appends an already built [RichText]. */
operator fun RichText.unaryPlus() = add(this)
/** Plain, non-formatted text. */
fun plain(text: String) = add(RichTextPlain(text))
fun bold(text: String) = add(RichTextBold(RichTextPlain(text)))
fun bold(block: RichTextBuilder.() -> Unit) = add(RichTextBold(buildRichText(block)))
fun italic(text: String) = add(RichTextItalic(RichTextPlain(text)))
fun italic(block: RichTextBuilder.() -> Unit) = add(RichTextItalic(buildRichText(block)))
fun underline(text: String) = add(RichTextUnderline(RichTextPlain(text)))
fun underline(block: RichTextBuilder.() -> Unit) = add(RichTextUnderline(buildRichText(block)))
fun strikethrough(text: String) = add(RichTextStrikethrough(RichTextPlain(text)))
fun strikethrough(block: RichTextBuilder.() -> Unit) = add(RichTextStrikethrough(buildRichText(block)))
fun spoiler(text: String) = add(RichTextSpoiler(RichTextPlain(text)))
fun spoiler(block: RichTextBuilder.() -> Unit) = add(RichTextSpoiler(buildRichText(block)))
fun subscript(text: String) = add(RichTextSubscript(RichTextPlain(text)))
fun subscript(block: RichTextBuilder.() -> Unit) = add(RichTextSubscript(buildRichText(block)))
fun superscript(text: String) = add(RichTextSuperscript(RichTextPlain(text)))
fun superscript(block: RichTextBuilder.() -> Unit) = add(RichTextSuperscript(buildRichText(block)))
fun marked(text: String) = add(RichTextMarked(RichTextPlain(text)))
fun marked(block: RichTextBuilder.() -> Unit) = add(RichTextMarked(buildRichText(block)))
fun code(text: String) = add(RichTextCode(RichTextPlain(text)))
fun code(block: RichTextBuilder.() -> Unit) = add(RichTextCode(buildRichText(block)))
fun dateTime(text: String, unixTime: TelegramDate, dateTimeFormat: String) =
add(RichTextDateTime(RichTextPlain(text), unixTime, dateTimeFormat))
fun dateTime(unixTime: TelegramDate, dateTimeFormat: String, block: RichTextBuilder.() -> Unit) =
add(RichTextDateTime(buildRichText(block), unixTime, dateTimeFormat))
fun textMention(text: String, user: User) = add(RichTextTextMention(RichTextPlain(text), user))
fun textMention(user: User, block: RichTextBuilder.() -> Unit) = add(RichTextTextMention(buildRichText(block), user))
fun customEmoji(customEmojiId: CustomEmojiId, alternativeText: String) =
add(RichTextCustomEmoji(customEmojiId, alternativeText))
fun mathematicalExpression(expression: String) = add(RichTextMathematicalExpression(expression))
fun url(text: String, url: String) = add(RichTextUrl(RichTextPlain(text), url))
fun url(url: String, block: RichTextBuilder.() -> Unit) = add(RichTextUrl(buildRichText(block), url))
fun email(text: String, emailAddress: String) = add(RichTextEmailAddress(RichTextPlain(text), emailAddress))
fun email(emailAddress: String, block: RichTextBuilder.() -> Unit) =
add(RichTextEmailAddress(buildRichText(block), emailAddress))
fun phone(text: String, phoneNumber: String) = add(RichTextPhoneNumber(RichTextPlain(text), phoneNumber))
fun phone(phoneNumber: String, block: RichTextBuilder.() -> Unit) =
add(RichTextPhoneNumber(buildRichText(block), phoneNumber))
fun bankCard(text: String, bankCardNumber: String) = add(RichTextBankCardNumber(RichTextPlain(text), bankCardNumber))
fun bankCard(bankCardNumber: String, block: RichTextBuilder.() -> Unit) =
add(RichTextBankCardNumber(buildRichText(block), bankCardNumber))
fun mention(text: String, username: String) = add(RichTextMention(RichTextPlain(text), username))
fun mention(username: String, block: RichTextBuilder.() -> Unit) = add(RichTextMention(buildRichText(block), username))
fun hashtag(text: String, hashtag: String) = add(RichTextHashtag(RichTextPlain(text), hashtag))
fun hashtag(hashtag: String, block: RichTextBuilder.() -> Unit) = add(RichTextHashtag(buildRichText(block), hashtag))
fun cashtag(text: String, cashtag: String) = add(RichTextCashtag(RichTextPlain(text), cashtag))
fun cashtag(cashtag: String, block: RichTextBuilder.() -> Unit) = add(RichTextCashtag(buildRichText(block), cashtag))
fun botCommand(text: String, botCommand: String) = add(RichTextBotCommand(RichTextPlain(text), botCommand))
fun botCommand(botCommand: String, block: RichTextBuilder.() -> Unit) =
add(RichTextBotCommand(buildRichText(block), botCommand))
fun anchor(name: String) = add(RichTextAnchor(name))
fun anchorLink(text: String, anchorName: String) = add(RichTextAnchorLink(RichTextPlain(text), anchorName))
fun anchorLink(anchorName: String, block: RichTextBuilder.() -> Unit) =
add(RichTextAnchorLink(buildRichText(block), anchorName))
fun reference(text: String, name: String) = add(RichTextReference(RichTextPlain(text), name))
fun reference(name: String, block: RichTextBuilder.() -> Unit) = add(RichTextReference(buildRichText(block), name))
fun referenceLink(text: String, referenceName: String) =
add(RichTextReferenceLink(RichTextPlain(text), referenceName))
fun referenceLink(referenceName: String, block: RichTextBuilder.() -> Unit) =
add(RichTextReferenceLink(buildRichText(block), referenceName))
fun build(): RichText = when (parts.size) {
0 -> RichTextGroup(emptyList())
1 -> parts.single()
else -> RichTextGroup(parts.toList())
}
}
/**
* Builder of [RichBlockListItem]s used inside [RichBlocksBuilder.list].
*/
@RichTextDsl
class RichBlockListBuilder {
private val items = mutableListOf<RichBlockListItem>()
fun item(
label: String,
hasCheckbox: Boolean? = null,
isChecked: Boolean? = null,
value: Int? = null,
labelType: String? = null,
block: RichBlocksBuilder.() -> Unit
) {
items.add(RichBlockListItem(label, buildRichBlocks(block), hasCheckbox, isChecked, value, labelType))
}
fun item(label: String, text: String) {
items.add(RichBlockListItem(label, listOf(RichBlockParagraph(RichTextPlain(text)))))
}
fun build(): List<RichBlockListItem> = items.toList()
}
/**
* Builder of a [List] of [RichBlock]s - the root of the rich message DSL. Text-bearing and container blocks have their
* own DSL functions; file/cell-heavy blocks (media, collage, slideshow, table, map) can be appended with [add] / unary
* plus.
*/
@RichTextDsl
class RichBlocksBuilder {
private val blocks = mutableListOf<RichBlock>()
/** Appends an already built [RichBlock]. */
fun add(block: RichBlock) {
blocks.add(block)
}
/** Appends an already built [RichBlock]. */
operator fun RichBlock.unaryPlus() = add(this)
fun paragraph(text: String) = add(RichBlockParagraph(RichTextPlain(text)))
fun paragraph(block: RichTextBuilder.() -> Unit) = add(RichBlockParagraph(buildRichText(block)))
fun heading(text: String, level: Int) = add(RichBlockSectionHeading(RichTextPlain(text), level))
fun heading(level: Int, block: RichTextBuilder.() -> Unit) = add(RichBlockSectionHeading(buildRichText(block), level))
fun preformatted(text: String, language: String? = null) = add(RichBlockPreformatted(RichTextPlain(text), language))
fun footer(text: String) = add(RichBlockFooter(RichTextPlain(text)))
fun footer(block: RichTextBuilder.() -> Unit) = add(RichBlockFooter(buildRichText(block)))
fun divider() = add(RichBlockDivider())
fun mathematicalExpression(expression: String) = add(RichBlockMathematicalExpression(expression))
fun anchor(name: String) = add(RichBlockAnchor(name))
fun thinking(text: String) = add(RichBlockThinking(RichTextPlain(text)))
fun thinking(block: RichTextBuilder.() -> Unit) = add(RichBlockThinking(buildRichText(block)))
fun list(block: RichBlockListBuilder.() -> Unit) = add(RichBlockList(RichBlockListBuilder().apply(block).build()))
fun blockQuotation(credit: RichText? = null, block: RichBlocksBuilder.() -> Unit) =
add(RichBlockBlockQuotation(buildRichBlocks(block), credit))
fun pullQuotation(credit: RichText? = null, block: RichTextBuilder.() -> Unit) =
add(RichBlockPullQuotation(buildRichText(block), credit))
fun details(summary: RichText, isOpen: Boolean? = null, block: RichBlocksBuilder.() -> Unit) =
add(RichBlockDetails(summary, buildRichBlocks(block), isOpen))
fun details(summary: String, isOpen: Boolean? = null, block: RichBlocksBuilder.() -> Unit) =
details(RichTextPlain(summary), isOpen, block)
fun build(): List<RichBlock> = blocks.toList()
}
/** Builds a [RichText] using the [RichTextBuilder] DSL. */
fun buildRichText(block: RichTextBuilder.() -> Unit): RichText = RichTextBuilder().apply(block).build()
/** Builds a [List] of [RichBlock]s using the [RichBlocksBuilder] DSL. */
fun buildRichBlocks(block: RichBlocksBuilder.() -> Unit): List<RichBlock> = RichBlocksBuilder().apply(block).build()
/** Builds a [RichTextInfo] using the [RichBlocksBuilder] DSL. */
fun buildRichTextInfo(isRtl: Boolean? = null, block: RichBlocksBuilder.() -> Unit): RichTextInfo =
RichTextInfo(buildRichBlocks(block), isRtl)

View File

@@ -0,0 +1,690 @@
package dev.inmo.tgbotapi.types.rich
import dev.inmo.tgbotapi.types.CustomEmojiId
import dev.inmo.tgbotapi.types.alternativeTextField
import dev.inmo.tgbotapi.types.anchorNameField
import dev.inmo.tgbotapi.types.bankCardNumberField
import dev.inmo.tgbotapi.types.botCommandFullField
import dev.inmo.tgbotapi.types.cashtagField
import dev.inmo.tgbotapi.types.chat.User
import dev.inmo.tgbotapi.types.customEmojiIdField
import dev.inmo.tgbotapi.types.dateTimeFormatField
import dev.inmo.tgbotapi.types.emailAddressField
import dev.inmo.tgbotapi.types.expressionField
import dev.inmo.tgbotapi.types.hashtagField
import dev.inmo.tgbotapi.types.internalUserLinkBeginning
import dev.inmo.tgbotapi.types.nameField
import dev.inmo.tgbotapi.types.phoneNumberField
import dev.inmo.tgbotapi.types.referenceNameField
import dev.inmo.tgbotapi.types.TelegramDate
import dev.inmo.tgbotapi.types.textField
import dev.inmo.tgbotapi.types.typeField
import dev.inmo.tgbotapi.types.unixTimeField
import dev.inmo.tgbotapi.types.urlField
import dev.inmo.tgbotapi.types.userField
import dev.inmo.tgbotapi.types.usernameField
import dev.inmo.tgbotapi.utils.extensions.toHtml
import kotlinx.serialization.EncodeDefault
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
/**
* A bold [RichTextEntity].
*
* @see <a href="https://core.telegram.org/bots/api#richtextbold">RichTextBold</a>
*/
@Serializable
data class RichTextBold(
@SerialName(textField)
val text: RichText
) : RichTextEntity {
@EncodeDefault
@SerialName(typeField)
override val type: String = TYPE
override val rawText: String = text.rawText
override val markdown: String = markdown(text)
override val html: String = html(text)
companion object {
const val TYPE = "bold"
fun markdown(text: RichText): String = "**${text.markdown}**"
fun html(text: RichText): String = "<b>${text.html}</b>"
}
}
/**
* An italicized [RichTextEntity].
*
* @see <a href="https://core.telegram.org/bots/api#richtextitalic">RichTextItalic</a>
*/
@Serializable
data class RichTextItalic(
@SerialName(textField)
val text: RichText
) : RichTextEntity {
@EncodeDefault
@SerialName(typeField)
override val type: String = TYPE
override val rawText: String = text.rawText
override val markdown: String = markdown(text)
override val html: String = html(text)
companion object {
const val TYPE = "italic"
fun markdown(text: RichText): String = "*${text.markdown}*"
fun html(text: RichText): String = "<i>${text.html}</i>"
}
}
/**
* An underlined [RichTextEntity].
*
* @see <a href="https://core.telegram.org/bots/api#richtextunderline">RichTextUnderline</a>
*/
@Serializable
data class RichTextUnderline(
@SerialName(textField)
val text: RichText
) : RichTextEntity {
@EncodeDefault
@SerialName(typeField)
override val type: String = TYPE
override val rawText: String = text.rawText
override val markdown: String = markdown(text)
override val html: String = html(text)
companion object {
const val TYPE = "underline"
fun markdown(text: RichText): String = "<u>${text.markdown}</u>"
fun html(text: RichText): String = "<u>${text.html}</u>"
}
}
/**
* A strikethrough [RichTextEntity].
*
* @see <a href="https://core.telegram.org/bots/api#richtextstrikethrough">RichTextStrikethrough</a>
*/
@Serializable
data class RichTextStrikethrough(
@SerialName(textField)
val text: RichText
) : RichTextEntity {
@EncodeDefault
@SerialName(typeField)
override val type: String = TYPE
override val rawText: String = text.rawText
override val markdown: String = markdown(text)
override val html: String = html(text)
companion object {
const val TYPE = "strikethrough"
fun markdown(text: RichText): String = "~~${text.markdown}~~"
fun html(text: RichText): String = "<s>${text.html}</s>"
}
}
/**
* A [RichTextEntity] covered by a spoiler.
*
* @see <a href="https://core.telegram.org/bots/api#richtextspoiler">RichTextSpoiler</a>
*/
@Serializable
data class RichTextSpoiler(
@SerialName(textField)
val text: RichText
) : RichTextEntity {
@EncodeDefault
@SerialName(typeField)
override val type: String = TYPE
override val rawText: String = text.rawText
override val markdown: String = markdown(text)
override val html: String = html(text)
companion object {
const val TYPE = "spoiler"
fun markdown(text: RichText): String = "||${text.markdown}||"
fun html(text: RichText): String = "<tg-spoiler>${text.html}</tg-spoiler>"
}
}
/**
* A subscript [RichTextEntity].
*
* @see <a href="https://core.telegram.org/bots/api#richtextsubscript">RichTextSubscript</a>
*/
@Serializable
data class RichTextSubscript(
@SerialName(textField)
val text: RichText
) : RichTextEntity {
@EncodeDefault
@SerialName(typeField)
override val type: String = TYPE
override val rawText: String = text.rawText
override val markdown: String = markdown(text)
override val html: String = html(text)
companion object {
const val TYPE = "subscript"
fun markdown(text: RichText): String = "<sub>${text.markdown}</sub>"
fun html(text: RichText): String = "<sub>${text.html}</sub>"
}
}
/**
* A superscript [RichTextEntity].
*
* @see <a href="https://core.telegram.org/bots/api#richtextsuperscript">RichTextSuperscript</a>
*/
@Serializable
data class RichTextSuperscript(
@SerialName(textField)
val text: RichText
) : RichTextEntity {
@EncodeDefault
@SerialName(typeField)
override val type: String = TYPE
override val rawText: String = text.rawText
override val markdown: String = markdown(text)
override val html: String = html(text)
companion object {
const val TYPE = "superscript"
fun markdown(text: RichText): String = "<sup>${text.markdown}</sup>"
fun html(text: RichText): String = "<sup>${text.html}</sup>"
}
}
/**
* A marked [RichTextEntity].
*
* @see <a href="https://core.telegram.org/bots/api#richtextmarked">RichTextMarked</a>
*/
@Serializable
data class RichTextMarked(
@SerialName(textField)
val text: RichText
) : RichTextEntity {
@EncodeDefault
@SerialName(typeField)
override val type: String = TYPE
override val rawText: String = text.rawText
override val markdown: String = markdown(text)
override val html: String = html(text)
companion object {
const val TYPE = "marked"
fun markdown(text: RichText): String = "==${text.markdown}=="
fun html(text: RichText): String = "<mark>${text.html}</mark>"
}
}
/**
* A monowidth [RichTextEntity].
*
* @see <a href="https://core.telegram.org/bots/api#richtextcode">RichTextCode</a>
*/
@Serializable
data class RichTextCode(
@SerialName(textField)
val text: RichText
) : RichTextEntity {
@EncodeDefault
@SerialName(typeField)
override val type: String = TYPE
override val rawText: String = text.rawText
override val markdown: String = markdown(text)
override val html: String = html(text)
companion object {
const val TYPE = "code"
fun markdown(text: RichText): String = "`${text.rawText}`"
fun html(text: RichText): String = "<code>${text.html}</code>"
}
}
/**
* A formatted date and time [RichTextEntity].
*
* @see <a href="https://core.telegram.org/bots/api#richtextdatetime">RichTextDateTime</a>
*/
@Serializable
data class RichTextDateTime(
@SerialName(textField)
val text: RichText,
@SerialName(unixTimeField)
val unixTime: TelegramDate,
@SerialName(dateTimeFormatField)
val dateTimeFormat: String
) : RichTextEntity {
@EncodeDefault
@SerialName(typeField)
override val type: String = TYPE
override val rawText: String = text.rawText
override val markdown: String = markdown(text, unixTime, dateTimeFormat)
override val html: String = html(text, unixTime, dateTimeFormat)
companion object {
const val TYPE = "date_time"
fun markdown(text: RichText, unixTime: TelegramDate, dateTimeFormat: String): String =
"![${text.markdown}](tg://time?unix=${unixTime.date}&format=$dateTimeFormat)"
fun html(text: RichText, unixTime: TelegramDate, dateTimeFormat: String): String =
"<tg-time unix=\"${unixTime.date}\" format=\"$dateTimeFormat\">${text.html}</tg-time>"
}
}
/**
* A mention of a Telegram user by their identifier.
*
* @see <a href="https://core.telegram.org/bots/api#richtexttextmention">RichTextTextMention</a>
*/
@Serializable
data class RichTextTextMention(
@SerialName(textField)
val text: RichText,
@SerialName(userField)
val user: User
) : RichTextEntity {
@EncodeDefault
@SerialName(typeField)
override val type: String = TYPE
override val rawText: String = text.rawText
override val markdown: String = markdown(text, user)
override val html: String = html(text, user)
companion object {
const val TYPE = "text_mention"
fun markdown(text: RichText, user: User): String =
"[${text.markdown}]($internalUserLinkBeginning${user.id.chatId.long})"
fun html(text: RichText, user: User): String =
"<a href=\"$internalUserLinkBeginning${user.id.chatId.long}\">${text.html}</a>"
}
}
/**
* A custom emoji [RichTextEntity].
*
* @see <a href="https://core.telegram.org/bots/api#richtextcustomemoji">RichTextCustomEmoji</a>
*/
@Serializable
data class RichTextCustomEmoji(
@SerialName(customEmojiIdField)
val customEmojiId: CustomEmojiId,
@SerialName(alternativeTextField)
val alternativeText: String
) : RichTextEntity {
@EncodeDefault
@SerialName(typeField)
override val type: String = TYPE
override val rawText: String = alternativeText
override val markdown: String = markdown(customEmojiId, alternativeText)
override val html: String = html(customEmojiId, alternativeText)
companion object {
const val TYPE = "custom_emoji"
fun markdown(customEmojiId: CustomEmojiId, alternativeText: String): String =
"![${alternativeText.escapeRichMarkdown()}](tg://emoji?id=${customEmojiId.string})"
fun html(customEmojiId: CustomEmojiId, alternativeText: String): String =
"<tg-emoji emoji-id=\"${customEmojiId.string}\">${alternativeText.toHtml()}</tg-emoji>"
}
}
/**
* A mathematical expression in LaTeX format.
*
* @see <a href="https://core.telegram.org/bots/api#richtextmathematicalexpression">RichTextMathematicalExpression</a>
*/
@Serializable
data class RichTextMathematicalExpression(
@SerialName(expressionField)
val expression: String
) : RichTextEntity {
@EncodeDefault
@SerialName(typeField)
override val type: String = TYPE
override val rawText: String = expression
override val markdown: String = markdown(expression)
override val html: String = html(expression)
companion object {
const val TYPE = "mathematical_expression"
fun markdown(expression: String): String = "\$$expression\$"
fun html(expression: String): String = "<tg-math>$expression</tg-math>"
}
}
/**
* A [RichTextEntity] with a link.
*
* @see <a href="https://core.telegram.org/bots/api#richtexturl">RichTextUrl</a>
*/
@Serializable
data class RichTextUrl(
@SerialName(textField)
val text: RichText,
@SerialName(urlField)
val url: String
) : RichTextEntity {
@EncodeDefault
@SerialName(typeField)
override val type: String = TYPE
override val rawText: String = text.rawText
override val markdown: String = markdown(text, url)
override val html: String = html(text, url)
companion object {
const val TYPE = "url"
fun markdown(text: RichText, url: String): String = "[${text.markdown}]($url)"
fun html(text: RichText, url: String): String = "<a href=\"$url\">${text.html}</a>"
}
}
/**
* A [RichTextEntity] with an email address.
*
* @see <a href="https://core.telegram.org/bots/api#richtextemailaddress">RichTextEmailAddress</a>
*/
@Serializable
data class RichTextEmailAddress(
@SerialName(textField)
val text: RichText,
@SerialName(emailAddressField)
val emailAddress: String
) : RichTextEntity {
@EncodeDefault
@SerialName(typeField)
override val type: String = TYPE
override val rawText: String = text.rawText
override val markdown: String = markdown(text, emailAddress)
override val html: String = html(text, emailAddress)
companion object {
const val TYPE = "email_address"
fun markdown(text: RichText, emailAddress: String): String = "[${text.markdown}](mailto:$emailAddress)"
fun html(text: RichText, emailAddress: String): String = "<a href=\"mailto:$emailAddress\">${text.html}</a>"
}
}
/**
* A [RichTextEntity] with a phone number.
*
* @see <a href="https://core.telegram.org/bots/api#richtextphonenumber">RichTextPhoneNumber</a>
*/
@Serializable
data class RichTextPhoneNumber(
@SerialName(textField)
val text: RichText,
@SerialName(phoneNumberField)
val phoneNumber: String
) : RichTextEntity {
@EncodeDefault
@SerialName(typeField)
override val type: String = TYPE
override val rawText: String = text.rawText
override val markdown: String = markdown(text, phoneNumber)
override val html: String = html(text, phoneNumber)
companion object {
const val TYPE = "phone_number"
fun markdown(text: RichText, phoneNumber: String): String = "[${text.markdown}](tel:$phoneNumber)"
fun html(text: RichText, phoneNumber: String): String = "<a href=\"tel:$phoneNumber\">${text.html}</a>"
}
}
/**
* A [RichTextEntity] with a bank card number.
*
* @see <a href="https://core.telegram.org/bots/api#richtextbankcardnumber">RichTextBankCardNumber</a>
*/
@Serializable
data class RichTextBankCardNumber(
@SerialName(textField)
val text: RichText,
@SerialName(bankCardNumberField)
val bankCardNumber: String
) : RichTextEntity {
@EncodeDefault
@SerialName(typeField)
override val type: String = TYPE
override val rawText: String = text.rawText
override val markdown: String = markdown(text)
override val html: String = html(text)
companion object {
const val TYPE = "bank_card_number"
fun markdown(text: RichText): String = text.markdown
fun html(text: RichText): String = text.html
}
}
/**
* A mention by a username.
*
* @see <a href="https://core.telegram.org/bots/api#richtextmention">RichTextMention</a>
*/
@Serializable
data class RichTextMention(
@SerialName(textField)
val text: RichText,
@SerialName(usernameField)
val username: String
) : RichTextEntity {
@EncodeDefault
@SerialName(typeField)
override val type: String = TYPE
override val rawText: String = text.rawText
override val markdown: String = markdown(text)
override val html: String = html(text)
companion object {
const val TYPE = "mention"
fun markdown(text: RichText): String = text.markdown
fun html(text: RichText): String = text.html
}
}
/**
* A hashtag.
*
* @see <a href="https://core.telegram.org/bots/api#richtexthashtag">RichTextHashtag</a>
*/
@Serializable
data class RichTextHashtag(
@SerialName(textField)
val text: RichText,
@SerialName(hashtagField)
val hashtag: String
) : RichTextEntity {
@EncodeDefault
@SerialName(typeField)
override val type: String = TYPE
override val rawText: String = text.rawText
override val markdown: String = markdown(text)
override val html: String = html(text)
companion object {
const val TYPE = "hashtag"
fun markdown(text: RichText): String = text.markdown
fun html(text: RichText): String = text.html
}
}
/**
* A cashtag.
*
* @see <a href="https://core.telegram.org/bots/api#richtextcashtag">RichTextCashtag</a>
*/
@Serializable
data class RichTextCashtag(
@SerialName(textField)
val text: RichText,
@SerialName(cashtagField)
val cashtag: String
) : RichTextEntity {
@EncodeDefault
@SerialName(typeField)
override val type: String = TYPE
override val rawText: String = text.rawText
override val markdown: String = markdown(text)
override val html: String = html(text)
companion object {
const val TYPE = "cashtag"
fun markdown(text: RichText): String = text.markdown
fun html(text: RichText): String = text.html
}
}
/**
* A bot command.
*
* @see <a href="https://core.telegram.org/bots/api#richtextbotcommand">RichTextBotCommand</a>
*/
@Serializable
data class RichTextBotCommand(
@SerialName(textField)
val text: RichText,
@SerialName(botCommandFullField)
val botCommand: String
) : RichTextEntity {
@EncodeDefault
@SerialName(typeField)
override val type: String = TYPE
override val rawText: String = text.rawText
override val markdown: String = markdown(text)
override val html: String = html(text)
companion object {
const val TYPE = "bot_command"
fun markdown(text: RichText): String = text.markdown
fun html(text: RichText): String = text.html
}
}
/**
* An anchor.
*
* @see <a href="https://core.telegram.org/bots/api#richtextanchor">RichTextAnchor</a>
*/
@Serializable
data class RichTextAnchor(
@SerialName(nameField)
val name: String
) : RichTextEntity {
@EncodeDefault
@SerialName(typeField)
override val type: String = TYPE
override val rawText: String = ""
override val markdown: String = markdown(name)
override val html: String = html(name)
companion object {
const val TYPE = "anchor"
fun markdown(name: String): String = "<a name=\"$name\"></a>"
fun html(name: String): String = "<a name=\"$name\"></a>"
}
}
/**
* A link to an anchor.
*
* @see <a href="https://core.telegram.org/bots/api#richtextanchorlink">RichTextAnchorLink</a>
*/
@Serializable
data class RichTextAnchorLink(
@SerialName(textField)
val text: RichText,
@SerialName(anchorNameField)
val anchorName: String
) : RichTextEntity {
@EncodeDefault
@SerialName(typeField)
override val type: String = TYPE
override val rawText: String = text.rawText
override val markdown: String = markdown(text, anchorName)
override val html: String = html(text, anchorName)
companion object {
const val TYPE = "anchor_link"
fun markdown(text: RichText, anchorName: String): String = "[${text.markdown}](#$anchorName)"
fun html(text: RichText, anchorName: String): String = "<a href=\"#$anchorName\">${text.html}</a>"
}
}
/**
* A reference.
*
* @see <a href="https://core.telegram.org/bots/api#richtextreference">RichTextReference</a>
*/
@Serializable
data class RichTextReference(
@SerialName(textField)
val text: RichText,
@SerialName(nameField)
val name: String
) : RichTextEntity {
@EncodeDefault
@SerialName(typeField)
override val type: String = TYPE
override val rawText: String = text.rawText
override val markdown: String = markdown(text, name)
override val html: String = html(text, name)
companion object {
const val TYPE = "reference"
fun markdown(text: RichText, name: String): String = "<tg-reference name=\"$name\">${text.markdown}</tg-reference>"
fun html(text: RichText, name: String): String = "<tg-reference name=\"$name\">${text.html}</tg-reference>"
}
}
/**
* A link to a reference.
*
* @see <a href="https://core.telegram.org/bots/api#richtextreferencelink">RichTextReferenceLink</a>
*/
@Serializable
data class RichTextReferenceLink(
@SerialName(textField)
val text: RichText,
@SerialName(referenceNameField)
val referenceName: String
) : RichTextEntity {
@EncodeDefault
@SerialName(typeField)
override val type: String = TYPE
override val rawText: String = text.rawText
override val markdown: String = markdown(text, referenceName)
override val html: String = html(text, referenceName)
companion object {
const val TYPE = "reference_link"
fun markdown(text: RichText, referenceName: String): String = "[${text.markdown}](#$referenceName)"
fun html(text: RichText, referenceName: String): String = "<a href=\"#$referenceName\">${text.html}</a>"
}
}

View File

@@ -0,0 +1,23 @@
package dev.inmo.tgbotapi.types.rich
/**
* Characters which have a special meaning in the
* [Rich Markdown style](https://core.telegram.org/bots/api#rich-markdown-style) and must be escaped with a backslash
* to be represented literally.
*/
private val richMarkdownSpecialCharacters = setOf(
'\\', '`', '*', '_', '~', '|', '[', ']', '(', ')', '<', '>', '#', '=', '!', '$'
)
/**
* Escapes all the [richMarkdownSpecialCharacters] of the receiver with a backslash so that the resulting string is
* represented literally in the [Rich Markdown style](https://core.telegram.org/bots/api#rich-markdown-style).
*/
fun String.escapeRichMarkdown(): String = buildString {
for (character in this@escapeRichMarkdown) {
if (character in richMarkdownSpecialCharacters) {
append('\\')
}
append(character)
}
}

View File

@@ -0,0 +1,19 @@
package dev.inmo.tgbotapi.types.rich
import dev.inmo.tgbotapi.types.blocksField
import dev.inmo.tgbotapi.types.isRtlField
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
/**
* Rich formatted message.
*
* @see <a href="https://core.telegram.org/bots/api#richmessage">RichMessage</a>
*/
@Serializable
data class RichTextInfo(
@SerialName(blocksField)
val blocks: List<RichBlock>,
@SerialName(isRtlField)
val isRtl: Boolean? = null
)

View File

@@ -0,0 +1,71 @@
package dev.inmo.tgbotapi.types
import dev.inmo.tgbotapi.types.rich.*
import kotlinx.serialization.json.Json
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertTrue
class RichMessageSerializationTest {
private val json = Json { encodeDefaults = true }
@Test
fun decodesRichMessageWithMixedRichText() {
val source = """
{
"blocks": [
{
"type": "paragraph",
"text": ["Hello ", {"type": "bold", "text": "world"}, "!"]
},
{"type": "heading", "text": "Title", "size": 1},
{"type": "divider"},
{"type": "list", "items": [
{"label": "1", "blocks": [{"type": "paragraph", "text": "first"}]}
]}
],
"is_rtl": false
}
""".trimIndent()
val message = json.decodeFromString(RichTextInfo.serializer(), source)
assertEquals(4, message.blocks.size)
val paragraph = message.blocks[0] as RichBlockParagraph
val group = paragraph.text as RichTextGroup
assertEquals(RichTextPlain("Hello "), group.parts[0])
assertEquals(RichTextBold(RichTextPlain("world")), group.parts[1])
assertEquals(RichTextPlain("!"), group.parts[2])
val heading = message.blocks[1] as RichBlockSectionHeading
assertEquals(RichTextPlain("Title"), heading.text)
assertEquals(1, heading.level)
assertTrue(message.blocks[2] is RichBlockDivider)
val list = message.blocks[3] as RichBlockList
assertEquals("1", list.items[0].label)
}
@Test
fun roundTripsRichMessage() {
val message = RichTextInfo(
blocks = listOf(
RichBlockParagraph(
RichTextGroup(
listOf(
RichTextPlain("a "),
RichTextItalic(RichTextPlain("b")),
RichTextUrl(RichTextPlain("link"), "https://example.org")
)
)
),
RichBlockDivider()
)
)
val encoded = json.encodeToString(RichTextInfo.serializer(), message)
val decoded = json.decodeFromString(RichTextInfo.serializer(), encoded)
assertEquals(message, decoded)
}
}

View File

@@ -0,0 +1,141 @@
package dev.inmo.tgbotapi.types.rich
import kotlin.test.Test
import kotlin.test.assertEquals
class RichBlockFormattingTest {
@Test
fun paragraph() {
val block = RichBlockParagraph(RichTextPlain("Hello"))
assertEquals("Hello", block.markdown)
assertEquals("<p>Hello</p>", block.html)
}
@Test
fun heading() {
val block = RichBlockSectionHeading(RichTextPlain("Title"), 2)
assertEquals("## Title", block.markdown)
assertEquals("<h2>Title</h2>", block.html)
}
@Test
fun divider() {
val block = RichBlockDivider()
assertEquals("---", block.markdown)
assertEquals("<hr/>", block.html)
}
@Test
fun footer() {
val block = RichBlockFooter(RichTextPlain("f"))
assertEquals("<footer>f</footer>", block.markdown)
assertEquals("<footer>f</footer>", block.html)
}
@Test
fun preformatted() {
val withLanguage = RichBlockPreformatted(RichTextPlain("code"), "kotlin")
assertEquals("```kotlin\ncode\n```", withLanguage.markdown)
assertEquals("<pre><code class=\"language-kotlin\">code</code></pre>", withLanguage.html)
val withoutLanguage = RichBlockPreformatted(RichTextPlain("c"))
assertEquals("```\nc\n```", withoutLanguage.markdown)
assertEquals("<pre>c</pre>", withoutLanguage.html)
}
@Test
fun mathematicalExpression() {
val block = RichBlockMathematicalExpression("E=mc^2")
assertEquals("\$\$E=mc^2\$\$", block.markdown)
assertEquals("<tg-math-block>E=mc^2</tg-math-block>", block.html)
}
@Test
fun anchor() {
val block = RichBlockAnchor("top")
assertEquals("<a name=\"top\"></a>", block.markdown)
assertEquals("<a name=\"top\"></a>", block.html)
}
@Test
fun bulletList() {
val block = RichBlockList(listOf(RichBlockListItem("-", listOf(RichBlockParagraph(RichTextPlain("one"))))))
assertEquals("- one", block.markdown)
assertEquals("<ul><li><p>one</p></li></ul>", block.html)
}
@Test
fun orderedList() {
val block = RichBlockList(
listOf(RichBlockListItem("1", listOf(RichBlockParagraph(RichTextPlain("one"))), labelType = "1"))
)
assertEquals("1. one", block.markdown)
assertEquals("<ol><li type=\"1\"><p>one</p></li></ol>", block.html)
}
@Test
fun taskList() {
val block = RichBlockList(
listOf(
RichBlockListItem(
"x",
listOf(RichBlockParagraph(RichTextPlain("done"))),
hasCheckbox = true,
isChecked = true
)
)
)
assertEquals("- [x] done", block.markdown)
assertEquals("<ul><li><input type=\"checkbox\" checked><p>done</p></li></ul>", block.html)
}
@Test
fun blockQuotation() {
val block = RichBlockBlockQuotation(listOf(RichBlockParagraph(RichTextPlain("q"))))
assertEquals("> q", block.markdown)
assertEquals("<blockquote><p>q</p></blockquote>", block.html)
}
@Test
fun details() {
val block = RichBlockDetails(RichTextPlain("sum"), listOf(RichBlockParagraph(RichTextPlain("body"))), isOpen = true)
assertEquals("<details open><summary>sum</summary>\n\nbody\n\n</details>", block.markdown)
assertEquals("<details open><summary>sum</summary><p>body</p></details>", block.html)
}
@Test
fun table() {
val block = RichBlockTable(
listOf(
listOf(
RichBlockTableCell(text = RichTextPlain("H1"), isHeader = true, align = "left", valign = "top"),
RichBlockTableCell(text = RichTextPlain("H2"), isHeader = true, align = "center", valign = "top")
),
listOf(
RichBlockTableCell(text = RichTextPlain("a"), align = "left", valign = "top"),
RichBlockTableCell(text = RichTextPlain("b"), align = "center", valign = "top")
)
)
)
assertEquals("| H1 | H2 |\n| :--- | :--: |\n| a | b |", block.markdown)
assertEquals(
"<table><tr><th align=\"left\" valign=\"top\">H1</th><th align=\"center\" valign=\"top\">H2</th></tr>" +
"<tr><td align=\"left\" valign=\"top\">a</td><td align=\"center\" valign=\"top\">b</td></tr></table>",
block.html
)
}
@Test
fun listOfBlocksJoinsBlocks() {
val blocks = listOf(RichBlockParagraph(RichTextPlain("a")), RichBlockDivider())
assertEquals("a\n\n---", blocks.toRichMarkdown())
assertEquals("<p>a</p>\n<hr/>", blocks.toRichHtml())
}
@Test
fun richTextInfoDelegatesToBlocks() {
val info = RichTextInfo(listOf(RichBlockParagraph(RichTextPlain("p")), RichBlockDivider()))
assertEquals("p\n\n---", info.markdown)
assertEquals("<p>p</p>\n<hr/>", info.html)
}
}

View File

@@ -0,0 +1,77 @@
package dev.inmo.tgbotapi.types.rich
import kotlin.test.Test
import kotlin.test.assertEquals
class RichTextDslTest {
@Test
fun buildsRichTextGroup() {
val richText = buildRichText {
plain("a ")
bold("b")
italic {
plain("c")
bold("d")
}
}
assertEquals(
RichTextGroup(
listOf(
RichTextPlain("a "),
RichTextBold(RichTextPlain("b")),
RichTextItalic(RichTextGroup(listOf(RichTextPlain("c"), RichTextBold(RichTextPlain("d")))))
)
),
richText
)
}
@Test
fun singlePartUnwraps() {
assertEquals(RichTextBold(RichTextPlain("x")), buildRichText { bold("x") })
}
@Test
fun rendersMarkdown() {
assertEquals("a **b**", buildRichText { plain("a "); bold("b") }.markdown)
}
@Test
fun buildsBlocks() {
val blocks = buildRichBlocks {
heading("Title", 1)
paragraph {
plain("Hello ")
bold("world")
}
divider()
list {
item("1", "first")
item("2", labelType = "1") { paragraph("second") }
}
blockQuotation {
paragraph("quoted")
}
}
assertEquals(5, blocks.size)
assertEquals(RichBlockSectionHeading(RichTextPlain("Title"), 1), blocks[0])
assertEquals(
RichBlockParagraph(RichTextGroup(listOf(RichTextPlain("Hello "), RichTextBold(RichTextPlain("world"))))),
blocks[1]
)
assertEquals(RichBlockDivider(), blocks[2])
val list = blocks[3] as RichBlockList
assertEquals(2, list.items.size)
assertEquals(RichBlockListItem("1", listOf(RichBlockParagraph(RichTextPlain("first")))), list.items[0])
assertEquals(RichBlockBlockQuotation(listOf(RichBlockParagraph(RichTextPlain("quoted")))), blocks[4])
}
@Test
fun buildsRichTextInfo() {
val info = buildRichTextInfo(isRtl = true) {
paragraph("p")
}
assertEquals(RichTextInfo(listOf(RichBlockParagraph(RichTextPlain("p"))), true), info)
assertEquals("p", info.markdown)
}
}

View File

@@ -0,0 +1,222 @@
package dev.inmo.tgbotapi.types.rich
import dev.inmo.tgbotapi.types.ChatId
import dev.inmo.tgbotapi.types.CustomEmojiId
import dev.inmo.tgbotapi.types.RawChatId
import dev.inmo.tgbotapi.types.TelegramDate
import dev.inmo.tgbotapi.types.chat.CommonUser
import kotlin.test.Test
import kotlin.test.assertEquals
class RichTextFormattingTest {
@Test
fun bold() {
val entity = RichTextBold(RichTextPlain("x"))
assertEquals("**x**", entity.markdown)
assertEquals("<b>x</b>", entity.html)
}
@Test
fun italic() {
val entity = RichTextItalic(RichTextPlain("x"))
assertEquals("*x*", entity.markdown)
assertEquals("<i>x</i>", entity.html)
}
@Test
fun underline() {
val entity = RichTextUnderline(RichTextPlain("x"))
assertEquals("<u>x</u>", entity.markdown)
assertEquals("<u>x</u>", entity.html)
}
@Test
fun strikethrough() {
val entity = RichTextStrikethrough(RichTextPlain("x"))
assertEquals("~~x~~", entity.markdown)
assertEquals("<s>x</s>", entity.html)
}
@Test
fun spoiler() {
val entity = RichTextSpoiler(RichTextPlain("x"))
assertEquals("||x||", entity.markdown)
assertEquals("<tg-spoiler>x</tg-spoiler>", entity.html)
}
@Test
fun subscript() {
val entity = RichTextSubscript(RichTextPlain("x"))
assertEquals("<sub>x</sub>", entity.markdown)
assertEquals("<sub>x</sub>", entity.html)
}
@Test
fun superscript() {
val entity = RichTextSuperscript(RichTextPlain("x"))
assertEquals("<sup>x</sup>", entity.markdown)
assertEquals("<sup>x</sup>", entity.html)
}
@Test
fun marked() {
val entity = RichTextMarked(RichTextPlain("x"))
assertEquals("==x==", entity.markdown)
assertEquals("<mark>x</mark>", entity.html)
}
@Test
fun code() {
val entity = RichTextCode(RichTextPlain("x"))
assertEquals("`x`", entity.markdown)
assertEquals("<code>x</code>", entity.html)
}
@Test
fun dateTime() {
val entity = RichTextDateTime(RichTextPlain("now"), TelegramDate(1647531900L), "wDT")
assertEquals("![now](tg://time?unix=1647531900&format=wDT)", entity.markdown)
assertEquals("<tg-time unix=\"1647531900\" format=\"wDT\">now</tg-time>", entity.html)
}
@Test
fun textMention() {
val entity = RichTextTextMention(RichTextPlain("John"), CommonUser(ChatId(RawChatId(12345L)), "John"))
assertEquals("[John](tg://user?id=12345)", entity.markdown)
assertEquals("<a href=\"tg://user?id=12345\">John</a>", entity.html)
}
@Test
fun customEmoji() {
val entity = RichTextCustomEmoji(CustomEmojiId("555"), "alt")
assertEquals("![alt](tg://emoji?id=555)", entity.markdown)
assertEquals("<tg-emoji emoji-id=\"555\">alt</tg-emoji>", entity.html)
}
@Test
fun mathematicalExpression() {
val entity = RichTextMathematicalExpression("x^2")
assertEquals("\$x^2\$", entity.markdown)
assertEquals("<tg-math>x^2</tg-math>", entity.html)
}
@Test
fun url() {
val entity = RichTextUrl(RichTextPlain("link"), "https://t.me/")
assertEquals("[link](https://t.me/)", entity.markdown)
assertEquals("<a href=\"https://t.me/\">link</a>", entity.html)
}
@Test
fun emailAddress() {
val entity = RichTextEmailAddress(RichTextPlain("mail"), "a@b.com")
assertEquals("[mail](mailto:a@b.com)", entity.markdown)
assertEquals("<a href=\"mailto:a@b.com\">mail</a>", entity.html)
}
@Test
fun phoneNumber() {
val entity = RichTextPhoneNumber(RichTextPlain("call"), "+123")
assertEquals("[call](tel:+123)", entity.markdown)
assertEquals("<a href=\"tel:+123\">call</a>", entity.html)
}
@Test
fun bankCardNumber() {
val entity = RichTextBankCardNumber(RichTextPlain("4242 4242 4242 4242"), "4242424242424242")
assertEquals("4242 4242 4242 4242", entity.markdown)
assertEquals("4242 4242 4242 4242", entity.html)
}
@Test
fun mention() {
val entity = RichTextMention(RichTextPlain("@user"), "user")
assertEquals("@user", entity.markdown)
assertEquals("@user", entity.html)
}
@Test
fun hashtag() {
val entity = RichTextHashtag(RichTextPlain("#tag"), "tag")
assertEquals("\\#tag", entity.markdown)
assertEquals("#tag", entity.html)
}
@Test
fun cashtag() {
val entity = RichTextCashtag(RichTextPlain("\$USD"), "USD")
assertEquals("\\\$USD", entity.markdown)
assertEquals("\$USD", entity.html)
}
@Test
fun botCommand() {
val entity = RichTextBotCommand(RichTextPlain("/start"), "start")
assertEquals("/start", entity.markdown)
assertEquals("/start", entity.html)
}
@Test
fun anchor() {
val entity = RichTextAnchor("top")
assertEquals("<a name=\"top\"></a>", entity.markdown)
assertEquals("<a name=\"top\"></a>", entity.html)
}
@Test
fun anchorLink() {
val entity = RichTextAnchorLink(RichTextPlain("go"), "top")
assertEquals("[go](#top)", entity.markdown)
assertEquals("<a href=\"#top\">go</a>", entity.html)
}
@Test
fun reference() {
val entity = RichTextReference(RichTextPlain("ref"), "note1")
assertEquals("<tg-reference name=\"note1\">ref</tg-reference>", entity.markdown)
assertEquals("<tg-reference name=\"note1\">ref</tg-reference>", entity.html)
}
@Test
fun referenceLink() {
val entity = RichTextReferenceLink(RichTextPlain("see"), "note1")
assertEquals("[see](#note1)", entity.markdown)
assertEquals("<a href=\"#note1\">see</a>", entity.html)
}
@Test
fun nestedGroupRecursesIntoInnerEntities() {
val entity = RichTextBold(
RichTextGroup(
listOf(
RichTextPlain("a "),
RichTextItalic(RichTextPlain("b"))
)
)
)
assertEquals("**a *b***", entity.markdown)
assertEquals("<b>a <i>b</i></b>", entity.html)
}
@Test
fun plainMarkdownEscapesSpecialCharacters() {
assertEquals("a\\*b\\_c", RichTextPlain("a*b_c").markdown)
assertEquals("\\[x\\]", RichTextPlain("[x]").markdown)
}
@Test
fun plainHtmlEscapesAngleBrackets() {
assertEquals("a&amp;lt;b", RichTextPlain("a<b").html)
}
@Test
fun rawTextExtractsPlainText() {
assertEquals("x", RichTextBold(RichTextPlain("x")).rawText)
assertEquals("alt", RichTextCustomEmoji(CustomEmojiId("1"), "alt").rawText)
assertEquals("e", RichTextMathematicalExpression("e").rawText)
assertEquals(
"a b",
RichTextGroup(listOf(RichTextPlain("a "), RichTextBold(RichTextPlain("b")))).rawText
)
}
}

View File

@@ -1906,6 +1906,7 @@ public final class dev/inmo/tgbotapi/extensions/utils/ClassCastsNewKt {
public static final fun ifInputInvoiceMessageContent (Ldev/inmo/tgbotapi/abstracts/CommonSendInvoiceData;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifInputInvoiceMessageContent (Ldev/inmo/tgbotapi/types/InlineQueries/InputMessageContent/InputMessageContent;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifInputLocationMessageContent (Ldev/inmo/tgbotapi/types/InlineQueries/InputMessageContent/InputMessageContent;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifInputRichMessageContent (Ldev/inmo/tgbotapi/types/InlineQueries/InputMessageContent/InputMessageContent;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifInputTextMessageContent (Ldev/inmo/tgbotapi/types/InlineQueries/InputMessageContent/InputMessageContent;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifInputVenueMessageContent (Ldev/inmo/tgbotapi/types/InlineQueries/InputMessageContent/InputMessageContent;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifInternal (Ldev/inmo/tgbotapi/types/ReplyInfo;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
@@ -1918,6 +1919,7 @@ public final class dev/inmo/tgbotapi/extensions/utils/ClassCastsNewKt {
public static final fun ifLeftChatMember (Ldev/inmo/tgbotapi/abstracts/OptionallyWithUser;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifLeftChatMemberEvent (Ldev/inmo/tgbotapi/abstracts/OptionallyWithUser;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifLeftChatMemberEvent (Ldev/inmo/tgbotapi/types/message/ChatEvents/abstracts/ChatEvent;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifLink (Ldev/inmo/tgbotapi/types/media/BaseTelegramMediaFile;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifLiveLocation (Ldev/inmo/tgbotapi/types/location/Location;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifLiveLocationContent (Ldev/inmo/tgbotapi/types/message/content/ResendableContent;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifLivePhotoContent (Ldev/inmo/tgbotapi/types/message/content/ResendableContent;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
@@ -2081,6 +2083,57 @@ public final class dev/inmo/tgbotapi/extensions/utils/ClassCastsNewKt {
public static final fun ifRequestGuestMessage (Ldev/inmo/tgbotapi/types/message/abstracts/Message;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifRestrictedChatMember (Ldev/inmo/tgbotapi/abstracts/OptionallyWithUser;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifRestrictedMemberChatMember (Ldev/inmo/tgbotapi/abstracts/OptionallyWithUser;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifRichBlockAnchor (Ldev/inmo/tgbotapi/types/rich/RichBlock;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifRichBlockAnimation (Ldev/inmo/tgbotapi/types/rich/RichBlock;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifRichBlockAudio (Ldev/inmo/tgbotapi/types/rich/RichBlock;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifRichBlockBlockQuotation (Ldev/inmo/tgbotapi/types/rich/RichBlock;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifRichBlockCollage (Ldev/inmo/tgbotapi/types/rich/RichBlock;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifRichBlockDetails (Ldev/inmo/tgbotapi/types/rich/RichBlock;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifRichBlockDivider (Ldev/inmo/tgbotapi/types/rich/RichBlock;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifRichBlockFooter (Ldev/inmo/tgbotapi/types/rich/RichBlock;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifRichBlockList (Ldev/inmo/tgbotapi/types/rich/RichBlock;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifRichBlockMap (Ldev/inmo/tgbotapi/types/rich/RichBlock;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifRichBlockMathematicalExpression (Ldev/inmo/tgbotapi/types/rich/RichBlock;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifRichBlockMedia (Ldev/inmo/tgbotapi/types/rich/RichBlock;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifRichBlockParagraph (Ldev/inmo/tgbotapi/types/rich/RichBlock;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifRichBlockPhoto (Ldev/inmo/tgbotapi/types/rich/RichBlock;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifRichBlockPreformatted (Ldev/inmo/tgbotapi/types/rich/RichBlock;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifRichBlockPullQuotation (Ldev/inmo/tgbotapi/types/rich/RichBlock;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifRichBlockSectionHeading (Ldev/inmo/tgbotapi/types/rich/RichBlock;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifRichBlockSlideshow (Ldev/inmo/tgbotapi/types/rich/RichBlock;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifRichBlockTable (Ldev/inmo/tgbotapi/types/rich/RichBlock;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifRichBlockThinking (Ldev/inmo/tgbotapi/types/rich/RichBlock;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifRichBlockVideo (Ldev/inmo/tgbotapi/types/rich/RichBlock;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifRichBlockVoiceNote (Ldev/inmo/tgbotapi/types/rich/RichBlock;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifRichMessageContent (Ldev/inmo/tgbotapi/types/message/content/ResendableContent;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifRichTextAnchor (Ldev/inmo/tgbotapi/types/rich/RichText;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifRichTextAnchorLink (Ldev/inmo/tgbotapi/types/rich/RichText;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifRichTextBankCardNumber (Ldev/inmo/tgbotapi/types/rich/RichText;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifRichTextBold (Ldev/inmo/tgbotapi/types/rich/RichText;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifRichTextBotCommand (Ldev/inmo/tgbotapi/types/rich/RichText;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifRichTextCashtag (Ldev/inmo/tgbotapi/types/rich/RichText;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifRichTextCode (Ldev/inmo/tgbotapi/types/rich/RichText;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifRichTextCustomEmoji (Ldev/inmo/tgbotapi/types/rich/RichText;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifRichTextDateTime (Ldev/inmo/tgbotapi/types/rich/RichText;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifRichTextEmailAddress (Ldev/inmo/tgbotapi/types/rich/RichText;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifRichTextEntity (Ldev/inmo/tgbotapi/types/rich/RichText;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifRichTextGroup (Ldev/inmo/tgbotapi/types/rich/RichText;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifRichTextHashtag (Ldev/inmo/tgbotapi/types/rich/RichText;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifRichTextItalic (Ldev/inmo/tgbotapi/types/rich/RichText;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifRichTextMarked (Ldev/inmo/tgbotapi/types/rich/RichText;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifRichTextMathematicalExpression (Ldev/inmo/tgbotapi/types/rich/RichText;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifRichTextMention (Ldev/inmo/tgbotapi/types/rich/RichText;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifRichTextPhoneNumber (Ldev/inmo/tgbotapi/types/rich/RichText;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifRichTextPlain (Ldev/inmo/tgbotapi/types/rich/RichText;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifRichTextReference (Ldev/inmo/tgbotapi/types/rich/RichText;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifRichTextReferenceLink (Ldev/inmo/tgbotapi/types/rich/RichText;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifRichTextSpoiler (Ldev/inmo/tgbotapi/types/rich/RichText;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifRichTextStrikethrough (Ldev/inmo/tgbotapi/types/rich/RichText;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifRichTextSubscript (Ldev/inmo/tgbotapi/types/rich/RichText;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifRichTextSuperscript (Ldev/inmo/tgbotapi/types/rich/RichText;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifRichTextTextMention (Ldev/inmo/tgbotapi/types/rich/RichText;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifRichTextUnderline (Ldev/inmo/tgbotapi/types/rich/RichText;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifRichTextUrl (Ldev/inmo/tgbotapi/types/rich/RichText;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifSecondaryChatInviteLink (Ldev/inmo/tgbotapi/abstracts/OptionallyWithUser;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifSecureValueIdentity (Ldev/inmo/tgbotapi/types/passport/decrypted/abstracts/SecureValue;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifSecureValueWithData (Ldev/inmo/tgbotapi/types/passport/decrypted/abstracts/SecureValue;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
@@ -2142,6 +2195,7 @@ public final class dev/inmo/tgbotapi/extensions/utils/ClassCastsNewKt {
public static final fun ifTelegramMediaDocument (Ldev/inmo/tgbotapi/types/media/InputPollMedia;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifTelegramMediaDocument (Ldev/inmo/tgbotapi/types/media/TelegramMedia;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifTelegramMediaFile (Ldev/inmo/tgbotapi/types/media/BaseTelegramMediaFile;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifTelegramMediaLink (Ldev/inmo/tgbotapi/types/media/InputPollOptionMedia;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifTelegramMediaLivePhoto (Ldev/inmo/tgbotapi/types/media/InputPollMedia;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifTelegramMediaLivePhoto (Ldev/inmo/tgbotapi/types/media/InputPollOptionMedia;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun ifTelegramMediaLivePhoto (Ldev/inmo/tgbotapi/types/media/TelegramMedia;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
@@ -2340,6 +2394,8 @@ public final class dev/inmo/tgbotapi/extensions/utils/ClassCastsNewKt {
public static final fun inputInvoiceMessageContentOrThrow (Ldev/inmo/tgbotapi/types/InlineQueries/InputMessageContent/InputMessageContent;)Ldev/inmo/tgbotapi/types/InlineQueries/InputMessageContent/InputInvoiceMessageContent;
public static final fun inputLocationMessageContentOrNull (Ldev/inmo/tgbotapi/types/InlineQueries/InputMessageContent/InputMessageContent;)Ldev/inmo/tgbotapi/types/InlineQueries/InputMessageContent/InputLocationMessageContent;
public static final fun inputLocationMessageContentOrThrow (Ldev/inmo/tgbotapi/types/InlineQueries/InputMessageContent/InputMessageContent;)Ldev/inmo/tgbotapi/types/InlineQueries/InputMessageContent/InputLocationMessageContent;
public static final fun inputRichMessageContentOrNull (Ldev/inmo/tgbotapi/types/InlineQueries/InputMessageContent/InputMessageContent;)Ldev/inmo/tgbotapi/types/InlineQueries/InputMessageContent/InputRichMessageContent;
public static final fun inputRichMessageContentOrThrow (Ldev/inmo/tgbotapi/types/InlineQueries/InputMessageContent/InputMessageContent;)Ldev/inmo/tgbotapi/types/InlineQueries/InputMessageContent/InputRichMessageContent;
public static final fun inputTextMessageContentOrNull (Ldev/inmo/tgbotapi/types/InlineQueries/InputMessageContent/InputMessageContent;)Ldev/inmo/tgbotapi/types/InlineQueries/InputMessageContent/InputTextMessageContent;
public static final fun inputTextMessageContentOrThrow (Ldev/inmo/tgbotapi/types/InlineQueries/InputMessageContent/InputMessageContent;)Ldev/inmo/tgbotapi/types/InlineQueries/InputMessageContent/InputTextMessageContent;
public static final fun inputVenueMessageContentOrNull (Ldev/inmo/tgbotapi/types/InlineQueries/InputMessageContent/InputMessageContent;)Ldev/inmo/tgbotapi/types/InlineQueries/InputMessageContent/InputVenueMessageContent;
@@ -2364,6 +2420,8 @@ public final class dev/inmo/tgbotapi/extensions/utils/ClassCastsNewKt {
public static final fun leftChatMemberEventOrThrow (Ldev/inmo/tgbotapi/types/message/ChatEvents/abstracts/ChatEvent;)Ldev/inmo/tgbotapi/types/message/ChatEvents/LeftChatMemberEvent;
public static final fun leftChatMemberOrNull (Ldev/inmo/tgbotapi/abstracts/OptionallyWithUser;)Ldev/inmo/tgbotapi/types/chat/member/LeftChatMember;
public static final fun leftChatMemberOrThrow (Ldev/inmo/tgbotapi/abstracts/OptionallyWithUser;)Ldev/inmo/tgbotapi/types/chat/member/LeftChatMember;
public static final fun linkOrNull (Ldev/inmo/tgbotapi/types/media/BaseTelegramMediaFile;)Ldev/inmo/tgbotapi/types/Link;
public static final fun linkOrThrow (Ldev/inmo/tgbotapi/types/media/BaseTelegramMediaFile;)Ldev/inmo/tgbotapi/types/Link;
public static final fun liveLocationContentOrNull (Ldev/inmo/tgbotapi/types/message/content/ResendableContent;)Ldev/inmo/tgbotapi/types/message/content/LiveLocationContent;
public static final fun liveLocationContentOrThrow (Ldev/inmo/tgbotapi/types/message/content/ResendableContent;)Ldev/inmo/tgbotapi/types/message/content/LiveLocationContent;
public static final fun liveLocationOrNull (Ldev/inmo/tgbotapi/types/location/Location;)Ldev/inmo/tgbotapi/types/location/LiveLocation;
@@ -2690,6 +2748,108 @@ public final class dev/inmo/tgbotapi/extensions/utils/ClassCastsNewKt {
public static final fun restrictedChatMemberOrThrow (Ldev/inmo/tgbotapi/abstracts/OptionallyWithUser;)Ldev/inmo/tgbotapi/types/chat/member/RestrictedChatMember;
public static final fun restrictedMemberChatMemberOrNull (Ldev/inmo/tgbotapi/abstracts/OptionallyWithUser;)Ldev/inmo/tgbotapi/types/chat/member/RestrictedMemberChatMember;
public static final fun restrictedMemberChatMemberOrThrow (Ldev/inmo/tgbotapi/abstracts/OptionallyWithUser;)Ldev/inmo/tgbotapi/types/chat/member/RestrictedMemberChatMember;
public static final fun richBlockAnchorOrNull (Ldev/inmo/tgbotapi/types/rich/RichBlock;)Ldev/inmo/tgbotapi/types/rich/RichBlockAnchor;
public static final fun richBlockAnchorOrThrow (Ldev/inmo/tgbotapi/types/rich/RichBlock;)Ldev/inmo/tgbotapi/types/rich/RichBlockAnchor;
public static final fun richBlockAnimationOrNull (Ldev/inmo/tgbotapi/types/rich/RichBlock;)Ldev/inmo/tgbotapi/types/rich/RichBlockAnimation;
public static final fun richBlockAnimationOrThrow (Ldev/inmo/tgbotapi/types/rich/RichBlock;)Ldev/inmo/tgbotapi/types/rich/RichBlockAnimation;
public static final fun richBlockAudioOrNull (Ldev/inmo/tgbotapi/types/rich/RichBlock;)Ldev/inmo/tgbotapi/types/rich/RichBlockAudio;
public static final fun richBlockAudioOrThrow (Ldev/inmo/tgbotapi/types/rich/RichBlock;)Ldev/inmo/tgbotapi/types/rich/RichBlockAudio;
public static final fun richBlockBlockQuotationOrNull (Ldev/inmo/tgbotapi/types/rich/RichBlock;)Ldev/inmo/tgbotapi/types/rich/RichBlockBlockQuotation;
public static final fun richBlockBlockQuotationOrThrow (Ldev/inmo/tgbotapi/types/rich/RichBlock;)Ldev/inmo/tgbotapi/types/rich/RichBlockBlockQuotation;
public static final fun richBlockCollageOrNull (Ldev/inmo/tgbotapi/types/rich/RichBlock;)Ldev/inmo/tgbotapi/types/rich/RichBlockCollage;
public static final fun richBlockCollageOrThrow (Ldev/inmo/tgbotapi/types/rich/RichBlock;)Ldev/inmo/tgbotapi/types/rich/RichBlockCollage;
public static final fun richBlockDetailsOrNull (Ldev/inmo/tgbotapi/types/rich/RichBlock;)Ldev/inmo/tgbotapi/types/rich/RichBlockDetails;
public static final fun richBlockDetailsOrThrow (Ldev/inmo/tgbotapi/types/rich/RichBlock;)Ldev/inmo/tgbotapi/types/rich/RichBlockDetails;
public static final fun richBlockDividerOrNull (Ldev/inmo/tgbotapi/types/rich/RichBlock;)Ldev/inmo/tgbotapi/types/rich/RichBlockDivider;
public static final fun richBlockDividerOrThrow (Ldev/inmo/tgbotapi/types/rich/RichBlock;)Ldev/inmo/tgbotapi/types/rich/RichBlockDivider;
public static final fun richBlockFooterOrNull (Ldev/inmo/tgbotapi/types/rich/RichBlock;)Ldev/inmo/tgbotapi/types/rich/RichBlockFooter;
public static final fun richBlockFooterOrThrow (Ldev/inmo/tgbotapi/types/rich/RichBlock;)Ldev/inmo/tgbotapi/types/rich/RichBlockFooter;
public static final fun richBlockListOrNull (Ldev/inmo/tgbotapi/types/rich/RichBlock;)Ldev/inmo/tgbotapi/types/rich/RichBlockList;
public static final fun richBlockListOrThrow (Ldev/inmo/tgbotapi/types/rich/RichBlock;)Ldev/inmo/tgbotapi/types/rich/RichBlockList;
public static final fun richBlockMapOrNull (Ldev/inmo/tgbotapi/types/rich/RichBlock;)Ldev/inmo/tgbotapi/types/rich/RichBlockMap;
public static final fun richBlockMapOrThrow (Ldev/inmo/tgbotapi/types/rich/RichBlock;)Ldev/inmo/tgbotapi/types/rich/RichBlockMap;
public static final fun richBlockMathematicalExpressionOrNull (Ldev/inmo/tgbotapi/types/rich/RichBlock;)Ldev/inmo/tgbotapi/types/rich/RichBlockMathematicalExpression;
public static final fun richBlockMathematicalExpressionOrThrow (Ldev/inmo/tgbotapi/types/rich/RichBlock;)Ldev/inmo/tgbotapi/types/rich/RichBlockMathematicalExpression;
public static final fun richBlockMediaOrNull (Ldev/inmo/tgbotapi/types/rich/RichBlock;)Ldev/inmo/tgbotapi/types/rich/RichBlockMedia;
public static final fun richBlockMediaOrThrow (Ldev/inmo/tgbotapi/types/rich/RichBlock;)Ldev/inmo/tgbotapi/types/rich/RichBlockMedia;
public static final fun richBlockParagraphOrNull (Ldev/inmo/tgbotapi/types/rich/RichBlock;)Ldev/inmo/tgbotapi/types/rich/RichBlockParagraph;
public static final fun richBlockParagraphOrThrow (Ldev/inmo/tgbotapi/types/rich/RichBlock;)Ldev/inmo/tgbotapi/types/rich/RichBlockParagraph;
public static final fun richBlockPhotoOrNull (Ldev/inmo/tgbotapi/types/rich/RichBlock;)Ldev/inmo/tgbotapi/types/rich/RichBlockPhoto;
public static final fun richBlockPhotoOrThrow (Ldev/inmo/tgbotapi/types/rich/RichBlock;)Ldev/inmo/tgbotapi/types/rich/RichBlockPhoto;
public static final fun richBlockPreformattedOrNull (Ldev/inmo/tgbotapi/types/rich/RichBlock;)Ldev/inmo/tgbotapi/types/rich/RichBlockPreformatted;
public static final fun richBlockPreformattedOrThrow (Ldev/inmo/tgbotapi/types/rich/RichBlock;)Ldev/inmo/tgbotapi/types/rich/RichBlockPreformatted;
public static final fun richBlockPullQuotationOrNull (Ldev/inmo/tgbotapi/types/rich/RichBlock;)Ldev/inmo/tgbotapi/types/rich/RichBlockPullQuotation;
public static final fun richBlockPullQuotationOrThrow (Ldev/inmo/tgbotapi/types/rich/RichBlock;)Ldev/inmo/tgbotapi/types/rich/RichBlockPullQuotation;
public static final fun richBlockSectionHeadingOrNull (Ldev/inmo/tgbotapi/types/rich/RichBlock;)Ldev/inmo/tgbotapi/types/rich/RichBlockSectionHeading;
public static final fun richBlockSectionHeadingOrThrow (Ldev/inmo/tgbotapi/types/rich/RichBlock;)Ldev/inmo/tgbotapi/types/rich/RichBlockSectionHeading;
public static final fun richBlockSlideshowOrNull (Ldev/inmo/tgbotapi/types/rich/RichBlock;)Ldev/inmo/tgbotapi/types/rich/RichBlockSlideshow;
public static final fun richBlockSlideshowOrThrow (Ldev/inmo/tgbotapi/types/rich/RichBlock;)Ldev/inmo/tgbotapi/types/rich/RichBlockSlideshow;
public static final fun richBlockTableOrNull (Ldev/inmo/tgbotapi/types/rich/RichBlock;)Ldev/inmo/tgbotapi/types/rich/RichBlockTable;
public static final fun richBlockTableOrThrow (Ldev/inmo/tgbotapi/types/rich/RichBlock;)Ldev/inmo/tgbotapi/types/rich/RichBlockTable;
public static final fun richBlockThinkingOrNull (Ldev/inmo/tgbotapi/types/rich/RichBlock;)Ldev/inmo/tgbotapi/types/rich/RichBlockThinking;
public static final fun richBlockThinkingOrThrow (Ldev/inmo/tgbotapi/types/rich/RichBlock;)Ldev/inmo/tgbotapi/types/rich/RichBlockThinking;
public static final fun richBlockVideoOrNull (Ldev/inmo/tgbotapi/types/rich/RichBlock;)Ldev/inmo/tgbotapi/types/rich/RichBlockVideo;
public static final fun richBlockVideoOrThrow (Ldev/inmo/tgbotapi/types/rich/RichBlock;)Ldev/inmo/tgbotapi/types/rich/RichBlockVideo;
public static final fun richBlockVoiceNoteOrNull (Ldev/inmo/tgbotapi/types/rich/RichBlock;)Ldev/inmo/tgbotapi/types/rich/RichBlockVoiceNote;
public static final fun richBlockVoiceNoteOrThrow (Ldev/inmo/tgbotapi/types/rich/RichBlock;)Ldev/inmo/tgbotapi/types/rich/RichBlockVoiceNote;
public static final fun richMessageContentOrNull (Ldev/inmo/tgbotapi/types/message/content/ResendableContent;)Ldev/inmo/tgbotapi/types/message/content/RichMessageContent;
public static final fun richMessageContentOrThrow (Ldev/inmo/tgbotapi/types/message/content/ResendableContent;)Ldev/inmo/tgbotapi/types/message/content/RichMessageContent;
public static final fun richTextAnchorLinkOrNull (Ldev/inmo/tgbotapi/types/rich/RichText;)Ldev/inmo/tgbotapi/types/rich/RichTextAnchorLink;
public static final fun richTextAnchorLinkOrThrow (Ldev/inmo/tgbotapi/types/rich/RichText;)Ldev/inmo/tgbotapi/types/rich/RichTextAnchorLink;
public static final fun richTextAnchorOrNull (Ldev/inmo/tgbotapi/types/rich/RichText;)Ldev/inmo/tgbotapi/types/rich/RichTextAnchor;
public static final fun richTextAnchorOrThrow (Ldev/inmo/tgbotapi/types/rich/RichText;)Ldev/inmo/tgbotapi/types/rich/RichTextAnchor;
public static final fun richTextBankCardNumberOrNull (Ldev/inmo/tgbotapi/types/rich/RichText;)Ldev/inmo/tgbotapi/types/rich/RichTextBankCardNumber;
public static final fun richTextBankCardNumberOrThrow (Ldev/inmo/tgbotapi/types/rich/RichText;)Ldev/inmo/tgbotapi/types/rich/RichTextBankCardNumber;
public static final fun richTextBoldOrNull (Ldev/inmo/tgbotapi/types/rich/RichText;)Ldev/inmo/tgbotapi/types/rich/RichTextBold;
public static final fun richTextBoldOrThrow (Ldev/inmo/tgbotapi/types/rich/RichText;)Ldev/inmo/tgbotapi/types/rich/RichTextBold;
public static final fun richTextBotCommandOrNull (Ldev/inmo/tgbotapi/types/rich/RichText;)Ldev/inmo/tgbotapi/types/rich/RichTextBotCommand;
public static final fun richTextBotCommandOrThrow (Ldev/inmo/tgbotapi/types/rich/RichText;)Ldev/inmo/tgbotapi/types/rich/RichTextBotCommand;
public static final fun richTextCashtagOrNull (Ldev/inmo/tgbotapi/types/rich/RichText;)Ldev/inmo/tgbotapi/types/rich/RichTextCashtag;
public static final fun richTextCashtagOrThrow (Ldev/inmo/tgbotapi/types/rich/RichText;)Ldev/inmo/tgbotapi/types/rich/RichTextCashtag;
public static final fun richTextCodeOrNull (Ldev/inmo/tgbotapi/types/rich/RichText;)Ldev/inmo/tgbotapi/types/rich/RichTextCode;
public static final fun richTextCodeOrThrow (Ldev/inmo/tgbotapi/types/rich/RichText;)Ldev/inmo/tgbotapi/types/rich/RichTextCode;
public static final fun richTextCustomEmojiOrNull (Ldev/inmo/tgbotapi/types/rich/RichText;)Ldev/inmo/tgbotapi/types/rich/RichTextCustomEmoji;
public static final fun richTextCustomEmojiOrThrow (Ldev/inmo/tgbotapi/types/rich/RichText;)Ldev/inmo/tgbotapi/types/rich/RichTextCustomEmoji;
public static final fun richTextDateTimeOrNull (Ldev/inmo/tgbotapi/types/rich/RichText;)Ldev/inmo/tgbotapi/types/rich/RichTextDateTime;
public static final fun richTextDateTimeOrThrow (Ldev/inmo/tgbotapi/types/rich/RichText;)Ldev/inmo/tgbotapi/types/rich/RichTextDateTime;
public static final fun richTextEmailAddressOrNull (Ldev/inmo/tgbotapi/types/rich/RichText;)Ldev/inmo/tgbotapi/types/rich/RichTextEmailAddress;
public static final fun richTextEmailAddressOrThrow (Ldev/inmo/tgbotapi/types/rich/RichText;)Ldev/inmo/tgbotapi/types/rich/RichTextEmailAddress;
public static final fun richTextEntityOrNull (Ldev/inmo/tgbotapi/types/rich/RichText;)Ldev/inmo/tgbotapi/types/rich/RichTextEntity;
public static final fun richTextEntityOrThrow (Ldev/inmo/tgbotapi/types/rich/RichText;)Ldev/inmo/tgbotapi/types/rich/RichTextEntity;
public static final fun richTextGroupOrNull (Ldev/inmo/tgbotapi/types/rich/RichText;)Ldev/inmo/tgbotapi/types/rich/RichTextGroup;
public static final fun richTextGroupOrThrow (Ldev/inmo/tgbotapi/types/rich/RichText;)Ldev/inmo/tgbotapi/types/rich/RichTextGroup;
public static final fun richTextHashtagOrNull (Ldev/inmo/tgbotapi/types/rich/RichText;)Ldev/inmo/tgbotapi/types/rich/RichTextHashtag;
public static final fun richTextHashtagOrThrow (Ldev/inmo/tgbotapi/types/rich/RichText;)Ldev/inmo/tgbotapi/types/rich/RichTextHashtag;
public static final fun richTextItalicOrNull (Ldev/inmo/tgbotapi/types/rich/RichText;)Ldev/inmo/tgbotapi/types/rich/RichTextItalic;
public static final fun richTextItalicOrThrow (Ldev/inmo/tgbotapi/types/rich/RichText;)Ldev/inmo/tgbotapi/types/rich/RichTextItalic;
public static final fun richTextMarkedOrNull (Ldev/inmo/tgbotapi/types/rich/RichText;)Ldev/inmo/tgbotapi/types/rich/RichTextMarked;
public static final fun richTextMarkedOrThrow (Ldev/inmo/tgbotapi/types/rich/RichText;)Ldev/inmo/tgbotapi/types/rich/RichTextMarked;
public static final fun richTextMathematicalExpressionOrNull (Ldev/inmo/tgbotapi/types/rich/RichText;)Ldev/inmo/tgbotapi/types/rich/RichTextMathematicalExpression;
public static final fun richTextMathematicalExpressionOrThrow (Ldev/inmo/tgbotapi/types/rich/RichText;)Ldev/inmo/tgbotapi/types/rich/RichTextMathematicalExpression;
public static final fun richTextMentionOrNull (Ldev/inmo/tgbotapi/types/rich/RichText;)Ldev/inmo/tgbotapi/types/rich/RichTextMention;
public static final fun richTextMentionOrThrow (Ldev/inmo/tgbotapi/types/rich/RichText;)Ldev/inmo/tgbotapi/types/rich/RichTextMention;
public static final fun richTextPhoneNumberOrNull (Ldev/inmo/tgbotapi/types/rich/RichText;)Ldev/inmo/tgbotapi/types/rich/RichTextPhoneNumber;
public static final fun richTextPhoneNumberOrThrow (Ldev/inmo/tgbotapi/types/rich/RichText;)Ldev/inmo/tgbotapi/types/rich/RichTextPhoneNumber;
public static final fun richTextPlainOrNull (Ldev/inmo/tgbotapi/types/rich/RichText;)Ldev/inmo/tgbotapi/types/rich/RichTextPlain;
public static final fun richTextPlainOrThrow (Ldev/inmo/tgbotapi/types/rich/RichText;)Ldev/inmo/tgbotapi/types/rich/RichTextPlain;
public static final fun richTextReferenceLinkOrNull (Ldev/inmo/tgbotapi/types/rich/RichText;)Ldev/inmo/tgbotapi/types/rich/RichTextReferenceLink;
public static final fun richTextReferenceLinkOrThrow (Ldev/inmo/tgbotapi/types/rich/RichText;)Ldev/inmo/tgbotapi/types/rich/RichTextReferenceLink;
public static final fun richTextReferenceOrNull (Ldev/inmo/tgbotapi/types/rich/RichText;)Ldev/inmo/tgbotapi/types/rich/RichTextReference;
public static final fun richTextReferenceOrThrow (Ldev/inmo/tgbotapi/types/rich/RichText;)Ldev/inmo/tgbotapi/types/rich/RichTextReference;
public static final fun richTextSpoilerOrNull (Ldev/inmo/tgbotapi/types/rich/RichText;)Ldev/inmo/tgbotapi/types/rich/RichTextSpoiler;
public static final fun richTextSpoilerOrThrow (Ldev/inmo/tgbotapi/types/rich/RichText;)Ldev/inmo/tgbotapi/types/rich/RichTextSpoiler;
public static final fun richTextStrikethroughOrNull (Ldev/inmo/tgbotapi/types/rich/RichText;)Ldev/inmo/tgbotapi/types/rich/RichTextStrikethrough;
public static final fun richTextStrikethroughOrThrow (Ldev/inmo/tgbotapi/types/rich/RichText;)Ldev/inmo/tgbotapi/types/rich/RichTextStrikethrough;
public static final fun richTextSubscriptOrNull (Ldev/inmo/tgbotapi/types/rich/RichText;)Ldev/inmo/tgbotapi/types/rich/RichTextSubscript;
public static final fun richTextSubscriptOrThrow (Ldev/inmo/tgbotapi/types/rich/RichText;)Ldev/inmo/tgbotapi/types/rich/RichTextSubscript;
public static final fun richTextSuperscriptOrNull (Ldev/inmo/tgbotapi/types/rich/RichText;)Ldev/inmo/tgbotapi/types/rich/RichTextSuperscript;
public static final fun richTextSuperscriptOrThrow (Ldev/inmo/tgbotapi/types/rich/RichText;)Ldev/inmo/tgbotapi/types/rich/RichTextSuperscript;
public static final fun richTextTextMentionOrNull (Ldev/inmo/tgbotapi/types/rich/RichText;)Ldev/inmo/tgbotapi/types/rich/RichTextTextMention;
public static final fun richTextTextMentionOrThrow (Ldev/inmo/tgbotapi/types/rich/RichText;)Ldev/inmo/tgbotapi/types/rich/RichTextTextMention;
public static final fun richTextUnderlineOrNull (Ldev/inmo/tgbotapi/types/rich/RichText;)Ldev/inmo/tgbotapi/types/rich/RichTextUnderline;
public static final fun richTextUnderlineOrThrow (Ldev/inmo/tgbotapi/types/rich/RichText;)Ldev/inmo/tgbotapi/types/rich/RichTextUnderline;
public static final fun richTextUrlOrNull (Ldev/inmo/tgbotapi/types/rich/RichText;)Ldev/inmo/tgbotapi/types/rich/RichTextUrl;
public static final fun richTextUrlOrThrow (Ldev/inmo/tgbotapi/types/rich/RichText;)Ldev/inmo/tgbotapi/types/rich/RichTextUrl;
public static final fun secondaryChatInviteLinkOrNull (Ldev/inmo/tgbotapi/abstracts/OptionallyWithUser;)Ldev/inmo/tgbotapi/types/SecondaryChatInviteLink;
public static final fun secondaryChatInviteLinkOrThrow (Ldev/inmo/tgbotapi/abstracts/OptionallyWithUser;)Ldev/inmo/tgbotapi/types/SecondaryChatInviteLink;
public static final fun secureValueIdentityOrNull (Ldev/inmo/tgbotapi/types/passport/decrypted/abstracts/SecureValue;)Ldev/inmo/tgbotapi/types/passport/decrypted/abstracts/SecureValueIdentity;
@@ -2812,6 +2972,8 @@ public final class dev/inmo/tgbotapi/extensions/utils/ClassCastsNewKt {
public static final fun telegramMediaDocumentOrThrow (Ldev/inmo/tgbotapi/types/media/TelegramMedia;)Ldev/inmo/tgbotapi/types/media/TelegramMediaDocument;
public static final fun telegramMediaFileOrNull (Ldev/inmo/tgbotapi/types/media/BaseTelegramMediaFile;)Ldev/inmo/tgbotapi/types/files/TelegramMediaFile;
public static final fun telegramMediaFileOrThrow (Ldev/inmo/tgbotapi/types/media/BaseTelegramMediaFile;)Ldev/inmo/tgbotapi/types/files/TelegramMediaFile;
public static final fun telegramMediaLinkOrNull (Ldev/inmo/tgbotapi/types/media/InputPollOptionMedia;)Ldev/inmo/tgbotapi/types/media/TelegramMediaLink;
public static final fun telegramMediaLinkOrThrow (Ldev/inmo/tgbotapi/types/media/InputPollOptionMedia;)Ldev/inmo/tgbotapi/types/media/TelegramMediaLink;
public static final fun telegramMediaLivePhotoOrNull (Ldev/inmo/tgbotapi/types/media/InputPollMedia;)Ldev/inmo/tgbotapi/types/media/TelegramMediaLivePhoto;
public static final fun telegramMediaLivePhotoOrNull (Ldev/inmo/tgbotapi/types/media/InputPollOptionMedia;)Ldev/inmo/tgbotapi/types/media/TelegramMediaLivePhoto;
public static final fun telegramMediaLivePhotoOrNull (Ldev/inmo/tgbotapi/types/media/TelegramMedia;)Ldev/inmo/tgbotapi/types/media/TelegramMediaLivePhoto;
@@ -3062,6 +3224,7 @@ public final class dev/inmo/tgbotapi/extensions/utils/ContentMessageConversation
public static final fun onlyLocationContentMessages (Lkotlinx/coroutines/flow/Flow;)Lkotlinx/coroutines/flow/Flow;
public static final fun onlyPhotoContentMessages (Lkotlinx/coroutines/flow/Flow;)Lkotlinx/coroutines/flow/Flow;
public static final fun onlyPollContentMessages (Lkotlinx/coroutines/flow/Flow;)Lkotlinx/coroutines/flow/Flow;
public static final fun onlyRichMessageContentMessages (Lkotlinx/coroutines/flow/Flow;)Lkotlinx/coroutines/flow/Flow;
public static final fun onlyStickerContentMessages (Lkotlinx/coroutines/flow/Flow;)Lkotlinx/coroutines/flow/Flow;
public static final fun onlyStoryContentMessages (Lkotlinx/coroutines/flow/Flow;)Lkotlinx/coroutines/flow/Flow;
public static final fun onlyTextContentMessages (Lkotlinx/coroutines/flow/Flow;)Lkotlinx/coroutines/flow/Flow;
@@ -3255,6 +3418,7 @@ public final class dev/inmo/tgbotapi/extensions/utils/extensions/raw/CallbackQue
public final class dev/inmo/tgbotapi/extensions/utils/extensions/raw/ChatJoinRequestKt {
public static final fun getInvite_link (Ldev/inmo/tgbotapi/types/chat/ChatJoinRequest;)Ldev/inmo/tgbotapi/types/ChatInviteLink;
public static final fun getQuery_id (Ldev/inmo/tgbotapi/types/chat/ChatJoinRequest;)Ljava/lang/String;
}
public final class dev/inmo/tgbotapi/extensions/utils/extensions/raw/ChatMemberUpdatedKt {

View File

@@ -22,6 +22,7 @@ fun Flow<ContentMessage<*>>.onlyPollContentMessages() = withContentType<PollCont
fun Flow<ContentMessage<*>>.onlyStickerContentMessages() = withContentType<StickerContent>()
fun Flow<ContentMessage<*>>.onlyTextContentMessages() = withContentType<TextContent>()
fun Flow<ContentMessage<*>>.onlyStoryContentMessages() = withContentType<StoryContent>()
fun Flow<ContentMessage<*>>.onlyRichMessageContentMessages() = withContentType<RichMessageContent>()
fun Flow<ContentMessage<*>>.onlyVenueContentMessages() = withContentType<VenueContent>()
fun Flow<ContentMessage<*>>.onlyVideoContentMessages() = withContentType<VideoContent>()
fun Flow<ContentMessage<*>>.onlyLivePhotoContentMessages() = withContentType<LivePhotoContent>()

View File

@@ -1,9 +1,14 @@
package dev.inmo.tgbotapi.extensions.utils.extensions.raw
import dev.inmo.tgbotapi.types.ChatInviteLink
import dev.inmo.tgbotapi.types.ChatJoinRequestQueryId
import dev.inmo.tgbotapi.types.chat.ChatJoinRequest
import dev.inmo.tgbotapi.utils.RiskFeature
@RiskFeature(RawFieldsUsageWarning)
val ChatJoinRequest.invite_link: ChatInviteLink?
get() = inviteLink
@RiskFeature(RawFieldsUsageWarning)
val ChatJoinRequest.query_id: ChatJoinRequestQueryId?
get() = queryId