import React, { useState, useEffect, useCallback } from 'react'; import { View, Text, StyleSheet, ScrollView, StatusBar, Dimensions, Linking, Alert, } from 'react-native'; import { useNavigation } from '@react-navigation/native'; import { NavigationProp } from '@react-navigation/native'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { useTheme } from '../../contexts/ThemeContext'; import { RootStackParamList } from '../../navigation/AppNavigator'; import ScreenHeader from '../../components/common/ScreenHeader'; import { SettingsCard, SettingItem, CustomSwitch, ChevronRight } from './SettingsComponents'; import { useTranslation } from 'react-i18next'; import { telemetryService, TelemetrySettings } from '../../services/telemetryService'; const { width } = Dimensions.get('window'); interface PrivacySettingsContentProps { isTablet?: boolean; } /** * Privacy Settings Content Component * * Provides user control over telemetry, analytics, and error reporting. * * Data Collection Summary: * - Analytics (PostHog): Usage patterns, screen views, interactions * - Error Reporting (Sentry): Crash reports and errors for app stability * - Session Replay: Screen recordings when errors occur * - PII: Personal identifiable information (IP, device info, etc.) */ export const PrivacySettingsContent: React.FC = ({ isTablet = false, }) => { const { t } = useTranslation(); const navigation = useNavigation>(); const { currentTheme } = useTheme(); // Telemetry settings state const [settings, setSettings] = useState({ analyticsEnabled: false, errorReportingEnabled: true, sessionReplayEnabled: false, piiEnabled: false, }); const [isLoading, setIsLoading] = useState(true); const showAlert = useCallback(( title: string, message: string, actions?: Array<{ label: string; onPress: () => void; style?: object }> ) => { const alertActions = (actions || [{ label: 'OK', onPress: () => { } }]).map(action => ({ text: action.label, onPress: action.onPress, style: undefined as 'default' | 'cancel' | 'destructive' | undefined, })); Alert.alert(title, message, alertActions, { cancelable: true }); }, []); // Load settings on mount useEffect(() => { const loadSettings = async () => { try { await telemetryService.initialize(); setSettings(telemetryService.getSettings()); } catch (error) { console.error('Failed to load telemetry settings:', error); } finally { setIsLoading(false); } }; loadSettings(); }, []); // Handle analytics toggle const handleAnalyticsToggle = async (enabled: boolean) => { try { await telemetryService.setAnalyticsEnabled(enabled); setSettings(prev => ({ ...prev, analyticsEnabled: enabled })); if (enabled) { showAlert( t('privacy.analytics_enabled_title'), t('privacy.analytics_enabled_message') ); } } catch (error) { console.error('Failed to update analytics setting:', error); } }; // Handle error reporting toggle const handleErrorReportingToggle = async (enabled: boolean) => { if (!enabled) { showAlert( t('privacy.disable_error_reporting_title'), t('privacy.disable_error_reporting_message'), [ { label: t('common.cancel', 'Cancel'), onPress: () => { } }, { label: t('common.disable', 'Disable'), onPress: async () => { await telemetryService.setErrorReportingEnabled(false); setSettings(prev => ({ ...prev, errorReportingEnabled: false })); } } ] ); } else { await telemetryService.setErrorReportingEnabled(true); setSettings(prev => ({ ...prev, errorReportingEnabled: true })); } }; // Handle session replay toggle const handleSessionReplayToggle = async (enabled: boolean) => { if (enabled) { showAlert( t('privacy.enable_session_replay_title'), t('privacy.enable_session_replay_message'), [ { label: t('common.cancel', 'Cancel'), onPress: () => { } }, { label: t('common.enable'), onPress: async () => { await telemetryService.setSessionReplayEnabled(true); setSettings(prev => ({ ...prev, sessionReplayEnabled: true })); } } ] ); } else { await telemetryService.setSessionReplayEnabled(false); setSettings(prev => ({ ...prev, sessionReplayEnabled: false })); } }; // Handle PII toggle const handlePiiToggle = async (enabled: boolean) => { if (enabled) { showAlert( t('privacy.enable_pii_title'), t('privacy.enable_pii_message'), [ { label: t('common.cancel', 'Cancel'), onPress: () => { } }, { label: t('common.enable'), onPress: async () => { await telemetryService.setPiiEnabled(true); setSettings(prev => ({ ...prev, piiEnabled: true })); } } ] ); } else { await telemetryService.setPiiEnabled(false); setSettings(prev => ({ ...prev, piiEnabled: false })); } }; // Disable all telemetry const handleDisableAll = () => { showAlert( t('privacy.disable_all_title'), t('privacy.disable_all_message'), [ { label: t('common.cancel', 'Cancel'), onPress: () => { } }, { label: t('privacy.disable_all_button'), onPress: async () => { await telemetryService.disableAllTelemetry(); setSettings({ analyticsEnabled: false, errorReportingEnabled: false, sessionReplayEnabled: false, piiEnabled: false, }); // Delay showing the next alert to avoid Reanimated conflicts setTimeout(() => { showAlert( t('privacy.all_disabled_title'), t('privacy.all_disabled_message') ); }, 300); } } ] ); }; // Reset to recommended defaults const handleResetToRecommended = async () => { await telemetryService.enableRecommendedTelemetry(); setSettings({ analyticsEnabled: false, errorReportingEnabled: true, sessionReplayEnabled: false, piiEnabled: false, }); // No chained alert here, this is direct so it's fine showAlert( t('privacy.reset_title'), t('privacy.reset_message') ); }; if (isLoading) { return ( {t('common.loading', 'Loading...')} ); } return ( <> {/* Info Card */} {t('privacy.info_title')} {t('privacy.info_description')} {/* Analytics Section */} ( )} descriptionNumberOfLines={2} isLast isTablet={isTablet} /> {/* Error Reporting Section */} ( )} descriptionNumberOfLines={2} isTablet={isTablet} /> ( )} descriptionNumberOfLines={2} isTablet={isTablet} /> ( )} descriptionNumberOfLines={2} isLast isTablet={isTablet} /> {/* Quick Actions */} } descriptionNumberOfLines={2} isTablet={isTablet} /> } descriptionNumberOfLines={2} isLast isTablet={isTablet} /> {/* Learn More */} Linking.openURL('https://tapframe.github.io/NuvioStreaming/#privacy-policy')} renderControl={() => } isTablet={isTablet} /> {/* Data Summary */} {t('privacy.current_settings')} {t('privacy.summary_analytics')}: {settings.analyticsEnabled ? t('common.on', 'On') : t('common.off', 'Off')} {t('privacy.summary_errors')}: {settings.errorReportingEnabled ? t('common.on', 'On') : t('common.off', 'Off')} {t('privacy.summary_replay')}: {settings.sessionReplayEnabled ? t('common.on', 'On') : t('common.off', 'Off')} {t('privacy.summary_pii')}: {settings.piiEnabled ? t('common.on', 'On') : t('common.off', 'Off')} {t('privacy.restart_note_detailed')} ); }; /** * PrivacySettingsScreen - Wrapper for mobile navigation */ const PrivacySettingsScreen: React.FC = () => { const navigation = useNavigation>(); const { currentTheme } = useTheme(); const { t } = useTranslation(); const insets = useSafeAreaInsets(); const screenIsTablet = width >= 768; return ( navigation.goBack()} /> ); }; const styles = StyleSheet.create({ container: { flex: 1, }, scrollView: { flex: 1, }, scrollContent: { paddingTop: 16, }, loadingContainer: { padding: 40, alignItems: 'center', }, loadingText: { fontSize: 16, }, infoCard: { marginHorizontal: 16, marginBottom: 20, padding: 16, borderRadius: 16, borderWidth: 1, }, infoTitle: { fontSize: 17, fontWeight: '600', marginBottom: 8, }, infoText: { fontSize: 14, lineHeight: 20, }, summaryCard: { marginHorizontal: 16, marginTop: 8, marginBottom: 20, padding: 16, borderRadius: 16, borderWidth: 1, }, summaryTitle: { fontSize: 15, fontWeight: '600', marginBottom: 12, }, summaryRow: { flexDirection: 'row', alignItems: 'center', marginBottom: 8, }, statusDot: { width: 8, height: 8, borderRadius: 4, marginRight: 10, }, summaryText: { fontSize: 14, }, restartNote: { fontSize: 12, fontStyle: 'italic', marginTop: 8, }, }); export default PrivacySettingsScreen;