diff --git a/packages/mobile/src/MobileWebAppContainer.tsx b/packages/mobile/src/MobileWebAppContainer.tsx index 0a18c7d15..7c1b14a84 100644 --- a/packages/mobile/src/MobileWebAppContainer.tsx +++ b/packages/mobile/src/MobileWebAppContainer.tsx @@ -214,6 +214,7 @@ const MobileWebAppContents = ({ destroyAndReload }: { destroyAndReload: () => vo allowUniversalAccessFromFileURLs={true} injectedJavaScriptBeforeContentLoaded={injectedJS} bounces={false} + keyboardDisplayRequiresUserAction={false} /> ) } diff --git a/packages/web/src/javascripts/Components/ChallengeModal/ChallengeModal.tsx b/packages/web/src/javascripts/Components/ChallengeModal/ChallengeModal.tsx index 0f1ae4149..4c72031e1 100644 --- a/packages/web/src/javascripts/Components/ChallengeModal/ChallengeModal.tsx +++ b/packages/web/src/javascripts/Components/ChallengeModal/ChallengeModal.tsx @@ -10,7 +10,7 @@ import { removeFromArray, } from '@standardnotes/snjs' import { ProtectedIllustration } from '@standardnotes/icons' -import { FunctionComponent, useCallback, useEffect, useState } from 'react' +import { FunctionComponent, useCallback, useEffect, useRef, useState } from 'react' import Button from '@/Components/Button/Button' import Icon from '@/Components/Icon/Icon' import ChallengeModalPrompt from './ChallengePrompt' @@ -51,6 +51,8 @@ const ChallengeModal: FunctionComponent = ({ challenge, onDismiss, }) => { + const promptsContainerRef = useRef(null) + const [values, setValues] = useState(() => { const values = {} as ChallengeModalValues for (const prompt of challenge.prompts) { @@ -175,14 +177,21 @@ const ChallengeModal: FunctionComponent = ({ const biometricPrompt = challenge.prompts.find((prompt) => prompt.validation === ChallengeValidation.Biometric) const hasOnlyBiometricPrompt = challenge.prompts.length === 1 && !!biometricPrompt - const hasBiometricPromptValue = biometricPrompt && values[biometricPrompt.id].value + const wasBiometricInputSuccessful = biometricPrompt && !!values[biometricPrompt.id].value + const hasSecureTextPrompt = challenge.prompts.some((prompt) => prompt.secureTextEntry) useEffect(() => { - const shouldAutoSubmit = hasOnlyBiometricPrompt && hasBiometricPromptValue + const shouldAutoSubmit = hasOnlyBiometricPrompt && wasBiometricInputSuccessful + const shouldFocusSecureTextPrompt = hasSecureTextPrompt && wasBiometricInputSuccessful if (shouldAutoSubmit) { submit() + } else if (shouldFocusSecureTextPrompt) { + const secureTextEntry = promptsContainerRef.current?.querySelector( + 'input[type="password"]', + ) as HTMLInputElement | null + secureTextEntry?.focus() } - }, [hasBiometricPromptValue, hasOnlyBiometricPrompt, submit]) + }, [wasBiometricInputSuccessful, hasOnlyBiometricPrompt, submit, hasSecureTextPrompt]) useEffect(() => { const removeListener = application.addAndroidBackHandlerEventListener(() => { @@ -239,6 +248,7 @@ const ChallengeModal: FunctionComponent = ({ e.preventDefault() submit() }} + ref={promptsContainerRef} > {challenge.prompts.map((prompt, index) => (