diff --git a/native/account/logged-out-modal-wrapper.react.js b/native/account/logged-out-modal-wrapper.react.js
new file mode 100644
--- /dev/null
+++ b/native/account/logged-out-modal-wrapper.react.js
@@ -0,0 +1,24 @@
+// @flow
+
+import * as React from 'react';
+
+import LoggedOutModal from './logged-out-modal.react.js';
+import type { RootNavigationProp } from '../navigation/root-navigator.react';
+import type { NavigationRoute } from '../navigation/route-names';
+
+type Props = {
+ +navigation: RootNavigationProp<'LoggedOutModal'>,
+ +route: NavigationRoute<'LoggedOutModal'>,
+};
+
+function LoggedOutModalWrapper(props: Props): React.Node {
+ return (
+
+ );
+}
+
+export default LoggedOutModalWrapper;
diff --git a/native/account/logged-out-modal.react.js b/native/account/logged-out-modal.react.js
--- a/native/account/logged-out-modal.react.js
+++ b/native/account/logged-out-modal.react.js
@@ -37,6 +37,7 @@
import LogInPanel from './log-in-panel.react.js';
import type { LogInState } from './log-in-panel.react.js';
import LoggedOutStaffInfo from './logged-out-staff-info.react.js';
+import type { SignInNavigationProp } from './sign-in-navigator.react';
import { authoritativeKeyserverID } from '../authoritative-keyserver.js';
import KeyboardAvoidingView from '../components/keyboard-avoiding-view.react.js';
import ConnectedStatusBar from '../connected-status-bar.react.js';
@@ -101,17 +102,19 @@
// prettier-ignore
function getPanelOpacity(
modeValue /*: string */,
- finishResettingToPrompt/*: () => void */,
+ finishResetting/*: () => void */,
) /*: number */ {
'worklet';
const targetPanelOpacity =
- modeValue === 'loading' || modeValue === 'prompt' ? 0 : 1;
+ modeValue === 'loading' || modeValue === 'prompt' || modeValue === 'restore'
+ ? 0
+ : 1;
return withTiming(
targetPanelOpacity,
timingConfig,
(succeeded /*?: boolean */) => {
if (succeeded && targetPanelOpacity === 0) {
- runOnJS(finishResettingToPrompt)();
+ runOnJS(finishResetting)();
}
},
);
@@ -240,11 +243,19 @@
+nextMode: LoggedOutMode,
};
-type Props = {
- +navigation: RootNavigationProp<'LoggedOutModal'>,
- +route: NavigationRoute<'LoggedOutModal'>,
-};
+type Props =
+ | {
+ +navigation: RootNavigationProp<'LoggedOutModal'>,
+ +route: NavigationRoute<'LoggedOutModal'>,
+ +defaultMode: 'prompt',
+ }
+ | {
+ +navigation: SignInNavigationProp<'RestoreScreen'>,
+ +route: NavigationRoute<'RestoreScreen'>,
+ +defaultMode: 'restore',
+ };
function LoggedOutModal(props: Props) {
+ const { defaultMode } = props;
const mountedRef = React.useRef(false);
React.useEffect(() => {
mountedRef.current = true;
@@ -276,7 +287,7 @@
);
const persistedStateLoaded = usePersistedStateLoaded();
- const initialMode = persistedStateLoaded ? 'prompt' : 'loading';
+ const initialMode = persistedStateLoaded ? defaultMode : 'loading';
const [mode, baseSetMode] = React.useState(() => ({
curMode: initialMode,
nextMode: initialMode,
@@ -298,16 +309,16 @@
const modeValue = useSharedValue(initialMode);
const buttonOpacity = useSharedValue(persistedStateLoaded ? 1 : 0);
- const onPrompt = mode.curMode === 'prompt';
- const prevOnPromptRef = React.useRef(onPrompt);
+ const onDefault = mode.curMode === defaultMode;
+ const prevOnDefaultRef = React.useRef(onDefault);
React.useEffect(() => {
- if (onPrompt && !prevOnPromptRef.current) {
+ if (onDefault && !prevOnDefaultRef.current) {
buttonOpacity.value = withTiming(1, {
easing: Easing.out(Easing.ease),
});
}
- prevOnPromptRef.current = onPrompt;
- }, [onPrompt, buttonOpacity]);
+ prevOnDefaultRef.current = onDefault;
+ }, [buttonOpacity, onDefault]);
const curContentHeight = dimensions.safeAreaHeight;
const prevContentHeightRef = React.useRef(curContentHeight);
@@ -328,20 +339,20 @@
[setMode, modeValue],
);
- const goBackToPrompt = React.useCallback(() => {
- nextModeRef.current = 'prompt';
- setMode({ nextMode: 'prompt' });
- modeValue.value = 'prompt';
+ const goBackToDefault = React.useCallback(() => {
+ nextModeRef.current = defaultMode;
+ setMode({ nextMode: defaultMode });
+ modeValue.value = defaultMode;
Keyboard.dismiss();
- }, [setMode, modeValue]);
+ }, [defaultMode, setMode, modeValue]);
const loadingCompleteRef = React.useRef(persistedStateLoaded);
React.useEffect(() => {
if (!loadingCompleteRef.current && persistedStateLoaded) {
- combinedSetMode('prompt');
+ combinedSetMode(defaultMode);
loadingCompleteRef.current = true;
}
- }, [persistedStateLoaded, combinedSetMode]);
+ }, [combinedSetMode, defaultMode, persistedStateLoaded]);
const [activeAlert, setActiveAlert] = React.useState(false);
@@ -366,19 +377,19 @@
const temporarilyHiddenPassword = React.useRef();
const curLogInPassword = logInState.passwordInputText;
- const resetToPrompt = React.useCallback(() => {
- if (nextModeRef.current === 'prompt') {
+ const resetToDefault = React.useCallback(() => {
+ if (nextModeRef.current === defaultMode) {
return false;
}
if (Platform.OS === 'ios' && curLogInPassword) {
temporarilyHiddenPassword.current = curLogInPassword;
setLogInState({ passwordInputText: null });
}
- goBackToPrompt();
+ goBackToDefault();
return true;
- }, [goBackToPrompt, curLogInPassword, setLogInState]);
+ }, [curLogInPassword, defaultMode, goBackToDefault, setLogInState]);
- const finishResettingToPrompt = React.useCallback(() => {
+ const finishResetting = React.useCallback(() => {
setMode({ curMode: nextModeRef.current });
if (temporarilyHiddenPassword.current) {
setLogInState({ passwordInputText: temporarilyHiddenPassword.current });
@@ -390,11 +401,11 @@
if (!isForeground) {
return undefined;
}
- BackHandler.addEventListener('hardwareBackPress', resetToPrompt);
+ BackHandler.addEventListener('hardwareBackPress', resetToDefault);
return () => {
- BackHandler.removeEventListener('hardwareBackPress', resetToPrompt);
+ BackHandler.removeEventListener('hardwareBackPress', resetToDefault);
};
- }, [isForeground, resetToPrompt]);
+ }, [isForeground, resetToDefault]);
const rehydrateConcluded = useSelector(
state => !!(state._persist && state._persist.rehydrated && navContext),
@@ -448,7 +459,7 @@
}, [navigate]);
const opacityStyle = useAnimatedStyle(() => ({
- opacity: getPanelOpacity(modeValue.value, finishResettingToPrompt),
+ opacity: getPanelOpacity(modeValue.value, finishResetting),
}));
const styles = useStyles(unboundStyles);
@@ -641,7 +652,7 @@
Comm
-
+
@@ -653,7 +664,7 @@
animatedContentStyle,
styles.header,
backButtonStyle,
- resetToPrompt,
+ resetToDefault,
panel,
],
);
@@ -666,11 +677,11 @@
}
return (
);
- }, [curModeIsSIWE, goBackToPrompt, nextModeIsPrompt]);
+ }, [curModeIsSIWE, goBackToDefault, nextModeIsPrompt]);
const splashStyle = useSelector(splashStyleSelector);
const backgroundStyle = React.useMemo(
diff --git a/native/account/qr-code-screen.react.js b/native/account/qr-code-screen.react.js
--- a/native/account/qr-code-screen.react.js
+++ b/native/account/qr-code-screen.react.js
@@ -8,9 +8,12 @@
import { qrCodeLinkURL } from 'lib/facts/links.js';
import { platformToIdentityDeviceType } from 'lib/types/identity-service-types.js';
import { getConfig } from 'lib/utils/config.js';
+import { usingRestoreFlow } from 'lib/utils/services-utils.js';
import type { SignInNavigationProp } from './sign-in-navigator.react.js';
+import LinkButton from '../components/link-button.react.js';
import type { NavigationRoute } from '../navigation/route-names.js';
+import { RestoreScreenRouteName } from '../navigation/route-names.js';
import { useStyles } from '../themes/colors.js';
type QRCodeScreenProps = {
@@ -18,7 +21,6 @@
+route: NavigationRoute<'QRCodeScreen'>,
};
-// eslint-disable-next-line no-unused-vars
function QRCodeScreen(props: QRCodeScreenProps): React.Node {
const { qrData, generateQRCode } = useQRAuthContext();
@@ -37,34 +39,56 @@
}, [platform, qrData]);
const styles = useStyles(unboundStyles);
+
+ let primaryRestoreButton = null;
+ const goToRestoreFlow = React.useCallback(() => {
+ props.navigation.navigate(RestoreScreenRouteName);
+ }, [props.navigation]);
+ if (usingRestoreFlow) {
+ primaryRestoreButton = (
+
+
+
+ );
+ }
+
return (
-
- Log in to Comm
-
- Open the Comm app on your logged-in phone and scan the QR code below
-
-
-
- How to find the scanner:
-
- Go to
- Profile
-
-
- Select
- Linked devices
-
-
- Click
- Add
- on the top right
+
+
+ Log in to Comm
+
+ Open the Comm app on your logged-in phone and scan the QR code below
+
+
+ How to find the scanner:
+
+ Go to
+ Profile
+
+
+ Select
+ Linked devices
+
+
+ Click
+ Add
+ on the top right
+
+
+ {primaryRestoreButton}
);
}
const unboundStyles = {
+ screenContainer: {
+ flex: 1,
+ },
container: {
flex: 1,
alignItems: 'center',
@@ -104,6 +128,10 @@
instructionsBold: {
fontWeight: 'bold',
},
+ primaryRestoreButton: {
+ alignItems: 'center',
+ marginBottom: 20,
+ },
};
export default QRCodeScreen;
diff --git a/native/account/restore-screen-wrapper.react.js b/native/account/restore-screen-wrapper.react.js
new file mode 100644
--- /dev/null
+++ b/native/account/restore-screen-wrapper.react.js
@@ -0,0 +1,24 @@
+// @flow
+
+import * as React from 'react';
+
+import LoggedOutModal from './logged-out-modal.react.js';
+import type { SignInNavigationProp } from './sign-in-navigator.react';
+import type { NavigationRoute } from '../navigation/route-names';
+
+type Props = {
+ +navigation: SignInNavigationProp<'RestoreScreen'>,
+ +route: NavigationRoute<'RestoreScreen'>,
+};
+
+function RestoreScreen(props: Props): React.Node {
+ return (
+
+ );
+}
+
+export default RestoreScreen;
diff --git a/native/account/sign-in-navigator.react.js b/native/account/sign-in-navigator.react.js
--- a/native/account/sign-in-navigator.react.js
+++ b/native/account/sign-in-navigator.react.js
@@ -9,11 +9,13 @@
import { SafeAreaView } from 'react-native-safe-area-context';
import QRCodeScreen from './qr-code-screen.react.js';
+import RestoreScreen from './restore-screen-wrapper.react.js';
import type { RootNavigationProp } from '../navigation/root-navigator.react.js';
import {
type ScreenParamList,
type SignInParamList,
QRCodeScreenRouteName,
+ RestoreScreenRouteName,
} from '../navigation/route-names.js';
import { useStyles, useColors } from '../themes/colors.js';
@@ -58,6 +60,10 @@
name={QRCodeScreenRouteName}
component={QRCodeScreen}
/>
+
);
diff --git a/native/navigation/root-navigator.react.js b/native/navigation/root-navigator.react.js
--- a/native/navigation/root-navigator.react.js
+++ b/native/navigation/root-navigator.react.js
@@ -58,7 +58,7 @@
RestoreSIWEBackupRouteName,
LinkedDevicesBottomSheetRouteName,
} from './route-names.js';
-import LoggedOutModal from '../account/logged-out-modal.react.js';
+import LoggedOutModalWrapper from '../account/logged-out-modal-wrapper.react.js';
import CreateMissingSIWEBackupMessage from '../account/registration/missing-registration-data/missing-siwe-backup-message.react.js';
import RegistrationNavigator from '../account/registration/registration-navigator.react.js';
import SignInNavigator from '../account/sign-in-navigator.react.js';
@@ -205,7 +205,7 @@