import { useState, type ReactNode } from "react"; import { View, Text, TouchableOpacity, ActivityIndicator } from "react-native"; import { Ionicons } from "@expo/vector-icons"; // Geteilter Schutz-Setup-Flow (Reihenfolge + Gating). Quelle der Wahrheit für // Blocker UND Onboarding — NIE die Reihenfolge hier ändern ohne beide zu prüfen. // Android: VPN → Geräteadmin → a11y (a11y zuletzt, sonst blockt der Tamper-Lock // die Admin-Seite). iOS: App-Lock → Bildschirmzeit → URL-Filter. // ─── iOS Unsupervised 3-Step Setup Flow ────────────────────────────────────── type SetupFlowProps = { familyControlsActive: boolean; screentimeCode: string | null; screentimeConfirmed: boolean; screentimeSaving: boolean; urlFilterActive: boolean; onActivateFamilyControls: () => Promise<{ enabled: boolean; error?: string }>; onGenerateScreentimeCode: () => void; onConfirmScreentime: () => void; onActivateUrlFilter: () => Promise<{ enabled: boolean; error?: string }>; colors: ReturnType; t: ReturnType['t']; }; export function IosUnsupervisedSetupFlow({ familyControlsActive, screentimeCode, screentimeConfirmed, screentimeSaving, urlFilterActive, onActivateFamilyControls, onGenerateScreentimeCode, onConfirmScreentime, onActivateUrlFilter, colors, t, }: SetupFlowProps) { const step1Done = familyControlsActive; const step2Done = screentimeConfirmed; const step3Done = urlFilterActive; return ( ); } function SetupStep1({ done, onActivate, colors, t, }: { done: boolean; onActivate: () => Promise<{ enabled: boolean; error?: string }>; colors: ReturnType; t: ReturnType['t']; }) { const [busy, setBusy] = useState(false); async function handlePress() { if (done || busy) return; setBusy(true); try { await onActivate(); } finally { setBusy(false); } } return ( {!done && ( {busy ? : {t('blocker.setup_step1_cta')} } )} ); } function SetupStep2({ unlocked, code, confirmed, saving, onGenerate, onConfirm, colors, t, }: { unlocked: boolean; code: string | null; confirmed: boolean; saving: boolean; onGenerate: () => void; onConfirm: () => void; colors: ReturnType; t: ReturnType['t']; }) { return ( {unlocked && !confirmed && ( {!code ? ( {t('blocker.screentime_generate_cta')} ) : ( {t('blocker.screentime_code_label')} {code} {[ t('blocker.screentime_step1'), t('blocker.screentime_step2'), t('blocker.screentime_step3'), ].map((step, i) => ( {step} ))} {t('blocker.screentime_step_note')} {saving ? : {t('blocker.screentime_confirm_cta')} } )} )} ); } function SetupStep3({ unlocked, done, onActivate, colors, t, }: { unlocked: boolean; done: boolean; onActivate: () => Promise<{ enabled: boolean; error?: string }>; colors: ReturnType; t: ReturnType['t']; }) { const [busy, setBusy] = useState(false); async function handlePress() { if (done || busy) return; setBusy(true); try { await onActivate(); } finally { setBusy(false); } } return ( {unlocked && !done && ( {t('blocker.setup_step3_warning')} {busy ? : {t('blocker.setup_step3_cta')} } )} ); } // ─── Android 3-Step Setup Flow ─────────────────────────────────────────────── type AndroidSetupFlowProps = { vpnActive: boolean; // = a11y-Service enabled UND Tamper-Lock armed (appDeletionLock). Nur "enabled" // reicht NICHT — der a11y-Service ist ohne armed-Flag komplett passiv. accessibilityLocked: boolean; deviceAdminActive: boolean; onActivateVpn: () => Promise<{ enabled: boolean; error?: string }>; onActivateAccessibility: () => Promise; onRequestDeviceAdmin: () => Promise<{ launched: boolean }>; colors: ReturnType; t: ReturnType['t']; }; export function AndroidSetupFlow({ vpnActive, accessibilityLocked, deviceAdminActive, onActivateVpn, onActivateAccessibility, onRequestDeviceAdmin, colors, t, }: AndroidSetupFlowProps) { // Reihenfolge KRITISCH: VPN → Geräteadmin → a11y. a11y MUSS zuletzt, weil der // Tamper-Lock (sobald armed) die Geräteadmin-Seite blockt — sonst kann der // User den Admin gar nicht mehr aktivieren. const vpnDone = vpnActive; const adminDone = deviceAdminActive; const a11yDone = accessibilityLocked; return ( {/* Display-Step 2 = Geräteadmin (Komponente AndroidStep3, i18n android_step3_*). */} {/* Display-Step 3 = a11y / ReBreak-Schutz (Komponente AndroidStep2, i18n android_step2_*). */} ); } function AndroidStep1({ done, onActivate, colors, t, }: { done: boolean; onActivate: () => Promise<{ enabled: boolean; error?: string }>; colors: ReturnType; t: ReturnType['t']; }) { const [busy, setBusy] = useState(false); async function handlePress() { if (done || busy) return; setBusy(true); try { await onActivate(); } finally { setBusy(false); } } return ( {!done && ( {busy ? : {t('blocker.android_step1_cta')} } )} ); } function AndroidStep2({ unlocked, done, onActivate, colors, t, }: { unlocked: boolean; done: boolean; onActivate: () => Promise; colors: ReturnType; t: ReturnType['t']; }) { const [busy, setBusy] = useState(false); async function handlePress() { if (busy) return; setBusy(true); try { await onActivate(); } finally { setBusy(false); } } return ( {unlocked && !done && ( {[ t('blocker.android_step2_instruction1'), t('blocker.android_step2_instruction2'), t('blocker.android_step2_instruction3'), ].map((line, i) => ( {line} ))} {busy ? : {t('blocker.android_step2_cta')} } {t('blocker.android_step2_note')} )} ); } function AndroidStep3({ unlocked, done, onRequestAdmin, colors, t, }: { unlocked: boolean; done: boolean; onRequestAdmin: () => Promise<{ launched: boolean }>; colors: ReturnType; t: ReturnType['t']; }) { const [busy, setBusy] = useState(false); async function handlePress() { if (done || busy) return; setBusy(true); try { await onRequestAdmin(); } finally { setBusy(false); } } return ( {unlocked && !done && ( {t('blocker.android_step3_warning')} {busy ? : {t('blocker.android_step3_cta')} } )} ); } function SetupStepCard({ stepNumber, title, subtitle, done, unlocked, lockedHint, colors, children, }: { stepNumber: number; title: string; subtitle: string; done: boolean; unlocked: boolean; lockedHint?: string; colors: ReturnType; children?: ReactNode; }) { const borderColor = done ? '#86efac' : unlocked ? colors.border : colors.border; const cardBg = done ? '#f0fdf4' : colors.surface; const numberBg = done ? '#dcfce7' : unlocked ? colors.surfaceElevated : colors.surfaceElevated; const numberColor = done ? colors.success : unlocked ? colors.text : colors.textMuted; const titleColor = done ? colors.success : unlocked ? colors.text : colors.textMuted; return ( {done ? : {stepNumber} } {title} {!!subtitle && ( {subtitle} )} {done && } {lockedHint && !done && ( {lockedHint} )} {children} ); }