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 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}