UNPKG

@cometchat/chat-uikit-react-native

Version:

Ready-to-use Chat UI Components for React Native

185 lines 6.83 kB
import React, { useEffect, useMemo, useRef } from "react"; import { ActivityIndicator, NativeEventEmitter, NativeModules, Platform, Text, View, } from "react-native"; import { Icon } from "../../icons/Icon"; import { useTheme } from "../../../theme"; import { getFileTypeIcon } from "../../constants/UIKitConstants"; const { FileManager } = NativeModules; const eventEmitter = new NativeEventEmitter(FileManager); /** * CometChatFileBubble is a component that displays a file bubble with title, * subtitle and an icon indicating the file type. It handles file download, * existence check and opening of the file. * * Props for the component. * The rendered file bubble. */ export const CometChatFileBubble = ({ fileUrl, title, titleStyle, subtitleStyle, subtitle, downloadIcon, downloadIconStyle, }) => { const [processing, setProcessing] = React.useState(false); const [fileExists, setFileExists] = React.useState(false); // State to track if the file exists const theme = useTheme(); let listener; // Android-specific download identifier const downloadIdRef = useRef(0); // Flag to indicate if file should be opened after downloading const openFileAfterDownloading = useRef(false); useEffect(() => { checkFileExists(); if (Platform.OS == "android") { listener = eventEmitter.addListener("downloadComplete", (data) => { if (data.downloadId && downloadIdRef.current && data.downloadId == downloadIdRef.current) { setProcessing(false); setFileExists(true); if (openFileAfterDownloading.current) { openFile(); openFileAfterDownloading.current = false; } } }); } return () => { if (Platform.OS == "android") { listener.remove(); } }; }, [fileUrl]); /** * Checks if the file exists locally. * * If true, download and open the file if it doesn't exist. */ const checkFileExists = async (downloadAndOpenFile = false) => { if (!fileUrl) return; const fileName = getFileName(); setProcessing(true); FileManager.doesFileExist(fileName, (result) => { setProcessing(false); if (JSON.parse(result).exists) { setFileExists(true); if (downloadAndOpenFile) { openFile(); openFileAfterDownloading.current = false; } } else { if (downloadAndOpenFile) { openFileAfterDownloading.current = true; downloadFile(); } } }); }; /** * Initiates the file download if it is not already processed or exists. */ const downloadFile = () => { if (processing || fileExists) return; // Do not process if file already exists if (!fileUrl) return; setProcessing(true); FileManager.checkAndDownload(fileUrl, getFileName(), (result) => { if (Platform.OS == "ios") { let parsedResult = JSON.parse(result); if (parsedResult.success == true) { setProcessing(false); setFileExists(true); } if (openFileAfterDownloading.current) { openFile(); openFileAfterDownloading.current = false; } } else if (Platform.OS == "android") { downloadIdRef.current = JSON.parse(result).downloadId; } }); }; /** * Opens the file using the FileManager. */ const openFile = () => { if (processing) return; if (!fileUrl) return; setProcessing(true); FileManager.openFile(fileUrl, getFileName(), (isOpened) => { setProcessing(false); }); }; /** * Extracts the file name from the file URL. * * The file name. */ const getFileName = () => { return fileUrl.substring(fileUrl.lastIndexOf("/") + 1).replace(" ", "_"); }; // Touch handling for iOS const wrapperPressTime = useRef(0); const viewProps = useMemo(() => { return Platform.OS === "ios" ? { onTouchStart: () => { wrapperPressTime.current = Date.now(); }, onTouchMove: () => { wrapperPressTime.current = null; }, onTouchEnd: () => { if (wrapperPressTime.current === null) return; const endTime = Date.now(); const pressDuration = endTime - wrapperPressTime.current; if (pressDuration < 500) { checkFileExists(true); } }, } : {}; }, []); // Touch handling for Android const pressTimeOnAndroid = useRef(0); const viewPropsForAndroid = useMemo(() => { return Platform.OS === "android" ? { onTouchStart: () => { pressTimeOnAndroid.current = Date.now(); }, onTouchEnd: () => { const endTime = Date.now(); const pressDuration = endTime - pressTimeOnAndroid.current; if (pressDuration < 500) { checkFileExists(true); } }, } : {}; }, []); /** * Handler to download the file when the download icon is pressed. * * @param {NativeSyntheticEvent<NativeTouchEvent>} e - The touch event. */ const shouldDownload = (e) => { e.stopPropagation(); setProcessing(true); downloadFile(); }; return (<View {...viewProps} style={{ flexDirection: "row", gap: 8 }}> <View {...viewPropsForAndroid} style={{ height: 32, width: 32 }}> <Icon name={getFileTypeIcon(title)} size={32}></Icon> </View> <View {...viewPropsForAndroid} style={{ flexDirection: "column", flexGrow: 1, flexShrink: 1 }}> {title && (<Text numberOfLines={1} ellipsizeMode={"tail"} style={[titleStyle]}> {title} </Text>)} {subtitle && (<Text numberOfLines={1} ellipsizeMode={"tail"} style={subtitleStyle}> {subtitle} </Text>)} </View> {processing && !fileExists && (<ActivityIndicator color={downloadIconStyle?.tintColor}/>)} </View>); }; //# sourceMappingURL=CometChatFileBubble.js.map