From 5367c5eb341c10beea8e79ce9b2ee8e51dcd046a Mon Sep 17 00:00:00 2001 From: Leendert de Borst Date: Mon, 17 Nov 2025 09:33:11 +0100 Subject: [PATCH] Tweak QR code translations (#1347) --- .../app/(tabs)/settings/qr-confirm.tsx | 22 ++++++++++++------- .../app/(tabs)/settings/qr-result.tsx | 2 +- .../app/(tabs)/settings/qr-scanner.tsx | 18 +++++---------- apps/mobile-app/i18n/locales/en.json | 19 +++++++++++++++- 4 files changed, 39 insertions(+), 22 deletions(-) diff --git a/apps/mobile-app/app/(tabs)/settings/qr-confirm.tsx b/apps/mobile-app/app/(tabs)/settings/qr-confirm.tsx index 86dfb05a3..f855dca27 100644 --- a/apps/mobile-app/app/(tabs)/settings/qr-confirm.tsx +++ b/apps/mobile-app/app/(tabs)/settings/qr-confirm.tsx @@ -11,6 +11,7 @@ import { ThemedButton } from '@/components/themed/ThemedButton'; import { ThemedContainer } from '@/components/themed/ThemedContainer'; import { ThemedScrollView } from '@/components/themed/ThemedScrollView'; import { ThemedText } from '@/components/themed/ThemedText'; +import { UsernameDisplay } from '@/components/ui/UsernameDisplay'; import { useApp } from '@/context/AppContext'; import { useWebApi } from '@/context/WebApiContext'; import NativeVaultManager from '@/specs/NativeVaultManager'; @@ -70,15 +71,13 @@ export default function QRConfirmScreen() : React.ReactNode { }); } catch (error) { console.error('Mobile unlock error:', error); - let errorMsg = t('settings.qrScanner.mobileUnlock.genericError'); + let errorMsg = t('common.errors.unknownErrorTryAgain'); if (error instanceof Error) { - if (error.message.includes('ENCRYPTION_ERROR')) { - errorMsg = t('settings.qrScanner.mobileUnlock.vaultLocked'); - } else if (error.message.includes('404')) { + if (error.message.includes('404')) { errorMsg = t('settings.qrScanner.mobileUnlock.requestExpired'); - } else if (error.message.includes('401') || error.message.includes('403')) { - errorMsg = t('settings.qrScanner.mobileUnlock.unauthorized'); + } else { + errorMsg = t('common.errors.unknownErrorTryAgain'); } } @@ -186,9 +185,13 @@ export default function QRConfirmScreen() : React.ReactNode { confirmationText: { fontSize: 16, lineHeight: 24, - marginBottom: 12, + marginBottom: 16, textAlign: 'center', }, + usernameDisplayContainer: { + marginBottom: 12, + width: '100%', + }, buttonContainer: { gap: 12, marginTop: 20, @@ -223,8 +226,11 @@ export default function QRConfirmScreen() : React.ReactNode { {t('settings.qrScanner.mobileUnlock.confirmTitle')} - {t('settings.qrScanner.mobileUnlock.confirmMessage', { username })} + {t('settings.qrScanner.mobileUnlock.confirmMessage')} + + + diff --git a/apps/mobile-app/app/(tabs)/settings/qr-result.tsx b/apps/mobile-app/app/(tabs)/settings/qr-result.tsx index cd4128515..c2c1eafe0 100644 --- a/apps/mobile-app/app/(tabs)/settings/qr-result.tsx +++ b/apps/mobile-app/app/(tabs)/settings/qr-result.tsx @@ -94,7 +94,7 @@ export default function QRResultScreen() : React.ReactNode { {message || (isSuccess ? t('settings.qrScanner.mobileUnlock.successDescription') - : t('settings.qrScanner.mobileUnlock.genericError'))} + : t('common.errors.unknownErrorTryAgain'))} diff --git a/apps/mobile-app/app/(tabs)/settings/qr-scanner.tsx b/apps/mobile-app/app/(tabs)/settings/qr-scanner.tsx index 73d3c3660..2d08de66c 100644 --- a/apps/mobile-app/app/(tabs)/settings/qr-scanner.tsx +++ b/apps/mobile-app/app/(tabs)/settings/qr-scanner.tsx @@ -118,13 +118,13 @@ export default function QRScannerScreen() : React.ReactNode { setIsLoadingAfterScan(false); console.error('QR validation error:', error); - let errorMsg = t('settings.qrScanner.mobileUnlock.genericError'); + let errorMsg = t('common.errors.unknownErrorTryAgain'); if (error instanceof Error) { if (error.message.includes('404')) { errorMsg = t('settings.qrScanner.mobileUnlock.requestExpired'); - } else if (error.message.includes('401') || error.message.includes('403')) { - errorMsg = t('settings.qrScanner.mobileUnlock.unauthorized'); + } else { + errorMsg = t('common.errors.unknownErrorTryAgain'); } } @@ -138,6 +138,7 @@ export default function QRScannerScreen() : React.ReactNode { /** * Handle barcode scanned - validate request and navigate to confirmation. + * Only processes AliasVault QR codes, silently ignores others. */ const handleBarcodeScanned = useCallback(({ data }: { data: string }) : void => { // Prevent multiple scans @@ -148,21 +149,14 @@ export default function QRScannerScreen() : React.ReactNode { // Parse the QR code to determine its type const parsedData = parseQRCode(data); + // Silently ignore non-AliasVault QR codes if (!parsedData.type) { - Alert.alert( - t('settings.qrScanner.invalidQrCode'), - t('settings.qrScanner.notAliasVaultQr'), - [{ text: t('common.ok'), /** - * Go back to the settings tab. - */ - onPress: (): void => router.back() }] - ); return; } // Validate the request and navigate (with min 500ms loading) validateAndNavigate(parsedData); - }, [isLoadingAfterScan, t, validateAndNavigate]); + }, [isLoadingAfterScan, validateAndNavigate]); // Handle QR code URL passed from deep link (e.g., from native camera) useEffect(() => { diff --git a/apps/mobile-app/i18n/locales/en.json b/apps/mobile-app/i18n/locales/en.json index ce58baca9..e48868374 100644 --- a/apps/mobile-app/i18n/locales/en.json +++ b/apps/mobile-app/i18n/locales/en.json @@ -8,7 +8,7 @@ "no": "No", "ok": "OK", "continue": "Continue", - "loading": "Loading...", + "loading": "Loading", "error": "Error", "success": "Success", "never": "Never", @@ -395,6 +395,23 @@ "failedToDelete": "Failed to delete account. Please try again.", "usernameNotFound": "Username not found. Please login again." } + }, + "qrScanner": { + "title": "QR Code Scanner", + "scanningMessage": "Point your camera at the QR code", + "invalidQrCode": "Invalid QR Code", + "notAliasVaultQr": "This is not a valid AliasVault QR code. Please scan a QR code generated by AliasVault.", + "cameraPermissionTitle": "Camera Permission Required", + "cameraPermissionMessage": "Please allow camera access to scan QR codes.", + "mobileUnlock": { + "confirmTitle": "Confirm Login", + "confirmMessage": "You are about to log in on a remote device with your account. This other device will have full access to your vault. Only proceed if you trust this device.", + "successTitle": "Device Unlocked", + "successDescription": "The remote device has been successfully unlocked.", + "requestExpired": "This unlock request has expired. Please generate a new QR code.", + "authenticationFailed": "Authentication failed. Please try again.", + "authenticationRequired": "Authentication required to confirm this action." + } } }, "navigation": {