Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 3 additions & 6 deletions src/home/room_image_viewer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use matrix_sdk::{
};
use matrix_sdk::reqwest::StatusCode;

use crate::{media_cache::{MediaCache, MediaCacheEntry}, shared::image_viewer::{ImageViewerAction, ImageViewerError, LoadState}};
use crate::{media_cache::{MediaCache, MediaCacheEntry}, shared::{attachment_download::media_source_mxc, image_viewer::{ImageViewerAction, ImageViewerError, LoadState}}};

/// Populates the image viewer modal with the given media content.
///
Expand All @@ -18,11 +18,8 @@ pub fn populate_matrix_image_modal(
media_source: MediaSource,
media_cache: &mut MediaCache,
) {
let MediaSource::Plain(mxc_uri) = media_source else {
return;
};
// Try to get media from cache or trigger fetch
let media_entry = media_cache.try_get_media_or_fetch(&mxc_uri, MediaFormat::File);
let media_entry = media_cache.try_get_media_or_fetch(&media_source, MediaFormat::File);

// Handle the different media states
match media_entry {
Expand All @@ -39,7 +36,7 @@ pub fn populate_matrix_image_modal(
};
cx.action(ImageViewerAction::Show(LoadState::Error(error)));
// Remove failed media entry from cache for MediaFormat::File so as to start all over again from loading Thumbnail.
media_cache.remove_cache_entry(&mxc_uri, Some(MediaFormat::File));
media_cache.remove_cache_entry(media_source_mxc(&media_source), Some(MediaFormat::File));
}
_ => {}
}
Expand Down
103 changes: 36 additions & 67 deletions src/home/room_screen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use matrix_sdk::{
AudioMessageEventContent, EmoteMessageEventContent, FileMessageEventContent, FormattedBody, ImageMessageEventContent, KeyVerificationRequestEventContent, LocationMessageEventContent, MessageFormat, MessageType, NoticeMessageEventContent, TextMessageEventContent, VideoMessageEventContent
}
},
sticker::{StickerEventContent, StickerMediaSource},
sticker::StickerEventContent,
}, matrix_uri::MatrixId, uint
}
};
Expand Down Expand Up @@ -3758,48 +3758,32 @@ fn populate_message_view(
let was_cached = existed && item_drawn_status.content_drawn;

let text_or_image_ref = item.text_or_image(cx, ids!(content.message));
match source {
StickerMediaSource::Plain(owned_mxc_url) => {
let filename = if body.is_empty() { "sticker".to_owned() } else { body.clone() };
let size = info.size.map(u64::from);
download_info = if was_cached {
matches!(text_or_image_ref.status(), TextOrImageStatus::Text)
.then(|| DownloadableAttachment {
media_source: MediaSource::Plain(owned_mxc_url.clone()),
filename,
size,
kind: DownloadKind::Image,
})
} else {
let (is_image_fully_drawn, fallback) = populate_image_message_content_with_fallback(
cx,
&text_or_image_ref,
Some(Box::new(info.clone())),
MediaSource::Plain(owned_mxc_url.clone()),
body,
media_cache,
filename,
size,
DownloadKind::Image,
);
new_drawn_status.content_drawn = is_image_fully_drawn;
fallback
};
}
// Encrypted sticker decryption isn't wired up yet; show a
// placeholder so the message doesn't render blank.
_ => {
if !was_cached {
let label = if body.is_empty() {
"[Encrypted sticker]".to_owned()
} else {
format!("[Encrypted sticker: {body}]")
};
text_or_image_ref.show_text(cx, label);
new_drawn_status.content_drawn = true;
}
}
}
let media_source: MediaSource = source.clone().into();
let filename = if body.is_empty() { "sticker".to_owned() } else { body.clone() };
let size = info.size.map(u64::from);
download_info = if was_cached {
matches!(text_or_image_ref.status(), TextOrImageStatus::Text)
.then(|| DownloadableAttachment {
media_source,
filename,
size,
kind: DownloadKind::Image,
})
} else {
let (is_image_fully_drawn, fallback) = populate_image_message_content_with_fallback(
cx,
&text_or_image_ref,
Some(Box::new(info.clone())),
media_source,
body,
media_cache,
filename,
size,
DownloadKind::Image,
);
new_drawn_status.content_drawn = is_image_fully_drawn;
fallback
};
(item, was_cached)
}
// Handle messages that have been redacted (deleted).
Expand Down Expand Up @@ -4148,12 +4132,10 @@ fn populate_image_message_content(

let mut fully_drawn = false;

// A closure that fetches and shows the image from the given `mxc_uri`,
// marking it as fully drawn if the image was available.
let mut fetch_and_show_image_uri = |cx: &mut Cx, mxc_uri: OwnedMxcUri, image_info: Box<ImageInfo>| {
match media_cache.try_get_media_or_fetch(&mxc_uri, MEDIA_THUMBNAIL_FORMAT.into()) {
let mut fetch_and_show_media_source = |cx: &mut Cx, media_source: MediaSource, image_info: Box<ImageInfo>| {
match media_cache.try_get_media_or_fetch(&media_source, MEDIA_THUMBNAIL_FORMAT.into()) {
(MediaCacheEntry::Loaded(data), _media_format) => {
let show_image_result = text_or_image_ref.show_image(cx, Some(MediaSource::Plain(mxc_uri)),|cx, img| {
let show_image_result = text_or_image_ref.show_image(cx, Some(media_source), |cx, img| {
utils::load_png_or_jpg(&img, cx, &data)
.map(|()| img.size_in_pixels(cx).unwrap_or_default())
});
Expand All @@ -4169,7 +4151,7 @@ fn populate_image_message_content(
(MediaCacheEntry::Requested, _media_format) => {
// If the image is being fetched, we try to show its blurhash.
if let (Some(ref blurhash), Some(width), Some(height)) = (image_info.blurhash.clone(), image_info.width, image_info.height) {
let show_image_result = text_or_image_ref.show_image(cx, Some(MediaSource::Plain(mxc_uri)), |cx, img| {
let show_image_result = text_or_image_ref.show_image(cx, Some(media_source), |cx, img| {
let (Ok(width), Ok(height)) = (width.try_into(), height.try_into()) else {
return Err(image_cache::ImageError::EmptyData)
};
Expand Down Expand Up @@ -4202,7 +4184,7 @@ fn populate_image_message_content(
Err(e) => {
error!("Failed to decode blurhash {e:?}");
Err(image_cache::ImageError::EmptyData)
}
}
}
});
if let Err(e) = show_image_result {
Expand All @@ -4218,26 +4200,13 @@ fn populate_image_message_content(
fully_drawn = true;
return;
}
text_or_image_ref
.show_text(cx, format!("{body}\n\nFailed to fetch image from {:?}", mxc_uri));
// For now, we consider this as being "complete". In the future, we could support
// retrying to fetch thumbnail of the image on a user click/tap.
fully_drawn = true;
}
}
};

let mut fetch_and_show_media_source = |cx: &mut Cx, media_source: MediaSource, image_info: Box<ImageInfo>| {
match media_source {
MediaSource::Encrypted(encrypted) => {
// We consider this as "fully drawn" since we don't yet support encryption.
text_or_image_ref.show_text(
cx,
format!("{body}\n\n[TODO] fetch encrypted image at {:?}", encrypted.url)
format!("{body}\n\nFailed to fetch image from {:?}", media_source_mxc(&media_source)),
);
},
MediaSource::Plain(mxc_uri) => {
fetch_and_show_image_uri(cx, mxc_uri, image_info)
// For now, we consider this as being "complete". In the future, we could support
// retrying to fetch thumbnail of the image on a user click/tap.
fully_drawn = true;
}
}
};
Expand Down
28 changes: 6 additions & 22 deletions src/media_cache.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use std::{ops::{Deref, DerefMut}, sync::{Arc, Mutex}, time::SystemTime};
use std::{ops::{Deref, DerefMut}, sync::{Arc, Mutex}};
use hashbrown::{hash_map::RawEntryMut, HashMap};
use makepad_widgets::{error, log, SignalToUI};
use makepad_widgets::{error, SignalToUI};
use matrix_sdk::{media::{MediaFormat, MediaRequestParameters, MediaThumbnailSettings}, ruma::{events::room::MediaSource, OwnedMxcUri}, Error, HttpError};
use matrix_sdk::reqwest::StatusCode;
use crate::{home::room_screen::TimelineUpdate, sliding_sync::{self, MatrixRequest}};
use crate::{home::room_screen::TimelineUpdate, shared::attachment_download::media_source_mxc, sliding_sync::{self, MatrixRequest}};

/// The value type in the media cache, one per Matrix URI.
#[derive(Debug, Clone)]
Expand Down Expand Up @@ -84,9 +84,10 @@ impl MediaCache {
/// Returns a tuple of the media cache entry and the media format of that cached entry.
pub fn try_get_media_or_fetch(
&mut self,
mxc_uri: &OwnedMxcUri,
source: &MediaSource,
requested_format: MediaFormat,
) -> (MediaCacheEntry, MediaFormat) {
let mxc_uri = media_source_mxc(source);
let mut post_request_retval = (MediaCacheEntry::Requested, requested_format.clone());
let entry_ref_to_fetch: MediaCacheEntryRef;

Expand Down Expand Up @@ -161,7 +162,7 @@ impl MediaCache {

sliding_sync::submit_async_request(MatrixRequest::FetchMedia {
media_request: MediaRequestParameters {
source: MediaSource::Plain(mxc_uri.clone()),
source: source.clone(),
format: requested_format,
},
on_fetched: insert_into_cache,
Expand Down Expand Up @@ -278,23 +279,6 @@ fn insert_into_cache<D: Into<Arc<[u8]>>>(
let new_value = match data {
Ok(data) => {
let data = data.into();

// debugging: dump out the media image to disk
if false {
if let MediaSource::Plain(mxc_uri) = &request.source {
log!("Fetched media for {mxc_uri}");
let mut path = crate::temp_storage::get_temp_dir_path().clone();
let filename = format!("{}_{}_{}",
SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_millis(),
mxc_uri.server_name().unwrap(), mxc_uri.media_id().unwrap(),
);
path.push(filename);
path.set_extension("png");
log!("Writing user media image to disk: {:?}", path);
std::fs::write(path, &data)
.expect("Failed to write user media image to disk");
}
}
MediaCacheEntry::Loaded(data)
}
Err(e) => error_to_media_cache_entry(e, &request)
Expand Down
Loading