Bluesky app fork with some witchin' additions 💫
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Unlock orientation when lightbox is open (#7257)

* unlock orientation when lightbox is open

* rm outer safe area view, make sure alt text is safe

* restore safe area view for android 14 and below

* lock orientation on launch for android

* set system ui background to black when lightbox is open

* reset state on relayout

* catch async functions with noops

* rm superfluous catches

* Delay unlock until after animation

* Simplify how key is determined

* Make landscape backdrop opaque

---------

Co-authored-by: Dan Abramov <dan.abramov@gmail.com>

authored by

Samuel Newman
Dan Abramov
and committed by
GitHub
6c9e1d48 f05962a4

+51 -6
+1 -1
app.config.js
··· 50 50 runtimeVersion: { 51 51 policy: 'appVersion', 52 52 }, 53 - orientation: 'portrait', 54 53 icon: './assets/app-icons/ios_icon_default_light.png', 55 54 userInterfaceStyle: 'automatic', 56 55 primaryColor: '#1083fe', ··· 346 345 }, 347 346 }, 348 347 ], 348 + ['expo-screen-orientation', {initialOrientation: 'PORTRAIT_UP'}], 349 349 ].filter(Boolean), 350 350 extra: { 351 351 eas: {
+1
package.json
··· 138 138 "expo-media-library": "~17.0.3", 139 139 "expo-navigation-bar": "~4.0.4", 140 140 "expo-notifications": "~0.29.11", 141 + "expo-screen-orientation": "^8.0.2", 141 142 "expo-sharing": "^13.0.0", 142 143 "expo-splash-screen": "~0.29.18", 143 144 "expo-status-bar": "~2.0.0",
+6 -1
src/App.native.tsx
··· 10 10 initialWindowMetrics, 11 11 SafeAreaProvider, 12 12 } from 'react-native-safe-area-context' 13 + import * as ScreenOrientation from 'expo-screen-orientation' 13 14 import * as SplashScreen from 'expo-splash-screen' 14 15 import * as SystemUI from 'expo-system-ui' 15 16 import {msg} from '@lingui/macro' ··· 22 23 import {ThemeProvider} from '#/lib/ThemeContext' 23 24 import I18nProvider from '#/locale/i18nProvider' 24 25 import {logger} from '#/logger' 25 - import {isIOS} from '#/platform/detection' 26 + import {isAndroid, isIOS} from '#/platform/detection' 26 27 import {Provider as A11yProvider} from '#/state/a11y' 27 28 import {Provider as MutedThreadsProvider} from '#/state/cache/thread-mutes' 28 29 import {Provider as DialogStateProvider} from '#/state/dialogs' ··· 76 77 SplashScreen.preventAutoHideAsync() 77 78 if (isIOS) { 78 79 SystemUI.setBackgroundColorAsync('black') 80 + } 81 + if (isAndroid) { 82 + // iOS is handled by the config plugin -sfn 83 + ScreenOrientation.lockAsync(ScreenOrientation.OrientationLock.PORTRAIT_UP) 79 84 } 80 85 81 86 /**
+3
src/alf/util/navigationBar.ts
··· 1 1 import * as NavigationBar from 'expo-navigation-bar' 2 + import * as SystemUI from 'expo-system-ui' 2 3 3 4 import {isAndroid} from '#/platform/detection' 4 5 import {Theme} from '../types' ··· 9 10 NavigationBar.setBackgroundColorAsync(t.atoms.bg.backgroundColor) 10 11 NavigationBar.setBorderColorAsync(t.atoms.bg.backgroundColor) 11 12 NavigationBar.setButtonStyleAsync(t.name !== 'light' ? 'light' : 'dark') 13 + SystemUI.setBackgroundColorAsync(t.atoms.bg.backgroundColor) 12 14 } else { 13 15 NavigationBar.setBackgroundColorAsync('black') 14 16 NavigationBar.setBorderColorAsync('black') 15 17 NavigationBar.setButtonStyleAsync('light') 18 + SystemUI.setBackgroundColorAsync('black') 16 19 } 17 20 } 18 21 }
+35 -4
src/view/com/lightbox/ImageViewing/index.tsx
··· 40 40 useSafeAreaFrame, 41 41 useSafeAreaInsets, 42 42 } from 'react-native-safe-area-context' 43 + import * as ScreenOrientation from 'expo-screen-orientation' 43 44 import {StatusBar} from 'expo-status-bar' 44 45 import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' 45 46 import {Trans} from '@lingui/macro' ··· 60 61 61 62 type Rect = {x: number; y: number; width: number; height: number} 62 63 64 + const PORTRAIT_UP = ScreenOrientation.OrientationLock.PORTRAIT_UP 63 65 const PIXEL_RATIO = PixelRatio.get() 64 66 const EDGES = 65 67 Platform.OS === 'android' && Platform.Version < 35 66 68 ? (['top', 'bottom', 'left', 'right'] satisfies Edge[]) 67 - : (['left', 'right'] satisfies Edge[]) // iOS or Android 15+, so no top/bottom safe area 69 + : ([] satisfies Edge[]) // iOS or Android 15+ bleeds into safe area 68 70 69 71 const SLOW_SPRING: WithSpringConfig = { 70 72 mass: isIOS ? 1.25 : 0.75, ··· 102 104 'use no memo' 103 105 const ref = useAnimatedRef<View>() 104 106 const [activeLightbox, setActiveLightbox] = useState(nextLightbox) 107 + const [orientation, setOrientation] = useState<'portrait' | 'landscape'>( 108 + 'portrait', 109 + ) 105 110 const openProgress = useSharedValue(0) 106 111 107 112 if (!activeLightbox && nextLightbox) { ··· 140 145 }, 141 146 ) 142 147 148 + // Delay the unlock until after we've finished the scale up animation. 149 + // It's complicated to do the same for locking it back so we don't attempt that. 150 + useAnimatedReaction( 151 + () => openProgress.get() === 1, 152 + (isOpen, wasOpen) => { 153 + if (isOpen && !wasOpen) { 154 + runOnJS(ScreenOrientation.unlockAsync)() 155 + } else if (!isOpen && wasOpen) { 156 + // default is PORTRAIT_UP - set via config plugin in app.config.js -sfn 157 + runOnJS(ScreenOrientation.lockAsync)(PORTRAIT_UP) 158 + } 159 + }, 160 + ) 161 + 143 162 const onFlyAway = React.useCallback(() => { 144 163 'worklet' 145 164 openProgress.set(0) ··· 154 173 aria-modal 155 174 accessibilityViewIsModal 156 175 aria-hidden={!activeLightbox}> 157 - <Animated.View ref={ref} style={{flex: 1}} collapsable={false}> 176 + <Animated.View 177 + ref={ref} 178 + style={{flex: 1}} 179 + collapsable={false} 180 + onLayout={e => { 181 + const layout = e.nativeEvent.layout 182 + setOrientation( 183 + layout.height > layout.width ? 'portrait' : 'landscape', 184 + ) 185 + }}> 158 186 {activeLightbox && ( 159 187 <ImageView 160 - key={activeLightbox.id} 188 + key={activeLightbox.id + '-' + orientation} 161 189 lightbox={activeLightbox} 190 + orientation={orientation} 162 191 onRequestClose={onRequestClose} 163 192 onPressSave={onPressSave} 164 193 onPressShare={onPressShare} ··· 174 203 175 204 function ImageView({ 176 205 lightbox, 206 + orientation, 177 207 onRequestClose, 178 208 onPressSave, 179 209 onPressShare, ··· 182 212 openProgress, 183 213 }: { 184 214 lightbox: Lightbox 215 + orientation: 'portrait' | 'landscape' 185 216 onRequestClose: () => void 186 217 onPressSave: (uri: string) => void 187 218 onPressShare: (uri: string) => void ··· 221 252 const openProgressValue = openProgress.get() 222 253 if (openProgressValue < 1) { 223 254 opacity = Math.sqrt(openProgressValue) 224 - } else if (screenSize) { 255 + } else if (screenSize && orientation === 'portrait') { 225 256 const dragProgress = Math.min( 226 257 Math.abs(dismissSwipeTranslateY.get()) / (screenSize.height / 2), 227 258 1,
+5
yarn.lock
··· 10621 10621 commander "2.20.0" 10622 10622 update-check "1.5.3" 10623 10623 10624 + expo-screen-orientation@^8.0.2: 10625 + version "8.0.2" 10626 + resolved "https://registry.yarnpkg.com/expo-screen-orientation/-/expo-screen-orientation-8.0.2.tgz#69139a1967557a331188d36b4dd615a0e220c2a0" 10627 + integrity sha512-YsY7Oumlv1WsHLQVgl1f+vAiMZfzUPGyVF2xc7jxmHKtM+jMzIflDl2qKLGfoB0S9Pgg6Z8V4+c+A8wlCURw4A== 10628 + 10624 10629 expo-sharing@^13.0.0: 10625 10630 version "13.0.0" 10626 10631 resolved "https://registry.yarnpkg.com/expo-sharing/-/expo-sharing-13.0.0.tgz#fbc46f4afdaa265a2811fe88c2a589aae2d2de0f"