Skip to content

Conversation

@alanpoon
Copy link
Contributor

@alanpoon alanpoon commented Aug 6, 2025

Fixes #327
Screenshot 2025-08-06 at 5 46 55 PM

in replacement of #443

Waiting for this PR to be merged: makepad/makepad#788.

@alanpoon alanpoon self-assigned this Aug 6, 2025
@alanpoon alanpoon added the blocked-on-makepad Blocked on a Makepad bug or missing Makepad feature label Aug 11, 2025
@alanpoon
Copy link
Contributor Author

Intention of adding an image magnifier and the ability to pan image.

The image's image_scale, image_pan will always be set to default in draw_walk. Hence unable to dynamically scale and pan image.
makepad/makepad#785

@kevinaboos
Copy link
Member

Intention of adding an image magnifier and the ability to pan image.

The image's image_scale, image_pan will always be set to default in draw_walk. Hence unable to dynamically scale and pan image. makepad/makepad#785

@alanpoon I just checked with Rik, and this line should not be present in the Image widget. It's some errant code left over from dealing with animations in a strange way.

You can submit a PR to makepad that removes that line, and then continue with this issue here.

@kevinaboos kevinaboos added waiting-on-author This issue is waiting on the original author for a response and removed blocked-on-makepad Blocked on a Makepad bug or missing Makepad feature labels Oct 17, 2025
@alanpoon
Copy link
Contributor Author

Sure, the makepad PR is here: makepad/makepad#788

@alanpoon
Copy link
Contributor Author

Screenshot 2025-10-19 at 10 58 51 AM Screenshot 2025-10-19 at 10 58 57 AM Screenshot 2025-10-19 at 10 59 17 AM

@alanpoon alanpoon added waiting-on-review This issue is waiting to be reviewed and removed waiting-on-author This issue is waiting on the original author for a response labels Oct 19, 2025
Copy link
Member

@kevinaboos kevinaboos left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Alan, nice work here.

My main comment is that we should decouple the ImageViewer widget from the RoomScreen. It doesn't need to know anything about the RoomScreen except for being able to access the RoomScreen's MediaCache instance (technically even that is not required, see Aarav's PR for an example of just passing the image data directly from the media fetch background task to the ImageViewer via an action).

Also, Aarav and I had a lot of discussions about using actions to communicate with the ImageViewer widget in PR#443. I think you can combine your approach (of storing images in the RoomScreen's MediaCache) with the action-based design from #443 (in which you emit an action including the image data/status instead of directly accessing the widget and calling a function on it). Actions are more idiomatic and also allow easy communication from any context, both in a background task and in a RoomScreen TimelineUpdate handler.

@alanpoon alanpoon added the waiting-on-author This issue is waiting on the original author for a response label Nov 3, 2025
@alanpoon alanpoon added waiting-on-review This issue is waiting to be reviewed and removed waiting-on-author This issue is waiting on the original author for a response labels Nov 4, 2025
src/app.rs Outdated
Comment on lines 523 to 545
// If the image viewer modal is really opened, handles non-Draw events using the modal.
let image_viewer_modal = self.ui.modal(ids!(image_viewer));
if image_viewer_modal.is_open() && image_viewer_modal.area().rect(cx).size.y > 0.0 {
let scope = &mut Scope::with_data(&mut self.app_state);
self.ui
.view(ids!(popup_list))
.handle_event(cx, event, scope);
self.ui
.modal(ids!(image_viewer))
.handle_event(cx, event, scope);
// Pass the Signal event to the underlying room screen, so as to populate the full image in the image viewer.
if let Event::Signal = event {
self.ui.handle_event(cx, event, scope);
}
if let Event::Actions(actions) = event {
for action in actions {
if self.handle_image_viewer_action(cx, action) {
continue;
}
}
}
return;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this one modal so uniquely different than all the other modals? I would only expect you to have to handle opening and closing the ImageViewer modal here, just like all other modals.

I don't understand why you need to explicitly pass events to the modal; this is almost certainly incorrect and will result in the event being delivered to the modal twice.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I forgot to comment on the rationale. Modal widget is not behaving as expected with the events being propagated to underneath layer. This results in other image being clicked while the image viewer modal is opened.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, that's concerning. Can you open an issue on the Makepad repo with a minimal example that reproduces this, and then link to it in a code comment here? Thanks.

I'll try to dig into modal issues this week to see if we can fix it there.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I created a branch at https://github.com/alanpoon/makepad/tree/modal_underneath_test to test modal. The event does not propagate to underneath layer. But it is happening to Robrix. Not sure why.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After testing, this line

self.ui.view(ids!(login_screen_view)).set_visible(cx, show_login);
is the culprit as to why event propagates to the underneath layer.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Created a tracking issue here: #626. Hope to be settle this issue after this PR is merged.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok ... strange. Perhaps we need to redesign the LoginScreen to be something other than just a simple overlay view.

However, I don't understand why the existence of the LoginScreen (or whether it's currently visible) would impact how events are delivered to other widgets in that same overlay view (within the app body). I don't think that's actually the problem, because all the other modals in that same overlay view work just fine.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see one of my latest comments — i think if you just put the ImageViewer in a Modal (like with the verification modal or other modals), it will work as expected. I've never had any problems with modals in the top-level app not working as intended.

@kevinaboos kevinaboos added waiting-on-author This issue is waiting on the original author for a response and removed waiting-on-review This issue is waiting to be reviewed labels Nov 5, 2025
@alanpoon alanpoon added waiting-on-review This issue is waiting to be reviewed and removed waiting-on-author This issue is waiting on the original author for a response labels Nov 7, 2025
Copy link
Member

@kevinaboos kevinaboos left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for addressing my comments, I left a few more comments below.

One thing I don't quite understand is why any code outside of the ImageViewer needs to be concerned with the size/dimensions of the image. Only the ImageViewer itself would care about that.... and actually, why does the ImageViewer even care? Doesn't it just show the image in a full-screen view with width: Fill, height: Fill?

(perhaps you need image dimension data for handling pan/zoom, but either way, it shouldn't be relevant outside of the ImageViewer widget code)

let Some(item) = tl_state.items.get(index) else { return; };
let Some(event_tl_item) = item.as_event() else { return; };

let (capped_width, capped_height) = constrain_image_dimensions(size.x, size.y, screen_width);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why does this part of the code need to be concerned with the dimensions of the image or the size of the app window?

Ideally, any code module anywhere within Robrix should be able to just tell the ImageViewer to "show this image" without having to figure out any more details or calculate any dimensions. The ImageViewer will just display it in a full-screen view (width: FIll, height: Fill) so i'm not sure why you even need to calculate or constrain the dimensions at all.

Either way, it definitely shouldn't be done here, because that means that anywhere else I want to use the ImageViewer, i have to copy all of this complex code to populate it. We want to make it super easy to show an image in the ImageViewer.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed this logic

src/app.rs Outdated
login_screen = <LoginScreen> {}
}

<RoomImageViewer> { }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think the problems with the event delivery and drawing will both be solved if you put this inside of a Modal, just like the verification modal a few lines below this. That way, the events will automatically be propagated to it when appropriate.

Also, the ImageViewer is a modal if you think about it, so that makes sense.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

verification.mov

It seems like verification modal also has this problem. In this example, it is possible to click the link preview underneath the verification Modal.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh damn, that's not good. Thanks for discovering that! Looks like we'll need to fix the modal behavior asap, I will take a look as soon as I can.

For now, in this PR, just assume that modals work as expected, and don't add in any weird hacks to workaround that problem. We'll fix the modals properly so that you don't have to make special exceptions here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See my response in #626. If you merge in the latest changes from main, you should no longer be able to click widgets that are behind an open Modal. (however, scroll events will still propagate through... nothing I can do about that.)

Comment on lines 1 to 5
//! Room Image Viewer components for displaying images in full-screen modal.
//!
//! The main component is `RoomImageViewerDetail` which provides an overlay showing:
//! - Sender information (avatar, username, timestamp)
//! - Image metadata (filename, file size)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i like the general concept of splitting the ImageViewer into two elements: the core full-screen image view, and some metadata in an overlay.

There are a lot of different places in Robrix that I would like to be able to use your new Image Viewer, e.g., for user/room avatars, thumbnails of uploaded images, etc.

Thus, I would encourage you to make this "Room Image Viewer" into a more generic "Image viewer with metadata", in which the overlay view just shows any arbitrary metadata that the "caller" of the image viewer wanted to include alongside the image. Room message can be one example of that metadata, but this widget definitely shouldn't just be room-specific, because there are many other use cases where an image may not be associated with a room message.

Comment on lines 664 to 681
let content_message = wr.text_or_image(ids!(content.message));
if let TextOrImageAction::Clicked(mxc_uri) = actions.find_widget_action(content_message.widget_uid()).cast() {
let Some((texture, size)) = content_message.get_texture_and_size(cx) else { continue; };
let texture = std::rc::Rc::new(texture);
let screen_width = wr.area().rect(cx).size.x;

self.handle_image_click(
cx,
mxc_uri,
texture,
size,
screen_width,
index,
room_screen_widget_uid,
scope,
);
continue;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

very nice, this looks a lot better!

In accordance with my other comment, I would recommend moving even more of this code (the stuff dealing with texture size and screen width) into the ImageViewer itself, if it's even needed at all.

Remember, we want it to be as easy as possible to send images to the image viewer from any other part of the app too.

@kevinaboos kevinaboos added the waiting-on-author This issue is waiting on the original author for a response label Nov 8, 2025
Copy link
Member

@kevinaboos kevinaboos left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oops, accidentally left a comment review instead of requesting changes. See above.

@kevinaboos kevinaboos removed the waiting-on-review This issue is waiting to be reviewed label Nov 11, 2025
@alanpoon alanpoon added waiting-on-review This issue is waiting to be reviewed and removed waiting-on-author This issue is waiting on the original author for a response labels Nov 12, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

waiting-on-review This issue is waiting to be reviewed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

When the user clicks a thumbnail image, show the full-size image in an image viewer widget

2 participants