Files
Media-Aggregation-and-Sorti…/src/screens/SearchScreen.js
T

121 lines
4.3 KiB
JavaScript

import React, { useState, useEffect } from 'react';
import {
StyleSheet, View, Text, TextInput, TouchableOpacity, ActivityIndicator,
} from 'react-native';
import { useTheme } from '../services/ThemeContext';
import DatabaseService from '../services/DatabaseService';
import PhotoGrid from '../components/PhotoGrid';
import MediaViewer from '../components/MediaViewer';
import SearchIcon from '../../assets/icons/search.svg';
const SearchScreen = ({ route }) => {
const userId = route?.params?.userId;
const { theme } = useTheme();
const [query, setQuery] = useState('');
const [results, setResults] = useState([]);
const [searching, setSearching] = useState(false);
const [selectedMedia, setSelectedMedia] = useState(null);
const [viewerVisible, setViewerVisible] = useState(false);
useEffect(() => {
const timer = setTimeout(() => {
if (query.trim().length > 0) performSearch();
else setResults([]);
}, 300);
return () => clearTimeout(timer);
}, [query]);
const performSearch = async () => {
if (!userId) return;
setSearching(true);
try {
const media = await DatabaseService.searchMedia(userId, query.trim());
setResults(media);
} catch (err) {
console.error('Search error:', err);
} finally {
setSearching(false);
}
};
return (
<View style={[styles.container, { backgroundColor: theme.background }]}>
<View style={[styles.searchBar, { backgroundColor: theme.searchBg }]}>
<SearchIcon width={16} height={16} color={theme.textSecondary} />
<TextInput
style={[styles.searchInput, { color: theme.text }]}
placeholder="Search photos and videos"
placeholderTextColor={theme.textTertiary}
value={query}
onChangeText={setQuery}
autoFocus
autoCapitalize="none"
autoCorrect={false}
/>
{query.length > 0 && (
<TouchableOpacity onPress={() => setQuery('')}>
<Text style={[styles.clearButton, { color: theme.textSecondary }]}>✕</Text>
</TouchableOpacity>
)}
</View>
{searching && (
<View style={styles.loadingContainer}>
<ActivityIndicator size="small" color={theme.primary} />
</View>
)}
{!searching && query.length > 0 && results.length === 0 && (
<View style={styles.emptyContainer}>
<SearchIcon width={48} height={48} color={theme.textTertiary} />
<Text style={[styles.emptyTitle, { color: theme.text }]}>No results</Text>
<Text style={[styles.emptyText, { color: theme.textSecondary }]}>Try different keywords</Text>
</View>
)}
{query.length === 0 && (
<View style={styles.emptyContainer}>
<SearchIcon width={48} height={48} color={theme.textTertiary} />
<Text style={[styles.emptyTitle, { color: theme.text }]}>Search your photos</Text>
<Text style={[styles.emptyText, { color: theme.textSecondary }]}>
Search by filename and indexed metadata
</Text>
</View>
)}
{results.length > 0 && (
<>
<Text style={[styles.resultCount, { color: theme.textSecondary }]}>
{results.length} result{results.length !== 1 ? 's' : ''}
</Text>
<PhotoGrid
data={results}
onItemPress={(item) => { setSelectedMedia(item); setViewerVisible(true); }}
/>
</>
)}
<MediaViewer visible={viewerVisible} media={selectedMedia} allMedia={results} onClose={() => setViewerVisible(false)} />
</View>
);
};
const styles = StyleSheet.create({
container: { flex: 1 },
searchBar: {
flexDirection: 'row', alignItems: 'center', marginHorizontal: 12,
marginTop: 48, marginBottom: 8, borderRadius: 24,
paddingHorizontal: 14, paddingVertical: 10, gap: 8,
},
searchInput: { flex: 1, fontSize: 15, padding: 0 },
clearButton: { fontSize: 16, padding: 4 },
loadingContainer: { padding: 20, alignItems: 'center' },
emptyContainer: { flex: 1, justifyContent: 'center', alignItems: 'center', paddingHorizontal: 24 },
emptyTitle: { fontSize: 18, fontWeight: '600', marginBottom: 6 },
emptyText: { fontSize: 13, textAlign: 'center' },
resultCount: { paddingHorizontal: 16, paddingVertical: 8, fontSize: 13 },
});
export default SearchScreen;