Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: new scan workflow #1025

Merged
merged 13 commits into from
Nov 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@
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 @@
borderColor: ColorPallet.grayscale.white,
},
viewFinderContainer: {
flex: 1,
flexGrow: 1,
justifyContent: 'center',
alignItems: 'center',
},
Expand All @@ -66,8 +54,30 @@
},
})

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 @@
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 @@
<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)}

Check warning on line 156 in packages/legacy/core/App/components/misc/QRScanner.tsx

View check run for this annotation

Codecov / codecov/patch

packages/legacy/core/App/components/misc/QRScanner.tsx#L156

Added line #L156 was not covered by tests
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)} />

Check warning on line 163 in packages/legacy/core/App/components/misc/QRScanner.tsx

View check run for this annotation

Codecov / codecov/patch

packages/legacy/core/App/components/misc/QRScanner.tsx#L163

Added line #L163 was not covered by tests
</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