mirror of
https://github.com/getpaseo/paseo.git
synced 2026-10-30 13:13:25 +00:00
Follow system rotation on mobile devices (#8256)
The app no longer locks to portrait. Phones and tablets on Android and iOS follow the device rotation and respect the system rotation lock, so Android tablets fill the display in landscape instead of letterboxing. Modals pass all orientations explicitly because React Native presents iPhone modals in portrait by default. Closes #1669 Co-authored-by: yz <43207690+yzim@users.noreply.github.com> Co-authored-by: magiclaw <930198090@qq.com>
This commit is contained in:
co-authored by
yz
magiclaw
parent
c663630bbd
commit
a8e0effb32
@@ -102,7 +102,7 @@ export default {
|
||||
name: variant.name,
|
||||
slug: "voice-mobile",
|
||||
version: nativeReleaseVersion.appVersion,
|
||||
orientation: "portrait",
|
||||
orientation: "default",
|
||||
icon: "./assets/images/icon.png",
|
||||
scheme: "paseo",
|
||||
userInterfaceStyle: "automatic",
|
||||
|
||||
@@ -59,3 +59,38 @@ describe("Android app config", () => {
|
||||
30_000,
|
||||
);
|
||||
});
|
||||
|
||||
it("follows system rotation on Android", async () => {
|
||||
const manifest = await resolveAndroidManifest();
|
||||
const activity = manifest.application[0].activity.find(
|
||||
(entry: ManifestEntry) => entry.$["android:name"] === ".MainActivity",
|
||||
);
|
||||
expect(activity.$["android:screenOrientation"]).toBe("unspecified");
|
||||
}, 30_000);
|
||||
|
||||
it("allows all orientations on iPhone and iPad", async () => {
|
||||
const { mkdtemp, rm } = await import("node:fs/promises");
|
||||
const { tmpdir } = await import("node:os");
|
||||
const { join } = await import("node:path");
|
||||
const root = await mkdtemp(join(tmpdir(), "paseo-ios-config-"));
|
||||
try {
|
||||
const { exp } = await getPrebuildConfigAsync(__dirname, { platforms: ["ios"] });
|
||||
await compileModsAsync(exp, {
|
||||
projectRoot: root,
|
||||
introspect: true,
|
||||
platforms: ["ios"],
|
||||
assertMissingModProviders: false,
|
||||
});
|
||||
const plist = exp._internal.modResults.ios.infoPlist;
|
||||
const orientations = [
|
||||
"UIInterfaceOrientationPortrait",
|
||||
"UIInterfaceOrientationPortraitUpsideDown",
|
||||
"UIInterfaceOrientationLandscapeLeft",
|
||||
"UIInterfaceOrientationLandscapeRight",
|
||||
];
|
||||
expect(plist.UISupportedInterfaceOrientations).toEqual(orientations);
|
||||
expect(plist["UISupportedInterfaceOrientations~ipad"]).toEqual(orientations);
|
||||
} finally {
|
||||
await rm(root, { recursive: true, force: true });
|
||||
}
|
||||
}, 30_000);
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Modal } from "@/components/ui/modal";
|
||||
import equal from "fast-deep-equal";
|
||||
import { recordRenderProfileReasons } from "@/utils/render-profiler";
|
||||
import {
|
||||
FlatList,
|
||||
Modal,
|
||||
Pressable,
|
||||
Text,
|
||||
View,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { Modal } from "@/components/ui/modal";
|
||||
import { usePanelStore } from "@/stores/panel-store";
|
||||
import { getHostRuntimeStore } from "@/runtime/host-runtime";
|
||||
import { router } from "expo-router";
|
||||
@@ -22,14 +23,7 @@ import {
|
||||
type ComponentType,
|
||||
type RefObject,
|
||||
} from "react";
|
||||
import {
|
||||
Modal,
|
||||
Pressable,
|
||||
ScrollView,
|
||||
Text,
|
||||
View,
|
||||
type PressableStateCallbackType,
|
||||
} from "react-native";
|
||||
import { Pressable, ScrollView, Text, View, type PressableStateCallbackType } from "react-native";
|
||||
import {
|
||||
EditingTextInput as TextInput,
|
||||
type EditingTextInputHandle,
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Modal } from "@/components/ui/modal";
|
||||
import {
|
||||
View,
|
||||
Text,
|
||||
Pressable,
|
||||
Modal,
|
||||
RefreshControl,
|
||||
FlatList,
|
||||
type ListRenderItem,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Modal } from "@/components/ui/modal";
|
||||
import { type ReactNode, useCallback, useEffect, useMemo, useState } from "react";
|
||||
import { Modal, Pressable, Text, View } from "react-native";
|
||||
import { Pressable, Text, View } from "react-native";
|
||||
import { GestureHandlerRootView } from "react-native-gesture-handler";
|
||||
import { StyleSheet } from "react-native-unistyles";
|
||||
import { SafeAreaProvider, useSafeAreaInsets } from "react-native-safe-area-context";
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Modal } from "@/components/ui/modal";
|
||||
import { useCallback, useEffect, useMemo, useRef } from "react";
|
||||
import { Modal, View } from "react-native";
|
||||
import { View } from "react-native";
|
||||
import { X } from "lucide-react-native";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { StyleSheet } from "react-native-unistyles";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Modal } from "@/components/ui/modal";
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||
import {
|
||||
Modal,
|
||||
Pressable,
|
||||
StyleSheet as RNStyleSheet,
|
||||
ScrollView,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { Modal } from "@/components/ui/modal";
|
||||
import {
|
||||
useCallback,
|
||||
useEffect,
|
||||
@@ -12,7 +13,6 @@ import {
|
||||
View,
|
||||
Text,
|
||||
Pressable,
|
||||
Modal,
|
||||
ScrollView,
|
||||
Platform,
|
||||
StatusBar,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { Modal } from "@/components/ui/modal";
|
||||
import {
|
||||
useCallback,
|
||||
useEffect,
|
||||
@@ -12,7 +13,6 @@ import { createPortal } from "react-dom";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import {
|
||||
Dimensions,
|
||||
Modal,
|
||||
Platform,
|
||||
Pressable,
|
||||
View,
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import { Modal as NativeModal, type ModalProps } from "react-native";
|
||||
|
||||
// React Native defaults iPhone modals to portrait even when the app supports rotation.
|
||||
const orientations: NonNullable<ModalProps["supportedOrientations"]> = [
|
||||
"portrait",
|
||||
"portrait-upside-down",
|
||||
"landscape-left",
|
||||
"landscape-right",
|
||||
];
|
||||
|
||||
export function Modal(props: ModalProps) {
|
||||
return <NativeModal supportedOrientations={orientations} {...props} />;
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
import { Modal } from "@/components/ui/modal";
|
||||
import {
|
||||
Children,
|
||||
cloneElement,
|
||||
@@ -16,7 +17,6 @@ import { createPortal } from "react-dom";
|
||||
import {
|
||||
Dimensions,
|
||||
Platform,
|
||||
Modal,
|
||||
Pressable,
|
||||
View,
|
||||
type PressableProps,
|
||||
|
||||
@@ -1,13 +1,7 @@
|
||||
import { Modal } from "@/components/ui/modal";
|
||||
import { usePanelStore } from "@/stores/panel-store";
|
||||
import { createElement, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||
import {
|
||||
Modal,
|
||||
Pressable,
|
||||
ScrollView,
|
||||
Text,
|
||||
View,
|
||||
type PressableStateCallbackType,
|
||||
} from "react-native";
|
||||
import { Pressable, ScrollView, Text, View, type PressableStateCallbackType } from "react-native";
|
||||
import {
|
||||
EditingTextInput as TextInput,
|
||||
type EditingTextInputHandle,
|
||||
|
||||
Reference in New Issue
Block a user