ruma_events/
media_preview_config.rs

1//! Types for the [`m.media_preview_config`] event.
2//!
3//! [`m.media_preview_config`]: https://github.com/matrix-org/matrix-spec-proposals/pull/4278
4
5use ruma_common::serde::JsonCastable;
6use ruma_macros::StringEnum;
7use serde::{Deserialize, Serialize};
8
9use crate::{macros::EventContent, PrivOwnedStr};
10
11/// The content of an `m.media_preview_config` event.
12#[derive(Clone, Debug, Default, Deserialize, Serialize, EventContent)]
13#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
14#[ruma_event(type = "m.media_preview_config", kind = GlobalAccountData + RoomAccountData)]
15pub struct MediaPreviewConfigEventContent {
16    /// The media previews configuration.
17    #[serde(skip_serializing_if = "Option::is_none")]
18    pub media_previews: Option<MediaPreviews>,
19
20    /// The invite avatars configuration.
21    #[serde(skip_serializing_if = "Option::is_none")]
22    pub invite_avatars: Option<InviteAvatars>,
23}
24
25impl JsonCastable<UnstableMediaPreviewConfigEventContent> for MediaPreviewConfigEventContent {}
26
27/// The content of an `io.element.msc4278.media_preview_config` event,
28/// the unstable version of `m.media_preview_config` in global account data.
29#[derive(Clone, Debug, Default, Deserialize, Serialize, EventContent)]
30#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
31#[ruma_event(type = "io.element.msc4278.media_preview_config", kind = GlobalAccountData + RoomAccountData)]
32#[serde(transparent)]
33pub struct UnstableMediaPreviewConfigEventContent(pub MediaPreviewConfigEventContent);
34
35impl JsonCastable<MediaPreviewConfigEventContent> for UnstableMediaPreviewConfigEventContent {}
36
37/// The configuration that handles if media previews should be shown in the timeline.
38#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, StringEnum, Default)]
39#[ruma_enum(rename_all = "lowercase")]
40#[non_exhaustive]
41pub enum MediaPreviews {
42    /// Media previews should be hidden.
43    Off,
44
45    /// Media previews should be only shown in private rooms.
46    Private,
47
48    /// Media previews should always be shown.
49    #[default]
50    On,
51
52    #[doc(hidden)]
53    _Custom(PrivOwnedStr),
54}
55
56/// The configuration to handle if avatars should be shown in invites.
57#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, StringEnum, Default)]
58#[ruma_enum(rename_all = "lowercase")]
59#[non_exhaustive]
60pub enum InviteAvatars {
61    /// Avatars in invites should be hidden.
62    Off,
63
64    /// Avatars in invites should be shown.
65    #[default]
66    On,
67
68    #[doc(hidden)]
69    _Custom(PrivOwnedStr),
70}
71
72impl MediaPreviewConfigEventContent {
73    /// Create a new empty [`MediaPreviewConfigEventContent`].
74    pub fn new() -> Self {
75        Self::default()
76    }
77
78    /// Set the value of the setting for the media previews.
79    pub fn media_previews(mut self, media_previews: Option<MediaPreviews>) -> Self {
80        self.media_previews = media_previews;
81        self
82    }
83
84    /// Set the value of the setting for the media previews.
85    pub fn invite_avatars(mut self, invite_avatars: Option<InviteAvatars>) -> Self {
86        self.invite_avatars = invite_avatars;
87        self
88    }
89
90    /// Merge the config from the global account data with the config from the room account data.
91    ///
92    /// The values that are set in the room account data take precedence over the values in the
93    /// global account data.
94    pub fn merge_global_and_room_config(global_config: Self, room_config: Self) -> Self {
95        Self {
96            media_previews: room_config.media_previews.or(global_config.media_previews),
97            invite_avatars: room_config.invite_avatars.or(global_config.invite_avatars),
98        }
99    }
100}
101
102impl std::ops::Deref for UnstableMediaPreviewConfigEventContent {
103    type Target = MediaPreviewConfigEventContent;
104
105    fn deref(&self) -> &Self::Target {
106        &self.0
107    }
108}
109
110impl From<MediaPreviewConfigEventContent> for UnstableMediaPreviewConfigEventContent {
111    fn from(value: MediaPreviewConfigEventContent) -> Self {
112        Self(value)
113    }
114}
115
116impl From<UnstableMediaPreviewConfigEventContent> for MediaPreviewConfigEventContent {
117    fn from(value: UnstableMediaPreviewConfigEventContent) -> Self {
118        value.0
119    }
120}
121
122#[cfg(all(test, feature = "unstable-msc4278"))]
123mod tests {
124    use assert_matches2::assert_matches;
125    use serde_json::{from_value as from_json_value, json, to_value as to_json_value};
126
127    use super::{MediaPreviewConfigEventContent, UnstableMediaPreviewConfigEventContent};
128    use crate::{
129        media_preview_config::{InviteAvatars, MediaPreviews},
130        AnyGlobalAccountDataEvent, GlobalAccountDataEvent,
131    };
132
133    #[test]
134    fn deserialize() {
135        let raw_unstable_media_preview_config = json!({
136            "type": "io.element.msc4278.media_preview_config",
137            "content": {
138                "media_previews": "private",
139                "invite_avatars": "off",
140            },
141        });
142        let unstable_media_preview_config_data =
143            from_json_value::<AnyGlobalAccountDataEvent>(raw_unstable_media_preview_config)
144                .unwrap();
145        assert_matches!(
146            unstable_media_preview_config_data,
147            AnyGlobalAccountDataEvent::UnstableMediaPreviewConfig(unstable_media_preview_config)
148        );
149        assert_eq!(
150            unstable_media_preview_config.content.media_previews,
151            Some(MediaPreviews::Private)
152        );
153        assert_eq!(unstable_media_preview_config.content.invite_avatars, Some(InviteAvatars::Off));
154
155        let raw_media_preview_config = json!({
156            "type": "m.media_preview_config",
157            "content": {
158                "media_previews": "on",
159                "invite_avatars": "on",
160            },
161        });
162        let media_preview_config_data =
163            from_json_value::<AnyGlobalAccountDataEvent>(raw_media_preview_config).unwrap();
164        assert_matches!(
165            media_preview_config_data,
166            AnyGlobalAccountDataEvent::MediaPreviewConfig(media_preview_config)
167        );
168        assert_eq!(media_preview_config.content.media_previews, Some(MediaPreviews::On));
169        assert_eq!(media_preview_config.content.invite_avatars, Some(InviteAvatars::On));
170    }
171
172    #[test]
173    fn serialize() {
174        let unstable_media_preview_config = UnstableMediaPreviewConfigEventContent(
175            MediaPreviewConfigEventContent::new()
176                .media_previews(Some(MediaPreviews::Off))
177                .invite_avatars(Some(InviteAvatars::On)),
178        );
179        let unstable_media_preview_config_account_data =
180            GlobalAccountDataEvent { content: unstable_media_preview_config };
181        assert_eq!(
182            to_json_value(unstable_media_preview_config_account_data).unwrap(),
183            json!({
184                "type": "io.element.msc4278.media_preview_config",
185                "content": {
186                    "media_previews": "off",
187                    "invite_avatars": "on",
188                },
189            })
190        );
191
192        let media_preview_config = MediaPreviewConfigEventContent::new()
193            .media_previews(Some(MediaPreviews::On))
194            .invite_avatars(Some(InviteAvatars::Off));
195        let media_preview_config_account_data =
196            GlobalAccountDataEvent { content: media_preview_config };
197        assert_eq!(
198            to_json_value(media_preview_config_account_data).unwrap(),
199            json!({
200                "type": "m.media_preview_config",
201                "content": {
202                    "media_previews": "on",
203                    "invite_avatars": "off",
204                },
205            })
206        );
207    }
208}