import { StyleConstants } from '@utils/styles/constants' import { useTheme } from '@utils/styles/ThemeManager' import React, { useCallback, useMemo, useRef, useState } from 'react' import { Image, ImageStyle, Pressable, StyleProp, StyleSheet, ViewStyle } from 'react-native' import { Blurhash } from 'react-native-blurhash' // blurhas -> if blurhash, show before any loading succeed // original -> load original // original, remote -> if original failed, then remote // preview, original -> first show preview, then original // preview, original, remote -> first show preview, then original, if original failed, then remote export interface Props { hidden?: boolean uri: { preview?: string; original?: string; remote?: string } blurhash?: string dimension?: { width: number; height: number } onPress?: () => void style?: StyleProp imageStyle?: StyleProp // For image viewer when there is no image size available setImageDimensions?: React.Dispatch< React.SetStateAction<{ width: number height: number }> > } const GracefullyImage = React.memo( ({ hidden = false, uri, blurhash, dimension, onPress, style, imageStyle, setImageDimensions }: Props) => { const { theme } = useTheme() const originalFailed = useRef(false) const [imageLoaded, setImageLoaded] = useState(false) const source = useMemo(() => { if (originalFailed.current) { return { uri: uri.remote || undefined } } else { return { uri: uri.original } } }, [originalFailed.current]) const onLoad = useCallback( ({ nativeEvent }) => { setImageLoaded(true) setImageDimensions && setImageDimensions({ width: nativeEvent.width, height: nativeEvent.height }) }, [source.uri] ) const onError = useCallback(() => { if (!originalFailed.current) { originalFailed.current = true } }, [originalFailed.current]) const previewView = useMemo( () => uri.preview && !imageLoaded ? ( ) : null, [imageLoaded] ) const originalView = useMemo( () => ( ), [source] ) const blurhashView = useMemo(() => { return blurhash && (hidden || !imageLoaded) ? ( ) : null }, [hidden, imageLoaded]) return ( ) }, (prev, next) => prev.hidden === next.hidden && prev.uri.preview === next.uri.preview && prev.uri.original === next.uri.original && prev.uri.remote === next.uri.remote ) const styles = StyleSheet.create({ blurhash: { width: '100%', height: '100%', position: 'absolute', top: StyleConstants.Spacing.XS / 2, left: StyleConstants.Spacing.XS / 2 } }) export default GracefullyImage