Skip to content
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

Show almost-instant preview when opening lightbox #6000

Merged
merged 5 commits into from
Oct 29, 2024
Merged

Conversation

gaearon
Copy link
Collaborator

@gaearon gaearon commented Oct 29, 2024

Stacked on #5999


We have two kinds of images: the "previews" shown in feed and fullsize images.

Previously, the lightbox would always show the fullsize image. After this change, the lightbox will initially show the "preview" and then switch to the fullsize image once it's downloaded. This works via Expo Image placeholder prop.

This means that, in most cases, opening lightbox should now feel almost instant. (No animation yet though.) It's not fully instant because there's still a delay to load it from the cache etc — we'll have more control over it after upgrading Expo.

This PR achieves that in several steps:

  1. We need to plumb down the thumbnail URL — this one is easy.
  2. This couldn't work before because we waited for onLoad event and forcibly displayed the spinner until then. The problem is that onLoad doesn't fire for placeholder images. So we couldn't use the placeholder prop before. To solve that, I'm changing the layout to place the spinner beneath the image. Then it can be rendered unconditionally.
  • I've had to resolve a minor layout hiccup on Android which was compositing opacity during dismiss incorrectly.
  1. While the image is loading, its dimensions aren't available. There's no quick way to get placeholder dimensions either so instead we just rely on the gestures (like zoom and pinch) being disabled until dimensions load.
  • The logic to ignore missing dimensions was already present. However, I've noticed that with internet being offline, the dimensions were incorrectly reported as 0x0 which caused double-tap gesture to send NaNs to zoomToRect, causing a crash on iOS. I've made a driveby fix to treat 0x0 as missing dimensions and to avoid calculations based on those.

Before

You always have to wait for the full image to load first. If there is no WiFi, you don't see anything at all on opening lightbox.

nowifi_before.mov

After

Images will appear instantly (and progressively enhance as full size loads) thanks to the preview being cached via feed.

If you have no WiFi, you still see the lower quality image (almost) instantly:

no_wifi.mov

However, you won't be able to interact with it (aside from dismissing) until the internet comes back online.

Test Plan

Try with WiFi off and on.

Substitute thumbUri with some fake URI to verify the image does get swapped.

Verify that the spinner still works (e.g. by setting thumbUri to a completely unrelated URL that isn't cached and turning off WiFi). Verify you can dismiss the image before even the placeholder has loaded.

Verify that while dismissing the image, the spinner beneath it is not visible.

accessibilityLabel={imageSrc.alt}
accessibilityHint=""
onLoad={() => setIsLoaded(true)}
accessibilityIgnoresInvertColors
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

was told to add this by the linter

@@ -31,7 +31,9 @@ export function Lightbox() {
const opts = activeLightbox
return (
<ImageView
images={[{uri: opts.profile.avatar || ''}]}
images={[
{uri: opts.profile.avatar || '', thumbUri: opts.profile.avatar || ''},
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

could pass the low res one but it's maybe too low res? can change tho

@@ -72,7 +72,7 @@ export function ProfileSubpageHeader({
) {
openLightbox({
type: 'images',
images: [{uri: avatar}],
images: [{uri: avatar, thumbUri: avatar}],
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

same

Copy link

github-actions bot commented Oct 29, 2024

Old size New size Diff
7.92 MB 7.92 MB 0 B (0.00%)

Comment on lines +139 to +141
<Animated.View style={[styles.imageScrollContainer, animatedStyle]}>
<ActivityIndicator size="small" color="#FFF" style={styles.loading} />
<Image
Copy link
Contributor

Choose a reason for hiding this comment

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

Nice. This is actually the "right" way to do this as of right now (using an Animated.View around the Image, as there's a bug when animating the image directly. Didn't realize we were doing this the whole time...would be curious to profile before/after and see if it was indeed reloading when doing some of the resize operations (probably was eating CPU)

enableLiveTextInteraction={showControls && !scaled}
/>
<Animated.View style={[styles.imageScrollContainer, animatedStyle]}>
<ActivityIndicator size="small" color="#FFF" style={styles.loading} />
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we want to use Loader instead to keep consistency with what we do elsewhere? No strong opinion, whatever you think looks nicer in this context.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

would rather not touch actual UI for now to stay safe, but can do later

Base automatically changed from images-lightbox-1 to main October 29, 2024 20:58
@arcalinea arcalinea temporarily deployed to images-lightbox-2 - social-app PR #6000 October 29, 2024 20:59 — with Render Destroyed
@gaearon gaearon merged commit ab492cd into main Oct 29, 2024
6 checks passed
@gaearon gaearon deleted the images-lightbox-2 branch October 29, 2024 21:00
estrattonbailey added a commit that referenced this pull request Oct 31, 2024
* origin/main: (213 commits)
  add Thai Language translation support (#5879)
  fix warning on labeler profile: emoji detected but emoji not enabled (#6011)
  Added blur to search's onPressMenu (#6017)
  React compiler beta and reenable rule (#5898)
  Sort imports (#6009)
  Clarify build instructions (#6008)
  Upgrade all tiptap deps to latest (#5232)
  width full on text container (#6007)
  Bump 1.94.0 (#6006)
  Add subtle web hover to interactive rows (#5989)
  Settings revamp (#5745)
  Show almost-instant preview when opening lightbox (#6000)
  Refactor lightbox model to plain object (#5999)
  temp revert to old modal (#6005)
  Extend composer checks to all posts in a thread (#5955)
  Remove indirection when rendering composer state (#5954)
  Refactor composer state for threads (#5945)
  Disable Post button when empty (#5953)
  fix splash screen (#5997)
  Fix video quality for short videos (#5996)
  ...
rshigg pushed a commit to rshigg/social-app that referenced this pull request Nov 2, 2024
* Plumb thumbUri down to the lightbox

* Remove onLoad tracking from lightbox

* Hook up placeholder URI to the image

* Fix NaN causing crash on double tap while offline

* Protect against NaNs in the future
rshigg pushed a commit to rshigg/social-app that referenced this pull request Nov 2, 2024
* Plumb thumbUri down to the lightbox

* Remove onLoad tracking from lightbox

* Hook up placeholder URI to the image

* Fix NaN causing crash on double tap while offline

* Protect against NaNs in the future
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants