matrix_sdk_ui/timeline/
futures.rs

1use std::future::IntoFuture;
2
3use eyeball::SharedObservable;
4use matrix_sdk::TransmissionProgress;
5use matrix_sdk_base::boxed_into_future;
6use mime::Mime;
7use tracing::{Instrument as _, Span};
8
9use super::{AttachmentSource, Error, Timeline};
10use crate::timeline::AttachmentConfig;
11
12pub struct SendAttachment<'a> {
13    timeline: &'a Timeline,
14    source: AttachmentSource,
15    mime_type: Mime,
16    config: AttachmentConfig,
17    tracing_span: Span,
18    pub(crate) send_progress: SharedObservable<TransmissionProgress>,
19    use_send_queue: bool,
20}
21
22impl<'a> SendAttachment<'a> {
23    pub(crate) fn new(
24        timeline: &'a Timeline,
25        source: AttachmentSource,
26        mime_type: Mime,
27        config: AttachmentConfig,
28    ) -> Self {
29        Self {
30            timeline,
31            source,
32            mime_type,
33            config,
34            tracing_span: Span::current(),
35            send_progress: Default::default(),
36            use_send_queue: false,
37        }
38    }
39
40    /// (Experimental) Uses the send queue to upload this media.
41    ///
42    /// This uses the send queue to upload the medias, and as such it provides
43    /// local echoes for the uploaded media too, not blocking the sending
44    /// request.
45    ///
46    /// This will be the default in future versions, when the feature work will
47    /// be done there.
48    pub fn use_send_queue(self) -> Self {
49        Self { use_send_queue: true, ..self }
50    }
51
52    /// Get a subscriber to observe the progress of sending the request body.
53    pub fn subscribe_to_send_progress(&self) -> eyeball::Subscriber<TransmissionProgress> {
54        self.send_progress.subscribe()
55    }
56}
57
58impl<'a> IntoFuture for SendAttachment<'a> {
59    type Output = Result<(), Error>;
60    boxed_into_future!(extra_bounds: 'a);
61
62    fn into_future(self) -> Self::IntoFuture {
63        let Self {
64            timeline,
65            source,
66            mime_type,
67            config,
68            tracing_span,
69            use_send_queue,
70            send_progress,
71        } = self;
72
73        let fut = async move {
74            let (data, filename) = source.try_into_bytes_and_filename()?;
75
76            let reply = timeline.infer_reply(config.in_reply_to).await;
77            let sdk_config = matrix_sdk::attachment::AttachmentConfig {
78                txn_id: config.txn_id,
79                info: config.info,
80                thumbnail: config.thumbnail,
81                caption: config.caption,
82                formatted_caption: config.formatted_caption,
83                mentions: config.mentions,
84                reply,
85            };
86
87            if use_send_queue {
88                timeline
89                    .room()
90                    .send_queue()
91                    .send_attachment(filename, mime_type, data, sdk_config)
92                    .await
93                    .map_err(|_| Error::FailedSendingAttachment)?;
94            } else {
95                timeline
96                    .room()
97                    .send_attachment(filename, &mime_type, data, sdk_config)
98                    .with_send_progress_observable(send_progress)
99                    .store_in_cache()
100                    .await
101                    .map_err(|_| Error::FailedSendingAttachment)?;
102            }
103
104            Ok(())
105        };
106
107        Box::pin(fut.instrument(tracing_span))
108    }
109}
110
111#[cfg(feature = "unstable-msc4274")]
112pub use galleries::*;
113
114#[cfg(feature = "unstable-msc4274")]
115mod galleries {
116    use std::future::IntoFuture;
117
118    use matrix_sdk_base::boxed_into_future;
119    use tracing::{Instrument as _, Span};
120
121    use super::{Error, Timeline};
122    use crate::timeline::GalleryConfig;
123
124    pub struct SendGallery<'a> {
125        timeline: &'a Timeline,
126        gallery: GalleryConfig,
127        tracing_span: Span,
128    }
129
130    impl<'a> SendGallery<'a> {
131        pub(crate) fn new(timeline: &'a Timeline, gallery: GalleryConfig) -> Self {
132            Self { timeline, gallery, tracing_span: Span::current() }
133        }
134    }
135
136    impl<'a> IntoFuture for SendGallery<'a> {
137        type Output = Result<(), Error>;
138        boxed_into_future!(extra_bounds: 'a);
139
140        fn into_future(self) -> Self::IntoFuture {
141            let Self { timeline, gallery, tracing_span } = self;
142
143            let fut = async move {
144                let reply = timeline.infer_reply(gallery.in_reply_to).await;
145
146                let mut config = matrix_sdk::attachment::GalleryConfig::new();
147
148                if let Some(txn_id) = gallery.txn_id {
149                    config = config.txn_id(txn_id);
150                }
151
152                for item in gallery.items {
153                    config = config.add_item(item.try_into()?);
154                }
155
156                config = config
157                    .caption(gallery.caption)
158                    .formatted_caption(gallery.formatted_caption)
159                    .mentions(gallery.mentions)
160                    .reply(reply);
161
162                timeline
163                    .room()
164                    .send_queue()
165                    .send_gallery(config)
166                    .await
167                    .map_err(|_| Error::FailedSendingAttachment)?;
168
169                Ok(())
170            };
171
172            Box::pin(fut.instrument(tracing_span))
173        }
174    }
175}