about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/state/lightbox.tsx1
-rw-r--r--src/view/com/lightbox/ImageViewing/@types/index.ts2
-rw-r--r--src/view/com/lightbox/ImageViewing/components/ImageItem/ImageItem.android.tsx21
-rw-r--r--src/view/com/lightbox/ImageViewing/components/ImageItem/ImageItem.ios.tsx48
-rw-r--r--src/view/com/lightbox/ImageViewing/components/ImageItem/ImageLoading.tsx37
-rw-r--r--src/view/com/lightbox/ImageViewing/hooks/useImageDimensions.ts18
-rw-r--r--src/view/com/lightbox/Lightbox.tsx4
-rw-r--r--src/view/com/profile/ProfileSubpageHeader.tsx2
-rw-r--r--src/view/com/util/post-embeds/index.tsx1
9 files changed, 56 insertions, 78 deletions
diff --git a/src/state/lightbox.tsx b/src/state/lightbox.tsx
index a97164327..0760d2c96 100644
--- a/src/state/lightbox.tsx
+++ b/src/state/lightbox.tsx
@@ -10,6 +10,7 @@ type ProfileImageLightbox = {
 
 type ImagesLightboxItem = {
   uri: string
+  thumbUri: string
   alt?: string
 }
 
diff --git a/src/view/com/lightbox/ImageViewing/@types/index.ts b/src/view/com/lightbox/ImageViewing/@types/index.ts
index 8400e12e4..8fdc3f364 100644
--- a/src/view/com/lightbox/ImageViewing/@types/index.ts
+++ b/src/view/com/lightbox/ImageViewing/@types/index.ts
@@ -16,4 +16,4 @@ export type Position = {
   y: number
 }
 
-export type ImageSource = {uri: string; alt?: string}
+export type ImageSource = {uri: string; thumbUri: string; alt?: string}
diff --git a/src/view/com/lightbox/ImageViewing/components/ImageItem/ImageItem.android.tsx b/src/view/com/lightbox/ImageViewing/components/ImageItem/ImageItem.android.tsx
index 814e39fa9..d4ce0f735 100644
--- a/src/view/com/lightbox/ImageViewing/components/ImageItem/ImageItem.android.tsx
+++ b/src/view/com/lightbox/ImageViewing/components/ImageItem/ImageItem.android.tsx
@@ -34,7 +34,6 @@ const SCREEN = {
 const MIN_DOUBLE_TAP_SCALE = 2
 const MAX_ORIGINAL_IMAGE_ZOOM = 2
 
-const AnimatedImage = Animated.createAnimatedComponent(Image)
 const initialTransform = createTransform()
 
 type Props = {
@@ -53,7 +52,6 @@ const ImageItem = ({
   isScrollViewBeingDragged,
 }: Props) => {
   const [isScaled, setIsScaled] = useState(false)
-  const [isLoaded, setIsLoaded] = useState(false)
   const imageDimensions = useImageDimensions(imageSrc)
   const committedTransform = useSharedValue(initialTransform)
   const panTranslation = useSharedValue({x: 0, y: 0})
@@ -313,20 +311,23 @@ const ImageItem = ({
         singleTap,
       )
 
-  const isLoading = !isLoaded || !imageDimensions
   return (
-    <Animated.View ref={containerRef} style={styles.container}>
-      {isLoading && (
-        <ActivityIndicator size="small" color="#FFF" style={styles.loading} />
-      )}
+    <Animated.View
+      ref={containerRef}
+      // Necessary to make opacity work for both children together.
+      renderToHardwareTextureAndroid
+      style={[styles.container, animatedStyle]}>
+      <ActivityIndicator size="small" color="#FFF" style={styles.loading} />
       <GestureDetector gesture={composedGesture}>
-        <AnimatedImage
+        <Image
           contentFit="contain"
           source={{uri: imageSrc.uri}}
-          style={[styles.image, animatedStyle]}
+          placeholderContentFit="contain"
+          placeholder={{uri: imageSrc.thumbUri}}
+          style={styles.image}
           accessibilityLabel={imageSrc.alt}
           accessibilityHint=""
-          onLoad={() => setIsLoaded(true)}
+          accessibilityIgnoresInvertColors
           cachePolicy="memory"
         />
       </GestureDetector>
diff --git a/src/view/com/lightbox/ImageViewing/components/ImageItem/ImageItem.ios.tsx b/src/view/com/lightbox/ImageViewing/components/ImageItem/ImageItem.ios.tsx
index 383490f4f..c81943948 100644
--- a/src/view/com/lightbox/ImageViewing/components/ImageItem/ImageItem.ios.tsx
+++ b/src/view/com/lightbox/ImageViewing/components/ImageItem/ImageItem.ios.tsx
@@ -7,9 +7,8 @@
  */
 
 import React, {useState} from 'react'
-
-import {Dimensions, StyleSheet} from 'react-native'
-import {Image} from 'expo-image'
+import {ActivityIndicator, Dimensions, StyleSheet} from 'react-native'
+import {Gesture, GestureDetector} from 'react-native-gesture-handler'
 import Animated, {
   interpolate,
   runOnJS,
@@ -17,14 +16,12 @@ import Animated, {
   useAnimatedStyle,
   useSharedValue,
 } from 'react-native-reanimated'
-import {useAnimatedScrollHandler} from '#/lib/hooks/useAnimatedScrollHandler_FIXED'
-import {Gesture, GestureDetector} from 'react-native-gesture-handler'
+import {Image} from 'expo-image'
 
+import {useAnimatedScrollHandler} from '#/lib/hooks/useAnimatedScrollHandler_FIXED'
+import {Dimensions as ImageDimensions, ImageSource} from '../../@types'
 import useImageDimensions from '../../hooks/useImageDimensions'
 
-import {ImageSource, Dimensions as ImageDimensions} from '../../@types'
-import {ImageLoading} from './ImageLoading'
-
 const SWIPE_CLOSE_OFFSET = 75
 const SWIPE_CLOSE_VELOCITY = 1
 const SCREEN = Dimensions.get('screen')
@@ -40,8 +37,6 @@ type Props = {
   showControls: boolean
 }
 
-const AnimatedImage = Animated.createAnimatedComponent(Image)
-
 const ImageItem = ({
   imageSrc,
   onTap,
@@ -51,7 +46,6 @@ const ImageItem = ({
 }: Props) => {
   const scrollViewRef = useAnimatedRef<Animated.ScrollView>()
   const translationY = useSharedValue(0)
-  const [loaded, setLoaded] = useState(false)
   const [scaled, setScaled] = useState(false)
   const imageDimensions = useImageDimensions(imageSrc)
   const maxZoomScale = imageDimensions
@@ -141,18 +135,21 @@ const ImageItem = ({
         showsHorizontalScrollIndicator={false}
         showsVerticalScrollIndicator={false}
         maximumZoomScale={maxZoomScale}
-        contentContainerStyle={styles.imageScrollContainer}
         onScroll={scrollHandler}>
-        {(!loaded || !imageDimensions) && <ImageLoading />}
-        <AnimatedImage
-          contentFit="contain"
-          source={{uri: imageSrc.uri}}
-          style={[styles.image, animatedStyle]}
-          accessibilityLabel={imageSrc.alt}
-          accessibilityHint=""
-          onLoad={() => setLoaded(true)}
-          enableLiveTextInteraction={showControls && !scaled}
-        />
+        <Animated.View style={[styles.imageScrollContainer, animatedStyle]}>
+          <ActivityIndicator size="small" color="#FFF" style={styles.loading} />
+          <Image
+            contentFit="contain"
+            source={{uri: imageSrc.uri}}
+            placeholderContentFit="contain"
+            placeholder={{uri: imageSrc.thumbUri}}
+            style={styles.image}
+            accessibilityLabel={imageSrc.alt}
+            accessibilityHint=""
+            enableLiveTextInteraction={showControls && !scaled}
+            accessibilityIgnoresInvertColors
+          />
+        </Animated.View>
       </Animated.ScrollView>
     </GestureDetector>
   )
@@ -170,6 +167,13 @@ const styles = StyleSheet.create({
     width: SCREEN.width,
     height: SCREEN.height,
   },
+  loading: {
+    position: 'absolute',
+    top: 0,
+    left: 0,
+    right: 0,
+    bottom: 0,
+  },
 })
 
 const getZoomRectAfterDoubleTap = (
diff --git a/src/view/com/lightbox/ImageViewing/components/ImageItem/ImageLoading.tsx b/src/view/com/lightbox/ImageViewing/components/ImageItem/ImageLoading.tsx
deleted file mode 100644
index 9667fcaa7..000000000
--- a/src/view/com/lightbox/ImageViewing/components/ImageItem/ImageLoading.tsx
+++ /dev/null
@@ -1,37 +0,0 @@
-/**
- * Copyright (c) JOB TODAY S.A. and its affiliates.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- */
-
-import React from 'react'
-
-import {ActivityIndicator, Dimensions, StyleSheet, View} from 'react-native'
-
-const SCREEN = Dimensions.get('screen')
-const SCREEN_WIDTH = SCREEN.width
-const SCREEN_HEIGHT = SCREEN.height
-
-export const ImageLoading = () => (
-  <View style={styles.loading}>
-    <ActivityIndicator size="small" color="#FFF" />
-  </View>
-)
-
-const styles = StyleSheet.create({
-  listItem: {
-    width: SCREEN_WIDTH,
-    height: SCREEN_HEIGHT,
-  },
-  loading: {
-    width: SCREEN_WIDTH,
-    height: SCREEN_HEIGHT,
-    alignItems: 'center',
-    justifyContent: 'center',
-  },
-  imageScrollContainer: {
-    height: SCREEN_HEIGHT,
-  },
-})
diff --git a/src/view/com/lightbox/ImageViewing/hooks/useImageDimensions.ts b/src/view/com/lightbox/ImageViewing/hooks/useImageDimensions.ts
index cb46fd0d9..8b5bc1b87 100644
--- a/src/view/com/lightbox/ImageViewing/hooks/useImageDimensions.ts
+++ b/src/view/com/lightbox/ImageViewing/hooks/useImageDimensions.ts
@@ -8,6 +8,7 @@
 
 import {useEffect, useState} from 'react'
 import {Image, ImageURISource} from 'react-native'
+
 import {Dimensions, ImageSource} from '../@types'
 
 const CACHE_SIZE = 50
@@ -36,8 +37,9 @@ const imageDimensionsCache = createCache(CACHE_SIZE)
 const useImageDimensions = (image: ImageSource): Dimensions | null => {
   const [dimensions, setDimensions] = useState<Dimensions | null>(null)
 
-  // eslint-disable-next-line @typescript-eslint/no-shadow
-  const getImageDimensions = (image: ImageSource): Promise<Dimensions> => {
+  const getImageDimensions = (
+    image: ImageSource,
+  ): Promise<Dimensions | null> => {
     return new Promise(resolve => {
       if (image.uri) {
         const source = image as ImageURISource
@@ -51,16 +53,20 @@ const useImageDimensions = (image: ImageSource): Dimensions | null => {
             source.uri,
             source.headers,
             (width: number, height: number) => {
-              imageDimensionsCache.set(cacheKey, {width, height})
-              resolve({width, height})
+              if (width > 0 && height > 0) {
+                imageDimensionsCache.set(cacheKey, {width, height})
+                resolve({width, height})
+              } else {
+                resolve(null)
+              }
             },
             () => {
-              resolve({width: 0, height: 0})
+              resolve(null)
             },
           )
         }
       } else {
-        resolve({width: 0, height: 0})
+        resolve(null)
       }
     })
   }
diff --git a/src/view/com/lightbox/Lightbox.tsx b/src/view/com/lightbox/Lightbox.tsx
index b6bc670c1..a7f8fed77 100644
--- a/src/view/com/lightbox/Lightbox.tsx
+++ b/src/view/com/lightbox/Lightbox.tsx
@@ -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 || ''},
+        ]}
         initialImageIndex={0}
         visible
         onRequestClose={onClose}
diff --git a/src/view/com/profile/ProfileSubpageHeader.tsx b/src/view/com/profile/ProfileSubpageHeader.tsx
index 6b267c6da..09f074e50 100644
--- a/src/view/com/profile/ProfileSubpageHeader.tsx
+++ b/src/view/com/profile/ProfileSubpageHeader.tsx
@@ -72,7 +72,7 @@ export function ProfileSubpageHeader({
     ) {
       openLightbox({
         type: 'images',
-        images: [{uri: avatar}],
+        images: [{uri: avatar, thumbUri: avatar}],
         index: 0,
       })
     }
diff --git a/src/view/com/util/post-embeds/index.tsx b/src/view/com/util/post-embeds/index.tsx
index 5100e7032..575b26694 100644
--- a/src/view/com/util/post-embeds/index.tsx
+++ b/src/view/com/util/post-embeds/index.tsx
@@ -134,6 +134,7 @@ export function PostEmbeds({
     if (images.length > 0) {
       const items = embed.images.map(img => ({
         uri: img.fullsize,
+        thumbUri: img.thumb,
         alt: img.alt,
         aspectRatio: img.aspectRatio,
       }))