chahinebrini 5d6c322129 wip: KeyboardAwareSheet migrations + Snake/Tetris UI + iron.png + useMe live-update
Sheets via neuer KeyboardAwareSheet-Composable (in Modal pattern, auto-grow
mit Tastatur, paddingBottom-Lift): EditMail, AddDomain, CreateRoom, ConnectMail.
GameOverScreen behält Spring-Slide-In, nutzt RN Keyboard.addListener für Lift.

- KeyboardAwareSheet.tsx — universal modal with sheet-grow + keyboard-padding
- react-native-keyboard-controller installiert + KeyboardProvider in Root
- Snake: time + ScoreProgressBar + useSnakeSounds (haptic, audio TODO)
- Tetris: title weg, Buttons zentriert, kein Pressable mit style-fn
- DPad-Buttons 60→48, more bg, no scale
- useMe: pub-sub listener pattern für app-weite avatar/nickname-Updates
- dm.tsx: resolveAvatar wrap (iron.png-Warning)
- Mail-error-humanizer + locales

Recovery-Doc-Update in docs/internal/RECOVERY_LOG_2026-05-10.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 23:59:25 +02:00

68 lines
2.5 KiB
TypeScript

import { ReactNode } from 'react';
import { Platform, ScrollView, StyleProp, ViewStyle } from 'react-native';
import { useKeyboardHeight } from '../hooks/useKeyboardHeight';
/**
* Universal-Wrapper für Forms/Pages mit TextInput.
*
* Für Vollbild-Formulare (Auth, Profile-Edit) reicht das alleine:
* - iOS: `automaticallyAdjustKeyboardInsets` (iOS 14+) verschiebt focused Input aktiv.
* - Android: `paddingBottom: keyboardHeight` + `windowSoftInputMode=adjustResize`
* im Manifest.
*
* Für FIXED-HEIGHT Sheets/Modals reicht das nicht — der Sheet selbst muss
* zusätzlich nach oben verschoben werden. Pattern:
* ```tsx
* const keyboardHeight = useKeyboardHeight();
* <Animated.View style={{
* transform: [{ translateY: ... }],
* marginBottom: keyboardHeight, // lift sheet above keyboard
* }}>
* <KeyboardAdjustedView>
* {form content}
* </KeyboardAdjustedView>
* </Animated.View>
* ```
*
* Siehe `EditMailAccountSheet.tsx` für vollständiges Sheet-Pattern.
*
* Anti-Pattern: KeyboardAvoidingView mit `behavior="padding"` greift bei
* Vollbild-Layouts mit `paddingTop: insets.top` nicht — siehe
* `docs/internal/RECOVERY_LOG_2026-05-10.md` §7.2.
*/
export interface KeyboardAdjustedViewProps {
children: ReactNode;
/** Style für den ScrollView (outer container). */
style?: StyleProp<ViewStyle>;
/** Style für den ScrollView-Inhalt (Padding gehört hier rein, nicht in `style`). */
contentContainerStyle?: StyleProp<ViewStyle>;
/** Extra Padding bottom on top of keyboard height (z.B. wenn fixed CTA-Bar drüber sitzt). */
extraBottomOffset?: number;
/** Default 'handled' — Tap auf nicht-Input-Bereich schließt Keyboard. */
keyboardShouldPersistTaps?: 'always' | 'never' | 'handled';
}
export function KeyboardAdjustedView({
children,
style,
contentContainerStyle,
extraBottomOffset = 0,
keyboardShouldPersistTaps = 'handled',
}: KeyboardAdjustedViewProps) {
const keyboardHeight = useKeyboardHeight();
const bottomPad = keyboardHeight > 0 ? keyboardHeight + extraBottomOffset : 0;
return (
<ScrollView
style={style}
contentContainerStyle={[contentContainerStyle, { paddingBottom: bottomPad }]}
keyboardShouldPersistTaps={keyboardShouldPersistTaps}
keyboardDismissMode={Platform.OS === 'ios' ? 'interactive' : 'on-drag'}
automaticallyAdjustKeyboardInsets={Platform.OS === 'ios'}
showsVerticalScrollIndicator={false}
>
{children}
</ScrollView>
);
}