chahinebrini 33aa3464b8 feat(onboarding): protection pointer redesign + i18n screenshots + lockedIn fix
## Protection Pre-Explainer: External Pointer

Vorher: Pulse-Ring absolute-positioniert IM Screenshot — Position musste
per-locale fine-tuned werden weil Apple-Dialog-Höhe variiert (DE/EN/FR/AR
haben unterschiedliche Text-Längen → Dialog hat verschiedene Höhen →
Erlauben-Button rutscht).

Jetzt: animierter Pfeil + Label-Pill UNTER dem Screenshot. Dimensions-
agnostic, funktioniert in allen 4 Sprachen ohne Locale-spezifische Magie.

- ScreenshotPointer komplett refactored: caret-up + bouncing pill mit
  Button-Label-Text (z.B. 'Tippe "Erlauben"' / 'Tap "Allow"' / etc.)
- onboardingAssets.ts: getPointerPosition deprecated/entfernt
- ProtectionSlide nutzt neue API mit buttonLabelKey
- 4 Locales: dialog_button_allow + dialog_button_continue
- tap_marker_hint refined (kein "roter Marker"-Ref mehr)

## i18n-aware Screenshots

en/fr/ar Permission-Dialog-Screenshots zur Map ergänzt. Resolver fällt
auf de zurück wenn andere Sprache fehlt.

## Dynamic Sizing

ProtectionSlide nutzt useWindowDimensions:
  height: min(320, max(200, screenH * 0.32))
→ passt auf iPhone SE (213px) bis Pro Max (320px capped) ohne Scroll.

OnboardingShell ScrollView-Padding reduziert (16→12 top, 24→16 bottom).
ProtectionSlide-Spacing tightened.

## Blocker: lockedIn Fix

Bug: `lockedIn = appDeletionLockActive` ignorierte URL-Filter-State —
wenn User nur FC aktivierte (ohne URL-Filter), zeigte App grünen "Schutz
aktiv"-Banner obwohl URL-Filter aus war. Fix:
  lockedIn = urlFilter && appDeletionLock
→ Beide müssen wirklich aktiv sein für den grünen Banner.

## LayerSwitchCard: lockedHint Prop

Optional Hint-Text der unter dem active Layer angezeigt wird, z.B.
"System-gesperrt. Nur in iOS-Einstellungen → Bildschirmzeit → Verwaltung
durch ReBreak deaktivierbar.". Wird für iOS App-Lock-Card genutzt.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-17 19:58:56 +02:00

66 lines
1.8 KiB
TypeScript

import { ReactNode } from 'react';
import { ScrollView, View } from 'react-native';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { useColors } from '../../lib/theme';
import { SlideProgress } from './SlideProgress';
/**
* Layout-Wrapper für alle Onboarding-Slides.
*
* ┌──────────────────────────────┐
* │ [Top-Padding + SafeArea] │
* │ ────── Progress-Bar ───── │
* │ │
* │ <children — ScrollView> │
* │ │
* │ ───── CTABar (sticky) ───── │
* └──────────────────────────────┘
*
* `cta` wird IM Shell gerendert (sticky-bottom + SafeArea). Slides müssen
* ihre Inhalte als `children` reinpacken (= scrollbarer Content-Bereich).
*/
export function OnboardingShell({
current,
total,
children,
cta,
}: {
current: number;
total: number;
children: ReactNode;
cta: ReactNode;
}) {
const colors = useColors();
const insets = useSafeAreaInsets();
return (
<View style={{ flex: 1, backgroundColor: colors.bg }}>
<View
style={{
paddingTop: insets.top + 12,
paddingHorizontal: 20,
paddingBottom: 8,
}}
>
<SlideProgress current={current} total={total} />
</View>
<ScrollView
style={{ flex: 1 }}
contentContainerStyle={{
paddingHorizontal: 20,
paddingTop: 12,
paddingBottom: 16,
flexGrow: 1,
}}
keyboardShouldPersistTaps="handled"
showsVerticalScrollIndicator={false}
>
{children}
</ScrollView>
{cta}
</View>
);
}