@cometchat/chat-uikit-react-native
Version:
Ready-to-use Chat UI Components for React Native
95 lines • 3.8 kB
JavaScript
import React, { useEffect, useRef, useState } from "react";
import { ActivityIndicator, Image, View, StyleSheet, Platform, } from "react-native";
import { ImageViewerModal } from "../CometChatImageViewerModal";
import { CommonUtils } from "../../utils/CommonUtils";
/**
* CometChatImageLoader is a component that displays an image with an activity indicator
* until the image is loaded. It supports thumbnail prefetching and opens an image viewer
* modal on a quick tap.
*
* Props for the component.
* The rendered image loader component.
*/
export const CometChatImageLoader = (props) => {
const { thumbnailUrl, imageUrl, style, imageResizeMode, activityIndicatorSize, activityIndicatorViewStyle, } = props;
const [isLoaded, setIsLoaded] = useState(false);
const [isVisible, setIsVisible] = useState(false);
const [imageSource, setImageSource] = useState();
// Ref to record touch press time for detecting quick taps
const pressTime = useRef(0);
/**
* Handles the touch start event.
*/
const handleTouchStart = () => {
pressTime.current = Date.now();
};
/**
* Handles the touch end event and opens the image viewer if tap duration is short.
*/
const handleTouchEnd = () => {
if (pressTime.current === null && Platform.OS === "ios")
return;
const endTime = Date.now();
const pressDuration = endTime - pressTime.current;
if (pressDuration < 500) {
setIsVisible(true);
}
};
/**
* Handles the touch move event. On iOS, cancels the tap detection.
*/
const onTouchMove = () => {
if (Platform.OS === "ios") {
pressTime.current = null;
}
};
useEffect(() => {
// Prefetch the thumbnail if available, else fallback to the full image
if (thumbnailUrl && typeof thumbnailUrl === "object" && "uri" in thumbnailUrl) {
CommonUtils.prefetchThumbnail(thumbnailUrl.uri).then((success) => {
if (success) {
setImageSource(thumbnailUrl);
}
else {
setImageSource(imageUrl); // Fallback to original imageUrl if prefetch fails
}
});
}
else {
setImageSource(imageUrl); // No thumbnail available, fallback to imageUrl
}
}, [thumbnailUrl, imageUrl]);
return (<>
{isVisible && (<ImageViewerModal imageUrl={imageUrl} isVisible={isVisible} onClose={() => {
setIsVisible(false);
}}/>)}
<View onTouchStart={handleTouchStart} onTouchEnd={handleTouchEnd} onTouchMove={onTouchMove} style={{
position: "relative",
justifyContent: "center",
alignItems: "center",
height: style?.height,
width: style?.width,
}}>
{/* Render the image. It is initially hidden until loaded. */}
<Image resizeMode={imageResizeMode || "cover"} source={imageSource} style={[styles.image, style]} onLoad={() => setIsLoaded(true)}/>
{/* Render the activity indicator until the image is loaded */}
{!isLoaded && (<ActivityIndicator size={activityIndicatorSize || "large"} style={[styles.loader, activityIndicatorViewStyle]}/>)}
</View>
</>);
};
// Default styles for the component
const styles = StyleSheet.create({
container: {
position: "relative",
justifyContent: "center",
alignItems: "center",
},
loader: {
position: "absolute",
zIndex: 1, // Ensure it is rendered above the image until the image loads
},
image: {
position: "absolute", // The image remains fixed in place while loading
},
});
//# sourceMappingURL=CometChatImageLoader.js.map