From 6c9e1d4837e9e385da5ca0c89c28000ad25c70d8 Mon Sep 17 00:00:00 2001 From: Samuel Newman Date: Tue, 24 Dec 2024 20:05:54 +0000 Subject: 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 --- src/view/com/lightbox/ImageViewing/index.tsx | 39 +++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 4 deletions(-) (limited to 'src/view/com/lightbox/ImageViewing/index.tsx') diff --git a/src/view/com/lightbox/ImageViewing/index.tsx b/src/view/com/lightbox/ImageViewing/index.tsx index 96f78a709..7018d753a 100644 --- a/src/view/com/lightbox/ImageViewing/index.tsx +++ b/src/view/com/lightbox/ImageViewing/index.tsx @@ -40,6 +40,7 @@ import { useSafeAreaFrame, useSafeAreaInsets, } from 'react-native-safe-area-context' +import * as ScreenOrientation from 'expo-screen-orientation' import {StatusBar} from 'expo-status-bar' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {Trans} from '@lingui/macro' @@ -60,11 +61,12 @@ import ImageItem from './components/ImageItem/ImageItem' type Rect = {x: number; y: number; width: number; height: number} +const PORTRAIT_UP = ScreenOrientation.OrientationLock.PORTRAIT_UP const PIXEL_RATIO = PixelRatio.get() const EDGES = Platform.OS === 'android' && Platform.Version < 35 ? (['top', 'bottom', 'left', 'right'] satisfies Edge[]) - : (['left', 'right'] satisfies Edge[]) // iOS or Android 15+, so no top/bottom safe area + : ([] satisfies Edge[]) // iOS or Android 15+ bleeds into safe area const SLOW_SPRING: WithSpringConfig = { mass: isIOS ? 1.25 : 0.75, @@ -102,6 +104,9 @@ export default function ImageViewRoot({ 'use no memo' const ref = useAnimatedRef() const [activeLightbox, setActiveLightbox] = useState(nextLightbox) + const [orientation, setOrientation] = useState<'portrait' | 'landscape'>( + 'portrait', + ) const openProgress = useSharedValue(0) if (!activeLightbox && nextLightbox) { @@ -140,6 +145,20 @@ export default function ImageViewRoot({ }, ) + // Delay the unlock until after we've finished the scale up animation. + // It's complicated to do the same for locking it back so we don't attempt that. + useAnimatedReaction( + () => openProgress.get() === 1, + (isOpen, wasOpen) => { + if (isOpen && !wasOpen) { + runOnJS(ScreenOrientation.unlockAsync)() + } else if (!isOpen && wasOpen) { + // default is PORTRAIT_UP - set via config plugin in app.config.js -sfn + runOnJS(ScreenOrientation.lockAsync)(PORTRAIT_UP) + } + }, + ) + const onFlyAway = React.useCallback(() => { 'worklet' openProgress.set(0) @@ -154,11 +173,21 @@ export default function ImageViewRoot({ aria-modal accessibilityViewIsModal aria-hidden={!activeLightbox}> - + { + const layout = e.nativeEvent.layout + setOrientation( + layout.height > layout.width ? 'portrait' : 'landscape', + ) + }}> {activeLightbox && ( void onPressSave: (uri: string) => void onPressShare: (uri: string) => void @@ -221,7 +252,7 @@ function ImageView({ const openProgressValue = openProgress.get() if (openProgressValue < 1) { opacity = Math.sqrt(openProgressValue) - } else if (screenSize) { + } else if (screenSize && orientation === 'portrait') { const dragProgress = Math.min( Math.abs(dismissSwipeTranslateY.get()) / (screenSize.height / 2), 1, -- cgit 1.4.1