[Injimob 917] Close only camera disabled banner when user clicks on close icon in banner (#1447)

* [INJIMOB-917] add enable permission text with underline in camera disabled banner

When user clicks on this, app will redirect the user to the app settings to enable the permissions

Signed-off-by: PuBHARGAVI <46226958+PuBHARGAVI@users.noreply.github.com>

* [INJIMOB-917] add translations for camera disable banner enable permission text

Signed-off-by: PuBHARGAVI <46226958+PuBHARGAVI@users.noreply.github.com>

* [INJIMOB-695] fix the logic of setting the isActive state of the app using AppState listener and fix the styles of Qr scanner

Signed-off-by: PuBHARGAVI <46226958+PuBHARGAVI@users.noreply.github.com>

* [INJIMOB-917]fix the styles of the camera disabled screen

Signed-off-by: PuBHARGAVI <46226958+PuBHARGAVI@users.noreply.github.com>

* [INJIMOB-917] revert appState listener changes in app.ts and set app active or inactive state everytime the app is launched

Signed-off-by: PuBHARGAVI <46226958+PuBHARGAVI@users.noreply.github.com>

* [INJIMOB-917] remove unused imports

Signed-off-by: PuBHARGAVI <46226958+PuBHARGAVI@users.noreply.github.com>

* [INJIMOB-917] remove unneccessary formatting change

Signed-off-by: PuBHARGAVI <46226958+PuBHARGAVI@users.noreply.github.com>

* [INJIMOB-917] fix the styles of camera scanner and add margin styles to the share screen

Signed-off-by: PuBHARGAVI <46226958+PuBHARGAVI@users.noreply.github.com>

* [INJIMOB-917] show activate option in kebab menu only if the VC has image

Signed-off-by: PuBHARGAVI <46226958+PuBHARGAVI@users.noreply.github.com>

* [INJIMOB-917] remove call to verifyIdentityOverlay component in scan Layout and receive vc screen files as we are not using it and move Invalid Identity component to verifyIdentityOverlay to remove redundancy

Signed-off-by: PuBHARGAVI <46226958+PuBHARGAVI@users.noreply.github.com>

* [INJIMOB-917] change the height of camera scanner to 320 and reduce the margin top and bottom of the whole scanner component to 20

Signed-off-by: PuBHARGAVI <46226958+PuBHARGAVI@users.noreply.github.com>

---------

Signed-off-by: PuBHARGAVI <46226958+PuBHARGAVI@users.noreply.github.com>
This commit is contained in:
PuBHARGAVI
2024-05-21 17:57:26 +05:30
committed by GitHub
parent c36123097b
commit dd97a7dd1c
22 changed files with 389 additions and 270 deletions

View File

@@ -1,8 +1,8 @@
fileignoreconfig:
- filename: package.json
checksum: 2d649ba48d1bd4bc7e6c0ea7046af77f8ecce6c9117045cc7b01a98f0a44bebb
checksum: 5b4fcb5ddc7cc96cc2d1733b544d56ea66e88cdab995a1052fbf9ac0e9c2dc21
- filename: package-lock.json
checksum: a376260a2a61ed12a2d4c8a0a19dee7b4b0b293c48c5946beeae014143be9829
checksum: 2a85120b444e292a418e007b963bee897ef2d45d3c631b99055b2089963507c1
- filename: lib/jsonld-signatures/suites/ed255192018/ed25519.ts
checksum: 493b6e31144116cb612c24d98b97d8adcad5609c0a52c865a6847ced0a0ddc3a
- filename: components/PasscodeVerify.tsx
@@ -38,7 +38,7 @@ fileignoreconfig:
- filename: screens/Home/MyVcs/GetIdInputModal.tsx
checksum: 5c736ed79a372d0ffa7c02eb33d0dc06edbbb08d120978ff287f5f06cd6c7746
- filename: shared/openId4VCI/Utils.ts
checksum: d6baca56726c21357ea64ad95e70d940a68585472a1fc12d546186eb5022ca3a
checksum: 56e6e62b24f0d61dec63a26c141a3e50c53bdbe3e387a0a04e38397bb087ecf9
- filename: shared/cryptoutil/cryptoUtil.ts
checksum: adbc2ff6df1df412e891c988c9ba03fc82f66c2f6c64339f87d513fc835d14cc
- filename: shared/telemetry/TelemetryConstants.js
@@ -102,13 +102,13 @@ fileignoreconfig:
- filename: .github/workflows/ui-automation.yml
checksum: 85993a912fb873a3a2a11adde702918aedff56494e6d45c2d70f272497bf9a27
- filename: injitest/src/test/java/androidTestCases/PinVcTest.java
checksum: d2bb009653a57ad4ae46d2495973aa07cf64e11fd62c1d33d656cc1cdc135c93
checksum: 80db93dd724c281a457c074910f02bb887cb34575792b2dd9f20d77a43a6cfad
- filename: injitest/src/test/java/androidTestCases/NoNetworkAndroidTest.java
checksum: 9d987a7422418f331960f897c1c10ca7e8209680b948eb8d7b48b0fe655e8659
- filename: injitest/src/test/java/androidTestCases/CredentialRegistryTest.java
checksum: 126ad4f513d5e417fdc3ccbace187315b8aae4399806d3259421f8bca7d41254
- filename: injitest/src/test/java/iosTestCases/NoNetworkIosTest.java
checksum: 698b2fed274f17a6daa76b0558bb0a733825fa224144f42aecb4affb8e3897a8
checksum: e4ce65bb37f3c6a2a36b327afdec2e25747c4a7d4a6f5c7f369306848a319dd8
- filename: ios/fastlane/Fastfile
checksum: a4e3772dc67a07ecbcfc58be0d6d4f7fa799cec7ac25bd269ac29459c8669ca4
- filename: injitest/src/test/java/iosTestCases/CredentialRegistryTest.java
@@ -144,7 +144,7 @@ fileignoreconfig:
- filename: shared/VCMetadata.ts
checksum: e93f988415bf91064e2cf5fbc09ff6c7226798baa5da721fa0715d5d0d6afddf
- filename: ios/Podfile.lock
checksum: 406f220cd0fd4526951b3792d1403ec0fb701fbbd22a4d887b62e90b69b1e6d0
checksum: e29b6cd09b56959ecf7747e3a9a67676e521856162af1ad2da91a2c13daad908
- filename: components/BackupAndRestoreBannerNotification.tsx
checksum: e465a9947727687d784d0cb9d8db1e28f765b0659bf4a3aa6d75643aa7b14102
- filename: components/ActivityLogEvent.ts
@@ -168,9 +168,9 @@ fileignoreconfig:
- filename: injitest/src/main/java/inji/api/ConfigManager.java
checksum: 880e066743f5979929cbfa90ef3a28bf4eb7147c9dba425b2abb035025d21aa7
- filename: injitest/src/test/java/androidTestCases/VcDownloadAndVerifyUsingEsignetTest.java
checksum: 0ddae5d539e3ff6ca6a9402d8261bb6de37ae6e6f81e6b523e71496e42e8f1f9
checksum: 6d40247474a1d1dcfb86f5d7e904b14b53ab1f786ea464a59bef39d5775a762b
- filename: injitest/src/test/java/androidTestCases/ChangeLanguageTest.java
checksum: c0234ddd85035f6c2cd62ba96a8a2b85da71f0752e9888130b9675bb6194bebe
checksum: 381f1ac3d03fa524aabd38904efa5031bd5c07717b1d51dcd2465cea58076362
- filename: ios/Inji/Inji.entitlements
checksum: b2d643f91a929933747b539b9d6a87fcac17317716dbb9ccfb399e7c53d8cd52
- filename: injitest/src/test/java/iosTestCases/ChangeLanguageTest.java
@@ -226,7 +226,7 @@ fileignoreconfig:
- filename: machines/backupAndRestore/backupRestore.ts
checksum: 60a55a1d0ef6e79f7b9fa1e61ed31b933364afb429bff03cebbc56339c764499
- filename: machines/backupAndRestore/backupRestore.typegen.ts
checksum: 90f6c78458e3bf24254acbb84864d594126375df0158d08d43dcb4fb541060f5
checksum: 64a8e42712083e0cbf0d6ce6b1139c62b59a14af17e4132d14f903d4d3bbe6b2
- filename: machines/app.typegen.ts
checksum: c310de13b855b22fe68e8fa954dc3a8a4728284c5904da99986a1f4eac8ea0be
- filename: screens/Home/MyVcsTabMachine.typegen.ts
@@ -234,7 +234,7 @@ fileignoreconfig:
- filename: machines/IssuersMachine.typegen.ts
checksum: 959fef1e51f0f3d5b12933f7b362e96401fb776ab12f0d13c6e542918b2ff255
- filename: screens/Home/MyVcsTab.tsx
checksum: 47f9d81e69eb662b76ab12640336b6409f89058c58137a9d837e998de7c0e75f
checksum: 46f69627d250aa51f06f591a8693dd3b365ee78b2573feb4ae03b6779bb6923b
- filename: machines/store.typegen.ts
checksum: 46f3a7c2d15ed03fc70e27ecae5a12c128011c49913b35cdb8edba12b1a999db
- filename: machines/VerifiableCredential/VCMetaMachine/VCMetaMachine.ts
@@ -258,23 +258,23 @@ fileignoreconfig:
- filename: machines/Issuers/IssuersService.ts
checksum: ee7622a03c23705b4c4dea218ccbe6504a51a5a68170a9059a2cde3b4c6a9984
- filename: screens/Home/ViewVcModal.tsx
checksum: 128176a2551fe256378eb88a3d962dd82bbaab44b5f986784de40bf1183f0145
checksum: cfb25d562185488432b76287c4ef93359c1c64d8e29f5755d4c0a726c1485442
- filename: injitest/src/main/resources/TestData.json
checksum: 1b5af14c96b456898259b4cb7a5607b006404cf0360274bdc204d7d065698e3c
- filename: injitest/src/test/java/androidTestCases/ActivateVcTest.java
checksum: c79ebcc903fda178b19b7476e4801c228cdb2cdb6f52bf0b6b5d81ca475bffb9
checksum: a9abd8c0478e9f5d7db8b8289002104107d26c2d08af8959219267f71f4a7a0b
- filename: machines/VerifiableCredential/VCMetaMachine/VCMetaActions.ts
checksum: 6c1f69f90102e57d1c08816b2bedadaa0ee95e0c7f9b1bc124cccc66ffb69fa2
checksum: 5ff9b2a0ad8b7f38b95ad84ec2006b8aecf119c678fadebb18de4ffffd966da8
- filename: injitest/src/test/java/androidTestCases/DeletingVcTest.java
checksum: 6f95a4046eb7959ffccbc530936dd6ab14aad425b934e7bf3b65f0308ae07ff0
checksum: e4c92989937c203ca6371cf6cb3920ceaf61ad53b38d667ff2606044dc5ce469
- filename: injitest/src/test/java/androidTestCases/GenerateUinOrVidTest.java
checksum: 677876a830862d779290d3272c4ad3bfdeb8d4f4c9899a6cdea5ceb7e52e1616
checksum: 3dec3f9d8b28467af89f574e868058446beff12d5dfba13892a2d2f3033b6894
- filename: machines/VerifiableCredential/VCMetaMachine/VCMetaSelectors.ts
checksum: 5f89d24401e6345fd402c7f523f23d567031a571d4b04e1c993c091fa47dc781
checksum: 0aa2f9aff9da14fad92f4e4b414b73d3f492fa7f6dabb3a17f550a20b3e4debf
- filename: injitest/src/test/java/androidTestCases/UnlockWithPasscodeTest.java
checksum: efe21ba6b9e1b760cee02f0d6c5c776722142feeff7417cfdb7536ab80be3476
- filename: injitest/src/test/java/androidTestCases/VerifyHistoryTest.java
checksum: ebd8683aed0b7b9be50ed8f900896557623c366c68b98bde392ea1a343edeafb
checksum: c2787a9adffade8310bd2245d8ea295f01e5528ae8dd156bc68ccda5321f150d
- filename: injitest/src/test/java/androidTestCases/VcDownloadAndVerifyUsingUinTest.java
checksum: ca06dd901386edcd914bd39b301629589d82269b79e80fad5e3562968532b590
- filename: machines/bleShare/scan/scanGuards.ts
@@ -286,19 +286,35 @@ fileignoreconfig:
- filename: machines/bleShare/scan/scanActions.ts
checksum: 1be68caa29937d5f724fc45f8164ee607e556aae008c00ac89b83968030ed7ed
- filename: injitest/src/test/java/iosTestCases/ActivateVcTest.java
checksum: 2adfd7c38a3302ab8ae091417eb9af15235406c7fb2c6399f6421bcf89612a5a
checksum: 280fcbfa6e7b26baa41aa9e60e8be857a16fd409f2dcc5b31d53ced7d1b26dec
- filename: injitest/src/test/java/iosTestCases/GenerateUinOrVidTest.java
checksum: a56bcafd022bc740bd17e657c578b7559fda30c84d80eb69060624009e5b021b
checksum: c2a97d691bad5e07ff04b2da0487ffeb86884e14d1489657276a3e003e954735
- filename: injitest/src/test/java/iosTestCases/VerifyHistoryTest.java
checksum: f5af73c269d0de91814dc77e270b08fadc44d8daf41f66d4b749bc0fc8793993
checksum: ff7f467874f8fa6284150359f81cf1f9f00bf979f58aeda608460fc026d6c79b
- filename: machines/store.ts
checksum: fa2330002fc3f638a09a816a37a8ef26268ae6ab65c23aacee846244ebb1cb4e
- filename: components/BannerNotificationContainer.tsx
checksum: e2c31bb25ebe1234369c7dc577fa3657b03c3a0bf561cd6fd5eb9e0919160cb1
checksum: 9e5b4a61b87e86666f0bee550d410df2b8576dfe5ec374de0ab139a468a234f7
- filename: injitest/src/test/java/iosTestCases/PinVcTest.java
checksum: 435d345931e2d14dad99faafdf0d79fad025c049252ea94bca57dd6608d69c4c
checksum: 55098750062a199fdf1e33078acc50080dea12a885f934a7aa88411c06899cb7
- filename: injitest/src/test/java/androidTestCases/VcBackupAndRestoreTest.java
checksum: 8713672812eb3f737243c0d431574a84766559a336754bc53c9c5bfbd006707d
checksum: 3700867ed1c7accda814ca1870c7d1ad7e27a9ba0571607eaabb5d1fa4fbdab3
- filename: machines/VerifiableCredential/VCItemMachine/VCItemMachine.typegen.ts
checksum: 8ac74d2e5c6de179e460b86899eb048ad4c5bd67abc3d28c015e92335b8afe24
checksum: 6164156146b0474943237d1e1a69ec05ba66d89ced06508353b6cffe582237b5
- filename: machines/backupAndRestore/backupWithEncryption.typegen.ts
checksum: 19ccac58df42ce0b6e36c66592e53441d709713fb1bff64454e0039dd3b0ac97
- filename: injitest/src/main/java/inji/utils/TestDataReader.java
checksum: 02d9ff0873d2f9685c4db6ad41d56eb91a59966feda20d7072ec32da6c2e22fe
- filename: injitest/src/test/java/iosTestCases/UnlockWithPasscodeTest.java
checksum: a44dab1127143fa303824068f81a8ee3e7697ace4c38460d5400a0a56fe9ba7d
- filename: injitest/src/test/java/iosTestCases/VcDownloadAndVerifyUsingEsignetTest.java
checksum: 23bcfd393abb1802d3ecf913dd535e2487a23db7afded1fa0a1fe284513c0fa8
- filename: injitest/src/test/java/iosTestCases/VcDownloadAndVerifyUsingUinTest.java
checksum: fdf6e7b3fc04af16c0c47d2d1d7e051d7cb03e0891d4697e40997932362d06e0
- filename: machines/Issuers/IssuersMachine.typegen.ts
checksum: 08fd5e4eff836c219a0f16f6d4178a3511ec2581507076d3f9d32dcadbc01351
- filename: injitest/src/test/java/iosTestCases/DeletingVcTest.java
checksum: 0816d4b9440da5384fd867d13555986d223124b9609280350226510a06ae96fa
- filename: machines/VerifiableCredential/VCItemMachine/VCItemMachine.ts
checksum: fdc0c23a7107eb713d20f60fda675f9e9fe8ef29c981d798d90e581dfee340c8
version: ""

12
App.tsx
View File

@@ -6,6 +6,7 @@ import {GlobalContext} from './shared/GlobalContext';
import {useSelector} from '@xstate/react';
import {useTranslation} from 'react-i18next';
import {
APP_EVENTS,
selectIsDecryptError,
selectIsKeyInvalidateError,
selectIsReadError,
@@ -13,7 +14,7 @@ import {
} from './machines/app';
import {DualMessageOverlay} from './components/DualMessageOverlay';
import {useApp} from './screens/AppController';
import {Alert} from 'react-native';
import {Alert, AppState} from 'react-native';
import {
configureTelemetry,
getErrorEventData,
@@ -26,6 +27,7 @@ import {isHardwareKeystoreExists} from './shared/cryptoutil/cryptoUtil';
import i18n from './i18n';
import './shared/flipperConfig';
import * as SplashScreen from 'expo-splash-screen';
import {isAndroid} from './shared/constants';
SplashScreen.preventAutoHideAsync();
@@ -58,6 +60,14 @@ const AppLayoutWrapper: React.FC = () => {
hideAppLoading();
}, []);
useEffect(() => {
if (AppState.currentState === 'active') {
appService.send(APP_EVENTS.ACTIVE());
} else {
appService.send(APP_EVENTS.INACTIVE());
}
}, []);
if (isDecryptError) {
DecryptErrorAlert(controller, t);
}

View File

@@ -1,6 +1,6 @@
import React, {useCallback, useContext, useEffect, useRef} from 'react';
import {Camera} from 'expo-camera';
import {TouchableOpacity, View, Image} from 'react-native';
import {TouchableOpacity, View} from 'react-native';
import {Button, Centered, Column, Row, Text} from './ui';
import {useInterpret, useSelector} from '@xstate/react';
import {useTranslation} from 'react-i18next';
@@ -21,6 +21,7 @@ import {selectIsActive} from '../machines/app';
import {RotatingIcon} from './RotatingIcon';
import {Theme} from './ui/styleUtils';
import {SvgImage} from './ui/svg';
import testIDProps from '../shared/commonUtil';
export const FaceScanner: React.FC<FaceScannerProps> = props => {
const {t} = useTranslation('FaceScanner');
@@ -81,14 +82,16 @@ export const FaceScanner: React.FC<FaceScannerProps> = props => {
return (
<Column fill align="space-between">
<View style={Theme.Styles.scannerContainer}>
<View style={Theme.CameraEnabledStyles.scannerContainer}>
<Camera
style={Theme.Styles.scanner}
{...testIDProps('camera')}
style={Theme.CameraEnabledStyles.scanner}
type={whichCamera}
ref={setCameraRef}
/>
</View>
<Text
testID="imageCaptureGuide"
align="center"
weight="semibold"
style={Theme.TextStyles.base}
@@ -105,7 +108,9 @@ export const FaceScanner: React.FC<FaceScannerProps> = props => {
onPress={() => service.send(FaceScannerEvents.CAPTURE())}>
{SvgImage.CameraCaptureIcon()}
</TouchableOpacity>
<Text size="small" weight="semibold" margin="8">
<Text
testID="captureText"
style={Theme.CameraEnabledStyles.iconText}>
{t('capture')}
</Text>
</Centered>
@@ -115,7 +120,9 @@ export const FaceScanner: React.FC<FaceScannerProps> = props => {
onPress={() => service.send(FaceScannerEvents.FLIP_CAMERA())}>
{SvgImage.FlipCameraIcon()}
</TouchableOpacity>
<Text size="smaller" weight="semibold" margin="8">
<Text
testID="flipCameraText"
style={Theme.CameraEnabledStyles.iconText}>
{t('flipCamera')}
</Text>
</Centered>

View File

@@ -2,7 +2,13 @@ import React, {useContext, useEffect, useState} from 'react';
import Icon from 'react-native-vector-icons/MaterialIcons';
import {Camera} from 'expo-camera';
import {BarCodeEvent, BarCodeScanner} from 'expo-barcode-scanner';
import {Linking, TouchableOpacity, View, Image, Pressable} from 'react-native';
import {
Linking,
TouchableOpacity,
View,
Pressable,
Platform,
} from 'react-native';
import {Theme} from './ui/styleUtils';
import {Column, Button, Text, Centered, Row} from './ui';
import {GlobalContext} from '../shared/GlobalContext';
@@ -16,34 +22,48 @@ import {SvgImage} from './ui/svg';
export const QrScanner: React.FC<QrScannerProps> = props => {
const {t} = useTranslation('QrScanner');
const {appService} = useContext(GlobalContext);
const [hasPermission, setHasPermission] = useState(null);
const [scanned, setScanned] = useState(false);
const [cameraType, setCameraType] = useState(Camera.Constants.Type.back);
const controller = useScanLayout();
const [hasCameraPermission, setHasCameraPermission] = useState<
boolean | null
>(null);
const [
showCameraPermissionDeniedBanner,
setShowCameraPermissionDeniedBanner,
] = useState(false);
const isActive = useSelector(appService, selectIsActive);
const openSettings = () => {
Linking.openSettings();
if (Platform.OS === 'android') {
Linking.openSettings();
} else {
Linking.openURL('App-Prefs:Privacy');
}
};
useEffect(() => {
(async () => {
const response = await Camera.requestCameraPermissionsAsync();
setHasPermission(response.granted);
})();
}, []);
useEffect(() => {
if (isActive && hasPermission === false) {
if (isActive && !Boolean(hasCameraPermission)) {
(async () => {
const response = await Camera.requestCameraPermissionsAsync();
setHasPermission(response.granted);
setShowCameraPermissionDeniedBanner(false);
const cameraPermissionResult = await Camera.getCameraPermissionsAsync();
if (cameraPermissionResult.status === 'undetermined') {
const response = await Camera.requestCameraPermissionsAsync();
setHasCameraPermission(response.granted);
if (response.granted === false) {
setShowCameraPermissionDeniedBanner(true);
}
} else if (cameraPermissionResult.status === 'granted') {
setHasCameraPermission(true);
} else if (cameraPermissionResult.status === 'denied') {
setHasCameraPermission(false);
setShowCameraPermissionDeniedBanner(true);
}
})();
}
}, [isActive]);
if (hasPermission === null) {
if (hasCameraPermission === null) {
return <View />;
}
@@ -51,82 +71,99 @@ export const QrScanner: React.FC<QrScannerProps> = props => {
return (
<View
{...testIDProps('cameraDisabledPopup')}
style={Theme.Styles.cameraDisabledPopupContainer}>
<Row style={Theme.Styles.cameraDisabledPopUp}>
<Column style={{flex: 1}}>
<Text
testID="cameraAccessDisabled"
color={Theme.Colors.whiteText}
weight="semibold"
margin="0 0 5 0">
{t('cameraAccessDisabled')}
</Text>
<Text
testID="cameraPermissionGuide"
color={Theme.Colors.whiteText}
size="regular"
style={{opacity: 0.8}}>
{t('cameraPermissionGuideLabel')}
</Text>
</Column>
<Pressable>
<Icon
testID="close"
name="close"
onPress={controller.DISMISS}
color={Theme.Colors.whiteText}
size={18}
/>
</Pressable>
</Row>
style={Theme.CameraDisabledStyles.container}>
<Column style={Theme.CameraDisabledStyles.banner}>
<Row style={Theme.CameraDisabledStyles.bannerTextContainer}>
<Column>
<Text
testID="cameraAccessDisabled"
color={Theme.Colors.whiteText}
margin="0 0 5 0"
style={Theme.CameraDisabledStyles.bannerTitle}>
{t('cameraAccessDisabled')}
</Text>
<Text
testID="cameraPermissionGuide"
color={Theme.Colors.whiteText}
style={Theme.CameraDisabledStyles.bannerGuide}>
{t('cameraPermissionGuideLabel')}
</Text>
</Column>
<Pressable>
<Icon
testID="close"
name="close"
onPress={() => setShowCameraPermissionDeniedBanner(false)}
color={Theme.Colors.whiteText}
size={18}
/>
</Pressable>
</Row>
<Row
style={Theme.CameraDisabledStyles.bannerEnablePermissionContainer}>
<Pressable
onPress={openSettings}
style={Theme.CameraDisabledStyles.bannerEnablePermission}>
<Text
testID="EnablePermissionText"
color={Theme.Colors.whiteText}>
{t('EnablePermission')}
</Text>
</Pressable>
</Row>
</Column>
</View>
);
};
return (
<Column fill align="space-between" margin="0 0 60 0">
<View style={Theme.Styles.scannerContainer}>
{hasPermission ? (
<Camera
{...testIDProps('camera')}
style={Theme.Styles.scanner}
barCodeScannerSettings={{
barcodeTypes: [BarCodeScanner.Constants.BarCodeType.qr],
}}
onBarCodeScanned={scanned ? undefined : onBarcodeScanned}
type={cameraType}
/>
) : (
<View style={Theme.Styles.disabledScannerContainer} />
)}
</View>
{props.title && (
<Text
testID="holdPhoneSteadyMessage"
align="center"
weight="semibold"
style={Theme.TextStyles.base}
margin="0 57">
{props.title}
</Text>
<>
{hasCameraPermission ? (
<Column style={Theme.CameraEnabledStyles.container}>
<View style={Theme.CameraEnabledStyles.scannerContainer}>
<Camera
{...testIDProps('camera')}
style={Theme.CameraEnabledStyles.scanner}
barCodeScannerSettings={{
barcodeTypes: [BarCodeScanner.Constants.BarCodeType.qr],
}}
onBarCodeScanned={scanned ? undefined : onBarcodeScanned}
type={cameraType}
/>
</View>
<Column fill align="space-between" style={{marginTop: 24}}>
{props.title && (
<Text
testID="holdPhoneSteadyMessage"
align="center"
style={Theme.CameraEnabledStyles.holdPhoneSteadyText}
margin="0 57">
{props.title}
</Text>
)}
<Column crossAlign="center">
<TouchableOpacity
onPress={() => {
setCameraType(
cameraType === Camera.Constants.Type.back
? Camera.Constants.Type.front
: Camera.Constants.Type.back,
);
}}>
{SvgImage.FlipCameraIcon()}
</TouchableOpacity>
<Text
testID="flipCameraText"
style={Theme.CameraEnabledStyles.iconText}>
{t('flipCamera')}
</Text>
</Column>
</Column>
</Column>
) : (
<View style={Theme.CameraDisabledStyles.scannerContainer} />
)}
<Column crossAlign="center">
<TouchableOpacity
disabled={hasPermission === false}
onPress={() => {
setCameraType(
cameraType === Camera.Constants.Type.back
? Camera.Constants.Type.front
: Camera.Constants.Type.back,
);
}}>
{SvgImage.FlipCameraIcon()}
</TouchableOpacity>
<Text testID="flipCameraText" size="small" weight="semibold" margin="8">
{t('flipCamera')}
</Text>
</Column>
{hasPermission == false && <CameraDisabledPopUp />}
</Column>
{showCameraPermissionDeniedBanner && <CameraDisabledPopUp />}
</>
);
function onBarcodeScanned(event: BarCodeEvent) {

View File

@@ -69,9 +69,8 @@ export const getKebabMenuOptions = props => {
if (props.vcMetadata.isVerified) {
vcActionsList.splice(1, 0, share);
if (props.vcHasImage) {
vcActionsList.splice(2, 0, shareWithSelfieOption);
vcActionsList.splice(2, 0, shareWithSelfieOption, VCActivationOption);
}
vcActionsList.splice(3, 0, VCActivationOption);
}
return vcActionsList;

View File

@@ -6,7 +6,7 @@ import {Theme} from './styleUtils';
import {LoaderAnimation} from './LoaderAnimation';
import {Modal} from './Modal';
import {BannerNotification} from '../../components/BannerNotification';
import { BannerStatusType } from '../../components/BannerNotification';
import {BannerStatusType} from '../../components/BannerNotification';
export const Loader: React.FC<LoaderProps> = props => {
const {t} = useTranslation('ScanScreen');
@@ -112,7 +112,9 @@ export const Loader: React.FC<LoaderProps> = props => {
<View style={Theme.Styles.hrLineFill}></View>
{props.showBanner && (
<BannerNotification
type={props.bannerType ? props.bannerType : BannerStatusType.SUCCESS}
type={
props.bannerType ? props.bannerType : BannerStatusType.SUCCESS
}
message={props.bannerMessage as string}
onClosePress={props.onBannerClose as () => void}
testId={props.bannerTestID as string}

View File

@@ -322,7 +322,7 @@ export class SvgImage {
}
static FlipCameraIcon() {
const {width, height} = Theme.Styles.cameraFlipIcon;
const {width, height} = Theme.CameraEnabledStyles.cameraFlipIcon;
return (
<FlipCameraIcon
{...testIDProps('flipCameraIcon')}
@@ -337,6 +337,7 @@ export class SvgImage {
static CameraCaptureIcon() {
return (
<CameraCaptureIcon
{...testIDProps('CameraCaptureIcon')}
color1={Theme.Colors.linearGradientStart}
color2={Theme.Colors.linearGradientEnd}
/>

View File

@@ -454,10 +454,6 @@ export const DefaultTheme = {
borderRadius: 10,
backgroundColor: Colors.LightOrange,
},
cameraFlipIcon: {
height: 42,
width: 42,
},
imageCaptureButton: {
marginLeft: 130,
marginRight: 50,
@@ -531,41 +527,6 @@ export const DefaultTheme = {
flexDirection: 'row',
alignItems: 'flex-end',
},
scannerContainer: {
borderRadius: 24,
alignSelf: 'center',
height: 350,
width: 320,
overflow: 'hidden',
},
scanner: {
height: 400,
width: '100%',
margin: 'auto',
},
disabledScannerContainer: {
borderRadius: 24,
height: 350,
width: '100%',
margin: 'auto',
backgroundColor: Colors.White,
borderWidth: 1,
borderColor: Colors.Gray89,
},
cameraDisabledPopupContainer: {
position: 'absolute',
top: 0,
left: 0,
right: 0,
},
cameraDisabledPopUp: {
justifyContent: 'space-between',
backgroundColor: Colors.Red,
position: 'relative',
padding: 20,
paddingHorizontal: 15,
marginTop: -24,
},
photoConsentLabel: {
backgroundColor: Colors.White,
padding: 0,
@@ -1524,6 +1485,73 @@ export const DefaultTheme = {
fontWeight: 'bold',
},
}),
CameraDisabledStyles: StyleSheet.create({
container: {
position: 'absolute',
width: Dimensions.get('screen').width,
},
banner: {
justifyContent: 'space-between',
backgroundColor: Colors.Red,
padding: 20,
paddingHorizontal: 15,
marginTop: -24,
},
bannerTextContainer: {
justifyContent: 'space-between',
},
bannerTitle: {
fontFamily: 'Inter_600SemiBold',
},
bannerGuide: {
opacity: 0.8,
fontFamily: 'Inter_400Regular',
},
bannerEnablePermissionContainer: {
marginTop: 15,
},
bannerEnablePermission: {
borderBottomWidth: 1.5,
borderBottomColor: Colors.White,
fontFamily: 'Inter_600SemiBold',
},
scannerContainer: {
borderRadius: 24,
height: 320,
width: 300,
marginTop: 40,
backgroundColor: Colors.White,
borderWidth: 1,
borderColor: Colors.Gray89,
},
}),
CameraEnabledStyles: StyleSheet.create({
container: {marginTop: 20, marginBottom: 20},
scannerContainer: {
borderRadius: 24,
alignSelf: 'center',
height: 320,
width: 300,
overflow: 'hidden',
},
scanner: {
height: '100%',
width: '100%',
margin: 'auto',
},
holdPhoneSteadyText: {
color: Colors.Black,
fontFamily: 'Inter_600SemiBold',
fontSize: 15,
},
cameraFlipIcon: {
height: 50,
width: 50,
},
iconText: {fontFamily: 'Inter_600SemiBold', fontSize: 12, marginTop: 6},
}),
BottomTabBarStyle: StyleSheet.create({
headerRightContainerStyle: {paddingEnd: 13},
headerLeftContainerStyle: {paddingEnd: 13},

View File

@@ -459,10 +459,6 @@ export const PurpleTheme = {
borderRadius: 10,
backgroundColor: Colors.LightPurple,
},
cameraFlipIcon: {
width: 42,
height: 42,
},
imageCaptureButton: {
marginLeft: 130,
marginRight: 50,
@@ -536,41 +532,6 @@ export const PurpleTheme = {
flexDirection: 'row',
alignItems: 'flex-end',
},
scannerContainer: {
borderRadius: 24,
alignSelf: 'center',
height: 350,
width: 320,
overflow: 'hidden',
},
scanner: {
height: 400,
width: '100%',
margin: 'auto',
},
disabledScannerContainer: {
borderRadius: 24,
height: 350,
width: '100%',
margin: 'auto',
backgroundColor: Colors.White,
borderWidth: 1,
borderColor: Colors.Gray89,
},
cameraDisabledPopupContainer: {
position: 'absolute',
top: 0,
left: 0,
right: 0,
},
cameraDisabledPopUp: {
justifyContent: 'space-between',
backgroundColor: Colors.Red,
position: 'relative',
padding: 20,
paddingHorizontal: 15,
marginTop: -24,
},
photoConsentLabel: {
backgroundColor: Colors.White,
padding: 0,
@@ -1525,6 +1486,70 @@ export const PurpleTheme = {
fontWeight: 'bold',
},
}),
CameraDisabledStyles: StyleSheet.create({
container: {
position: 'absolute',
width: Dimensions.get('screen').width,
},
banner: {
justifyContent: 'space-between',
backgroundColor: Colors.Red,
padding: 20,
paddingHorizontal: 15,
marginTop: -24,
},
bannerTextContainer: {
justifyContent: 'space-between',
},
bannerTitle: {
fontFamily: 'Inter_600SemiBold',
},
bannerGuide: {
opacity: 0.8,
fontFamily: 'Inter_400Regular',
},
bannerEnablePermissionContainer: {
marginTop: 15,
},
bannerEnablePermission: {
borderBottomWidth: 1.5,
borderBottomColor: Colors.White,
fontFamily: 'Inter_600SemiBold',
},
scannerContainer: {
borderRadius: 24,
height: 320,
width: 300,
marginTop: 40,
backgroundColor: Colors.White,
borderWidth: 1,
borderColor: Colors.Gray89,
},
}),
CameraEnabledStyles: StyleSheet.create({
container: {marginTop: 20, marginBottom: 20},
scannerContainer: {
borderRadius: 24,
alignSelf: 'center',
height: 320,
width: 300,
overflow: 'hidden',
},
scanner: {
height: '100%',
width: '100%',
margin: 'auto',
},
holdPhoneSteadyText: {
color: Colors.Black,
fontFamily: 'Inter_600SemiBold',
},
cameraFlipIcon: {
height: 50,
width: 50,
},
iconText: {fontFamily: 'Inter_600SemiBold', fontSize: 12, marginTop: 6},
}),
BottomTabBarStyle: StyleSheet.create({
headerRightContainerStyle: {paddingEnd: 13},
headerLeftContainerStyle: {paddingEnd: 13},

View File

@@ -484,6 +484,9 @@
}
}
},
"Permissions": {
"enablePermission": "تمكين الإذن"
},
"RequestScreen": {
"receiveCard": "البطاقة المستلمة",
"bluetoothDenied": "يرجى تمكين بلوتوث لتتمكن من طلب البطاقة",

View File

@@ -488,6 +488,9 @@
}
}
},
"Permissions": {
"enablePermission": "Enable Permission"
},
"RequestScreen": {
"receiveCard": "Receive Card",
"bluetoothDenied": "Please enable Bluetooth to be able to request card",

View File

@@ -483,6 +483,9 @@
}
}
},
"Permissions": {
"enablePermission": "Paganahin ang Pahintulot"
},
"RequestScreen": {
"receiveCard": "Tumanggap ng Card",
"bluetoothDenied": "Mangyaring paganahin ang Bluetooth upang makahiling ng card",

View File

@@ -486,6 +486,9 @@
}
}
},
"Permissions": {
"enablePermission": "अनुमति सक्षम करें"
},
"RequestScreen": {
"receiveCard": "कार्ड प्राप्त करें",
"bluetoothDenied": "कृपया ब्लूटूथ को सक्षम करें ताकि वह कार्ड का अनुरोध कर सके",

View File

@@ -484,6 +484,9 @@
}
}
},
"Permissions": {
"enablePermission": "ಅನುಮತಿಯನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ"
},
"RequestScreen": {
"receiveCard": "ಕಾರ್ಡ್ ಸ್ವೀಕರಿಸಿ",
"bluetoothDenied": "ವಿನಂತಿಸಲು ಬ್ಲೂಟೂತ್ ಅನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿಕಾರ್ಡ್",

View File

@@ -484,6 +484,9 @@
}
}
},
"Permissions": {
"enablePermission": "அனுமதியை இயக்கு"
},
"RequestScreen": {
"receiveCard": "பெற்ற அட்டை",
"bluetoothDenied": "அட்டைஐக் கோர புளூடூத்தை இயக்கவும்",

View File

@@ -369,19 +369,30 @@ export const appMachine = model.createMachine(
const blurHandler = () => callback({type: 'INACTIVE'});
const focusHandler = () => callback({type: 'ACTIVE'});
let changeEventSubscription = AppState.addEventListener(
'change',
changeHandler,
);
AppState.addEventListener('change', changeHandler);
let blurEventSubscription, focusEventSubscription;
if (isAndroid()) {
AppState.addEventListener('blur', blurHandler);
AppState.addEventListener('focus', focusHandler);
blurEventSubscription = AppState.addEventListener(
'blur',
blurHandler,
);
focusEventSubscription = AppState.addEventListener(
'focus',
focusHandler,
);
}
return () => {
AppState.removeEventListener('change', changeHandler);
changeEventSubscription.remove();
if (isAndroid()) {
AppState.removeEventListener('blur', blurHandler);
AppState.removeEventListener('focus', focusHandler);
blurEventSubscription.remove();
focusEventSubscription.remove();
}
};
},

View File

@@ -57,7 +57,7 @@ export const QrLogin: React.FC<QrLoginProps> = props => {
onFaceValid={controller.FACE_VALID}
onFaceInvalid={controller.FACE_INVALID}
isInvalidIdentity={controller.isInvalidIdentity}
onDismiss={controller.DISMISS}
onNavigateHome={controller.GO_TO_HOME}
onRetryVerification={controller.RETRY_VERIFICATION}
/>
@@ -80,25 +80,6 @@ export const QrLogin: React.FC<QrLoginProps> = props => {
onPress={controller.CONFIRM}
service={props.service}
/>
<Error
isModal
alignActionsOnEnd
showClose={false}
isVisible={controller.isInvalidIdentity}
title={t('ScanScreen:postFaceCapture.captureFailureTitle')}
message={t('ScanScreen:postFaceCapture.captureFailureMessage')}
image={SvgImage.PermissionDenied()}
primaryButtonTestID={'retry'}
primaryButtonText={t('ScanScreen:status.retry')}
primaryButtonEvent={controller.RETRY_VERIFICATION}
textButtonTestID={'home'}
textButtonText={t('ScanScreen:status.accepted.home')}
textButtonEvent={controller.GO_TO_HOME}
customImageStyles={{paddingBottom: 0, marginBottom: -6}}
customStyles={{marginTop: '20%'}}
testID={'shareWithSelfieError'}
/>
</Column>
</View>
);

View File

@@ -68,18 +68,6 @@ export const ReceiveVcScreen: React.FC = () => {
</Column>
)}
<VerifyIdentityOverlay
credential={controller.selectCredential}
verifiableCredentialData={verifiableCredentialData}
isVerifyingIdentity={controller.isVerifyingIdentity}
onCancel={controller.CANCEL}
onFaceValid={controller.FACE_VALID}
onFaceInvalid={controller.FACE_INVALID}
isInvalidIdentity={controller.isInvalidIdentity}
onDismiss={controller.DISMISS}
onRetryVerification={controller.RETRY_VERIFICATION}
/>
<MessageOverlay
isVisible={savingOverlayVisible}
message={t('saving')}

View File

@@ -14,7 +14,7 @@ import {VerifyIdentityOverlay} from '../VerifyIdentityOverlay';
import {SvgImage} from '../../components/ui/svg';
import {View, I18nManager} from 'react-native';
import {Text} from './../../components/ui';
import { BannerStatusType } from '../../components/BannerNotification';
import {BannerStatusType} from '../../components/BannerNotification';
const ScanStack = createNativeStackNavigator();
@@ -50,18 +50,6 @@ export const ScanLayout: React.FC = () => {
return (
<React.Fragment>
<VerifyIdentityOverlay
credential={controller.credential}
verifiableCredentialData={controller.verifiableCredentialData}
isVerifyingIdentity={controller.isVerifyingIdentity}
onCancel={controller.CANCEL}
onFaceValid={controller.FACE_VALID}
onFaceInvalid={controller.FACE_INVALID}
isInvalidIdentity={controller.isInvalidIdentity}
onDismiss={controller.DISMISS}
onRetryVerification={controller.RETRY_VERIFICATION}
/>
<ScanStack.Navigator initialRouteName="ScanScreen">
{controller.isReviewing &&
controller.flowType === VCShareFlowType.SIMPLE_SHARE && (

View File

@@ -144,7 +144,7 @@ export const ScanScreen: React.FC = () => {
function qrScannerComponent() {
return (
<Column crossAlign="center" margin="0 0 0 -6">
<Column crossAlign="center">
<QrScanner
onQrFound={scanScreenController.SCAN}
title={t('scanningGuide')}

View File

@@ -137,6 +137,9 @@ export const SendVcScreen: React.FC = () => {
onCancel={controller.CANCEL}
onFaceValid={controller.FACE_VALID}
onFaceInvalid={controller.FACE_INVALID}
isInvalidIdentity={controller.isInvalidIdentity}
onNavigateHome={controller.GO_TO_HOME}
onRetryVerification={controller.RETRY_VERIFICATION}
/>
<FaceVerificationAlertOverlay
@@ -144,25 +147,6 @@ export const SendVcScreen: React.FC = () => {
onConfirm={controller.FACE_VERIFICATION_CONSENT}
close={controller.DISMISS}
/>
<Error
isModal
alignActionsOnEnd
showClose={false}
isVisible={controller.isInvalidIdentity}
title={t('ScanScreen:postFaceCapture.captureFailureTitle')}
message={t('ScanScreen:postFaceCapture.captureFailureMessage')}
image={SvgImage.PermissionDenied()}
primaryButtonTestID={'retry'}
primaryButtonText={t('ScanScreen:status.retry')}
primaryButtonEvent={controller.RETRY_VERIFICATION}
textButtonTestID={'home'}
textButtonText={t('ScanScreen:status.accepted.home')}
textButtonEvent={controller.GO_TO_HOME}
customImageStyles={{paddingBottom: 0, marginBottom: -6}}
customStyles={{marginTop: '20%'}}
testID={'shareWithSelfieError'}
/>
</React.Fragment>
);
};

View File

@@ -5,6 +5,8 @@ import {Theme} from '../components/ui/styleUtils';
import {VerifiableCredential} from '../machines/VerifiableCredential/VCMetaMachine/vc';
import {Modal} from '../components/ui/Modal';
import {useTranslation} from 'react-i18next';
import {Error} from '../components/ui/Error';
import {SvgImage} from '../components/ui/svg';
export const VerifyIdentityOverlay: React.FC<
VerifyIdentityOverlayProps
@@ -33,6 +35,25 @@ export const VerifyIdentityOverlay: React.FC<
)}
</Column>
</Modal>
<Error
isModal
alignActionsOnEnd
showClose={false}
isVisible={props.isInvalidIdentity}
title={t('ScanScreen:postFaceCapture.captureFailureTitle')}
message={t('ScanScreen:postFaceCapture.captureFailureMessage')}
image={SvgImage.PermissionDenied()}
primaryButtonTestID={'retry'}
primaryButtonText={t('ScanScreen:status.retry')}
primaryButtonEvent={props.onRetryVerification}
textButtonTestID={'home'}
textButtonText={t('ScanScreen:status.accepted.home')}
textButtonEvent={props.onNavigateHome}
customImageStyles={{paddingBottom: 0, marginBottom: -6}}
customStyles={{marginTop: '20%'}}
testID={'shareWithSelfieError'}
/>
</>
);
};
@@ -44,4 +65,7 @@ export interface VerifyIdentityOverlayProps {
onCancel: () => void;
onFaceValid: () => void;
onFaceInvalid: () => void;
isInvalidIdentity: boolean;
onNavigateHome: () => void;
onRetryVerification: () => void;
}