Rollback-Punkt vor Expo SDK 54 / RN 0.81 Upgrade. UI/UX: - Profile: ProfileHeader redesign (sign-in chip + member-since), StatsBar 3 pill cards, Demographics accordion completed (Geburtsjahr, Geschlecht, Familienstand, Beruf-split, Wohnort), Pro-Trial-Banner, Approved-Domains list, DigaMissionBanner - Settings: section-based layout, neutral icons (matched Header dropdown style) - Header dropdown: extended with logout + games-page link - Notifications page: skeleton dummy data - Locales: i18n keys for new screens New components: - WheelPickerModal: native iOS UIPickerView wheel for long lists (Geburtsjahr 91 items, Bundesland 16, Stadt 30+/Bundesland) - OptionsBottomSheet: iOS-style options sheet (used briefly for Geschlecht, currently unused — kept for potential future use) - germanCities.ts: Top-cities per Bundesland (DSGVO-clean static data) New libs (NewArch-codegen verified): - @react-native-menu/menu 2.0.0 (UIMenu wrapper, Apple HIG-konform) - @lodev09/react-native-true-sheet 3.10.1 (UISheetPresentationController wrapper — ABER incompatible mit RN 0.79.6, Build-Error → Trigger für SDK-54-Upgrade) Maestro E2E: - Initial setup mit auth/community/profile/urge flows Scripts: - build-ios-clean.sh: Xcode DerivedData + ios/build cleanup vor expo run:ios Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
166 lines
4.1 KiB
TypeScript
166 lines
4.1 KiB
TypeScript
import { useEffect } from 'react';
|
|
import { Stack } from 'expo-router';
|
|
import { StatusBar } from 'expo-status-bar';
|
|
import * as Notifications from 'expo-notifications';
|
|
import { GestureHandlerRootView } from 'react-native-gesture-handler';
|
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
import { SafeAreaProvider } from 'react-native-safe-area-context';
|
|
import { ActionSheetProvider } from '@expo/react-native-action-sheet';
|
|
import * as SplashScreen from 'expo-splash-screen';
|
|
import {
|
|
useFonts,
|
|
Nunito_400Regular,
|
|
Nunito_600SemiBold,
|
|
Nunito_700Bold,
|
|
Nunito_800ExtraBold,
|
|
} from '@expo-google-fonts/nunito';
|
|
import { useAuthStore } from '../stores/auth';
|
|
import { useThemeStore } from '../stores/theme';
|
|
import { useLanguageStore } from '../stores/language';
|
|
import { BrandSplash } from '../components/BrandSplash';
|
|
import '../lib/i18n'; // i18next-Init via Side-Effect
|
|
import '../global.css';
|
|
|
|
SplashScreen.preventAutoHideAsync();
|
|
|
|
Notifications.setNotificationHandler({
|
|
handleNotification: async () => ({
|
|
shouldShowBanner: true,
|
|
shouldShowList: true,
|
|
shouldPlaySound: true,
|
|
shouldSetBadge: false,
|
|
}),
|
|
});
|
|
|
|
const queryClient = new QueryClient({
|
|
defaultOptions: {
|
|
queries: {
|
|
retry: 2,
|
|
staleTime: 1000 * 60,
|
|
},
|
|
},
|
|
});
|
|
|
|
function RootLayoutInner() {
|
|
const { loading, init } = useAuthStore();
|
|
const initTheme = useThemeStore((s) => s.init);
|
|
const initLanguage = useLanguageStore((s) => s.init);
|
|
const [fontsLoaded] = useFonts({
|
|
Nunito_400Regular,
|
|
Nunito_600SemiBold,
|
|
Nunito_700Bold,
|
|
Nunito_800ExtraBold,
|
|
});
|
|
|
|
useEffect(() => {
|
|
init();
|
|
initTheme();
|
|
initLanguage();
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
if (fontsLoaded && !loading) {
|
|
SplashScreen.hideAsync();
|
|
}
|
|
}, [fontsLoaded, loading]);
|
|
|
|
if (!fontsLoaded || loading) {
|
|
return <BrandSplash />;
|
|
}
|
|
|
|
return (
|
|
<>
|
|
<StatusBar style="dark" />
|
|
<Stack
|
|
screenOptions={{
|
|
headerShown: false,
|
|
animation: 'slide_from_right',
|
|
contentStyle: { backgroundColor: '#ffffff' },
|
|
}}
|
|
>
|
|
<Stack.Screen name="index" />
|
|
<Stack.Screen name="(auth)" />
|
|
<Stack.Screen name="(app)" />
|
|
<Stack.Screen
|
|
name="lyra"
|
|
options={{
|
|
headerShown: false,
|
|
presentation: 'card',
|
|
animation: 'slide_from_right',
|
|
}}
|
|
/>
|
|
<Stack.Screen
|
|
name="urge"
|
|
options={{
|
|
headerShown: false,
|
|
presentation: 'card',
|
|
animation: 'slide_from_bottom',
|
|
}}
|
|
/>
|
|
<Stack.Screen
|
|
name="dm"
|
|
options={{
|
|
headerShown: false,
|
|
presentation: 'card',
|
|
animation: 'slide_from_right',
|
|
}}
|
|
/>
|
|
<Stack.Screen
|
|
name="settings"
|
|
options={{
|
|
headerShown: false,
|
|
presentation: 'card',
|
|
animation: 'slide_from_right',
|
|
}}
|
|
/>
|
|
<Stack.Screen
|
|
name="profile/index"
|
|
options={{
|
|
headerShown: false,
|
|
presentation: 'card',
|
|
animation: 'slide_from_right',
|
|
}}
|
|
/>
|
|
<Stack.Screen
|
|
name="profile/[userId]"
|
|
options={{
|
|
headerShown: false,
|
|
presentation: 'card',
|
|
animation: 'slide_from_right',
|
|
}}
|
|
/>
|
|
<Stack.Screen
|
|
name="games"
|
|
options={{
|
|
headerShown: false,
|
|
presentation: 'card',
|
|
animation: 'slide_from_right',
|
|
}}
|
|
/>
|
|
<Stack.Screen
|
|
name="debug"
|
|
options={{
|
|
headerShown: false,
|
|
presentation: 'card',
|
|
animation: 'slide_from_right',
|
|
}}
|
|
/>
|
|
</Stack>
|
|
</>
|
|
);
|
|
}
|
|
|
|
export default function RootLayout() {
|
|
return (
|
|
<GestureHandlerRootView style={{ flex: 1 }}>
|
|
<QueryClientProvider client={queryClient}>
|
|
<ActionSheetProvider>
|
|
<SafeAreaProvider>
|
|
<RootLayoutInner />
|
|
</SafeAreaProvider>
|
|
</ActionSheetProvider>
|
|
</QueryClientProvider>
|
|
</GestureHandlerRootView>
|
|
);
|
|
}
|