mobile: fix orientation changing and fullscreen mode on tablets

This commit is contained in:
Ammar Ahmed
2025-12-02 14:01:51 +05:00
parent 8e5743f417
commit c957094b1e
5 changed files with 97 additions and 137 deletions

View File

@@ -111,7 +111,6 @@ export const FluidPanels = forwardRef<TabsRef, TabProps>(function FluidTabs(
const containerWidth = widths
? widths.sidebar + widths.list + widths.editor
: dimensions.width;
const drawerPosition = 0;
const homePosition = widths.sidebar;
const editorPosition = widths.sidebar + widths.list;
@@ -440,15 +439,7 @@ export const FluidPanels = forwardRef<TabsRef, TabProps>(function FluidTabs(
width: containerWidth,
flexDirection: "row"
},
deviceMode === "tablet"
? {
transform: [
{
translateX: 0
}
]
}
: animatedStyles
animatedStyles
]}
>
{children}

View File

@@ -58,6 +58,7 @@ import { Button } from "../ui/button";
import SettingsService from "../../services/settings";
import { isFeatureAvailable } from "@notesnook/common";
import PaywallSheet from "../sheets/paywall";
import useGlobalSafeAreaInsets from "../../hooks/use-global-safe-area-insets";
const renderScene = SceneMap({
home: SideMenuHome,
notebooks: SideMenuNotebooks,
@@ -68,6 +69,7 @@ const renderScene = SceneMap({
export const SideMenu = React.memo(
function SideMenu() {
const { colors } = useThemeColors();
const insets = useGlobalSafeAreaInsets();
const [index, setIndex] = React.useState(
SettingsService.getProperty("defaultSidebarTab")
);
@@ -87,10 +89,13 @@ export const SideMenu = React.memo(
]);
return (
<SafeAreaView
<View
style={{
flex: 1,
backgroundColor: colors.primary.background
backgroundColor: colors.primary.background,
paddingTop: insets.top,
paddingBottom: insets.bottom,
paddingLeft: insets.left
}}
>
<TabView
@@ -103,7 +108,7 @@ export const SideMenu = React.memo(
animationEnabled={false}
lazy
/>
</SafeAreaView>
</View>
);
},
() => true
@@ -351,9 +356,8 @@ const TabBar = (
color={colors.primary.icon}
onPress={async () => {
if (props.navigationState.index === 1) {
const notebooksFeature = await isFeatureAvailable(
"notebooks"
);
const notebooksFeature =
await isFeatureAvailable("notebooks");
if (!notebooksFeature.isAllowed) {
PaywallSheet.present(notebooksFeature);
return;

View File

@@ -29,7 +29,7 @@ import React, {
useRef,
useState
} from "react";
import { Dimensions, LayoutChangeEvent, Platform, View } from "react-native";
import { LayoutChangeEvent, View } from "react-native";
import Orientation, {
OrientationType,
useDeviceOrientationChange
@@ -39,7 +39,6 @@ import Animated, {
useSharedValue,
withTiming
} from "react-native-reanimated";
import { SafeAreaView } from "react-native-safe-area-context";
import { notesnook } from "../../e2e/test.ids";
import { db } from "../common/database";
import { FluidPanels } from "../components/fluid-panels";
@@ -69,15 +68,13 @@ import {
eOpenFullscreenEditor,
eUnlockNote
} from "../utils/events";
import { editorRef, fluidTabsRef } from "../utils/global-refs";
import { valueLimiter } from "../utils/functions";
import { fluidTabsRef } from "../utils/global-refs";
import { AppNavigationStack } from "./navigation-stack";
import type { PaneWidths } from "../screens/editor/wrapper";
const MOBILE_SIDEBAR_SIZE = 0.85;
const valueLimiter = (value: number, min: number, max: number) => {
return value < min ? min : value > max ? max : value;
};
let SideMenu: any = null;
let EditorWrapper: any = null;
@@ -93,7 +90,6 @@ export const FluidPanelsView = React.memo(
const insets = useGlobalSafeAreaInsets();
const animatedOpacity = useSharedValue(0);
const animatedTranslateY = useSharedValue(-9999);
const overlayRef = useRef<Animated.View>(null);
const [orientation, setOrientation] = useState<OrientationType>(
Orientation.getInitialOrientation()
@@ -102,10 +98,17 @@ export const FluidPanelsView = React.memo(
const [isLoading, setIsLoading] = useState(false);
useDeviceOrientationChange((o) => {
setOrientation(o);
if (
o !== OrientationType.UNKNOWN &&
o !== OrientationType["FACE-UP"] &&
o !== OrientationType["FACE-DOWN"] &&
o !== OrientationType["PORTRAIT-UPSIDEDOWN"]
) {
setOrientation(o);
}
});
const isLandscape = orientation.includes("LANDSCAPE");
console.log(orientation);
useEffect(() => {
if (!appLoading) {
@@ -147,16 +150,6 @@ export const FluidPanelsView = React.memo(
if (deviceMode === "smallTablet") {
fluidTabsRef.current?.openDrawer(false);
}
editorRef.current?.setNativeProps({
style: {
width: dimensions.width,
zIndex: 999,
paddingHorizontal:
deviceMode === "smallTablet"
? dimensions.width * 0
: dimensions.width * 0.15
}
});
}, [deviceMode, dimensions.width, setFullscreen]);
const closeFullScreenEditor = useCallback(
@@ -169,17 +162,6 @@ export const FluidPanelsView = React.memo(
editorController.current?.commands.updateSettings({
fullscreen: false
});
editorRef.current?.setNativeProps({
style: {
width:
_deviceMode === "smallTablet"
? dimensions.width -
valueLimiter(dimensions.width * 0.4, 300, 450)
: dimensions.width * 0.48,
zIndex: null,
paddingHorizontal: 0
}
});
if (_deviceMode === "smallTablet") {
fluidTabsRef.current?.goToIndex(1, false);
}
@@ -221,38 +203,8 @@ export const FluidPanelsView = React.memo(
(current: string | null, size: { width: number; height: number }) => {
setDeviceModeState(current);
const needsLayout = current !== deviceMode;
if (fullscreen && current !== "mobile") {
// Runs after size is set via state.
setTimeout(() => {
editorRef.current?.setNativeProps({
style: {
width: size.width,
zIndex: 999,
paddingHorizontal:
current === "smallTablet" ? size.width * 0 : size.width * 0.15
}
});
}, 1);
} else {
if (fullscreen) eSendEvent(eCloseFullscreenEditor, current);
editorRef.current?.setNativeProps({
style: {
position: "relative",
width:
current === "tablet"
? size.width * 0.48
: current === "smallTablet"
? size.width - valueLimiter(size.width * 0.4, 300, 450)
: size.width,
zIndex: null,
paddingHorizontal: 0
}
});
}
if (!needsLayout) {
return;
eSendEvent(eCloseFullscreenEditor, current);
}
const state = getAppState();
@@ -280,40 +232,42 @@ export const FluidPanelsView = React.memo(
}
break;
}
}, 32);
}, 400);
},
[deviceMode, fullscreen, setDeviceModeState]
);
const checkDeviceType = React.useCallback(
(size: { width: number; height: number }) => {
setDimensions({
width: size.width,
height: size.height
});
DDS.setSize(size, orientation);
const nextDeviceMode = DDS.isLargeTablet()
? "tablet"
: DDS.isSmallTab
? "smallTablet"
: "mobile";
setDeviceMode(nextDeviceMode, size);
},
[orientation, setDeviceMode, setDimensions]
);
useEffect(() => {
if (orientation !== "UNKNOWN") {
checkDeviceType(dimensions);
}
}, [orientation, dimensions]);
const _onLayout = React.useCallback(
(event: LayoutChangeEvent) => {
const size = event?.nativeEvent?.layout;
if (!size || (size.width === dimensions.width && deviceMode !== null)) {
DDS.setSize(size, orientation);
setDeviceMode(deviceMode, size);
checkDeviceType(size);
return;
setDimensions({
width: size.width,
height: size.height
});
if (size.width > size.height) {
setOrientation(OrientationType["LANDSCAPE-RIGHT"]);
} else {
setOrientation(OrientationType["PORTRAIT"]);
}
checkDeviceType(size);
},
[
checkDeviceType,
@@ -324,11 +278,6 @@ export const FluidPanelsView = React.memo(
]
);
if (!deviceMode) {
const size = Dimensions.get("window");
checkDeviceType(size);
}
const PANE_OFFSET = useMemo(
() => ({
mobile: {
@@ -356,7 +305,7 @@ export const FluidPanelsView = React.memo(
[dimensions.width, fullscreen]
);
const PANE_WIDTHS = useMemo(
const PANE_WIDTHS: PaneWidths = useMemo(
() => ({
mobile: {
sidebar: dimensions.width * MOBILE_SIDEBAR_SIZE,
@@ -382,6 +331,7 @@ export const FluidPanelsView = React.memo(
(scrollOffset: number) => {
if (!deviceMode) return;
hideAllTooltips();
if (
scrollOffset >
PANE_OFFSET[deviceMode as keyof typeof PANE_OFFSET].sidebar - 10
@@ -409,7 +359,7 @@ export const FluidPanelsView = React.memo(
};
}, []);
if (!isLoading) {
if (!isLoading && !SideMenu && !EditorWrapper) {
SideMenu = require("../components/side-menu").SideMenu;
EditorWrapper = require("../screens/editor/wrapper").EditorWrapper;
}
@@ -421,15 +371,7 @@ export const FluidPanelsView = React.memo(
style={{
height: "100%",
width: "100%",
backgroundColor: colors.primary.background,
marginRight:
orientation === "LANDSCAPE-RIGHT" && Platform.OS === "ios"
? insets.right
: 0,
marginLeft:
orientation === "LANDSCAPE-LEFT" && Platform.OS === "ios"
? insets.left
: 0
backgroundColor: colors.primary.background
}}
>
{deviceMode && PANE_WIDTHS[deviceMode as keyof typeof PANE_WIDTHS] ? (
@@ -503,9 +445,7 @@ export const FluidPanelsView = React.memo(
style={{
flex: 1,
paddingTop: insets.top,
paddingBottom: insets.bottom,
paddingLeft: insets.left,
paddingRight: insets.right
paddingBottom: insets.bottom
}}
>
<AppNavigationStack />

View File

@@ -23,21 +23,36 @@ import {
AppState,
AppStateStatus,
KeyboardAvoidingView,
Platform,
TextInput,
View
} from "react-native";
import Editor from ".";
import useGlobalSafeAreaInsets from "../../hooks/use-global-safe-area-insets";
import useIsFloatingKeyboard from "../../hooks/use-is-floating-keyboard";
import useKeyboard from "../../hooks/use-keyboard";
import { DDS } from "../../services/device-detection";
import { useSettingStore } from "../../stores/use-setting-store";
import { editorRef } from "../../utils/global-refs";
import { editorController, textInput } from "./tiptap/utils";
import deviceInfo from "react-native-device-info";
export const EditorWrapper = ({ widths }: { widths: any }) => {
export type PaneWidths = {
mobile: {
sidebar: number;
list: number;
editor: number;
};
smallTablet: {
sidebar: number;
list: number;
editor: number;
};
tablet: {
sidebar: number;
list: number;
editor: number;
};
};
export const EditorWrapper = ({ widths }: { widths: PaneWidths }) => {
const { colors } = useThemeColors();
const { colors: toolBarColors } = useThemeColors("editorToolbar");
const deviceMode = useSettingStore((state) => state.deviceMode);
@@ -47,8 +62,9 @@ export const EditorWrapper = ({ widths }: { widths: any }) => {
const introCompleted = useSettingStore(
(state) => state.settings.introCompleted
);
const keyboard = useKeyboard();
const prevState = useRef<AppStateStatus>(undefined);
const isFullscreen = useSettingStore((state) => state.fullscreen);
const dimensions = useSettingStore((state) => state.dimensions);
const onAppStateChanged = async (state: AppStateStatus) => {
if (!prevState.current) {
@@ -72,32 +88,37 @@ export const EditorWrapper = ({ widths }: { widths: any }) => {
};
}, [loading]);
const getMarginBottom = () => {
const bottomInsets =
Platform.OS === "android" ? 12 : insets.bottom + 16 || 14;
if (!keyboard.keyboardShown) return bottomInsets / 1.5;
if (deviceInfo.isTablet() && Platform.OS === "ios" && !floating)
return bottomInsets;
if (Platform.OS === "ios") return bottomInsets / 1.5;
return 0;
};
return (
<View
testID="editor-wrapper"
ref={editorRef}
style={{
width: widths[!introCompleted ? "mobile" : (deviceMode as any)]?.editor,
height: "100%",
minHeight: "100%",
backgroundColor: toolBarColors.primary.background,
borderLeftWidth: DDS.isTab ? 1 : 0,
borderLeftColor: DDS.isTab
? colors.secondary.background
: "transparent",
paddingBottom:
Platform.OS === "android" ? insets.bottom + 10 : insets.bottom
}}
style={[
{
width: isFullscreen
? dimensions.width
: widths[
!introCompleted ? "mobile" : (deviceMode as keyof PaneWidths)
]?.editor,
height: "100%",
minHeight: "100%",
backgroundColor: toolBarColors.primary.background,
paddingLeft: isFullscreen
? deviceMode === "smallTablet"
? 0
: dimensions.width * 0.15
: null,
paddingRight: isFullscreen
? deviceMode === "smallTablet"
? 0
: dimensions.width * 0.15
: insets.right,
borderLeftWidth: DDS.isTab ? 1 : 0,
borderLeftColor: DDS.isTab
? colors.secondary.background
: "transparent",
paddingBottom: insets.bottom
}
]}
>
{loading || !introCompleted ? null : (
<KeyboardAvoidingView

View File

@@ -35,6 +35,10 @@ import { useTagStore } from "../stores/use-tag-store";
import { eUpdateNoteInEditor } from "./events";
import { unlockVault } from "./unlock-vault";
export const valueLimiter = (value: number, min: number, max: number) => {
return value < min ? min : value > max ? max : value;
};
export function getObfuscatedEmail(email: string) {
if (!email) return "";
const [username, provider] = email.split("@");