Page MenuHomePhabricator

D14038.id46090.diff
No OneTemporary

D14038.id46090.diff

diff --git a/lib/utils/services-utils.js b/lib/utils/services-utils.js
--- a/lib/utils/services-utils.js
+++ b/lib/utils/services-utils.js
@@ -21,7 +21,7 @@
// If this is true, then we're using the login 2.0, which means that a user
// can either restore an account (primary login) or log in using the QR code
// (secondary login).
-const usingRestoreFlow = false;
+const usingRestoreFlow = true;
function handleHTTPResponseError(response: Response): void {
if (!response.ok) {
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 (
+ <LoggedOutModal
+ navigation={props.navigation}
+ route={props.route}
+ defaultMode="prompt"
+ />
+ );
+}
+
+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<?string>();
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 @@
<View>
<Text style={styles.header}>Comm</Text>
<AnimatedView style={backButtonStyle}>
- <TouchableOpacity activeOpacity={0.6} onPress={resetToPrompt}>
+ <TouchableOpacity activeOpacity={0.6} onPress={resetToDefault}>
<Icon name="arrow-circle-o-left" size={36} color="#FFFFFFAA" />
</TouchableOpacity>
</AnimatedView>
@@ -653,7 +664,7 @@
animatedContentStyle,
styles.header,
backButtonStyle,
- resetToPrompt,
+ resetToDefault,
panel,
],
);
@@ -666,11 +677,11 @@
}
return (
<FullscreenSIWEPanel
- goBackToPrompt={goBackToPrompt}
+ goBackToPrompt={goBackToDefault}
closing={nextModeIsPrompt}
/>
);
- }, [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 = (
+ <View style={styles.primaryRestoreButton}>
+ <LinkButton
+ text="Not logged in on another phone?"
+ onPress={goToRestoreFlow}
+ />
+ </View>
+ );
+ }
+
return (
- <View style={styles.container}>
- <Text style={styles.heading}>Log in to Comm</Text>
- <Text style={styles.headingSubtext}>
- Open the Comm app on your logged-in phone and scan the QR code below
- </Text>
- <QRCode value={qrCodeURL} size={200} />
- <View style={styles.instructionsBox}>
- <Text style={styles.instructionsTitle}>How to find the scanner:</Text>
- <Text style={styles.instructionsStep}>
- <Text>Go to </Text>
- <Text style={styles.instructionsBold}>Profile</Text>
- </Text>
- <Text style={styles.instructionsStep}>
- <Text>Select </Text>
- <Text style={styles.instructionsBold}>Linked devices </Text>
- </Text>
- <Text style={styles.instructionsStep}>
- <Text>Click </Text>
- <Text style={styles.instructionsBold}>Add </Text>
- <Text>on the top right</Text>
+ <View style={styles.screenContainer}>
+ <View style={styles.container}>
+ <Text style={styles.heading}>Log in to Comm</Text>
+ <Text style={styles.headingSubtext}>
+ Open the Comm app on your logged-in phone and scan the QR code below
</Text>
+ <QRCode value={qrCodeURL} size={200} />
+ <View style={styles.instructionsBox}>
+ <Text style={styles.instructionsTitle}>How to find the scanner:</Text>
+ <Text style={styles.instructionsStep}>
+ <Text>Go to </Text>
+ <Text style={styles.instructionsBold}>Profile</Text>
+ </Text>
+ <Text style={styles.instructionsStep}>
+ <Text>Select </Text>
+ <Text style={styles.instructionsBold}>Linked devices </Text>
+ </Text>
+ <Text style={styles.instructionsStep}>
+ <Text>Click </Text>
+ <Text style={styles.instructionsBold}>Add </Text>
+ <Text>on the top right</Text>
+ </Text>
+ </View>
</View>
+ {primaryRestoreButton}
</View>
);
}
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 (
+ <LoggedOutModal
+ navigation={props.navigation}
+ route={props.route}
+ defaultMode="restore"
+ />
+ );
+}
+
+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}
/>
+ <QRCodeSignInStack.Screen
+ name={RestoreScreenRouteName}
+ component={RestoreScreen}
+ />
</QRCodeSignInStack.Navigator>
</SafeAreaView>
);
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 @@
<Root.Navigator screenOptions={defaultScreenOptions}>
<Root.Screen
name={LoggedOutModalRouteName}
- component={LoggedOutModal}
+ component={LoggedOutModalWrapper}
options={disableGesturesScreenOptions}
/>
<Root.Screen
diff --git a/native/navigation/route-names.js b/native/navigation/route-names.js
--- a/native/navigation/route-names.js
+++ b/native/navigation/route-names.js
@@ -151,6 +151,7 @@
export const CreateRolesScreenRouteName = 'CreateRolesScreen';
export const SignInNavigatorRouteName = 'SignInNavigator';
export const QRCodeScreenRouteName = 'QRCodeScreen';
+export const RestoreScreenRouteName = 'RestoreScreen';
export const UserProfileBottomSheetNavigatorRouteName =
'UserProfileBottomSheetNavigator';
export const UserProfileBottomSheetRouteName = 'UserProfileBottomSheet';
@@ -335,6 +336,7 @@
export type SignInParamList = {
+QRCodeScreen: void,
+ +RestoreScreen: void,
};
export type UserProfileBottomSheetParamList = {

File Metadata

Mime Type
text/plain
Expires
Mon, Dec 23, 10:05 AM (4 h, 17 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2694426
Default Alt Text
D14038.id46090.diff (15 KB)

Event Timeline