Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: 10731 Focus composer without showing keyboard when users go to chats #32711

Merged
merged 38 commits into from
Sep 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
d8eb426
fix: 10731
christianwen Dec 8, 2023
07fdad0
Merge branch 'main' into fix/10731-chat-composer-behavior
christianwen Dec 11, 2023
a5f99b7
lint fix
christianwen Dec 11, 2023
f764d66
resolve conflict
christianwen Jan 2, 2024
f6e2e28
lint fix
christianwen Jan 2, 2024
4b19bdf
fix confict
christianwen Jan 25, 2024
7e930b8
lint fix
christianwen Jan 25, 2024
96e924d
fix conflicts
christianwen Feb 20, 2024
8edc49a
resolve conflict
christianwen Mar 5, 2024
5dc6922
fix focus input
christianwen Mar 5, 2024
b6647b4
focus input on safari
christianwen Mar 5, 2024
432e67e
Merge branch 'main' into fix/10731-chat-composer-behavior
christianwen Apr 8, 2024
e6bfa42
Merge branch 'main' into fix/10731-chat-composer-behavior
christianwen Apr 10, 2024
eb79042
lint fix
christianwen Apr 10, 2024
aec542a
resolve conflicts
christianwen Apr 16, 2024
802f37d
Merge branch 'main' into fix/10731-chat-composer-behavior
christianwen Apr 17, 2024
d036e24
conflicts
christianwen May 7, 2024
dd50857
resolve conflicts
christianwen Aug 13, 2024
b008b05
fix rn to remove autoFill when hide context menu
christianwen Aug 14, 2024
025fa15
type fix
christianwen Aug 14, 2024
c48bb63
resolve conflicts
christianwen Aug 27, 2024
726154d
lint fix
christianwen Aug 27, 2024
5e13e27
Merge branch 'main' into fix/10731-chat-composer-behavior
christianwen Sep 9, 2024
69bc468
remove outdated file
christianwen Sep 9, 2024
c037b05
resolve conflicts
christianwen Sep 13, 2024
3e60d1e
Merge branch 'main' into fix/10731-chat-composer-behavior
christianwen Sep 17, 2024
7ba9d60
clean isFocusedWhileChangingInputMode logic
christianwen Sep 17, 2024
958e9df
conflicts
christianwen Sep 20, 2024
ca23e24
bump rn livemarkdown version
christianwen Sep 20, 2024
c59d44f
use isKeyboardShown
christianwen Sep 24, 2024
fb798c0
Merge branch 'main' into fix/10731-chat-composer-behavior
christianwen Sep 24, 2024
fcac742
update rn-livemarkdown version
christianwen Sep 24, 2024
18055ae
remove CONST
christianwen Sep 24, 2024
381fdff
safari keyboard show
christianwen Sep 25, 2024
e08d442
lint fix
christianwen Sep 25, 2024
2282bf6
remove redundant fix
christianwen Sep 25, 2024
1245315
lint fix
christianwen Sep 25, 2024
33e093e
resolve conflicts
christianwen Sep 30, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion src/components/Composer/index.native.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import type {MarkdownStyle} from '@expensify/react-native-live-markdown';
import mimeDb from 'mime-db';
import type {ForwardedRef} from 'react';
import React, {useCallback, useEffect, useMemo, useRef} from 'react';
import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
import type {NativeSyntheticEvent, TextInput, TextInputChangeEventData, TextInputPasteEventData} from 'react-native';
import {StyleSheet} from 'react-native';
import type {FileObject} from '@components/AttachmentModal';
import type {AnimatedMarkdownTextInputRef} from '@components/RNMarkdownTextInput';
import RNMarkdownTextInput from '@components/RNMarkdownTextInput';
import useAutoFocusInput from '@hooks/useAutoFocusInput';
import useKeyboardState from '@hooks/useKeyboardState';
import useMarkdownStyle from '@hooks/useMarkdownStyle';
import useResetComposerFocus from '@hooks/useResetComposerFocus';
import useStyleUtils from '@hooks/useStyleUtils';
Expand Down Expand Up @@ -37,6 +38,7 @@ function Composer(
selection,
value,
isGroupPolicyReport = false,
showSoftInputOnFocus,
...props
}: ComposerProps,
ref: ForwardedRef<TextInput>,
Expand All @@ -48,8 +50,11 @@ function Composer(
const markdownStyle = useMarkdownStyle(value, !isGroupPolicyReport ? excludeReportMentionStyle : excludeNoStyles);
const styles = useThemeStyles();
const StyleUtils = useStyleUtils();
const [contextMenuHidden, setContextMenuHidden] = useState(!showSoftInputOnFocus);

const {inputCallbackRef, inputRef: autoFocusInputRef} = useAutoFocusInput();
const keyboardState = useKeyboardState();
const isKeyboardShown = keyboardState?.isKeyboardShown ?? false;

useEffect(() => {
if (autoFocus === !!autoFocusInputRef.current) {
Expand Down Expand Up @@ -109,6 +114,13 @@ function Composer(
const maxHeightStyle = useMemo(() => StyleUtils.getComposerMaxHeightStyle(maxLines, isComposerFullSize), [StyleUtils, isComposerFullSize, maxLines]);
const composerStyle = useMemo(() => StyleSheet.flatten([style, textContainsOnlyEmojis ? styles.onlyEmojisTextLineHeight : {}]), [style, textContainsOnlyEmojis, styles]);

useEffect(() => {
if (!showSoftInputOnFocus || !isKeyboardShown) {
return;
}
setContextMenuHidden(false);
}, [showSoftInputOnFocus, isKeyboardShown]);

return (
<RNMarkdownTextInput
multiline
Expand All @@ -135,6 +147,8 @@ function Composer(
props?.onBlur?.(e);
}}
onClear={onClear}
showSoftInputOnFocus={showSoftInputOnFocus}
contextMenuHidden={contextMenuHidden}
/>
);
}
Expand Down
2 changes: 2 additions & 0 deletions src/components/Composer/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ function Composer(
isComposerFullSize = false,
shouldContainScroll = true,
isGroupPolicyReport = false,
showSoftInputOnFocus = true,
...props
}: ComposerProps,
ref: ForwardedRef<TextInput | HTMLInputElement>,
Expand Down Expand Up @@ -388,6 +389,7 @@ function Composer(
value={value}
defaultValue={defaultValue}
autoFocus={autoFocus}
inputMode={!showSoftInputOnFocus ? 'none' : 'text'}
/* eslint-disable-next-line react/jsx-props-no-spreading */
{...props}
onSelectionChange={addCursorPositionToSelectionChange}
Expand Down
2 changes: 2 additions & 0 deletions src/components/Composer/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ type ComposerProps = Omit<TextInputProps, 'onClear'> & {

/** Indicates whether the composer is in a group policy report. Used for disabling report mentioning style in markdown input */
isGroupPolicyReport?: boolean;

showSoftInputOnFocus?: boolean;
};

export type {TextSelection, ComposerProps, CustomSelectionChangeEvent};
2 changes: 0 additions & 2 deletions src/pages/home/ReportScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,6 @@ function ReportScreen({route, currentReportID = '', navigation}: ReportScreenPro

const {reportPendingAction, reportErrors} = ReportUtils.getReportOfflinePendingActionAndErrors(report);
const screenWrapperStyle: ViewStyle[] = [styles.appContent, styles.flex1, {marginTop: viewportOffsetTop}];
const isEmptyChat = useMemo(() => ReportUtils.isEmptyReport(report), [report]);
const isOptimisticDelete = report?.statusNum === CONST.REPORT.STATUS_NUM.CLOSED;
const indexOfLinkedMessage = useMemo(
(): number => reportActions.findIndex((obj) => String(obj.reportActionID) === String(reportActionIDFromRoute)),
Expand Down Expand Up @@ -802,7 +801,6 @@ function ReportScreen({route, currentReportID = '', navigation}: ReportScreenPro
policy={policy}
pendingAction={reportPendingAction}
isComposerFullSize={!!isComposerFullSize}
isEmptyChat={isEmptyChat}
lastReportAction={lastReportAction}
workspaceTooltip={workspaceTooltip}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ import useStyleUtils from '@hooks/useStyleUtils';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import * as Browser from '@libs/Browser';
import canFocusInputOnScreenFocus from '@libs/canFocusInputOnScreenFocus';
import {forceClearInput} from '@libs/ComponentUtils';
import * as ComposerUtils from '@libs/ComposerUtils';
import convertToLTRForComposer from '@libs/convertToLTRForComposer';
Expand All @@ -40,7 +39,6 @@ import getPlatform from '@libs/getPlatform';
import * as KeyDownListener from '@libs/KeyboardShortcut/KeyDownPressListener';
import Parser from '@libs/Parser';
import ReportActionComposeFocusManager from '@libs/ReportActionComposeFocusManager';
import * as ReportActionsUtils from '@libs/ReportActionsUtils';
import * as ReportUtils from '@libs/ReportUtils';
import updateMultilineInputRange from '@libs/updateMultilineInputRange';
import willBlurTextInputOnTapOutsideFunc from '@libs/willBlurTextInputOnTapOutside';
Expand All @@ -66,9 +64,6 @@ type SyncSelection = {
type NewlyAddedChars = {startIndex: number; endIndex: number; diff: string};

type ComposerWithSuggestionsOnyxProps = {
/** The parent report actions for the report */
parentReportActions: OnyxEntry<OnyxTypes.ReportActions>;

/** The modal state */
modal: OnyxEntry<OnyxTypes.Modal>;

Expand Down Expand Up @@ -150,22 +145,12 @@ type ComposerWithSuggestionsProps = ComposerWithSuggestionsOnyxProps &
/** Whether the edit is focused */
editFocused: boolean;

/** Wheater chat is empty */
isEmptyChat?: boolean;

/** The last report action */
lastReportAction?: OnyxEntry<OnyxTypes.ReportAction>;

/** Whether to include chronos */
includeChronos?: boolean;

/** The parent report action ID */
parentReportActionID?: string;

/** The parent report ID */
// eslint-disable-next-line react/no-unused-prop-types -- its used in the withOnyx HOC
parentReportID: string | undefined;

/** Whether report is from group policy */
isGroupPolicyReport: boolean;

Expand Down Expand Up @@ -211,10 +196,6 @@ const debouncedBroadcastUserIsTyping = lodashDebounce(

const willBlurTextInputOnTapOutside = willBlurTextInputOnTapOutsideFunc();

// We want consistent auto focus behavior on input between native and mWeb so we have some auto focus management code that will
// prevent auto focus on existing chat for mobile device
const shouldFocusInputOnScreenFocus = canFocusInputOnScreenFocus();

Comment on lines -214 to -217
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this was deleted?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same question.

After rechecking. This is added #18699 and now we change the expectation. So this should be removed to align with new expect

/**
* This component holds the value and selection state.
* If a component really needs access to these state values it should be put here.
Expand All @@ -226,14 +207,11 @@ function ComposerWithSuggestions(
// Onyx
modal,
preferredSkinTone = CONST.EMOJI_DEFAULT_SKIN_TONE,
parentReportActions,

// Props: Report
reportID,
includeChronos,
isEmptyChat,
lastReportAction,
parentReportActionID,
isGroupPolicyReport,
policyID,

Expand Down Expand Up @@ -298,17 +276,13 @@ function ComposerWithSuggestions(
const {shouldUseNarrowLayout} = useResponsiveLayout();
const maxComposerLines = shouldUseNarrowLayout ? CONST.COMPOSER.MAX_LINES_SMALL_SCREEN : CONST.COMPOSER.MAX_LINES;

const parentReportAction = parentReportActions?.[parentReportActionID ?? '-1'];
const shouldAutoFocus =
!modal?.isVisible &&
Modal.areAllModalsHidden() &&
isFocused &&
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@christianwen Why do we remove isFocused condition? Do this change break any other feature? I am struggling to find the reason why we add this condition

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, I think we should add isFocused again, when the chat is not focused, we shouldn't trigger focus input

(shouldFocusInputOnScreenFocus || (isEmptyChat && !ReportActionsUtils.isTransactionThread(parentReportAction))) &&
shouldShowComposeInput;
const shouldAutoFocus = !modal?.isVisible && shouldShowComposeInput && Modal.areAllModalsHidden() && isFocused;

const valueRef = useRef(value);
valueRef.current = value;

const [showSoftInputOnFocus, setShowSoftInputOnFocus] = useState(false);

const [selection, setSelection] = useState<TextSelection>(() => ({start: value.length, end: value.length, positionX: 0, positionY: 0}));

const [composerHeight, setComposerHeight] = useState(0);
Expand Down Expand Up @@ -798,6 +772,19 @@ function ComposerWithSuggestions(
shouldCalculateCaretPosition
onLayout={onLayout}
onScroll={hideSuggestionMenu}
showSoftInputOnFocus={showSoftInputOnFocus}
onTouchStart={() => {
if (showSoftInputOnFocus) {
return;
}
if (Browser.isMobileSafari()) {
setTimeout(() => {
setShowSoftInputOnFocus(true);
}, CONST.ANIMATED_TRANSITION);
return;
}
setShowSoftInputOnFocus(true);
}}
shouldContainScroll={Browser.isMobileSafari()}
isGroupPolicyReport={isGroupPolicyReport}
/>
Expand Down Expand Up @@ -848,11 +835,6 @@ export default withOnyx<ComposerWithSuggestionsProps & RefAttributes<ComposerRef
editFocused: {
key: ONYXKEYS.INPUT_FOCUSED,
},
parentReportActions: {
key: ({parentReportID}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${parentReportID}`,
canEvict: false,
initWithStoredValues: false,
},
})(memo(ComposerWithSuggestionsWithRef));

export type {ComposerWithSuggestionsProps, ComposerRef};
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ import useNetwork from '@hooks/useNetwork';
import useResponsiveLayout from '@hooks/useResponsiveLayout';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import canFocusInputOnScreenFocus from '@libs/canFocusInputOnScreenFocus';
import * as DeviceCapabilities from '@libs/DeviceCapabilities';
import {getDraftComment} from '@libs/DraftCommentUtils';
import getModalState from '@libs/getModalState';
Expand Down Expand Up @@ -64,7 +63,7 @@ type SuggestionsRef = {
};

type ReportActionComposeProps = WithCurrentUserPersonalDetailsProps &
Pick<ComposerWithSuggestionsProps, 'reportID' | 'isEmptyChat' | 'isComposerFullSize' | 'lastReportAction'> & {
Pick<ComposerWithSuggestionsProps, 'reportID' | 'isComposerFullSize' | 'lastReportAction'> & {
/** A method to call when the form is submitted */
onSubmit: (newComment: string) => void;

Expand All @@ -90,10 +89,6 @@ type ReportActionComposeProps = WithCurrentUserPersonalDetailsProps &
shouldShowEducationalTooltip?: boolean;
};

// We want consistent auto focus behavior on input between native and mWeb so we have some auto focus management code that will
// prevent auto focus on existing chat for mobile device
const shouldFocusInputOnScreenFocus = canFocusInputOnScreenFocus();

const willBlurTextInputOnTapOutside = willBlurTextInputOnTapOutsideFunc();

// eslint-disable-next-line import/no-mutable-exports
Expand All @@ -108,7 +103,6 @@ function ReportActionCompose({
report,
reportID,
isReportReadyForDisplay = true,
isEmptyChat,
lastReportAction,
shouldShowEducationalTooltip,
onComposerFocus,
Expand All @@ -129,7 +123,7 @@ function ReportActionCompose({
*/
const [isFocused, setIsFocused] = useState(() => {
const initialModalState = getModalState();
return shouldFocusInputOnScreenFocus && shouldShowComposeInput && !initialModalState?.isVisible && !initialModalState?.willAlertModalBecomeVisible;
return shouldShowComposeInput && !initialModalState?.isVisible && !initialModalState?.willAlertModalBecomeVisible;
});
const [isFullComposerAvailable, setIsFullComposerAvailable] = useState(isComposerFullSize);
const [shouldHideEducationalTooltip, setShouldHideEducationalTooltip] = useState(false);
Expand Down Expand Up @@ -465,11 +459,8 @@ function ReportActionCompose({
raiseIsScrollLikelyLayoutTriggered={raiseIsScrollLikelyLayoutTriggered}
reportID={reportID}
policyID={report?.policyID ?? '-1'}
parentReportID={report?.parentReportID}
parentReportActionID={report?.parentReportActionID}
includeChronos={ReportUtils.chatIncludesChronos(report)}
isGroupPolicyReport={isGroupPolicyReport}
isEmptyChat={isEmptyChat}
lastReportAction={lastReportAction}
isMenuVisible={isMenuVisible}
inputPlaceholder={inputPlaceholder}
Expand Down
6 changes: 0 additions & 6 deletions src/pages/home/report/ReportFooter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,6 @@ type ReportFooterProps = {
/** Whether to show educational tooltip in workspace chat for first-time user */
workspaceTooltip: OnyxEntry<OnyxTypes.WorkspaceTooltip>;

/** Whether the chat is empty */
isEmptyChat?: boolean;

/** The pending action when we are adding a chat */
pendingAction?: PendingAction;

Expand All @@ -72,7 +69,6 @@ function ReportFooter({
report = {reportID: '-1'},
reportMetadata,
policy,
isEmptyChat = true,
isReportReadyForDisplay = true,
isComposerFullSize = false,
workspaceTooltip,
Expand Down Expand Up @@ -213,7 +209,6 @@ function ReportFooter({
onComposerBlur={onComposerBlur}
reportID={report.reportID}
report={report}
isEmptyChat={isEmptyChat}
lastReportAction={lastReportAction}
pendingAction={pendingAction}
isComposerFullSize={isComposerFullSize}
Expand All @@ -235,7 +230,6 @@ export default memo(
lodashIsEqual(prevProps.report, nextProps.report) &&
prevProps.pendingAction === nextProps.pendingAction &&
prevProps.isComposerFullSize === nextProps.isComposerFullSize &&
prevProps.isEmptyChat === nextProps.isEmptyChat &&
prevProps.lastReportAction === nextProps.lastReportAction &&
prevProps.isReportReadyForDisplay === nextProps.isReportReadyForDisplay &&
prevProps.workspaceTooltip?.shouldShow === nextProps.workspaceTooltip?.shouldShow &&
Expand Down
Loading