Skip to content

Commit

Permalink
feat: new scan workflow (#1025)
Browse files Browse the repository at this point in the history
Signed-off-by: Jason C. Leach <[email protected]>
  • Loading branch information
jleach authored Nov 22, 2023
1 parent 2a448d0 commit 96349a5
Show file tree
Hide file tree
Showing 17 changed files with 310 additions and 102 deletions.
5 changes: 3 additions & 2 deletions .github/workflows/quality.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:

- uses: actions/setup-python@v4
with:
python-version: '3.11'
python-version: '3.11'

- name: Setup NodeJS
uses: ./.github/actions/setup-node
Expand Down Expand Up @@ -47,7 +47,7 @@ jobs:

- uses: actions/setup-python@v4
with:
python-version: '3.11'
python-version: '3.11'

- name: Setup NodeJS
uses: ./.github/actions/setup-node
Expand All @@ -65,3 +65,4 @@ jobs:
yarn run test:coverage
- uses: codecov/codecov-action@v3
if: always()
3 changes: 0 additions & 3 deletions packages/legacy/core/App/components/misc/NewQRView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,9 @@ const NewQRView: React.FC<Props> = ({ defaultToConnect, handleCodeScan, error, e
container: {
flex: 1,
backgroundColor: ColorPallet.brand.secondaryBackground,
justifyContent: 'space-between',
alignItems: 'center',
},
camera: {
flex: 1,
width: '100%',
justifyContent: 'center',
alignItems: 'center',
},
Expand Down
94 changes: 69 additions & 25 deletions packages/legacy/core/App/components/misc/QRScanner.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import { useNavigation } from '@react-navigation/core'
import React, { useState } from 'react'
import { useTranslation } from 'react-i18next'
import { Vibration, View, StyleSheet, Text } from 'react-native'
import { View, Modal, Vibration, Pressable, StyleSheet, Text } from 'react-native'
import { BarCodeReadEvent, RNCamera } from 'react-native-camera'
import Icon from 'react-native-vector-icons/MaterialIcons'
import Icon from 'react-native-vector-icons/MaterialCommunityIcons'

import { hitSlop } from '../../constants'
import { useTheme } from '../../contexts/theme'
import { QrCodeScanError } from '../../types/error'
import { Screens } from '../../types/navigators'
import { testIdWithKey } from '../../utils/testable'
import InfoBox, { InfoBoxType } from '../misc/InfoBox'

import QRScannerClose from './QRScannerClose'
import QRScannerTorch from './QRScannerTorch'

interface Props {
Expand All @@ -18,31 +20,17 @@ interface Props {
enableCameraOnError?: boolean
}

const CameraViewContainer: React.FC<React.PropsWithChildren> = ({ children }) => {
return (
<View
style={{
flex: 1,
flexDirection: 'column',
alignItems: 'center',
}}
>
{children}
</View>
)
}

const QRScanner: React.FC<Props> = ({ handleCodeScan, error, enableCameraOnError }) => {
const navigation = useNavigation()
const [cameraActive, setCameraActive] = useState(true)
const [torchActive, setTorchActive] = useState(false)
const [showInfoBox, setShowInfoBox] = useState(false)
const { t } = useTranslation()
const invalidQrCodes = new Set<string>()
const { ColorPallet, TextTheme } = useTheme()
const styles = StyleSheet.create({
container: {
height: '100%',
width: '100%',
flex: 1,
},
viewFinder: {
width: 250,
Expand All @@ -52,7 +40,7 @@ const QRScanner: React.FC<Props> = ({ handleCodeScan, error, enableCameraOnError
borderColor: ColorPallet.grayscale.white,
},
viewFinderContainer: {
flex: 1,
flexGrow: 1,
justifyContent: 'center',
alignItems: 'center',
},
Expand All @@ -66,8 +54,30 @@ const QRScanner: React.FC<Props> = ({ handleCodeScan, error, enableCameraOnError
},
})

const styleForState = ({ pressed }: { pressed: boolean }) => [{ opacity: pressed ? 0.2 : 1 }]

const toggleShowInfoBox = () => setShowInfoBox(!showInfoBox)

return (
<View style={styles.container}>
<Modal visible={showInfoBox} animationType="fade" transparent>
<View
style={{
flex: 1,
paddingHorizontal: 10,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'rgba(0,0,0,0.6)',
}}
>
<InfoBox
notificationType={InfoBoxType.Info}
title={t('Scan.BadQRCode')}
description={t('Scan.BadQRCodeDescription')}
onCallToActionPressed={toggleShowInfoBox}
/>
</View>
</Modal>
<RNCamera
style={styles.container}
type={RNCamera.Constants.Type.back}
Expand All @@ -84,25 +94,27 @@ const QRScanner: React.FC<Props> = ({ handleCodeScan, error, enableCameraOnError
if (invalidQrCodes.has(event.data)) {
return
}

if (error?.data === event?.data) {
invalidQrCodes.add(error.data)
if (enableCameraOnError) {
return setCameraActive(true)
}
}

if (cameraActive) {
Vibration.vibrate()
handleCodeScan(event)

return setCameraActive(false)
}
}}
>
<CameraViewContainer>
<QRScannerClose onPress={() => navigation.goBack()}></QRScannerClose>
<View style={{ flex: 1 }}>
<View style={styles.errorContainer}>
{error ? (
<>
<Icon style={styles.icon} name="cancel" size={30}></Icon>
<Icon style={styles.icon} name="cancel" size={30} />
<Text
testID={testIdWithKey('ErrorMessage')}
style={[TextTheme.caption, { color: ColorPallet.grayscale.white }]}
Expand All @@ -114,11 +126,43 @@ const QRScanner: React.FC<Props> = ({ handleCodeScan, error, enableCameraOnError
<Text style={[TextTheme.caption, { color: ColorPallet.grayscale.white, height: 30, margin: 4 }]}> </Text>
)}
</View>
<View style={{ flexDirection: 'row', marginHorizontal: 40, alignItems: 'center' }}>
<Icon name="qrcode-scan" size={46} style={{ color: 'white' }} />
<Text style={{ color: 'white', fontSize: 21, marginHorizontal: 10 }}>
A valid QR code will scan automatically.
</Text>
</View>
<View style={styles.viewFinderContainer}>
<View style={styles.viewFinder} />
</View>
<QRScannerTorch active={torchActive} onPress={() => setTorchActive(!torchActive)} />
</CameraViewContainer>
<View style={{ justifyContent: 'center', alignItems: 'center' }}>
<Pressable
accessibilityLabel={t('Scan.ScanNow')}
accessibilityRole={'button'}
testID={testIdWithKey('ScanNow')}
onPress={toggleShowInfoBox}
style={styleForState}
hitSlop={hitSlop}
>
<Icon name="circle-outline" size={60} style={{ color: 'white', marginBottom: -15 }} />
</Pressable>
</View>
<View style={{ marginHorizontal: 24, height: 24, marginBottom: 60, flexDirection: 'row' }}>
<Pressable
accessibilityLabel={t('Scan.ScanHelp')}
accessibilityRole={'button'}
testID={testIdWithKey('ScanHelp')}
// @ts-ignore
onPress={() => navigation.navigate(Screens.ScanHelp)}
style={styleForState}
hitSlop={hitSlop}
>
<Icon name="help-circle" size={24} style={{ color: 'white' }} />
</Pressable>
<View style={{ width: 10, marginLeft: 'auto' }} />
<QRScannerTorch active={torchActive} onPress={() => setTorchActive(!torchActive)} />
</View>
</View>
</RNCamera>
</View>
)
Expand Down
48 changes: 0 additions & 48 deletions packages/legacy/core/App/components/misc/QRScannerClose.tsx

This file was deleted.

5 changes: 3 additions & 2 deletions packages/legacy/core/App/components/misc/QRScannerTorch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ interface Props extends React.PropsWithChildren {
function createStyles({ ColorPallet }: ITheme) {
return StyleSheet.create({
container: {
width: 48,
height: 48,
width: 24,
height: 24,
justifyContent: 'center',
alignItems: 'center',
borderWidth: 1,
Expand All @@ -35,6 +35,7 @@ const TorchButton: React.FC<Props> = ({ active, onPress, children }) => {
const { t } = useTranslation()
const theme = useTheme()
const styles = createStyles(theme)

return (
<TouchableOpacity
accessible={true}
Expand Down
6 changes: 4 additions & 2 deletions packages/legacy/core/App/components/texts/Link.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ interface LinkProps {
style?: TextStyle
textProps?: TextProps
onPress: () => void
testID?: string
}

const Link: React.FC<LinkProps> = ({ linkText, onPress, style = {}, ...textProps }) => {
const Link: React.FC<LinkProps> = ({ linkText, onPress, style = {}, testID, ...textProps }) => {
const { TextTheme, ColorPallet } = useTheme()
const styles = StyleSheet.create({
link: {
Expand All @@ -21,13 +22,14 @@ const Link: React.FC<LinkProps> = ({ linkText, onPress, style = {}, ...textProps
alignSelf: 'flex-start',
},
})

return (
<Text
style={[styles.link, style]}
accessibilityLabel={linkText}
accessible
accessibilityRole={'link'}
testID={testIdWithKey(testIdForAccessabilityLabel(linkText))}
testID={testID ? testID : testIdWithKey(testIdForAccessabilityLabel(linkText))}
onPress={onPress}
{...textProps}
>
Expand Down
7 changes: 5 additions & 2 deletions packages/legacy/core/App/constants.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import { PINValidationRules } from './types/security'

export const dateIntFormat = 'YYYYMMDD'

const lengthOfhiddenAttributes = 10
const unicodeForBulletCharacter = '\u2022'

export const whereToUseWalletUrl = 'http://example.com'

export const dateIntFormat = 'YYYYMMDD'

export const hiddenFieldValue = Array(lengthOfhiddenAttributes).fill(unicodeForBulletCharacter).join('')
// Used to property prefix TestIDs so they can be looked up
// by on-device automated testing systems like SauceLabs.
Expand Down
11 changes: 10 additions & 1 deletion packages/legacy/core/App/localization/en/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,16 @@ const translation = {
"MyQRCode": "My QR code",
"UnableToHandleRedirection": "Unable to handle redirection",
"Close": "Close",
"Torch": "Flash"
"Torch": "Flash",
"ScanHelp": "Scan Help",
"ScanNow": "Scan Now",
"WhatToScan": "What QR Codes can be scanned?",
"ScanOnySpecial": "Only special QR codes can be scanned by Bifold Wallet.",
"ScanOnlySpecial2": "These are presented by participating services or people to receive a credential offer, request for information or to connect.",
"ScanOnlySpecial3": "Bifold Wallet currently doesn't support adding digital credential by scanning or taking photos of physical ones.",
"WhereToUseLink": "See where you can use Bifold Wallet",
"BadQRCode": "QR Code Not Recognized",
"BadQRCodeDescription": "Ths QR code scanned doesn't work with Bifold Wallet. Bifold Wallet only works with participating services.\n\nIt currently can't add digital credentials by taking photos of physical ones.",
},
"Connection": {
"JustAMoment": "Just a moment while we make a secure connection...",
Expand Down
10 changes: 9 additions & 1 deletion packages/legacy/core/App/localization/fr/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,15 @@ const translation = {
"MyQRCode": "My QR code (FR)",
"UnableToHandleRedirection": "Impossible de traiter la redirection",
"Close": "Fermer",
"Torch": "Flash"
"Torch": "Flash",
"ScanHelp": "Scan Help (FR)",
"ScanNow": "Scan Now (FR)",
"ScanOnySpecial": "Only special QR codes can be scanned by Bifold Wallet. (FR)",
"ScanOnlySpecial2": "These are presented by participating services or people to receive a credential offer, request for information or to connect. (FR)",
"ScanOnlySpecial3": "Bifold Wallet currently doesn't support adding digital credential by scanning or taking photos of physical ones. (FR)",
"WhereToUseLink": "See where you can use Bifold Wallet (FR)",
"BadQRCode": "QR Code Not Recognized (FR)",
"BadQRCodeDescription": "Ths QR code scanned doesn't work with Bifold Wallet. Bifold Wallet only works with participating services.\n\nIt currently can't add digital credentials by taking photos of physical ones. (FR)",
},
"Connection": {
"JustAMoment": "Veuillez patienter pendant que nous établissons une connexion sécurisée...",
Expand Down
10 changes: 9 additions & 1 deletion packages/legacy/core/App/localization/pt-br/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,15 @@ const translation = {
"MyQRCode": "Meu QR code",
"UnableToHandleRedirection": "Não foi possível tratar redirecionamento",
"Close": "Fechar",
"Torch": "Flash"
"Torch": "Flash",
"ScanHelp": "Scan Help (PB)",
"ScanNow": "Scan Now (PB)",
"ScanOnySpecial": "Only special QR codes can be scanned by Bifold Wallet. (PB)",
"ScanOnlySpecial2": "These are presented by participating services or people to receive a credential offer, request for information or to connect. (PB)",
"ScanOnlySpecial3": "Bifold Wallet currently doesn't support adding digital credential by scanning or taking photos of physical ones. (PB)",
"WhereToUseLink": "See where you can use Bifold Wallet (PB)",
"BadQRCode": "QR Code Not Recognized (PB)",
"BadQRCodeDescription": "Ths QR code scanned doesn't work with Bifold Wallet. Bifold Wallet only works with participating services.\n\nIt currently can't add digital credentials by taking photos of physical ones. (PB)",
},
"Connection": {
"JustAMoment": "Aguarde um momento enquanto fazemos uma conexão segura...",
Expand Down
Loading

0 comments on commit 96349a5

Please sign in to comment.