import React, { useEffect, useState, useCallback } from 'react'; import { View, Text, StyleSheet, ScrollView, Switch, ActivityIndicator, TouchableOpacity, } from 'react-native'; import AsyncStorage from '@react-native-async-storage/async-storage'; import { useNavigation } from '@react-navigation/native'; import { colors } from '../styles'; import { stremioService } from '../services/stremioService'; import MaterialIcons from 'react-native-vector-icons/MaterialIcons'; import { useCatalogContext } from '../contexts/CatalogContext'; import { logger } from '../utils/logger'; interface CatalogSetting { addonId: string; catalogId: string; type: string; name: string; enabled: boolean; } interface CatalogSettingsStorage { [key: string]: boolean | number; _lastUpdate: number; } const CATALOG_SETTINGS_KEY = 'catalog_settings'; const CatalogSettingsScreen = () => { const [loading, setLoading] = useState(true); const [settings, setSettings] = useState([]); const navigation = useNavigation(); const { refreshCatalogs } = useCatalogContext(); // Load saved settings and available catalogs const loadSettings = useCallback(async () => { try { setLoading(true); // Get installed addons and their catalogs const addons = await stremioService.getInstalledAddonsAsync(); const availableCatalogs: CatalogSetting[] = []; // Get saved settings const savedSettings = await AsyncStorage.getItem(CATALOG_SETTINGS_KEY); const savedCatalogs: { [key: string]: boolean } = savedSettings ? JSON.parse(savedSettings) : {}; // Process each addon's catalogs addons.forEach(addon => { if (addon.catalogs && addon.catalogs.length > 0) { // Create a map to store unique catalogs by their type and id const uniqueCatalogs = new Map(); addon.catalogs.forEach(catalog => { // Create a unique key that includes addon id, type, and catalog id const settingKey = `${addon.id}:${catalog.type}:${catalog.id}`; // Format catalog name let displayName = catalog.name; // Clean up the name and ensure type is included const contentType = catalog.type === 'movie' ? 'Movies' : 'TV Shows'; // Remove duplicate words (case-insensitive) const words = displayName.split(' '); const uniqueWords = []; const seenWords = new Set(); for (const word of words) { const lowerWord = word.toLowerCase(); if (!seenWords.has(lowerWord)) { uniqueWords.push(word); // Keep original case seenWords.add(lowerWord); } } displayName = uniqueWords.join(' '); // Add content type if not present (case-insensitive) if (!displayName.toLowerCase().includes(contentType.toLowerCase())) { displayName = `${displayName} ${contentType}`; } // Create unique catalog setting uniqueCatalogs.set(settingKey, { addonId: addon.id, catalogId: catalog.id, type: catalog.type, name: `${addon.name} - ${displayName}`, enabled: savedCatalogs[settingKey] ?? true // Enable by default }); }); // Add unique catalogs to the available catalogs array availableCatalogs.push(...uniqueCatalogs.values()); } }); // Sort catalogs by addon name and then by catalog name const sortedCatalogs = availableCatalogs.sort((a, b) => { const [addonNameA] = a.name.split(' - '); const [addonNameB] = b.name.split(' - '); if (addonNameA !== addonNameB) { return addonNameA.localeCompare(addonNameB); } return a.name.localeCompare(b.name); }); setSettings(sortedCatalogs); } catch (error) { logger.error('Failed to load catalog settings:', error); } finally { setLoading(false); } }, []); // Save settings when they change const saveSettings = async (newSettings: CatalogSetting[]) => { try { const settingsObj: CatalogSettingsStorage = { _lastUpdate: Date.now() }; newSettings.forEach(setting => { const key = `${setting.addonId}:${setting.type}:${setting.catalogId}`; settingsObj[key] = setting.enabled; }); await AsyncStorage.setItem(CATALOG_SETTINGS_KEY, JSON.stringify(settingsObj)); refreshCatalogs(); // Trigger catalog refresh after saving settings } catch (error) { logger.error('Failed to save catalog settings:', error); } }; // Toggle individual catalog const toggleCatalog = (setting: CatalogSetting) => { const newSettings = settings.map(s => { if (s.addonId === setting.addonId && s.type === setting.type && s.catalogId === setting.catalogId) { return { ...s, enabled: !s.enabled }; } return s; }); setSettings(newSettings); saveSettings(newSettings); }; useEffect(() => { loadSettings(); }, [loadSettings]); // Group settings by addon const groupedSettings: { [key: string]: CatalogSetting[] } = {}; settings.forEach(setting => { if (!groupedSettings[setting.addonId]) { groupedSettings[setting.addonId] = []; } groupedSettings[setting.addonId].push(setting); }); if (loading) { return ( ); } return ( navigation.goBack()} > Catalog Settings Choose which catalogs to show on your home screen. Changes will take effect immediately. {Object.entries(groupedSettings).map(([addonId, addonCatalogs]) => ( {addonCatalogs[0].name.split(' - ')[0]} {addonCatalogs.map((setting) => ( {setting.name.split(' - ')[1]} toggleCatalog(setting)} trackColor={{ false: colors.mediumGray, true: colors.primary }} /> ))} ))} ); }; const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: colors.background, }, loadingContainer: { flex: 1, justifyContent: 'center', alignItems: 'center', }, header: { flexDirection: 'row', alignItems: 'center', padding: 16, borderBottomWidth: 1, borderBottomColor: colors.border, }, backButton: { marginRight: 16, }, headerTitle: { fontSize: 20, fontWeight: 'bold', color: colors.text, }, scrollView: { flex: 1, }, description: { padding: 16, fontSize: 14, color: colors.mediumGray, }, addonSection: { marginBottom: 24, }, addonTitle: { fontSize: 18, fontWeight: 'bold', color: colors.text, paddingHorizontal: 16, marginBottom: 8, }, catalogItem: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', paddingVertical: 12, paddingHorizontal: 16, borderBottomWidth: 1, borderBottomColor: colors.border, }, catalogName: { fontSize: 16, color: colors.text, flex: 1, marginRight: 16, }, }); export default CatalogSettingsScreen;