// @flow import * as _ from "lodash"; import * as React from "react"; import { Image as RNImage, Animated, StyleSheet, View, Platform, ImageStyle, ImageURISource, ImageSourcePropType, StyleProp } from "react-native"; import { BlurView } from "expo-blur"; import CacheManager, { DownloadOptions } from "./CacheManager"; interface ImageProps { style?: StyleProp; defaultSource?: ImageURISource | number; preview?: ImageSourcePropType; options?: DownloadOptions; uri: string; transitionDuration?: number; tint?: "dark" | "light"; onError: (error: { nativeEvent: { error: Error } }) => void; } interface ImageState { uri: string | undefined; intensity: Animated.Value; } export default class Image extends React.Component { mounted = true; static defaultProps = { transitionDuration: 300, tint: "dark", onError: () => {} }; state = { uri: undefined, intensity: new Animated.Value(100) }; componentDidMount() { this.load(this.props); } componentDidUpdate(prevProps: ImageProps, prevState: ImageState) { const { preview, transitionDuration, uri: newURI } = this.props; const { uri, intensity } = this.state; if (newURI !== prevProps.uri) { this.load(this.props); } else if (uri && preview && prevState.uri === undefined) { Animated.timing(intensity, { duration: transitionDuration, toValue: 0, useNativeDriver: Platform.OS === "android" }).start(); } } componentWillUnmount() { this.mounted = false; } async load({ uri, options = {}, onError }: ImageProps): Promise { if (uri) { try { const path = await CacheManager.get(uri, options).getPath(); if (this.mounted) { if (path) { this.setState({ uri: path }); } else { onError({ nativeEvent: { error: new Error("Could not load image") } }); } } } catch (error) { onError({ nativeEvent: { error } }); } } } render() { const { preview, style, defaultSource, tint, ...otherProps } = this.props; const { uri, intensity } = this.state; const isImageReady = !!uri; const opacity = intensity.interpolate({ inputRange: [0, 100], outputRange: [0, 0.5] }); const flattenedStyle = StyleSheet.flatten(style); const computedStyle: StyleProp = [ StyleSheet.absoluteFill, _.transform(_.pickBy(flattenedStyle, (_val, key) => propsToCopy.indexOf(key) !== -1), (result, value: any, key) => Object.assign(result, { [key]: value - (flattenedStyle.borderWidth || 0) }) ) ]; return ( {!!defaultSource && !isImageReady && } {!!preview && ( )} {isImageReady && } {!!preview && Platform.OS === "ios" && } {!!preview && Platform.OS === "android" && ( )} ); } } const black = "black"; const white = "white"; const propsToCopy = [ "borderRadius", "borderBottomLeftRadius", "borderBottomRightRadius", "borderTopLeftRadius", "borderTopRightRadius" ]; const AnimatedBlurView = Animated.createAnimatedComponent(BlurView);