-
Notifications
You must be signed in to change notification settings - Fork 37
Add image viewer widget #565
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
91bf416
to
440bde3
Compare
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. |
1b7875f
to
ddd04b9
Compare
@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. |
Sure, the makepad PR is here: makepad/makepad#788 |
There was a problem hiding this 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.
/// 1. Optionally initializes the modal with a new MXC URI | ||
/// 2. Attempts to fetch or retrieve cached media | ||
/// 3. Updates the UI based on the current media state: loading, loaded and failed. | ||
fn populate_image_modal( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should be moved into the image viewer widget module.
src/home/room_screen.rs
Outdated
if let LoadState::Loaded = populate_image_modal(cx, &mut self.image_viewer_timeout_timer, None, tl) { | ||
let image_viewer_modal = get_global_image_viewer_modal(cx); | ||
image_viewer_modal.set_image_loaded(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is an unusual code flow/design. One would expect the ImageViewer to be completely independent from the timeline, as we'd like to use the same ImageViewer for any image across the app (including user Avatars, room Avatars, etc), not just images in a specific timeline.
Aarav and I already had this discussion in PR #443. In my opinion, the flow of actions there are much clearer and not dependent upon the timeline.
I don't mind storing the full-size image in the timeline's media cache, but the ImageViewer should also be able to watch for actions when media is fetched, rather than exclusively relying on the RoomScreen widget. What happens if the RoomScreen is closed or otherwise not receiving updates by the time that the full-size image is fetched?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, with an action-based design, we don't need the ImageViewer to be a global instance.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The issue with Aarav's action-based design is that clicking the image multiple times will cause memory spikes. As the action is sending large image bytes multiple times.
populate_image_modal(cx, &mut self.image_viewer_timeout_timer, Some(mxc_uri), tl); | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we have a better way of doing this now, you can handle this properly by moving it to L856, and in that case you don't have to check for the RoomId or even include the RoomId in the action variant.
src/home/room_screen.rs
Outdated
/// Whether or not all rooms have been loaded (received from the homeserver). | ||
#[rust] all_rooms_loaded: bool, | ||
/// Timer for displaying `timeout` in the image viewer modal. | ||
#[rust] image_viewer_timeout_timer: Timer |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you need a timeout timer, it would be best to put it in the Image viewer widget itself, not in an unrelated widget like the RoomScreen.
However, I don't think you actually need a separate timer here. The fetch-media network request will naturally return an error if it times out, so you should just rely on that and treat it just like any other fetch error. It doesn't make sense to have a special case for time outs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In that way, you can also display other errors (e.g., no connection, image deleted, invalid URI, etc)
// Here we set the global singleton for the PopupList widget, | ||
// which is used to access PopupList Widget from anywhere in the app. | ||
crate::shared::popup_list::set_global_popup_list(cx, &self.ui); | ||
crate::shared::image_viewer_modal::set_global_image_viewer_modal(cx, self.ui.image_viewer_modal(id!(image_viewer_modal))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove. This shouldn't be necessary.
pub ICON_LINK = dep("crate://self/resources/icons/link.svg") | ||
pub ICON_PIN = dep("crate://self/resources/icons/pin.svg") | ||
pub ICON_REPLY = dep("crate://self/resources/icons/reply.svg") | ||
pub ICON_SEARCH = dep("crate://self/resources/icons/search.svg") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The icon used in the Image viewer should be a magnifying class with a +/- in it, not a search icon.
src/shared/text_or_image.rs
Outdated
if let Some(room_props) = scope.props.get::<RoomScreenProps>() { | ||
let room_id = room_props.room_id.clone(); | ||
// Send an Action containing the room_id and MXC URI to the room_screen | ||
cx.widget_action(self.widget_uid(), &scope.path, TextOrImageAction::Clicked(room_id, mxc_uri.clone())); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can't always guarantee that a TextOrImage
widget is a child of a RoomScreen widget, so we shouldn't attempt to access RoomScreenProps via scope.
However, RoomId shouldn't be necessary at all here (see my other comments), so we can remove this entirely.
cx.set_cursor(MouseCursor::Hand); | ||
} | ||
Hit::FingerHoverOut(_) => { | ||
cx.set_cursor(MouseCursor::Arrow); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you want Default here.
} | ||
} | ||
|
||
timeout_label_view = <View> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In keeping with my other comments, this should be a general error label, not limited to just time outs. The error from the network fetch operation should be shown to the user here (with a user-friendly message).
use link::tsp_link::TspVerificationModal; | ||
use crate::shared::image_viewer_modal::ImageViewerModal; | ||
|
||
APP_TAB_COLOR = #344054 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All of this AppTab stuff is old. Looks like a merge conflict mistake.
Fixes #327

in replacement of #443
Waiting for this PR to be merged: makepad/makepad#788.