import React, { ReactNode, useEffect, useRef } from "react";
import FastImage, { OnLoadEvent } from "react-native-fast-image";
import { interpolate, useAnimatedStyle } from "react-native-reanimated";
import SkeletonContent from "react-native-skeleton-content-nonexpo";
import { useColors, useReanimatedValue } from "../commons";
import { Spinner, Svg, View } from "../components";
import { StyledProps } from "./Styled";
export type ImageProps = StyledProps & {
uri?: string;
require?: number;
onLoaded?: (w: number, h: number) => void;
renderError?: () => ReactNode;
renderLoading?: () => ReactNode;
cover?: boolean;
isLoading?: boolean;
background?: boolean;
color?: string;
};
const SVG_IMAGE_DEFAULT = `
`;
export const Image = (props: ImageProps) => {
const {
uri,
require,
onLoaded,
renderError,
renderLoading,
cover,
isLoading,
background,
color,
size,
width,
height,
} = props;
const sourceImage = uri ? { uri } : require;
const colors = useColors();
const statusRef = useRef(uri ? 1 : 0);
const statusValue = useReanimatedValue(uri ? 1 : 0); // 0: normal, 1: loading, 2: error
const setLoadingValue = (value: number) => {
if (statusRef.current !== value) {
statusRef.current = value;
statusValue.value = value;
}
};
const onLoadStart = () => {
if (uri) setLoadingValue(1);
};
const onLoad = (e: OnLoadEvent) => {
onLoaded?.(e.nativeEvent.width, e.nativeEvent.height);
};
const onLoadEnd = () => {
if (statusRef.current === 1) setLoadingValue(0);
};
const onError = () => {
if (statusRef.current === 1) setLoadingValue(2);
};
const renderDefault = () => {
if (renderError) return renderError();
const d = size || height || width;
const r = typeof d === "number" ? d / 4 : 20;
return (
);
};
const renderSkeleton = () => {
if (renderLoading) return renderLoading();
if (!cover && !background) return ;
return (
);
};
const errorStyle = useAnimatedStyle(
() => ({
opacity: interpolate(statusValue.value, [0, 1, 2], [0, 0, 1]),
}),
[]
);
const loadingStyle = useAnimatedStyle(
() => ({
opacity: interpolate(statusValue.value, [0, 1, 2], [0, 1, 0]),
}),
[]
);
useEffect(() => {
onLoadStart();
}, [uri]);
return (
{!!sourceImage && (
<>
{/* error */}
{renderDefault()}
{/* loading */}
{renderSkeleton()}
>
)}
{/* image */}
{!sourceImage ? (
isLoading ? (
renderSkeleton()
) : (
renderDefault()
)
) : (
)}
);
};