matrix_sdk_ui/timeline/
futures.rs1use 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 pub fn use_send_queue(self) -> Self {
49 Self { use_send_queue: true, ..self }
50 }
51
52 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}