Skip to content

Commit

Permalink
Merge pull request #30345 from tienifr/fix/24473
Browse files Browse the repository at this point in the history
fix: 24473 Deepliink - Keyboard displayed upon splash screen
  • Loading branch information
danieldoglas authored Nov 7, 2023
2 parents 2868f68 + d1fcd9e commit bf38a82
Show file tree
Hide file tree
Showing 6 changed files with 41 additions and 26 deletions.
22 changes: 18 additions & 4 deletions src/Expensify.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ const defaultProps = {
isCheckingPublicRoom: true,
};

const SplashScreenHiddenContext = React.createContext({});

function Expensify(props) {
const appStateChangeListener = useRef(null);
const [isNavigationReady, setIsNavigationReady] = useState(false);
Expand All @@ -105,6 +107,14 @@ function Expensify(props) {
}, [props.isCheckingPublicRoom]);

const isAuthenticated = useMemo(() => Boolean(lodashGet(props.session, 'authToken', null)), [props.session]);

const contextValue = useMemo(
() => ({
isSplashHidden,
}),
[isSplashHidden],
);

const shouldInit = isNavigationReady && (!isAuthenticated || props.isSidebarLoaded) && hasAttemptedToOpenPublicRoom;
const shouldHideSplash = shouldInit && !isSplashHidden;

Expand Down Expand Up @@ -216,10 +226,12 @@ function Expensify(props) {

<AppleAuthWrapper />
{hasAttemptedToOpenPublicRoom && (
<NavigationRoot
onReady={setNavigationReady}
authenticated={isAuthenticated}
/>
<SplashScreenHiddenContext.Provider value={contextValue}>
<NavigationRoot
onReady={setNavigationReady}
authenticated={isAuthenticated}
/>
</SplashScreenHiddenContext.Provider>
)}

{shouldHideSplash && <SplashScreenHider onHide={onSplashHide} />}
Expand Down Expand Up @@ -251,3 +263,5 @@ export default compose(
},
}),
)(Expensify);

export {SplashScreenHiddenContext};
9 changes: 6 additions & 3 deletions src/hooks/useAutoFocusInput.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,24 @@
import {useFocusEffect} from '@react-navigation/native';
import {useCallback, useEffect, useRef, useState} from 'react';
import {useCallback, useContext, useEffect, useRef, useState} from 'react';
import CONST from '@src/CONST';
import * as Expensify from '@src/Expensify';

export default function useAutoFocusInput() {
const [isInputInitialized, setIsInputInitialized] = useState(false);
const [isScreenTransitionEnded, setIsScreenTransitionEnded] = useState(false);

const {isSplashHidden} = useContext(Expensify.SplashScreenHiddenContext);

const inputRef = useRef(null);
const focusTimeoutRef = useRef(null);

useEffect(() => {
if (!isScreenTransitionEnded || !isInputInitialized || !inputRef.current) {
if (!isScreenTransitionEnded || !isInputInitialized || !inputRef.current || !isSplashHidden) {
return;
}
inputRef.current.focus();
setIsScreenTransitionEnded(false);
}, [isScreenTransitionEnded, isInputInitialized]);
}, [isScreenTransitionEnded, isInputInitialized, isSplashHidden]);

useFocusEffect(
useCallback(() => {
Expand Down
8 changes: 4 additions & 4 deletions src/pages/NewChatPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import OptionsSelector from '@components/OptionsSelector';
import ScreenWrapper from '@components/ScreenWrapper';
import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
import withWindowDimensions, {windowDimensionsPropTypes} from '@components/withWindowDimensions';
import useDelayedInputFocus from '@hooks/useDelayedInputFocus';
import useAutoFocusInput from '@hooks/useAutoFocusInput';
import useNetwork from '@hooks/useNetwork';
import useWindowDimensions from '@hooks/useWindowDimensions';
import * as Browser from '@libs/Browser';
Expand Down Expand Up @@ -53,7 +53,6 @@ const defaultProps = {
const excludedGroupEmails = _.without(CONST.EXPENSIFY_EMAILS, CONST.EMAIL.CONCIERGE);

function NewChatPage({betas, isGroupChat, personalDetails, reports, translate, isSearchingForReports}) {
const optionSelectorRef = React.createRef(null);
const [searchTerm, setSearchTerm] = useState('');
const [filteredRecentReports, setFilteredRecentReports] = useState([]);
const [filteredPersonalDetails, setFilteredPersonalDetails] = useState([]);
Expand Down Expand Up @@ -216,7 +215,7 @@ function NewChatPage({betas, isGroupChat, personalDetails, reports, translate, i
setSearchTerm(text);
}, []);

useDelayedInputFocus(optionSelectorRef, 600);
const {inputCallbackRef} = useAutoFocusInput();

return (
<ScreenWrapper
Expand All @@ -239,7 +238,7 @@ function NewChatPage({betas, isGroupChat, personalDetails, reports, translate, i
>
<View style={[styles.flex1, styles.w100, styles.pRelative, selectedOptions.length > 0 ? safeAreaPaddingBottomStyle : {}]}>
<OptionsSelector
ref={optionSelectorRef}
ref={inputCallbackRef}
canSelectMultipleOptions
shouldShowMultipleOptionSelectorAsButton
multipleOptionSelectorButtonText={translate('newChatPage.addToGroup')}
Expand All @@ -260,6 +259,7 @@ function NewChatPage({betas, isGroupChat, personalDetails, reports, translate, i
textInputLabel={translate('optionsSelector.nameEmailOrPhoneNumber')}
safeAreaPaddingBottomStyle={safeAreaPaddingBottomStyle}
isLoadingNewOptions={isSearchingForReports}
autoFocus={false}
/>
</View>
{isSmallScreenWidth && <OfflineIndicator />}
Expand Down
8 changes: 4 additions & 4 deletions src/pages/tasks/TaskAssigneeSelectorModal.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* eslint-disable es/no-optional-chaining */
import lodashGet from 'lodash/get';
import PropTypes from 'prop-types';
import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
import React, {useCallback, useEffect, useMemo, useState} from 'react';
import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import _ from 'underscore';
Expand All @@ -11,6 +11,7 @@ import OptionsSelector from '@components/OptionsSelector';
import ScreenWrapper from '@components/ScreenWrapper';
import withCurrentUserPersonalDetails from '@components/withCurrentUserPersonalDetails';
import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
import useAutoFocusInput from '@hooks/useAutoFocusInput';
import compose from '@libs/compose';
import Navigation from '@libs/Navigation/Navigation';
import * as OptionsListUtils from '@libs/OptionsListUtils';
Expand Down Expand Up @@ -80,7 +81,7 @@ function TaskAssigneeSelectorModal(props) {
const [filteredCurrentUserOption, setFilteredCurrentUserOption] = useState(null);
const [isLoading, setIsLoading] = React.useState(true);

const optionRef = useRef();
const {inputCallbackRef} = useAutoFocusInput();

const updateOptions = useCallback(() => {
const {recentReports, personalDetails, userToInvite, currentUserOption} = OptionsListUtils.getFilteredOptions(
Expand Down Expand Up @@ -208,7 +209,6 @@ function TaskAssigneeSelectorModal(props) {
return (
<ScreenWrapper
includeSafeAreaPaddingBottom={false}
onEntryTransitionEnd={() => optionRef.current && optionRef.current.textInput.focus()}
testID={TaskAssigneeSelectorModal.displayName}
>
{({didScreenTransitionEnd, safeAreaPaddingBottomStyle}) => (
Expand All @@ -229,7 +229,7 @@ function TaskAssigneeSelectorModal(props) {
textInputLabel={props.translate('optionsSelector.nameEmailOrPhoneNumber')}
safeAreaPaddingBottomStyle={safeAreaPaddingBottomStyle}
autoFocus={false}
ref={optionRef}
ref={inputCallbackRef}
/>
</View>
</FullPageNotFoundView>
Expand Down
9 changes: 5 additions & 4 deletions src/pages/tasks/TaskShareDestinationSelectorModal.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
/* eslint-disable es/no-optional-chaining */
import PropTypes from 'prop-types';
import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
import React, {useCallback, useEffect, useMemo, useState} from 'react';
import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import _ from 'underscore';
import HeaderWithBackButton from '@components/HeaderWithBackButton';
import OptionsSelector from '@components/OptionsSelector';
import ScreenWrapper from '@components/ScreenWrapper';
import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
import useAutoFocusInput from '@hooks/useAutoFocusInput';
import useNetwork from '@hooks/useNetwork';
import * as Report from '@libs/actions/Report';
import compose from '@libs/compose';
Expand Down Expand Up @@ -51,8 +52,9 @@ function TaskShareDestinationSelectorModal(props) {
const [searchValue, setSearchValue] = useState('');
const [headerMessage, setHeaderMessage] = useState('');
const [filteredRecentReports, setFilteredRecentReports] = useState([]);

const {inputCallbackRef} = useAutoFocusInput();
const {isSearchingForReports} = props;
const optionRef = useRef();
const {isOffline} = useNetwork();

const filteredReports = useMemo(() => {
Expand Down Expand Up @@ -127,7 +129,6 @@ function TaskShareDestinationSelectorModal(props) {
return (
<ScreenWrapper
includeSafeAreaPaddingBottom={false}
onEntryTransitionEnd={() => optionRef.current && optionRef.current.textInput.focus()}
testID={TaskShareDestinationSelectorModal.displayName}
>
{({didScreenTransitionEnd, safeAreaPaddingBottomStyle}) => (
Expand All @@ -151,7 +152,7 @@ function TaskShareDestinationSelectorModal(props) {
textInputAlert={isOffline ? `${props.translate('common.youAppearToBeOffline')} ${props.translate('search.resultsAreLimited')}` : ''}
safeAreaPaddingBottomStyle={safeAreaPaddingBottomStyle}
autoFocus={false}
ref={optionRef}
ref={inputCallbackRef}
isLoadingNewOptions={isSearchingForReports}
/>
</View>
Expand Down
11 changes: 4 additions & 7 deletions src/pages/workspace/WorkspaceNewRoomPage.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import PropTypes from 'prop-types';
import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
import React, {useCallback, useEffect, useMemo, useState} from 'react';
import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import _ from 'underscore';
Expand All @@ -13,7 +13,7 @@ import Text from '@components/Text';
import TextInput from '@components/TextInput';
import ValuePicker from '@components/ValuePicker';
import withNavigationFocus from '@components/withNavigationFocus';
import useDelayedInputFocus from '@hooks/useDelayedInputFocus';
import useAutoFocusInput from '@hooks/useAutoFocusInput';
import useLocalize from '@hooks/useLocalize';
import useNetwork from '@hooks/useNetwork';
import useWindowDimensions from '@hooks/useWindowDimensions';
Expand Down Expand Up @@ -161,10 +161,7 @@ function WorkspaceNewRoomPage(props) {
[translate],
);

const roomNameInputRef = useRef(null);

// use a 600ms delay for delayed focus on the room name input field so that it works consistently on native iOS / Android
useDelayedInputFocus(roomNameInputRef, 600);
const {inputCallbackRef} = useAutoFocusInput();

return (
<FullPageNotFoundView
Expand Down Expand Up @@ -199,7 +196,7 @@ function WorkspaceNewRoomPage(props) {
>
<View style={styles.mb5}>
<RoomNameInput
ref={(el) => (roomNameInputRef.current = el)}
ref={inputCallbackRef}
inputID="roomName"
isFocused={props.isFocused}
shouldDelayFocus
Expand Down

0 comments on commit bf38a82

Please sign in to comment.