mirror of
https://github.com/bulwarkmail/native.git
synced 2026-10-31 08:06:36 +00:00
fix: stop the cold start flashing white and the mail header jumping in
On a cold start the splash was followed by about a second of blank white, then mail rows whose header sat under the status bar until it popped in and pushed the list down. - `AppTheme` had no `android:windowBackground`, so while JS loaded the window showed the platform default (near-white, or grey at night). It is now the app's own background, #ffffff by day and #09090b at night (`values-night`), matching `src/theme/tokens.ts`. - `NavigationContainer` had no theme, so React Navigation painted its light default behind and between screens even in dark mode. It now uses the palette's background. - The mail list took its top inset from the native `SafeAreaView`, which on Fabric only learns the insets a few frames after mounting. It now pads with `useSafeAreaInsets()`, which the navigator's safe-area provider fills from the initial window metrics on the first render; the value is the same, it just arrives in time.
This commit is contained in:
@@ -2,7 +2,7 @@ import React from 'react';
|
||||
import { ActivityIndicator, AppState, Linking, StyleSheet, Text, View } from 'react-native';
|
||||
import { StatusBar } from 'expo-status-bar';
|
||||
import { useColorScheme } from 'react-native';
|
||||
import { NavigationContainer, createNavigationContainerRef } from '@react-navigation/native';
|
||||
import { DarkTheme, DefaultTheme, NavigationContainer, createNavigationContainerRef } from '@react-navigation/native';
|
||||
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
|
||||
import { createNativeStackNavigator, type NativeStackScreenProps } from '@react-navigation/native-stack';
|
||||
import { Mail, Calendar, BookUser, HardDrive, Settings } from 'lucide-react-native';
|
||||
@@ -267,6 +267,13 @@ export default function App() {
|
||||
const resolvedScheme: 'light' | 'dark' =
|
||||
themePref === 'system' ? (systemScheme === 'light' ? 'light' : 'dark') : themePref;
|
||||
const statusBarStyle: 'light' | 'dark' = resolvedScheme === 'light' ? 'dark' : 'light';
|
||||
// React Navigation's default theme is light: without this its containers
|
||||
// paint white behind and between screens, even in dark mode.
|
||||
const background = useColors().background;
|
||||
const navigationTheme = React.useMemo(() => {
|
||||
const base = resolvedScheme === 'light' ? DefaultTheme : DarkTheme;
|
||||
return { ...base, colors: { ...base.colors, background, card: background } };
|
||||
}, [resolvedScheme, background]);
|
||||
// Persisted active account is the signal that the user was already signed
|
||||
// in on the previous launch. When present we render the main UI with the
|
||||
// cached mail list instead of the "Restoring session" spinner; the real
|
||||
@@ -642,7 +649,7 @@ export default function App() {
|
||||
}
|
||||
|
||||
return (
|
||||
<NavigationContainer ref={navigationRef}>
|
||||
<NavigationContainer ref={navigationRef} theme={navigationTheme}>
|
||||
<StatusBar style={statusBarStyle} />
|
||||
<Stack.Navigator screenOptions={{ headerShown: false }}>
|
||||
<Stack.Screen name="MainTabs" component={MainTabsNavigator} />
|
||||
|
||||
@@ -1 +1,4 @@
|
||||
<resources/>
|
||||
<resources>
|
||||
<!-- Matches the dark palette background (src/theme/tokens.ts). -->
|
||||
<color name="window_background">#09090b</color>
|
||||
</resources>
|
||||
@@ -3,4 +3,6 @@
|
||||
<color name="iconBackground">#09090b</color>
|
||||
<color name="colorPrimary">#023c69</color>
|
||||
<color name="colorPrimaryDark">#09090b</color>
|
||||
<!-- Behind the React root until the first frame; matches the light palette background (src/theme/tokens.ts). -->
|
||||
<color name="window_background">#ffffff</color>
|
||||
</resources>
|
||||
@@ -4,6 +4,7 @@
|
||||
<item name="android:editTextBackground">@drawable/rn_edit_text_material</item>
|
||||
<item name="colorPrimary">@color/colorPrimary</item>
|
||||
<item name="android:statusBarColor">#09090b</item>
|
||||
<item name="android:windowBackground">@color/window_background</item>
|
||||
</style>
|
||||
<style name="Theme.App.SplashScreen" parent="AppTheme">
|
||||
<item name="android:windowBackground">@drawable/ic_launcher_background</item>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import { View, Text, StyleSheet, FlatList, Pressable, TextInput, Image, ActivityIndicator, Modal, Platform, ScrollView, TouchableWithoutFeedback, Alert } from 'react-native';
|
||||
import { SafeAreaView } from 'react-native-safe-area-context';
|
||||
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
||||
import DateTimePicker, { type DateTimePickerEvent } from '@react-native-community/datetimepicker';
|
||||
import * as DocumentPicker from 'expo-document-picker';
|
||||
import {
|
||||
@@ -295,6 +295,10 @@ interface EmailListScreenProps {
|
||||
export default function EmailListScreen({ onEmailPress, onComposePress }: EmailListScreenProps) {
|
||||
const c = useColors();
|
||||
const styles = React.useMemo(() => makeStyles(c), [c]);
|
||||
// The navigator's safe-area provider knows the insets on the first render;
|
||||
// the native SafeAreaView only learned them a few frames later on Fabric,
|
||||
// so the header first drew under the status bar and then jumped down.
|
||||
const insets = useSafeAreaInsets();
|
||||
const { t } = useLocaleStore();
|
||||
const [drawerOpen, setDrawerOpen] = React.useState(false);
|
||||
const [filterMenuOpen, setFilterMenuOpen] = React.useState(false);
|
||||
@@ -917,7 +921,7 @@ export default function EmailListScreen({ onEmailPress, onComposePress }: EmailL
|
||||
}, [mailboxes, currentMailboxId, selectMailbox]);
|
||||
|
||||
return (
|
||||
<SafeAreaView style={styles.container} edges={['top']}>
|
||||
<View style={[styles.container, { paddingTop: insets.top }]}>
|
||||
{/* Header */}
|
||||
{selectionMode ? (
|
||||
<View style={styles.header}>
|
||||
@@ -1592,7 +1596,7 @@ export default function EmailListScreen({ onEmailPress, onComposePress }: EmailL
|
||||
/>
|
||||
|
||||
<UndoSnackbar />
|
||||
</SafeAreaView>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user