deer social fork for personal usage. but you might see a use idk. github mirror

Edge to edge support (#7497)

authored by Mathieu Acthernoene and committed by GitHub a770f563 6e80b340

+5 -5
app.config.js
··· 1 1 const pkg = require('./package.json') 2 2 3 - const DARK_SPLASH_ANDROID_BACKGROUND = '#0f141b' 4 - 5 3 module.exports = function (config) { 6 4 /** 7 5 * App version number. Should be incremented as part of a release cycle. ··· 140 138 }, 141 139 androidStatusBar: { 142 140 barStyle: 'light-content', 143 - backgroundColor: '#00000000', 144 141 }, 145 142 // Dark nav bar in light mode is better than light nav bar in dark mode 146 143 androidNavigationBar: { 147 144 barStyle: 'light-content', 148 - backgroundColor: DARK_SPLASH_ANDROID_BACKGROUND, 149 145 }, 150 146 android: { 151 147 icon: './assets/app-icons/android_icon_default_light.png', ··· 197 193 plugins: [ 198 194 'expo-video', 199 195 'expo-localization', 196 + [ 197 + 'react-native-edge-to-edge', 198 + {android: {enforceNavigationBarContrast: false}}, 199 + ], 200 200 USE_SENTRY && [ 201 201 '@sentry/react-native/expo', 202 202 { ··· 240 240 './plugins/withAndroidManifestPlugin.js', 241 241 './plugins/withAndroidManifestFCMIconPlugin.js', 242 242 './plugins/withAndroidStylesAccentColorPlugin.js', 243 - './plugins/withAndroidSplashScreenStatusBarTranslucentPlugin.js', 243 + './plugins/withAndroidDayNightThemePlugin.js', 244 244 './plugins/withAndroidNoJitpackPlugin.js', 245 245 './plugins/withNoBundleCompression.js', 246 246 './plugins/shareExtension/withShareExtensions.js',
+2 -3
package.json
··· 141 141 "expo-linking": "~7.0.5", 142 142 "expo-localization": "~16.0.1", 143 143 "expo-media-library": "~17.0.6", 144 - "expo-navigation-bar": "~4.0.9", 145 144 "expo-notifications": "~0.29.14", 146 145 "expo-screen-orientation": "~8.0.4", 147 146 "expo-sharing": "~13.0.1", 148 147 "expo-splash-screen": "~0.29.22", 149 - "expo-status-bar": "~2.0.1", 150 148 "expo-system-ui": "~4.0.9", 151 149 "expo-task-manager": "~12.0.6", 152 150 "expo-updates": "~0.27.4", ··· 178 176 "react-native-compressor": "1.10.3", 179 177 "react-native-date-picker": "^5.0.7", 180 178 "react-native-drawer-layout": "^4.1.1", 179 + "react-native-edge-to-edge": "^1.6.0", 181 180 "react-native-emoji-popup": "^0.1.2", 182 181 "react-native-gesture-handler": "2.20.2", 183 182 "react-native-get-random-values": "~1.11.0", 184 183 "react-native-image-crop-picker": "^0.41.6", 185 184 "react-native-ios-context-menu": "^1.15.3", 186 - "react-native-keyboard-controller": "^1.14.5", 185 + "react-native-keyboard-controller": "^1.17.1", 187 186 "react-native-mmkv": "^2.12.2", 188 187 "react-native-pager-view": "6.5.1", 189 188 "react-native-picker-select": "^9.3.1",
+27
plugins/withAndroidDayNightThemePlugin.js
··· 1 + // Based on https://github.com/expo/expo/pull/33957 2 + // Could be removed once the app has been updated to Expo 53 3 + const {withAndroidStyles} = require('@expo/config-plugins') 4 + 5 + module.exports = function withAndroidDayNightThemePlugin(appConfig) { 6 + const cleanupList = new Set([ 7 + 'colorPrimary', 8 + 'android:editTextBackground', 9 + 'android:textColor', 10 + 'android:editTextStyle', 11 + ]) 12 + 13 + return withAndroidStyles(appConfig, config => { 14 + config.modResults.resources.style = config.modResults.resources.style 15 + ?.map(style => { 16 + if (style.$.name === 'AppTheme' && style.item != null) { 17 + style.item = style.item.filter(item => !cleanupList.has(item.$.name)) 18 + } 19 + return style 20 + }) 21 + .filter(style => { 22 + return style.$.name !== 'ResetEditText' 23 + }) 24 + 25 + return config 26 + }) 27 + }
-28
plugins/withAndroidSplashScreenStatusBarTranslucentPlugin.js
··· 1 - const {withStringsXml, AndroidConfig} = require('@expo/config-plugins') 2 - 3 - module.exports = function withAndroidSplashScreenStatusBarTranslucentPlugin( 4 - appConfig, 5 - ) { 6 - return withStringsXml(appConfig, function (decoratedAppConfig) { 7 - try { 8 - decoratedAppConfig.modResults = AndroidConfig.Strings.setStringItem( 9 - [ 10 - { 11 - _: 'true', 12 - $: { 13 - name: 'expo_splash_screen_status_bar_translucent', 14 - translatable: 'false', 15 - }, 16 - }, 17 - ], 18 - decoratedAppConfig.modResults, 19 - ) 20 - } catch (e) { 21 - console.error( 22 - `withAndroidSplashScreenStatusBarTranslucentPlugin failed`, 23 - e, 24 - ) 25 - } 26 - return decoratedAppConfig 27 - }) 28 - }
+1 -1
plugins/withAndroidStylesAccentColorPlugin.js
··· 12 12 decoratedAppConfig.modResults, 13 13 { 14 14 add: true, 15 - parent: AndroidConfig.Styles.getAppThemeLightNoActionBarGroup(), 15 + parent: AndroidConfig.Styles.getAppThemeGroup(), 16 16 name: 'colorAccent', 17 17 value: '@color/colorPrimary', 18 18 },
+2 -5
src/App.native.tsx
··· 46 46 import {Provider as UnreadNotifsProvider} from '#/state/queries/notifications/unread' 47 47 import { 48 48 Provider as SessionProvider, 49 - SessionAccount, 49 + type SessionAccount, 50 50 useSession, 51 51 useSessionApi, 52 52 } from '#/state/session' 53 53 import {readLastActiveAccount} from '#/state/session/util' 54 54 import {Provider as ShellStateProvider} from '#/state/shell' 55 55 import {Provider as ComposerProvider} from '#/state/shell/composer' 56 - import {Provider as LightStatusBarProvider} from '#/state/shell/light-status-bar' 57 56 import {Provider as LoggedOutViewProvider} from '#/state/shell/logged-out' 58 57 import {Provider as ProgressGuideProvider} from '#/state/shell/progress-guide' 59 58 import {Provider as SelectedFeedProvider} from '#/state/shell/selected-feed' ··· 219 218 <StarterPackProvider> 220 219 <SafeAreaProvider 221 220 initialMetrics={initialWindowMetrics}> 222 - <LightStatusBarProvider> 223 - <InnerApp /> 224 - </LightStatusBarProvider> 221 + <InnerApp /> 225 222 </SafeAreaProvider> 226 223 </StarterPackProvider> 227 224 </BottomSheetProvider>
+2 -5
src/App.web.tsx
··· 35 35 import {Provider as UnreadNotifsProvider} from '#/state/queries/notifications/unread' 36 36 import { 37 37 Provider as SessionProvider, 38 - SessionAccount, 38 + type SessionAccount, 39 39 useSession, 40 40 useSessionApi, 41 41 } from '#/state/session' 42 42 import {readLastActiveAccount} from '#/state/session/util' 43 43 import {Provider as ShellStateProvider} from '#/state/shell' 44 44 import {Provider as ComposerProvider} from '#/state/shell/composer' 45 - import {Provider as LightStatusBarProvider} from '#/state/shell/light-status-bar' 46 45 import {Provider as LoggedOutViewProvider} from '#/state/shell/logged-out' 47 46 import {Provider as ProgressGuideProvider} from '#/state/shell/progress-guide' 48 47 import {Provider as SelectedFeedProvider} from '#/state/shell/selected-feed' ··· 193 192 <LightboxStateProvider> 194 193 <PortalProvider> 195 194 <StarterPackProvider> 196 - <LightStatusBarProvider> 197 - <InnerApp /> 198 - </LightStatusBarProvider> 195 + <InnerApp /> 199 196 </StarterPackProvider> 200 197 </PortalProvider> 201 198 </LightboxStateProvider>
-21
src/alf/util/navigationBar.ts
··· 1 - import * as NavigationBar from 'expo-navigation-bar' 2 - import * as SystemUI from 'expo-system-ui' 3 - 4 - import {isAndroid} from '#/platform/detection' 5 - import {Theme} from '../types' 6 - 7 - export function setNavigationBar(themeType: 'theme' | 'lightbox', t: Theme) { 8 - if (isAndroid) { 9 - if (themeType === 'theme') { 10 - NavigationBar.setBackgroundColorAsync(t.atoms.bg.backgroundColor) 11 - NavigationBar.setBorderColorAsync(t.atoms.bg.backgroundColor) 12 - NavigationBar.setButtonStyleAsync(t.name !== 'light' ? 'light' : 'dark') 13 - SystemUI.setBackgroundColorAsync(t.atoms.bg.backgroundColor) 14 - } else { 15 - NavigationBar.setBackgroundColorAsync('black') 16 - NavigationBar.setBorderColorAsync('black') 17 - NavigationBar.setButtonStyleAsync('light') 18 - SystemUI.setBackgroundColorAsync('black') 19 - } 20 - } 21 - }
+14
src/alf/util/systemUI.ts
··· 1 + import * as SystemUI from 'expo-system-ui' 2 + 3 + import {isAndroid} from '#/platform/detection' 4 + import {Theme} from '../types' 5 + 6 + export function setSystemUITheme(themeType: 'theme' | 'lightbox', t: Theme) { 7 + if (isAndroid) { 8 + if (themeType === 'theme') { 9 + SystemUI.setBackgroundColorAsync(t.atoms.bg.backgroundColor) 10 + } else { 11 + SystemUI.setBackgroundColorAsync('black') 12 + } 13 + } 14 + }
+1 -1
src/components/ContextMenu/index.tsx
··· 556 556 // pure vibes based 557 557 const TOP_INSET = insets.top + 80 558 558 const BOTTOM_INSET_IOS = insets.bottom + 20 559 - const BOTTOM_INSET_ANDROID = 12 // TODO: revisit when edge-to-edge mode is enabled -sfn 559 + const BOTTOM_INSET_ANDROID = insets.bottom + 12 560 560 561 561 const {height} = evt.nativeEvent.layout 562 562 const topPosition =
+14 -9
src/components/Dialog/sheet-wrapper.ts
··· 1 1 import {useCallback} from 'react' 2 + import {SystemBars} from 'react-native-edge-to-edge' 2 3 3 - import {useDialogStateControlContext} from '#/state/dialogs' 4 + import {isIOS} from '#/platform/detection' 4 5 5 6 /** 6 7 * If we're calling a system API like the image picker that opens a sheet 7 8 * wrap it in this function to make sure the status bar is the correct color. 8 9 */ 9 10 export function useSheetWrapper() { 10 - const {setFullyExpandedCount} = useDialogStateControlContext() 11 - return useCallback( 12 - async <T>(promise: Promise<T>): Promise<T> => { 13 - setFullyExpandedCount(c => c + 1) 11 + return useCallback(async <T>(promise: Promise<T>): Promise<T> => { 12 + if (isIOS) { 13 + const entry = SystemBars.pushStackEntry({ 14 + style: { 15 + statusBar: 'light', 16 + }, 17 + }) 14 18 const res = await promise 15 - setFullyExpandedCount(c => c - 1) 19 + SystemBars.popStackEntry(entry) 16 20 return res 17 - }, 18 - [setFullyExpandedCount], 19 - ) 21 + } else { 22 + return await promise 23 + } 24 + }, []) 20 25 }
+1 -4
src/lib/hooks/useEnableKeyboardController.tsx
··· 26 26 children: React.ReactNode 27 27 }) { 28 28 return ( 29 - <KeyboardProvider 30 - enabled={false} 31 - // I don't think this is necessary, but Chesterton's fence and all that -sfn 32 - statusBarTranslucent={true}> 29 + <KeyboardProvider enabled={false}> 33 30 <KeyboardControllerProviderInner> 34 31 {children} 35 32 </KeyboardControllerProviderInner>
+1 -1
src/screens/Login/index.tsx
··· 8 8 import {logEvent} from '#/lib/statsig/statsig' 9 9 import {logger} from '#/logger' 10 10 import {useServiceQuery} from '#/state/queries/service' 11 - import {SessionAccount, useSession} from '#/state/session' 11 + import {type SessionAccount, useSession} from '#/state/session' 12 12 import {useLoggedOutView} from '#/state/shell/logged-out' 13 13 import {LoggedOutLayout} from '#/view/com/util/layouts/LoggedOutLayout' 14 14 import {ForgotPasswordForm} from '#/screens/Login/ForgotPasswordForm'
+3 -2
src/screens/Messages/components/MessageInput.tsx
··· 24 24 useMessageDraft, 25 25 useSaveMessageDraft, 26 26 } from '#/state/messages/message-drafts' 27 - import {EmojiPickerPosition} from '#/view/com/composer/text-input/web/EmojiPicker.web' 27 + import {type EmojiPickerPosition} from '#/view/com/composer/text-input/web/EmojiPicker.web' 28 28 import * as Toast from '#/view/com/util/Toast' 29 - import {atoms as a, useTheme} from '#/alf' 29 + import {android, atoms as a, useTheme} from '#/alf' 30 30 import {useSharedInputStyles} from '#/components/forms/TextField' 31 31 import {PaperPlane_Stroke2_Corner0_Rounded as PaperPlane} from '#/components/icons/PaperPlane' 32 32 import {useExtractEmbedFromFacets} from './MessageInputEmbed' ··· 174 174 a.text_md, 175 175 a.px_sm, 176 176 t.atoms.text, 177 + android({paddingTop: 0}), 177 178 {paddingBottom: isIOS ? 5 : 0}, 178 179 animatedStyle, 179 180 ]}
+2 -2
src/screens/SignupQueued.tsx
··· 1 1 import React from 'react' 2 2 import {Modal, ScrollView, View} from 'react-native' 3 + import {SystemBars} from 'react-native-edge-to-edge' 3 4 import {useSafeAreaInsets} from 'react-native-safe-area-context' 4 - import {StatusBar} from 'expo-status-bar' 5 5 import {msg, plural, Trans} from '@lingui/macro' 6 6 import {useLingui} from '@lingui/react' 7 7 ··· 106 106 animationType={native('slide')} 107 107 presentationStyle="formSheet" 108 108 style={[web(a.util_screen_outer)]}> 109 - {isIOS && <StatusBar style="light" />} 109 + {isIOS && <SystemBars style={{statusBar: 'light'}} />} 110 110 <ScrollView 111 111 style={[a.flex_1, t.atoms.bg]} 112 112 contentContainerStyle={{borderWidth: 0}}
+2 -2
src/screens/Takendown.tsx
··· 1 1 import {useMemo, useState} from 'react' 2 2 import {Modal, View} from 'react-native' 3 + import {SystemBars} from 'react-native-edge-to-edge' 3 4 import {KeyboardAwareScrollView} from 'react-native-keyboard-controller' 4 5 import {useSafeAreaInsets} from 'react-native-safe-area-context' 5 - import {StatusBar} from 'expo-status-bar' 6 6 import {ComAtprotoAdminDefs, ComAtprotoModerationDefs} from '@atproto/api' 7 7 import {msg, Trans} from '@lingui/macro' 8 8 import {useLingui} from '@lingui/react' ··· 126 126 animationType={native('slide')} 127 127 presentationStyle="formSheet" 128 128 style={[web(a.util_screen_outer)]}> 129 - {isIOS && <StatusBar style="light" />} 129 + {isIOS && <SystemBars style={{statusBar: 'light'}} />} 130 130 <KeyboardAwareScrollView style={[a.flex_1, t.atoms.bg]} centerContent> 131 131 <View 132 132 style={[
+5 -3
src/screens/VideoFeed/index.tsx
··· 8 8 ViewabilityConfig, 9 9 ViewToken, 10 10 } from 'react-native' 11 + import {SystemBars} from 'react-native-edge-to-edge' 11 12 import { 12 13 Gesture, 13 14 GestureDetector, ··· 77 78 import {UserAvatar} from '#/view/com/util/UserAvatar' 78 79 import {Header} from '#/screens/VideoFeed/components/Header' 79 80 import {atoms as a, ios, platform, ThemeProvider, useTheme} from '#/alf' 80 - import {setNavigationBar} from '#/alf/util/navigationBar' 81 + import {setSystemUITheme} from '#/alf/util/systemUI' 81 82 import {Button, ButtonIcon, ButtonText} from '#/components/Button' 82 83 import {Divider} from '#/components/Divider' 83 84 import {ArrowLeft_Stroke2_Corner0_Rounded as ArrowLeftIcon} from '#/components/icons/Arrow' ··· 126 127 useFocusEffect( 127 128 useCallback(() => { 128 129 setMinShellMode(true) 129 - setNavigationBar('lightbox', t) 130 + setSystemUITheme('lightbox', t) 130 131 return () => { 131 132 setMinShellMode(false) 132 - setNavigationBar('theme', t) 133 + setSystemUITheme('theme', t) 133 134 } 134 135 }, [setMinShellMode, t]), 135 136 ) ··· 140 141 return ( 141 142 <ThemeProvider theme="dark"> 142 143 <Layout.Screen noInsetTop style={{backgroundColor: 'black'}}> 144 + <SystemBars style={{statusBar: 'light', navigationBar: 'light'}} /> 143 145 <View 144 146 style={[ 145 147 a.absolute,
+11 -38
src/state/shell/light-status-bar.tsx
··· 1 - import {createContext, useContext, useEffect, useState} from 'react' 2 - 3 - import {isWeb} from '#/platform/detection' 4 - 5 - const LightStatusBarRefCountContext = createContext<boolean>(false) 6 - const SetLightStatusBarRefCountContext = createContext<React.Dispatch< 7 - React.SetStateAction<number> 8 - > | null>(null) 9 - 10 - export function useLightStatusBar() { 11 - return useContext(LightStatusBarRefCountContext) 12 - } 1 + import {useEffect} from 'react' 2 + import {SystemBars} from 'react-native-edge-to-edge' 13 3 14 4 export function useSetLightStatusBar(enabled: boolean) { 15 - const setRefCount = useContext(SetLightStatusBarRefCountContext) 16 5 useEffect(() => { 17 - // noop on web -sfn 18 - if (isWeb) return 19 - 20 - if (!setRefCount) { 21 - if (__DEV__) 22 - console.error( 23 - 'useLightStatusBar was used without a SetLightStatusBarRefCountContext provider', 24 - ) 25 - return 26 - } 27 6 if (enabled) { 28 - setRefCount(prev => prev + 1) 29 - return () => setRefCount(prev => prev - 1) 7 + const entry = SystemBars.pushStackEntry({ 8 + style: { 9 + statusBar: 'light', 10 + }, 11 + }) 12 + return () => { 13 + SystemBars.popStackEntry(entry) 14 + } 30 15 } 31 - }, [enabled, setRefCount]) 32 - } 33 - 34 - export function Provider({children}: React.PropsWithChildren<{}>) { 35 - const [refCount, setRefCount] = useState(0) 36 - 37 - return ( 38 - <SetLightStatusBarRefCountContext.Provider value={setRefCount}> 39 - <LightStatusBarRefCountContext.Provider value={refCount > 0}> 40 - {children} 41 - </LightStatusBarRefCountContext.Provider> 42 - </SetLightStatusBarRefCountContext.Provider> 43 - ) 16 + }, [enabled]) 44 17 }
+1 -2
src/view/com/composer/Composer.tsx
··· 1464 1464 1465 1465 // Android etc 1466 1466 if (!isIOS) { 1467 - // if Android <35 or web, bottom is 0 anyway. if >=35, this is needed to account 1468 - // for the edge-to-edge nav bar 1467 + // need to account for the edge-to-edge nav bar 1469 1468 return bottom * -1 1470 1469 } 1471 1470
+21 -35
src/view/com/lightbox/ImageViewing/index.tsx
··· 9 9 // https://github.com/jobtoday/react-native-image-viewing 10 10 11 11 import React, {useCallback, useEffect, useMemo, useState} from 'react' 12 - import { 13 - LayoutAnimation, 14 - PixelRatio, 15 - Platform, 16 - StyleSheet, 17 - View, 18 - } from 'react-native' 12 + import {LayoutAnimation, PixelRatio, StyleSheet, View} from 'react-native' 13 + import {SystemBars} from 'react-native-edge-to-edge' 19 14 import {Gesture} from 'react-native-gesture-handler' 20 15 import PagerView from 'react-native-pager-view' 21 16 import Animated, { 22 - AnimatedRef, 17 + type AnimatedRef, 23 18 cancelAnimation, 24 19 interpolate, 25 20 measure, 26 21 runOnJS, 27 - SharedValue, 22 + type SharedValue, 28 23 useAnimatedReaction, 29 24 useAnimatedRef, 30 25 useAnimatedStyle, ··· 32 27 useSharedValue, 33 28 withDecay, 34 29 withSpring, 35 - WithSpringConfig, 30 + type WithSpringConfig, 36 31 } from 'react-native-reanimated' 37 32 import { 38 - Edge, 39 33 SafeAreaView, 40 34 useSafeAreaFrame, 41 35 useSafeAreaInsets, 42 36 } from 'react-native-safe-area-context' 43 37 import * as ScreenOrientation from 'expo-screen-orientation' 44 - import {StatusBar} from 'expo-status-bar' 45 38 import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' 46 39 import {Trans} from '@lingui/macro' 47 40 48 - import {Dimensions} from '#/lib/media/types' 41 + import {type Dimensions} from '#/lib/media/types' 49 42 import {colors, s} from '#/lib/styles' 50 43 import {isIOS} from '#/platform/detection' 51 - import {Lightbox} from '#/state/lightbox' 44 + import {type Lightbox} from '#/state/lightbox' 52 45 import {Button} from '#/view/com/util/forms/Button' 53 46 import {Text} from '#/view/com/util/text/Text' 54 47 import {ScrollView} from '#/view/com/util/Views' 55 - import {ios, useTheme} from '#/alf' 56 - import {setNavigationBar} from '#/alf/util/navigationBar' 48 + import {useTheme} from '#/alf' 49 + import {setSystemUITheme} from '#/alf/util/systemUI' 57 50 import {PlatformInfo} from '../../../../../modules/expo-bluesky-swiss-army' 58 - import {ImageSource, Transform} from './@types' 51 + import {type ImageSource, type Transform} from './@types' 59 52 import ImageDefaultHeader from './components/ImageDefaultHeader' 60 53 import ImageItem from './components/ImageItem/ImageItem' 61 54 ··· 63 56 64 57 const PORTRAIT_UP = ScreenOrientation.OrientationLock.PORTRAIT_UP 65 58 const PIXEL_RATIO = PixelRatio.get() 66 - const EDGES = 67 - Platform.OS === 'android' && Platform.Version < 35 68 - ? (['top', 'bottom', 'left', 'right'] satisfies Edge[]) 69 - : ([] satisfies Edge[]) // iOS or Android 15+ bleeds into safe area 70 59 71 60 const SLOW_SPRING: WithSpringConfig = { 72 61 mass: isIOS ? 1.25 : 0.75, ··· 167 156 168 157 return ( 169 158 // Keep it always mounted to avoid flicker on the first frame. 170 - <SafeAreaView 159 + <View 171 160 style={[styles.screen, !activeLightbox && styles.screenHidden]} 172 - edges={EDGES} 173 161 aria-modal 174 162 accessibilityViewIsModal 175 163 aria-hidden={!activeLightbox}> ··· 197 185 /> 198 186 )} 199 187 </Animated.View> 200 - </SafeAreaView> 188 + </View> 201 189 ) 202 190 } 203 191 ··· 325 313 }, 326 314 ) 327 315 328 - // style nav bar on android 316 + // style system ui on android 329 317 const t = useTheme() 330 318 useEffect(() => { 331 - setNavigationBar('lightbox', t) 319 + setSystemUITheme('lightbox', t) 332 320 return () => { 333 - setNavigationBar('theme', t) 321 + setSystemUITheme('theme', t) 334 322 } 335 323 }, [t]) 336 324 337 325 return ( 338 326 <Animated.View style={[styles.container, containerStyle]}> 339 - <StatusBar 340 - animated 341 - style="light" 342 - hideTransitionAnimation="slide" 343 - backgroundColor="black" 344 - // hiding causes layout shifts on android, 345 - // so avoid until we add edge-to-edge mode 346 - hidden={ios(isScaled || !showControls)} 327 + <SystemBars 328 + style={{statusBar: 'light', navigationBar: 'light'}} 329 + hidden={{ 330 + statusBar: isScaled || !showControls, 331 + navigationBar: false, 332 + }} 347 333 /> 348 334 <Animated.View 349 335 style={[styles.backdrop, backdropStyle]}
+2 -2
src/view/com/modals/CreateOrEditList.tsx
··· 8 8 TouchableOpacity, 9 9 View, 10 10 } from 'react-native' 11 - import {Image as RNImage} from 'react-native-image-crop-picker' 11 + import {type Image as RNImage} from 'react-native-image-crop-picker' 12 12 import {LinearGradient} from 'expo-linear-gradient' 13 - import {AppBskyGraphDefs, RichText as RichTextAPI} from '@atproto/api' 13 + import {type AppBskyGraphDefs, RichText as RichTextAPI} from '@atproto/api' 14 14 import {msg, Trans} from '@lingui/macro' 15 15 import {useLingui} from '@lingui/react' 16 16
+11 -14
src/view/shell/index.tsx
··· 1 1 import {useCallback, useEffect, useState} from 'react' 2 2 import {BackHandler, useWindowDimensions, View} from 'react-native' 3 3 import {Drawer} from 'react-native-drawer-layout' 4 + import {SystemBars} from 'react-native-edge-to-edge' 4 5 import {Gesture} from 'react-native-gesture-handler' 5 6 import {useSafeAreaInsets} from 'react-native-safe-area-context' 6 - import {StatusBar} from 'expo-status-bar' 7 7 import {useNavigation, useNavigationState} from '@react-navigation/native' 8 8 9 9 import {useDedupe} from '#/lib/hooks/useDedupe' ··· 19 19 useIsDrawerSwipeDisabled, 20 20 useSetDrawerOpen, 21 21 } from '#/state/shell' 22 - import {useLightStatusBar} from '#/state/shell/light-status-bar' 23 22 import {useCloseAnyActiveElement} from '#/state/util' 24 23 import {Lightbox} from '#/view/com/lightbox/Lightbox' 25 24 import {ModalsContainer} from '#/view/com/modals/Modal' 26 25 import {ErrorBoundary} from '#/view/com/util/ErrorBoundary' 27 26 import {atoms as a, select, useTheme} from '#/alf' 28 - import {setNavigationBar} from '#/alf/util/navigationBar' 27 + import {setSystemUITheme} from '#/alf/util/systemUI' 29 28 import {MutedWordsDialog} from '#/components/dialogs/MutedWords' 30 29 import {SigninDialog} from '#/components/dialogs/Signin' 31 30 import {Outlet as PortalOutlet} from '#/components/Portal' ··· 161 160 162 161 export const Shell: React.FC = function ShellImpl() { 163 162 const {fullyExpandedCount} = useDialogStateControlContext() 164 - const lightStatusBar = useLightStatusBar() 165 163 const t = useTheme() 166 164 useIntentHandler() 167 165 168 166 useEffect(() => { 169 - setNavigationBar('theme', t) 167 + setSystemUITheme('theme', t) 170 168 }, [t]) 171 169 172 170 return ( 173 171 <View testID="mobileShellView" style={[a.h_full, t.atoms.bg]}> 174 - <StatusBar 175 - style={ 176 - t.name !== 'light' || 177 - (isIOS && fullyExpandedCount > 0) || 178 - lightStatusBar 179 - ? 'light' 180 - : 'dark' 181 - } 182 - animated 172 + <SystemBars 173 + style={{ 174 + statusBar: 175 + t.name !== 'light' || (isIOS && fullyExpandedCount > 0) 176 + ? 'light' 177 + : 'dark', 178 + navigationBar: t.name !== 'light' ? 'light' : 'dark', 179 + }} 183 180 /> 184 181 <RoutesContainer> 185 182 <ShellInner />
+9 -17
yarn.lock
··· 11067 11067 dependencies: 11068 11068 invariant "^2.2.4" 11069 11069 11070 - expo-navigation-bar@~4.0.9: 11071 - version "4.0.9" 11072 - resolved "https://registry.yarnpkg.com/expo-navigation-bar/-/expo-navigation-bar-4.0.9.tgz#e0409c2db8f6384d12c87f45c2674effc9fae1b6" 11073 - integrity sha512-dCJ04yPixFOUixJaWlmCZafGeQ1L1g6vWn+oX8rqPnYN9kYCMUz2aRNnhRRoK5MBGFTK/nue2D49TE/AwwWt9w== 11074 - dependencies: 11075 - "@react-native/normalize-colors" "0.76.8" 11076 - debug "^4.3.2" 11077 - 11078 11070 expo-notifications@~0.29.14: 11079 11071 version "0.29.14" 11080 11072 resolved "https://registry.yarnpkg.com/expo-notifications/-/expo-notifications-0.29.14.tgz#77beb6bc74b1b1abfa3adcab77fb6c9ea5d7d1b0" ··· 11114 11106 integrity sha512-f+bPpF06bqiuW1Fbrd3nxeaSsmTVTBEKEYe3epYt4IE6y4Ulli3qEUamMLlRQiDGuIXPU6zQlscpy2mdBUI5cA== 11115 11107 dependencies: 11116 11108 "@expo/prebuild-config" "^8.0.27" 11117 - 11118 - expo-status-bar@~2.0.1: 11119 - version "2.0.1" 11120 - resolved "https://registry.yarnpkg.com/expo-status-bar/-/expo-status-bar-2.0.1.tgz#fc07726346dc30fbb68aadb0d7890b34fba42eee" 11121 - integrity sha512-AkIPX7jWHRPp83UBZ1iXtVvyr0g+DgBVvIXTtlmPtmUsm8Vq9Bb5IGj86PW8osuFlgoTVAg7HI/+Ok7yEYwiRg== 11122 11109 11123 11110 expo-structured-headers@~4.0.0: 11124 11111 version "4.0.0" ··· 16761 16748 dependencies: 16762 16749 use-latest-callback "^0.2.1" 16763 16750 16751 + react-native-edge-to-edge@^1.6.0: 16752 + version "1.6.0" 16753 + resolved "https://registry.yarnpkg.com/react-native-edge-to-edge/-/react-native-edge-to-edge-1.6.0.tgz#2ba63b941704a7f713e298185c26cde4d9e4b973" 16754 + integrity sha512-2WCNdE3Qd6Fwg9+4BpbATUxCLcouF6YRY7K+J36KJ4l3y+tWN6XCqAC4DuoGblAAbb2sLkhEDp4FOlbOIot2Og== 16755 + 16764 16756 react-native-emoji-popup@^0.1.2: 16765 16757 version "0.1.2" 16766 16758 resolved "https://registry.yarnpkg.com/react-native-emoji-popup/-/react-native-emoji-popup-0.1.2.tgz#7cd3874ba0496031e6f3e24de77e0df895168ce6" ··· 16807 16799 resolved "https://registry.yarnpkg.com/react-native-is-edge-to-edge/-/react-native-is-edge-to-edge-1.1.6.tgz#69ec13f70d76e9245e275eed4140d0873a78f902" 16808 16800 integrity sha512-1pHnFTlBahins6UAajXUqeCOHew9l9C2C8tErnpGC3IyLJzvxD+TpYAixnCbrVS52f7+NvMttbiSI290XfwN0w== 16809 16801 16810 - react-native-keyboard-controller@^1.14.5: 16811 - version "1.14.5" 16812 - resolved "https://registry.yarnpkg.com/react-native-keyboard-controller/-/react-native-keyboard-controller-1.14.5.tgz#ec1e7d1fb8ee18b69ced4d8ddd6fd99bdaaf14bb" 16813 - integrity sha512-Cx7+SWI/P50i4PKJZN4T43RqoFkJ3GBoxjQ5ysrzZGoImHTF4j3atSwcBQGMmunKCem1yGOOQ84or+Vbcor6wQ== 16802 + react-native-keyboard-controller@^1.17.1: 16803 + version "1.17.1" 16804 + resolved "https://registry.yarnpkg.com/react-native-keyboard-controller/-/react-native-keyboard-controller-1.17.1.tgz#46efe148c1bdd0ee22094dcb2660f70f81e6544e" 16805 + integrity sha512-YM3GYvtkuWimCKkZFURn5hIb1WiKOQqi2DijdwZSF5QSSzGqfqwzEEC3bm1xCN8HGHAEIXAaWIBUsc3Xp5L+Ng== 16814 16806 dependencies: 16815 16807 react-native-is-edge-to-edge "^1.1.6" 16816 16808