import React, { useState, useCallback, useMemo, useRef, useEffect } from 'react'; import { View, StyleSheet, ScrollView, StatusBar, Platform, Text, TouchableOpacity, Dimensions, TextInput, ActivityIndicator } from 'react-native'; import { useNavigation, useFocusEffect } from '@react-navigation/native'; import { NavigationProp } from '@react-navigation/native'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { useTheme } from '../../contexts/ThemeContext'; import { useSettings } from '../../hooks/useSettings'; import { RootStackParamList } from '../../navigation/AppNavigator'; import ScreenHeader from '../../components/common/ScreenHeader'; import { SettingsCard, SettingItem, CustomSwitch, ChevronRight } from './SettingsComponents'; import { useRealtimeConfig } from '../../hooks/useRealtimeConfig'; import { MaterialIcons } from '@expo/vector-icons'; import { BottomSheetModal, BottomSheetScrollView, BottomSheetBackdrop } from '@gorhom/bottom-sheet'; import { useTranslation } from 'react-i18next'; import { SvgXml } from 'react-native-svg'; import { toastService } from '../../services/toastService'; import { introService } from '../../services/introService'; const { width } = Dimensions.get('window'); const INTRODB_LOGO_URI = 'https://introdb.app/images/logo-vector.svg'; // Available languages for audio/subtitle selection const AVAILABLE_LANGUAGES = [ { code: 'en', name: 'English' }, { code: 'es', name: 'Spanish' }, { code: 'fr', name: 'French' }, { code: 'de', name: 'German' }, { code: 'it', name: 'Italian' }, { code: 'ja', name: 'Japanese' }, { code: 'ko', name: 'Korean' }, { code: 'zh', name: 'Chinese' }, { code: 'ru', name: 'Russian' }, { code: 'pt', name: 'Portuguese' }, { code: 'hi', name: 'Hindi' }, { code: 'ar', name: 'Arabic' }, { code: 'nl', name: 'Dutch' }, { code: 'sv', name: 'Swedish' }, { code: 'no', name: 'Norwegian' }, { code: 'fi', name: 'Finnish' }, { code: 'da', name: 'Danish' }, { code: 'pl', name: 'Polish' }, { code: 'tr', name: 'Turkish' }, { code: 'cs', name: 'Czech' }, { code: 'hu', name: 'Hungarian' }, { code: 'el', name: 'Greek' }, { code: 'th', name: 'Thai' }, { code: 'vi', name: 'Vietnamese' }, { code: 'id', name: 'Indonesian' }, { code: 'ms', name: 'Malay' }, { code: 'ta', name: 'Tamil' }, { code: 'te', name: 'Telugu' }, { code: 'bn', name: 'Bengali' }, { code: 'uk', name: 'Ukrainian' }, { code: 'he', name: 'Hebrew' }, { code: 'fa', name: 'Persian' }, { code: 'hr', name: 'Croatian' }, { code: 'sr', name: 'Serbian' }, { code: 'bg', name: 'Bulgarian' }, { code: 'sl', name: 'Slovenian' }, { code: 'mk', name: 'Macedonian' }, { code: 'fil', name: 'Filipino' }, { code: 'ro', name: 'Romanian' }, { code: 'sq', name: 'Albanian' }, { code: 'ca', name: 'Catalan' }, ]; const SUBTITLE_SOURCE_OPTIONS = [ { value: 'internal', label: 'Internal First', description: 'Prefer embedded subtitles, then external' }, { value: 'external', label: 'External First', description: 'Prefer addon subtitles, then embedded' }, { value: 'any', label: 'Any Available', description: 'Use first available subtitle track' }, ]; // Props for the reusable content component interface PlaybackSettingsContentProps { isTablet?: boolean; } /** * Reusable PlaybackSettingsContent component * Can be used inline (tablets) or wrapped in a screen (mobile) */ export const PlaybackSettingsContent: React.FC = ({ isTablet = false }) => { const navigation = useNavigation>(); const { currentTheme } = useTheme(); const { settings, updateSetting } = useSettings(); const { t } = useTranslation(); const config = useRealtimeConfig(); const [introDbLogoXml, setIntroDbLogoXml] = useState(null); const [apiKeyInput, setApiKeyInput] = useState(settings?.introDbApiKey || ''); const [isVerifyingKey, setIsVerifyingKey] = useState(false); const isMounted = useRef(true); useEffect(() => { isMounted.current = true; return () => { isMounted.current = false; }; }, []); useEffect(() => { setApiKeyInput(settings?.introDbApiKey || ''); }, [settings?.introDbApiKey]); const handleApiKeySubmit = async () => { if (!apiKeyInput.trim()) { updateSetting('introDbApiKey', ''); toastService.success(t('settings.items.api_key_cleared', { defaultValue: 'API Key Cleared' })); return; } setIsVerifyingKey(true); const isValid = await introService.verifyApiKey(apiKeyInput); if (!isMounted.current) return; setIsVerifyingKey(false); if (isValid) { updateSetting('introDbApiKey', apiKeyInput); toastService.success(t('settings.items.api_key_saved', { defaultValue: 'API Key Saved' })); } else { toastService.error(t('settings.items.api_key_invalid', { defaultValue: 'Invalid API Key' })); } }; useEffect(() => { let cancelled = false; const load = async () => { try { const res = await fetch(INTRODB_LOGO_URI); let xml = await res.text(); // Inline CSS class-based styles because react-native-svg doesn't support