Page MenuHomePhabricator

D8805.id29862.diff
No OneTemporary

D8805.id29862.diff

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
@@ -95,6 +95,8 @@
'RelationshipListItemTooltipModal';
export const RobotextMessageTooltipModalRouteName =
'RobotextMessageTooltipModal';
+export const SecondaryDeviceQRCodeScannerRouteName =
+ 'SecondaryDeviceQRCodeScanner';
export const SidebarListModalRouteName = 'SidebarListModal';
export const SubchannelsListModalRouteName = 'SubchannelsListModal';
export const TabNavigatorRouteName = 'TabNavigator';
@@ -217,6 +219,7 @@
+FriendList: void,
+BlockList: void,
+LinkedDevices: void,
+ +SecondaryDeviceQRCodeScanner: void,
};
export type CommunityDrawerParamList = { +TabNavigator: void };
diff --git a/native/profile/linked-devices-header-right-button.react.js b/native/profile/linked-devices-header-right-button.react.js
--- a/native/profile/linked-devices-header-right-button.react.js
+++ b/native/profile/linked-devices-header-right-button.react.js
@@ -1,15 +1,23 @@
// @flow
+import { useNavigation } from '@react-navigation/native';
import * as React from 'react';
import { Text, TouchableOpacity } from 'react-native';
+import { SecondaryDeviceQRCodeScannerRouteName } from '../navigation/route-names.js';
import { useStyles } from '../themes/colors.js';
function LinkedDevicesHeaderRightButton(): React.Node {
const styles = useStyles(unboundStyles);
+ const navigation = useNavigation();
+
+ const navigateToQRCodeScanner = React.useCallback(
+ () => navigation.navigate(SecondaryDeviceQRCodeScannerRouteName),
+ [navigation],
+ );
return (
- <TouchableOpacity onPress={null}>
+ <TouchableOpacity onPress={navigateToQRCodeScanner}>
<Text style={styles.textStyle}>Add</Text>
</TouchableOpacity>
);
diff --git a/native/profile/profile.react.js b/native/profile/profile.react.js
--- a/native/profile/profile.react.js
+++ b/native/profile/profile.react.js
@@ -22,6 +22,7 @@
import ProfileHeader from './profile-header.react.js';
import ProfileScreen from './profile-screen.react.js';
import RelationshipList from './relationship-list.react.js';
+import SecondaryDeviceQRCodeScanner from './secondary-device-qr-code-scanner.react.js';
import KeyboardAvoidingView from '../components/keyboard-avoiding-view.react.js';
import CommunityDrawerButton from '../navigation/community-drawer-button.react.js';
import type { CommunityDrawerNavigationProp } from '../navigation/community-drawer-navigator.react.js';
@@ -39,6 +40,7 @@
DefaultNotificationsPreferencesRouteName,
BlockListRouteName,
LinkedDevicesRouteName,
+ SecondaryDeviceQRCodeScannerRouteName,
type ScreenParamList,
type ProfileParamList,
} from '../navigation/route-names.js';
@@ -57,6 +59,10 @@
// eslint-disable-next-line react/display-name
headerRight: () => <LinkedDevicesHeaderRightButton />,
};
+const secondaryDeviceQRCodeScannerOptions = {
+ headerTitle: '',
+ headerBackTitleVisible: false,
+};
const buildInfoOptions = { headerTitle: 'Build info' };
const devToolsOptions = { headerTitle: 'Developer tools' };
const appearanceOptions = { headerTitle: 'Appearance' };
@@ -142,6 +148,11 @@
component={LinkedDevices}
options={linkedDevicesOptions}
/>
+ <Profile.Screen
+ name={SecondaryDeviceQRCodeScannerRouteName}
+ component={SecondaryDeviceQRCodeScanner}
+ options={secondaryDeviceQRCodeScannerOptions}
+ />
<Profile.Screen
name={BuildInfoRouteName}
component={BuildInfo}
diff --git a/native/profile/secondary-device-qr-code-scanner.react.js b/native/profile/secondary-device-qr-code-scanner.react.js
new file mode 100644
--- /dev/null
+++ b/native/profile/secondary-device-qr-code-scanner.react.js
@@ -0,0 +1,116 @@
+// @flow
+
+import { useNavigation } from '@react-navigation/native';
+import { BarCodeScanner, type BarCodeEvent } from 'expo-barcode-scanner';
+import * as React from 'react';
+import { View } from 'react-native';
+
+import { useStyles } from '../themes/colors.js';
+import Alert from '../utils/alert.js';
+
+const barCodeTypes = [BarCodeScanner.Constants.BarCodeType.qr];
+
+// eslint-disable-next-line no-unused-vars
+function SecondaryDeviceQRCodeScanner(props: { ... }): React.Node {
+ const [hasPermission, setHasPermission] = React.useState(null);
+ const [scanned, setScanned] = React.useState(false);
+
+ const styles = useStyles(unboundStyles);
+ const navigation = useNavigation();
+
+ React.useEffect(() => {
+ const getBarCodeScannerPermissions = async () => {
+ const { status } = await BarCodeScanner.requestPermissionsAsync();
+ setHasPermission(status === 'granted');
+ };
+
+ getBarCodeScannerPermissions();
+ }, []);
+
+ React.useEffect(() => {
+ if (hasPermission === false) {
+ Alert.alert(
+ 'No access to camera',
+ 'Please allow Comm to access your camera in order to scan the QR code.',
+ [{ text: 'OK' }],
+ { cancelable: true },
+ );
+
+ navigation.goBack();
+ }
+ }, [hasPermission, navigation]);
+
+ const onConnect = React.useCallback((barCodeEvent: BarCodeEvent) => {
+ const { type, data } = barCodeEvent;
+ Alert.alert(
+ 'Scan successful',
+ `Bar code with type ${type} and data ${data} has been scanned!`,
+ [{ text: 'OK' }],
+ { cancelable: false },
+ );
+ }, []);
+
+ const onCancelScan = React.useCallback(() => setScanned(false), []);
+
+ const handleBarCodeScanned = React.useCallback(
+ (barCodeEvent: BarCodeEvent) => {
+ setScanned(true);
+ Alert.alert(
+ 'Connect with this device?',
+ 'Are you sure you want to allow this device to log in to your account?',
+ [
+ {
+ text: 'Cancel',
+ style: 'cancel',
+ onPress: onCancelScan,
+ },
+ {
+ text: 'Connect',
+ onPress: () => onConnect(barCodeEvent),
+ },
+ ],
+ { cancelable: false },
+ );
+ },
+ [onCancelScan, onConnect],
+ );
+
+ if (hasPermission === null) {
+ return <View />;
+ }
+
+ // Note: According to the BarCodeScanner Expo docs, we should adhere to two
+ // guidances when using the BarCodeScanner:
+ // 1. We should specify the potential barCodeTypes we want to scan for to
+ // minimize battery usage.
+ // 2. We should set the onBarCodeScanned callback to undefined if it scanned
+ // in order to 'pause' the scanner from continuing to scan while we
+ // process the data from the scan.
+ // See: https://docs.expo.io/versions/latest/sdk/bar-code-scanner
+ return (
+ <View style={styles.container}>
+ <BarCodeScanner
+ onBarCodeScanned={scanned ? undefined : handleBarCodeScanned}
+ barCodeTypes={barCodeTypes}
+ style={styles.scanner}
+ />
+ </View>
+ );
+}
+
+const unboundStyles = {
+ container: {
+ flex: 1,
+ flexDirection: 'column',
+ justifyContent: 'center',
+ },
+ scanner: {
+ position: 'absolute',
+ top: 0,
+ left: 0,
+ right: 0,
+ bottom: 0,
+ },
+};
+
+export default SecondaryDeviceQRCodeScanner;

File Metadata

Mime Type
text/plain
Expires
Mon, Dec 23, 2:39 PM (13 h, 33 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2694909
Default Alt Text
D8805.id29862.diff (7 KB)

Event Timeline