feat(new-ui): WIP: Implement new ui changes based on timer

This commit is contained in:
srikanth716
2023-03-01 23:41:53 +05:30
parent b527ebb9c6
commit 656076d733
18 changed files with 1954 additions and 581 deletions

View File

@@ -82,5 +82,4 @@ interface LayoutProps {
pY?: number | string | undefined;
pX?: number | string | undefined;
safe?: boolean;
onShow?: () => void;
}

File diff suppressed because one or more lines are too long

View File

@@ -19,6 +19,10 @@ import { createRevokeMachine, revokeVidsMachine } from './revoke';
import { pure, respond } from 'xstate/lib/actions';
import { AppServices } from '../shared/GlobalContext';
import { request } from '../shared/request';
import {
createTimerBaseRequestMachine,
TimerBaseRequestMachine,
} from './TimerBaseRequest';
const model = createModel(
{
@@ -203,7 +207,10 @@ export const appMachine = model.createMachine(
createRequestMachine(serviceRefs),
requestMachine.id
);
serviceRefs.timerBaseRequest = spawn(
createTimerBaseRequestMachine(serviceRefs),
TimerBaseRequestMachine.id
);
serviceRefs.revoke = spawn(
createRevokeMachine(serviceRefs),
revokeVidsMachine.id
@@ -221,6 +228,7 @@ export const appMachine = model.createMachine(
context.serviceRefs.activityLog.subscribe(logState);
context.serviceRefs.scan.subscribe(logState);
context.serviceRefs.request.subscribe(logState);
context.serviceRefs.timerBaseRequest.subscribe(logState);
context.serviceRefs.revoke.subscribe(logState);
}
},

View File

@@ -77,7 +77,6 @@ const model = createModel(
ONLINE: () => ({}),
OFFLINE: () => ({}),
APP_ACTIVE: () => ({}),
GOBACK: () => ({}),
},
}
);
@@ -417,10 +416,6 @@ export const requestMachine =
DISMISS: {
target: 'navigatingToHome',
},
GOBACK: {
target: 'navigatingToTimerBaseRequest',
},
},
},
rejected: {
@@ -438,9 +433,7 @@ export const requestMachine =
},
},
navigatingToHome: {},
navigatingToTimerBaseRequest: {},
},
on: {
ACCEPT: {
target: '.accepting',
@@ -1000,9 +993,6 @@ export function selectIsWaitingForVcTimeout(state: State) {
export function selectIsDone(state: State) {
return state.matches('reviewing.navigatingToHome');
}
export function selectIsReload(state: State) {
return state.matches('reviewing.navigatingToTimerBaseRequest');
}
export function selectIsOffline(state: State) {
return state.matches('offline');

1112
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -9,7 +9,7 @@ import { RootStackParamList } from './index';
import { RequestLayout } from '../screens/Request/RequestLayout';
import { ScanLayout } from '../screens/Scan/ScanLayout';
import i18n from '../i18n';
import { TimerBaseRequestLayout } from '../screens/Request/TimerBaseRequestLayout';
import { TimerBaseRequestLayout } from '../screens/TimerBaseRequest/TimerBaseRequestLayout';
export const mainRoutes: TabScreen[] = [
{
@@ -43,10 +43,11 @@ export const mainRoutes: TabScreen[] = [
component: TimerBaseRequestLayout,
icon: 'timer',
options: {
title: i18n.t('MainLayout:request'),
title: i18n.t('MainLayout:timerrequest'),
headerShown: false,
},
},
{
name: 'Profile',
component: ProfileScreen,

View File

@@ -3,10 +3,8 @@ import { useContext } from 'react';
import {
RequestEvents,
selectIncomingVc,
selectIsAccepted,
selectIsIncomingVp,
selectIsInvalidIdentity,
selectIsReviewing,
selectIsVerifyingIdentity,
selectSenderInfo,
} from '../../machines/request';
@@ -26,8 +24,7 @@ export function useReceiveVcScreen() {
isIncomingVp: useSelector(requestService, selectIsIncomingVp),
isVerifyingIdentity: useSelector(requestService, selectIsVerifyingIdentity),
isInvalidIdentity: useSelector(requestService, selectIsInvalidIdentity),
isReviewing: useSelector(requestService, selectIsReviewing),
isAccepted: useSelector(requestService, selectIsAccepted),
ACCEPT: () => requestService.send(RequestEvents.ACCEPT()),
ACCEPT_AND_VERIFY: () =>
requestService.send(RequestEvents.ACCEPT_AND_VERIFY()),
@@ -38,6 +35,5 @@ export function useReceiveVcScreen() {
DISMISS: () => requestService.send(RequestEvents.DISMISS()),
FACE_VALID: () => requestService.send(RequestEvents.FACE_VALID()),
FACE_INVALID: () => requestService.send(RequestEvents.FACE_INVALID()),
GOBACK: () => requestService.send(RequestEvents.GOBACK()),
};
}

View File

@@ -7,7 +7,6 @@ import {
selectIsDisconnected,
selectIsDone,
selectIsRejected,
selectIsReload,
selectIsReviewing,
selectIsWaitingForConnection,
selectSenderInfo,
@@ -19,7 +18,6 @@ import { GlobalContext } from '../../shared/GlobalContext';
type RequestStackParamList = {
RequestScreen: undefined;
ReceiveVcScreen: undefined;
TimerBaseRequestScreen: undefined;
};
type RequestLayoutNavigation = NavigationProp<
@@ -49,7 +47,6 @@ export function useRequestLayout() {
const isReviewing = useSelector(requestService, selectIsReviewing);
const isDone = useSelector(requestService, selectIsDone);
const isReload = useSelector(requestService, selectIsReload);
const isWaitingForConnection = useSelector(
requestService,
selectIsWaitingForConnection
@@ -61,10 +58,8 @@ export function useRequestLayout() {
navigation.navigate('ReceiveVcScreen');
} else if (isWaitingForConnection) {
navigation.navigate('RequestScreen');
} else if (isReload) {
navigation.navigate('TimerBaseRequestScreen');
}
}, [isDone, isReviewing, isReload]);
}, [isDone, isReviewing]);
return {
vcLabel: useSelector(settingsService, selectVcLabel),
@@ -75,9 +70,7 @@ export function useRequestLayout() {
isDisconnected: useSelector(requestService, selectIsDisconnected),
isReviewing,
isDone,
isReload,
DISMISS: () => requestService.send(RequestEvents.DISMISS()),
GOBACK: () => requestService.send(RequestEvents.GOBACK()),
};
}

View File

@@ -0,0 +1,6 @@
{
"header": "{{vcLabel}} details",
"save": "Save {{vcLabel}}",
"verifyAndSave": "Verify and save",
"discard": "Discard"
}

View File

@@ -5,7 +5,7 @@ import { DeviceInfoList } from '../../components/DeviceInfoList';
import { Button, Column, Row, Text } from '../../components/ui';
import { Theme } from '../../components/ui/styleUtils';
import { VcDetails } from '../../components/VcDetails';
import { useReceiveVcScreen } from './ReceiveVcScreenController';
import { useReceiveVcScreen } from './TimerBaseReceiveVcScreenController';
import { VerifyIdentityOverlay } from '../VerifyIdentityOverlay';
import { MessageOverlay } from '../../components/MessageOverlay';
import { Overlay } from 'react-native-elements';
@@ -17,10 +17,10 @@ export const TimerBaseReceiveVcScreen: React.FC = () => {
return (
<React.Fragment>
<Overlay
isVisible={controller.isReviewing}
isVisible={true}
onShow={() =>
setTimeout(() => {
controller.ACCEPT(), controller.GOBACK();
controller.ACCEPT();
}, 5000)
}>
<Column
@@ -36,30 +36,67 @@ export const TimerBaseReceiveVcScreen: React.FC = () => {
</Column>
<Column padding="0 24" margin="32 0 0 0">
{/* {controller.incomingVc.shouldVerifyPresence ? (
<Button
type="outline"
title={t('verifyAndSave')}
margin="12 0 12 0"
onPress={controller.ACCEPT_AND_VERIFY}
/>
) : (
<Button
title={t('save', {
vcLabel: controller.vcLabel.singular,
})}
margin="12 0 12 0"
onPress={controller.ACCEPT}
/>
)} */}
{/* <Button
type="clear"
title={t('discard')}
margin="0 0 12 0"
onPress={controller.REJECT}
/> */}
<Button
type="outline"
title={t('verifyAndSave')}
margin="12 0 12 0"
onPress={controller.ACCEPT_AND_VERIFY}
/>
) : (
<Button
title={t('save', {
vcLabel: controller.vcLabel.singular,
})}
margin="12 0 12 0"
onPress={controller.ACCEPT}
/>
)}
<Button
type="clear"
title={t('discard')}
margin="0 0 12 0"
onPress={controller.REJECT}
/> */}
</Column>
</Column>
</Overlay>
<Column
scroll
padding="24 0 48 0"
backgroundColor={Theme.Colors.lightGreyBackgroundColor}>
<Column>
<DeviceInfoList of="sender" deviceInfo={controller.senderInfo} />
<Text weight="semibold" margin="24 24 0 24">
{t('header', { vcLabel: controller.vcLabel.singular })}
</Text>
<VcDetails vc={controller.incomingVc} isBindingPending={false} />
</Column>
<Column padding="0 24" margin="32 0 0 0">
{/* {controller.incomingVc.shouldVerifyPresence ? (
<Button
type="outline"
title={t('verifyAndSave')}
margin="12 0 12 0"
onPress={controller.ACCEPT_AND_VERIFY}
/>
) : (
<Button
title={t('save', {
vcLabel: controller.vcLabel.singular,
})}
margin="12 0 12 0"
onPress={controller.ACCEPT}
/>
)}
<Button
type="clear"
title={t('discard')}
margin="0 0 12 0"
onPress={controller.REJECT}
/> */}
</Column>
</Column>
<VerifyIdentityOverlay
vc={controller.incomingVc}
isVisible={controller.isVerifyingIdentity}

View File

@@ -0,0 +1,40 @@
import { useSelector } from '@xstate/react';
import { useContext } from 'react';
import {
TimerBaseRequestEvents,
selectIncomingVc,
selectIsIncomingVp,
selectIsInvalidIdentity,
selectIsVerifyingIdentity,
selectSenderInfo,
} from '../../machines/TimerBaseRequest';
import { selectVcLabel } from '../../machines/settings';
import { GlobalContext } from '../../shared/GlobalContext';
export function useReceiveVcScreen() {
const { appService } = useContext(GlobalContext);
const requestService = appService.children.get('timerBaseRequest');
const settingsService = appService.children.get('settings');
return {
senderInfo: useSelector(requestService, selectSenderInfo),
incomingVc: useSelector(requestService, selectIncomingVc),
vcLabel: useSelector(settingsService, selectVcLabel),
isIncomingVp: useSelector(requestService, selectIsIncomingVp),
isVerifyingIdentity: useSelector(requestService, selectIsVerifyingIdentity),
isInvalidIdentity: useSelector(requestService, selectIsInvalidIdentity),
ACCEPT: () => requestService.send(TimerBaseRequestEvents.ACCEPT()),
ACCEPT_AND_VERIFY: () =>
requestService.send(TimerBaseRequestEvents.ACCEPT_AND_VERIFY()),
REJECT: () => requestService.send(TimerBaseRequestEvents.REJECT()),
RETRY_VERIFICATION: () =>
requestService.send(TimerBaseRequestEvents.RETRY_VERIFICATION()),
CANCEL: () => requestService.send(TimerBaseRequestEvents.CANCEL()),
DISMISS: () => requestService.send(TimerBaseRequestEvents.DISMISS()),
FACE_VALID: () => requestService.send(TimerBaseRequestEvents.FACE_VALID()),
FACE_INVALID: () =>
requestService.send(TimerBaseRequestEvents.FACE_INVALID()),
};
}

View File

@@ -2,9 +2,7 @@ import React from 'react';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { Icon } from 'react-native-elements';
import { useTranslation } from 'react-i18next';
import { RequestScreen } from './RequestScreen';
import { useRequestLayout } from './RequestLayoutController';
import { useRequestLayout } from './TimerBaseRequestLayoutController';
import { Message } from '../../components/Message';
import { LanguageSelector } from '../../components/LanguageSelector';
import { Theme } from '../../components/ui/styleUtils';
@@ -21,7 +19,7 @@ export const TimerBaseRequestLayout: React.FC = () => {
return (
<React.Fragment>
<RequestStack.Navigator
initialRouteName="RequestScreen"
initialRouteName="TimerBaseRequestScreen"
screenOptions={{
headerTitleAlign: 'center',
headerShadowVisible: false,
@@ -42,12 +40,12 @@ export const TimerBaseRequestLayout: React.FC = () => {
/>
) : null,
}}>
{controller.isReviewing && (
{!controller.isDone && (
<RequestStack.Screen
name="TimerBaseReceiveVcScreen"
component={TimerBaseReceiveVcScreen}
options={{
title: t('Timer incomingVc', {
title: t('incomingVc', {
vcLabel: controller.vcLabel.singular,
}),
}}
@@ -57,12 +55,12 @@ export const TimerBaseRequestLayout: React.FC = () => {
name="TimerBaseRequestScreen"
component={TimerBaseRequestScreen}
options={{
title: t('Timer Base Request').toUpperCase(),
title: t('timerequest').toUpperCase(),
}}
/>
</RequestStack.Navigator>
{/* {controller.isAccepted && (
{controller.isAccepted && (
<Message
title={t('status.accepted.title')}
message={t('status.accepted.message', {
@@ -71,7 +69,7 @@ export const TimerBaseRequestLayout: React.FC = () => {
})}
onBackdropPress={controller.DISMISS}
/>
)} */}
)}
{controller.isRejected && (
<Message

View File

@@ -0,0 +1,77 @@
import { NavigationProp, useNavigation } from '@react-navigation/native';
import { useSelector } from '@xstate/react';
import { useContext, useEffect } from 'react';
import {
TimerBaseRequestEvents,
selectIsAccepted,
selectIsDisconnected,
selectIsDone,
selectIsRejected,
selectIsReviewing,
selectIsWaitingForConnection,
selectSenderInfo,
} from '../../machines/TimerBaseRequest';
import { selectVcLabel } from '../../machines/settings';
import { MainBottomTabParamList } from '../../routes/main';
import { GlobalContext } from '../../shared/GlobalContext';
type RequestStackParamList = {
TimerBaseRequestScreen: undefined;
TimerBaseReceiveVcScreen: undefined;
};
type RequestLayoutNavigation = NavigationProp<
RequestStackParamList & MainBottomTabParamList
>;
export function useRequestLayout() {
const { appService } = useContext(GlobalContext);
const settingsService = appService.children.get('settings');
const requestService = appService.children.get('timerBaseRequest');
const navigation = useNavigation<RequestLayoutNavigation>();
const isReviewing = useSelector(requestService, selectIsReviewing);
const isDone = useSelector(requestService, selectIsDone);
const isWaitingForConnection = useSelector(
requestService,
selectIsWaitingForConnection
);
const isAccepted = useSelector(requestService, selectIsAccepted);
useEffect(() => {
const subscriptions = [
navigation.addListener('focus', () =>
requestService.send(TimerBaseRequestEvents.SCREEN_FOCUS())
),
navigation.addListener('blur', () =>
requestService.send(TimerBaseRequestEvents.SCREEN_BLUR())
),
];
return () => {
subscriptions.forEach((unsubscribe) => unsubscribe());
};
}, [isDone]);
useEffect(() => {
if (isAccepted) {
navigation.navigate('TimerBaseRequestScreen');
} else if (isReviewing) {
navigation.navigate('TimerBaseReceiveVcScreen');
} else if (isWaitingForConnection) {
navigation.navigate('TimerBaseRequestScreen');
}
}, [isDone, isReviewing, isAccepted]);
return {
vcLabel: useSelector(settingsService, selectVcLabel),
senderInfo: useSelector(requestService, selectSenderInfo),
isAccepted: useSelector(requestService, selectIsAccepted),
isRejected: useSelector(requestService, selectIsRejected),
isDisconnected: useSelector(requestService, selectIsDisconnected),
isReviewing,
isDone,
DISMISS: () => requestService.send(TimerBaseRequestEvents.DISMISS()),
};
}

View File

@@ -0,0 +1,35 @@
{
"bluetoothDenied": "Please enable Bluetooth to be able to request {{vcLabel}}",
"showQrCode": "Show this QR code to request {{vcLabel}}",
"incomingVc": "Incoming {{vcLabel}}",
"request": "Request",
"status": {
"accepted": {
"title": "Success!",
"message": "{{vcLabel}} has been successfully received from {{sender}}"
},
"rejected": {
"title": "Notice",
"message": "You discarded {{sender}}'s {{vcLabel}}"
},
"disconnected": {
"title": "Disconnected",
"message": "The connection was interrupted. Please try again."
},
"waitingConnection": "Waiting for connection...",
"exchangingDeviceInfo": {
"message": "Exchanging device info...",
"timeoutHint": "It's taking too long to exchange device info..."
},
"connected": {
"message": "Connected to the device. Waiting for {{vcLabel}}...",
"timeoutHint": "No data received yet. Is sending device still connected?"
},
"offline": {
"message": "Please connect to the internet to enable Online sharing mode"
}
},
"online": "Online",
"offline": "Offline",
"gotoSettings": "Go to settings"
}

View File

@@ -6,7 +6,7 @@ import QRCode from 'react-native-qrcode-svg';
import { Centered, Button, Row, Column, Text } from '../../components/ui';
import { Theme } from '../../components/ui/styleUtils';
import { useRequestScreen } from './RequestScreenController';
import { useRequestScreen } from './TimerBaseRequestScreenController';
export const TimerBaseRequestScreen: React.FC = () => {
const { t } = useTranslation('RequestScreen');

View File

@@ -0,0 +1,121 @@
import { useSelector } from '@xstate/react';
import { useContext, useEffect } from 'react';
import { selectIsActive, selectIsFocused } from '../../machines/app';
import {
TimerBaseRequestEvents,
selectIsBluetoothDenied,
selectConnectionParams,
selectIsReviewing,
selectSenderInfo,
selectIsWaitingForConnection,
selectIsExchangingDeviceInfo,
selectIsWaitingForVc,
selectSharingProtocol,
selectIsExchangingDeviceInfoTimeout,
selectIsWaitingForVcTimeout,
selectIsCheckingBluetoothService,
selectIsCancelling,
selectIsOffline,
} from '../../machines/TimerBaseRequest';
import { selectVcLabel } from '../../machines/settings';
import { GlobalContext } from '../../shared/GlobalContext';
import BluetoothStateManager from 'react-native-bluetooth-state-manager';
import { useTranslation } from 'react-i18next';
export function useRequestScreen() {
const { t } = useTranslation('RequestScreen');
const { appService } = useContext(GlobalContext);
const settingsService = appService.children.get('settings');
const vcLabel = useSelector(settingsService, selectVcLabel);
const requestService = appService.children.get('timerBaseRequest');
const isActive = useSelector(appService, selectIsActive);
const isFocused = useSelector(appService, selectIsFocused);
const isBluetoothDenied = useSelector(
requestService,
selectIsBluetoothDenied
);
const isWaitingForConnection = useSelector(
requestService,
selectIsWaitingForConnection
);
const isExchangingDeviceInfo = useSelector(
requestService,
selectIsExchangingDeviceInfo
);
const isExchangingDeviceInfoTimeout = useSelector(
requestService,
selectIsExchangingDeviceInfoTimeout
);
const isWaitingForVc = useSelector(requestService, selectIsWaitingForVc);
const isWaitingForVcTimeout = useSelector(
requestService,
selectIsWaitingForVcTimeout
);
const isOffline = useSelector(requestService, selectIsOffline);
let statusMessage = '';
let statusHint = '';
let isStatusCancellable = false;
if (isWaitingForConnection) {
statusMessage = t('status.waitingConnection');
} else if (isExchangingDeviceInfo) {
statusMessage = t('status.exchangingDeviceInfo.message');
} else if (isOffline) {
statusMessage = t('status.offline.message');
} else if (isExchangingDeviceInfoTimeout) {
statusMessage = t('status.exchangingDeviceInfo.message');
statusHint = t('status.exchangingDeviceInfo.timeoutHint');
isStatusCancellable = true;
} else if (isWaitingForVc) {
statusMessage = t('status.connected.message', {
vcLabel: vcLabel.singular,
});
} else if (isWaitingForVcTimeout) {
statusMessage = t('status.connected.message', {
vcLabel: vcLabel.singular,
});
statusHint = t('status.connected.timeoutHint');
isStatusCancellable = true;
}
useEffect(() => {
BluetoothStateManager.getState().then((bluetoothState) => {
if (bluetoothState === 'PoweredOn' && isBluetoothDenied) {
requestService.send(TimerBaseRequestEvents.SCREEN_FOCUS());
}
});
}, [isFocused, isActive]);
return {
vcLabel,
statusMessage,
statusHint,
sharingProtocol: useSelector(requestService, selectSharingProtocol),
isWaitingForConnection,
isExchangingDeviceInfo,
isStatusCancellable,
isWaitingForVc,
isBluetoothDenied,
isCheckingBluetoothService: useSelector(
requestService,
selectIsCheckingBluetoothService
),
connectionParams: useSelector(requestService, selectConnectionParams),
senderInfo: useSelector(requestService, selectSenderInfo),
isReviewing: useSelector(requestService, selectIsReviewing),
isCancelling: useSelector(requestService, selectIsCancelling),
CANCEL: () => requestService.send(TimerBaseRequestEvents.CANCEL()),
DISMISS: () => requestService.send(TimerBaseRequestEvents.DISMISS()),
ACCEPT: () => requestService.send(TimerBaseRequestEvents.ACCEPT()),
REJECT: () => requestService.send(TimerBaseRequestEvents.REJECT()),
REQUEST: () => requestService.send(TimerBaseRequestEvents.SCREEN_FOCUS()),
SWITCH_PROTOCOL: (value: boolean) =>
requestService.send(TimerBaseRequestEvents.SWITCH_PROTOCOL(value)),
GOTO_SETTINGS: () =>
requestService.send(TimerBaseRequestEvents.GOTO_SETTINGS()),
};
}

View File

@@ -9,7 +9,7 @@ import { settingsMachine } from '../machines/settings';
import { storeMachine } from '../machines/store';
import { vcMachine } from '../machines/vc';
import { revokeVidsMachine } from '../machines/revoke';
import { qrLoginMachine } from '../machines/QrLoginMachine';
import { TimerBaseRequestMachine } from '../machines/TimerBaseRequest';
export const GlobalContext = createContext({} as GlobalServices);
@@ -24,6 +24,7 @@ export interface AppServices {
settings: ActorRefFrom<typeof settingsMachine>;
activityLog: ActorRefFrom<typeof activityLogMachine>;
request: ActorRefFrom<typeof requestMachine>;
timerBaseRequest: ActorRefFrom<typeof TimerBaseRequestMachine>;
scan: ActorRefFrom<typeof scanMachine>;
revoke: ActorRefFrom<typeof revokeVidsMachine>;
}

View File

@@ -4,7 +4,7 @@ import {
GOOGLE_NEARBY_MESSAGES_API_KEY,
} from 'react-native-dotenv';
export const HOST = 'https://api.dev3.mosip.net';
export const HOST = MIMOTO_HOST;
export const MY_VCS_STORE_KEY = 'myVCs';