From 8d7ff81cfc8391a4f75209a0042d6d615b9f95d4 Mon Sep 17 00:00:00 2001
From: jemubm <105349292+jemubm@users.noreply.github.com>
Date: Sun, 16 Jul 2023 16:10:31 +0100
Subject: [PATCH 1/9] refactor: Revamp qr scanner (#2527)
Signed-off-by: jemubm <105349292+jemubm@users.noreply.github.com>
Co-authored-by: Juliano Lazzarotto <30806844+stackchain@users.noreply.github.com>
---
.../src/TxHistory/TxHistoryNavigator.tsx | 6 +-
.../QRCodeScanner/QRCodeScanner.stories.tsx | 32 +-
.../QRCodeScanner/QRCodeScanner.tsx | 281 +++++++++++++++++-
.../src/features/Send/common/strings.ts | 5 +
.../InputReceiver/ReadQRCodeScreen.tsx | 4 +-
.../wallet-mobile/src/i18n/locales/en-US.json | 1 +
apps/wallet-mobile/src/navigation.tsx | 12 +-
7 files changed, 314 insertions(+), 27 deletions(-)
diff --git a/apps/wallet-mobile/src/TxHistory/TxHistoryNavigator.tsx b/apps/wallet-mobile/src/TxHistory/TxHistoryNavigator.tsx
index 4ad78dba1f..9655590e5c 100644
--- a/apps/wallet-mobile/src/TxHistory/TxHistoryNavigator.tsx
+++ b/apps/wallet-mobile/src/TxHistory/TxHistoryNavigator.tsx
@@ -15,6 +15,7 @@ import {EditAmountScreen} from '../features/Send/useCases/ListAmountsToSend/Edit
import {ReadQRCodeScreen} from '../features/Send/useCases/StartMultiTokenTx/InputReceiver/ReadQRCodeScreen'
import {StartMultiTokenTxScreen} from '../features/Send/useCases/StartMultiTokenTx/StartMultiTokenTxScreen'
import {
+ BackButton,
defaultStackNavigationOptions,
defaultStackNavigationOptionsV2,
TxHistoryRoutes,
@@ -141,8 +142,11 @@ export const TxHistoryNavigator = () => {
name="send-read-qr-code"
component={ReadQRCodeScreen}
options={{
- title: strings.qrScannerTitle,
...sendOptions,
+ headerTransparent: true,
+ title: strings.qrScannerTitle,
+ headerTintColor: '#fff',
+ headerLeft: (props) => ,
}}
/>
diff --git a/apps/wallet-mobile/src/components/QRCodeScanner/QRCodeScanner.stories.tsx b/apps/wallet-mobile/src/components/QRCodeScanner/QRCodeScanner.stories.tsx
index 11726062f8..3865a7037c 100644
--- a/apps/wallet-mobile/src/components/QRCodeScanner/QRCodeScanner.stories.tsx
+++ b/apps/wallet-mobile/src/components/QRCodeScanner/QRCodeScanner.stories.tsx
@@ -4,6 +4,7 @@ import {Camera} from 'expo-camera'
import React from 'react'
import {Text, View} from 'react-native'
+import {Button} from '../Button'
import {Spacer} from '../Spacer'
import {QRCodeScanner} from './QRCodeScanner'
@@ -13,44 +14,51 @@ const Wrapper = () => {
const [status] = Camera.useCameraPermissions()
const [publicKeyHex, setPublicKeyHex] = React.useState(null)
const [path, setPath] = React.useState(null)
+ const [withMask, setMaskEnabled] = React.useState(true)
const handleOnRead = async ({data}) => {
const parsedData = JSON.parse(data)
+
setPublicKeyHex(parsedData.publicKeyHex)
setPath(parsedData.path)
action('onRead')
- return Promise.resolve(false)
+
+ return Promise.resolve(true)
}
return (
-
+
-
- QR DATA
+
+
- {`publicKeyHex: ${publicKeyHex}`}
+
- {`path: ${path}`}
+
- PREMISSIONS STATUS
+
- NOTE: To reset permissions, reinstall the app
+
- {`status: ${status?.status}`}
+
- {`granted: ${status?.granted}`}
+
- {`expires: ${status?.expires}`}
+
- {`canAskAgain: ${status?.canAskAgain}`}
+
+
+
)
}
+
+const Info = ({text}) => {text}
diff --git a/apps/wallet-mobile/src/components/QRCodeScanner/QRCodeScanner.tsx b/apps/wallet-mobile/src/components/QRCodeScanner/QRCodeScanner.tsx
index 7d5efaee5f..712be911e4 100644
--- a/apps/wallet-mobile/src/components/QRCodeScanner/QRCodeScanner.tsx
+++ b/apps/wallet-mobile/src/components/QRCodeScanner/QRCodeScanner.tsx
@@ -1,11 +1,23 @@
-import {BarCodeScanner} from 'expo-barcode-scanner'
+import {BarCodeBounds, BarCodeScanner, BarCodeScannerResult} from 'expo-barcode-scanner'
import {Camera} from 'expo-camera'
import * as React from 'react'
-import {StyleSheet} from 'react-native'
+import {StyleSheet, Text, useWindowDimensions, View} from 'react-native'
+import {Path, Svg} from 'react-native-svg'
-export const QRCodeScanner = ({onRead}: {onRead: ({data}: {data: string}) => Promise}) => {
+export const QRCodeScanner = ({
+ onRead,
+ withMask,
+ maskText = '',
+}: {
+ onRead: (event: BarCodeScannerResult) => Promise
+ withMask?: boolean
+ maskText?: string
+}) => {
const [status, requestPermissions] = Camera.useCameraPermissions()
+ const {height: deviceHeight, width: deviceWidth} = useWindowDimensions()
const [qrScanned, setQrScanned] = React.useState(false)
+
+ const scannerBounds = getScannerBounds({deviceHeight, deviceWidth})
const granted = status && status.granted
React.useEffect(() => {
@@ -15,7 +27,18 @@ export const QRCodeScanner = ({onRead}: {onRead: ({data}: {data: string}) => Pro
}, [granted, requestPermissions])
const handleBarCodeScanned = async (event) => {
- if (!qrScanned) {
+ const isQrInsideScannerBounds =
+ withMask && (event.bounds !== undefined || event.boundingBox !== undefined)
+ ? getIsQrInsideScannerBounds({
+ qrBounds: event.bounds,
+ qrBoundingBox: event.boundingBox,
+ scannerBounds,
+ deviceHeight,
+ deviceWidth,
+ })
+ : true
+
+ if (!qrScanned && isQrInsideScannerBounds) {
setQrScanned(true)
const error = await onRead(event)
@@ -30,15 +53,257 @@ export const QRCodeScanner = ({onRead}: {onRead: ({data}: {data: string}) => Pro
}
return (
- // expo-barcode-scanner issue in android https://github.com/expo/expo/issues/5212
- // so expo-camera is used
+ /*
+ * expo-barcode-scanner issue in android https://github.com/expo/expo/issues/5212
+ * so expo-camera is used
+ */
+ >
+ {withMask && }
+
+ )
+}
+
+const Mask = ({maskText}: {maskText: string}) => (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {maskText}
+
+
+)
+
+const LayerTop = ({children}: {children?: React.ReactNode}) => {children}
+const LayerCenter = ({children}: {children?: React.ReactNode}) => {children}
+const LayerCenterLeft = ({children}: {children?: React.ReactNode}) => (
+ {children}
+)
+const LayerCenterRight = ({children}: {children?: React.ReactNode}) => (
+ {children}
+)
+const LayerBottom = ({children}: {children?: React.ReactNode}) => {children}
+const CameraOpening = ({children}: {children?: React.ReactNode}) => {children}
+const InnerCameraOpeningTop = ({children}: {children?: React.ReactNode}) => (
+ {children}
+)
+const InnerCameraOpeningCenter = ({children}: {children?: React.ReactNode}) => (
+ {children}
+)
+const InnerCameraOpeningBottom = ({children}: {children?: React.ReactNode}) => (
+ {children}
+)
+const TopLeftCorner = () =>
+const TopRightCorner = () =>
+const BottomRightCorner = () =>
+const BottomLeftCorner = () =>
+
+const MaskText = ({children}: {children?: React.ReactNode}) => {children}
+
+const Corner = ({style}) => {
+ return
+}
+
+const ArcSvg = (props) => {
+ return (
+
)
}
+
+export const getScannerBounds = ({deviceHeight, deviceWidth}: {deviceHeight: number; deviceWidth: number}) => {
+ const top = deviceHeight / 2 - QR_MAX_HEIGHT / 2
+ const bottom = top + QR_MAX_HEIGHT
+ const left = deviceWidth / 2 - QR_MAX_WIDTH / 2
+ const right = left + QR_MAX_WIDTH
+
+ return {
+ width: QR_MAX_WIDTH,
+ height: QR_MAX_HEIGHT,
+ top,
+ bottom,
+ left,
+ right,
+ }
+}
+
+export const getScaledQrBounds = ({
+ qrBounds,
+ qrBoundingBox,
+ deviceHeight,
+ deviceWidth,
+}: {
+ qrBounds: BarCodeBounds
+ qrBoundingBox: BarCodeBounds
+ deviceHeight: number
+ deviceWidth: number
+}) => {
+ // qr bounds values are inversely proportioned + issues in some android devices https://github.com/expo/expo/issues/17795
+ const height = qrBoundingBox !== undefined ? qrBoundingBox.size.width : Number(qrBounds.size.width) * deviceHeight
+ const width = qrBoundingBox !== undefined ? qrBoundingBox.size.height : Number(qrBounds.size.height) * deviceWidth
+ const left = qrBoundingBox !== undefined ? qrBoundingBox.origin.y : Number(qrBounds.origin.y) * deviceWidth
+ const top = qrBoundingBox !== undefined ? qrBoundingBox.origin.x : Number(qrBounds.origin.x) * deviceHeight
+ const bottom = top + height
+ const right = left + width
+
+ return {
+ height,
+ width,
+ right,
+ top,
+ bottom,
+ left,
+ }
+}
+
+export const getIsQrInsideScannerBounds = ({
+ qrBounds,
+ qrBoundingBox,
+ scannerBounds,
+ deviceHeight,
+ deviceWidth,
+}: {
+ qrBounds: BarCodeBounds
+ qrBoundingBox: BarCodeBounds
+ scannerBounds: ReturnType
+ deviceHeight: number
+ deviceWidth: number
+}) => {
+ const scaledQrBounds = getScaledQrBounds({qrBounds, qrBoundingBox, deviceHeight, deviceWidth})
+
+ return (
+ scaledQrBounds.top > scannerBounds.top &&
+ scaledQrBounds.bottom < scannerBounds.bottom &&
+ scaledQrBounds.left > scannerBounds.left &&
+ scaledQrBounds.right < scannerBounds.right
+ )
+}
+
+const QR_MAX_WIDTH = 310 // divisible number. Pixel ratio issue on low end android devices
+const QR_MAX_HEIGHT = 310 // divisible number. Pixel ratio issue on low end android devices
+const opacity = 'rgba(0, 0, 0, .7)'
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ flexDirection: 'column',
+ },
+ maskContainer: {
+ flex: 1,
+ },
+ layerTop: {
+ flex: 1,
+ backgroundColor: opacity,
+ marginBottom: 0,
+ },
+ layerCenter: {
+ flexDirection: 'row',
+ borderWidth: 0,
+ },
+ layerCenterLeft: {
+ flex: 1,
+ backgroundColor: opacity,
+ borderWidth: 0,
+ },
+ cameraOpening: {
+ height: QR_MAX_HEIGHT,
+ width: QR_MAX_WIDTH,
+ },
+ layerCenterRight: {
+ flex: 1,
+ backgroundColor: opacity,
+ },
+ layerBottom: {
+ flex: 1,
+ backgroundColor: opacity,
+ alignItems: 'center',
+ },
+ innerCameraOpeningTop: {
+ flex: 1,
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ position: 'relative',
+ },
+ innerCameraOpeningCenter: {
+ flex: 1,
+ },
+ innerCameraOpeningBottom: {
+ flex: 1,
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ position: 'relative',
+ },
+ topLeftCorner: {
+ top: 0,
+ left: 0,
+ flex: 1,
+ },
+ topRightCorner: {
+ top: 0,
+ right: 0,
+ flex: 1,
+ transform: [{rotate: '90deg'}],
+ },
+ bottomLeftCorner: {
+ bottom: 0,
+ left: 0,
+ transform: [{rotate: '270deg'}],
+ },
+ bottomRightCorner: {
+ bottom: 0,
+ right: 0,
+ transform: [{rotate: '180deg'}],
+ },
+ text: {
+ color: '#fff',
+ fontWeight: 'bold',
+ lineHeight: 24,
+ fontSize: 16,
+ maxWidth: 240,
+ textAlign: 'center',
+ paddingTop: 20,
+ },
+})
diff --git a/apps/wallet-mobile/src/features/Send/common/strings.ts b/apps/wallet-mobile/src/features/Send/common/strings.ts
index 4149b0b2a7..c9fd2134e9 100644
--- a/apps/wallet-mobile/src/features/Send/common/strings.ts
+++ b/apps/wallet-mobile/src/features/Send/common/strings.ts
@@ -57,6 +57,7 @@ export const useStrings = () => {
failedTxTitle: intl.formatMessage(messages.failedTxTitle),
failedTxText: intl.formatMessage(messages.failedTxText),
failedTxButton: intl.formatMessage(messages.failedTxButton),
+ addressReaderQrText: intl.formatMessage(messages.addressReaderQrText),
}
}
@@ -250,4 +251,8 @@ export const messages = defineMessages({
id: 'global.assets.assetLabel',
defaultMessage: '!!!Asset',
},
+ addressReaderQrText: {
+ id: 'components.send.addressreaderqr.text',
+ defaultMessage: '!!!Scan recipients QR code to add a crypto address',
+ },
})
diff --git a/apps/wallet-mobile/src/features/Send/useCases/StartMultiTokenTx/InputReceiver/ReadQRCodeScreen.tsx b/apps/wallet-mobile/src/features/Send/useCases/StartMultiTokenTx/InputReceiver/ReadQRCodeScreen.tsx
index 68acb01548..690f7f9a3c 100644
--- a/apps/wallet-mobile/src/features/Send/useCases/StartMultiTokenTx/InputReceiver/ReadQRCodeScreen.tsx
+++ b/apps/wallet-mobile/src/features/Send/useCases/StartMultiTokenTx/InputReceiver/ReadQRCodeScreen.tsx
@@ -7,11 +7,13 @@ import {useSelectedWallet} from '../../../../../SelectedWallet'
import {Quantity} from '../../../../../yoroi-wallets/types'
import {pastedFormatter} from '../../../../../yoroi-wallets/utils'
import {useSend} from '../../../common/SendContext'
+import {useStrings} from '../../../common/strings'
export const ReadQRCodeScreen = () => {
const navigation = useNavigation()
const wallet = useSelectedWallet()
const {receiverChanged, amountChanged, tokenSelectedChanged} = useSend()
+ const strings = useStrings()
const handleOnRead = ({data: qrData}) => {
const regex = /(cardano):([a-zA-Z1-9]\w+)\??/
@@ -36,7 +38,7 @@ export const ReadQRCodeScreen = () => {
return Promise.resolve(false)
}
- return
+ return
}
const getParams = (params: string) => {
diff --git a/apps/wallet-mobile/src/i18n/locales/en-US.json b/apps/wallet-mobile/src/i18n/locales/en-US.json
index efd6864b5d..c3957021b6 100644
--- a/apps/wallet-mobile/src/i18n/locales/en-US.json
+++ b/apps/wallet-mobile/src/i18n/locales/en-US.json
@@ -131,6 +131,7 @@
"components.send.assetselectorscreen.youHave": "You have",
"components.send.assetselectorscreen.noAssetsAddedYet": "No {fungible} added yet",
"components.send.addressreaderqr.title": "Scan QR code address",
+ "components.send.addressreaderqr.text": "Scan recipients QR code to add a wallet address",
"components.send.amountfield.label": "Amount",
"components.send.editamountscreen.title": "Asset amount",
"components.send.memofield.label": "Memo",
diff --git a/apps/wallet-mobile/src/navigation.tsx b/apps/wallet-mobile/src/navigation.tsx
index 620672c509..3886408aa1 100644
--- a/apps/wallet-mobile/src/navigation.tsx
+++ b/apps/wallet-mobile/src/navigation.tsx
@@ -28,6 +28,12 @@ export const useParams = (guard: Guard): Params => {
type Guard = (params: Params | object) => params is Params
+export const BackButton = (props) => (
+
+
+
+)
+
// OPTIONS
const WIDTH = Dimensions.get('window').width
export const defaultStackNavigationOptionsV2: StackNavigationOptions = {
@@ -54,11 +60,7 @@ export const defaultStackNavigationOptionsV2: StackNavigationOptions = {
headerRightContainerStyle: {
paddingRight: 10,
},
- headerLeft: (props) => (
-
-
-
- ),
+ headerLeft: (props) => ,
}
export const defaultStackNavigationOptions: StackNavigationOptions = {
From 4155c9115f8c90afc6d5e8f9b22d6038a1cd8241 Mon Sep 17 00:00:00 2001
From: jemubm <105349292+jemubm@users.noreply.github.com>
Date: Tue, 18 Jul 2023 10:33:13 +0200
Subject: [PATCH 2/9] fix: Input password dots color on android (#2537)
---
apps/wallet-mobile/android/app/src/dev/res/values/styles.xml | 2 +-
.../wallet-mobile/android/app/src/nightly/res/values/styles.xml | 2 +-
.../android/app/src/production/res/values/styles.xml | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/apps/wallet-mobile/android/app/src/dev/res/values/styles.xml b/apps/wallet-mobile/android/app/src/dev/res/values/styles.xml
index 45104b3922..cf13b945bd 100644
--- a/apps/wallet-mobile/android/app/src/dev/res/values/styles.xml
+++ b/apps/wallet-mobile/android/app/src/dev/res/values/styles.xml
@@ -1,7 +1,7 @@
-