Skip to content

Commit 6871452

Browse files
authored
Merge pull request Expensify#87350 from software-mansion-labs/@GCyganek/landscape-mode/fix-suggestions-modal-composer
2 parents 91aafd4 + 9222f99 commit 6871452

8 files changed

Lines changed: 74 additions & 23 deletions

File tree

src/CONST/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2560,6 +2560,7 @@ const CONST = {
25602560
SUGGESTER_INNER_PADDING: 8,
25612561
SUGGESTION_ROW_HEIGHT: 40,
25622562
SMALL_CONTAINER_HEIGHT_FACTOR: 2.5,
2563+
SMALL_CONTAINER_HEIGHT_FACTOR_LANDSCAPE_MODE: 1.5,
25632564
MAX_AMOUNT_OF_SUGGESTIONS: 20,
25642565
MAX_AMOUNT_OF_VISIBLE_SUGGESTIONS_IN_CONTAINER: 5,
25652566
HERE_TEXT: '@here',

src/components/AutoCompleteSuggestions/AutoCompleteSuggestionsPortal/getBottomSuggestionPadding/index.android.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
import {Dimensions} from 'react-native';
22

3-
function getBottomSuggestionPadding(bottom: number): number {
3+
function getBottomSuggestionPadding(bottom: number, isInLandscapeMode: boolean): number {
44
const {height} = Dimensions.get('window');
55
const basePadding = 30;
66

7+
if (isInLandscapeMode) {
8+
return basePadding;
9+
}
10+
711
// Calculate what percentage of the screen height the bottom position represents
812
const bottomPercentageToHeight = (bottom / height) * 100;
913

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// eslint-disable-next-line @typescript-eslint/no-unused-vars
2-
function getBottomSuggestionPadding(bottom?: number): number {
3-
return 16;
2+
function getBottomSuggestionPadding(bottom?: number, isInLandscapeMode?: boolean): number {
3+
return 30;
44
}
55

66
export default getBottomSuggestionPadding;

src/components/AutoCompleteSuggestions/AutoCompleteSuggestionsPortal/getBottomSuggestionPadding/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// eslint-disable-next-line @typescript-eslint/no-unused-vars
2-
function getBottomSuggestionPadding(bottom?: number): number {
2+
function getBottomSuggestionPadding(bottom?: number, isInLandscapeMode?: boolean): number {
33
return 6;
44
}
55

src/components/AutoCompleteSuggestions/AutoCompleteSuggestionsPortal/index.native.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,16 @@ import getBottomSuggestionPadding from './getBottomSuggestionPadding';
77
import TransparentOverlay from './TransparentOverlay/TransparentOverlay';
88
import type {AutoCompleteSuggestionsPortalProps} from './types';
99

10-
function AutoCompleteSuggestionsPortal<TSuggestion>({left = 0, width = 0, bottom = 0, resetSuggestions = () => {}, ...props}: AutoCompleteSuggestionsPortalProps<TSuggestion>) {
10+
function AutoCompleteSuggestionsPortal<TSuggestion>({
11+
left = 0,
12+
width = 0,
13+
bottom = 0,
14+
resetSuggestions = () => {},
15+
isInLandscapeMode = false,
16+
...props
17+
}: AutoCompleteSuggestionsPortalProps<TSuggestion>) {
1118
const StyleUtils = useStyleUtils();
12-
const bottomPadding = getBottomSuggestionPadding(bottom);
19+
const bottomPadding = getBottomSuggestionPadding(bottom, isInLandscapeMode);
1320
const styles = useMemo(() => StyleUtils.getBaseAutoCompleteSuggestionContainerStyle({left, width, bottom: bottom + bottomPadding}), [StyleUtils, left, width, bottom, bottomPadding]);
1421

1522
if (!width) {

src/components/AutoCompleteSuggestions/AutoCompleteSuggestionsPortal/index.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ function AutoCompleteSuggestionsPortal<TSuggestion>({
2020
width = 0,
2121
bottom = 0,
2222
resetSuggestions = () => {},
23+
// isInLandscapeMode is only used on native platforms to adjust the bottom padding
24+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
25+
isInLandscapeMode = false,
2326
...props
2427
}: AutoCompleteSuggestionsPortalProps<TSuggestion>): ReactElement | null | false {
2528
const StyleUtils = useStyleUtils();

src/components/AutoCompleteSuggestions/AutoCompleteSuggestionsPortal/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ type AutoCompleteSuggestionsPortalProps<TSuggestion> = ExternalProps<TSuggestion
77
width: number;
88
bottom: number;
99
measuredHeightOfSuggestionRows: number;
10+
isInLandscapeMode?: boolean;
1011
};
1112

1213
// eslint-disable-next-line import/prefer-default-export

src/components/AutoCompleteSuggestions/index.tsx

Lines changed: 52 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,15 @@ import CONST from '@src/CONST';
99
import AutoCompleteSuggestionsPortal from './AutoCompleteSuggestionsPortal';
1010
import type {AutoCompleteSuggestionsProps, MeasureParentContainerAndCursor} from './types';
1111

12-
const measureHeightOfSuggestionRows = (numRows: number, canBeBig: boolean): number => {
12+
const measureHeightOfSuggestionRows = (numRows: number, canBeBig: boolean, isInLandscapeMode: boolean): number => {
13+
if (isInLandscapeMode) {
14+
if (numRows > 1) {
15+
// In landscape mode, we display a scrollable window with a height of 1.5 items, indicating that there are more items available beyond what is currently visible
16+
return CONST.AUTO_COMPLETE_SUGGESTER.SMALL_CONTAINER_HEIGHT_FACTOR_LANDSCAPE_MODE * CONST.AUTO_COMPLETE_SUGGESTER.SUGGESTION_ROW_HEIGHT;
17+
}
18+
19+
return numRows * CONST.AUTO_COMPLETE_SUGGESTER.SUGGESTION_ROW_HEIGHT;
20+
}
1321
if (canBeBig) {
1422
if (numRows > CONST.AUTO_COMPLETE_SUGGESTER.MAX_AMOUNT_OF_VISIBLE_SUGGESTIONS_IN_CONTAINER) {
1523
// On large screens, if there are more than 5 suggestions, we display a scrollable window with a height of 5 items, indicating that there are more items available
@@ -42,6 +50,13 @@ const initialContainerState = {
4250
cursorCoordinates: {x: 0, y: 0},
4351
};
4452

53+
function getLeftOffset(x: number, leftInset: number, bigScreenLeftOffset: number, shouldUseNarrowLayout: boolean, isInLandscapeMode: boolean): number {
54+
if (shouldUseNarrowLayout) {
55+
return isInLandscapeMode ? x - leftInset : x;
56+
}
57+
return bigScreenLeftOffset;
58+
}
59+
4560
/**
4661
* On the mobile-web platform, when long-pressing on auto-complete suggestions,
4762
* we need to prevent focus shifting to avoid blurring the main input (which makes the suggestions picker close and fires the onSelect callback).
@@ -55,13 +70,15 @@ function AutoCompleteSuggestions<TSuggestion>({measureParentContainerAndReportCu
5570
const leftValue = React.useRef<number>(0);
5671
const prevLeftValue = React.useRef<number>(0);
5772
const {height: windowHeight, width: windowWidth} = useWindowDimensionsForAutoCompleteSuggestions();
58-
const {shouldUseNarrowLayout} = useResponsiveLayout();
73+
const {shouldUseNarrowLayout, isInLandscapeMode} = useResponsiveLayout();
74+
const prevIsInLandscapeModeValue = React.useRef(isInLandscapeMode);
5975
const [suggestionHeight, setSuggestionHeight] = React.useState(0);
6076
const [containerState, setContainerState] = React.useState(initialContainerState);
6177
const StyleUtils = useStyleUtils();
6278
const insets = useSafeAreaInsets();
6379
const {keyboardHeight, isKeyboardAnimatingRef} = useKeyboardState();
6480
const {paddingBottom: bottomInset, paddingTop: topInset} = StyleUtils.getPlatformSafeAreaPadding(insets ?? undefined);
81+
const {left: leftInset} = insets;
6582

6683
useEffect(() => {
6784
const container = containerRef.current;
@@ -95,8 +112,8 @@ function AutoCompleteSuggestions<TSuggestion>({measureParentContainerAndReportCu
95112
xCoordinatesOfCursor + CONST.AUTO_COMPLETE_SUGGESTER.BIG_SCREEN_SUGGESTION_WIDTH > windowWidth
96113
? windowWidth - CONST.AUTO_COMPLETE_SUGGESTER.BIG_SCREEN_SUGGESTION_WIDTH
97114
: xCoordinatesOfCursor;
98-
const contentMaxHeight = measureHeightOfSuggestionRows(suggestionsLength, true);
99-
const contentMinHeight = measureHeightOfSuggestionRows(suggestionsLength, false);
115+
const contentMaxHeight = measureHeightOfSuggestionRows(suggestionsLength, true, isInLandscapeMode);
116+
const contentMinHeight = measureHeightOfSuggestionRows(suggestionsLength, false, isInLandscapeMode);
100117
let bottomValue = windowHeight - (cursorCoordinates.y - scrollValue + y) - keyboardHeight;
101118
const widthValue = shouldUseNarrowLayout ? width : CONST.AUTO_COMPLETE_SUGGESTER.BIG_SCREEN_SUGGESTION_WIDTH;
102119

@@ -107,34 +124,39 @@ function AutoCompleteSuggestions<TSuggestion>({measureParentContainerAndReportCu
107124
contentHeight: contentMaxHeight,
108125
topInset,
109126
});
110-
const isEnoughSpaceToRenderMenuAboveForSmall = isEnoughSpaceToRenderMenuAboveCursor({
111-
y,
112-
cursorCoordinates,
113-
scrollValue,
114-
contentHeight: contentMinHeight,
115-
topInset,
116-
});
117127

118-
const newLeftOffset = shouldUseNarrowLayout ? x : bigScreenLeftOffset;
128+
// In landscape mode, we always render the menu above the cursor
129+
const isEnoughSpaceToRenderMenuAboveForSmall =
130+
isInLandscapeMode ||
131+
isEnoughSpaceToRenderMenuAboveCursor({
132+
y,
133+
cursorCoordinates,
134+
scrollValue,
135+
contentHeight: contentMinHeight,
136+
topInset,
137+
});
138+
139+
const newLeftOffset = getLeftOffset(x, leftInset, bigScreenLeftOffset, shouldUseNarrowLayout, isInLandscapeMode);
119140
// If the suggested word is longer than 150 (approximately half the width of the suggestion popup), then adjust a new position of popup
120141
const isAdjustmentNeeded = Math.abs(prevLeftValue.current - bigScreenLeftOffset) > 150;
121-
if (isInitialRender.current || isAdjustmentNeeded) {
142+
if (isInitialRender.current || isAdjustmentNeeded || prevIsInLandscapeModeValue.current !== isInLandscapeMode) {
122143
isSuggestionMenuAboveRef.current = isSuggestionMenuRenderedAbove(isEnoughSpaceToRenderMenuAboveForBig, isEnoughSpaceToRenderMenuAboveForSmall);
123144
leftValue.current = newLeftOffset;
124145
isInitialRender.current = false;
125146
prevLeftValue.current = newLeftOffset;
147+
prevIsInLandscapeModeValue.current = isInLandscapeMode;
126148
}
127149

128150
let measuredHeight = 0;
129151
if (isSuggestionMenuAboveRef.current && isEnoughSpaceToRenderMenuAboveForBig) {
130152
// calculation for big suggestion box above the cursor
131-
measuredHeight = measureHeightOfSuggestionRows(suggestionsLength, true);
153+
measuredHeight = measureHeightOfSuggestionRows(suggestionsLength, true, isInLandscapeMode);
132154
} else if (isSuggestionMenuAboveRef.current && isEnoughSpaceToRenderMenuAboveForSmall) {
133155
// calculation for small suggestion box above the cursor
134-
measuredHeight = measureHeightOfSuggestionRows(suggestionsLength, false);
156+
measuredHeight = measureHeightOfSuggestionRows(suggestionsLength, false, isInLandscapeMode);
135157
} else {
136158
// calculation for big suggestion box below the cursor
137-
measuredHeight = measureHeightOfSuggestionRows(suggestionsLength, true);
159+
measuredHeight = measureHeightOfSuggestionRows(suggestionsLength, true, isInLandscapeMode);
138160
bottomValue = windowHeight - y - cursorCoordinates.y + scrollValue - measuredHeight - CONST.AUTO_COMPLETE_SUGGESTER.SUGGESTION_ROW_HEIGHT - keyboardHeight;
139161
}
140162

@@ -146,7 +168,19 @@ function AutoCompleteSuggestions<TSuggestion>({measureParentContainerAndReportCu
146168
cursorCoordinates,
147169
});
148170
});
149-
}, [measureParentContainerAndReportCursor, windowHeight, windowWidth, keyboardHeight, shouldUseNarrowLayout, suggestionsLength, bottomInset, topInset, isKeyboardAnimatingRef]);
171+
}, [
172+
measureParentContainerAndReportCursor,
173+
windowHeight,
174+
windowWidth,
175+
keyboardHeight,
176+
shouldUseNarrowLayout,
177+
suggestionsLength,
178+
bottomInset,
179+
topInset,
180+
isKeyboardAnimatingRef,
181+
isInLandscapeMode,
182+
leftInset,
183+
]);
150184

151185
// Prevent rendering if container dimensions are not set or if we have no suggestions
152186
if ((containerState.width === 0 && containerState.left === 0 && containerState.bottom === 0) || !suggestionsLength) {
@@ -161,6 +195,7 @@ function AutoCompleteSuggestions<TSuggestion>({measureParentContainerAndReportCu
161195
width={containerState.width}
162196
bottom={containerState.bottom}
163197
measuredHeightOfSuggestionRows={suggestionHeight}
198+
isInLandscapeMode={isInLandscapeMode}
164199
/>
165200
);
166201
}

0 commit comments

Comments
 (0)