Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F3515756
D14038.id46090.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
15 KB
Referenced Files
None
Subscribers
None
D14038.id46090.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D14038: [native] Navigate from the QR screen to the restore screen
Attached
Detach File
Event Timeline
Log In to Comment