import React, { useMemo, useCallback } from 'react'; import { View, Text, StyleSheet, FlatList, TouchableOpacity, ActivityIndicator, } from 'react-native'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { MaterialIcons } from '@expo/vector-icons'; import { fileStore, FileRecord } from '../services/fileStore'; import { safDirectory } from '../services/safDirectory'; import { useSyncQueue } from '../hooks/useSyncQueue'; import { useAutoSync } from '../hooks/useAutoSync'; import { useSyncPush } from '../hooks/useSyncPush'; function formatSize(bytes: number): string { if (bytes === 0) return ''; if (bytes < 1024) return `${bytes} o`; if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} Ko`; return `${(bytes / (1024 * 1024)).toFixed(1)} Mo`; } export function SyncDetailScreen() { const insets = useSafeAreaInsets(); const { pendingCount, isSyncing, refresh } = useSyncQueue(); const { triggerSync } = useAutoSync(); const { push } = useSyncPush(); const pendingFiles = useMemo(() => { return fileStore.getPendingSync(); }, []); const handleSyncAll = useCallback(async () => { await triggerSync(); try { const { getStoredDeviceServerId } = await import('../hooks/useDeviceRegistration'); const serverId = await getStoredDeviceServerId(); if (serverId) { await push(serverId); } } catch { // push notification is best-effort } refresh(); }, [triggerSync, push, refresh]); const renderItem = useCallback(({ item }: { item: FileRecord }) => ( {item.name} {formatSize(item.size)} {item.mimeType ? ` · ${item.mimeType.split('/').pop()}` : ''} ), []); return ( {pendingCount > 0 && ( {isSyncing ? ( ) : ( )} {isSyncing ? 'Synchronisation...' : `Synchroniser (${pendingCount})`} )} {pendingFiles.length === 0 ? ( Tout est synchronisé Aucun fichier en attente d'upload ) : ( item.id} renderItem={renderItem} contentContainerStyle={styles.list} ListHeaderComponent={ {pendingFiles.length} fichier{pendingFiles.length > 1 ? 's' : ''} en attente } /> )} ); } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#f5f5f5', }, syncBtn: { flexDirection: 'row', alignItems: 'center', justifyContent: 'center', backgroundColor: '#1976D2', marginHorizontal: 16, marginTop: 16, borderRadius: 10, paddingVertical: 14, gap: 10, }, syncBtnDisabled: { backgroundColor: '#90CAF9', }, syncBtnText: { fontSize: 16, color: '#fff', fontWeight: '600', }, list: { padding: 16, }, headerText: { fontSize: 14, color: '#666', marginBottom: 12, }, fileRow: { flexDirection: 'row', alignItems: 'center', backgroundColor: '#fff', borderRadius: 10, padding: 12, marginBottom: 8, gap: 12, }, fileInfo: { flex: 1, }, fileName: { fontSize: 15, color: '#333', fontWeight: '500', }, fileMeta: { fontSize: 12, color: '#999', marginTop: 2, }, localBadge: { width: 28, height: 28, borderRadius: 14, backgroundColor: '#f5f5f5', justifyContent: 'center', alignItems: 'center', }, empty: { flex: 1, justifyContent: 'center', alignItems: 'center', gap: 12, }, emptyTitle: { fontSize: 18, fontWeight: '600', color: '#333', }, emptySubtitle: { fontSize: 14, color: '#999', }, });