import React, { useCallback, useEffect, useState, useRef } from 'react'; import { View, Text, StyleSheet, TouchableOpacity, Switch, ScrollView, SafeAreaView, StatusBar, Platform, useColorScheme, ActivityIndicator, Alert, Animated } from 'react-native'; import { useSettings, settingsEmitter } from '../hooks/useSettings'; import { useNavigation, useFocusEffect } from '@react-navigation/native'; import { MaterialIcons } from '@expo/vector-icons'; import { colors } from '../styles/colors'; import { catalogService, StreamingAddon } from '../services/catalogService'; import { useCustomCatalogNames } from '../hooks/useCustomCatalogNames'; const ANDROID_STATUSBAR_HEIGHT = StatusBar.currentHeight || 0; interface CatalogItem { id: string; // Combined ID in format: addonId:type:catalogId name: string; addonName: string; type: string; } const HeroCatalogsScreen: React.FC = () => { const { settings, updateSetting } = useSettings(); const systemColorScheme = useColorScheme(); const isDarkMode = systemColorScheme === 'dark' || settings.enableDarkMode; const navigation = useNavigation(); const [loading, setLoading] = useState(true); const [catalogs, setCatalogs] = useState([]); const [selectedCatalogs, setSelectedCatalogs] = useState(settings.selectedHeroCatalogs || []); const { getCustomName, isLoadingCustomNames } = useCustomCatalogNames(); const [showSavedIndicator, setShowSavedIndicator] = useState(false); const fadeAnim = useRef(new Animated.Value(0)).current; // Ensure selected catalogs state is refreshed whenever the screen gains focus useFocusEffect( useCallback(() => { setSelectedCatalogs(settings.selectedHeroCatalogs || []); }, [settings.selectedHeroCatalogs]) ); // Subscribe to settings changes useEffect(() => { const unsubscribe = settingsEmitter.addListener(() => { // Refresh selected catalogs when settings change setSelectedCatalogs(settings.selectedHeroCatalogs || []); }); return unsubscribe; }, [settings.selectedHeroCatalogs]); // Fade in/out animation for the "Changes saved" indicator useEffect(() => { if (showSavedIndicator) { Animated.sequence([ Animated.timing(fadeAnim, { toValue: 1, duration: 300, useNativeDriver: true }), Animated.delay(1500), Animated.timing(fadeAnim, { toValue: 0, duration: 300, useNativeDriver: true }) ]).start(() => setShowSavedIndicator(false)); } }, [showSavedIndicator, fadeAnim]); const handleSave = useCallback(() => { // First update the settings updateSetting('selectedHeroCatalogs', selectedCatalogs); // Show the confirmation indicator setShowSavedIndicator(true); // Short delay before navigating back to allow settings to save // and the user to see the confirmation message setTimeout(() => { navigation.goBack(); }, 800); }, [navigation, selectedCatalogs, updateSetting]); const handleBack = useCallback(() => { navigation.goBack(); }, [navigation]); // Load all available catalogs useEffect(() => { const loadCatalogs = async () => { setLoading(true); try { const addons = await catalogService.getAllAddons(); const catalogItems: CatalogItem[] = []; addons.forEach(addon => { if (addon.catalogs && addon.catalogs.length > 0) { addon.catalogs.forEach(catalog => { catalogItems.push({ id: `${addon.id}:${catalog.type}:${catalog.id}`, name: catalog.name, addonName: addon.name, type: catalog.type, }); }); } }); setCatalogs(catalogItems); } catch (error) { console.error('Failed to load catalogs:', error); Alert.alert('Error', 'Failed to load catalogs'); } finally { setLoading(false); } }; loadCatalogs(); }, []); const handleSelectAll = useCallback(() => { setSelectedCatalogs(catalogs.map(catalog => catalog.id)); }, [catalogs]); const handleSelectNone = useCallback(() => { setSelectedCatalogs([]); }, []); const toggleCatalog = useCallback((catalogId: string) => { setSelectedCatalogs(prev => { if (prev.includes(catalogId)) { return prev.filter(id => id !== catalogId); } else { return [...prev, catalogId]; } }); }, []); // Group catalogs by addon const catalogsByAddon: Record = {}; catalogs.forEach(catalog => { if (!catalogsByAddon[catalog.addonName]) { catalogsByAddon[catalog.addonName] = []; } catalogsByAddon[catalog.addonName].push(catalog); }); return ( Hero Section Catalogs {/* Saved indicator */} Settings Saved {loading || isLoadingCustomNames ? ( Loading catalogs... ) : ( <> Select All Clear All Save Select which catalogs to display in the hero section. If none are selected, all catalogs will be used. Don't forget to press Save when you're done. {Object.entries(catalogsByAddon).map(([addonName, addonCatalogs]) => ( {addonName} {addonCatalogs.map(catalog => { const [addonId, type, catalogId] = catalog.id.split(':'); const displayName = getCustomName(addonId, type, catalogId, catalog.name); return ( toggleCatalog(catalog.id)} > {displayName} {catalog.type === 'movie' ? 'Movies' : 'TV Shows'} ); })} ))} )} ); }; const styles = StyleSheet.create({ container: { flex: 1, }, header: { flexDirection: 'row', alignItems: 'center', paddingHorizontal: 16, paddingVertical: 12, paddingTop: Platform.OS === 'android' ? ANDROID_STATUSBAR_HEIGHT + 12 : 8, }, backButton: { marginRight: 16, padding: 4, }, headerTitle: { fontSize: 22, fontWeight: '700', letterSpacing: 0.5, }, loadingContainer: { flex: 1, justifyContent: 'center', alignItems: 'center', }, loadingText: { marginTop: 16, fontSize: 16, }, scrollView: { flex: 1, }, scrollContent: { paddingBottom: 32, }, actionBar: { flexDirection: 'row', paddingHorizontal: 16, paddingVertical: 12, justifyContent: 'space-between', alignItems: 'center', }, actionButton: { paddingHorizontal: 12, paddingVertical: 8, borderRadius: 8, marginRight: 8, }, actionButtonText: { fontSize: 14, fontWeight: '600', }, saveButton: { paddingHorizontal: 16, paddingVertical: 8, borderRadius: 8, backgroundColor: colors.primary, flexDirection: 'row', alignItems: 'center', justifyContent: 'center', minWidth: 100, elevation: 2, shadowColor: '#000', shadowOffset: { width: 0, height: 1 }, shadowOpacity: 0.2, shadowRadius: 1.5, }, saveButtonText: { color: colors.white, fontSize: 14, fontWeight: '600', }, saveIcon: { marginRight: 6, }, infoCard: { marginHorizontal: 16, marginBottom: 16, padding: 12, borderRadius: 8, backgroundColor: 'rgba(0, 0, 0, 0.05)', }, infoText: { fontSize: 14, }, addonSection: { marginBottom: 16, }, addonName: { fontSize: 16, fontWeight: '700', marginHorizontal: 16, marginBottom: 8, }, catalogsContainer: { marginHorizontal: 16, borderRadius: 12, overflow: 'hidden', }, catalogItem: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', paddingVertical: 12, paddingHorizontal: 16, borderBottomWidth: 1, }, catalogInfo: { flex: 1, }, catalogName: { fontSize: 16, fontWeight: '500', }, catalogType: { fontSize: 14, marginTop: 2, }, savedIndicator: { position: 'absolute', top: Platform.OS === 'android' ? (StatusBar.currentHeight || 0) + 60 : 90, alignSelf: 'center', paddingHorizontal: 16, paddingVertical: 8, borderRadius: 24, flexDirection: 'row', alignItems: 'center', justifyContent: 'center', zIndex: 1000, elevation: 5, shadowColor: '#000', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.25, shadowRadius: 3.84, }, savedIndicatorText: { color: '#FFFFFF', marginLeft: 6, fontWeight: '600', }, }); export default HeroCatalogsScreen;