import React, { useRef, useState, useEffect } from 'react'; import { View, Text, StyleSheet, FlatList, Image, Dimensions, ActivityIndicator, ScrollView, } from 'react-native'; import { RouteProp, useRoute } from '@react-navigation/native'; import Pdf from 'react-native-pdf'; import { downloadAsync, documentDirectory, getInfoAsync } from 'expo-file-system/legacy'; import { useFile, useFileImage } from '../hooks/useFiles'; import { apiClient } from '../api/client'; import { TagChip } from '../components/TagChip'; import { FileThumbnail } from '../components/FileThumbnail'; const SCREEN_WIDTH = Dimensions.get('window').width; type RootStackParamList = { FileDetail: { fileIds: string[]; initialIndex: number }; }; type FileDetailRouteProp = RouteProp; function DetailItem({ fileId }: { fileId: string }) { const { data: imageData, isLoading: imageLoading } = useFileImage(fileId); const { data: fileData } = useFile(fileId); const uri = imageData?.data?.url; const file = fileData as any; const isPdf = file?.data?.mimeType === 'application/pdf'; const [localPdfUri, setLocalPdfUri] = useState(null); const [pdfLoading, setPdfLoading] = useState(false); useEffect(() => { if (!isPdf || !uri) return; let cancelled = false; async function downloadPdf() { if (!uri) return; setPdfLoading(true); const localUri = `${documentDirectory}pdf_${fileId}.pdf`; try { const info = await getInfoAsync(localUri); if (info.exists && info.size > 100) { if (!cancelled) setLocalPdfUri(localUri); return; } const headers: Record = {}; const token = apiClient.getAccessToken(); if (token) headers['Authorization'] = `Bearer ${token}`; await downloadAsync(uri, localUri, { headers }); if (!cancelled) setLocalPdfUri(localUri); } catch (e) { console.log('PDF download error:', e); } finally { if (!cancelled) setPdfLoading(false); } } downloadPdf(); return () => { cancelled = true; }; }, [isPdf, uri, fileId]); return ( {isPdf ? ( pdfLoading || !localPdfUri ? ( ) : ( { console.log(`PDF loaded: ${numberOfPages} pages`); }} onError={(error) => { console.log('PDF error:', error); }} /> ) ) : uri ? ( ) : file ? ( ) : ( )} {imageData?.data?.name ?? file?.name ?? fileId} {imageData?.data?.size != null && ( Taille : {(imageData.data.size / 1024).toFixed(1)} Ko )} {file?.createdAt && ( Ajouté le {new Date(file.createdAt).toLocaleDateString('fr-FR', { day: 'numeric', month: 'long', year: 'numeric', })} )} {file?.tags && file.tags.length > 0 && ( Tags {file.tags.map((tag: any) => ( ))} )} {file?.ocrText && ( Texte OCR {file.ocrText} )} ); } export function FileDetailScreen() { const route = useRoute(); const { fileIds, initialIndex } = route.params; const flatListRef = useRef(null); const [currentIndex, setCurrentIndex] = useState(initialIndex); return ( item} horizontal pagingEnabled showsHorizontalScrollIndicator={false} initialScrollIndex={initialIndex} getItemLayout={(_, index) => ({ length: SCREEN_WIDTH, offset: SCREEN_WIDTH * index, index, })} onMomentumScrollEnd={(e) => { const index = Math.round(e.nativeEvent.contentOffset.x / SCREEN_WIDTH); setCurrentIndex(index); }} renderItem={({ item }) => ( )} /> {currentIndex + 1} / {fileIds.length} ); } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#000', }, pageWrapper: { width: SCREEN_WIDTH, }, page: { flex: 1, }, pageContent: { flexGrow: 1, }, imageContainer: { flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: '#000', }, image: { width: SCREEN_WIDTH, height: SCREEN_WIDTH, }, pdf: { width: SCREEN_WIDTH, height: SCREEN_WIDTH, backgroundColor: '#fff', }, placeholder: { width: SCREEN_WIDTH, height: SCREEN_WIDTH, justifyContent: 'center', alignItems: 'center', backgroundColor: '#1a1a2e', }, placeholderText: { fontSize: 48, color: '#1976D2', fontWeight: '700', }, details: { backgroundColor: '#fff', borderTopLeftRadius: 16, borderTopRightRadius: 16, marginTop: -16, padding: 20, }, fileName: { fontSize: 18, fontWeight: '700', color: '#333', marginBottom: 8, }, meta: { fontSize: 14, color: '#666', marginBottom: 4, }, tagsRow: { flexDirection: 'row', flexWrap: 'wrap', gap: 6, marginTop: 8, }, tagsSection: { marginTop: 12, }, sectionLabel: { fontSize: 14, fontWeight: '600', color: '#333', marginBottom: 4, }, ocrSection: { marginTop: 16, }, ocrText: { fontSize: 14, color: '#555', lineHeight: 20, marginTop: 4, }, pagination: { position: 'absolute', bottom: 16, alignSelf: 'center', backgroundColor: 'rgba(0,0,0,0.5)', borderRadius: 12, paddingHorizontal: 12, paddingVertical: 4, }, paginationText: { color: '#fff', fontSize: 13, }, });