import { StyleConstants } from '@utils/styles/constants' import { Surface } from 'gl-react-expo' import { Blurhash } from 'gl-react-blurhash' import React, { useCallback, useEffect, useState } from 'react' import { Image, Pressable, StyleProp, StyleSheet, View, ViewStyle } from 'react-native' import { Image as ImageCache } from 'react-native-expo-image-cache' import { useTheme } from '@utils/styles/ThemeManager' type CancelPromise = ((reason?: Error) => void) | undefined type ImageSize = { width: number; height: number } interface ImageSizeOperation { start: () => Promise cancel: CancelPromise } const getImageSize = (uri: string): ImageSizeOperation => { let cancel: CancelPromise const start = (): Promise => new Promise<{ width: number; height: number }>((resolve, reject) => { cancel = reject Image.getSize( uri, (width, height) => { cancel = undefined resolve({ width, height }) }, error => { reject(error) } ) }) return { start, cancel } } export interface Props { hidden?: boolean cache?: boolean uri: { preview?: string; original?: string; remote?: string } blurhash?: string dimension?: { width: number; height: number } onPress?: () => void style?: StyleProp } const GracefullyImage: React.FC = ({ hidden = false, cache = false, uri, blurhash, dimension, onPress, style }) => { const { mode, theme } = useTheme() const [imageVisible, setImageVisible] = useState() const [imageLoadingFailed, setImageLoadingFailed] = useState(false) useEffect(() => { let cancel: CancelPromise const sideEffect = async (): Promise => { try { if (uri.preview) { const tryPreview = getImageSize(uri.preview) cancel = tryPreview.cancel const res = await tryPreview.start() if (res) { setImageVisible(uri.preview) return } } } catch (error) { if (__DEV__) console.warn('Image preview', error) } try { const tryOriginal = getImageSize(uri.original!) cancel = tryOriginal.cancel const res = await tryOriginal.start() if (res) { setImageVisible(uri.original!) return } } catch (error) { if (__DEV__) console.warn('Image original', error) } try { if (uri.remote) { const tryRemote = getImageSize(uri.remote) cancel = tryRemote.cancel const res = await tryRemote.start() if (res) { setImageVisible(uri.remote) return } } } catch (error) { if (__DEV__) console.warn('Image remote', error) } setImageLoadingFailed(true) } if (uri.original) { sideEffect() } return () => { if (cancel) { cancel() } } }, [uri]) const children = useCallback(() => { if (imageVisible && !hidden) { if (cache) { return } else { return } } else if (blurhash) { return ( ) } else { return ( ) } }, [hidden, mode, imageVisible]) return (