UNPKG

@cometchat/chat-uikit-react-native

Version:

Ready-to-use Chat UI Components for React Native

95 lines 3.8 kB
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