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                mentions: config.mentions,
83                reply,
84            };
85
86            if use_send_queue {
87                timeline
88                    .room()
89                    .send_queue()
90                    .send_attachment(filename, mime_type, data, sdk_config)
91                    .await
92                    .map_err(|_| Error::FailedSendingAttachment)?;
93            } else {
94                timeline
95                    .room()
96                    .send_attachment(filename, &mime_type, data, sdk_config)
97                    .with_send_progress_observable(send_progress)
98                    .store_in_cache()
99                    .await
100                    .map_err(|_| Error::FailedSendingAttachment)?;
101            }
102
103            Ok(())
104        };
105
106        Box::pin(fut.instrument(tracing_span))
107    }
108}
109
110#[cfg(feature = "unstable-msc4274")]
111pub use galleries::*;
112
113#[cfg(feature = "unstable-msc4274")]
114mod galleries {
115    use std::future::IntoFuture;
116
117    use matrix_sdk_base::boxed_into_future;
118    use tracing::{Instrument as _, Span};
119
120    use super::{Error, Timeline};
121    use crate::timeline::GalleryConfig;
122
123    pub struct SendGallery<'a> {
124        timeline: &'a Timeline,
125        gallery: GalleryConfig,
126        tracing_span: Span,
127    }
128
129    impl<'a> SendGallery<'a> {
130        pub(crate) fn new(timeline: &'a Timeline, gallery: GalleryConfig) -> Self {
131            Self { timeline, gallery, tracing_span: Span::current() }
132        }
133    }
134
135    impl<'a> IntoFuture for SendGallery<'a> {
136        type Output = Result<(), Error>;
137        boxed_into_future!(extra_bounds: 'a);
138
139        fn into_future(self) -> Self::IntoFuture {
140            let Self { timeline, gallery, tracing_span } = self;
141
142            let fut = async move {
143                let reply = timeline.infer_reply(gallery.in_reply_to).await;
144
145                let mut config = matrix_sdk::attachment::GalleryConfig::new();
146
147                if let Some(txn_id) = gallery.txn_id {
148                    config = config.txn_id(txn_id);
149                }
150
151                for item in gallery.items {
152                    config = config.add_item(item.try_into()?);
153                }
154
155                config = config.caption(gallery.caption).mentions(gallery.mentions).reply(reply);
156
157                timeline
158                    .room()
159                    .send_queue()
160                    .send_gallery(config)
161                    .await
162                    .map_err(|_| Error::FailedSendingAttachment)?;
163
164                Ok(())
165            };
166
167            Box::pin(fut.instrument(tracing_span))
168        }
169    }
170}