import React, { useState, useEffect, useCallback } from 'react'; import { StyleSheet, View, Text, ActivityIndicator, ScrollView, RefreshControl, } from 'react-native'; import { useFocusEffect } from '@react-navigation/native'; import { useTheme } from '../services/ThemeContext'; import DatabaseService from '../services/DatabaseService'; import GoogleAUTH from '../AUTH/GoogleAUTH'; import NASAUTH from '../AUTH/NASAUTH'; import TopBar from '../components/TopBar'; import PhotoGrid from '../components/PhotoGrid'; import MediaViewer from '../components/MediaViewer'; import { TouchableOpacity } from 'react-native'; const HomeScreen = ({ navigation, route }) => { const userId = route?.params?.userId; const { theme } = useTheme(); const [currentUser, setCurrentUser] = useState(null); const [linkedAccounts, setLinkedAccounts] = useState([]); const [allMedia, setAllMedia] = useState([]); const [filteredMedia, setFilteredMedia] = useState([]); const [selectedFilter, setSelectedFilter] = useState('all'); const [loading, setLoading] = useState(true); const [refreshing, setRefreshing] = useState(false); const [selectedMedia, setSelectedMedia] = useState(null); const [viewerVisible, setViewerVisible] = useState(false); useFocusEffect( useCallback(() => { if (userId) loadUserData(); }, [userId]) ); useEffect(() => { if (currentUser) loadAllMedia(); }, [currentUser]); useEffect(() => { filterMedia(); }, [selectedFilter, allMedia]); const loadUserData = async () => { try { const user = await DatabaseService.getUserById(userId); setCurrentUser(user); const accounts = await DatabaseService.getLinkedAccounts(userId); setLinkedAccounts(accounts); } catch (err) { console.error('Error loading user data:', err); } }; const loadAllMedia = async () => { if (!loading) setLoading(true); try { const mediaFromDb = await DatabaseService.getMediaByUser(userId); const newMedia = []; // Google Photos fetch const googleAccount = linkedAccounts.find((a) => a.service_type === 'GOOGLE_PHOTOS'); if (googleAccount) { try { const googleAuth = new GoogleAUTH(); googleAuth.accessToken = googleAccount.account_data?.accessToken; googleAuth.refreshToken = googleAccount.account_data?.refreshToken; googleAuth.expiresAt = Date.now() + 3600000; const photos = await googleAuth.getPhotos(50); if (photos?.mediaItems?.length) newMedia.push(...photos.mediaItems); } catch (err) { console.error('Google Photos fetch error:', err); } } // iCloud fetch (placeholder) const iosAccount = linkedAccounts.find((a) => a.service_type === 'ICLOUD_PHOTOS'); if (iosAccount) { try { console.log('iCloud: placeholder - would fetch photos here'); } catch (err) { console.error('iCloud fetch error:', err); } } // NAS fetch const nasAccount = linkedAccounts.find((a) => a.service_type === 'NAS'); if (nasAccount) { try { const nasAuth = new NASAUTH(); const nasData = nasAccount.account_data; await nasAuth.authenticate(nasData.host, nasData.port, nasData.username, nasData.password, nasData.photoFolder); const nasPhotos = await nasAuth.getPhotos(nasData.photoFolder); if (nasPhotos?.mediaItems) newMedia.push(...nasPhotos.mediaItems); await nasAuth.revokeAccess(); } catch (err) { console.error('NAS fetch error:', err); } } const combined = [...mediaFromDb, ...newMedia]; const unique = Array.from(new Map(combined.map((m) => [m.source_id || m.id || m.path, m])).values()); setAllMedia(unique); } catch (err) { console.error('Error loading media:', err); } finally { setLoading(false); setRefreshing(false); } }; const filterMedia = () => { let filtered = allMedia; if (selectedFilter !== 'all') { filtered = allMedia.filter((m) => m.source_service === selectedFilter); } filtered.sort((a, b) => new Date(b.created_date || 0) - new Date(a.created_date || 0)); setFilteredMedia(filtered); }; const getServiceIcon = (type) => ({ GOOGLE_PHOTOS: '📷', ICLOUD_PHOTOS: '🍎', NAS: '💾' }[type] || '📱'); const getServiceName = (type) => ({ GOOGLE_PHOTOS: 'Google Photos', ICLOUD_PHOTOS: 'iCloud', NAS: 'NAS' }[type] || type); if (loading && allMedia.length === 0) { return ( Loading photos... ); } const FilterChips = () => ( setSelectedFilter('all')} > All {linkedAccounts.map((acc) => ( setSelectedFilter(acc.service_type)} > {getServiceIcon(acc.service_type)} {getServiceName(acc.service_type)} ))} ); return ( navigation.navigate('Search')} onProfilePress={() => navigation.navigate('Settings', { userId })} onMenuPress={() => navigation.navigate('Settings', { userId })} /> {linkedAccounts.length > 0 && } {filteredMedia.length === 0 ? ( 📸 No Photos Yet Photos from your connected services will appear here { setRefreshing(true); loadAllMedia(); }} > Refresh ) : ( { setSelectedMedia(item); setViewerVisible(true); }} refreshControl={ { setRefreshing(true); loadAllMedia(); }} /> } /> )} setViewerVisible(false)} /> ); }; const styles = StyleSheet.create({ container: { flex: 1 }, centerContainer: { flex: 1, justifyContent: 'center', alignItems: 'center', paddingHorizontal: 24 }, loadingText: { marginTop: 12, fontSize: 14 }, // Filter chips filterRow: { paddingHorizontal: 12, paddingVertical: 8, gap: 8 }, chip: { flexDirection: 'row', alignItems: 'center', paddingHorizontal: 14, paddingVertical: 7, borderRadius: 20, gap: 6, }, chipIcon: { fontSize: 13 }, chipText: { fontSize: 13, fontWeight: '500', color: '#3c4043' }, // Empty emptyTitle: { fontSize: 18, fontWeight: '600', marginBottom: 6 }, emptyText: { fontSize: 13, textAlign: 'center', marginBottom: 20 }, retryButton: { paddingHorizontal: 24, paddingVertical: 10, borderRadius: 20 }, retryButtonText: { color: '#fff', fontSize: 14, fontWeight: '600' }, }); export default HomeScreen;