Language selection at the initial launch

This commit is contained in:
srikanth716
2023-02-09 01:42:53 +05:30
parent a94db0b69e
commit 6356273153
14 changed files with 775 additions and 43 deletions

View File

@@ -8,7 +8,7 @@ import { Text } from './Text';
import { Theme, Spacing } from './styleUtils';
export const Button: React.FC<ButtonProps> = (props) => {
const type = props.type || 'solid';
const type = props.type || 'solid' || 'radius' || 'gradient';
const buttonStyle: StyleProp<ViewStyle> = [
props.fill ? Theme.ButtonStyles.fill : null,
Theme.ButtonStyles[type],
@@ -28,7 +28,7 @@ export const Button: React.FC<ButtonProps> = (props) => {
}
};
return (
return !(type === 'gradient') ? (
<RNEButton
buttonStyle={buttonStyle}
containerStyle={[
@@ -54,6 +54,27 @@ export const Button: React.FC<ButtonProps> = (props) => {
onPress={handleOnPress}
loading={props.loading}
/>
) : (
<RNEButton
ViewComponent={require('react-native-linear-gradient').default}
linearGradientProps={{ colors: props.colors }}
buttonStyle={buttonStyle}
containerStyle={[
props.fill ? Theme.ButtonStyles.fill : null,
containerStyle,
]}
type={props.type}
raised={props.raised}
title={
<Text weight="semibold" align="center" color={Theme.Colors.whiteText}>
{props.title}
</Text>
}
style={[buttonStyle]}
icon={props.icon}
onPress={handleOnPress}
loading={props.loading}
/>
);
};
@@ -62,10 +83,13 @@ interface ButtonProps {
disabled?: boolean;
margin?: Spacing;
type?: RNEButtonProps['type'];
linearGradient?: boolean;
isVcThere?: boolean;
onPress?: RNEButtonProps['onPress'];
fill?: boolean;
raised?: boolean;
loading?: boolean;
icon?: RNEButtonProps['icon'];
styles?: StyleProp<ViewStyle>;
colors?: (string | number)[];
}

View File

@@ -0,0 +1,69 @@
import React, { useEffect, useState } from 'react';
import { Dimensions } from 'react-native';
import { Icon, ListItem } from 'react-native-elements';
import { Column } from './Layout';
import { Text } from './Text';
import { Theme } from './styleUtils';
interface Picker extends React.VFC<PickerProps<unknown>> {
<T>(props: PickerProps<T>): ReturnType<React.FC>;
}
export const SetupPicker: Picker = (props: PickerProps<unknown>) => {
const [isContentVisible, setIsContentVisible] = useState(false);
const [selectedIndex, setSelectedIndex] = useState(-1);
useEffect(() => {
setSelectedIndex(
props.items.findIndex(({ value }) => value === props.selectedValue)
);
}, [props.selectedValue]);
const toggleContent = () => setIsContentVisible(!isContentVisible);
const selectItem = (index: number) => {
setSelectedIndex(index);
props.onValueChange(props.items[index].value, index);
toggleContent();
};
return (
<Column
width={Dimensions.get('window').width * 0.8}
backgroundColor={Theme.Colors.whiteBackgroundColor}>
{props.items.map((item, index) => (
<ListItem
bottomDivider
topDivider={index !== 0}
onPress={() => selectItem(index)}
key={index}>
<ListItem.Content>
<ListItem.Title>
<Text
color={selectedIndex === index ? Theme.Colors.Icon : null}
weight={selectedIndex === index ? 'semibold' : 'regular'}>
{item.label}
</Text>
</ListItem.Title>
</ListItem.Content>
{selectedIndex === index ? (
<Icon name="radio-button-checked" color={Theme.Colors.Icon} />
) : (
<Icon name="radio-button-unchecked" color={Theme.Colors.GrayIcon} />
)}
</ListItem>
))}
</Column>
);
};
interface PickerProps<T> {
items: PickerItem<T>[];
selectedValue: T;
onValueChange: (value: T, index: number) => void;
}
interface PickerItem<T> {
label: string;
value: T;
}

View File

@@ -15,6 +15,7 @@ const Colors = {
Transparent: 'transparent',
Warning: '#f0ad4e',
LightOrange: '#fce7e3',
GrayText: '#6F6F6F',
};
export type ElevationLevel = 0 | 1 | 2 | 3 | 4 | 5;
@@ -60,6 +61,8 @@ export const DefaultTheme = {
OnboardingCloseIcon: Colors.White,
WarningIcon: Colors.Warning,
ProfileIconBg: Colors.LightOrange,
GrayText: Colors.GrayText,
gradientBtn: ['#F59B4B', '#E86E04'],
},
Styles: StyleSheet.create({
title: {
@@ -399,6 +402,9 @@ export const DefaultTheme = {
borderRadius: 10,
backgroundColor: Colors.Orange,
},
gradient: {
borderRadius: 10,
},
}),
OIDCAuthStyles: StyleSheet.create({
viewContainer: {

View File

@@ -15,6 +15,7 @@ const Colors = {
Purple: '#70308C',
Transparent: 'transparent',
Warning: '#f0ad4e',
GrayText: '#6F6F6F',
};
export type ElevationLevel = 0 | 1 | 2 | 3 | 4 | 5;
@@ -59,6 +60,8 @@ export const PurpleTheme = {
OnboardingCircleIcon: Colors.White,
OnboardingCloseIcon: Colors.White,
WarningIcon: Colors.Warning,
GrayText: Colors.GrayText,
gradientBtn: ['#F59B4B', '#E86E04'],
},
Styles: StyleSheet.create({
title: {
@@ -344,6 +347,9 @@ export const PurpleTheme = {
borderRadius: 10,
backgroundColor: Colors.Orange,
},
gradient: {
borderRadius: 10,
},
}),
OIDCAuthStyles: StyleSheet.create({
viewContainer: {

View File

@@ -60,7 +60,7 @@
"no": "No",
"Alert": "Alert",
"ok": "Okay",
"downloading":"Downloading Your Card"
"downloading": "Downloading Your Card"
},
"AuthScreen": {
"header": "Would you like to use biometrics to unlock the application?",
@@ -146,7 +146,7 @@
"noReceivedVcsText": "Tap on Request below to receive {{vcLabel}}"
},
"ViewVcModal": {
"title":"ID Details",
"title": "ID Details",
"cancel": "Cancel",
"lock": "Lock",
"unlock": "Unlock",
@@ -218,7 +218,7 @@
"cancel": "Cancel",
"essentialClaims": "Essential Claims",
"voluntaryClaims": "Voluntary Claims",
"required":"Required"
"required": "Required"
},
"ReceiveVcScreen": {
"header": "{{vcLabel}} details",
@@ -329,6 +329,11 @@
"getStarted": "Get started",
"unlockApp": "Unlock application"
},
"SetupLanguage": {
"header": "Choose Language",
"description": "Lorem Ipsum is simply dummy text of the printing and typesetting industry",
"save": "Save Preference"
},
"common": {
"cancel": "Cancel",
"save": "Save",

View File

@@ -1,5 +1,5 @@
import { init } from 'mosip-inji-face-sdk';
import { ContextFrom, EventFrom, send, StateFrom } from 'xstate';
import { assign, ContextFrom, EventFrom, send, StateFrom } from 'xstate';
import { createModel } from 'xstate/lib/model';
import getAllConfigurations from '../shared/commonprops/commonProps';
import { AppServices } from '../shared/GlobalContext';
@@ -11,6 +11,7 @@ const model = createModel(
passcode: '',
biometrics: '',
canUseBiometrics: false,
selectLanguage: false,
},
{
events: {
@@ -19,6 +20,7 @@ const model = createModel(
LOGOUT: () => ({}),
LOGIN: () => ({}),
STORE_RESPONSE: (response?: unknown) => ({ response }),
SELECT: () => ({}),
},
}
);
@@ -60,21 +62,29 @@ export const authMachine = model.createMachine(
},
checkingAuth: {
always: [
{ cond: 'hasLanguageset', target: 'languagesetup' },
{ cond: 'hasPasscodeSet', target: 'unauthorized' },
{ cond: 'hasBiometricSet', target: 'unauthorized' },
{ target: 'settingUp' },
],
},
languagesetup: {
on: {
SELECT: {
target: 'settingUp',
},
},
},
settingUp: {
on: {
SETUP_PASSCODE: {
target: 'authorized',
actions: ['setPasscode', 'storeContext'],
actions: ['setPasscode', 'storeContext', 'setLanguage'],
},
SETUP_BIOMETRICS: {
// Note! dont authorized yet we need to setup passcode too as discuss
// target: 'authorized',
actions: ['setBiometrics', 'storeContext'],
actions: ['setBiometrics', 'storeContext', 'setLanguage'],
},
},
},
@@ -127,6 +137,9 @@ export const authMachine = model.createMachine(
setBiometrics: model.assign({
biometrics: (_, event: SetupBiometricsEvent) => event.biometrics,
}),
setLanguage: assign({
selectLanguage: (context) => !context.selectLanguage,
}),
},
services: {
@@ -154,6 +167,9 @@ export const authMachine = model.createMachine(
hasBiometricSet: (context) => {
return context.biometrics !== '' && context.passcode !== '';
},
hasLanguageset: (context) => {
return !context.selectLanguage;
},
},
}
);
@@ -190,3 +206,7 @@ export function selectUnauthorized(state: State) {
export function selectSettingUp(state: State) {
return state.matches('settingUp');
}
export function selectLanguagesetup(state: State) {
return state.matches('languagesetup');
}

View File

@@ -24,6 +24,7 @@ export interface Typegen0 {
requestStoredContext: 'xstate.init';
setBiometrics: 'SETUP_BIOMETRICS';
setContext: 'STORE_RESPONSE';
setLanguage: 'SETUP_BIOMETRICS' | 'SETUP_PASSCODE';
setPasscode: 'SETUP_PASSCODE';
storeContext:
| 'SETUP_BIOMETRICS'
@@ -35,6 +36,7 @@ export interface Typegen0 {
'eventsCausingGuards': {
hasBiometricSet: '';
hasData: 'STORE_RESPONSE';
hasLanguageset: '';
hasPasscodeSet: '';
};
'eventsCausingServices': {
@@ -44,6 +46,7 @@ export interface Typegen0 {
| 'authorized'
| 'checkingAuth'
| 'init'
| 'languagesetup'
| 'savingDefaults'
| 'settingUp'
| 'unauthorized';

538
package-lock.json generated
View File

@@ -53,6 +53,7 @@
"react-native-fs": "^2.20.0",
"react-native-gesture-handler": "~2.1.0",
"react-native-keychain": "^8.0.0",
"react-native-linear-gradient": "^2.6.2",
"react-native-location-enabler": "^4.1.0",
"react-native-permissions": "^3.6.0",
"react-native-popable": "^0.4.3",
@@ -7829,8 +7830,284 @@
}
},
"node_modules/chokidar2": {
"resolved": "node_modules/watchpack/chokidar2",
"link": true
"version": "2.0.0",
"resolved": "file:node_modules/watchpack/chokidar2",
"dev": true,
"optional": true,
"dependencies": {
"chokidar": "^2.1.8"
},
"engines": {
"node": "<8.10.0"
}
},
"node_modules/chokidar2/node_modules/anymatch": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz",
"integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==",
"dev": true,
"optional": true,
"dependencies": {
"micromatch": "^3.1.4",
"normalize-path": "^2.1.1"
}
},
"node_modules/chokidar2/node_modules/anymatch/node_modules/normalize-path": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
"integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==",
"dev": true,
"optional": true,
"dependencies": {
"remove-trailing-separator": "^1.0.1"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/chokidar2/node_modules/binary-extensions": {
"version": "1.13.1",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz",
"integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==",
"dev": true,
"optional": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/chokidar2/node_modules/braces": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
"integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
"dev": true,
"optional": true,
"dependencies": {
"arr-flatten": "^1.1.0",
"array-unique": "^0.3.2",
"extend-shallow": "^2.0.1",
"fill-range": "^4.0.0",
"isobject": "^3.0.1",
"repeat-element": "^1.1.2",
"snapdragon": "^0.8.1",
"snapdragon-node": "^2.0.1",
"split-string": "^3.0.2",
"to-regex": "^3.0.1"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/chokidar2/node_modules/braces/node_modules/extend-shallow": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
"integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==",
"dev": true,
"optional": true,
"dependencies": {
"is-extendable": "^0.1.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/chokidar2/node_modules/chokidar": {
"version": "2.1.8",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz",
"integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==",
"deprecated": "Chokidar 2 does not receive security updates since 2019. Upgrade to chokidar 3 with 15x fewer dependencies",
"dev": true,
"optional": true,
"dependencies": {
"anymatch": "^2.0.0",
"async-each": "^1.0.1",
"braces": "^2.3.2",
"glob-parent": "^3.1.0",
"inherits": "^2.0.3",
"is-binary-path": "^1.0.0",
"is-glob": "^4.0.0",
"normalize-path": "^3.0.0",
"path-is-absolute": "^1.0.0",
"readdirp": "^2.2.1",
"upath": "^1.1.1"
},
"optionalDependencies": {
"fsevents": "^1.2.7"
}
},
"node_modules/chokidar2/node_modules/fill-range": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
"integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==",
"dev": true,
"optional": true,
"dependencies": {
"extend-shallow": "^2.0.1",
"is-number": "^3.0.0",
"repeat-string": "^1.6.1",
"to-regex-range": "^2.1.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/chokidar2/node_modules/fill-range/node_modules/extend-shallow": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
"integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==",
"dev": true,
"optional": true,
"dependencies": {
"is-extendable": "^0.1.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/chokidar2/node_modules/fsevents": {
"version": "1.2.13",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz",
"integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==",
"deprecated": "fsevents 1 will break on node v14+ and could be using insecure binaries. Upgrade to fsevents 2.",
"dev": true,
"hasInstallScript": true,
"optional": true,
"os": [
"darwin"
],
"dependencies": {
"bindings": "^1.5.0",
"nan": "^2.12.1"
},
"engines": {
"node": ">= 4.0"
}
},
"node_modules/chokidar2/node_modules/glob-parent": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz",
"integrity": "sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==",
"dev": true,
"optional": true,
"dependencies": {
"is-glob": "^3.1.0",
"path-dirname": "^1.0.0"
}
},
"node_modules/chokidar2/node_modules/glob-parent/node_modules/is-glob": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
"integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==",
"dev": true,
"optional": true,
"dependencies": {
"is-extglob": "^2.1.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/chokidar2/node_modules/is-binary-path": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz",
"integrity": "sha512-9fRVlXc0uCxEDj1nQzaWONSpbTfx0FmJfzHF7pwlI8DkWGoHBBea4Pg5Ky0ojwwxQmnSifgbKkI06Qv0Ljgj+Q==",
"dev": true,
"optional": true,
"dependencies": {
"binary-extensions": "^1.0.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/chokidar2/node_modules/is-extendable": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
"integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==",
"dev": true,
"optional": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/chokidar2/node_modules/is-number": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
"integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==",
"dev": true,
"optional": true,
"dependencies": {
"kind-of": "^3.0.2"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/chokidar2/node_modules/is-number/node_modules/kind-of": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
"integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
"dev": true,
"optional": true,
"dependencies": {
"is-buffer": "^1.1.5"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/chokidar2/node_modules/micromatch": {
"version": "3.1.10",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
"integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
"dev": true,
"optional": true,
"dependencies": {
"arr-diff": "^4.0.0",
"array-unique": "^0.3.2",
"braces": "^2.3.1",
"define-property": "^2.0.2",
"extend-shallow": "^3.0.2",
"extglob": "^2.0.4",
"fragment-cache": "^0.2.1",
"kind-of": "^6.0.2",
"nanomatch": "^1.2.9",
"object.pick": "^1.3.0",
"regex-not": "^1.0.0",
"snapdragon": "^0.8.1",
"to-regex": "^3.0.2"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/chokidar2/node_modules/readdirp": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz",
"integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==",
"dev": true,
"optional": true,
"dependencies": {
"graceful-fs": "^4.1.11",
"micromatch": "^3.1.10",
"readable-stream": "^2.0.2"
},
"engines": {
"node": ">=0.10"
}
},
"node_modules/chokidar2/node_modules/to-regex-range": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz",
"integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==",
"dev": true,
"optional": true,
"dependencies": {
"is-number": "^3.0.0",
"repeat-string": "^1.6.1"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/chownr": {
"version": "2.0.0",
@@ -21169,6 +21446,15 @@
"resolved": "https://registry.npmjs.org/react-native-keychain/-/react-native-keychain-8.0.0.tgz",
"integrity": "sha512-c7Cs+YQN26UaQsRG1dmlXL7VL2ctnXwH/dl0IOMEQ7ZaL2NdN313YSAI8ZEZZjrVhNmPsyWEuvTFqWrdpItqQg=="
},
"node_modules/react-native-linear-gradient": {
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/react-native-linear-gradient/-/react-native-linear-gradient-2.6.2.tgz",
"integrity": "sha512-Z8Xxvupsex+9BBFoSYS87bilNPWcRfRsGC0cpJk72Nxb5p2nEkGSBv73xZbEHnW2mUFvP+huYxrVvjZkr/gRjQ==",
"peerDependencies": {
"react": "*",
"react-native": "*"
}
},
"node_modules/react-native-location-enabler": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/react-native-location-enabler/-/react-native-location-enabler-4.1.1.tgz",
@@ -25240,17 +25526,6 @@
"chokidar2": "file:./chokidar2"
}
},
"node_modules/watchpack/chokidar2": {
"version": "2.0.0",
"dev": true,
"optional": true,
"dependencies": {
"chokidar": "^2.1.8"
},
"engines": {
"node": "<8.10.0"
}
},
"node_modules/wbuf": {
"version": "1.7.3",
"resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz",
@@ -33530,9 +33805,238 @@
}
},
"chokidar2": {
"version": "file:node_modules/watchpack/chokidar2",
"version": "2.0.0",
"dev": true,
"optional": true,
"requires": {
"chokidar": "^2.1.8"
},
"dependencies": {
"anymatch": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz",
"integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==",
"dev": true,
"optional": true,
"requires": {
"micromatch": "^3.1.4",
"normalize-path": "^2.1.1"
},
"dependencies": {
"normalize-path": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
"integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==",
"dev": true,
"optional": true,
"requires": {
"remove-trailing-separator": "^1.0.1"
}
}
}
},
"binary-extensions": {
"version": "1.13.1",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz",
"integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==",
"dev": true,
"optional": true
},
"braces": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
"integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
"dev": true,
"optional": true,
"requires": {
"arr-flatten": "^1.1.0",
"array-unique": "^0.3.2",
"extend-shallow": "^2.0.1",
"fill-range": "^4.0.0",
"isobject": "^3.0.1",
"repeat-element": "^1.1.2",
"snapdragon": "^0.8.1",
"snapdragon-node": "^2.0.1",
"split-string": "^3.0.2",
"to-regex": "^3.0.1"
},
"dependencies": {
"extend-shallow": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
"integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==",
"dev": true,
"optional": true,
"requires": {
"is-extendable": "^0.1.0"
}
}
}
},
"chokidar": {
"version": "2.1.8",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz",
"integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==",
"dev": true,
"optional": true,
"requires": {
"anymatch": "^2.0.0",
"async-each": "^1.0.1",
"braces": "^2.3.2",
"fsevents": "^1.2.7",
"glob-parent": "^3.1.0",
"inherits": "^2.0.3",
"is-binary-path": "^1.0.0",
"is-glob": "^4.0.0",
"normalize-path": "^3.0.0",
"path-is-absolute": "^1.0.0",
"readdirp": "^2.2.1",
"upath": "^1.1.1"
}
},
"fill-range": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
"integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==",
"dev": true,
"optional": true,
"requires": {
"extend-shallow": "^2.0.1",
"is-number": "^3.0.0",
"repeat-string": "^1.6.1",
"to-regex-range": "^2.1.0"
},
"dependencies": {
"extend-shallow": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
"integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==",
"dev": true,
"optional": true,
"requires": {
"is-extendable": "^0.1.0"
}
}
}
},
"fsevents": {
"version": "1.2.13",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz",
"integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==",
"dev": true,
"optional": true,
"requires": {
"bindings": "^1.5.0",
"nan": "^2.12.1"
}
},
"glob-parent": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz",
"integrity": "sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==",
"dev": true,
"optional": true,
"requires": {
"is-glob": "^3.1.0",
"path-dirname": "^1.0.0"
},
"dependencies": {
"is-glob": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
"integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==",
"dev": true,
"optional": true,
"requires": {
"is-extglob": "^2.1.0"
}
}
}
},
"is-binary-path": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz",
"integrity": "sha512-9fRVlXc0uCxEDj1nQzaWONSpbTfx0FmJfzHF7pwlI8DkWGoHBBea4Pg5Ky0ojwwxQmnSifgbKkI06Qv0Ljgj+Q==",
"dev": true,
"optional": true,
"requires": {
"binary-extensions": "^1.0.0"
}
},
"is-extendable": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
"integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==",
"dev": true,
"optional": true
},
"is-number": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
"integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==",
"dev": true,
"optional": true,
"requires": {
"kind-of": "^3.0.2"
},
"dependencies": {
"kind-of": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
"integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
"dev": true,
"optional": true,
"requires": {
"is-buffer": "^1.1.5"
}
}
}
},
"micromatch": {
"version": "3.1.10",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
"integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
"dev": true,
"optional": true,
"requires": {
"arr-diff": "^4.0.0",
"array-unique": "^0.3.2",
"braces": "^2.3.1",
"define-property": "^2.0.2",
"extend-shallow": "^3.0.2",
"extglob": "^2.0.4",
"fragment-cache": "^0.2.1",
"kind-of": "^6.0.2",
"nanomatch": "^1.2.9",
"object.pick": "^1.3.0",
"regex-not": "^1.0.0",
"snapdragon": "^0.8.1",
"to-regex": "^3.0.2"
}
},
"readdirp": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz",
"integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==",
"dev": true,
"optional": true,
"requires": {
"graceful-fs": "^4.1.11",
"micromatch": "^3.1.10",
"readable-stream": "^2.0.2"
}
},
"to-regex-range": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz",
"integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==",
"dev": true,
"optional": true,
"requires": {
"is-number": "^3.0.0",
"repeat-string": "^1.6.1"
}
}
}
},
"chownr": {
@@ -44115,6 +44619,12 @@
"resolved": "https://registry.npmjs.org/react-native-keychain/-/react-native-keychain-8.0.0.tgz",
"integrity": "sha512-c7Cs+YQN26UaQsRG1dmlXL7VL2ctnXwH/dl0IOMEQ7ZaL2NdN313YSAI8ZEZZjrVhNmPsyWEuvTFqWrdpItqQg=="
},
"react-native-linear-gradient": {
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/react-native-linear-gradient/-/react-native-linear-gradient-2.6.2.tgz",
"integrity": "sha512-Z8Xxvupsex+9BBFoSYS87bilNPWcRfRsGC0cpJk72Nxb5p2nEkGSBv73xZbEHnW2mUFvP+huYxrVvjZkr/gRjQ==",
"requires": {}
},
"react-native-location-enabler": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/react-native-location-enabler/-/react-native-location-enabler-4.1.1.tgz",

View File

@@ -58,6 +58,7 @@
"react-native-fs": "^2.20.0",
"react-native-gesture-handler": "~2.1.0",
"react-native-keychain": "^8.0.0",
"react-native-linear-gradient": "^2.6.2",
"react-native-location-enabler": "^4.1.0",
"react-native-permissions": "^3.6.0",
"react-native-popable": "^0.4.3",

View File

@@ -9,19 +9,16 @@ import { WelcomeScreen } from '../screens/WelcomeScreen';
import { PasscodeScreen } from '../screens/PasscodeScreen';
import { MainLayout } from '../screens/MainLayout';
import { NotificationsScreen } from '../screens/NotificationsScreen';
import { Image } from 'react-native';
import { SetupLanguageScreen } from '../screens/SetupLanguageScreen';
export const baseRoutes: Screen[] = [
{
name: 'Language',
component: SetupLanguageScreen,
},
{
name: 'Welcome',
component: WelcomeScreen,
options: {
headerLeft: () =>
React.createElement(Image, {
source: require('../assets/idpass-logo.png'),
style: { width: 124, height: 27, resizeMode: 'contain' },
}),
},
},
{
name: 'Auth',
@@ -52,6 +49,7 @@ export const authRoutes: Screen[] = [
];
export type RootStackParamList = {
Language: undefined;
Welcome: undefined;
Auth: undefined;
Passcode: {

View File

@@ -4,11 +4,8 @@ import {
NativeStackNavigationOptions,
createNativeStackNavigator,
} from '@react-navigation/native-stack';
import { LanguageSelector } from '../components/LanguageSelector';
import { authRoutes, baseRoutes } from '../routes';
import { useAppLayout } from './AppLayoutController';
import { Icon } from 'react-native-elements';
import { Theme } from '../components/ui/styleUtils';
import { StatusBar } from 'react-native';
const { Navigator, Screen } = createNativeStackNavigator();
@@ -20,18 +17,17 @@ export const AppLayout: React.FC = () => {
title: '',
headerTitleAlign: 'center',
headerShadowVisible: false,
headerRight: () => (
<LanguageSelector
triggerComponent={<Icon name="language" color={Theme.Colors.Icon} />}
/>
),
headerBackVisible: false,
};
return (
<NavigationContainer>
<StatusBar animated={true} barStyle="dark-content" />
<Navigator initialRouteName={baseRoutes[0].name} screenOptions={options}>
<Navigator
initialRouteName={
controller.isLanguagesetup ? baseRoutes[0].name : baseRoutes[1].name
}
screenOptions={options}>
{baseRoutes.map((route) => (
<Screen key={route.name} {...route} />
))}

View File

@@ -1,13 +1,15 @@
import { useSelector } from '@xstate/react';
import { useContext } from 'react';
import { selectAuthorized } from '../machines/auth';
import { selectAuthorized, selectLanguagesetup } from '../machines/auth';
import { GlobalContext } from '../shared/GlobalContext';
export function useAppLayout() {
const { appService } = useContext(GlobalContext);
const authService = appService.children.get('auth');
const isLanguagesetup = useSelector(authService, selectLanguagesetup);
return {
isAuthorized: useSelector(authService, selectAuthorized),
isLanguagesetup,
};
}

View File

@@ -0,0 +1,78 @@
import React from 'react';
import { SUPPORTED_LANGUAGES } from '../i18n';
import { Dimensions, I18nManager, View } from 'react-native';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { useTranslation } from 'react-i18next';
import i18next from 'i18next';
import RNRestart from 'react-native-restart';
import { SetupPicker } from '../components/ui/SetupPicker';
import { Button, Column, Text } from '../components/ui';
import { Theme } from '../components/ui/styleUtils';
import { Icon } from 'react-native-elements';
import { RootRouteProps } from '../routes';
import { useWelcomeScreen } from './WelcomeScreenController';
export const SetupLanguageScreen: React.FC<RootRouteProps> = (props) => {
const { i18n } = useTranslation();
const languages = Object.entries(SUPPORTED_LANGUAGES).map(
([value, label]) => ({ label, value })
);
const { t } = useTranslation('SetupLanguage');
const controller = useWelcomeScreen(props);
const changeLanguage = async (language: string) => {
if (language !== i18n.language) {
await i18n.changeLanguage(language).then(async () => {
await AsyncStorage.setItem('language', i18n.language);
const isRTL = i18next.dir(language) === 'rtl' ? true : false;
if (isRTL !== I18nManager.isRTL) {
try {
I18nManager.forceRTL(isRTL);
setTimeout(() => {
RNRestart.Restart();
}, 150);
} catch (e) {
console.log('error', e);
}
}
});
}
};
return (
<Column
align="space-between"
crossAlign="center"
backgroundColor={Theme.Colors.whiteBackgroundColor}
height={Dimensions.get('window').height * 0.9}>
<Icon
name="globe"
type="simple-line-icon"
color={Theme.Colors.Icon}
size={50}
/>
<Column crossAlign="center">
<Text weight="semibold">{t('header')}</Text>
<Text weight="regular" align="center" color={Theme.Colors.GrayText}>
{t('description')}
</Text>
</Column>
<SetupPicker
items={languages}
selectedValue={i18n.language}
onValueChange={changeLanguage}
/>
<Column padding="20" backgroundColor={Theme.Colors.whiteBackgroundColor}>
<Button
linearGradient
type="gradient"
title={t('save')}
onPress={() => {
controller.SELECT(), controller.unlockPage;
}}
colors={Theme.Colors.gradientBtn}
/>
</Column>
</Column>
);
};

View File

@@ -1,6 +1,12 @@
import { useSelector } from '@xstate/react';
import { useContext } from 'react';
import { selectBiometrics, selectPasscode, selectSettingUp } from '../machines/auth';
import {
AuthEvents,
selectBiometrics,
selectLanguagesetup,
selectPasscode,
selectSettingUp,
} from '../machines/auth';
import { selectBiometricUnlockEnabled } from '../machines/settings';
import { RootRouteProps } from '../routes';
import { GlobalContext } from '../shared/GlobalContext';
@@ -13,11 +19,19 @@ export function useWelcomeScreen(props: RootRouteProps) {
const isSettingUp = useSelector(authService, selectSettingUp);
const passcode = useSelector(authService, selectPasscode);
const biometrics = useSelector(authService, selectBiometrics);
const isBiometricUnlockEnabled = useSelector(settingsService, selectBiometricUnlockEnabled);
const isBiometricUnlockEnabled = useSelector(
settingsService,
selectBiometricUnlockEnabled
);
const isLanguagesetup = useSelector(authService, selectLanguagesetup);
return {
isSettingUp,
isLanguagesetup,
SELECT: () => {
authService.send(AuthEvents.SELECT()),
props.navigation.navigate('Welcome');
},
unlockPage: () => {
// prioritize biometrics
if (!isSettingUp && isBiometricUnlockEnabled && biometrics !== '') {