Merge branch 'main' into vishnukvmd-patch-1

This commit is contained in:
Neeraj Gupta 2023-04-03 11:53:09 +05:30 committed by GitHub
commit 2893eb45fa
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 618 additions and 102 deletions

35
.github/workflows/l18n-crowdin.yml vendored Normal file
View file

@ -0,0 +1,35 @@
name: Sync crowdin translation
on:
push:
paths: # run action automatically when app_en.arb file is changed
- 'lib/l10n/arb/app_en.arb'
branches: [ main ]
schedule:
- cron: '0 */12 * * *' # Every 12 hours - https://crontab.guru/#0_*/12_*_*_*
workflow_dispatch: # for manually running the action
jobs:
synchronize-with-crowdin:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: crowdin action
uses: crowdin/github-action@v1
with:
upload_sources: true
upload_translations: true
download_translations: true
localization_branch_name: l10n_translations
create_pull_request: true
skip_untranslated_strings: true
pull_request_title: 'New Translations'
pull_request_body: 'New translations via [Crowdin GH Action](https://github.com/crowdin/github-action)'
pull_request_base_branch_name: 'main'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }}
CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}

View file

@ -52,15 +52,20 @@ releases](https://github.com/ente-io/auth/releases/latest/download/ente-auth.apk
contains APKs, built straight from source. These builds keep themselves updated,
without relying on third party stores.
You can alternatively install the build from PlayStore.
You can alternatively install the build from PlayStore or F-Droid.
<a href="https://play.google.com/store/apps/details?id=io.ente.auth"> <img
width="197" alt="Get it on Google Play"
src="https://ente.io/static/ed265c3abdcd3efa5e29f64b927bcb44/e230a/play-store-badge.webp">
</a>
<a href="https://f-droid.org/packages/io.ente.auth/">
<img width="197" alt="Get it on F-Droid" src="https://ente.io/static/5378d3de690a04a5011268b9caf739f5/e230a/f-droid-badge.webp">
</a>
### iPhone / Apple Silicon
<a href="https://apps.apple.com/us/app/ente-authenticator/id6444121398"> <img
width="197" alt="Download on AppStore"
src="https://user-images.githubusercontent.com/1161789/154795157-c4468ff9-97fd-46f3-87fe-dca789d8733a.png">
@ -102,6 +107,10 @@ If you have feature requests, please create a [GitHub issue](https://github.com/
If you wish to support us, please ⭐
[star](https://github.com/ente-io/auth/stargazers) this project.
## 🙌 Translation
[![Crowdin](https://badges.crowdin.net/ente-authenticator-app/localized.svg)](https://crowdin.com/project/ente-authenticator-app)
If you're interested in helping out with translation, please visit our [Crowdin project](https://crowdin.com/project/ente-authenticator-app) to get started. Thank you for your support.
## 💜 Community

View file

@ -2,4 +2,5 @@
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
<monochrome android:drawable="@drawable/ic_launcher_foreground"/>
</adaptive-icon>

6
crowdin.yml Normal file
View file

@ -0,0 +1,6 @@
project_id_env: CROWDIN_PROJECT_ID
api_token_env: CROWDIN_PERSONAL_TOKEN
files:
- source: /lib/l10n/arb/app_en.arb
translation: /lib/l10n/arb/app_%two_letters_code%.arb

View file

@ -1,30 +1,30 @@
ente authenticator provides end-to-end encrypted cloud backups so that you don't have to worry about losing your tokens. We use the same protocols [ente
Photos](https://ente.io) uses to encrypt and preserve your data.
ente's Authenticator app helps you generate and store 2 step verification (2FA)
tokens on your mobile devices.
Multi Device Synchronization
FEATURES
- Secure Backups
ente provides end-to-end encrypted cloud backups so that you don't have to worry
about losing your tokens. We use the same protocols ente Photos uses to encrypt
and preserve your data.
- Multi Device Synchronization
ente will automatically sync the 2FA tokens you add to your account, across all
your devices. Every new device you sign into will have access to these tokens.
Mode
- Offline Mode
ente generates 2FA tokens offline, so your network connectivity will not get in
the way of your workflow.
Import and Export Tokens
- Import and Export Tokens
You can add tokens to ente by one of the following methods:
1. Scanning a QR code
2. Manually entering (copy-pasting) a 2FA secret
3. Bulk importing from a file that contains a list of codes in the following
format:
3. Bulk importing from a file that contains a list of codes in the following format:
```
otpauth://totp/ACCOUNT?secret=SUPERSECRET&issuer=SERVICE
```
The codes maybe separated by new lines or commas.
You can also export the codes you have added to ente, to an **unencrypted** text
@ -32,4 +32,6 @@ file, that adheres to the above format.
SUPPORT
We take pride in offering human support. If you are our paid customer, you can reach out to team@ente.io and expect a response from our team within 24 hours.
If you need help, please reach out to support@ente.io, and a human will get in touch with you.
If you have feature requests, please create an issue @ https://github.com/ente-io/auth

View file

@ -38,8 +38,7 @@ class Configuration {
static const tokenKey = "token";
static const encryptedTokenKey = "encrypted_token";
static const userIDKey = "user_id";
static const hasMigratedSecureStorageToFirstUnlockKey =
"has_migrated_secure_storage_to_first_unlock";
static const hasMigratedSecureStorageKey = "has_migrated_secure_storage";
final kTempFolderDeletionTimeBuffer = const Duration(days: 1).inMicroseconds;
@ -63,8 +62,9 @@ class Configuration {
late String _sharedDocumentsMediaDirectory;
String? _volatilePassword;
final _secureStorageOptionsIOS =
const IOSOptions(accessibility: KeychainAccessibility.first_unlock);
final _secureStorageOptionsIOS = const IOSOptions(
accessibility: KeychainAccessibility.first_unlock_this_device,
);
// const IOSOptions(accessibility: IOSAccessibility.first_unlock);
@ -462,7 +462,7 @@ class Configuration {
Future<void> _migrateSecurityStorageToFirstUnlock() async {
final hasMigratedSecureStorageToFirstUnlock =
_preferences.getBool(hasMigratedSecureStorageToFirstUnlockKey) ?? false;
_preferences.getBool(hasMigratedSecureStorageKey) ?? false;
if (!hasMigratedSecureStorageToFirstUnlock &&
_key != null &&
_secretKey != null) {
@ -477,7 +477,7 @@ class Configuration {
iOptions: _secureStorageOptionsIOS,
);
await _preferences.setBool(
hasMigratedSecureStorageToFirstUnlockKey,
hasMigratedSecureStorageKey,
true,
);
}

View file

@ -1,8 +1,8 @@
{
"@@locale": "de",
"@@locale": "en",
"counterAppBarTitle": "Zähler",
"@counterAppBarTitle": {
"description": "Text, der in der AppBar der Zähler-Seite angezeigt wird"
"description": "Text shown in the AppBar of the Counter Page"
},
"onBoardingBody": "Sichern Sie Ihre 2FA-Codes",
"onBoardingGetStarted": "Los geht's",
@ -11,7 +11,7 @@
"importEnterSetupKey": "Einen Setup-Schlüssel eingeben",
"importAccountPageTitle": "Kontodaten eingeben",
"codeIssuerHint": "Aussteller",
"codeSecretKeyHint" : "Geheimer Schlüssel",
"codeSecretKeyHint": "Geheimer Schlüssel",
"codeAccountHint": "Konto (you@domain.com)",
"accountKeyType": "Art des Schlüssels",
"timeBasedKeyType": "Zeitbasiert (TOTP)",
@ -56,21 +56,19 @@
"welcomeBackTitle": "Willkommen zurück!",
"madeWithLoveAtPrefix": "gemacht mit ❤️ bei ",
"changeEmail": "E-Mail ändern",
"ok": "OK",
"cancel": "Abbrechen",
"yes": "Ja",
"no": "Nein",
"email": "E-Mail",
"support": "Support",
"support": "Unterstützung",
"settings": "Einstellungen",
"copied": "Kopiert",
"tryAgainMessage": "Bitte versuchen Sie es erneut",
"existingUser": "Bestehender Benutzer",
"newUser" : "Neu bei ente",
"newUser": "Neu bei ente",
"delete": "Löschen",
"enterYourPasswordHint": "Geben Sie Ihr Passwort ein",
"forgotPassword": "Passwort vergessen",
"oops": "Oops",
"somethingWentWrongMessage": "Ein Fehler ist aufgetreten, bitte versuchen Sie es erneut",
"leaveFamily": "Familie verlassen",
"leaveFamilyMessage": "Sind Sie sicher, dass Sie den Familien-Plan verlassen wollen?",
@ -85,7 +83,7 @@
"recoverAccount": "Konto wiederherstellen",
"enterRecoveryKeyHint": "Geben Sie Ihren Wiederherstellungsschlüssel ein",
"recover": "Wiederherstellen",
"contactSupportViaEmailMessage":"Bitte senden Sie eine E-Mail an {email} von Ihrer registrierten E-Mail-Adresse",
"contactSupportViaEmailMessage": "Bitte senden Sie eine E-Mail an {email} von Ihrer registrierten E-Mail-Adresse",
"@contactSupportViaEmailMessage": {
"placeholders": {
"email": {
@ -112,5 +110,4 @@
"confirmPassword": "Bestätigen Sie das Passwort",
"close": "Schließen",
"oopsSomethingWentWrong": "Ups, da ist etwas schief gelaufen."
}

View file

@ -55,6 +55,8 @@
"incorrectPassword": "Incorrect password",
"welcomeBackTitle": "Welcome back!",
"madeWithLoveAtPrefix": "made with ❤️ at ",
"supportDevs" : "Subscribe to <bold-green>ente</bold-green> to support this project.",
"supportDiscount" : "Use coupon code \"AUTH\" to get 10% off first year",
"changeEmail": "change email",
"ok": "OK",
"cancel": "Cancel",

View file

@ -1,7 +1,7 @@
{
"@@locale": "es",
"counterAppBarTitle": "Contador",
"@counterAppBarTitle": {
"description": "Texto mostrado en la AppBar de la página del contador"
}
"@@locale": "en",
"counterAppBarTitle": "Contador",
"@counterAppBarTitle": {
"description": "Text shown in the AppBar of the Counter Page"
}
}

116
lib/l10n/arb/app_fr.arb Normal file
View file

@ -0,0 +1,116 @@
{
"@@locale": "en",
"counterAppBarTitle": "Compteur",
"@counterAppBarTitle": {
"description": "Text shown in the AppBar of the Counter Page"
},
"onBoardingBody": "Sécurisez vos codes 2FA",
"onBoardingGetStarted": "Premiers Pas",
"setupFirstAccount": "Configurez votre premier compte",
"importScanQrCode": "Scannez un QR Code",
"importEnterSetupKey": "Saisir une clé de configuration",
"importAccountPageTitle": "Saisir les détails du compte",
"codeIssuerHint": "Émetteur",
"codeSecretKeyHint": "Clé secrète",
"codeAccountHint": "Compte (vous@domaine.fr)",
"accountKeyType": "Type de clé",
"timeBasedKeyType": "Basé sur l'heure (TOTP)",
"counterBasedKeyType": "Basé sur le compteur (HOTP)",
"saveAction": "Sauvegarder",
"nextTotpTitle": "suivant",
"deleteCodeTitle": "Supprimer le code ?",
"deleteCodeMessage": "Êtes-vous sûr de vouloir supprimer ce code ? Cette action est irréversible.",
"viewLogsAction": "Afficher les journaux",
"sendLogsDescription": "Cela enverra des logs pour nous aider à déboguer votre problème. Bien que nous prenions des précautions pour nous assurer que les informations sensibles ne sont pas enregistrées, nous vous encourageons à consulter ces journaux avant de les partager.",
"preparingLogsTitle": "Préparation des journaux...",
"emailLogsTitle": "Journaux d'email",
"emailLogsMessage": "Envoyez les logs à {email}",
"@emailLogsMessage": {
"placeholders": {
"email": {
"type": "String"
}
}
},
"copyEmailAction": "Copier le-mail",
"exportLogsAction": "Exporter les journaux",
"reportABug": "Signaler un bug",
"crashAndErrorReporting": "Rapport de plantage et d'erreur",
"reportBug": "Signaler un bug",
"emailUsMessage": "Veuillez nous envoyer un e-mail à {email}",
"@emailUsMessage": {
"placeholders": {
"email": {
"type": "String"
}
}
},
"contactSupport": "Contacter le support",
"verifyPassword": "Vérifier le mot de passe",
"pleaseWaitTitle": "Veuillez patienter...",
"generatingEncryptionKeysTitle": "Génération des clés de chiffrement...",
"recreatePassword": "Recréer le mot de passe",
"recreatePasswordMessage": "L'appareil actuel n'est pas assez puissant pour vérifier votre mot de passe, donc nous avons besoin de le régénérer une fois d'une manière qu'il fonctionne avec tous les périphériques.\n\nVeuillez vous connecter en utilisant votre clé de récupération et régénérer votre mot de passe (vous pouvez utiliser le même si vous le souhaitez).",
"useRecoveryKeyAction": "Utiliser la clé de récupération",
"incorrectPassword": "Mot de passe incorrect",
"welcomeBackTitle": "Bon retour parmi nous !",
"madeWithLoveAtPrefix": "fait avec ❤️ à ",
"supportDiscount": "Utilisez le code coupon \"AUTH\" pour obtenir 10% de réduction sur la première année",
"changeEmail": "modifier l'e-mail",
"ok": "Ok",
"cancel": "Annuler",
"yes": "Oui",
"no": "Non",
"email": "E-mail",
"support": "Support",
"settings": "Paramètres",
"copied": "Copié",
"tryAgainMessage": "Veuillez réessayer",
"existingUser": "Utilisateur existant",
"newUser": "Nouveau sur ente",
"delete": "Supprimer",
"enterYourPasswordHint": "Saisir votre mot de passe",
"forgotPassword": "Mot de passe oublié",
"oops": "Oups",
"somethingWentWrongMessage": "Quelque chose s'est mal passé, veuillez recommencer",
"leaveFamily": "Quitter le plan familial",
"leaveFamilyMessage": "Êtes-vous certains de vouloir quitter le plan familial?",
"inFamilyPlanMessage": "Vous êtes sur un plan familial !",
"swipeHint": "Glisser vers la gauche pour modifier ou supprimer des codes",
"scan": "Analyser",
"scanACode": "Scanner un code",
"verify": "Vérifier",
"enterCodeHint": "Saisir le code à 6 caractères de votre appli d'authentification",
"lostDeviceTitle": "Appareil perdu ?",
"twoFactorAuthTitle": "Authentification à deux facteurs",
"recoverAccount": "Récupérer un compte",
"enterRecoveryKeyHint": "Saisissez votre clé de récupération",
"recover": "Restaurer",
"contactSupportViaEmailMessage": "Veuillez envoyer un e-mail à {} depuis votre adresse enregistrée",
"@contactSupportViaEmailMessage": {
"placeholders": {
"email": {
"type": "String"
}
}
},
"noRecoveryKeyTitle": "Pas de clé de récupération ?",
"enterEmailHint": "Entrez votre adresse e-mail",
"invalidEmailTitle": "Adresse e-mail non valide",
"invalidEmailMessage": "Veuillez saisir une adresse e-mail valide.",
"deleteAccount": "Supprimer le compte",
"deleteAccountQuery": "Nous sommes désolés de vous voir partir. Êtes-vous confronté à un problème?",
"yesSendFeedbackAction": "Oui, envoyer un commentaire",
"noDeleteAccountAction": "Non, supprimer le compte",
"initiateAccountDeleteTitle": "Veuillez vous authentifier pour débuter la suppression du compte",
"confirmAccountDeleteTitle": "Êtes-vous sûr de vouloir supprimer votre compte ente ?",
"confirmAccountDeleteMessage": "Vos données téléchargées, à travers toutes les applications (Photos et Authenticator), seront planifiées pour la suppression, et votre compte sera définitivement supprimé.",
"sendEmail": "Envoyer un e-mail",
"createNewAccount": "Créer un nouveau compte",
"passwordStrengthWeak": "Faible",
"passwordStrengthStrong": "Fort",
"passwordStrengthModerate": "Modéré",
"confirmPassword": "Confirmer le mot de passe",
"close": "Fermer",
"oopsSomethingWentWrong": "Oops ! Une erreur s'est produite."
}

117
lib/l10n/arb/app_it.arb Normal file
View file

@ -0,0 +1,117 @@
{
"@@locale": "en",
"counterAppBarTitle": "Contatore",
"@counterAppBarTitle": {
"description": "Text shown in the AppBar of the Counter Page"
},
"onBoardingBody": "Proteggi i tuoi codici 2FA",
"onBoardingGetStarted": "Per iniziare",
"setupFirstAccount": "Configura il tuo primo account",
"importScanQrCode": "Scansiona un codice QR",
"importEnterSetupKey": "Inserisci il codice segreto",
"importAccountPageTitle": "Inserisci i dettagli del tuo account",
"codeIssuerHint": "Emittente",
"codeSecretKeyHint": "Codice segreto",
"codeAccountHint": "Account (username@dominio.it)",
"accountKeyType": "Tipo di chiave",
"timeBasedKeyType": "Basata sul tempo (TOTP)",
"counterBasedKeyType": "Basata su contatore (HOTP)",
"saveAction": "Salva",
"nextTotpTitle": "successivo",
"deleteCodeTitle": "Eliminare il codice?",
"deleteCodeMessage": "Sei sicuro di voler rimuovere questo codice? L'azione è irreversibile.",
"viewLogsAction": "Visualizza i log",
"sendLogsDescription": "Invierai i tuoi log per aiutarci a risolvere il tuo problema. Prendiamo precauzioni per garantire che le informazioni sensibili non siano registrate, tuttavia ti invitiamo a leggerli prima di condividerli con noi.",
"preparingLogsTitle": "Preparando i log...",
"emailLogsTitle": "Invia i log per email",
"emailLogsMessage": "Invia i log all'indirizzo {email}",
"@emailLogsMessage": {
"placeholders": {
"email": {
"type": "String"
}
}
},
"copyEmailAction": "Copia email",
"exportLogsAction": "Esporta log",
"reportABug": "Segnala un problema",
"crashAndErrorReporting": "Segnalazione degli errori e dei crash",
"reportBug": "Segnala un bug",
"emailUsMessage": "Per favore inviaci un'email a {email}",
"@emailUsMessage": {
"placeholders": {
"email": {
"type": "String"
}
}
},
"contactSupport": "Contatta il supporto",
"verifyPassword": "Verifica la password",
"pleaseWaitTitle": "Attendere prego...",
"generatingEncryptionKeysTitle": "Generazione delle chiavi di crittografia...",
"recreatePassword": "Crea una nuova password",
"recreatePasswordMessage": "Il tuo dispositivo non è abbastanza potente per verificare la tua password, quindi abbiamo bisogno di rigenerarla in un modo che funziona con tutti i dispositivi. \n\nEffettua il login utilizzando la tua chiave di recupero e rigenera la tua password (puoi utilizzare nuovamente la stessa se vuoi).",
"useRecoveryKeyAction": "Utilizza un codice di recupero",
"incorrectPassword": "Password sbagliata",
"welcomeBackTitle": "Bentornato!",
"madeWithLoveAtPrefix": "realizzato con ❤️ a ",
"supportDevs": "Iscriviti a <bold-green>ente</bold-green> per supportare questo progetto.",
"supportDiscount": "Utilizzare il codice coupon \"AUTH\" per ottenere il 10% di sconto al primo anno",
"changeEmail": "modifica email",
"ok": "OK",
"cancel": "Annulla",
"yes": "Si",
"no": "No",
"email": "Email",
"support": "Supporto",
"settings": "Impostazioni",
"copied": "Copiato",
"tryAgainMessage": "Per favore riprova",
"existingUser": "Accedi",
"newUser": "Nuovo utente",
"delete": "Cancella",
"enterYourPasswordHint": "Inserisci la tua password",
"forgotPassword": "Password dimenticata",
"oops": "Oops",
"somethingWentWrongMessage": "Qualcosa è andato storto, per favore riprova",
"leaveFamily": "Abbandona il piano famiglia",
"leaveFamilyMessage": "Sei sicuro di voler uscire dal piano famiglia?",
"inFamilyPlanMessage": "Sei un utente con piano famiglia!",
"swipeHint": "Scorri a sinistra per modificare o rimuovere i codici",
"scan": "Scansiona",
"scanACode": "Scansiona un codice",
"verify": "Verifica",
"enterCodeHint": "Inserisci il codice di 6 cifre dalla tua app di autenticazione",
"lostDeviceTitle": "Dispositivo perso?",
"twoFactorAuthTitle": "Autenticazione a due fattori",
"recoverAccount": "Recupera account",
"enterRecoveryKeyHint": "Inserisci la tua chiave di recupero",
"recover": "Recupera",
"contactSupportViaEmailMessage": "Per favore invia un'email a {email} dal tuo indirizzo email registrato",
"@contactSupportViaEmailMessage": {
"placeholders": {
"email": {
"type": "String"
}
}
},
"noRecoveryKeyTitle": "Nessuna chiave di recupero?",
"enterEmailHint": "Inserisci il tuo indirizzo email",
"invalidEmailTitle": "Indirizzo email non valido",
"invalidEmailMessage": "Inserisci un indirizzo email valido.",
"deleteAccount": "Elimina account",
"deleteAccountQuery": "Ci dispiace vederti andare via. Stai avendo qualche problema?",
"yesSendFeedbackAction": "Sì, invia un feedback",
"noDeleteAccountAction": "No, elimina l'account",
"initiateAccountDeleteTitle": "Si prega di autenticarsi per avviare l'eliminazione dell'account",
"confirmAccountDeleteTitle": "Sei sicuro di voler eliminare il tuo account?",
"confirmAccountDeleteMessage": "I tuoi dati caricati, in tutte le app (sia foto che autenticatore), verranno pianificati per la cancellazione, e il tuo account sarà eliminato in modo permanente.",
"sendEmail": "Invia email",
"createNewAccount": "Crea un nuovo account",
"passwordStrengthWeak": "Debole",
"passwordStrengthStrong": "Forte",
"passwordStrengthModerate": "Mediocre",
"confirmPassword": "Conferma la password",
"close": "Chiudi",
"oopsSomethingWentWrong": "Oops, qualcosa è andato storto."
}

116
lib/l10n/arb/app_nl.arb Normal file
View file

@ -0,0 +1,116 @@
{
"@@locale": "en",
"counterAppBarTitle": "Teller",
"@counterAppBarTitle": {
"description": "Text shown in the AppBar of the Counter Page"
},
"onBoardingBody": "Beveilig je 2FA codes",
"onBoardingGetStarted": "Begin",
"setupFirstAccount": "Maak je account aan",
"importScanQrCode": "Scan een QR-code",
"importEnterSetupKey": "Voer een toegangssleutel in",
"importAccountPageTitle": "Accountgegevens invoeren",
"codeIssuerHint": "Uitgever",
"codeSecretKeyHint": "Geheime code",
"codeAccountHint": "Account (jij@domein.nl)",
"accountKeyType": "Type sleutel",
"timeBasedKeyType": "Tijd gebaseerd (TOTP)",
"counterBasedKeyType": "Teller gebaseerd (HOTP)",
"saveAction": "Opslaan",
"nextTotpTitle": "volgende",
"deleteCodeTitle": "Code verwijderen?",
"deleteCodeMessage": "Weet je zeker dat je deze code wilt verwijderen? Deze actie is onomkeerbaar.",
"viewLogsAction": "Bekijk logs",
"sendLogsDescription": "Dit zal logs verzenden om ons te helpen uw probleem op te lossen. Hoewel we voorzorgsmaatregelen nemen om ervoor te zorgen dat gevoelige informatie niet wordt gedeeld, raden we je aan deze logs te bekijken voordat je ze deelt.",
"preparingLogsTitle": "Klaarmaken...",
"emailLogsTitle": "E-mail logs",
"emailLogsMessage": "Verstuur de logs alsjeblieft naar {email}",
"@emailLogsMessage": {
"placeholders": {
"email": {
"type": "String"
}
}
},
"copyEmailAction": "E-mail kopiëren",
"exportLogsAction": "Logs exporteren",
"reportABug": "Een fout melden",
"crashAndErrorReporting": "Crash- en foutrapportage",
"reportBug": "Een fout melden",
"emailUsMessage": "Stuur ons een e-mail op {email}",
"@emailUsMessage": {
"placeholders": {
"email": {
"type": "String"
}
}
},
"contactSupport": "Klantenservice",
"verifyPassword": "Bevestig wachtwoord",
"pleaseWaitTitle": "Een ogenblik geduld...",
"generatingEncryptionKeysTitle": "Encryptiesleutels genereren...",
"recreatePassword": "Wachtwoord opnieuw instellen",
"recreatePasswordMessage": "Het huidige apparaat is niet krachtig genoeg om je wachtwoord te verifiëren, dus moeten we de code een keer opnieuw genereren op een manier die met alle apparaten werkt.\n\nLog in met behulp van uw herstelcode en genereer opnieuw uw wachtwoord (je kunt dezelfde indien gewenst opnieuw gebruiken).",
"useRecoveryKeyAction": "Herstelcode gebruiken",
"incorrectPassword": "Onjuist wachtwoord",
"welcomeBackTitle": "Welkom terug!",
"madeWithLoveAtPrefix": "gemaakt met ❤️ door ",
"supportDiscount": "Gebruik couponcode \"AUTH\" om 10% korting te krijgen op het eerste jaar",
"changeEmail": "e-mailadres wijzigen",
"ok": "Oké",
"cancel": "Annuleer",
"yes": "Ja",
"no": "Nee",
"email": "E-mail",
"support": "Ondersteuning",
"settings": "Instellingen",
"copied": "Gekopieerd",
"tryAgainMessage": "Probeer het nog eens",
"existingUser": "Bestaande gebruiker",
"newUser": "Nieuw bij ente",
"delete": "Verwijderen",
"enterYourPasswordHint": "Voer je wachtwoord in",
"forgotPassword": "Wachtwoord vergeten",
"oops": "Oeps",
"somethingWentWrongMessage": "Er is iets fout gegaan, probeer het opnieuw",
"leaveFamily": "Familie verlaten",
"leaveFamilyMessage": "Weet je zeker dat je het familie-plan wil verlaten?",
"inFamilyPlanMessage": "Je hebt een familie-plan!",
"swipeHint": "Veeg naar links om codes te bewerken of te verwijderen",
"scan": "Scannen",
"scanACode": "Scan een code",
"verify": "Verifiëren",
"enterCodeHint": "Voer de 6-cijferige code van je verificatie-app in",
"lostDeviceTitle": "Apparaat verloren?",
"twoFactorAuthTitle": "Tweestapsverificatie",
"recoverAccount": "Account herstellen",
"enterRecoveryKeyHint": "Voer je herstelcode in",
"recover": "Herstellen",
"contactSupportViaEmailMessage": "Verstuur a.u.b. een e-mail naar {email} van uw geregistreerde e-mailadres",
"@contactSupportViaEmailMessage": {
"placeholders": {
"email": {
"type": "String"
}
}
},
"noRecoveryKeyTitle": "Geen herstelcode?",
"enterEmailHint": "Voer je e-mailadres in",
"invalidEmailTitle": "Ongeldig e-mailadres",
"invalidEmailMessage": "Voer een geldig e-mailadres in.",
"deleteAccount": "Account verwijderen",
"deleteAccountQuery": "We zullen het vervelend vinden om je te zien vertrekken. Zijn er problemen?",
"yesSendFeedbackAction": "Ja, geef feedback",
"noDeleteAccountAction": "Nee, verwijder account",
"initiateAccountDeleteTitle": "Gelieve te verifiëren om het account te verwijderen",
"confirmAccountDeleteTitle": "Weet je zeker dat je je ente account wil verwijderen?",
"confirmAccountDeleteMessage": "Uw geüploade gegevens, in alle apps (Photos en Authenticator), worden ingepland voor verwijdering en uw account zal permanent worden verwijderd.",
"sendEmail": "E-mail versturen",
"createNewAccount": "Nieuw account aanmaken",
"passwordStrengthWeak": "Zwak",
"passwordStrengthStrong": "Sterk",
"passwordStrengthModerate": "Matig",
"confirmPassword": "Wachtwoord bevestigen",
"close": "Sluiten",
"oopsSomethingWentWrong": "Oeps, er is iets fout gegaan."
}

3
lib/l10n/arb/app_pt.arb Normal file
View file

@ -0,0 +1,3 @@
{
"@@locale": "en"
}

3
lib/l10n/arb/app_zh.arb Normal file
View file

@ -0,0 +1,3 @@
{
"@@locale": "en"
}

View file

@ -46,7 +46,7 @@ class Code {
account +
"?algorithm=SHA1&digits=6&issuer=" +
issuer +
"period=30&secret=" +
"&period=30&secret=" +
secret,
);
}
@ -76,6 +76,9 @@ class Code {
static String _getIssuer(Uri uri) {
try {
if (uri.queryParameters.containsKey("issuer")) {
return uri.queryParameters['issuer']!;
}
final String path = Uri.decodeComponent(uri.path);
return path.split(':')[0].substring(1);
} catch (e) {

View file

@ -32,10 +32,11 @@ class BillingService {
bool _isOnSubscriptionPage = false;
Subscription _cachedSubscription;
Future<BillingPlans> _future;
Future<void> init() async {
}
Future<void> init() async {}
void clearCache() {
_future = null;
@ -99,22 +100,25 @@ class BillingService {
}
}
Future<Subscription> fetchSubscription() async {
try {
final response = await _dio.get(
_config.getHttpEndpoint() + "/billing/subscription",
options: Options(
headers: {
"X-Auth-Token": _config.getToken(),
},
),
);
final subscription = Subscription.fromMap(response.data["subscription"]);
return subscription;
} on DioError catch (e, s) {
_logger.severe(e, s);
rethrow;
Future<Subscription> getSubscription() async {
if (_cachedSubscription == null) {
try {
final response = await _dio.get(
_config.getHttpEndpoint() + "/billing/subscription",
options: Options(
headers: {
"X-Auth-Token": _config.getToken(),
},
),
);
_cachedSubscription =
Subscription.fromMap(response.data["subscription"]);
} on DioError catch (e, s) {
_logger.severe(e, s);
rethrow;
}
}
return _cachedSubscription;
}
Future<Subscription> cancelStripeSubscription() async {

View file

@ -28,6 +28,7 @@ class EnteColorScheme {
final Color strokeFaint;
// Fixed Colors
final Color primaryGreen;
final Color primary700;
final Color primary500;
final Color primary400;
@ -53,6 +54,7 @@ class EnteColorScheme {
this.strokeBase,
this.strokeMuted,
this.strokeFaint, {
this.primaryGreen = _primaryGreen,
this.primary700 = _primary700,
this.primary500 = _primary500,
this.primary400 = _primary400,
@ -143,6 +145,8 @@ const Color strokeFaintDark = Color.fromRGBO(255, 255, 255, 0.16);
// Fixed Colors
const Color _primaryGreen = Color.fromRGBO(29, 185, 84, 1);
const Color _primary700 = Color.fromARGB(255, 164, 0, 182);
const Color _primary500 = Color.fromARGB(255, 204, 10, 101);
const Color _primary400 = Color.fromARGB(255, 122, 41, 193);

View file

@ -1,7 +1,6 @@
import 'dart:async';
import 'package:ente_auth/ui/linear_progress_widget.dart';
import 'package:flutter/material.dart';
import 'package:flutter_animation_progress_bar/flutter_animation_progress_bar.dart';
import 'package:flutter/scheduler.dart';
class CodeTimerProgress extends StatefulWidget {
final int period;
@ -15,46 +14,42 @@ class CodeTimerProgress extends StatefulWidget {
_CodeTimerProgressState createState() => _CodeTimerProgressState();
}
class _CodeTimerProgressState extends State<CodeTimerProgress> {
Timer? _everySecondTimer;
late int _timeRemaining;
class _CodeTimerProgressState extends State<CodeTimerProgress>
with SingleTickerProviderStateMixin {
late final Ticker _ticker;
double _progress = 0.0;
late final int _microSecondsInPeriod;
@override
void initState() {
super.initState();
_timeRemaining = widget.period;
_updateTimeRemaining();
_everySecondTimer =
Timer.periodic(const Duration(milliseconds: 200), (Timer t) {
_microSecondsInPeriod = widget.period * 1000000;
_ticker = createTicker((elapsed) {
_updateTimeRemaining();
});
_ticker.start();
_updateTimeRemaining();
}
void _updateTimeRemaining() {
int newTimeRemaining =
widget.period - (DateTime.now().second % widget.period);
if (newTimeRemaining != _timeRemaining) {
setState(() {
_timeRemaining = newTimeRemaining;
});
}
int timeRemaining = (_microSecondsInPeriod) -
(DateTime.now().microsecondsSinceEpoch % _microSecondsInPeriod);
setState(() {
_progress = (timeRemaining / _microSecondsInPeriod);
});
}
@override
void dispose() {
_everySecondTimer?.cancel();
_ticker.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return FAProgressBar(
currentValue: _timeRemaining / widget.period * 100,
size: 4,
animatedDuration: const Duration(milliseconds: 200),
progressColor: Colors.orange,
changeColorValue: 40,
changeProgressColor: Colors.green,
return LinearProgressWidget(
color: _progress > 0.4 ? Colors.green : Colors.orange,
fractionOfStorage: _progress,
);
}
}

View file

@ -0,0 +1,27 @@
import 'package:flutter/material.dart';
class LinearProgressWidget extends StatelessWidget {
final Color color;
final double fractionOfStorage;
const LinearProgressWidget({
required this.color,
required this.fractionOfStorage,
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constrains) {
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(4),
color: color,
),
width: constrains.maxWidth * fractionOfStorage,
height: 4,
);
},
);
}
}

View file

@ -0,0 +1,68 @@
import 'dart:io';
import 'package:ente_auth/l10n/l10n.dart';
import 'package:ente_auth/models/subscription.dart';
// ignore: import_of_legacy_library_into_null_safe
import 'package:ente_auth/services/billing_service.dart';
import 'package:ente_auth/theme/ente_theme.dart';
import 'package:flutter/material.dart';
import 'package:styled_text/styled_text.dart';
import 'package:url_launcher/url_launcher.dart';
class SupportDevWidget extends StatelessWidget {
const SupportDevWidget({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
final l10n = context.l10n;
// fetch
return FutureBuilder<Subscription>(
future: BillingService.instance.getSubscription(),
builder: (context, snapshot) {
if (snapshot.hasData) {
final subscription = snapshot.data;
if (subscription != null && subscription.productID != "free") {
return GestureDetector(
onTap: () {
launchUrl(Uri.parse("https://ente.io"));
},
child: Padding(
padding:
const EdgeInsets.symmetric(vertical: 12.0, horizontal: 6),
child: Column(
children: [
StyledText(
text: l10n.supportDevs,
tags: {
'bold-green': StyledTextTag(
style: TextStyle(
fontWeight: FontWeight.bold,
color: getEnteColorScheme(context).primaryGreen,
),
),
},
),
const Padding(padding: EdgeInsets.all(6)),
Platform.isAndroid
? Text(
l10n.supportDiscount,
textAlign: TextAlign.center,
style: const TextStyle(
color: Colors.grey,
),
)
: const SizedBox.shrink(),
],
),
),
);
}
}
return const SizedBox.shrink();
},
);
}
}

View file

@ -9,9 +9,9 @@ import 'package:ente_auth/ui/settings/account_section_widget.dart';
import 'package:ente_auth/ui/settings/app_version_widget.dart';
import 'package:ente_auth/ui/settings/danger_section_widget.dart';
import 'package:ente_auth/ui/settings/data_section_widget.dart';
import 'package:ente_auth/ui/settings/made_with_love_widget.dart';
import 'package:ente_auth/ui/settings/security_section_widget.dart';
import 'package:ente_auth/ui/settings/social_section_widget.dart';
import 'package:ente_auth/ui/settings/support_dev_widget.dart';
import 'package:ente_auth/ui/settings/support_section_widget.dart';
import 'package:ente_auth/ui/settings/theme_switch_widget.dart';
import 'package:ente_auth/ui/settings/title_bar_widget.dart';
@ -84,7 +84,7 @@ class SettingsPage extends StatelessWidget {
sectionSpacing,
const DangerSectionWidget(),
const AppVersionWidget(),
const MadeWithLoveWidget(),
const SupportDevWidget(),
const Padding(
padding: EdgeInsets.only(bottom: 60),
),

View file

@ -21,7 +21,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
ConnectivityPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlugin"))
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin"))
FlutterSecureStorageMacosPlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStorageMacosPlugin"))
FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin"))
FLTPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlusPlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
SentryFlutterPlugin.register(with: registry.registrar(forPlugin: "SentryFlutterPlugin"))

View file

@ -438,14 +438,6 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
flutter_animation_progress_bar:
dependency: "direct main"
description:
name: flutter_animation_progress_bar
sha256: "85f05404faeef7141b1c5b53571293fc19359c120c4aea4430b2b7d808461d09"
url: "https://pub.dev"
source: hosted
version: "2.3.1"
flutter_bloc:
dependency: "direct main"
description:
@ -527,26 +519,26 @@ packages:
dependency: "direct main"
description:
name: flutter_secure_storage
sha256: de957362e046bc68da8dcf6c1d922cb8bdad8dd4979ec69480cf1a3c481abe8e
sha256: "98352186ee7ad3639ccc77ad7924b773ff6883076ab952437d20f18a61f0a7c5"
url: "https://pub.dev"
source: hosted
version: "6.1.0"
version: "8.0.0"
flutter_secure_storage_linux:
dependency: transitive
description:
name: flutter_secure_storage_linux
sha256: "736436adaf91552433823f51ce22e098c2f0551db06b6596f58597a25b8ea797"
sha256: "0912ae29a572230ad52d8a4697e5518d7f0f429052fd51df7e5a7952c7efe2a3"
url: "https://pub.dev"
source: hosted
version: "1.1.2"
version: "1.1.3"
flutter_secure_storage_macos:
dependency: transitive
description:
name: flutter_secure_storage_macos
sha256: "388f76fd0f093e7415a39ec4c169ae7cceeee6d9f9ba529d788a13f2be4de7bd"
sha256: "083add01847fc1c80a07a08e1ed6927e9acd9618a35e330239d4422cd2a58c50"
url: "https://pub.dev"
source: hosted
version: "1.1.2"
version: "3.0.0"
flutter_secure_storage_platform_interface:
dependency: transitive
description:
@ -567,10 +559,10 @@ packages:
dependency: transitive
description:
name: flutter_secure_storage_windows
sha256: ca89c8059cf439985aa83c59619b3674c7ef6cc2e86943d169a7369d6a69cab5
sha256: fc2910ec9b28d60598216c29ea763b3a96c401f0ce1d13cdf69ccb0e5c93c3ee
url: "https://pub.dev"
source: hosted
version: "1.1.3"
version: "2.0.0"
flutter_slidable:
dependency: "direct main"
description:
@ -1315,6 +1307,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.2.0"
styled_text:
dependency: "direct main"
description:
name: styled_text
sha256: f72928d1ebe8cb149e3b34a689cb1ddca696b808187cf40ac3a0bd183dff379c
url: "https://pub.dev"
source: hosted
version: "7.0.0"
synchronized:
dependency: transitive
description:
@ -1523,6 +1523,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "6.1.0"
xmlstream:
dependency: transitive
description:
name: xmlstream
sha256: "2d10c69a9d5fc46f71798b80ee6db15bc0d5bf560fdbdd264776cbeee0c83631"
url: "https://pub.dev"
source: hosted
version: "1.0.0"
yaml:
dependency: transitive
description:
@ -1533,4 +1541,4 @@ packages:
version: "3.1.1"
sdks:
dart: ">=2.18.0 <3.0.0"
flutter: ">=3.3.0"
flutter: ">=3.7.0"

View file

@ -1,6 +1,6 @@
name: ente_auth
description: ente two-factor authenticator
version: 1.0.32+32
version: 1.0.36+36
publish_to: none
environment:
@ -27,7 +27,6 @@ dependencies:
fk_user_agent: ^2.1.0
flutter:
sdk: flutter
flutter_animation_progress_bar: ^2.2.1
flutter_bloc: ^8.0.1
flutter_email_sender: ^5.1.0
flutter_inappwebview: ^5.7.1
@ -36,7 +35,7 @@ dependencies:
flutter_localizations:
sdk: flutter
flutter_native_splash: ^2.2.13
flutter_secure_storage: ^6.0.0
flutter_secure_storage: ^8.0.0
flutter_slidable: ^2.0.0
flutter_sodium:
git:
@ -63,6 +62,7 @@ dependencies:
shared_preferences: ^2.0.5
sqflite: ^2.1.0
step_progress_indicator: ^1.0.2
styled_text: ^7.0.0
url_launcher: ^6.1.5
uuid: ^3.0.4