diff --git a/native/navigation/app-navigator.react.js b/native/navigation/app-navigator.react.js
index 118df8b4a..0a03b0611 100644
--- a/native/navigation/app-navigator.react.js
+++ b/native/navigation/app-navigator.react.js
@@ -1,251 +1,268 @@
// @flow
import type { BottomTabNavigationProp } from '@react-navigation/bottom-tabs';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import * as SplashScreen from 'expo-splash-screen';
import * as React from 'react';
+import { Alert } from 'react-native';
import { PersistGate } from 'redux-persist/integration/react';
import { unreadCount } from 'lib/selectors/thread-selectors';
+import { getMessageForException } from 'lib/utils/errors';
+import sleep from 'lib/utils/sleep';
import AppsDirectory from '../apps/apps-directory.react';
import Calendar from '../calendar/calendar.react';
import Chat from '../chat/chat.react';
import { MultimediaMessageTooltipModal } from '../chat/multimedia-message-tooltip-modal.react';
import { RobotextMessageTooltipModal } from '../chat/robotext-message-tooltip-modal.react';
import ThreadSettingsMemberTooltipModal from '../chat/settings/thread-settings-member-tooltip-modal.react';
import { TextMessageTooltipModal } from '../chat/text-message-tooltip-modal.react';
import SWMansionIcon from '../components/swmansion-icon.react';
import { type SQLiteContextType, SQLiteContext } from '../data/sqlite-context';
import KeyboardStateContainer from '../keyboard/keyboard-state-container.react';
import CameraModal from '../media/camera-modal.react';
import ImageModal from '../media/image-modal.react';
import VideoPlaybackModal from '../media/video-playback-modal.react';
import Profile from '../profile/profile.react';
import RelationshipListItemTooltipModal from '../profile/relationship-list-item-tooltip-modal.react';
import PushHandler from '../push/push-handler.react';
import { getPersistor } from '../redux/persist';
import { useSelector } from '../redux/redux-utils';
import { RootContext } from '../root-context';
import { waitForInteractions } from '../utils/timers';
import ActionResultModal from './action-result-modal.react';
import { createOverlayNavigator } from './overlay-navigator.react';
import type { OverlayRouterNavigationProp } from './overlay-router';
import type { RootNavigationProp } from './root-navigator.react';
import {
CalendarRouteName,
ChatRouteName,
ProfileRouteName,
TabNavigatorRouteName,
ImageModalRouteName,
MultimediaMessageTooltipModalRouteName,
ActionResultModalRouteName,
TextMessageTooltipModalRouteName,
ThreadSettingsMemberTooltipModalRouteName,
RelationshipListItemTooltipModalRouteName,
RobotextMessageTooltipModalRouteName,
CameraModalRouteName,
VideoPlaybackModalRouteName,
AppsRouteName,
type ScreenParamList,
type TabParamList,
type OverlayParamList,
} from './route-names';
import { tabBar } from './tab-bar.react';
let splashScreenHasHidden = false;
const calendarTabOptions = {
tabBarLabel: 'Calendar',
// eslint-disable-next-line react/display-name
tabBarIcon: ({ color }) => (
),
};
const getChatTabOptions = (badge: number) => ({
tabBarLabel: 'Inbox',
// eslint-disable-next-line react/display-name
tabBarIcon: ({ color }) => (
),
tabBarBadge: badge ? badge : undefined,
});
const profileTabOptions = {
tabBarLabel: 'Profile',
// eslint-disable-next-line react/display-name
tabBarIcon: ({ color }) => (
),
};
const appsTabOptions = {
tabBarLabel: 'Apps',
// eslint-disable-next-line react/display-name
tabBarIcon: ({ color }) => (
),
};
export type TabNavigationProp<
RouteName: $Keys = $Keys,
> = BottomTabNavigationProp;
const Tab = createBottomTabNavigator<
ScreenParamList,
TabParamList,
TabNavigationProp<>,
>();
const tabBarOptions = {
keyboardHidesTabBar: false,
activeTintColor: '#AE94DB',
style: {
backgroundColor: '#0A0A0A',
borderTopWidth: 1,
},
};
function TabNavigator() {
const chatBadge = useSelector(unreadCount);
const isCalendarEnabled = useSelector(state => state.enabledApps.calendar);
let calendarTab;
if (isCalendarEnabled) {
calendarTab = (
);
}
return (
{calendarTab}
);
}
export type AppNavigationProp<
RouteName: $Keys = $Keys,
> = OverlayRouterNavigationProp;
const App = createOverlayNavigator<
ScreenParamList,
OverlayParamList,
AppNavigationProp<>,
>();
type AppNavigatorProps = {
navigation: RootNavigationProp<'App'>,
...
};
function AppNavigator(props: AppNavigatorProps): React.Node {
const { navigation } = props;
const rootContext = React.useContext(RootContext);
const localDatabaseContext: ?SQLiteContextType = React.useContext(
SQLiteContext,
);
const storeLoadedFromLocalDatabase = localDatabaseContext?.threadStoreLoaded;
const setNavStateInitialized =
rootContext && rootContext.setNavStateInitialized;
React.useEffect(() => {
setNavStateInitialized && setNavStateInitialized();
}, [setNavStateInitialized]);
const [
localSplashScreenHasHidden,
setLocalSplashScreenHasHidden,
] = React.useState(splashScreenHasHidden);
React.useEffect(() => {
if (localSplashScreenHasHidden) {
return;
}
splashScreenHasHidden = true;
(async () => {
await waitForInteractions();
try {
- await SplashScreen.hideAsync();
+ await Promise.race([
+ SplashScreen.hideAsync(),
+ (async () => {
+ await sleep(5000);
+ throw new Error(
+ 'SplashScreen.hideAsync did not resolve/reject within 5 seconds',
+ );
+ })(),
+ ]);
+ } catch (e) {
+ Alert.alert(
+ 'SplashScreen.hideAsync() failed :(',
+ getMessageForException(e),
+ );
+ } finally {
setLocalSplashScreenHasHidden(true);
- } catch {}
+ }
})();
}, [localSplashScreenHasHidden]);
let pushHandler;
if (localSplashScreenHasHidden) {
pushHandler = (
);
}
if (!storeLoadedFromLocalDatabase) {
return null;
}
return (
{pushHandler}
);
}
const styles = {
icon: {
fontSize: 28,
},
};
export default AppNavigator;