From 15e75ac24bfcca1cf73a4f07c5e0542a2a3ced95 Mon Sep 17 00:00:00 2001 From: Elias Nahum Date: Tue, 24 Jan 2023 21:48:37 +0200 Subject: [PATCH] iPad: enable rotation in all directions (#7007) * iPad: enable rotation in all directions * feedback review --- app/components/tutorial_highlight/index.tsx | 28 +++---- app/components/tutorial_highlight/item.tsx | 6 +- .../__snapshots__/index.test.tsx.snap | 80 +++++++++++++++++++ app/components/user_list_row/index.tsx | 21 +++-- app/screens/bottom_sheet/index.tsx | 8 +- .../servers_list/server_item/server_item.tsx | 26 ++++-- ios/Mattermost/Info.plist | 16 ++-- 7 files changed, 146 insertions(+), 39 deletions(-) diff --git a/app/components/tutorial_highlight/index.tsx b/app/components/tutorial_highlight/index.tsx index e83fcfa84b..182ad6e6e6 100644 --- a/app/components/tutorial_highlight/index.tsx +++ b/app/components/tutorial_highlight/index.tsx @@ -1,7 +1,7 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import React, {useEffect, useState} from 'react'; +import React, {useCallback} from 'react'; import {Modal, StyleSheet, useWindowDimensions, View} from 'react-native'; import HighlightItem from './item'; @@ -11,45 +11,43 @@ type Props = { itemBounds: TutorialItemBounds; itemBorderRadius?: number; onDismiss: () => void; + onLayout: () => void; onShow?: () => void; } -const TutorialHighlight = ({children, itemBounds, itemBorderRadius, onDismiss, onShow}: Props) => { +const TutorialHighlight = ({children, itemBounds, itemBorderRadius, onDismiss, onLayout, onShow}: Props) => { const {width, height} = useWindowDimensions(); - const [visible, setIsVisible] = useState(false); - const isLandscape = width > height; - const supportedOrientations = isLandscape ? 'landscape' : 'portrait'; - useEffect(() => { - const t = setTimeout(() => { - setIsVisible(true); - }, 500); - - return () => clearTimeout(t); - }, []); + const handleShowTutorial = useCallback(() => { + if (onShow) { + setTimeout(onShow, 1000); + } + }, [itemBounds]); return ( + {itemBounds.endX > 0 && + } {children} ); diff --git a/app/components/tutorial_highlight/item.tsx b/app/components/tutorial_highlight/item.tsx index de98bb12ae..dc96f45f50 100644 --- a/app/components/tutorial_highlight/item.tsx +++ b/app/components/tutorial_highlight/item.tsx @@ -14,22 +14,24 @@ type Props = { height: number; itemBounds: TutorialItemBounds; onDismiss: () => void; + onLayout: () => void; width: number; } -const HighlightItem = ({height, itemBounds, onDismiss, borderRadius = 0, width}: Props) => { +const HighlightItem = ({height, itemBounds, onDismiss, onLayout, borderRadius = 0, width}: Props) => { const theme = useTheme(); const isDark = tinyColor(theme.centerChannelBg).isDark(); const pathD = useMemo(() => { const parent = {startX: 0, startY: 0, endX: width, endY: height}; return constructRectangularPathWithBorderRadius(parent, itemBounds, borderRadius); - }, [borderRadius, itemBounds, width]); + }, [borderRadius, itemBounds, width, height]); return ( diff --git a/app/components/user_list/__snapshots__/index.test.tsx.snap b/app/components/user_list/__snapshots__/index.test.tsx.snap index f06eeaf570..22a2b45a71 100644 --- a/app/components/user_list/__snapshots__/index.test.tsx.snap +++ b/app/components/user_list/__snapshots__/index.test.tsx.snap @@ -538,6 +538,86 @@ exports[`components/channel_list_row should show results and tutorial 1`] = ` + + + + + + + Long-press on an item to view a user's profile + + + + { viewRef.current?.measureInWindow((x, y, w, h) => { const bounds: TutorialItemBounds = { - startX: x - 20, + startX: x, startY: y, endX: x + w, endY: y + h, }; if (viewRef.current) { - setShowTutorial(true); setItemBounds(bounds); } }); @@ -140,12 +140,16 @@ function UserListRow({ }, []); useEffect(() => { - let time: NodeJS.Timeout; if (highlight && !tutorialWatched) { - time = setTimeout(startTutorial, 650); + if (isTablet) { + setShowTutorial(true); + return; + } + InteractionManager.runAfterInteractions(() => { + setShowTutorial(true); + }); } - return () => clearTimeout(time); - }, [highlight, tutorialWatched]); + }, [highlight, tutorialWatched, isTablet]); const handlePress = useCallback(() => { onPress?.(user); @@ -155,6 +159,10 @@ function UserListRow({ onLongPress?.(user); }, [onLongPress, user]); + const onLayout = useCallback(() => { + startTutorial(); + }, []); + const icon = useMemo(() => { if (!selectable) { return null; @@ -256,6 +264,7 @@ function UserListRow({ (); + useEffect(() => { + interaction.current = InteractionManager.createInteractionHandle(); + }, []); + const bottomSheetBackgroundStyle = useMemo(() => [ styles.bottomSheetBackground, {borderWidth: isTablet ? 0 : 1}, @@ -118,7 +122,9 @@ const BottomSheet = ({ }, [close]); const handleAnimationStart = useCallback(() => { - interaction.current = InteractionManager.createInteractionHandle(); + if (!interaction.current) { + interaction.current = InteractionManager.createInteractionHandle(); + } }, []); const handleClose = useCallback(() => { diff --git a/app/screens/home/channel_list/servers/servers_list/server_item/server_item.tsx b/app/screens/home/channel_list/servers/servers_list/server_item/server_item.tsx index 687a0fe364..0a8eb6b8e0 100644 --- a/app/screens/home/channel_list/servers/servers_list/server_item/server_item.tsx +++ b/app/screens/home/channel_list/servers/servers_list/server_item/server_item.tsx @@ -3,7 +3,7 @@ import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react'; import {useIntl} from 'react-intl'; -import {Animated, DeviceEventEmitter, Platform, StyleProp, Text, View, ViewStyle} from 'react-native'; +import {Animated, DeviceEventEmitter, InteractionManager, Platform, StyleProp, Text, View, ViewStyle} from 'react-native'; import {RectButton} from 'react-native-gesture-handler'; import Swipeable from 'react-native-gesture-handler/Swipeable'; import {Navigation} from 'react-native-navigation'; @@ -200,19 +200,23 @@ const ServerItem = ({ const startTutorial = () => { viewRef.current?.measureInWindow((x, y, w, h) => { const bounds: TutorialItemBounds = { - startX: x - 20, + startX: x, startY: y, - endX: x + w + 20, + endX: x + w, endY: y + h, }; if (viewRef.current) { - setShowTutorial(true); setItemBounds(bounds); } }); }; + const onLayout = useCallback(() => { + swipeable.current?.close(); + startTutorial(); + }, []); + const containerStyle = useMemo(() => { const style: StyleProp = [styles.container]; if (isActive) { @@ -344,12 +348,16 @@ const ServerItem = ({ }, [server.lastActiveAt, isActive]); useEffect(() => { - let time: NodeJS.Timeout; if (highlight && !tutorialWatched) { - time = setTimeout(startTutorial, 650); + if (isTablet) { + setShowTutorial(true); + return; + } + InteractionManager.runAfterInteractions(() => { + setShowTutorial(true); + }); } - return () => clearTimeout(time); - }, [highlight, tutorialWatched]); + }, [highlight, tutorialWatched, isTablet]); const serverItem = `server_list.server_item.${server.displayName.replace(/ /g, '_').toLocaleLowerCase()}`; const serverItemTestId = isActive ? `${serverItem}.active` : `${serverItem}.inactive`; @@ -466,6 +474,8 @@ const ServerItem = ({ itemBounds={itemBounds} onDismiss={handleDismissTutorial} onShow={handleShowTutorial} + onLayout={onLayout} + itemBorderRadius={8} > Upload photos and videos from your device to $(PRODUCT_NAME) NSSpeechRecognitionUsageDescription Send voice messages to $(PRODUCT_NAME) + NSUserActivityTypes + + INSendMessageIntent + UIAppFonts OpenSans-Bold.ttf @@ -113,23 +117,21 @@ armv7 UIRequiresFullScreen - + UISupportedInterfaceOrientations - UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight + UIInterfaceOrientationPortrait UISupportedInterfaceOrientations~ipad - UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown UIViewControllerBasedStatusBarAppearance - NSUserActivityTypes - - INSendMessageIntent -