UNPKG

react-native-ajora

Version:

The most complete AI agent UI for React Native

190 lines (186 loc) 6.29 kB
import React from "react"; import { StyleSheet, View, Text, TouchableOpacity, Pressable, Alert, Linking, } from "react-native"; import { MaterialIcons } from "@expo/vector-icons"; import Color from "./Color"; const styles = StyleSheet.create({ container: { backgroundColor: Color.card, borderRadius: 12, borderWidth: 1, borderColor: Color.border, shadowColor: Color.shadow, shadowOffset: { width: 0, height: 2, }, shadowOpacity: 0.08, shadowRadius: 4, elevation: 2, maxWidth: 350, minWidth: 250, overflow: "hidden", }, fileCard: { flexDirection: "row", alignItems: "center", padding: 16, }, fileIcon: { marginRight: 16, color: Color.mutedForeground, }, fileInfo: { flex: 1, }, fileName: { fontSize: 16, fontWeight: "600", color: Color.foreground, marginBottom: 4, }, fileMeta: { fontSize: 14, color: Color.mutedForeground, }, actionButton: { width: 48, height: 48, borderRadius: 24, backgroundColor: Color.primary, justifyContent: "center", alignItems: "center", marginLeft: 12, shadowColor: Color.shadow, shadowOffset: { width: 0, height: 2, }, shadowOpacity: 0.1, shadowRadius: 4, elevation: 2, }, actionIcon: { color: Color.primaryForeground, }, }); export function MessageFile({ containerStyle, fileProps, currentMessage, onPress, onDownload, onOpen, }) { if (currentMessage == null) return null; const supportedFileMimeTypes = ["application/pdf"]; const filePart = currentMessage.parts?.find((part) => part.fileData?.mimeType && supportedFileMimeTypes.includes(part.fileData.mimeType)); const fileData = filePart?.fileData; // Helper function to get filename const getFileName = () => { if (fileData?.displayName) { return fileData.displayName; } if (fileData?.fileUri) { const pathParts = fileData.fileUri.split("/"); const fileName = pathParts[pathParts.length - 1]; const cleanFileName = fileName.split("?")[0]; return cleanFileName || "File"; } return "File"; }; // Helper function to get file extension const getFileExtension = () => { if (fileData?.mimeType) { const format = fileData.mimeType.split("/")[1]; return format?.toLowerCase() || ""; } const fileName = getFileName(); const lastDotIndex = fileName.lastIndexOf("."); if (lastDotIndex === -1) return ""; return fileName.substring(lastDotIndex + 1).toLowerCase(); }; // Helper function to determine file type const getFileType = (extension) => { const typeMap = { pdf: "document", }; return typeMap[extension] || "document"; }; // Helper function to get file icon const getFileIcon = (fileType) => { const iconMap = { document: "picture-as-pdf", }; return iconMap[fileType] || "picture-as-pdf"; }; // Helper function to format file size const formatFileSize = (bytes) => { if (!bytes || bytes === 0) return ""; const k = 1024; const sizes = ["B", "KB", "MB", "GB"]; const i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + " " + sizes[i]; }; const fileName = getFileName(); const fileExtension = getFileExtension(); const fileType = getFileType(fileExtension); const handleOpenFile = async () => { if (onOpen) { onOpen(); return; } if (fileData?.fileUri) { try { const canOpen = await Linking.canOpenURL(fileData.fileUri); if (canOpen) { await Linking.openURL(fileData.fileUri); } else { Alert.alert("Cannot open file", "No app is available to open this file type.", [{ text: "OK" }]); } } catch (error) { Alert.alert("Error", "Failed to open file. Please try again.", [ { text: "OK" }, ]); } } }; const handlePress = () => { if (onPress) { onPress(); } else { handleOpenFile(); } }; // If no file data is found, show a fallback message if (!fileData) { return (<Pressable style={[styles.container, containerStyle]} onPress={handlePress} {...fileProps}> <View style={styles.fileCard}> <MaterialIcons name="picture-as-pdf" size={24} style={styles.fileIcon}/> <View style={styles.fileInfo}> <Text style={styles.fileName}>PDF Document</Text> <Text style={styles.fileMeta}>No file data available</Text> </View> {onDownload && (<TouchableOpacity style={styles.actionButton} onPress={onDownload} activeOpacity={0.7}> <MaterialIcons name="download" size={20} style={styles.actionIcon}/> </TouchableOpacity>)} </View> </Pressable>); } return (<Pressable style={[styles.container, containerStyle]} onPress={handlePress} {...fileProps}> <View style={styles.fileCard}> <MaterialIcons name={getFileIcon(fileType)} size={24} style={styles.fileIcon}/> <View style={styles.fileInfo}> <Text style={styles.fileName} numberOfLines={1}> {fileName} </Text> <Text style={styles.fileMeta}> {fileExtension ? `${fileExtension.toUpperCase()} file` : "File"} </Text> </View> {onDownload && (<TouchableOpacity style={styles.actionButton} onPress={onDownload} activeOpacity={0.7}> <MaterialIcons name="download" size={20} style={styles.actionIcon}/> </TouchableOpacity>)} </View> </Pressable>); } //# sourceMappingURL=MessageFile.js.map