acter_core/events/
stories.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
use derive_builder::Builder;
use derive_getters::Getters;
use matrix_sdk_base::ruma::events::{
    macros::EventContent,
    room::message::{
        AudioMessageEventContent, FileMessageEventContent, ImageMessageEventContent,
        LocationMessageEventContent, TextMessageEventContent, VideoMessageEventContent,
    },
};
use serde::{Deserialize, Serialize};

use super::{Colorize, ObjRef, Update};
use crate::{util::deserialize_some, Result};

#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(tag = "type")]
pub enum StoryContent {
    /// An image message.
    Image(ImageMessageEventContent),
    /// A video message.
    Video(VideoMessageEventContent),
    /// A text message.
    Text(TextMessageEventContent),
    /// An audio message.
    Audio(AudioMessageEventContent),
    /// A file message
    File(FileMessageEventContent),
    /// A location message.
    Location(LocationMessageEventContent),
}

impl StoryContent {
    pub fn type_str(&self) -> String {
        match self {
            StoryContent::File(_) => "file".to_owned(),
            StoryContent::Image(_) => "image".to_owned(),
            StoryContent::Location(_) => "location".to_owned(),
            StoryContent::Text(_) => "text".to_owned(),
            StoryContent::Audio(_) => "audio".to_owned(),
            StoryContent::Video(_) => "video".to_owned(),
        }
    }
    pub fn text_str(&self) -> String {
        match self {
            StoryContent::Image(ImageMessageEventContent { body, .. })
            | StoryContent::File(FileMessageEventContent { body, .. })
            | StoryContent::Location(LocationMessageEventContent { body, .. })
            | StoryContent::Video(VideoMessageEventContent { body, .. })
            | StoryContent::Audio(AudioMessageEventContent { body, .. }) => body.clone(),

            StoryContent::Text(TextMessageEventContent {
                formatted, body, ..
            }) => {
                if let Some(formatted) = formatted {
                    formatted.body.clone()
                } else {
                    body.clone()
                }
            }
        }
    }

    pub fn text(&self) -> Option<TextMessageEventContent> {
        match self {
            StoryContent::Text(body) => Some(body.clone()),
            _ => None,
        }
    }

    pub fn audio(&self) -> Option<AudioMessageEventContent> {
        match self {
            StoryContent::Audio(body) => Some(body.clone()),
            _ => None,
        }
    }

    pub fn video(&self) -> Option<VideoMessageEventContent> {
        match self {
            StoryContent::Video(body) => Some(body.clone()),
            _ => None,
        }
    }

    pub fn file(&self) -> Option<FileMessageEventContent> {
        match self {
            StoryContent::File(content) => Some(content.clone()),
            _ => None,
        }
    }

    pub fn image(&self) -> Option<ImageMessageEventContent> {
        match self {
            StoryContent::Image(content) => Some(content.clone()),
            _ => None,
        }
    }

    pub fn location(&self) -> Option<LocationMessageEventContent> {
        match self {
            StoryContent::Location(content) => Some(content.clone()),
            _ => None,
        }
    }
}
/// A Story slide represents one full-sized slide of Story
#[derive(Clone, Debug, Builder, Deserialize, Getters, Serialize)]
pub struct StorySlide {
    /// A slide must contain some Story-worthy content
    #[serde(flatten)]
    pub content: StoryContent,

    /// A slide may optionally contain references to other items
    #[builder(default)]
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub references: Vec<ObjRef>,

    /// You can define custom background and foreground colors
    #[builder(default)]
    #[serde(
        default,
        skip_serializing_if = "Option::is_none",
        deserialize_with = "deserialize_some"
    )]
    pub colors: Option<Colorize>,
}

/// The payload for our Story creation event.
#[derive(Clone, Debug, Builder, Deserialize, Serialize, Getters, EventContent)]
#[ruma_event(type = "global.acter.dev.story", kind = MessageLike)]
#[builder(name = "StoryBuilder", derive(Debug))]
pub struct StoryEventContent {
    /// A Story entry may have one or more slides of Story
    /// which are scrolled through horizontally
    pub slides: Vec<StorySlide>,
}

/// The payload for our Story update event.
#[derive(Clone, Debug, Builder, Deserialize, Serialize, EventContent)]
#[ruma_event(type = "global.acter.dev.story.update", kind = MessageLike)]
#[builder(name = "StoryUpdateBuilder", derive(Debug))]
pub struct StoryUpdateEventContent {
    #[builder(setter(into))]
    #[serde(rename = "m.relates_to")]
    pub story_entry: Update,

    /// A Story entry may have one or more slides of Story
    /// which are scrolled through horizontally
    #[builder(default)]
    #[serde(
        default,
        skip_serializing_if = "Option::is_none",
        deserialize_with = "deserialize_some"
    )]
    pub slides: Option<Vec<StorySlide>>,
}

impl StoryUpdateEventContent {
    pub fn apply(&self, task: &mut StoryEventContent) -> Result<bool> {
        let mut updated = false;
        if let Some(slides) = &self.slides {
            task.slides.clone_from(slides);
            updated = true;
        }
        Ok(updated)
    }
}