Skip to content

Commit 643fabc

Browse files
Merge pull request #96751 from software-mansion-labs/@GCyganek/landscape-mode/report-submit-to-popover
Fix Contact list modal broken in landscape mode
2 parents 21e27d5 + 1ee43ac commit 643fabc

5 files changed

Lines changed: 51 additions & 28 deletions

File tree

src/components/EmojiPicker/EmojiPickerMenu/useEmojiPickerMenu.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,16 @@ import useKeyboardState from '@hooks/useKeyboardState';
44
import useLocalize from '@hooks/useLocalize';
55
import useOnyx from '@hooks/useOnyx';
66
import usePreferredEmojiSkinTone from '@hooks/usePreferredEmojiSkinTone';
7+
import useSafeAreaInsets from '@hooks/useSafeAreaInsets';
78
import useStyleUtils from '@hooks/useStyleUtils';
89
import useWindowDimensions from '@hooks/useWindowDimensions';
910

1011
import type {EmojiPickerList, EmojiPickerListItem} from '@libs/EmojiUtils';
1112
import {getHeaderEmojis, getSpacersIndexes, mergeEmojisWithFrequentlyUsedEmojis, processFrequentlyUsedEmojis, suggestEmojis} from '@libs/EmojiUtils';
1213
import isInLandscapeModeUtil from '@libs/isInLandscapeMode';
1314

14-
import CONST from '@src/CONST';
1515
import ONYXKEYS from '@src/ONYXKEYS';
16+
import calculateModalHeightInLandscapeMode from '@src/utils/calculateModalHeightInLandscapeMode';
1617

1718
import type {FlashListRef} from '@shopify/flash-list';
1819

@@ -33,8 +34,9 @@ const useEmojiPickerMenu = () => {
3334
const [preferredSkinTone] = usePreferredEmojiSkinTone();
3435
const {windowHeight, windowWidth} = useWindowDimensions();
3536
const StyleUtils = useStyleUtils();
36-
const {keyboardHeight} = useKeyboardState();
37+
const {keyboardActiveHeight} = useKeyboardState();
3738
const isInLandscapeMode = isInLandscapeModeUtil(windowWidth, windowHeight);
39+
const {top: topSafeAreaInset} = useSafeAreaInsets();
3840

3941
/**
4042
* The EmojiPicker sets the `innerContainerStyle` with `maxHeight: '95%'` in `styles.popoverInnerContainer`
@@ -44,7 +46,7 @@ const useEmojiPickerMenu = () => {
4446
*/
4547
const listStyle = StyleUtils.getEmojiPickerListHeight(
4648
isListFiltered,
47-
windowHeight * (isInLandscapeMode ? CONST.MODAL_MAX_HEIGHT_TO_WINDOW_HEIGHT_RATIO_LANDSCAPE_MODE : 0.95) - keyboardHeight,
49+
isInLandscapeMode ? calculateModalHeightInLandscapeMode(windowHeight, topSafeAreaInset, keyboardActiveHeight) : (windowHeight - topSafeAreaInset) * 0.95 - keyboardActiveHeight,
4850
);
4951

5052
useEffect(() => {

src/components/withKeyboardState.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ function KeyboardStateProvider({children}: ChildrenProps): ReactElement | null {
5050
const keyboardDidHideListener = KeyboardEvents.addListener('keyboardDidHide', () => {
5151
setKeyboardHeight(0);
5252
setIsKeyboardActive(false);
53+
// Sometimes 'keyboardWillHide' is not called (popover closed when keyboard is open), in this case we don't want stale keyboardActiveHeight value
54+
setKeyboardActiveHeight(0);
5355
});
5456
const keyboardWillShowListener = KeyboardEvents.addListener('keyboardWillShow', (e) => {
5557
setIsKeyboardActive(true);

src/hooks/useReportSubmitToPopover.tsx

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import CONST from '@src/CONST';
99
import ONYXKEYS from '@src/ONYXKEYS';
1010
import {personalDetailsLoginSelector} from '@src/selectors/PersonalDetails';
1111
import type AnchorAlignment from '@src/types/utils/AnchorAlignment';
12+
import calculateModalHeightInLandscapeMode from '@src/utils/calculateModalHeightInLandscapeMode';
1213

1314
import type {RefObject} from 'react';
1415

@@ -17,10 +18,12 @@ import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
1718
import {View} from 'react-native';
1819

1920
import useIsInLandscapeMode from './useIsInLandscapeMode';
21+
import useKeyboardState from './useKeyboardState';
2022
import useOnyx from './useOnyx';
2123
import usePopoverPosition from './usePopoverPosition';
2224
import usePrevious from './usePrevious';
2325
import useResponsiveLayout from './useResponsiveLayout';
26+
import useSafeAreaInsets from './useSafeAreaInsets';
2427
import useStyleUtils from './useStyleUtils';
2528
import useThemeStyles from './useThemeStyles';
2629
import useViewportOffsetTop from './useViewportOffsetTop';
@@ -60,15 +63,18 @@ function useReportSubmitToPopover({reportID, onSubmitSuccess, anchorAlignment =
6063
// Bottom-docked Modal path only; aligns with Popover path that omits modal shell padding chrome
6164
// eslint-disable-next-line rulesdir/prefer-shouldUseNarrowLayout-instead-of-isSmallScreenWidth
6265
const {isSmallScreenWidth} = useResponsiveLayout();
63-
const isBottomDockedInLandscape = isSmallScreenWidth && isInLandscapeMode;
66+
const {keyboardActiveHeight} = useKeyboardState();
67+
const {top: topSafeAreaInset} = useSafeAreaInsets();
6468

6569
const submitToPopoverContentHeight = useMemo(() => {
66-
if (!isBottomDockedInLandscape) {
70+
if (!isInLandscapeMode) {
6771
return popoverDimensions.height;
6872
}
6973

70-
return Math.min(popoverDimensions.height, windowHeight * CONST.MODAL_MAX_HEIGHT_TO_WINDOW_HEIGHT_RATIO_LANDSCAPE_MODE);
71-
}, [isBottomDockedInLandscape, windowHeight]);
74+
const contentHeightLandscapeMode = calculateModalHeightInLandscapeMode(windowHeight, topSafeAreaInset, keyboardActiveHeight);
75+
76+
return Math.min(popoverDimensions.height, contentHeightLandscapeMode);
77+
}, [isInLandscapeMode, windowHeight, keyboardActiveHeight, topSafeAreaInset]);
7278
const anchorRef = useRef<View>(null);
7379
const oneShotOnSubmitSuccessRef = useRef<(() => void) | undefined>(undefined);
7480
const onSubmitWithManagerEmailRef = useRef<ReportSubmitToPopoverOpenOptions['onSubmitWithManagerEmail']>(undefined);
@@ -227,9 +233,9 @@ function useReportSubmitToPopover({reportID, onSubmitSuccess, anchorAlignment =
227233
const innerContainerStyle = useMemo(
228234
() => ({
229235
...popoverContainerStyle,
230-
...(isBottomDockedInLandscape ? styles.getPopoverMaxHeight(windowHeight, true) : {minHeight: popoverDimensions.minHeight}),
236+
...(isInLandscapeMode ? styles.getPopoverMaxHeight(windowHeight, true) : {minHeight: popoverDimensions.minHeight}),
231237
}),
232-
[popoverContainerStyle, isBottomDockedInLandscape, windowHeight, styles],
238+
[popoverContainerStyle, isInLandscapeMode, windowHeight, styles],
233239
);
234240

235241
const reportSubmitToPopover = useMemo(() => {
@@ -259,7 +265,7 @@ function useReportSubmitToPopover({reportID, onSubmitSuccess, anchorAlignment =
259265
>
260266
<View
261267
collapsable={false}
262-
style={[StyleUtils.getHeight(submitToPopoverContentHeight), styles.flexColumn, styles.flex1, styles.w100, styles.pt4]}
268+
style={[StyleUtils.getHeight(submitToPopoverContentHeight), styles.flexColumn, !isInLandscapeMode && styles.flex1, styles.w100, styles.pt4]}
263269
>
264270
<ReportSubmitToContent
265271
key={submitToContentKey}
@@ -276,28 +282,28 @@ function useReportSubmitToPopover({reportID, onSubmitSuccess, anchorAlignment =
276282
</PopoverWithMeasuredContent>
277283
);
278284
}, [
279-
StyleUtils,
280-
styles.flexColumn,
281-
styles.flex1,
282-
styles.pt4,
283-
styles.w100,
285+
shouldRenderSubmitToPopover,
284286
innerContainerStyle,
285287
outerStyle,
286-
submitToPopoverContentHeight,
287-
shouldRenderSubmitToPopover,
288288
isVisible,
289289
closeReportSubmitToPopover,
290290
handleReportSubmitToPopoverModalHide,
291291
anchorPosition,
292292
anchorAlignment,
293-
anchorRef,
293+
StyleUtils,
294+
submitToPopoverContentHeight,
295+
styles.flexColumn,
296+
styles.flex1,
297+
styles.w100,
298+
styles.pt4,
299+
isInLandscapeMode,
300+
submitToContentKey,
294301
report,
295302
policy,
296303
isLoadingReportData,
297304
handleCombinedSubmitSuccess,
298305
isSearchSubmitFlow,
299306
handleSearchSubmitWithManagerEmail,
300-
submitToContentKey,
301307
]);
302308

303309
return {

src/pages/ReportSubmitToContent.tsx

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,12 @@ import Text from '@components/Text';
99
import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails';
1010
import useDebouncedState from '@hooks/useDebouncedState';
1111
import useIsInLandscapeMode from '@hooks/useIsInLandscapeMode';
12+
import useKeyboardState from '@hooks/useKeyboardState';
1213
import {useMemoizedLazyIllustrations} from '@hooks/useLazyAsset';
1314
import useLocalize from '@hooks/useLocalize';
1415
import useNetwork from '@hooks/useNetwork';
1516
import useOnyx from '@hooks/useOnyx';
1617
import usePermissions from '@hooks/usePermissions';
17-
import useResponsiveLayout from '@hooks/useResponsiveLayout';
1818
import useSearchShouldCalculateTotals from '@hooks/useSearchShouldCalculateTotals';
1919
import useStyleUtils from '@hooks/useStyleUtils';
2020
import useThemeStyles from '@hooks/useThemeStyles';
@@ -79,10 +79,9 @@ function ReportSubmitToContent({
7979
const styles = useThemeStyles();
8080
const StyleUtils = useStyleUtils();
8181
const {translate, localeCompare} = useLocalize();
82-
// eslint-disable-next-line rulesdir/prefer-shouldUseNarrowLayout-instead-of-isSmallScreenWidth
83-
const {isSmallScreenWidth} = useResponsiveLayout();
8482
const isInLandscapeMode = useIsInLandscapeMode();
85-
const isBottomDockedInLandscape = isSmallScreenWidth && isInLandscapeMode;
83+
const {keyboardActiveHeight} = useKeyboardState();
84+
8685
const currentUserDetails = useCurrentUserPersonalDetails();
8786
const {isBetaEnabled} = usePermissions();
8887
const [transactionViolations] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS);
@@ -404,22 +403,22 @@ function ReportSubmitToContent({
404403

405404
const confirmButtonOptions = useMemo(
406405
() => ({
407-
showButton: true,
406+
showButton: !keyboardActiveHeight || !isInLandscapeMode,
408407
text: translate('common.confirm'),
409408
onConfirm: handleSubmit,
410409
confirmButtonSize: 'medium' as const,
411410
}),
412-
[handleSubmit, translate],
411+
[handleSubmit, translate, keyboardActiveHeight, isInLandscapeMode],
413412
);
414413

415414
const containerStyle = useMemo(() => {
416415
const baseStyle = [styles.w100, styles.flex1, styles.pt3, styles.pb3];
417-
if (isBottomDockedInLandscape) {
416+
if (isInLandscapeMode) {
418417
return baseStyle;
419418
}
420419

421420
return [...baseStyle, StyleUtils.getMinimumHeight(CONST.POPOVER_REPORT_SUBMIT_TO_CONTENT_HEIGHT)];
422-
}, [StyleUtils, isBottomDockedInLandscape, styles.flex1, styles.pb3, styles.pt3, styles.w100]);
421+
}, [StyleUtils, isInLandscapeMode, styles.flex1, styles.pb3, styles.pt3, styles.w100]);
423422

424423
if (shouldShowNotFoundView) {
425424
return (
@@ -445,7 +444,7 @@ function ReportSubmitToContent({
445444
isRowMultilineSupported
446445
style={{containerStyle: styles.flex1}}
447446
disableMaintainingScrollPosition
448-
addBottomSafeAreaPadding
447+
addBottomSafeAreaPadding={!isInLandscapeMode}
449448
>
450449
{hasError && (
451450
<FormHelpMessage
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import CONST from '@src/CONST';
2+
3+
// Calculates the height of a modal in landscape mode based on the window height and keyboard state.
4+
function calculateModalHeightInLandscapeMode(windowHeight: number, topSafeAreaInset: number, keyboardActiveHeight: number) {
5+
const availableWindowHeight = windowHeight - topSafeAreaInset;
6+
7+
if (keyboardActiveHeight > 0) {
8+
return availableWindowHeight - keyboardActiveHeight;
9+
}
10+
11+
return availableWindowHeight * CONST.MODAL_MAX_HEIGHT_TO_WINDOW_HEIGHT_RATIO_LANDSCAPE_MODE;
12+
}
13+
14+
export default calculateModalHeightInLandscapeMode;

0 commit comments

Comments
 (0)