@cometchat/chat-uikit-react-native
Version:
Ready-to-use Chat UI Components for React Native
185 lines • 6.83 kB
JavaScript
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