11import 'expo-dev-client' ;
2- import { router , Slot , usePathname } from 'expo-router' ;
2+ import { router , Slot } from 'expo-router' ;
33import { ThemeProvider } from '@react-navigation/native' ;
44import "../global.css" ;
5- import { useEffect } from 'react' ;
5+ import { useEffect , useState } from 'react' ;
66import { GestureHandlerRootView } from 'react-native-gesture-handler' ;
77import { BottomSheetModalProvider } from '@gorhom/bottom-sheet' ;
88import { setNavigationBar , themeAtom } from '@hooks/useColorScheme' ;
@@ -23,6 +23,9 @@ import advancedFormat from 'dayjs/plugin/advancedFormat'
2323import relativeTime from 'dayjs/plugin/relativeTime' ;
2424import { useAtom } from 'jotai' ;
2525import { useColorScheme } from 'nativewind' ;
26+ import * as SplashScreen from 'expo-splash-screen' ;
27+ import * as SystemUI from 'expo-system-ui' ;
28+ import { Appearance } from 'react-native' ;
2629
2730dayjs . extend ( utc )
2831dayjs . extend ( timezone )
@@ -40,46 +43,77 @@ if (__DEV__) {
4043 ] ) ;
4144}
4245
46+ // Prevent splash from auto-hiding before app is ready
47+ SplashScreen . preventAutoHideAsync ( )
48+
49+ SplashScreen . setOptions ( {
50+ duration : 200 ,
51+ fade : true ,
52+ } ) ;
53+
4354const messaging = getMessaging ( )
4455
4556export default function RootLayout ( ) {
4657
47- // const path = usePathname()
48- // console.log(path)
4958
50- const { getItem } = useAsyncStorage ( `default-site` )
59+ const [ appIsReady , setAppIsReady ] = useState ( false ) ;
60+ const { getItem } = useAsyncStorage ( `default-site` ) ;
61+ const { colorScheme, setColorScheme } = useColorScheme ( ) ;
62+ const isDarkColorScheme = colorScheme === 'dark' ;
63+ const [ theme ] = useAtom ( themeAtom ) ;
64+
65+ // Set system UI background color early to prevent flash
66+ useEffect ( ( ) => {
67+ const setSystemBackground = async ( ) => {
68+ const scheme = Appearance . getColorScheme ( ) ;
69+ const bgColor = scheme === 'dark' ? '#121212' : '#ffffff' ;
70+ await SystemUI . setBackgroundColorAsync ( bgColor ) ;
71+ } ;
72+ setSystemBackground ( ) ;
73+ } , [ ] ) ;
5174
5275
5376 useEffect ( ( ) => {
5477
5578 const onMount = async ( ) => {
56- // Get the defualt site from the async storage
57- // Also check if the app was started by a notification
58- const initialNotification = await messaging . getInitialNotification ( ) ;
59-
60- if ( initialNotification ) {
61- if ( initialNotification . data ?. channel_id && initialNotification . data ?. sitename ) {
62- setDefaultSite ( initialNotification . data . sitename as string )
63- let path = 'chat'
64- if ( initialNotification . data . is_thread ) {
65- path = 'thread'
79+
80+ try {
81+ // Get the defualt site from the async storage
82+ // Also check if the app was started by a notification
83+ const initialNotification = await messaging . getInitialNotification ( ) ;
84+
85+ if ( initialNotification ) {
86+ if ( initialNotification . data ?. channel_id && initialNotification . data ?. sitename ) {
87+ setDefaultSite ( initialNotification . data . sitename as string )
88+ let path = 'chat'
89+ if ( initialNotification . data . is_thread ) {
90+ path = 'thread'
91+ }
92+ router . navigate ( `/${ initialNotification . data . sitename } /${ path } /${ initialNotification . data . channel_id } ` , {
93+ withAnchor : true
94+ } )
95+
96+ return
6697 }
67- router . navigate ( `/${ initialNotification . data . sitename } /${ path } /${ initialNotification . data . channel_id } ` , {
68- withAnchor : true
69- } )
98+ }
7099
71- return
100+ // If not started by notification
101+ // On load, check if the user has a site set
102+ const defaultSite = await getItem ( )
103+ if ( defaultSite ) {
104+ router . replace ( `/${ defaultSite } ` )
105+ } else {
106+ router . replace ( '/landing' )
72107 }
73- }
74108
75- // If not started by notification
76- // On load, check if the user has a site set
77- const defaultSite = await getItem ( )
78- if ( defaultSite ) {
79- router . replace ( `/${ defaultSite } ` )
80- } else {
81- router . replace ( '/landing' )
109+ } catch ( error ) {
110+ console . warn ( 'Error during app initialization:' , error ) ;
111+ router . replace ( '/landing' ) ;
112+ } finally {
113+ // mark app as ready regardless of success or failure
114+ setAppIsReady ( true ) ;
82115 }
116+
83117 }
84118
85119 // Handle notification open when app is in background
@@ -104,11 +138,12 @@ export default function RootLayout() {
104138 } ;
105139 } , [ ] ) ;
106140
107- const { colorScheme, setColorScheme } = useColorScheme ( ) ;
108-
109- const isDarkColorScheme = colorScheme === 'dark'
110-
111- const [ theme ] = useAtom ( themeAtom ) ;
141+ // Hide splash screen when app is ready
142+ useEffect ( ( ) => {
143+ if ( appIsReady ) {
144+ SplashScreen . hide ( ) ;
145+ }
146+ } , [ appIsReady ] ) ;
112147
113148 useEffect ( ( ) => {
114149 if ( theme . state === 'hasData' ) {
@@ -157,4 +192,4 @@ export default function RootLayout() {
157192 </ GestureHandlerRootView >
158193 </ >
159194 )
160- }
195+ }
0 commit comments