use serde::{Deserialize, Serialize};
use super::text::RichText;
use crate::types::{Animation, Audio, Integer, Location, PhotoSize, Video, Voice};
#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(from = "RawRichBlock", into = "RawRichBlock")]
pub enum RichBlock {
Anchor(String),
Animation(RichBlockAnimation),
Audio(RichBlockAudio),
BlockQuotation(RichBlockBlockQuotation),
Collage(RichBlockCollage),
Details(RichBlockDetails),
Divider,
Footer(RichText),
List(Vec<RichBlockListItem>),
Map(RichBlockMap),
MathematicalExpression(String),
Paragraph(RichText),
Photo(RichBlockPhoto),
Preformatted(RichBlockPreformatted),
PullQuotation(RichBlockPullQuotation),
SectionHeading(RichText, Integer),
Slideshow(RichBlockSlideshow),
Table(RichBlockTable),
Thinking(RichText),
Video(RichBlockVideo),
VoiceNote(RichBlockVoiceNote),
}
#[serde_with::skip_serializing_none]
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct RichBlockAnimation {
pub animation: Animation,
pub caption: Option<RichBlockCaption>,
pub has_spoiler: Option<bool>,
}
#[serde_with::skip_serializing_none]
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct RichBlockAudio {
pub audio: Audio,
pub caption: Option<RichBlockCaption>,
}
#[serde_with::skip_serializing_none]
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct RichBlockBlockQuotation {
pub blocks: Vec<RichBlock>,
pub credit: Option<RichText>,
}
#[serde_with::skip_serializing_none]
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct RichBlockCaption {
pub text: RichText,
pub credit: Option<RichText>,
}
impl<T> From<T> for RichBlockCaption
where
T: Into<RichText>,
{
fn from(value: T) -> Self {
Self {
text: value.into(),
credit: None,
}
}
}
impl<A, B> From<(A, B)> for RichBlockCaption
where
A: Into<RichText>,
B: Into<RichText>,
{
fn from((text, credit): (A, B)) -> Self {
Self::from(text).with_credit(credit)
}
}
impl RichBlockCaption {
pub fn with_credit<T>(mut self, value: T) -> Self
where
T: Into<RichText>,
{
self.credit = Some(value.into());
self
}
}
#[serde_with::skip_serializing_none]
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct RichBlockCollage {
pub blocks: Vec<RichBlock>,
pub caption: Option<RichBlockCaption>,
}
#[serde_with::skip_serializing_none]
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct RichBlockDetails {
pub blocks: Vec<RichBlock>,
pub summary: RichText,
pub is_open: Option<bool>,
}
#[serde_with::skip_serializing_none]
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct RichBlockListItem {
pub blocks: Vec<RichBlock>,
pub label: String,
pub has_checkbox: Option<bool>,
pub is_checked: Option<bool>,
#[serde(rename = "type")]
pub item_type: Option<RichBlockListItemType>,
pub value: Option<Integer>,
}
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
pub enum RichBlockListItemType {
#[serde(rename = "1")]
Decimal,
#[serde(rename = "a")]
LowercaseLetters,
#[serde(rename = "i")]
LowercaseRoman,
#[serde(rename = "A")]
UppercaseLetters,
#[serde(rename = "I")]
UppercaseRoman,
}
#[serde_with::skip_serializing_none]
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct RichBlockMap {
pub location: Location,
pub height: Integer,
pub width: Integer,
pub zoom: Integer,
pub caption: Option<RichBlockCaption>,
}
#[serde_with::skip_serializing_none]
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct RichBlockPhoto {
pub photo: Vec<PhotoSize>,
pub caption: Option<RichBlockCaption>,
pub has_spoiler: Option<bool>,
}
#[serde_with::skip_serializing_none]
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct RichBlockPreformatted {
pub text: RichText,
pub language: Option<String>,
}
#[serde_with::skip_serializing_none]
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct RichBlockPullQuotation {
pub text: RichText,
pub credit: Option<RichText>,
}
#[serde_with::skip_serializing_none]
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct RichBlockSlideshow {
pub blocks: Vec<RichBlock>,
pub caption: Option<RichBlockCaption>,
}
#[serde_with::skip_serializing_none]
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct RichBlockTable {
pub cells: Vec<Vec<RichBlockTableCell>>,
pub caption: Option<RichText>,
pub is_bordered: Option<bool>,
pub is_striped: Option<bool>,
}
#[serde_with::skip_serializing_none]
#[derive(Debug, Default, Clone, Deserialize, Serialize)]
pub struct RichBlockTableCell {
pub align: RichBlockTableCellAlign,
pub valign: RichBlockTableCellValign,
pub colspan: Option<Integer>,
pub is_header: Option<bool>,
pub rowspan: Option<Integer>,
pub text: Option<RichText>,
}
impl<T> From<T> for RichBlockTableCell
where
T: Into<RichText>,
{
fn from(value: T) -> Self {
Self::default().with_text(value)
}
}
impl RichBlockTableCell {
pub fn with_align(mut self, value: RichBlockTableCellAlign) -> Self {
self.align = value;
self
}
pub fn with_colspan(mut self, value: Integer) -> Self {
self.colspan = Some(value);
self
}
pub fn with_is_header(mut self, value: bool) -> Self {
self.is_header = Some(value);
self
}
pub fn with_rowspan(mut self, value: Integer) -> Self {
self.rowspan = Some(value);
self
}
pub fn with_text<T>(mut self, value: T) -> Self
where
T: Into<RichText>,
{
self.text = Some(value.into());
self
}
pub fn with_valign(mut self, value: RichBlockTableCellValign) -> Self {
self.valign = value;
self
}
}
#[derive(Clone, Copy, Debug, Default, Deserialize, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum RichBlockTableCellAlign {
#[default]
Left,
Center,
Right,
}
#[derive(Clone, Copy, Debug, Default, Deserialize, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum RichBlockTableCellValign {
Top,
#[default]
Middle,
Bottom,
}
#[serde_with::skip_serializing_none]
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct RichBlockVideo {
pub video: Video,
pub caption: Option<RichBlockCaption>,
pub has_spoiler: Option<bool>,
}
#[serde_with::skip_serializing_none]
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct RichBlockVoiceNote {
pub voice_note: Voice,
pub caption: Option<RichBlockCaption>,
}
#[serde_with::skip_serializing_none]
#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(rename_all = "snake_case", tag = "type")]
enum RawRichBlock {
Anchor {
name: String,
},
Animation(RichBlockAnimation),
Audio(RichBlockAudio),
#[serde(rename = "blockquote")]
BlockQuotation(RichBlockBlockQuotation),
Collage(RichBlockCollage),
Details(RichBlockDetails),
Divider,
Footer {
text: RichText,
},
List {
items: Vec<RichBlockListItem>,
},
Map(RichBlockMap),
MathematicalExpression {
expression: String,
},
Paragraph {
text: RichText,
},
Photo(RichBlockPhoto),
#[serde(rename = "pre")]
Preformatted(RichBlockPreformatted),
#[serde(rename = "pullquote")]
PullQuotation(RichBlockPullQuotation),
#[serde(rename = "heading")]
SectionHeading {
text: RichText,
size: Integer,
},
Slideshow(RichBlockSlideshow),
Table(RichBlockTable),
Thinking {
text: RichText,
},
Video(RichBlockVideo),
VoiceNote(RichBlockVoiceNote),
}
impl From<RichBlock> for RawRichBlock {
fn from(value: RichBlock) -> Self {
match value {
RichBlock::Anchor(name) => Self::Anchor { name },
RichBlock::Animation(value) => Self::Animation(value),
RichBlock::Audio(value) => Self::Audio(value),
RichBlock::BlockQuotation(value) => Self::BlockQuotation(value),
RichBlock::Collage(value) => Self::Collage(value),
RichBlock::Details(value) => Self::Details(value),
RichBlock::Divider => Self::Divider,
RichBlock::Footer(text) => Self::Footer { text },
RichBlock::List(items) => Self::List { items },
RichBlock::Map(value) => Self::Map(value),
RichBlock::MathematicalExpression(expression) => Self::MathematicalExpression { expression },
RichBlock::Paragraph(text) => Self::Paragraph { text },
RichBlock::Photo(value) => Self::Photo(value),
RichBlock::Preformatted(value) => Self::Preformatted(value),
RichBlock::PullQuotation(value) => Self::PullQuotation(value),
RichBlock::SectionHeading(text, size) => Self::SectionHeading { text, size },
RichBlock::Slideshow(value) => Self::Slideshow(value),
RichBlock::Table(value) => Self::Table(value),
RichBlock::Thinking(text) => Self::Thinking { text },
RichBlock::Video(value) => Self::Video(value),
RichBlock::VoiceNote(value) => Self::VoiceNote(value),
}
}
}
impl From<RawRichBlock> for RichBlock {
fn from(value: RawRichBlock) -> Self {
match value {
RawRichBlock::Anchor { name } => Self::Anchor(name),
RawRichBlock::Animation(value) => Self::Animation(value),
RawRichBlock::Audio(value) => Self::Audio(value),
RawRichBlock::BlockQuotation(value) => Self::BlockQuotation(value),
RawRichBlock::Collage(value) => Self::Collage(value),
RawRichBlock::Details(value) => Self::Details(value),
RawRichBlock::Divider => Self::Divider,
RawRichBlock::Footer { text } => Self::Footer(text),
RawRichBlock::List { items } => Self::List(items),
RawRichBlock::Map(value) => Self::Map(value),
RawRichBlock::MathematicalExpression { expression } => Self::MathematicalExpression(expression),
RawRichBlock::Paragraph { text } => Self::Paragraph(text),
RawRichBlock::Photo(value) => Self::Photo(value),
RawRichBlock::Preformatted(value) => Self::Preformatted(value),
RawRichBlock::PullQuotation(value) => Self::PullQuotation(value),
RawRichBlock::SectionHeading { text, size } => Self::SectionHeading(text, size),
RawRichBlock::Slideshow(value) => Self::Slideshow(value),
RawRichBlock::Table(value) => Self::Table(value),
RawRichBlock::Thinking { text } => Self::Thinking(text),
RawRichBlock::Video(value) => Self::Video(value),
RawRichBlock::VoiceNote(value) => Self::VoiceNote(value),
}
}
}