diff --git a/CHANGELOG.md b/CHANGELOG.md index eac13715f2..3d200f17b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ * `Core`: * (`Rich Messages`) Added `h1` through `h6` shortcuts for plain and rich-text headings in `InputRichBlocksBuilder` + * (`Rich Messages`) Reworked the input table DSL to build cells through nested `table { row { cell(...) { } } }` builders * (`Rich Messages`) Replaced the flat `InputRichBlockListItem` data class with ordered/unordered variants, added the string-serialized `LabelType` hierarchy (`A`, `a`, `I`, `i`, `1`), and split the list DSL into `InputRichBlockOrderedListBuilder`/`InputRichBlockUnorderedListBuilder` * (`Rich Messages`) Added `InputRichBlock` hierarchy with all 21 `InputRichBlock*` types (mirroring the received `RichBlock*` hierarchy and reusing `RichText`/`RichBlockCaption`/`RichBlockTableCell`), the label-less `InputRichBlockListItem` and the `InputRichBlockSerializer`; every `InputRichBlock` exposes `subBlocks` navigation * (`Rich Messages`) Added `TelegramMediaVoiceNote` (`InputMediaVoiceNote`) and the `RichMessageMemberTelegramMedia` marker interface implemented by it, `TelegramMediaAnimation`, `TelegramMediaAudio`, `TelegramMediaPhoto` and `TelegramMediaVideo`; added `VoiceFile.toTelegramMediaVoiceNote` converters diff --git a/tgbotapi.core/api/tgbotapi.core.api b/tgbotapi.core/api/tgbotapi.core.api index 15485f1029..126ac39336 100644 --- a/tgbotapi.core/api/tgbotapi.core.api +++ b/tgbotapi.core/api/tgbotapi.core.api @@ -35854,6 +35854,19 @@ public final class dev/inmo/tgbotapi/types/rich/InputRichBlockTable$Companion { public final fun serializer ()Lkotlinx/serialization/KSerializer; } +public final class dev/inmo/tgbotapi/types/rich/InputRichBlockTableBuilder { + public fun ()V + public final fun build ()Ljava/util/List; + public final fun row (Lkotlin/jvm/functions/Function1;)V +} + +public final class dev/inmo/tgbotapi/types/rich/InputRichBlockTableRowBuilder { + public fun ()V + public final fun build ()Ljava/util/List; + public final fun cell (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/Integer;Ljava/lang/Integer;Lkotlin/jvm/functions/Function1;)V + public static synthetic fun cell$default (Ldev/inmo/tgbotapi/types/rich/InputRichBlockTableRowBuilder;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/Integer;Ljava/lang/Integer;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V +} + public final class dev/inmo/tgbotapi/types/rich/InputRichBlockThinking : dev/inmo/tgbotapi/types/rich/InputRichBlock { public static final field Companion Ldev/inmo/tgbotapi/types/rich/InputRichBlockThinking$Companion; public static final field TYPE Ljava/lang/String; @@ -36005,8 +36018,8 @@ public final class dev/inmo/tgbotapi/types/rich/InputRichBlocksBuilder { public static synthetic fun pullQuotation$default (Ldev/inmo/tgbotapi/types/rich/InputRichBlocksBuilder;Ldev/inmo/tgbotapi/types/rich/RichText;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V public final fun slideshow (Ldev/inmo/tgbotapi/types/rich/RichBlockCaption;Lkotlin/jvm/functions/Function1;)V public static synthetic fun slideshow$default (Ldev/inmo/tgbotapi/types/rich/InputRichBlocksBuilder;Ldev/inmo/tgbotapi/types/rich/RichBlockCaption;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V - public final fun table (Ljava/util/List;Ljava/lang/Boolean;Ljava/lang/Boolean;Ldev/inmo/tgbotapi/types/rich/RichText;)V - public static synthetic fun table$default (Ldev/inmo/tgbotapi/types/rich/InputRichBlocksBuilder;Ljava/util/List;Ljava/lang/Boolean;Ljava/lang/Boolean;Ldev/inmo/tgbotapi/types/rich/RichText;ILjava/lang/Object;)V + public final fun table (Ljava/lang/Boolean;Ljava/lang/Boolean;Ldev/inmo/tgbotapi/types/rich/RichText;Lkotlin/jvm/functions/Function1;)V + public static synthetic fun table$default (Ldev/inmo/tgbotapi/types/rich/InputRichBlocksBuilder;Ljava/lang/Boolean;Ljava/lang/Boolean;Ldev/inmo/tgbotapi/types/rich/RichText;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V public final fun thinking (Ljava/lang/String;)V public final fun thinking (Lkotlin/jvm/functions/Function1;)V public final fun unaryPlus (Ldev/inmo/tgbotapi/types/rich/InputRichBlock;)V diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/rich/InputRichBlocksDsl.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/rich/InputRichBlocksDsl.kt index 88be62ad1c..eddaece652 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/rich/InputRichBlocksDsl.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/rich/InputRichBlocksDsl.kt @@ -49,6 +49,37 @@ class InputRichBlockUnorderedListBuilder { fun build(): List = items.toList() } +/** Builder of [RichBlockTableCell]s used inside [InputRichBlockTableBuilder.row]. */ +@RichTextDsl +class InputRichBlockTableRowBuilder { + private val cells = mutableListOf() + + fun cell( + align: String, + valign: String, + isHeader: Boolean? = null, + colspan: Int? = null, + rowspan: Int? = null, + block: RichTextBuilder.() -> Unit + ) { + cells.add(RichBlockTableCell(buildRichText(block), isHeader, colspan, rowspan, align, valign)) + } + + fun build(): List = cells.toList() +} + +/** Builder of table rows used inside [InputRichBlocksBuilder.table]. */ +@RichTextDsl +class InputRichBlockTableBuilder { + private val rows = mutableListOf>() + + fun row(block: InputRichBlockTableRowBuilder.() -> Unit) { + rows.add(InputRichBlockTableRowBuilder().apply(block).build()) + } + + fun build(): List> = rows.toList() +} + /** * Builder of a [List] of [InputRichBlock]s - the root of the rich message input DSL. Text-bearing and container blocks * have their own DSL functions; media blocks (photo, video, animation, audio, voice note, collage, slideshow, table, @@ -136,11 +167,11 @@ class InputRichBlocksBuilder { add(InputRichBlockSlideshow(buildInputRichBlocks(block), caption)) fun table( - cells: List>, isBordered: Boolean? = null, isStriped: Boolean? = null, - caption: RichText? = null - ) = add(InputRichBlockTable(cells, isBordered, isStriped, caption)) + caption: RichText? = null, + block: InputRichBlockTableBuilder.() -> Unit + ) = add(InputRichBlockTable(InputRichBlockTableBuilder().apply(block).build(), isBordered, isStriped, caption)) fun map( location: StaticLocation, diff --git a/tgbotapi.core/src/commonTest/kotlin/dev/inmo/tgbotapi/types/rich/InputRichBlocksDslTest.kt b/tgbotapi.core/src/commonTest/kotlin/dev/inmo/tgbotapi/types/rich/InputRichBlocksDslTest.kt index 371201bd14..5f981764fd 100644 --- a/tgbotapi.core/src/commonTest/kotlin/dev/inmo/tgbotapi/types/rich/InputRichBlocksDslTest.kt +++ b/tgbotapi.core/src/commonTest/kotlin/dev/inmo/tgbotapi/types/rich/InputRichBlocksDslTest.kt @@ -78,4 +78,52 @@ class InputRichBlocksDslTest { assertEquals(RichTextPlain("h1"), (blocks[0] as InputRichBlockSectionHeading).text) assertEquals(RichTextBold(RichTextPlain("h2")), (blocks[1] as InputRichBlockSectionHeading).text) } + + @Test + fun buildsTable() { + val blocks = buildInputRichBlocks { + table(isBordered = true, isStriped = false, caption = RichTextPlain("caption")) { + row { + cell(align = "left", valign = "top", isHeader = true, colspan = 2) { + bold("heading") + } + } + row { + cell(align = "center", valign = "middle", rowspan = 2) { + plain("value") + } + } + } + } + + assertEquals( + listOf( + InputRichBlockTable( + cells = listOf( + listOf( + RichBlockTableCell( + text = RichTextBold(RichTextPlain("heading")), + isHeader = true, + colspan = 2, + align = "left", + valign = "top" + ) + ), + listOf( + RichBlockTableCell( + text = RichTextPlain("value"), + rowspan = 2, + align = "center", + valign = "middle" + ) + ) + ), + isBordered = true, + isStriped = false, + caption = RichTextPlain("caption") + ) + ), + blocks + ) + } }