diff --git a/native/account/qr-auth-progress-screen.react.js b/native/account/qr-auth-progress-screen.react.js
new file mode 100644
--- /dev/null
+++ b/native/account/qr-auth-progress-screen.react.js
@@ -0,0 +1,206 @@
+// @flow
+
+import { useFocusEffect } from '@react-navigation/core';
+import * as React from 'react';
+import { View, Text } from 'react-native';
+import * as Progress from 'react-native-progress';
+
+import { useSecondaryDeviceQRAuthContext } from 'lib/components/secondary-device-qr-auth-context-provider.react.js';
+
+import AuthContainer from './auth-components/auth-container.react.js';
+import AuthContentContainer from './auth-components/auth-content-container.react.js';
+import type { AuthNavigationProp } from './registration/auth-navigator.react.js';
+import {
+ RestoreBackupErrorScreenRouteName,
+ type NavigationRoute,
+} from '../navigation/route-names.js';
+import { useSelector } from '../redux/redux-utils.js';
+import { useColors, useStyles } from '../themes/colors.js';
+
+type ProgressStepProps = {
+ +stepNumber: string,
+ +state: 'pending' | 'active' | 'completed',
+ +label: string,
+};
+
+function ProgressStep(props: ProgressStepProps): React.Node {
+ const { stepNumber, state, label } = props;
+ const styles = useStyles(unboundStyles);
+ // const colors = useColors();
+
+ const stepStyle = React.useMemo(() => {
+ switch (state) {
+ case 'completed':
+ return [styles.stepIcon, styles.stepIconCompleted];
+ case 'active':
+ return [styles.stepIcon, styles.stepIconActive];
+ default:
+ return [styles.stepIcon, styles.stepIconPending];
+ }
+ }, [state, styles]);
+
+ const stepContent = state === 'completed' ? '✓' : stepNumber;
+
+ return (
+
+
+ {stepContent}
+
+
+ {label}
+
+
+ );
+}
+
+type Props = {
+ +navigation: AuthNavigationProp<'QRAuthProgressScreen'>,
+ +route: NavigationRoute<'QRAuthProgressScreen'>,
+};
+
+function QRAuthProgressScreen(props: Props): React.Node {
+ const styles = useStyles(unboundStyles);
+ const colors = useColors();
+
+ const { qrAuthInProgress } = useSecondaryDeviceQRAuthContext();
+ const userDataRestoreStatus = useSelector(
+ state => state.restoreBackupState.status,
+ );
+
+ useFocusEffect(
+ React.useCallback(() => {
+ if (userDataRestoreStatus === 'user_data_restore_failed') {
+ props.navigation.navigate(RestoreBackupErrorScreenRouteName, {
+ deviceType: 'secondary',
+ });
+ }
+ }, [props.navigation, userDataRestoreStatus]),
+ );
+
+ const userDataRestoreStarted = userDataRestoreStatus !== 'no_backup';
+ const step: 'authenticating' | 'restoring' =
+ qrAuthInProgress && !userDataRestoreStarted
+ ? 'authenticating'
+ : 'restoring';
+
+ const authStepState = step === 'authenticating' ? 'active' : 'completed';
+ const restoringStepState = step === 'restoring' ? 'active' : 'pending';
+ const title =
+ step === 'authenticating' ? 'Authenticating device' : 'Restoring your data';
+
+ return (
+
+
+ {title}...
+
+
+
+
+
+
+
+
+
+ You will be automatically navigated to the app after this process is
+ finished.
+
+
+
+
+
+
+ );
+}
+
+const unboundStyles = {
+ container: {
+ flex: 1,
+ },
+ title: {
+ fontSize: 24,
+ color: 'panelForegroundLabel',
+ paddingBottom: 40,
+ },
+ section: {
+ fontFamily: 'Arial',
+ fontSize: 15,
+ lineHeight: 20,
+ color: 'panelForegroundSecondaryLabel',
+ paddingBottom: 16,
+ },
+ progressContainer: {
+ flexGrow: 1,
+ alignItems: 'center',
+ justifyContent: 'center',
+ },
+ progressSteps: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ justifyContent: 'center',
+ marginBottom: 24,
+ },
+ stepContainer: {
+ alignItems: 'center',
+ justifyContent: 'center',
+ },
+ stepIcon: {
+ width: 40,
+ height: 40,
+ borderRadius: 20,
+ alignItems: 'center',
+ justifyContent: 'center',
+ marginBottom: 4,
+ },
+ stepIconPending: {
+ backgroundColor: 'transparent',
+ borderWidth: 2,
+ borderColor: 'panelSecondaryForegroundBorder',
+ },
+ stepIconActive: {
+ backgroundColor: 'purpleButton',
+ borderWidth: 2,
+ borderColor: 'violetLight100',
+ },
+ stepIconCompleted: {
+ backgroundColor: 'greenIndicatorInner',
+ borderWidth: 2,
+ borderColor: 'greenIndicatorOuter',
+ },
+ stepIconText: {
+ color: 'panelForegroundIcon',
+ fontSize: 16,
+ fontWeight: 'bold',
+ },
+ stepLabelContainer: {
+ maxWidth: 100,
+ height: 48,
+ justifyContent: 'center',
+ },
+ stepLabel: {
+ color: 'panelForegroundLabel',
+ fontSize: 14,
+ textAlign: 'center',
+ },
+ stepConnector: {
+ width: 30,
+ height: 2,
+ backgroundColor: 'panelSecondaryForegroundBorder',
+ marginHorizontal: 10,
+ marginBottom: 48,
+ },
+};
+
+export default QRAuthProgressScreen;
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
@@ -22,7 +22,10 @@
import type { AuthNavigationProp } from './registration/auth-navigator.react.js';
import LinkButton from '../components/link-button.react.js';
import type { NavigationRoute } from '../navigation/route-names.js';
-import { RestorePromptScreenRouteName } from '../navigation/route-names.js';
+import {
+ RestorePromptScreenRouteName,
+ QRAuthProgressScreenRouteName,
+} from '../navigation/route-names.js';
import { useColors, useStyles } from '../themes/colors.js';
type QRCodeScreenProps = {
@@ -31,8 +34,13 @@
};
function QRCodeScreen(props: QRCodeScreenProps): React.Node {
- const { qrData, openSecondaryQRAuth, closeSecondaryQRAuth, canGenerateQRs } =
- useSecondaryDeviceQRAuthContext();
+ const {
+ qrData,
+ openSecondaryQRAuth,
+ closeSecondaryQRAuth,
+ canGenerateQRs,
+ qrAuthInProgress,
+ } = useSecondaryDeviceQRAuthContext();
const [attemptNumber, setAttemptNumber] = React.useState(0);
@@ -59,6 +67,14 @@
}, [closeSecondaryQRAuth]),
);
+ useFocusEffect(
+ React.useCallback(() => {
+ if (qrAuthInProgress) {
+ props.navigation.navigate(QRAuthProgressScreenRouteName);
+ }
+ }, [qrAuthInProgress, props.navigation]),
+ );
+
const { platform } = getConfig().platformDetails;
const qrCodeURL = React.useMemo(() => {
if (!qrData || !canGenerateQRs) {
diff --git a/native/account/registration/auth-navigator.react.js b/native/account/registration/auth-navigator.react.js
--- a/native/account/registration/auth-navigator.react.js
+++ b/native/account/registration/auth-navigator.react.js
@@ -55,6 +55,7 @@
type ScreenParamList,
type AuthParamList,
QRCodeScreenRouteName,
+ QRAuthProgressScreenRouteName,
RestorePromptScreenRouteName,
RestorePasswordAccountScreenRouteName,
RestoreBackupScreenRouteName,
@@ -62,6 +63,7 @@
RestoreSIWEBackupRouteName,
ConnectFarcasterDCsRouteName,
} from '../../navigation/route-names.js';
+import QRAuthProgressScreen from '../qr-auth-progress-screen.react.js';
import QRCodeScreen from '../qr-code-screen.react.js';
import RestoreBackupErrorScreen from '../restore-backup-error-screen.react.js';
import RestoreBackupScreen from '../restore-backup-screen.react.js';
@@ -214,6 +216,11 @@
component={AccountDoesNotExist}
/>
+