mirror of
https://github.com/aliasvault/aliasvault.git
synced 2026-05-13 01:45:12 -04:00
Update mobile app language setting configure for mobile app (#993)
This commit is contained in:
committed by
Leendert de Borst
parent
ca9b9e465c
commit
cb5cd1006c
@@ -28,12 +28,12 @@
|
||||
"searchCredentials": "Zoek inloggegevens...",
|
||||
"searchPlaceholder": "Inloggegevens zoeken...",
|
||||
"welcomeTitle": "Welkom bij AliasVault!",
|
||||
"welcomeDescription": "Om de AliasVault browser extensie te gebruiken: navigeer naar een website en gebruik de AliasVault automatisch invullen popup om nieuwe inloggegevens aan te maken.",
|
||||
"welcomeDescription": "Om de AliasVault browser extensie te gebruiken: navigeer naar een website en gebruik de AliasVault autofill popup om nieuwe inloggegevens aan te maken.",
|
||||
"manualCreationHint": "Als je handmatig identiteiten wilt aanmaken, open dan de volledige AliasVault app via het uitklapicoon in de rechterbovenhoek.",
|
||||
"lastUsed": "Laatst gebruikt",
|
||||
"createdAt": "Aangemaakt",
|
||||
"updatedAt": "Laatst bijgewerkt",
|
||||
"autofill": "Automatisch invullen",
|
||||
"autofill": "Autofill",
|
||||
"fillForm": "Formulier Invullen",
|
||||
"copyUsername": "Gebruikersnaam Kopiëren",
|
||||
"openWebsite": "Website Openen",
|
||||
|
||||
@@ -61,14 +61,14 @@
|
||||
"loggedIn": "Ingelogd",
|
||||
"logout": "Uitloggen",
|
||||
"globalSettings": "Globale Instellingen",
|
||||
"autofillPopup": "Automatisch invullen popup",
|
||||
"autofillPopup": "Autofill popup",
|
||||
"activeOnAllSites": "Actief op alle sites (tenzij hieronder uitgeschakeld)",
|
||||
"disabledOnAllSites": "Uitgeschakeld op alle sites",
|
||||
"enabled": "Ingeschakeld",
|
||||
"disabled": "Uitgeschakeld",
|
||||
"rightClickContextMenu": "Rechts-klik contextmenu",
|
||||
"siteSpecificSettings": "Site-specifieke Instellingen",
|
||||
"autofillPopupOn": "Automatisch invullen popup op: ",
|
||||
"autofillPopupOn": "Autofill popup op: ",
|
||||
"enabledForThisSite": "Ingeschakeld voor deze site",
|
||||
"disabledForThisSite": "Uitgeschakeld voor deze site",
|
||||
"temporarilyDisabledUntil": "Tijdelijk uitgeschakeld tot ",
|
||||
|
||||
@@ -113,7 +113,7 @@ const nlTranslations: IContentTranslations = {
|
||||
manualCredentialDescription: 'Specificeer je eigen e-mailadres en gebruikersnaam.',
|
||||
failedToCreateIdentity: 'Identiteit aanmaken mislukt. Probeer opnieuw.',
|
||||
enterEmailAndOrUsername: 'Voer e-mail en/of gebruikersnaam in',
|
||||
autofillWithAliasVault: 'Automatisch invullen met AliasVault',
|
||||
autofillWithAliasVault: 'Autofill met AliasVault',
|
||||
generateRandomPassword: 'Willekeurig wachtwoord genereren (kopiëren naar klembord)',
|
||||
passwordCopiedToClipboard: 'Wachtwoord gekopieerd naar klembord'
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Tabs, router } from 'expo-router';
|
||||
import React, { useEffect } from 'react';
|
||||
import { Platform, StyleSheet, View } from 'react-native';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Platform, StyleSheet, View } from 'react-native';
|
||||
|
||||
import emitter from '@/utils/EventEmitter';
|
||||
|
||||
|
||||
@@ -4,10 +4,10 @@ import * as Haptics from 'expo-haptics';
|
||||
import { Stack, useLocalSearchParams, useNavigation, useRouter } from 'expo-router';
|
||||
import { useState, useEffect, useRef, useCallback } from 'react';
|
||||
import { Resolver, useForm } from 'react-hook-form';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { StyleSheet, View, TouchableOpacity, Alert, Keyboard, KeyboardAvoidingView, Platform, Pressable } from 'react-native';
|
||||
import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view';
|
||||
import Toast from 'react-native-toast-message';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { CreateIdentityGenerator, IdentityHelperUtils, IdentityGenerator } from '@/utils/dist/shared/identity-generator';
|
||||
import type { Credential } from '@/utils/dist/shared/models/vault';
|
||||
@@ -98,7 +98,7 @@ export default function AddEditCredentialScreen() : React.ReactNode {
|
||||
text2: t('auth.errors.enterPassword')
|
||||
});
|
||||
}
|
||||
}, [id, dbContext.sqliteClient, setValue]);
|
||||
}, [id, dbContext.sqliteClient, setValue, t]);
|
||||
|
||||
/**
|
||||
* On mount, load an existing credential if we're in edit mode, or extract the service name from the service URL
|
||||
@@ -133,7 +133,7 @@ export default function AddEditCredentialScreen() : React.ReactNode {
|
||||
serviceNameRef.current?.focus();
|
||||
}, 100);
|
||||
}
|
||||
}, [id, isEditMode, serviceUrl, loadExistingCredential, setValue, authContext.isOffline, router]);
|
||||
}, [id, isEditMode, serviceUrl, loadExistingCredential, setValue, authContext.isOffline, router, t]);
|
||||
|
||||
/**
|
||||
* Initialize the identity and password generators with settings from user's vault.
|
||||
@@ -315,7 +315,7 @@ export default function AddEditCredentialScreen() : React.ReactNode {
|
||||
|
||||
setIsSyncing(false);
|
||||
}
|
||||
}, [isEditMode, id, serviceUrl, router, executeVaultMutation, dbContext.sqliteClient, mode, generateRandomAlias, webApi, watch, setIsSaveDisabled, setIsSyncing, isSaveDisabled]);
|
||||
}, [isEditMode, id, serviceUrl, router, executeVaultMutation, dbContext.sqliteClient, mode, generateRandomAlias, webApi, watch, setIsSaveDisabled, setIsSyncing, isSaveDisabled, t]);
|
||||
|
||||
/**
|
||||
* Generate a random username.
|
||||
@@ -555,7 +555,7 @@ export default function AddEditCredentialScreen() : React.ReactNode {
|
||||
),
|
||||
});
|
||||
}
|
||||
}, [navigation, mode, handleSubmit, onSubmit, colors.primary, isEditMode, router, styles.headerLeftButton, styles.headerLeftButtonText, styles.headerRightButton, styles.headerRightButtonDisabled, isSaveDisabled]);
|
||||
}, [navigation, mode, handleSubmit, onSubmit, colors.primary, isEditMode, router, styles.headerLeftButton, styles.headerLeftButtonText, styles.headerRightButton, styles.headerRightButtonDisabled, isSaveDisabled, t]);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import MaterialIcons from '@expo/vector-icons/MaterialIcons';
|
||||
import { useNavigation, useRouter } from 'expo-router';
|
||||
import { useCallback, useEffect } from 'react';
|
||||
import { StyleSheet, View, TouchableOpacity, AppState } from 'react-native';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { StyleSheet, View, TouchableOpacity, AppState } from 'react-native';
|
||||
|
||||
import { useColors } from '@/hooks/useColorScheme';
|
||||
|
||||
@@ -89,7 +89,7 @@ export default function AutofillCredentialCreatedScreen() : React.ReactNode {
|
||||
</TouchableOpacity>
|
||||
),
|
||||
});
|
||||
}, [navigation, colors.primary, styles.headerRightButton, handleStayInApp]);
|
||||
}, [navigation, colors.primary, styles.headerRightButton, handleStayInApp, t]);
|
||||
|
||||
return (
|
||||
<ThemedSafeAreaView style={styles.container}>
|
||||
@@ -108,7 +108,7 @@ export default function AutofillCredentialCreatedScreen() : React.ReactNode {
|
||||
{t('credentials.credentialCreatedMessage')}
|
||||
</ThemedText>
|
||||
<ThemedText style={[styles.message, styles.boldMessage]}>
|
||||
{t('credentials.switchBackToBrowser')}
|
||||
{t('credentials.switchBackToBrowser')}
|
||||
</ThemedText>
|
||||
</ThemedView>
|
||||
</ThemedSafeAreaView>
|
||||
|
||||
@@ -3,10 +3,10 @@ import { useNavigation, useFocusEffect } from '@react-navigation/native';
|
||||
import * as Haptics from 'expo-haptics';
|
||||
import { useRouter, useLocalSearchParams } from 'expo-router';
|
||||
import { useState, useEffect, useCallback, useRef } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { StyleSheet, Text, FlatList, TouchableOpacity, TextInput, RefreshControl, Platform, Animated, Alert } from 'react-native';
|
||||
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
||||
import Toast from 'react-native-toast-message';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import type { Credential } from '@/utils/dist/shared/models/vault';
|
||||
import emitter from '@/utils/EventEmitter';
|
||||
@@ -76,7 +76,7 @@ export default function CredentialsScreen() : React.ReactNode {
|
||||
});
|
||||
setIsLoadingCredentials(false);
|
||||
}
|
||||
}, [dbContext.sqliteClient, setIsLoadingCredentials]);
|
||||
}, [dbContext.sqliteClient, setIsLoadingCredentials, t]);
|
||||
|
||||
useEffect(() => {
|
||||
const unsubscribeFocus = navigation.addListener('focus', () => {
|
||||
@@ -194,7 +194,7 @@ export default function CredentialsScreen() : React.ReactNode {
|
||||
text2: err instanceof Error ? err.message : 'Unknown error',
|
||||
});
|
||||
}
|
||||
}, [syncVault, loadCredentials, setIsLoadingCredentials, setRefreshing, webApi, authContext, router]);
|
||||
}, [syncVault, loadCredentials, setIsLoadingCredentials, setRefreshing, webApi, authContext, router, t]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isAuthenticated || !isDatabaseAvailable) {
|
||||
@@ -301,7 +301,7 @@ export default function CredentialsScreen() : React.ReactNode {
|
||||
*/
|
||||
headerTitle: (): React.ReactNode => Platform.OS === 'android' ? <AndroidHeader title={t('credentials.title')} /> : <Text>{t('credentials.title')}</Text>,
|
||||
});
|
||||
}, [navigation]);
|
||||
}, [navigation, t]);
|
||||
|
||||
/**
|
||||
* Delete a credential.
|
||||
|
||||
@@ -2,9 +2,9 @@ import { Ionicons } from '@expo/vector-icons';
|
||||
import * as FileSystem from 'expo-file-system';
|
||||
import { useLocalSearchParams, useRouter, useNavigation, Stack } from 'expo-router';
|
||||
import React, { useEffect, useState, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { StyleSheet, View, TouchableOpacity, ActivityIndicator, Alert, Share, useColorScheme, TextInput, Linking } from 'react-native';
|
||||
import { WebView } from 'react-native-webview';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import type { Credential } from '@/utils/dist/shared/models/vault';
|
||||
import type { Email } from '@/utils/dist/shared/models/webapi';
|
||||
@@ -76,7 +76,7 @@ export default function EmailDetailsScreen() : React.ReactNode {
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
}, [dbContext.sqliteClient, id, webApi]);
|
||||
}, [dbContext.sqliteClient, id, webApi, t]);
|
||||
|
||||
useEffect(() => {
|
||||
loadEmail();
|
||||
@@ -117,7 +117,7 @@ export default function EmailDetailsScreen() : React.ReactNode {
|
||||
},
|
||||
]
|
||||
);
|
||||
}, [id, router, webApi]);
|
||||
}, [id, router, webApi, t]);
|
||||
|
||||
/**
|
||||
* Handle the download attachment button press.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Ionicons } from '@expo/vector-icons';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { StyleSheet, View, TouchableOpacity } from 'react-native';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { StyleSheet, View, TouchableOpacity } from 'react-native';
|
||||
|
||||
import { useColors } from '@/hooks/useColorScheme';
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Ionicons } from '@expo/vector-icons';
|
||||
import { useFocusEffect } from 'expo-router';
|
||||
import { useState, useCallback } from 'react';
|
||||
import { StyleSheet, View, Alert, TouchableOpacity } from 'react-native';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { StyleSheet, View, Alert, TouchableOpacity } from 'react-native';
|
||||
|
||||
import { useColors } from '@/hooks/useColorScheme';
|
||||
import { useVaultMutate } from '@/hooks/useVaultMutate';
|
||||
@@ -58,7 +58,7 @@ export default function IdentityGeneratorSettingsScreen(): React.ReactNode {
|
||||
};
|
||||
|
||||
loadSettings();
|
||||
}, [dbContext.sqliteClient])
|
||||
}, [dbContext.sqliteClient, t])
|
||||
);
|
||||
|
||||
/**
|
||||
@@ -75,7 +75,7 @@ export default function IdentityGeneratorSettingsScreen(): React.ReactNode {
|
||||
console.error('Error updating language setting:', error);
|
||||
Alert.alert(t('common.error'), t('settings.identityGeneratorSettings.errors.languageUpdateFailed'));
|
||||
}
|
||||
}, [executeVaultMutation, dbContext.sqliteClient]);
|
||||
}, [executeVaultMutation, dbContext.sqliteClient, t]);
|
||||
|
||||
/**
|
||||
* Handle gender change.
|
||||
@@ -90,7 +90,7 @@ export default function IdentityGeneratorSettingsScreen(): React.ReactNode {
|
||||
console.error('Error updating gender setting:', error);
|
||||
Alert.alert(t('common.error'), t('settings.identityGeneratorSettings.errors.genderUpdateFailed'));
|
||||
}
|
||||
}, [executeVaultMutation, dbContext.sqliteClient]);
|
||||
}, [executeVaultMutation, dbContext.sqliteClient, t]);
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
descriptionText: {
|
||||
|
||||
@@ -147,21 +147,45 @@ export default function SettingsScreen() : React.ReactNode {
|
||||
* Handle the language settings press.
|
||||
*/
|
||||
const handleLanguagePress = (): void => {
|
||||
const isIOS = Platform.OS === 'ios';
|
||||
|
||||
Alert.alert(
|
||||
t('settings.language'),
|
||||
t('settings.languageSystemMessage'),
|
||||
[
|
||||
{ text: t('common.cancel'), style: 'cancel' },
|
||||
{
|
||||
text: t('settings.openSettings'),
|
||||
{
|
||||
text: t('settings.openSettings'),
|
||||
style: 'default',
|
||||
/**
|
||||
* Open iOS settings
|
||||
* Open platform-specific settings
|
||||
*/
|
||||
onPress: (): void => {
|
||||
// Open iOS Settings app
|
||||
if (Platform.OS === 'ios') {
|
||||
Linking.openURL('app-settings:');
|
||||
onPress: async (): Promise<void> => {
|
||||
if (isIOS) {
|
||||
// Open iOS Settings app
|
||||
await Linking.openURL('app-settings:');
|
||||
} else {
|
||||
// Fallback to general locale settings
|
||||
try {
|
||||
await Linking.openSettings();
|
||||
return;
|
||||
} catch (error) {
|
||||
console.warn('Failed to open general locale settings:', error);
|
||||
}
|
||||
|
||||
// Fallback to general settings
|
||||
try {
|
||||
await Linking.openSettings();
|
||||
return;
|
||||
} catch (error) {
|
||||
console.warn('Failed to open general settings:', error);
|
||||
}
|
||||
|
||||
// Final fallback - show manual instructions
|
||||
Alert.alert(
|
||||
t('common.error') ?? 'Error',
|
||||
'Unable to open device settings. Please manually navigate to the app settings and change the language.'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import * as Haptics from 'expo-haptics';
|
||||
import { useState, useEffect, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { StyleSheet, View, TouchableOpacity, Alert, RefreshControl, Platform } from 'react-native';
|
||||
import Toast from 'react-native-toast-message';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import type { RefreshToken } from '@/utils/dist/shared/models/webapi';
|
||||
|
||||
@@ -94,7 +94,7 @@ export default function ActiveSessionsScreen() : React.ReactNode {
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
}, [webApi, setIsLoading, setRefreshTokens]);
|
||||
}, [webApi, setIsLoading, setRefreshTokens, t]);
|
||||
|
||||
/**
|
||||
* Handle the revoke session action.
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import * as Haptics from 'expo-haptics';
|
||||
import { useState, useEffect, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { StyleSheet, View, RefreshControl, Platform } from 'react-native';
|
||||
import Toast from 'react-native-toast-message';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import type { AuthLogModel } from '@/utils/dist/shared/models/webapi';
|
||||
import { AuthEventType } from '@/utils/dist/shared/models/webapi';
|
||||
@@ -102,7 +102,7 @@ export default function AuthLogsScreen() : React.ReactNode {
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
}, [webApi, setIsLoading, setLogs]);
|
||||
}, [webApi, setIsLoading, setLogs, t]);
|
||||
|
||||
/**
|
||||
* Refresh the logs on pull to refresh.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { router } from 'expo-router';
|
||||
import { useState } from 'react';
|
||||
import { StyleSheet, View, Alert, KeyboardAvoidingView, Platform } from 'react-native';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { StyleSheet, View, Alert, KeyboardAvoidingView, Platform } from 'react-native';
|
||||
|
||||
import { useColors } from '@/hooks/useColorScheme';
|
||||
import { useVaultMutate } from '@/hooks/useVaultMutate';
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { router } from 'expo-router';
|
||||
import { useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { StyleSheet, View, Alert, KeyboardAvoidingView, Platform } from 'react-native';
|
||||
import srp from 'secure-remote-password/client';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import type { DeleteAccountInitiateRequest, DeleteAccountInitiateResponse, DeleteAccountRequest } from '@/utils/dist/shared/models/webapi';
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Ionicons } from '@expo/vector-icons';
|
||||
import { router } from 'expo-router';
|
||||
import { StyleSheet, View, TouchableOpacity } from 'react-native';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { StyleSheet, View, TouchableOpacity } from 'react-native';
|
||||
|
||||
import { useColors } from '@/hooks/useColorScheme';
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import * as LocalAuthentication from 'expo-local-authentication';
|
||||
import { useState, useEffect, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { StyleSheet, View, Alert, Platform, Linking, Switch, TouchableOpacity } from 'react-native';
|
||||
import Toast from 'react-native-toast-message';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { useColors } from '@/hooks/useColorScheme';
|
||||
|
||||
@@ -134,7 +134,7 @@ export default function VaultUnlockSettingsScreen() : React.ReactNode {
|
||||
visibilityTime: 1200,
|
||||
});
|
||||
}
|
||||
}, [hasBiometrics, setAuthMethods, biometricDisplayName]);
|
||||
}, [hasBiometrics, setAuthMethods, biometricDisplayName, t]);
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
disabledText: {
|
||||
@@ -200,7 +200,7 @@ export default function VaultUnlockSettingsScreen() : React.ReactNode {
|
||||
</View>
|
||||
</View>
|
||||
<ThemedText style={styles.helpText}>
|
||||
{t('settings.vaultUnlockSettings.biometricHelp', {
|
||||
{t('settings.vaultUnlockSettings.biometricHelp', {
|
||||
keystore: Platform.OS === 'ios' ? t('settings.vaultUnlockSettings.keystoreIOS') : t('settings.vaultUnlockSettings.keystoreAndroid'),
|
||||
biometric: biometricDisplayName
|
||||
})}
|
||||
|
||||
@@ -41,7 +41,10 @@ function RootLayoutNav() : React.ReactNode {
|
||||
const hasBooted = useRef(false);
|
||||
|
||||
useEffect(() => {
|
||||
const initializeApp = async () => {
|
||||
/**
|
||||
* Initialize the app.
|
||||
*/
|
||||
const initializeApp = async () : Promise<void> => {
|
||||
if (hasBooted.current) {
|
||||
return;
|
||||
}
|
||||
@@ -54,135 +57,135 @@ function RootLayoutNav() : React.ReactNode {
|
||||
|
||||
hasBooted.current = true;
|
||||
|
||||
/**
|
||||
* Handle vault unlocking process.
|
||||
*/
|
||||
async function handleVaultUnlock() : Promise<void> {
|
||||
const { enabledAuthMethods } = await initializeAuth();
|
||||
/**
|
||||
* Handle vault unlocking process.
|
||||
*/
|
||||
async function handleVaultUnlock() : Promise<void> {
|
||||
const { enabledAuthMethods } = await initializeAuth();
|
||||
|
||||
try {
|
||||
const hasEncryptedDatabase = await NativeVaultManager.hasEncryptedDatabase();
|
||||
if (hasEncryptedDatabase) {
|
||||
const isFaceIDEnabled = enabledAuthMethods.includes('faceid');
|
||||
if (!isFaceIDEnabled) {
|
||||
setRedirectTarget('/unlock');
|
||||
setBootComplete(true);
|
||||
return;
|
||||
}
|
||||
|
||||
setStatus('Unlocking vault');
|
||||
const isUnlocked = await dbContext.unlockVault();
|
||||
if (isUnlocked) {
|
||||
await new Promise(resolve => setTimeout(resolve, 750));
|
||||
setStatus('Decrypting vault');
|
||||
await new Promise(resolve => setTimeout(resolve, 750));
|
||||
|
||||
// Check if the vault is up to date, if not, redirect to the upgrade page.
|
||||
if (await dbContext.hasPendingMigrations()) {
|
||||
setRedirectTarget('/upgrade');
|
||||
try {
|
||||
const hasEncryptedDatabase = await NativeVaultManager.hasEncryptedDatabase();
|
||||
if (hasEncryptedDatabase) {
|
||||
const isFaceIDEnabled = enabledAuthMethods.includes('faceid');
|
||||
if (!isFaceIDEnabled) {
|
||||
setRedirectTarget('/unlock');
|
||||
setBootComplete(true);
|
||||
return;
|
||||
}
|
||||
|
||||
setStatus('Unlocking vault');
|
||||
const isUnlocked = await dbContext.unlockVault();
|
||||
if (isUnlocked) {
|
||||
await new Promise(resolve => setTimeout(resolve, 750));
|
||||
setStatus('Decrypting vault');
|
||||
await new Promise(resolve => setTimeout(resolve, 750));
|
||||
|
||||
// Check if the vault is up to date, if not, redirect to the upgrade page.
|
||||
if (await dbContext.hasPendingMigrations()) {
|
||||
setRedirectTarget('/upgrade');
|
||||
setBootComplete(true);
|
||||
return;
|
||||
}
|
||||
|
||||
setBootComplete(true);
|
||||
return;
|
||||
}
|
||||
|
||||
setRedirectTarget('/unlock');
|
||||
setBootComplete(true);
|
||||
return;
|
||||
} else {
|
||||
setRedirectTarget('/unlock');
|
||||
setBootComplete(true);
|
||||
return;
|
||||
}
|
||||
|
||||
setRedirectTarget('/unlock');
|
||||
setBootComplete(true);
|
||||
return;
|
||||
} else {
|
||||
} catch {
|
||||
setRedirectTarget('/unlock');
|
||||
setBootComplete(true);
|
||||
return;
|
||||
}
|
||||
} catch {
|
||||
setRedirectTarget('/unlock');
|
||||
setBootComplete(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the app.
|
||||
*/
|
||||
const initialize = async () : Promise<void> => {
|
||||
const { isLoggedIn } = await initializeAuth();
|
||||
|
||||
if (!isLoggedIn) {
|
||||
setRedirectTarget('/login');
|
||||
setBootComplete(true);
|
||||
return;
|
||||
}
|
||||
|
||||
// First perform vault sync
|
||||
await syncVault({
|
||||
initialSync: true,
|
||||
/**
|
||||
* Handle the status update.
|
||||
*/
|
||||
onStatus: (message) => {
|
||||
setStatus(message);
|
||||
},
|
||||
/**
|
||||
* Handle successful vault sync and continue with vault unlock flow.
|
||||
*/
|
||||
onSuccess: async () => {
|
||||
// Continue with the rest of the flow after successful sync
|
||||
handleVaultUnlock();
|
||||
},
|
||||
/**
|
||||
* Handle offline state and prompt user for action.
|
||||
*/
|
||||
onOffline: async () => {
|
||||
Alert.alert(
|
||||
'Sync Issue',
|
||||
'The AliasVault server could not be reached and your vault could not be synced. Would you like to open your local vault in read-only mode or retry the connection?',
|
||||
[
|
||||
{
|
||||
text: 'Open Local Vault',
|
||||
/**
|
||||
* Handle opening vault in read-only mode.
|
||||
*/
|
||||
onPress: async () : Promise<void> => {
|
||||
setStatus('Opening vault in read-only mode');
|
||||
await handleVaultUnlock();
|
||||
}
|
||||
},
|
||||
{
|
||||
text: 'Retry Sync',
|
||||
/**
|
||||
* Handle retrying the connection.
|
||||
*/
|
||||
onPress: () : void => {
|
||||
setStatus('Retrying connection...');
|
||||
initialize();
|
||||
}
|
||||
}
|
||||
]
|
||||
);
|
||||
},
|
||||
/**
|
||||
* Handle error during vault sync.
|
||||
*/
|
||||
onError: async (error: string) => {
|
||||
// Show modal with error message
|
||||
Alert.alert('Error', error);
|
||||
/**
|
||||
* Initialize the app.
|
||||
*/
|
||||
const initialize = async () : Promise<void> => {
|
||||
const { isLoggedIn } = await initializeAuth();
|
||||
|
||||
// The logout user and navigate to the login screen.
|
||||
await webApi.logout(error);
|
||||
if (!isLoggedIn) {
|
||||
setRedirectTarget('/login');
|
||||
setBootComplete(true);
|
||||
},
|
||||
/**
|
||||
* On upgrade required.
|
||||
*/
|
||||
onUpgradeRequired: () : void => {
|
||||
setRedirectTarget('/upgrade');
|
||||
setBootComplete(true);
|
||||
},
|
||||
});
|
||||
};
|
||||
return;
|
||||
}
|
||||
|
||||
// First perform vault sync
|
||||
await syncVault({
|
||||
initialSync: true,
|
||||
/**
|
||||
* Handle the status update.
|
||||
*/
|
||||
onStatus: (message) => {
|
||||
setStatus(message);
|
||||
},
|
||||
/**
|
||||
* Handle successful vault sync and continue with vault unlock flow.
|
||||
*/
|
||||
onSuccess: async () => {
|
||||
// Continue with the rest of the flow after successful sync
|
||||
handleVaultUnlock();
|
||||
},
|
||||
/**
|
||||
* Handle offline state and prompt user for action.
|
||||
*/
|
||||
onOffline: async () => {
|
||||
Alert.alert(
|
||||
'Sync Issue',
|
||||
'The AliasVault server could not be reached and your vault could not be synced. Would you like to open your local vault in read-only mode or retry the connection?',
|
||||
[
|
||||
{
|
||||
text: 'Open Local Vault',
|
||||
/**
|
||||
* Handle opening vault in read-only mode.
|
||||
*/
|
||||
onPress: async () : Promise<void> => {
|
||||
setStatus('Opening vault in read-only mode');
|
||||
await handleVaultUnlock();
|
||||
}
|
||||
},
|
||||
{
|
||||
text: 'Retry Sync',
|
||||
/**
|
||||
* Handle retrying the connection.
|
||||
*/
|
||||
onPress: () : void => {
|
||||
setStatus('Retrying connection...');
|
||||
initialize();
|
||||
}
|
||||
}
|
||||
]
|
||||
);
|
||||
},
|
||||
/**
|
||||
* Handle error during vault sync.
|
||||
*/
|
||||
onError: async (error: string) => {
|
||||
// Show modal with error message
|
||||
Alert.alert('Error', error);
|
||||
|
||||
// The logout user and navigate to the login screen.
|
||||
await webApi.logout(error);
|
||||
setRedirectTarget('/login');
|
||||
setBootComplete(true);
|
||||
},
|
||||
/**
|
||||
* On upgrade required.
|
||||
*/
|
||||
onUpgradeRequired: () : void => {
|
||||
setRedirectTarget('/upgrade');
|
||||
setBootComplete(true);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
initialize();
|
||||
};
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { IdentityHelperUtils } from '@/utils/dist/shared/identity-generator';
|
||||
import type { Credential } from '@/utils/dist/shared/models/vault';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import FormInputCopyToClipboard from '@/components/form/FormInputCopyToClipboard';
|
||||
import { ThemedText } from '@/components/themed/ThemedText';
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { useFocusEffect } from '@react-navigation/native';
|
||||
import { router } from 'expo-router';
|
||||
import React, { useState, useEffect, useCallback } from 'react';
|
||||
import { View, StyleSheet, TouchableOpacity, Linking, AppState } from 'react-native';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { View, StyleSheet, TouchableOpacity, Linking, AppState } from 'react-native';
|
||||
|
||||
import { AppInfo } from '@/utils/AppInfo';
|
||||
import type { ApiErrorResponse, MailboxEmail } from '@/utils/dist/shared/models/webapi';
|
||||
@@ -210,7 +210,7 @@ export const EmailPreview: React.FC<EmailPreviewProps> = ({ email }) : React.Rea
|
||||
clearInterval(interval);
|
||||
}
|
||||
};
|
||||
}, [email, loading, webApi, dbContext, isPublicDomain, isPrivateDomain, authContext.isOffline, isComponentVisible]);
|
||||
}, [email, loading, webApi, dbContext, isPublicDomain, isPrivateDomain, authContext.isOffline, isComponentVisible, t]);
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
date: {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { Credential } from '@/utils/dist/shared/models/vault';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import type { Credential } from '@/utils/dist/shared/models/vault';
|
||||
|
||||
import FormInputCopyToClipboard from '@/components/form/FormInputCopyToClipboard';
|
||||
import { ThemedText } from '@/components/themed/ThemedText';
|
||||
import { ThemedView } from '@/components/themed/ThemedView';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { View, Text, StyleSheet, Linking, Pressable } from 'react-native';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { View, Text, StyleSheet, Linking, Pressable } from 'react-native';
|
||||
|
||||
import type { Credential } from '@/utils/dist/shared/models/vault';
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import * as Clipboard from 'expo-clipboard';
|
||||
import * as OTPAuth from 'otpauth';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { View, StyleSheet, TouchableOpacity, Platform } from 'react-native';
|
||||
import Toast from 'react-native-toast-message';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import type { Credential, TotpCode } from '@/utils/dist/shared/models/vault';
|
||||
|
||||
|
||||
@@ -19,10 +19,10 @@ const initI18n = async (): Promise<void> => {
|
||||
const deviceLanguage = locales[0]?.languageCode ?? 'en';
|
||||
const selectedLanguage = resources[deviceLanguage as keyof typeof resources] ? deviceLanguage : 'en';
|
||||
|
||||
// eslint-disable-next-line import/no-named-as-default-member
|
||||
await i18n
|
||||
.use(initReactI18next)
|
||||
.init({
|
||||
compatibilityJSON: 'v3',
|
||||
resources,
|
||||
lng: selectedLanguage,
|
||||
fallbackLng: 'en',
|
||||
|
||||
@@ -142,8 +142,9 @@
|
||||
},
|
||||
"language": "Language",
|
||||
"systemLanguage": "System Language",
|
||||
"languageSystemMessage": "To change the app language, we'll open iOS Settings where you can configure the preferred language for AliasVault.",
|
||||
"languageSystemMessage": "To change the app language, configure the preferred language for AliasVault in your device settings.",
|
||||
"openSettings": "Open Settings",
|
||||
"unableToOpenSettings": "Unable to open device settings. Please manually navigate to the app settings and change the language.",
|
||||
"vaultUnlockSettings": {
|
||||
"title": "Vault Unlock Method",
|
||||
"description": "Choose how you want to unlock your vault.",
|
||||
|
||||
@@ -122,8 +122,8 @@
|
||||
},
|
||||
"settings": {
|
||||
"title": "Instellingen",
|
||||
"iosAutofill": "iOS Automatisch Invullen",
|
||||
"androidAutofill": "Android Automatisch Invullen",
|
||||
"iosAutofill": "iOS autofill",
|
||||
"androidAutofill": "Android autofill",
|
||||
"vaultUnlock": "Kluis Ontgrendel Methode",
|
||||
"autoLock": "Automatisch Vergrendelen Timeout",
|
||||
"identityGenerator": "Identiteit Generator",
|
||||
@@ -142,8 +142,9 @@
|
||||
},
|
||||
"language": "Taal",
|
||||
"systemLanguage": "Systeemtaal",
|
||||
"languageSystemMessage": "Om de app-taal te wijzigen, openen we iOS Instellingen waar u de gewenste taal voor AliasVault kunt configureren.",
|
||||
"languageSystemMessage": "Wijzig de app-taal via het app instellingen scherm op je apparaat.",
|
||||
"openSettings": "Open Instellingen",
|
||||
"unableToOpenSettings": "Het openen van de instellingen is niet gelukt. Ga naar de app-instellingen en wijzig de taal.",
|
||||
"vaultUnlockSettings": {
|
||||
"title": "Kluis Ontgrendel Methode",
|
||||
"description": "Kies hoe u uw kluis wilt ontgrendelen.",
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
"loading_error_message" = "Het laden van referenties ging mis. Open de AliasVault app om te controleren op updates.";
|
||||
"ok" = "OK";
|
||||
"login_required" = "Inloggen Vereist";
|
||||
"login_required_message" = "Om Automatisch Invullen te gebruiken, log eerst in op uw AliasVault account in de AliasVault app.";
|
||||
"login_required_message" = "Om autofill te gebruiken, log eerst in op uw AliasVault account in de AliasVault app.";
|
||||
"biometric_required" = "%@ Vereist";
|
||||
"biometric_required_message" = "Om AliasVault Automatisch Invullen te gebruiken, schakel %@ in bij uw apparaat instellingen en/of ga naar de AliasVault app instellingen om het te configureren.";
|
||||
"biometric_app_required_message" = "Om Automatisch Invullen te gebruiken, schakel %@ in als uw kluis ontgrendel methode in de AliasVault app instellingen.";
|
||||
"biometric_required_message" = "Om autofill te gebruiken, schakel %@ in bij uw apparaat instellingen en/of ga naar de AliasVault app instellingen om het te configureren.";
|
||||
"biometric_app_required_message" = "Om autofill te gebruiken, schakel %@ in als uw kluis ontgrendel methode in de AliasVault app instellingen.";
|
||||
"loading_credentials" = "Referenties laden...";
|
||||
"no_credentials_found" = "Geen referenties gevonden";
|
||||
"no_credentials_match" = "Geen bestaande referenties komen overeen met uw zoekopdracht";
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"loading_error_message" = "Het laden van referenties ging mis. Open de AliasVault app om te controleren op updates.";
|
||||
"ok" = "OK";
|
||||
"login_required" = "Inloggen Vereist";
|
||||
"login_required_message" = "Om Automatisch Invullen te gebruiken, log eerst in op uw AliasVault account in de AliasVault app.";
|
||||
"login_required_message" = "Om autofill te gebruiken, log eerst in op uw AliasVault account in de AliasVault app.";
|
||||
"biometric_required" = "%@ Vereist";
|
||||
"biometric_required_message" = "Om AliasVault Automatisch Invullen te gebruiken, schakel %@ in bij uw apparaat instellingen en/of ga naar de AliasVault app instellingen om het te configureren.";
|
||||
"biometric_app_required_message" = "Om Automatisch Invullen te gebruiken, schakel %@ in als uw kluis ontgrendel methode in de AliasVault app instellingen.";
|
||||
|
||||
Reference in New Issue
Block a user