Files
inji-wallet/components/QrCodeOverlay.tsx
balachandarg-tw a7d1b9adbf [INJIMOB-956]: SVG rendering (#2080)
* [INJIMOB-956]: Android native module integration

Signed-off-by: balachandarg-tw <balachandar.g@thoughtworks.com>

* [INJIMOB-956]: iOS native module integration and react native layer

Signed-off-by: balachandarg-tw <balachandar.g@thoughtworks.com>

* [INJIMOB-956]: React native UI design changes

Signed-off-by: balachandarg-tw <balachandar.g@thoughtworks.com>

* [INJIMOB-3499]: Updating android native module integration to adapt latest chagnes in libray api

Signed-off-by: balachandarg-tw <balachandar.g@thoughtworks.com>

* [INJIMOB-3499]: Updated Native module integration

Signed-off-by: balachandarg-tw <balachandar.g@thoughtworks.com>

* [INJIMOB-956]: Update tht package dependency version

Signed-off-by: balachandarg-tw <balachandar.g@thoughtworks.com>

* [INJIMOB-956]: Loading before SVg rendering issue fixed

Signed-off-by: balachandarg-tw <balachandar.g@thoughtworks.com>

* [INJIMOB-956]: show Qr code button based on fallback image id

Signed-off-by: balachandarg-tw <balachandar.g@thoughtworks.com>

* [INJIMOB-956]: Update Swift package dependency

Signed-off-by: balachandarg-tw <balachandar.g@thoughtworks.com>

* [INJIMOB-3499]: Update Swift Package dependency to develop of Renderer library

Signed-off-by: balachandarg-tw <balachandar.g@thoughtworks.com>

* [INJIMOB-956]: Update in received screen

Signed-off-by: balachandarg-tw <balachandar.g@thoughtworks.com>

* [INJIMOB-956]: Update format in renderVC call

Signed-off-by: balachandarg-tw <balachandar.g@thoughtworks.com>

* [INJIMOB-956]: Change ordering of the params

Signed-off-by: balachandarg-tw <balachandar.g@thoughtworks.com>

* [INJIMOB-956]: Changes in caching

Signed-off-by: balachandarg-tw <balachandar.g@thoughtworks.com>

* [INJIMOB-956]: Updating the package dependency files

Signed-off-by: balachandarg-tw <balachandar.g@thoughtworks.com>

---------

Signed-off-by: balachandarg-tw <balachandar.g@thoughtworks.com>
2025-09-16 20:58:16 +05:30

176 lines
5.5 KiB
TypeScript

import React, {useEffect, useRef, useState} from 'react';
import {Pressable, View} from 'react-native';
import {Icon, Overlay} from 'react-native-elements';
import {Centered, Column, Row, Text, Button} from './ui';
import QRCode from 'react-native-qrcode-svg';
import {Theme} from './ui/styleUtils';
import {useTranslation} from 'react-i18next';
import testIDProps from '../shared/commonUtil';
import {SvgImage} from './ui/svg';
import {NativeModules} from 'react-native';
import {VerifiableCredential} from '../machines/VerifiableCredential/VCMetaMachine/vc';
import {DEFAULT_ECL, MAX_QR_DATA_LENGTH} from '../shared/constants';
import {VCMetadata} from '../shared/VCMetadata';
import {shareImageToAllSupportedApps} from '../shared/sharing/imageUtils';
import {ShareOptions} from 'react-native-share';
export const QrCodeOverlay: React.FC<QrCodeOverlayProps> = props => {
const {RNPixelpassModule} = NativeModules;
const {t} = useTranslation('VcDetails');
const [qrString, setQrString] = useState('');
const [qrError, setQrError] = useState(false);
const base64ImageType = 'data:image/png;base64,';
const {RNSecureKeystoreModule} = NativeModules;
async function getQRData(): Promise<string> {
let qrData: string;
try {
const keyData = await RNSecureKeystoreModule.getData(props.meta.id);
if (keyData[1] && keyData.length > 0) {
qrData = keyData[1];
} else {
throw new Error('No key data found');
}
} catch {
const {credential} = props.verifiableCredential;
qrData = await RNPixelpassModule.generateQRData(
JSON.stringify(credential),
'',
);
await RNSecureKeystoreModule.storeData(props.meta.id, qrData);
}
return qrData;
}
let qrRef = useRef(null);
function handleShareQRCodePress() {
qrRef.current.toDataURL(dataURL => {
shareImage(`${base64ImageType}${dataURL}`);
});
}
async function shareImage(base64String: string) {
const options: ShareOptions = {
url: base64String,
};
const shareStatus = await shareImageToAllSupportedApps(options);
if (!shareStatus) {
console.error('Error while sharing QR code::');
}
}
function onQRError() {
console.warn('Data is too big');
setQrError(true);
}
useEffect(() => {
(async () => {
const qrData = await getQRData();
if (qrData?.length < MAX_QR_DATA_LENGTH) {
setQrString(qrData);
} else {
setQrError(true);
}
})();
}, []);
const [isQrOverlayVisible, setIsQrOverlayVisible] = useState(false);
const overlayVisible = props.forceVisible ?? isQrOverlayVisible;
const toggleQrOverlay = () => {
if (props.onClose) props.onClose();
else setIsQrOverlayVisible(!overlayVisible);
};
return (
qrString != '' &&
!qrError && (
<React.Fragment>
<View testID="qrCodeView" style={Theme.QrCodeStyles.QrView}>
{props.showInlineQr !== false && (
<Pressable
{...testIDProps('qrCodePressable')}
accessible={false}
onPress={toggleQrOverlay}>
<QRCode
{...testIDProps('qrCode')}
size={72}
value={qrString}
backgroundColor={Theme.Colors.QRCodeBackgroundColor}
ecl={DEFAULT_ECL}
onError={onQRError}
/>
<View
testID="magnifierZoom"
style={[Theme.QrCodeStyles.magnifierZoom]}>
{SvgImage.MagnifierZoom()}
</View>
</Pressable>
)}
</View>
<Overlay
isVisible={overlayVisible}
onBackdropPress={toggleQrOverlay}
overlayStyle={{padding: 1, borderRadius: 21}}>
<Column style={Theme.QrCodeStyles.expandedQrCode}>
<Row pY={20} style={Theme.QrCodeStyles.QrCodeHeader}>
<Text
testID="qrCodeHeader"
align="center"
style={Theme.TextStyles.header}
weight="bold">
{t('qrCodeHeader')}
</Text>
<Icon
{...testIDProps('qrCodeCloseIcon')}
name="close"
onPress={toggleQrOverlay}
color={Theme.Colors.Details}
size={32}
/>
</Row>
<Centered testID="qrCodeDetails" pY={30}>
<QRCode
{...testIDProps('qrCodeExpandedView')}
size={300}
value={qrString}
backgroundColor={Theme.Colors.QRCodeBackgroundColor}
ecl={DEFAULT_ECL}
quietZone={10}
onError={onQRError}
getRef={data => (qrRef.current = data)}
/>
<Button
testID="share"
styles={Theme.QrCodeStyles.shareQrCodeButton}
title={t('shareQRCode')}
type="gradient"
icon={
<Icon
name="share-variant-outline"
type="material-community"
size={24}
color="white"
/>
}
onPress={handleShareQRCodePress}
/>
</Centered>
</Column>
</Overlay>
</React.Fragment>
)
);
};
interface QrCodeOverlayProps {
verifiableCredential: VerifiableCredential;
meta: VCMetadata;
showInlineQr?: boolean;
forceVisible?: boolean;
onClose?: () => void;
}