diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/App.native.tsx | 7 | ||||
-rw-r--r-- | src/alf/util/navigationBar.ts | 3 | ||||
-rw-r--r-- | src/view/com/lightbox/ImageViewing/index.tsx | 39 |
3 files changed, 44 insertions, 5 deletions
diff --git a/src/App.native.tsx b/src/App.native.tsx index 780295ddc..d1d6b7213 100644 --- a/src/App.native.tsx +++ b/src/App.native.tsx @@ -10,6 +10,7 @@ import { initialWindowMetrics, SafeAreaProvider, } from 'react-native-safe-area-context' +import * as ScreenOrientation from 'expo-screen-orientation' import * as SplashScreen from 'expo-splash-screen' import * as SystemUI from 'expo-system-ui' import {msg} from '@lingui/macro' @@ -22,7 +23,7 @@ import {s} from '#/lib/styles' import {ThemeProvider} from '#/lib/ThemeContext' import I18nProvider from '#/locale/i18nProvider' import {logger} from '#/logger' -import {isIOS} from '#/platform/detection' +import {isAndroid, isIOS} from '#/platform/detection' import {Provider as A11yProvider} from '#/state/a11y' import {Provider as MutedThreadsProvider} from '#/state/cache/thread-mutes' import {Provider as DialogStateProvider} from '#/state/dialogs' @@ -77,6 +78,10 @@ SplashScreen.preventAutoHideAsync() if (isIOS) { SystemUI.setBackgroundColorAsync('black') } +if (isAndroid) { + // iOS is handled by the config plugin -sfn + ScreenOrientation.lockAsync(ScreenOrientation.OrientationLock.PORTRAIT_UP) +} /** * Begin geolocation ASAP diff --git a/src/alf/util/navigationBar.ts b/src/alf/util/navigationBar.ts index face86983..cb315f70a 100644 --- a/src/alf/util/navigationBar.ts +++ b/src/alf/util/navigationBar.ts @@ -1,4 +1,5 @@ import * as NavigationBar from 'expo-navigation-bar' +import * as SystemUI from 'expo-system-ui' import {isAndroid} from '#/platform/detection' import {Theme} from '../types' @@ -9,10 +10,12 @@ export function setNavigationBar(themeType: 'theme' | 'lightbox', t: Theme) { NavigationBar.setBackgroundColorAsync(t.atoms.bg.backgroundColor) NavigationBar.setBorderColorAsync(t.atoms.bg.backgroundColor) NavigationBar.setButtonStyleAsync(t.name !== 'light' ? 'light' : 'dark') + SystemUI.setBackgroundColorAsync(t.atoms.bg.backgroundColor) } else { NavigationBar.setBackgroundColorAsync('black') NavigationBar.setBorderColorAsync('black') NavigationBar.setButtonStyleAsync('light') + SystemUI.setBackgroundColorAsync('black') } } } 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<View>() 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}> - <Animated.View ref={ref} style={{flex: 1}} collapsable={false}> + <Animated.View + ref={ref} + style={{flex: 1}} + collapsable={false} + onLayout={e => { + const layout = e.nativeEvent.layout + setOrientation( + layout.height > layout.width ? 'portrait' : 'landscape', + ) + }}> {activeLightbox && ( <ImageView - key={activeLightbox.id} + key={activeLightbox.id + '-' + orientation} lightbox={activeLightbox} + orientation={orientation} onRequestClose={onRequestClose} onPressSave={onPressSave} onPressShare={onPressShare} @@ -174,6 +203,7 @@ export default function ImageViewRoot({ function ImageView({ lightbox, + orientation, onRequestClose, onPressSave, onPressShare, @@ -182,6 +212,7 @@ function ImageView({ openProgress, }: { lightbox: Lightbox + orientation: 'portrait' | 'landscape' onRequestClose: () => 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, |