diff --git a/.github/workflows/test-integration.yaml b/.github/workflows/test-integration.yaml index f8dd73a3b..80161dd5d 100644 --- a/.github/workflows/test-integration.yaml +++ b/.github/workflows/test-integration.yaml @@ -10,41 +10,40 @@ jobs: timeout-minutes: 60 strategy: matrix: - api-level: [21, 30, 34] # [minSdk, most used, newest] + api-level: [26] # [ most used ] steps: - name: Delete unnecessary tools 🔧 uses: jlumbroso/free-disk-space@v1.3.1 with: android: false # Don't remove Android tools - tool-cache: true # Remove image tool cache - rm -rf "$AGENT_TOOLSDIRECTORY" + tool-cache: false # Don't remove image tool cache - rm -rf "$AGENT_TOOLSDIRECTORY" dotnet: true # rm -rf /usr/share/dotnet haskell: true # rm -rf /opt/ghc... swap-storage: true # rm -f /mnt/swapfile (4GiB) docker-images: false # Takes 16s, enable if needed in the future large-packages: false # includes google-cloud-sdk and it's slow - + - name: Checkout uses: actions/checkout@v4 - name: Set up JDK 17 uses: actions/setup-java@v4 - with: distribution: 'zulu' java-version: 17 - - uses: subosito/flutter-action@v2 + - name: Setup Flutter + uses: subosito/flutter-action@v2 with: flutter-version: '3.22.0' channel: 'stable' - + - run: flutter pub get + # Run integration test - name: Run Integration Tests uses: reactivecircus/android-emulator-runner@v2 with: api-level: ${{ matrix.api-level }} arch: x86_64 - disable-animations: true - disk-size: 6000M - heap-size: 600M - script: flutter test integration_test --flavor netknights \ No newline at end of file + profile: Nexus 6 + script: flutter test integration_test --flavor netknights diff --git a/lib/l10n/app_cs.arb b/lib/l10n/app_cs.arb index b71fbdef6..b50d07b0d 100644 --- a/lib/l10n/app_cs.arb +++ b/lib/l10n/app_cs.arb @@ -645,5 +645,9 @@ "example": "Name" } } + }, + "sendPushRequestResponseFailed": "Odpověď se nepodařilo odeslat.", + "@sendPushRequestResponseFailed": { + "description": "Error message when the response to a push request could not be sent." } } \ No newline at end of file diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index 6f404f101..b61ccf68e 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -624,5 +624,9 @@ "example": "Name" } } + }, + "sendPushRequestResponseFailed": "Senden der Antwort fehlgeschlagen.", + "@sendPushRequestResponseFailed": { + "description": "Error message when the response to a push request could not be sent." } } \ No newline at end of file diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 496611261..42b307dc0 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -667,5 +667,9 @@ "example": "Name" } } + }, + "sendPushRequestResponseFailed": "Failed to send the response.", + "@sendPushRequestResponseFailed": { + "description": "Error message when the response to a push request could not be sent." } } \ No newline at end of file diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index 1718c4cd8..4fce9bbed 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -641,5 +641,9 @@ "example": "Name" } } + }, + "sendPushRequestResponseFailed": "No se ha podido enviar la respuesta.", + "@sendPushRequestResponseFailed": { + "description": "Error message when the response to a push request could not be sent." } } \ No newline at end of file diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index 3f323383f..72592f1af 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -646,5 +646,9 @@ "example": "Name" } } + }, + "sendPushRequestResponseFailed": "Échec de l'envoi de la réponse.", + "@sendPushRequestResponseFailed": { + "description": "Error message when the response to a push request could not be sent." } } \ No newline at end of file diff --git a/lib/l10n/app_localizations.dart b/lib/l10n/app_localizations.dart index 3cfe1d41d..5299ec91d 100644 --- a/lib/l10n/app_localizations.dart +++ b/lib/l10n/app_localizations.dart @@ -93,15 +93,7 @@ abstract class AppLocalizations { ]; /// A list of this localizations delegate's supported locales. - static const List supportedLocales = [ - Locale('cs'), - Locale('de'), - Locale('en'), - Locale('es'), - Locale('fr'), - Locale('nl'), - Locale('pl') - ]; + static const List supportedLocales = [Locale('cs'), Locale('de'), Locale('en'), Locale('es'), Locale('fr'), Locale('nl'), Locale('pl')]; /// No description provided for @patchNotesNewFeatures. /// @@ -1704,23 +1696,26 @@ class _AppLocalizationsDelegate extends LocalizationsDelegate } AppLocalizations lookupAppLocalizations(Locale locale) { - - // Lookup logic when only language code is specified. switch (locale.languageCode) { - case 'cs': return AppLocalizationsCs(); - case 'de': return AppLocalizationsDe(); - case 'en': return AppLocalizationsEn(); - case 'es': return AppLocalizationsEs(); - case 'fr': return AppLocalizationsFr(); - case 'nl': return AppLocalizationsNl(); - case 'pl': return AppLocalizationsPl(); + case 'cs': + return AppLocalizationsCs(); + case 'de': + return AppLocalizationsDe(); + case 'en': + return AppLocalizationsEn(); + case 'es': + return AppLocalizationsEs(); + case 'fr': + return AppLocalizationsFr(); + case 'nl': + return AppLocalizationsNl(); + case 'pl': + return AppLocalizationsPl(); } - throw FlutterError( - 'AppLocalizations.delegate failed to load unsupported locale "$locale". This is likely ' - 'an issue with the localizations generation tool. Please file an issue ' - 'on GitHub with a reproducible sample app and the gen-l10n configuration ' - 'that was used.' - ); + throw FlutterError('AppLocalizations.delegate failed to load unsupported locale "$locale". This is likely ' + 'an issue with the localizations generation tool. Please file an issue ' + 'on GitHub with a reproducible sample app and the gen-l10n configuration ' + 'that was used.'); } diff --git a/lib/l10n/app_localizations_cs.dart b/lib/l10n/app_localizations_cs.dart index 059168d49..14d1ab4a1 100644 --- a/lib/l10n/app_localizations_cs.dart +++ b/lib/l10n/app_localizations_cs.dart @@ -22,7 +22,8 @@ class AppLocalizationsCs extends AppLocalizations { String get patchNotesV4_3_1Improvement1 => 'Skener QR kódů byl vylepšen.'; @override - String get patchNotesV4_3_0NewFeatures1 => 'Přidána podpora pro import tokenů z Google, Aegis a 2FAS Authenticator. Další zdroje importu budou přidány v budoucnu.'; + String get patchNotesV4_3_0NewFeatures1 => + 'Přidána podpora pro import tokenů z Google, Aegis a 2FAS Authenticator. Další zdroje importu budou přidány v budoucnu.'; @override String get patchNotesV4_3_0NewFeatures2 => 'Do nastavení byla přidána možnost zpětné vazby.'; @@ -108,7 +109,8 @@ class AppLocalizationsCs extends AppLocalizations { } @override - String get confirmTokenDeletionHint => 'Pokud tento token odstraníte, nebude již možné se přihlásit.\nProsím, ujistěte se, že se můžete přihlásit k přidruženému účtu bez tohoto tokenu.'; + String get confirmTokenDeletionHint => + 'Pokud tento token odstraníte, nebude již možné se přihlásit.\nProsím, ujistěte se, že se můžete přihlásit k přidruženému účtu bez tohoto tokenu.'; @override String get confirmFolderDeletionHint => 'Odstranění složky nemá žádný vliv na tokeny v ní.\nTokeny jsou přesunuty do hlavního seznamu.'; @@ -329,7 +331,8 @@ class AppLocalizationsCs extends AppLocalizations { String get send => 'Odeslat'; @override - String get sendErrorLogDescription => 'Vytvoří se připravený e-mail.\nObsahuje informace o aplikaci, chybě a zařízení.\nPřed odesláním můžete e-mail upravit.\nZde se můžete podívat, jak informace používáme:'; + String get sendErrorLogDescription => + 'Vytvoří se připravený e-mail.\nObsahuje informace o aplikaci, chybě a zařízení.\nPřed odesláním můžete e-mail upravit.\nZde se můžete podívat, jak informace používáme:'; @override String get showPrivacyPolicy => 'Zobrazit zásady ochrany osobních údajů'; @@ -356,7 +359,8 @@ class AppLocalizationsCs extends AppLocalizations { String get open => 'Otevřít'; @override - String get sendErrorDialogBody => 'V aplikaci se vyskytla neznámá chyba. Informace uvedené níže mohou být odeslány vývojářům e-mailem pro vyřešení chyby v budoucnu.'; + String get sendErrorDialogBody => + 'V aplikaci se vyskytla neznámá chyba. Informace uvedené níže mohou být odeslány vývojářům e-mailem pro vyřešení chyby v budoucnu.'; @override String get noFbToken => 'Není k dispozici žádný token Firebase.'; @@ -489,7 +493,8 @@ class AppLocalizationsCs extends AppLocalizations { String get decryptErrorTitle => 'Chyba dešifrování'; @override - String get decryptErrorContent => 'Bohužel se aplikaci nepodařilo dešifrovat vaše tokeny. To znamená, že šifrovací klíč je poškozen. Můžete to zkusit znovu nebo odstranit data aplikace, čímž by došlo k odstranění tokenů v aplikaci.'; + String get decryptErrorContent => + 'Bohužel se aplikaci nepodařilo dešifrovat vaše tokeny. To znamená, že šifrovací klíč je poškozen. Můžete to zkusit znovu nebo odstranit data aplikace, čímž by došlo k odstranění tokenů v aplikaci.'; @override String get decryptErrorButtonDelete => 'Odstranit'; @@ -551,7 +556,8 @@ class AppLocalizationsCs extends AppLocalizations { } @override - String get legacySigningErrorMessage => 'Token byl vytvořen v zastaralé verzi aplikace, což může vést k problémům při jeho používání.\nPokud problém přetrvává, doporučujeme vytvořit nový push token!'; + String get legacySigningErrorMessage => + 'Token byl vytvořen v zastaralé verzi aplikace, což může vést k problémům při jeho používání.\nPokud problém přetrvává, doporučujeme vytvořit nový push token!'; @override String get selectImportSource => 'Vyberte zdroj importu'; @@ -661,7 +667,8 @@ class AppLocalizationsCs extends AppLocalizations { String get importHint2FAS => 'Vyberte zálohu 2FAS.\nPokud nemáte zálohu, vytvořte ji v aplikaci 2FAS. Doporučujeme použít heslo.'; @override - String get importHintAegisBackupFile => 'Vyberte svůj export Aegis (.JSON).\nPokud nemáte export, vytvořte si jej prostřednictvím nabídky nastavení v aplikaci Aegis. Doporučujeme použít heslo.'; + String get importHintAegisBackupFile => + 'Vyberte svůj export Aegis (.JSON).\nPokud nemáte export, vytvořte si jej prostřednictvím nabídky nastavení v aplikaci Aegis. Doporučujeme použít heslo.'; @override String get importHintAegisQrScan => 'Naskenujte QR kód, který obdržíte při přenosu záznamů z aplikace Aegis.'; @@ -673,16 +680,19 @@ class AppLocalizationsCs extends AppLocalizations { String get importHintGoogleQrScan => 'Naskenujte QR kód, který obdržíte při exportu účtů z Google Authenticator.'; @override - String get importHintGoogleQrFile => 'Vyberte obrazový soubor s QR kódem, který obdržíte při exportu účtů z Google Authenticator.\n!! Upozorňujeme, že není bezpečné ukládat QR kód do zařízení, protože tokeny nejsou šifrovány !!'; + String get importHintGoogleQrFile => + 'Vyberte obrazový soubor s QR kódem, který obdržíte při exportu účtů z Google Authenticator.\n!! Upozorňujeme, že není bezpečné ukládat QR kód do zařízení, protože tokeny nejsou šifrovány !!'; @override - String get importHintAuthenticatorProFile => 'Chcete-li vytvořit zálohu aplikace Authenticator Pro, přejděte do nastavení a klepněte na položku \"Automatické zálohování\". Vyberte umístění úložiště a nastavte heslo. Poté stiskněte \"Zálohovat nyní\" a exportujte tokeny.'; + String get importHintAuthenticatorProFile => + 'Chcete-li vytvořit zálohu aplikace Authenticator Pro, přejděte do nastavení a klepněte na položku \"Automatické zálohování\". Vyberte umístění úložiště a nastavte heslo. Poté stiskněte \"Zálohovat nyní\" a exportujte tokeny.'; @override String get importHintFreeOtpPlusQrScan => 'Naskenujte QR kód, který obdržíte po stisknutí tří teček na dlaždici tokenu, a vyberte možnost \"Sdílet QR kód\".'; @override - String get importHintFreeOtpPlusFile => 'Chcete-li vytvořit zálohu aplikace FreeOTP+, klepněte na tři tečky v pravém horním rohu a vyberte možnost \"Exportovat\". Můžete si vybrat mezi formátem JSON a URI. Zálohu doporučujeme po importu odstranit, protože není šifrovaná.'; + String get importHintFreeOtpPlusFile => + 'Chcete-li vytvořit zálohu aplikace FreeOTP+, klepněte na tři tečky v pravém horním rohu a vyberte možnost \"Exportovat\". Můžete si vybrat mezi formátem JSON a URI. Zálohu doporučujeme po importu odstranit, protože není šifrovaná.'; @override String get qrFileDecodeError => 'Z vybraného obrázku nebylo možné dekódovat QR kód, použijte prosím místo toho skener QR kódů.'; @@ -700,7 +710,8 @@ class AppLocalizationsCs extends AppLocalizations { String get feedbackDescription => 'Pokud máte nějaké dotazy, návrhy nebo problémy, dejte nám prosím vědět.'; @override - String get feedbackHint => 'Otevře se připravený e-mail, který nám můžete zaslat. V případě potřeby budou doplněny informace o vašem zařízení a verzi aplikace. Před odesláním můžete e-mail zkontrolovat a upravit.'; + String get feedbackHint => + 'Otevře se připravený e-mail, který nám můžete zaslat. V případě potřeby budou doplněny informace o vašem zařízení a verzi aplikace. Před odesláním můžete e-mail zkontrolovat a upravit.'; @override String get feedbackPrivacyPolicy1 => 'Odesláním zpětné vazby souhlasíte s našimi '; @@ -730,7 +741,8 @@ class AppLocalizationsCs extends AppLocalizations { String get noMailAppTitle => 'Není nainstalována žádná e-mailová aplikace'; @override - String get noMailAppDescription => 'There is no e-mail app installed or initialised on this device, please try again when you are able to send an email message.'; + String get noMailAppDescription => + 'There is no e-mail app installed or initialised on this device, please try again when you are able to send an email message.'; @override String get authenticationRequest => 'Žádost o ověření'; @@ -746,7 +758,8 @@ class AppLocalizationsCs extends AppLocalizations { } @override - String get pleaseSyncManuallyWhenNetworkIsAvailable => 'Synchronizujte prosím push tokeny ručně prostřednictvím nastavení, když je k dispozici síťové připojení.'; + String get pleaseSyncManuallyWhenNetworkIsAvailable => + 'Synchronizujte prosím push tokeny ručně prostřednictvím nastavení, když je k dispozici síťové připojení.'; @override String get pushTokens => 'Žetony Push'; diff --git a/lib/l10n/app_localizations_de.dart b/lib/l10n/app_localizations_de.dart index ae0cfbe6b..28bf84a9a 100644 --- a/lib/l10n/app_localizations_de.dart +++ b/lib/l10n/app_localizations_de.dart @@ -22,7 +22,8 @@ class AppLocalizationsDe extends AppLocalizations { String get patchNotesV4_3_1Improvement1 => 'Der QR-Code-Scanner wurde verbessert.'; @override - String get patchNotesV4_3_0NewFeatures1 => 'Unterstützung für den Import von Token von Google, Aegis und 2FAS Authenticator hinzugefügt. Weitere Importquellen werden in Zukunft hinzugefügt.'; + String get patchNotesV4_3_0NewFeatures1 => + 'Unterstützung für den Import von Token von Google, Aegis und 2FAS Authenticator hinzugefügt. Weitere Importquellen werden in Zukunft hinzugefügt.'; @override String get patchNotesV4_3_0NewFeatures2 => 'Feedback-Option zu den Einstellungen hinzugefügt.'; @@ -108,10 +109,12 @@ class AppLocalizationsDe extends AppLocalizations { } @override - String get confirmTokenDeletionHint => 'Unter Umständen können Sie sich nicht mehr einloggen, wenn Sie diesen Token löschen.\nBitte stellen Sie sicher, dass Sie sich ohne diesen Token in den dazugehörigen Account einloggen können.'; + String get confirmTokenDeletionHint => + 'Unter Umständen können Sie sich nicht mehr einloggen, wenn Sie diesen Token löschen.\nBitte stellen Sie sicher, dass Sie sich ohne diesen Token in den dazugehörigen Account einloggen können.'; @override - String get confirmFolderDeletionHint => 'Das Löschen eines Ordners hat keine Auswirkungen auf die Token, die sich darin befinden.\nDie Token werden in die Hauptliste verschoben.'; + String get confirmFolderDeletionHint => + 'Das Löschen eines Ordners hat keine Auswirkungen auf die Token, die sich darin befinden.\nDie Token werden in die Hauptliste verschoben.'; @override String get generatingPhonePart => 'Generiere Telefonanteil'; @@ -149,7 +152,8 @@ class AppLocalizationsDe extends AppLocalizations { String get enablePolling => 'Aktives Stellen von Push-Anfragen'; @override - String get requestPushChallengesPeriodically => 'Fordert regelmäßig Push-Anfragen vom Server an. Aktivieren Sie diese Funktion, wenn Nachrichten ansonsten nicht erhalten werden.'; + String get requestPushChallengesPeriodically => + 'Fordert regelmäßig Push-Anfragen vom Server an. Aktivieren Sie diese Funktion, wenn Nachrichten ansonsten nicht erhalten werden.'; @override String get synchronizePushTokens => 'Synchronisiere Push Token'; @@ -267,7 +271,8 @@ class AppLocalizationsDe extends AppLocalizations { String get goToSettingsButton => 'Gehe zu Einstellungen'; @override - String get goToSettingsDescription => 'Authentifizierung durch Gerätepasswort oder Biometrie ist nicht eingerichtet. Bitte aktivieren Sie dies in den Geräteeinstellungen.'; + String get goToSettingsDescription => + 'Authentifizierung durch Gerätepasswort oder Biometrie ist nicht eingerichtet. Bitte aktivieren Sie dies in den Geräteeinstellungen.'; @override String get lockOut => 'Biometrie ist deaktiviert. Bitte sperren und entsperren Sie Ihren Bildschirm um diese zu aktivieren.'; @@ -329,7 +334,8 @@ class AppLocalizationsDe extends AppLocalizations { String get send => 'Senden'; @override - String get sendErrorLogDescription => 'Es wird eine vorgefertigte E-Mail erstellt.\nSie enthält Informationen über die App, den Fehler und das Gerät.\nSie können die E-Mail vor dem Senden bearbeiten.\nWie wir die Informationen verwenden, sehen Sie hier:'; + String get sendErrorLogDescription => + 'Es wird eine vorgefertigte E-Mail erstellt.\nSie enthält Informationen über die App, den Fehler und das Gerät.\nSie können die E-Mail vor dem Senden bearbeiten.\nWie wir die Informationen verwenden, sehen Sie hier:'; @override String get showPrivacyPolicy => 'Datenschutzerklärung anzeigen'; @@ -356,7 +362,8 @@ class AppLocalizationsDe extends AppLocalizations { String get open => 'Öffnen'; @override - String get sendErrorDialogBody => 'Ein unbekannter Fehler ist aufgetreten. Die unten gezeigten Informationen können den Entwicklern per E-Mail zugesendet werden, um zu helfen, diesen Fehler in Zukunft zu vermeiden.'; + String get sendErrorDialogBody => + 'Ein unbekannter Fehler ist aufgetreten. Die unten gezeigten Informationen können den Entwicklern per E-Mail zugesendet werden, um zu helfen, diesen Fehler in Zukunft zu vermeiden.'; @override String get noFbToken => 'Kein Firebase Token vorhanden'; @@ -480,7 +487,8 @@ class AppLocalizationsDe extends AppLocalizations { String get grantCameraPermissionDialogContent => 'Um QR-Codes zu scannen, benötigt die App Zugriff auf die Kamera.'; @override - String get grantCameraPermissionDialogPermanentlyDenied => 'Sie haben die Berechtigung für den Kamerazugriff permanent verweigert. Bitte aktivieren Sie die Berechtigung in den Einstellungen ihres Smartphones.'; + String get grantCameraPermissionDialogPermanentlyDenied => + 'Sie haben die Berechtigung für den Kamerazugriff permanent verweigert. Bitte aktivieren Sie die Berechtigung in den Einstellungen ihres Smartphones.'; @override String get grantCameraPermissionDialogButton => 'Berechtigung erteilen'; @@ -489,7 +497,8 @@ class AppLocalizationsDe extends AppLocalizations { String get decryptErrorTitle => 'Entschlüsselung fehlgeschlagen'; @override - String get decryptErrorContent => 'Leider konnten Ihre Token nicht entschlüsselt werden. Das deutet darauf hin, dass der Verschlüsselungsschlüssel nicht mehr verfügbar ist. Sie können es erneut versuchen oder die App Daten löschen. Dabei werden alle Token aus der App geschlöscht.'; + String get decryptErrorContent => + 'Leider konnten Ihre Token nicht entschlüsselt werden. Das deutet darauf hin, dass der Verschlüsselungsschlüssel nicht mehr verfügbar ist. Sie können es erneut versuchen oder die App Daten löschen. Dabei werden alle Token aus der App geschlöscht.'; @override String get decryptErrorButtonDelete => 'Löschen.'; @@ -507,7 +516,8 @@ class AppLocalizationsDe extends AppLocalizations { String get hidePushTokens => 'Push-Token ausblenden'; @override - String get hidePushTokensDescription => 'Push-Token aus der Token-Liste ausblenden. Dadurch werden die Token nicht gelöscht und sind weiterhin auf einem separaten Bildschirm sichtbar.'; + String get hidePushTokensDescription => + 'Push-Token aus der Token-Liste ausblenden. Dadurch werden die Token nicht gelöscht und sind weiterhin auf einem separaten Bildschirm sichtbar.'; @override String get settingsGroupGeneral => 'Allgemeines'; @@ -519,7 +529,8 @@ class AppLocalizationsDe extends AppLocalizations { String get privacyPolicy => 'Datenschutzerklärung'; @override - String get introScanQrCode => 'Sie können QR-Codes scannen, um Token hinzuzufügen.\nWir unterstützen alle gängigen Two-Factor-Authentication Token und auch die privacyIDEA Token.'; + String get introScanQrCode => + 'Sie können QR-Codes scannen, um Token hinzuzufügen.\nWir unterstützen alle gängigen Two-Factor-Authentication Token und auch die privacyIDEA Token.'; @override String get introAddTokenManually => 'Wenn Sie keinen QR-Code scannen möchten, können Sie Token auch manuell hinzufügen.'; @@ -531,7 +542,8 @@ class AppLocalizationsDe extends AppLocalizations { String get introEditToken => 'Hier können Sie den Namen des Tokens bearbeiten und einige Details einsehen.'; @override - String get introLockToken => 'Um die Sicherheit noch weiter zu erhöhen, können Sie Token sperren.\nDer Token kann dann erst nach der Authentifizierung verwendet werden.'; + String get introLockToken => + 'Um die Sicherheit noch weiter zu erhöhen, können Sie Token sperren.\nDer Token kann dann erst nach der Authentifizierung verwendet werden.'; @override String get introDragToken => 'Reorganisieren Sie Ihre Token, indem Sie sie einige Sekunden lang drücken und dann an die gewünschte Position ziehen.'; @@ -551,7 +563,8 @@ class AppLocalizationsDe extends AppLocalizations { } @override - String get legacySigningErrorMessage => 'Der Token wurde in einer veralteten Version der App erstellt, was zu Problemen bei der Verwendung führen kann. Es wird empfohlen, einen neuen Push-Token zu erstellen, wenn das Problem weiterhin besteht!'; + String get legacySigningErrorMessage => + 'Der Token wurde in einer veralteten Version der App erstellt, was zu Problemen bei der Verwendung führen kann. Es wird empfohlen, einen neuen Push-Token zu erstellen, wenn das Problem weiterhin besteht!'; @override String get selectImportSource => 'Importquelle auswählen'; @@ -658,10 +671,12 @@ class AppLocalizationsDe extends AppLocalizations { } @override - String get importHint2FAS => 'Wählen Sie das 2FAS-Backup aus.\nFalls Sie kein Backup haben, erstellen Sie eins in der 2FAS-App. Wir empfehlen die Verwendung eines Passworts.'; + String get importHint2FAS => + 'Wählen Sie das 2FAS-Backup aus.\nFalls Sie kein Backup haben, erstellen Sie eins in der 2FAS-App. Wir empfehlen die Verwendung eines Passworts.'; @override - String get importHintAegisBackupFile => 'Wähle dein Aegis-Export (.json) aus.\nWenn Sie keinen Export haben, erstellen Sie bitte eins über das Einstellungen Menu in der Aegis-App. Wir empfehlen die Verwendung eines Passworts.'; + String get importHintAegisBackupFile => + 'Wähle dein Aegis-Export (.json) aus.\nWenn Sie keinen Export haben, erstellen Sie bitte eins über das Einstellungen Menu in der Aegis-App. Wir empfehlen die Verwendung eines Passworts.'; @override String get importHintAegisQrScan => 'Scannen Sie den QR-Code, den Sie erhalten, wenn Sie Einträge aus Aegis übertragen.'; @@ -673,19 +688,24 @@ class AppLocalizationsDe extends AppLocalizations { String get importHintGoogleQrScan => 'Scannen Sie den QR-Code, den Sie erhalten, wenn Sie Ihre Konten aus Google Authenticator exportieren.'; @override - String get importHintGoogleQrFile => 'Wählen Sie eine Bilddatei mit dem QR-Code, den Sie erhalten, wenn Sie Ihre Konten aus dem Google Authenticator exportieren.\n!! Der QR-Code enthält die Token in unverschlüsselter Form. Es ist deshalb nicht sicher, diesen länger als nötig aufzubewahren !!'; + String get importHintGoogleQrFile => + 'Wählen Sie eine Bilddatei mit dem QR-Code, den Sie erhalten, wenn Sie Ihre Konten aus dem Google Authenticator exportieren.\n!! Der QR-Code enthält die Token in unverschlüsselter Form. Es ist deshalb nicht sicher, diesen länger als nötig aufzubewahren !!'; @override - String get importHintAuthenticatorProFile => 'Um ein Backup der Authenticator Pro-App zu erstellen navigieren Sie zu den Einstellungen und tippen Sie auf \"Automatische Sicherung\". Wählen Sie einen Speicherort und setzen Sie ein Passwort. Anschließend drücken Sie auf \"Jetzt sichern\" um die Token zu exportieren.'; + String get importHintAuthenticatorProFile => + 'Um ein Backup der Authenticator Pro-App zu erstellen navigieren Sie zu den Einstellungen und tippen Sie auf \"Automatische Sicherung\". Wählen Sie einen Speicherort und setzen Sie ein Passwort. Anschließend drücken Sie auf \"Jetzt sichern\" um die Token zu exportieren.'; @override - String get importHintFreeOtpPlusQrScan => 'Scannen Sie den QR-Code, den Sie erhalten, wenn Sie auf die drei Punkte in der Kachel des Tokens drücken, und wählen Sie \"QR-Code teilen\".'; + String get importHintFreeOtpPlusQrScan => + 'Scannen Sie den QR-Code, den Sie erhalten, wenn Sie auf die drei Punkte in der Kachel des Tokens drücken, und wählen Sie \"QR-Code teilen\".'; @override - String get importHintFreeOtpPlusFile => 'Um ein Backup der FreeOTP+ App zu erstellen, tippen Sie auf die drei Punkte in der oberen rechten Ecke und wählen Sie \"Exportieren\". Sie können zwischen dem JSON- und dem URI-Format wählen. Wir empfehlen, das Backup nach dem Importieren zu löschen, da es nicht verschlüsselt ist.'; + String get importHintFreeOtpPlusFile => + 'Um ein Backup der FreeOTP+ App zu erstellen, tippen Sie auf die drei Punkte in der oberen rechten Ecke und wählen Sie \"Exportieren\". Sie können zwischen dem JSON- und dem URI-Format wählen. Wir empfehlen, das Backup nach dem Importieren zu löschen, da es nicht verschlüsselt ist.'; @override - String get qrFileDecodeError => 'Es war nicht möglich, den QR-Code aus dem ausgewählten Bild zu dekodieren. Bitte verwenden Sie stattdessen den QR-Code-Scanner.'; + String get qrFileDecodeError => + 'Es war nicht möglich, den QR-Code aus dem ausgewählten Bild zu dekodieren. Bitte verwenden Sie stattdessen den QR-Code-Scanner.'; @override String get tokenLink => 'Token Link'; @@ -700,7 +720,8 @@ class AppLocalizationsDe extends AppLocalizations { String get feedbackDescription => 'Wenn Sie Fragen, Anregungen oder Probleme haben, lassen Sie es uns wissen.'; @override - String get feedbackHint => 'Es öffnet sich eine vorgefertigte E-Mail, die Sie an uns senden können. Falls gewünscht, werden Informationen über Ihr Gerät und die Version der Anwendung hinzugefügt. Vor dem Versenden können Sie die E-Mail überprüfen und bearbeiten.'; + String get feedbackHint => + 'Es öffnet sich eine vorgefertigte E-Mail, die Sie an uns senden können. Falls gewünscht, werden Informationen über Ihr Gerät und die Version der Anwendung hinzugefügt. Vor dem Versenden können Sie die E-Mail überprüfen und bearbeiten.'; @override String get feedbackPrivacyPolicy1 => 'Mit dem Senden des Feedbacks stimmen Sie unserer '; @@ -730,7 +751,8 @@ class AppLocalizationsDe extends AppLocalizations { String get noMailAppTitle => 'Keine Mail-App gefunden'; @override - String get noMailAppDescription => 'Auf diesem Gerät ist keine E-Mail-App installiert oder initialisiert, bitte versuchen Sie es erneut, wenn Sie eine E-Mail-Nachricht senden können.'; + String get noMailAppDescription => + 'Auf diesem Gerät ist keine E-Mail-App installiert oder initialisiert, bitte versuchen Sie es erneut, wenn Sie eine E-Mail-Nachricht senden können.'; @override String get authenticationRequest => 'Authentifizierung'; @@ -746,7 +768,8 @@ class AppLocalizationsDe extends AppLocalizations { } @override - String get pleaseSyncManuallyWhenNetworkIsAvailable => 'Bitte synchronisieren Sie die Push Token über die Einstellungen manuell, wenn eine Netzwerkverbindung verfügbar ist.'; + String get pleaseSyncManuallyWhenNetworkIsAvailable => + 'Bitte synchronisieren Sie die Push Token über die Einstellungen manuell, wenn eine Netzwerkverbindung verfügbar ist.'; @override String get pushTokens => 'Push-Token'; @@ -826,7 +849,8 @@ class AppLocalizationsDe extends AppLocalizations { String get exportTokens => 'Tokens exportieren'; @override - String get enterPasswordToEncrypt => 'Geben Sie ein Passwort ein, um die Tokens zu verschlüsseln. Dieses Passwort wird benötigt, um die Tokens zu importieren.'; + String get enterPasswordToEncrypt => + 'Geben Sie ein Passwort ein, um die Tokens zu verschlüsseln. Dieses Passwort wird benötigt, um die Tokens zu importieren.'; @override String get exportLockedTokenReason => 'Bitte authentifizieren Sie sich, um gesperrte Tokens zu exportieren.'; diff --git a/lib/l10n/app_localizations_en.dart b/lib/l10n/app_localizations_en.dart index 2cc95e32e..707bce230 100644 --- a/lib/l10n/app_localizations_en.dart +++ b/lib/l10n/app_localizations_en.dart @@ -22,7 +22,8 @@ class AppLocalizationsEn extends AppLocalizations { String get patchNotesV4_3_1Improvement1 => 'Improved the qr code scanner.'; @override - String get patchNotesV4_3_0NewFeatures1 => 'Support for importing tokens from Google, Aegis and 2FAS Authenticator has been added. More import sources will be added in the future.'; + String get patchNotesV4_3_0NewFeatures1 => + 'Support for importing tokens from Google, Aegis and 2FAS Authenticator has been added. More import sources will be added in the future.'; @override String get patchNotesV4_3_0NewFeatures2 => 'Added feedback option to the settings.'; @@ -108,7 +109,8 @@ class AppLocalizationsEn extends AppLocalizations { } @override - String get confirmTokenDeletionHint => 'You may no longer be able to log in if you delete this token.\nPlease make sure that you can log in to the associated account without this token.'; + String get confirmTokenDeletionHint => + 'You may no longer be able to log in if you delete this token.\nPlease make sure that you can log in to the associated account without this token.'; @override String get confirmFolderDeletionHint => 'Deleting a folder has no effect on the tokens in it.\nThe tokens are moved to the main list.'; @@ -149,7 +151,8 @@ class AppLocalizationsEn extends AppLocalizations { String get enablePolling => 'Enable polling'; @override - String get requestPushChallengesPeriodically => 'Request push challenges from the server periodically. Enable this if push challenges are not received normally.'; + String get requestPushChallengesPeriodically => + 'Request push challenges from the server periodically. Enable this if push challenges are not received normally.'; @override String get synchronizePushTokens => 'Synchronize push tokens'; @@ -329,7 +332,8 @@ class AppLocalizationsEn extends AppLocalizations { String get send => 'Send'; @override - String get sendErrorLogDescription => 'A predefined email is created.\nIt contains information about the app, the error and the device.\nYou can edit the email before sending it.\nYou can see here how we use the information:'; + String get sendErrorLogDescription => + 'A predefined email is created.\nIt contains information about the app, the error and the device.\nYou can edit the email before sending it.\nYou can see here how we use the information:'; @override String get showPrivacyPolicy => 'Show privacy policy'; @@ -356,7 +360,8 @@ class AppLocalizationsEn extends AppLocalizations { String get open => 'Open'; @override - String get sendErrorDialogBody => 'An unexpected error occurred in the application. The information below can be send to the developers by email to help prevent this error in the future.'; + String get sendErrorDialogBody => + 'An unexpected error occurred in the application. The information below can be send to the developers by email to help prevent this error in the future.'; @override String get noFbToken => 'No Firebase token available'; @@ -480,7 +485,8 @@ class AppLocalizationsEn extends AppLocalizations { String get grantCameraPermissionDialogContent => 'Please grant camera permission to scan QR codes.'; @override - String get grantCameraPermissionDialogPermanentlyDenied => 'Camera permission is permanently denied. Please grant camera permission in your Phone\'s settings.'; + String get grantCameraPermissionDialogPermanentlyDenied => + 'Camera permission is permanently denied. Please grant camera permission in your Phone\'s settings.'; @override String get grantCameraPermissionDialogButton => 'Grant permission'; @@ -489,7 +495,8 @@ class AppLocalizationsEn extends AppLocalizations { String get decryptErrorTitle => 'Decryption error'; @override - String get decryptErrorContent => 'Unfortunately, the app was unable to decrypt your tokens. This indicates that the encryption key is broken. You can try again or delete the app data, which would delete the tokens in the app.'; + String get decryptErrorContent => + 'Unfortunately, the app was unable to decrypt your tokens. This indicates that the encryption key is broken. You can try again or delete the app data, which would delete the tokens in the app.'; @override String get decryptErrorButtonDelete => 'Delete'; @@ -507,7 +514,8 @@ class AppLocalizationsEn extends AppLocalizations { String get hidePushTokens => 'Hide push tokens'; @override - String get hidePushTokensDescription => 'Hide push tokens from the token list. This will not delete the tokens and they will still be visible on a separate screen.'; + String get hidePushTokensDescription => + 'Hide push tokens from the token list. This will not delete the tokens and they will still be visible on a separate screen.'; @override String get settingsGroupGeneral => 'General'; @@ -519,7 +527,8 @@ class AppLocalizationsEn extends AppLocalizations { String get privacyPolicy => 'Privacy policy'; @override - String get introScanQrCode => 'You can scan QR codes to add tokens.\nWe support every common Two-Factor-Authentication token and also the privacyIDEA tokens.'; + String get introScanQrCode => + 'You can scan QR codes to add tokens.\nWe support every common Two-Factor-Authentication token and also the privacyIDEA tokens.'; @override String get introAddTokenManually => 'If you don\'t want to scan a QR code, you can also add tokens manually.'; @@ -551,7 +560,8 @@ class AppLocalizationsEn extends AppLocalizations { } @override - String get legacySigningErrorMessage => 'The token was enrolled in a old version of this app, which may cause trouble using it.\nIt is suggested to enroll a new push token if the problem persist!'; + String get legacySigningErrorMessage => + 'The token was enrolled in a old version of this app, which may cause trouble using it.\nIt is suggested to enroll a new push token if the problem persist!'; @override String get selectImportSource => 'Select import source'; @@ -661,7 +671,8 @@ class AppLocalizationsEn extends AppLocalizations { String get importHint2FAS => 'Select your 2FAS backup.\nIf you do not have a backup, create one in the 2FAS app. We recommend using a password.'; @override - String get importHintAegisBackupFile => 'Select your Aegis export (.JSON).\nIf you do not have an export, please create one via the settings menu in the Aegis app. The use of a password is recommended.'; + String get importHintAegisBackupFile => + 'Select your Aegis export (.JSON).\nIf you do not have an export, please create one via the settings menu in the Aegis app. The use of a password is recommended.'; @override String get importHintAegisQrScan => 'Scan the QR code you receive when you transfer entries from Aegis.'; @@ -673,16 +684,19 @@ class AppLocalizationsEn extends AppLocalizations { String get importHintGoogleQrScan => 'Scan the QR code you receive when you export your accounts from Google Authenticator.'; @override - String get importHintGoogleQrFile => 'Select an image file with the QR code you receive when you export your accounts from Google Authenticator.\n!! Note that it is not safe to save the QR code on your device as the tokens are not encrypted !!'; + String get importHintGoogleQrFile => + 'Select an image file with the QR code you receive when you export your accounts from Google Authenticator.\n!! Note that it is not safe to save the QR code on your device as the tokens are not encrypted !!'; @override - String get importHintAuthenticatorProFile => 'To create a backup of the Authenticator Pro app, navigate to the settings and tap on \"Auto backup\". Select a storage location and set a password. Then press \"Back up now\" to export the tokens.'; + String get importHintAuthenticatorProFile => + 'To create a backup of the Authenticator Pro app, navigate to the settings and tap on \"Auto backup\". Select a storage location and set a password. Then press \"Back up now\" to export the tokens.'; @override String get importHintFreeOtpPlusQrScan => 'Scan the QR code you receive when you press the three dots in the tile of the token and select \"Share QR code\".'; @override - String get importHintFreeOtpPlusFile => 'To create a backup of the FreeOTP+ app, tap on the three dots in the upper right corner and select \"Export\". You can choose between JSON and URI format. We recommend to delete the backup after importing it, because it is not encrypted.'; + String get importHintFreeOtpPlusFile => + 'To create a backup of the FreeOTP+ app, tap on the three dots in the upper right corner and select \"Export\". You can choose between JSON and URI format. We recommend to delete the backup after importing it, because it is not encrypted.'; @override String get qrFileDecodeError => 'It was not possible to decode the QR code from the selected image, please use the QR code scanner instead.'; @@ -700,7 +714,8 @@ class AppLocalizationsEn extends AppLocalizations { String get feedbackDescription => 'If you have any questions, suggestions or problems, please let us know.'; @override - String get feedbackHint => 'A ready-made e-mail will open, which you can send to us. If desired, information about your device and the version of the application will be added. You can check and edit the email before sending it.'; + String get feedbackHint => + 'A ready-made e-mail will open, which you can send to us. If desired, information about your device and the version of the application will be added. You can check and edit the email before sending it.'; @override String get feedbackPrivacyPolicy1 => 'By sending the feedback you agree to our '; @@ -730,7 +745,8 @@ class AppLocalizationsEn extends AppLocalizations { String get noMailAppTitle => 'No mail app found'; @override - String get noMailAppDescription => 'There is no e-mail app installed or initialised on this device, please try again when you are able to send an email message.'; + String get noMailAppDescription => + 'There is no e-mail app installed or initialised on this device, please try again when you are able to send an email message.'; @override String get authenticationRequest => 'Authentication request'; diff --git a/lib/l10n/app_localizations_es.dart b/lib/l10n/app_localizations_es.dart index 2c238e791..254a35c70 100644 --- a/lib/l10n/app_localizations_es.dart +++ b/lib/l10n/app_localizations_es.dart @@ -22,7 +22,8 @@ class AppLocalizationsEs extends AppLocalizations { String get patchNotesV4_3_1Improvement1 => 'Se ha mejorado el escáner de códigos QR.'; @override - String get patchNotesV4_3_0NewFeatures1 => 'Añadido soporte para importar tokens de Google, Aegis y 2FAS Authenticator. En el futuro se añadirán más fuentes de importación'; + String get patchNotesV4_3_0NewFeatures1 => + 'Añadido soporte para importar tokens de Google, Aegis y 2FAS Authenticator. En el futuro se añadirán más fuentes de importación'; @override String get patchNotesV4_3_0NewFeatures2 => 'Añadida opción de feedback a los ajustes'; @@ -108,7 +109,8 @@ class AppLocalizationsEs extends AppLocalizations { } @override - String get confirmTokenDeletionHint => 'Es posible que ya no pueda iniciar sesión si elimina este token.\nAsegúrese de que puede iniciar sesión en la cuenta asociada sin este token.'; + String get confirmTokenDeletionHint => + 'Es posible que ya no pueda iniciar sesión si elimina este token.\nAsegúrese de que puede iniciar sesión en la cuenta asociada sin este token.'; @override String get confirmFolderDeletionHint => 'Eliminar una carpeta no afecta a los tokens que contiene.\nLos tokens se mueven a la lista principal.'; @@ -149,7 +151,8 @@ class AppLocalizationsEs extends AppLocalizations { String get enablePolling => 'Activar polling'; @override - String get requestPushChallengesPeriodically => 'Solicita retos push al servidor periódicamente. Habilite esta opción si los retos push no se reciben normalmente.'; + String get requestPushChallengesPeriodically => + 'Solicita retos push al servidor periódicamente. Habilite esta opción si los retos push no se reciben normalmente.'; @override String get synchronizePushTokens => 'Sinchronizar push tokens'; @@ -267,7 +270,8 @@ class AppLocalizationsEs extends AppLocalizations { String get goToSettingsButton => 'Ir a la configuración'; @override - String get goToSettingsDescription => 'La autenticación por credenciales o biométrica no está configurada en tu dispositivo. Por favor, configúrala en los ajustes del dispositivo.'; + String get goToSettingsDescription => + 'La autenticación por credenciales o biométrica no está configurada en tu dispositivo. Por favor, configúrala en los ajustes del dispositivo.'; @override String get lockOut => 'La autenticación biométrica está desactivada. Bloquea y desbloquea la pantalla para activarla.'; @@ -329,7 +333,8 @@ class AppLocalizationsEs extends AppLocalizations { String get send => 'Enviar'; @override - String get sendErrorLogDescription => 'Se crea un correo electrónico listo.\nContiene información sobre la app, el error y el dispositivo.\nPuedes editar el correo antes de enviarlo.\nAquí puede ver cómo utilizamos la información:'; + String get sendErrorLogDescription => + 'Se crea un correo electrónico listo.\nContiene información sobre la app, el error y el dispositivo.\nPuedes editar el correo antes de enviarlo.\nAquí puede ver cómo utilizamos la información:'; @override String get showPrivacyPolicy => 'Mostrar política de privacidad'; @@ -356,7 +361,8 @@ class AppLocalizationsEs extends AppLocalizations { String get open => 'Abrir'; @override - String get sendErrorDialogBody => 'Se ha producido un error inesperado en la aplicación. La siguiente información puede ser enviada a los desarrolladores por correo electrónico para ayudar a prevenir este error en el futuro.'; + String get sendErrorDialogBody => + 'Se ha producido un error inesperado en la aplicación. La siguiente información puede ser enviada a los desarrolladores por correo electrónico para ayudar a prevenir este error en el futuro.'; @override String get noFbToken => 'No hay token de Firebase.'; @@ -480,7 +486,8 @@ class AppLocalizationsEs extends AppLocalizations { String get grantCameraPermissionDialogContent => 'Por favor, concede permiso a la cámara para escanear códigos QR'; @override - String get grantCameraPermissionDialogPermanentlyDenied => 'El permiso de cámara está denegado permanentemente. Concede el permiso de cámara en la configuración del teléfono'; + String get grantCameraPermissionDialogPermanentlyDenied => + 'El permiso de cámara está denegado permanentemente. Concede el permiso de cámara en la configuración del teléfono'; @override String get grantCameraPermissionDialogButton => 'Conceder permiso'; @@ -489,7 +496,8 @@ class AppLocalizationsEs extends AppLocalizations { String get decryptErrorTitle => 'Error de descifrado'; @override - String get decryptErrorContent => 'Lamentablemente, la aplicación no ha podido descifrar tus tokens. Esto indica que la clave de cifrado está rota. Puedes volver a intentarlo o borrar los datos de la app, lo que eliminaría los tokens de la app.'; + String get decryptErrorContent => + 'Lamentablemente, la aplicación no ha podido descifrar tus tokens. Esto indica que la clave de cifrado está rota. Puedes volver a intentarlo o borrar los datos de la app, lo que eliminaría los tokens de la app.'; @override String get decryptErrorButtonDelete => 'Borrar'; @@ -507,7 +515,8 @@ class AppLocalizationsEs extends AppLocalizations { String get hidePushTokens => 'Ocultar tokens push'; @override - String get hidePushTokensDescription => 'Ocultar tokens push de la lista de tokens. Esto no borrará los tokens y seguirán siendo visibles en una pantalla aparte'; + String get hidePushTokensDescription => + 'Ocultar tokens push de la lista de tokens. Esto no borrará los tokens y seguirán siendo visibles en una pantalla aparte'; @override String get settingsGroupGeneral => 'Información general'; @@ -519,7 +528,8 @@ class AppLocalizationsEs extends AppLocalizations { String get privacyPolicy => 'Política de privacidad'; @override - String get introScanQrCode => 'Puedes escanear códigos QR para añadir tokens.\nSoportamos todos los tokens comunes de Two-Factor-Authentication y también los tokens privacyIDEA'; + String get introScanQrCode => + 'Puedes escanear códigos QR para añadir tokens.\nSoportamos todos los tokens comunes de Two-Factor-Authentication y también los tokens privacyIDEA'; @override String get introAddTokenManually => 'Si no quieres escanear un código QR, también puedes añadir tokens manualmente'; @@ -531,7 +541,8 @@ class AppLocalizationsEs extends AppLocalizations { String get introEditToken => 'Aquí puedes editar el nombre del token y ver algunos detalles'; @override - String get introLockToken => 'Para mejorar la seguridad aún más, puedes bloquear los tokens.\nEntonces el token sólo se puede utilizar después de la autenticación.'; + String get introLockToken => + 'Para mejorar la seguridad aún más, puedes bloquear los tokens.\nEntonces el token sólo se puede utilizar después de la autenticación.'; @override String get introDragToken => 'Reorganiza tus tokens pulsándolo durante unos segundos y arrastrándolo a la posición deseada'; @@ -551,7 +562,8 @@ class AppLocalizationsEs extends AppLocalizations { } @override - String get legacySigningErrorMessage => 'El token se creó en una versión obsoleta de la aplicación, lo que puede provocar problemas al utilizarlo.\nSe recomienda crear un nuevo token push si el problema persiste.'; + String get legacySigningErrorMessage => + 'El token se creó en una versión obsoleta de la aplicación, lo que puede provocar problemas al utilizarlo.\nSe recomienda crear un nuevo token push si el problema persiste.'; @override String get selectImportSource => 'Seleccionar fuente de importación'; @@ -658,10 +670,12 @@ class AppLocalizationsEs extends AppLocalizations { } @override - String get importHint2FAS => 'Seleccione su copia de seguridad de 2FAS. Si no tiene una copia de seguridad, cree una en la aplicación 2FAS. Le recomendamos que utilice una contraseña'; + String get importHint2FAS => + 'Seleccione su copia de seguridad de 2FAS. Si no tiene una copia de seguridad, cree una en la aplicación 2FAS. Le recomendamos que utilice una contraseña'; @override - String get importHintAegisBackupFile => 'Seleccione su exportación de Aegis (.JSON).\nSi no tiene una exportación, cree una a través del menú de configuración en la app de Aegis. Se recomienda utilizar una contraseña'; + String get importHintAegisBackupFile => + 'Seleccione su exportación de Aegis (.JSON).\nSi no tiene una exportación, cree una a través del menú de configuración en la app de Aegis. Se recomienda utilizar una contraseña'; @override String get importHintAegisQrScan => 'Escanea el código QR que recibes al transferir entradas desde Aegis'; @@ -673,16 +687,20 @@ class AppLocalizationsEs extends AppLocalizations { String get importHintGoogleQrScan => 'Escanea el código QR que recibes al exportar tus cuentas desde Google Authenticator'; @override - String get importHintGoogleQrFile => 'Selecciona un archivo de imagen con el código QR que recibes al exportar tus cuentas desde Google Authenticator.\n!! Tenga en cuenta que no es seguro guardar el código QR en su dispositivo, ya que los tokens no están cifrados !!'; + String get importHintGoogleQrFile => + 'Selecciona un archivo de imagen con el código QR que recibes al exportar tus cuentas desde Google Authenticator.\n!! Tenga en cuenta que no es seguro guardar el código QR en su dispositivo, ya que los tokens no están cifrados !!'; @override - String get importHintAuthenticatorProFile => 'Para crear una copia de seguridad de la aplicación Authenticator Pro, vaya a la configuración y pulse en \"Copia de seguridad automática\". Seleccione una ubicación de almacenamiento y establezca una contraseña. A continuación, pulse \"Hacer copia de seguridad ahora\" para exportar los tokens.'; + String get importHintAuthenticatorProFile => + 'Para crear una copia de seguridad de la aplicación Authenticator Pro, vaya a la configuración y pulse en \"Copia de seguridad automática\". Seleccione una ubicación de almacenamiento y establezca una contraseña. A continuación, pulse \"Hacer copia de seguridad ahora\" para exportar los tokens.'; @override - String get importHintFreeOtpPlusQrScan => 'Escanea el código QR que recibes al pulsar los tres puntos en el azulejo de la ficha y selecciona \"Compartir código QR\".'; + String get importHintFreeOtpPlusQrScan => + 'Escanea el código QR que recibes al pulsar los tres puntos en el azulejo de la ficha y selecciona \"Compartir código QR\".'; @override - String get importHintFreeOtpPlusFile => 'Para crear una copia de seguridad de la app FreeOTP+, pulse los tres puntos de la esquina superior derecha y seleccione \"Exportar\". Puede elegir entre los formatos JSON y URI. Recomendamos eliminar la copia de seguridad después de importarla, ya que no está cifrada.'; + String get importHintFreeOtpPlusFile => + 'Para crear una copia de seguridad de la app FreeOTP+, pulse los tres puntos de la esquina superior derecha y seleccione \"Exportar\". Puede elegir entre los formatos JSON y URI. Recomendamos eliminar la copia de seguridad después de importarla, ya que no está cifrada.'; @override String get qrFileDecodeError => 'No fue posible decodificar el código QR de la imagen seleccionada, por favor utilice el escáner de código QR en su lugar.'; @@ -700,7 +718,8 @@ class AppLocalizationsEs extends AppLocalizations { String get feedbackDescription => 'Si tienes alguna pregunta, sugerencia o problema, háznoslo saber'; @override - String get feedbackHint => 'Se abrirá un correo electrónico preparado que podrá enviarnos. Si lo desea, se añadirá información sobre su dispositivo y la versión de la aplicación. Puede comprobar y editar el correo electrónico antes de enviarlo.'; + String get feedbackHint => + 'Se abrirá un correo electrónico preparado que podrá enviarnos. Si lo desea, se añadirá información sobre su dispositivo y la versión de la aplicación. Puede comprobar y editar el correo electrónico antes de enviarlo.'; @override String get feedbackPrivacyPolicy1 => 'Al enviar sus comentarios, acepta nuestra '; @@ -730,7 +749,8 @@ class AppLocalizationsEs extends AppLocalizations { String get noMailAppTitle => 'No hay aplicación de correo electrónico'; @override - String get noMailAppDescription => 'No hay ninguna app de correo electrónico instalada o inicializada en este dispositivo, inténtalo de nuevo cuando puedas enviar un mensaje de correo electrónico.'; + String get noMailAppDescription => + 'No hay ninguna app de correo electrónico instalada o inicializada en este dispositivo, inténtalo de nuevo cuando puedas enviar un mensaje de correo electrónico.'; @override String get authenticationRequest => 'Autenticación'; @@ -746,7 +766,8 @@ class AppLocalizationsEs extends AppLocalizations { } @override - String get pleaseSyncManuallyWhenNetworkIsAvailable => 'Por favor, sincronice los tokens push manualmente a través de los ajustes cuando haya una conexión de red disponible.'; + String get pleaseSyncManuallyWhenNetworkIsAvailable => + 'Por favor, sincronice los tokens push manualmente a través de los ajustes cuando haya una conexión de red disponible.'; @override String get pushTokens => 'Push Tokens'; diff --git a/lib/l10n/app_localizations_fr.dart b/lib/l10n/app_localizations_fr.dart index f4fc25048..e35bf2af7 100644 --- a/lib/l10n/app_localizations_fr.dart +++ b/lib/l10n/app_localizations_fr.dart @@ -22,7 +22,8 @@ class AppLocalizationsFr extends AppLocalizations { String get patchNotesV4_3_1Improvement1 => 'Le scanner de codes QR a été amélioré.'; @override - String get patchNotesV4_3_0NewFeatures1 => 'Ajout de la prise en charge de l\'importation de jetons depuis Google, Aegis et 2FAS Authenticator. D\'autres sources d\'importation seront ajoutées à l\'avenir.'; + String get patchNotesV4_3_0NewFeatures1 => + 'Ajout de la prise en charge de l\'importation de jetons depuis Google, Aegis et 2FAS Authenticator. D\'autres sources d\'importation seront ajoutées à l\'avenir.'; @override String get patchNotesV4_3_0NewFeatures2 => 'Ajout d\'une option de retour d\'information dans les paramètres'; @@ -108,10 +109,12 @@ class AppLocalizationsFr extends AppLocalizations { } @override - String get confirmTokenDeletionHint => 'Il se peut que vous ne puissiez plus vous connecter si vous supprimez ce token.\nVeuillez vous assurer que vous pouvez vous connecter au compte associé sans ce token.'; + String get confirmTokenDeletionHint => + 'Il se peut que vous ne puissiez plus vous connecter si vous supprimez ce token.\nVeuillez vous assurer que vous pouvez vous connecter au compte associé sans ce token.'; @override - String get confirmFolderDeletionHint => 'La suppression d\'un dossier n\'a aucun effet sur les tokens qui s\'y trouvent.\nLes tokens sont déplacés dans la liste principale.'; + String get confirmFolderDeletionHint => + 'La suppression d\'un dossier n\'a aucun effet sur les tokens qui s\'y trouvent.\nLes tokens sont déplacés dans la liste principale.'; @override String get generatingPhonePart => 'Générer la part du téléphone'; @@ -149,7 +152,8 @@ class AppLocalizationsFr extends AppLocalizations { String get enablePolling => 'Activer l\'interrogation du serveur.'; @override - String get requestPushChallengesPeriodically => 'Demander des challenges push depuis le serveur périodiquement. Activer cette fonction si les challenges push ne sont pas reçus normalement.'; + String get requestPushChallengesPeriodically => + 'Demander des challenges push depuis le serveur périodiquement. Activer cette fonction si les challenges push ne sont pas reçus normalement.'; @override String get synchronizePushTokens => 'Synchoniser les jetons Push'; @@ -267,7 +271,8 @@ class AppLocalizationsFr extends AppLocalizations { String get goToSettingsButton => 'Aller aux paramètres'; @override - String get goToSettingsDescription => 'L\'authentification par identifiants ou biométrie n\'est pas configurée sur votre appareil. Veuillez le configurer dans les paramètres de l\'appareil.'; + String get goToSettingsDescription => + 'L\'authentification par identifiants ou biométrie n\'est pas configurée sur votre appareil. Veuillez le configurer dans les paramètres de l\'appareil.'; @override String get lockOut => 'L\'authentification biométrique est désactivée. Veuillez verrouiller et déverrouiller votre écran pour l\'activer.'; @@ -329,7 +334,8 @@ class AppLocalizationsFr extends AppLocalizations { String get send => 'Envoyer'; @override - String get sendErrorLogDescription => 'Un e-mail pré-rempli est créé.\nIl contient des informations sur l\'application, l\'erreur et le périphérique.\nVous pouvez modifier l\'e-mail avant de l\'envoyer.\nVous pouvez voir ici comment nous utilisons les informations:'; + String get sendErrorLogDescription => + 'Un e-mail pré-rempli est créé.\nIl contient des informations sur l\'application, l\'erreur et le périphérique.\nVous pouvez modifier l\'e-mail avant de l\'envoyer.\nVous pouvez voir ici comment nous utilisons les informations:'; @override String get showPrivacyPolicy => 'Afficher la déclaration de confidentialité'; @@ -356,7 +362,8 @@ class AppLocalizationsFr extends AppLocalizations { String get open => 'Ouvrir'; @override - String get sendErrorDialogBody => 'Une erreur inattendue est survenue dans l\'application. L\'information suivante peut être transmise aux développeurs par email afin d\'aider à corriger cette erreur dans le futur.'; + String get sendErrorDialogBody => + 'Une erreur inattendue est survenue dans l\'application. L\'information suivante peut être transmise aux développeurs par email afin d\'aider à corriger cette erreur dans le futur.'; @override String get noFbToken => 'Pas de jeton Firebase'; @@ -480,7 +487,8 @@ class AppLocalizationsFr extends AppLocalizations { String get grantCameraPermissionDialogContent => 'Veuillez accorder à la caméra l\'autorisation de scanner les codes QR'; @override - String get grantCameraPermissionDialogPermanentlyDenied => 'L\'autorisation de l\'appareil photo est refusée de manière permanente. Veuillez accorder l\'autorisation à l\'appareil photo dans les paramètres de votre téléphone.'; + String get grantCameraPermissionDialogPermanentlyDenied => + 'L\'autorisation de l\'appareil photo est refusée de manière permanente. Veuillez accorder l\'autorisation à l\'appareil photo dans les paramètres de votre téléphone.'; @override String get grantCameraPermissionDialogButton => 'Accorder l\'autorisation'; @@ -489,7 +497,8 @@ class AppLocalizationsFr extends AppLocalizations { String get decryptErrorTitle => 'Erreur de décryptage'; @override - String get decryptErrorContent => 'Malheureusement, l\'application n\'a pas pu décrypter vos jetons. Cela indique que la clé de cryptage est cassée. Vous pouvez réessayer ou supprimer les données de l\'application, ce qui supprimera les jetons dans l\'application.'; + String get decryptErrorContent => + 'Malheureusement, l\'application n\'a pas pu décrypter vos jetons. Cela indique que la clé de cryptage est cassée. Vous pouvez réessayer ou supprimer les données de l\'application, ce qui supprimera les jetons dans l\'application.'; @override String get decryptErrorButtonDelete => 'Supprimer'; @@ -507,7 +516,8 @@ class AppLocalizationsFr extends AppLocalizations { String get hidePushTokens => 'Hide push tokens'; @override - String get hidePushTokensDescription => 'Masquer les jetons de poussée de la liste des jetons. Cela ne supprimera pas les jetons et ils seront toujours visibles sur un écran séparé'; + String get hidePushTokensDescription => + 'Masquer les jetons de poussée de la liste des jetons. Cela ne supprimera pas les jetons et ils seront toujours visibles sur un écran séparé'; @override String get settingsGroupGeneral => 'Généralités'; @@ -519,7 +529,8 @@ class AppLocalizationsFr extends AppLocalizations { String get privacyPolicy => 'Politique de confidentialité'; @override - String get introScanQrCode => 'You can scan QR codes to add tokens.\nWe support every common Two-Factor-Authentication token and also the privacyIDEA tokens.'; + String get introScanQrCode => + 'You can scan QR codes to add tokens.\nWe support every common Two-Factor-Authentication token and also the privacyIDEA tokens.'; @override String get introAddTokenManually => 'Si vous ne souhaitez pas scanner un code QR, vous pouvez également ajouter des jetons manuellement.'; @@ -531,10 +542,12 @@ class AppLocalizationsFr extends AppLocalizations { String get introEditToken => 'Ici, vous pouvez modifier le nom du token et voir quelques détails'; @override - String get introLockToken => 'Pour améliorer encore la sécurité, vous pouvez verrouiller les tokens. Le token ne peut alors être utilisé qu\'après l\'authentification.'; + String get introLockToken => + 'Pour améliorer encore la sécurité, vous pouvez verrouiller les tokens. Le token ne peut alors être utilisé qu\'après l\'authentification.'; @override - String get introDragToken => 'Réorganisez vos jetons en appuyant dessus pendant quelques secondes, puis en les faisant glisser jusqu\'à la position souhaitée'; + String get introDragToken => + 'Réorganisez vos jetons en appuyant dessus pendant quelques secondes, puis en les faisant glisser jusqu\'à la position souhaitée'; @override String get introAddFolder => 'Vous pouvez créer des dossiers pour organiser vos jetons'; @@ -551,7 +564,8 @@ class AppLocalizationsFr extends AppLocalizations { } @override - String get legacySigningErrorMessage => 'Le token a été créé dans une version obsolète de l\'application, ce qui peut entraîner des problèmes d\'utilisation.\nIl est recommandé de créer un nouveau token push si le problème persiste !'; + String get legacySigningErrorMessage => + 'Le token a été créé dans une version obsolète de l\'application, ce qui peut entraîner des problèmes d\'utilisation.\nIl est recommandé de créer un nouveau token push si le problème persiste !'; @override String get selectImportSource => 'Sélectionner la source d\'importation'; @@ -658,10 +672,12 @@ class AppLocalizationsFr extends AppLocalizations { } @override - String get importHint2FAS => 'Choisissez votre sauvegarde 2FAS.\nSi vous n\'avez pas de sauvegarde, créez-en une dans l\'application 2FAS. Nous vous recommandons d\'utiliser un mot de passe'; + String get importHint2FAS => + 'Choisissez votre sauvegarde 2FAS.\nSi vous n\'avez pas de sauvegarde, créez-en une dans l\'application 2FAS. Nous vous recommandons d\'utiliser un mot de passe'; @override - String get importHintAegisBackupFile => 'Choisissez votre exportation Aegis (.JSON).\nSi vous n\'avez pas d\'exportation, veuillez en créer une via le menu Paramètres dans l\'application Aegis. Il est recommandé d\'utiliser un mot de passe'; + String get importHintAegisBackupFile => + 'Choisissez votre exportation Aegis (.JSON).\nSi vous n\'avez pas d\'exportation, veuillez en créer une via le menu Paramètres dans l\'application Aegis. Il est recommandé d\'utiliser un mot de passe'; @override String get importHintAegisQrScan => 'Scannez le code QR que vous recevez lorsque vous transférez des entrées depuis Aegis'; @@ -673,19 +689,24 @@ class AppLocalizationsFr extends AppLocalizations { String get importHintGoogleQrScan => 'Scannez le code QR que vous recevez lorsque vous exportez vos comptes depuis Google Authenticator'; @override - String get importHintGoogleQrFile => 'Sélectionnez un fichier image avec le code QR que vous obtenez lorsque vous exportez vos comptes depuis Google Authenticator.\n!! Notez qu\'il n\'est pas sûr d\'enregistrer le code QR sur votre appareil, car les jetons ne sont pas cryptés !!'; + String get importHintGoogleQrFile => + 'Sélectionnez un fichier image avec le code QR que vous obtenez lorsque vous exportez vos comptes depuis Google Authenticator.\n!! Notez qu\'il n\'est pas sûr d\'enregistrer le code QR sur votre appareil, car les jetons ne sont pas cryptés !!'; @override - String get importHintAuthenticatorProFile => 'Pour créer une sauvegarde de l\'application Authenticator Pro, accédez aux paramètres et appuyez sur \"Sauvegarde automatique\". Sélectionnez un emplacement de stockage et définissez un mot de passe. Puis appuyez sur \"Sauvegarder maintenant\" pour exporter les tokens.'; + String get importHintAuthenticatorProFile => + 'Pour créer une sauvegarde de l\'application Authenticator Pro, accédez aux paramètres et appuyez sur \"Sauvegarde automatique\". Sélectionnez un emplacement de stockage et définissez un mot de passe. Puis appuyez sur \"Sauvegarder maintenant\" pour exporter les tokens.'; @override - String get importHintFreeOtpPlusQrScan => 'Scannez le code QR que vous recevez lorsque vous appuyez sur les trois points dans la tuile du jeton et sélectionnez \"Partager le code QR\".'; + String get importHintFreeOtpPlusQrScan => + 'Scannez le code QR que vous recevez lorsque vous appuyez sur les trois points dans la tuile du jeton et sélectionnez \"Partager le code QR\".'; @override - String get importHintFreeOtpPlusFile => 'Pour créer une sauvegarde de l\'application FreeOTP+, appuyez sur les trois points dans le coin supérieur droit et sélectionnez \"Exporter\". Vous pouvez choisir entre les formats JSON et URI. Nous recommandons de supprimer la sauvegarde après l\'avoir importée, car elle n\'est pas cryptée.'; + String get importHintFreeOtpPlusFile => + 'Pour créer une sauvegarde de l\'application FreeOTP+, appuyez sur les trois points dans le coin supérieur droit et sélectionnez \"Exporter\". Vous pouvez choisir entre les formats JSON et URI. Nous recommandons de supprimer la sauvegarde après l\'avoir importée, car elle n\'est pas cryptée.'; @override - String get qrFileDecodeError => 'Il n\'a pas été possible de décoder le code QR à partir de l\'image sélectionnée, veuillez utiliser le scanner de code QR à la place'; + String get qrFileDecodeError => + 'Il n\'a pas été possible de décoder le code QR à partir de l\'image sélectionnée, veuillez utiliser le scanner de code QR à la place'; @override String get tokenLink => 'Lien vers le token'; @@ -700,7 +721,8 @@ class AppLocalizationsFr extends AppLocalizations { String get feedbackDescription => 'Si vous avez des questions, des suggestions ou des problèmes, n\'hésitez pas à nous en faire part'; @override - String get feedbackHint => 'Un e-mail prêt à l\'emploi s\'ouvre, que vous pouvez nous envoyer. Si vous le souhaitez, des informations sur votre appareil et la version de l\'application seront ajoutées. Vous pouvez vérifier et modifier l\'e-mail avant de l\'envoyer.'; + String get feedbackHint => + 'Un e-mail prêt à l\'emploi s\'ouvre, que vous pouvez nous envoyer. Si vous le souhaitez, des informations sur votre appareil et la version de l\'application seront ajoutées. Vous pouvez vérifier et modifier l\'e-mail avant de l\'envoyer.'; @override String get feedbackPrivacyPolicy1 => 'En envoyant le retour d\'information, vous acceptez notre '; @@ -730,7 +752,8 @@ class AppLocalizationsFr extends AppLocalizations { String get noMailAppTitle => 'Aucune application de messagerie trouvée'; @override - String get noMailAppDescription => 'Aucune application de messagerie n\'est installée ou initialisée sur cet appareil. Veuillez réessayer lorsque vous serez en mesure d\'envoyer un message électronique.'; + String get noMailAppDescription => + 'Aucune application de messagerie n\'est installée ou initialisée sur cet appareil. Veuillez réessayer lorsque vous serez en mesure d\'envoyer un message électronique.'; @override String get authenticationRequest => 'Authentification'; @@ -746,7 +769,8 @@ class AppLocalizationsFr extends AppLocalizations { } @override - String get pleaseSyncManuallyWhenNetworkIsAvailable => 'Veuillez synchroniser manuellement les jetons Push via les paramètres lorsqu\'une connexion réseau est disponible'; + String get pleaseSyncManuallyWhenNetworkIsAvailable => + 'Veuillez synchroniser manuellement les jetons Push via les paramètres lorsqu\'une connexion réseau est disponible'; @override String get pushTokens => 'Push Tokens'; diff --git a/lib/l10n/app_localizations_nl.dart b/lib/l10n/app_localizations_nl.dart index 33a4fcb63..d12f5c5e6 100644 --- a/lib/l10n/app_localizations_nl.dart +++ b/lib/l10n/app_localizations_nl.dart @@ -22,7 +22,8 @@ class AppLocalizationsNl extends AppLocalizations { String get patchNotesV4_3_1Improvement1 => 'De QR-code scanner is verbeterd.'; @override - String get patchNotesV4_3_0NewFeatures1 => 'Ondersteuning toegevoegd voor het importeren van tokens van Google, Aegis en 2FAS Authenticator. Meer importbronnen zullen in de toekomst worden toegevoegd.'; + String get patchNotesV4_3_0NewFeatures1 => + 'Ondersteuning toegevoegd voor het importeren van tokens van Google, Aegis en 2FAS Authenticator. Meer importbronnen zullen in de toekomst worden toegevoegd.'; @override String get patchNotesV4_3_0NewFeatures2 => 'Feedbackoptie toegevoegd aan de instellingen.'; @@ -108,10 +109,12 @@ class AppLocalizationsNl extends AppLocalizations { } @override - String get confirmTokenDeletionHint => 'U kunt mogelijk niet meer inloggen als u dit token verwijdert. Controleer of u zonder dit token kunt inloggen op het gekoppelde account.'; + String get confirmTokenDeletionHint => + 'U kunt mogelijk niet meer inloggen als u dit token verwijdert. Controleer of u zonder dit token kunt inloggen op het gekoppelde account.'; @override - String get confirmFolderDeletionHint => 'Het verwijderen van een map heeft geen effect op de tokens in de map. De tokens worden verplaatst naar de hoofdlijst.'; + String get confirmFolderDeletionHint => + 'Het verwijderen van een map heeft geen effect op de tokens in de map. De tokens worden verplaatst naar de hoofdlijst.'; @override String get generatingPhonePart => 'Genereren telefoon gedeelte'; @@ -329,7 +332,8 @@ class AppLocalizationsNl extends AppLocalizations { String get send => 'verzenden'; @override - String get sendErrorLogDescription => 'Er wordt een kant-en-klare e-mail gemaakt die informatie bevat over de app, de fout en het apparaat.\nJe kunt de e-mail bewerken voordat je hem verstuurt.\nJe kunt hier zien hoe we de informatie gebruiken:'; + String get sendErrorLogDescription => + 'Er wordt een kant-en-klare e-mail gemaakt die informatie bevat over de app, de fout en het apparaat.\nJe kunt de e-mail bewerken voordat je hem verstuurt.\nJe kunt hier zien hoe we de informatie gebruiken:'; @override String get showPrivacyPolicy => 'Privacybeleid tonen'; @@ -356,7 +360,8 @@ class AppLocalizationsNl extends AppLocalizations { String get open => 'Openen'; @override - String get sendErrorDialogBody => 'Een onverwachte fout heeft plaatsgevonden in de applicatie. De onderstaande informatie kan worden verstuurd naar de ontwikkelaars via e-mail om het probleem in de toekomst te voorkomen.'; + String get sendErrorDialogBody => + 'Een onverwachte fout heeft plaatsgevonden in de applicatie. De onderstaande informatie kan worden verstuurd naar de ontwikkelaars via e-mail om het probleem in de toekomst te voorkomen.'; @override String get noFbToken => 'Geen Firebase Token beschikbaar'; @@ -480,7 +485,8 @@ class AppLocalizationsNl extends AppLocalizations { String get grantCameraPermissionDialogContent => 'Geef de camera toestemming om QR-codes te scannen.'; @override - String get grantCameraPermissionDialogPermanentlyDenied => 'Cameratoestemming is permanent geweigerd. Geef de camera toestemming in de instellingen van uw telefoon.'; + String get grantCameraPermissionDialogPermanentlyDenied => + 'Cameratoestemming is permanent geweigerd. Geef de camera toestemming in de instellingen van uw telefoon.'; @override String get grantCameraPermissionDialogButton => 'Toestemming verlenen'; @@ -489,7 +495,8 @@ class AppLocalizationsNl extends AppLocalizations { String get decryptErrorTitle => 'Fout bij decoderen'; @override - String get decryptErrorContent => 'Helaas heeft de app je tokens niet kunnen decoderen. Dit geeft aan dat de coderingssleutel is verbroken. U kunt het opnieuw proberen of de app-gegevens verwijderen, waardoor de tokens in de app worden verwijderd.'; + String get decryptErrorContent => + 'Helaas heeft de app je tokens niet kunnen decoderen. Dit geeft aan dat de coderingssleutel is verbroken. U kunt het opnieuw proberen of de app-gegevens verwijderen, waardoor de tokens in de app worden verwijderd.'; @override String get decryptErrorButtonDelete => 'Verwijderen'; @@ -507,7 +514,8 @@ class AppLocalizationsNl extends AppLocalizations { String get hidePushTokens => 'Verberg push tokens'; @override - String get hidePushTokensDescription => 'Verberg push tokens uit de token lijst. Hierdoor worden de tokens niet verwijderd en blijven ze zichtbaar op een apart scherm.'; + String get hidePushTokensDescription => + 'Verberg push tokens uit de token lijst. Hierdoor worden de tokens niet verwijderd en blijven ze zichtbaar op een apart scherm.'; @override String get settingsGroupGeneral => 'Algemene informatie'; @@ -519,7 +527,8 @@ class AppLocalizationsNl extends AppLocalizations { String get privacyPolicy => 'Privacybeleid'; @override - String get introScanQrCode => 'Je kunt QR-codes scannen om tokens toe te voegen.We ondersteunen alle gangbare Two-Factor-Authenticatie tokens en ook de privacyIDEA tokens.'; + String get introScanQrCode => + 'Je kunt QR-codes scannen om tokens toe te voegen.We ondersteunen alle gangbare Two-Factor-Authenticatie tokens en ook de privacyIDEA tokens.'; @override String get introAddTokenManually => 'Als je geen QR-code wilt scannen, kun je tokens ook handmatig toevoegen.'; @@ -531,7 +540,8 @@ class AppLocalizationsNl extends AppLocalizations { String get introEditToken => 'Hier kun je de naam van het token bewerken en enkele details bekijken.'; @override - String get introLockToken => 'Om de beveiliging nog meer te verbeteren, kun je tokens vergrendelen.¨Dan kan het token alleen gebruikt worden na authenticatie.'; + String get introLockToken => + 'Om de beveiliging nog meer te verbeteren, kun je tokens vergrendelen.¨Dan kan het token alleen gebruikt worden na authenticatie.'; @override String get introDragToken => 'Reorganiseer je tokens door er een paar seconden op te drukken en het dan naar de gewenste positie te slepen.'; @@ -551,7 +561,8 @@ class AppLocalizationsNl extends AppLocalizations { } @override - String get legacySigningErrorMessage => 'Het token is aangemaakt in een verouderde versie van de app, wat kan leiden tot problemen bij het gebruik ervan.\nHet wordt aanbevolen om een nieuw push token aan te maken als het probleem zich blijft voordoen!'; + String get legacySigningErrorMessage => + 'Het token is aangemaakt in een verouderde versie van de app, wat kan leiden tot problemen bij het gebruik ervan.\nHet wordt aanbevolen om een nieuw push token aan te maken als het probleem zich blijft voordoen!'; @override String get selectImportSource => 'Selecteer importbron'; @@ -658,10 +669,12 @@ class AppLocalizationsNl extends AppLocalizations { } @override - String get importHint2FAS => 'Selecteer uw 2FAS-back-up. Als u geen back-up hebt, maak er dan een aan in de 2FAS-app. Wij raden u aan een wachtwoord te gebruiken.'; + String get importHint2FAS => + 'Selecteer uw 2FAS-back-up. Als u geen back-up hebt, maak er dan een aan in de 2FAS-app. Wij raden u aan een wachtwoord te gebruiken.'; @override - String get importHintAegisBackupFile => 'Selecteer uw Aegis-export (.JSON).Als u geen export hebt, maak er dan een aan via het instellingenmenu in de Aegis-app. Het gebruik van een wachtwoord wordt aanbevolen.'; + String get importHintAegisBackupFile => + 'Selecteer uw Aegis-export (.JSON).Als u geen export hebt, maak er dan een aan via het instellingenmenu in de Aegis-app. Het gebruik van een wachtwoord wordt aanbevolen.'; @override String get importHintAegisQrScan => 'Scan de QR-code die u ontvangt bij het overbrengen van items uit Aegis.'; @@ -673,19 +686,24 @@ class AppLocalizationsNl extends AppLocalizations { String get importHintGoogleQrScan => 'Scan de QR-code die u ontvangt wanneer u uw accounts exporteert vanuit Google Authenticator.'; @override - String get importHintGoogleQrFile => 'Selecteer een afbeeldingsbestand met de QR-code die u ontvangt wanneer u uw accounts exporteert vanuit Google Authenticator.\n!! Let op: het is niet veilig om de QR-code op je apparaat op te slaan, omdat de tokens niet versleuteld zijn !!'; + String get importHintGoogleQrFile => + 'Selecteer een afbeeldingsbestand met de QR-code die u ontvangt wanneer u uw accounts exporteert vanuit Google Authenticator.\n!! Let op: het is niet veilig om de QR-code op je apparaat op te slaan, omdat de tokens niet versleuteld zijn !!'; @override - String get importHintAuthenticatorProFile => 'Om een back-up te maken van de Authenticator Pro app, navigeer je naar de instellingen en tik je op \"Auto back-up\". Selecteer een opslaglocatie en stel een wachtwoord in. Druk vervolgens op \"Nu back-uppen\" om de tokens te exporteren.'; + String get importHintAuthenticatorProFile => + 'Om een back-up te maken van de Authenticator Pro app, navigeer je naar de instellingen en tik je op \"Auto back-up\". Selecteer een opslaglocatie en stel een wachtwoord in. Druk vervolgens op \"Nu back-uppen\" om de tokens te exporteren.'; @override - String get importHintFreeOtpPlusQrScan => 'Scan de QR-code die u ontvangt wanneer u op de drie stippen in de tegel van de token drukt en selecteer \"QR-code delen\".'; + String get importHintFreeOtpPlusQrScan => + 'Scan de QR-code die u ontvangt wanneer u op de drie stippen in de tegel van de token drukt en selecteer \"QR-code delen\".'; @override - String get importHintFreeOtpPlusFile => 'Om een back-up van de FreeOTP+ app te maken, tikt u op de drie puntjes in de rechterbovenhoek en selecteert u \"Exporteren\". U kunt kiezen tussen JSON en URI formaat. We raden u aan de back-up te verwijderen na het importeren, omdat deze niet versleuteld is.'; + String get importHintFreeOtpPlusFile => + 'Om een back-up van de FreeOTP+ app te maken, tikt u op de drie puntjes in de rechterbovenhoek en selecteert u \"Exporteren\". U kunt kiezen tussen JSON en URI formaat. We raden u aan de back-up te verwijderen na het importeren, omdat deze niet versleuteld is.'; @override - String get qrFileDecodeError => 'Het was niet mogelijk om de QR code te decoderen van de geselecteerde afbeelding, gebruik in plaats daarvan de QR code scanner.'; + String get qrFileDecodeError => + 'Het was niet mogelijk om de QR code te decoderen van de geselecteerde afbeelding, gebruik in plaats daarvan de QR code scanner.'; @override String get tokenLink => 'tokenlink'; @@ -700,7 +718,8 @@ class AppLocalizationsNl extends AppLocalizations { String get feedbackDescription => 'Als je vragen, suggesties of problemen hebt, laat het ons dan weten.'; @override - String get feedbackHint => 'Er wordt een kant-en-klare e-mail geopend die je naar ons kunt sturen. Indien gewenst wordt informatie over je apparaat en de versie van de applicatie toegevoegd. U kunt de e-mail controleren en bewerken voordat u deze verzendt.'; + String get feedbackHint => + 'Er wordt een kant-en-klare e-mail geopend die je naar ons kunt sturen. Indien gewenst wordt informatie over je apparaat en de versie van de applicatie toegevoegd. U kunt de e-mail controleren en bewerken voordat u deze verzendt.'; @override String get feedbackPrivacyPolicy1 => 'Door feedback te sturen ga je akkoord met ons '; @@ -730,7 +749,8 @@ class AppLocalizationsNl extends AppLocalizations { String get noMailAppTitle => 'Geen mail app gevonden'; @override - String get noMailAppDescription => 'Er is geen e-mail app geïnstalleerd of geïnitialiseerd op dit apparaat, probeer het opnieuw wanneer u in staat bent om een e-mailbericht te verzenden.'; + String get noMailAppDescription => + 'Er is geen e-mail app geïnstalleerd of geïnitialiseerd op dit apparaat, probeer het opnieuw wanneer u in staat bent om een e-mailbericht te verzenden.'; @override String get authenticationRequest => 'Verificatieverzoek'; @@ -746,7 +766,8 @@ class AppLocalizationsNl extends AppLocalizations { } @override - String get pleaseSyncManuallyWhenNetworkIsAvailable => 'Synchroniseer de push tokens handmatig via de instellingen als er een netwerkverbinding beschikbaar is.'; + String get pleaseSyncManuallyWhenNetworkIsAvailable => + 'Synchroniseer de push tokens handmatig via de instellingen als er een netwerkverbinding beschikbaar is.'; @override String get pushTokens => 'Push Tokens'; diff --git a/lib/l10n/app_localizations_pl.dart b/lib/l10n/app_localizations_pl.dart index 7f1534c50..e962f0c4b 100644 --- a/lib/l10n/app_localizations_pl.dart +++ b/lib/l10n/app_localizations_pl.dart @@ -22,7 +22,8 @@ class AppLocalizationsPl extends AppLocalizations { String get patchNotesV4_3_1Improvement1 => 'Został poprawiony skaner kodów QR.'; @override - String get patchNotesV4_3_0NewFeatures1 => 'Dodano obsługę importowania tokenów z Google, Aegis i 2FAS Authenticator. Więcej źródeł importu zostanie dodanych w przyszłości'; + String get patchNotesV4_3_0NewFeatures1 => + 'Dodano obsługę importowania tokenów z Google, Aegis i 2FAS Authenticator. Więcej źródeł importu zostanie dodanych w przyszłości'; @override String get patchNotesV4_3_0NewFeatures2 => 'Dodano opcję opinii do ustawień.'; @@ -108,7 +109,8 @@ class AppLocalizationsPl extends AppLocalizations { } @override - String get confirmTokenDeletionHint => 'Usunięcie tego tokenu może uniemożliwić zalogowanie się. Upewnij się, że możesz zalogować się na powiązane konto bez tego tokenu.'; + String get confirmTokenDeletionHint => + 'Usunięcie tego tokenu może uniemożliwić zalogowanie się. Upewnij się, że możesz zalogować się na powiązane konto bez tego tokenu.'; @override String get confirmFolderDeletionHint => 'Usunięcie folderu nie ma wpływu na znajdujące się w nim tokeny. Tokeny są przenoszone do głównej listy.'; @@ -267,7 +269,8 @@ class AppLocalizationsPl extends AppLocalizations { String get goToSettingsButton => 'Idź do ustawień'; @override - String get goToSettingsDescription => 'Ustawienia zabezpieczeń, bądź uwierzytelnianie biometryczne nie są skonfigurowane w twoim urządzeniu. Skonfiguruj je w ustawieniach urządzenia.'; + String get goToSettingsDescription => + 'Ustawienia zabezpieczeń, bądź uwierzytelnianie biometryczne nie są skonfigurowane w twoim urządzeniu. Skonfiguruj je w ustawieniach urządzenia.'; @override String get lockOut => 'Uwierzytelnianie biometryczne jest wyłączone. Zablokuj i odblokuj ponownie ekran, żeby je włączyć.'; @@ -329,7 +332,8 @@ class AppLocalizationsPl extends AppLocalizations { String get send => 'Wyślij'; @override - String get sendErrorLogDescription => 'Tworzona jest gotowa wiadomość e-mail zawierająca informacje o aplikacji, błędzie i urządzeniu.\nMożesz edytować wiadomość e-mail przed jej wysłaniem.\nTutaj można zobaczyć, w jaki sposób wykorzystujemy te informacje:'; + String get sendErrorLogDescription => + 'Tworzona jest gotowa wiadomość e-mail zawierająca informacje o aplikacji, błędzie i urządzeniu.\nMożesz edytować wiadomość e-mail przed jej wysłaniem.\nTutaj można zobaczyć, w jaki sposób wykorzystujemy te informacje:'; @override String get showPrivacyPolicy => 'Pokaż politykę prywatności'; @@ -356,7 +360,8 @@ class AppLocalizationsPl extends AppLocalizations { String get open => 'Otwórz'; @override - String get sendErrorDialogBody => 'Napotkano nieoczekiwany błąd w aplikacji. Poniższa wiadomość może zostać wysłana do deweloperów poprzez email, żeby pomóc uniknąć tego problemu w przyszłości.'; + String get sendErrorDialogBody => + 'Napotkano nieoczekiwany błąd w aplikacji. Poniższa wiadomość może zostać wysłana do deweloperów poprzez email, żeby pomóc uniknąć tego problemu w przyszłości.'; @override String get noFbToken => 'Brak dostępnego tokena Firebase'; @@ -480,7 +485,8 @@ class AppLocalizationsPl extends AppLocalizations { String get grantCameraPermissionDialogContent => 'Przyznaj uprawnienia kamery do skanowania kodów QR.'; @override - String get grantCameraPermissionDialogPermanentlyDenied => 'Uprawnienia do aparatu zostały trwale zablokowane. Przyznaj uprawnienia aparatu w ustawieniach telefonu.'; + String get grantCameraPermissionDialogPermanentlyDenied => + 'Uprawnienia do aparatu zostały trwale zablokowane. Przyznaj uprawnienia aparatu w ustawieniach telefonu.'; @override String get grantCameraPermissionDialogButton => 'Grant permission'; @@ -489,7 +495,8 @@ class AppLocalizationsPl extends AppLocalizations { String get decryptErrorTitle => 'Decryption error'; @override - String get decryptErrorContent => 'Niestety, aplikacja nie była w stanie odszyfrować tokenów. Oznacza to, że klucz szyfrowania jest uszkodzony. Możesz spróbować ponownie lub usunąć dane aplikacji, co spowoduje usunięcie tokenów w aplikacji.'; + String get decryptErrorContent => + 'Niestety, aplikacja nie była w stanie odszyfrować tokenów. Oznacza to, że klucz szyfrowania jest uszkodzony. Możesz spróbować ponownie lub usunąć dane aplikacji, co spowoduje usunięcie tokenów w aplikacji.'; @override String get decryptErrorButtonDelete => 'Usuń'; @@ -519,7 +526,8 @@ class AppLocalizationsPl extends AppLocalizations { String get privacyPolicy => 'Polityka prywatności'; @override - String get introScanQrCode => 'Możesz skanować kody QR, aby dodawać tokeny. Obsługujemy każdy popularny token uwierzytelniania dwuskładnikowego, a także tokeny privacyIDEA.'; + String get introScanQrCode => + 'Możesz skanować kody QR, aby dodawać tokeny. Obsługujemy każdy popularny token uwierzytelniania dwuskładnikowego, a także tokeny privacyIDEA.'; @override String get introAddTokenManually => 'Jeśli nie chcesz skanować kodu QR, możesz również dodać tokeny ręcznie.'; @@ -531,7 +539,8 @@ class AppLocalizationsPl extends AppLocalizations { String get introEditToken => 'Tutaj możesz edytować nazwę tokena i zobaczyć kilka szczegółów.'; @override - String get introLockToken => 'Aby jeszcze bardziej zwiększyć bezpieczeństwo, możesz zablokować tokeny. Wtedy token może być używany tylko po uwierzytelnieniu.'; + String get introLockToken => + 'Aby jeszcze bardziej zwiększyć bezpieczeństwo, możesz zablokować tokeny. Wtedy token może być używany tylko po uwierzytelnieniu.'; @override String get introDragToken => 'Reorganizuj swoje tokeny, naciskając je przez kilka sekund, a następnie przeciągając je do żądanej pozycji.'; @@ -551,7 +560,8 @@ class AppLocalizationsPl extends AppLocalizations { } @override - String get legacySigningErrorMessage => 'Token został utworzony w nieaktualnej wersji aplikacji, co może prowadzić do problemów podczas korzystania z niego.\nZaleca się utworzenie nowego tokena push, jeśli problem nadal występuje!'; + String get legacySigningErrorMessage => + 'Token został utworzony w nieaktualnej wersji aplikacji, co może prowadzić do problemów podczas korzystania z niego.\nZaleca się utworzenie nowego tokena push, jeśli problem nadal występuje!'; @override String get selectImportSource => 'Wybierz źródło importu'; @@ -661,7 +671,8 @@ class AppLocalizationsPl extends AppLocalizations { String get importHint2FAS => 'Wybierz kopię zapasową 2FAS. Jeśli nie masz kopii zapasowej, utwórz ją w aplikacji 2FAS. Zalecamy użycie hasła.'; @override - String get importHintAegisBackupFile => 'Wybierz swój eksport Aegis (.JSON).\nJeśli nie masz eksportu, utwórz go za pomocą menu ustawień w aplikacji Aegis. Zalecane jest użycie hasła.'; + String get importHintAegisBackupFile => + 'Wybierz swój eksport Aegis (.JSON).\nJeśli nie masz eksportu, utwórz go za pomocą menu ustawień w aplikacji Aegis. Zalecane jest użycie hasła.'; @override String get importHintAegisQrScan => 'Zeskanuj kod QR otrzymany podczas przesyłania wpisów z Aegis'; @@ -673,16 +684,19 @@ class AppLocalizationsPl extends AppLocalizations { String get importHintGoogleQrScan => 'Zeskanuj kod QR otrzymany podczas eksportowania kont z Google Authenticator'; @override - String get importHintGoogleQrFile => 'Wybierz plik obrazu z kodem QR otrzymanym podczas eksportowania kont z Google Authenticator.\n!! Należy pamiętać, że zapisywanie kodu QR na urządzeniu nie jest bezpieczne, ponieważ tokeny nie są szyfrowane !!'; + String get importHintGoogleQrFile => + 'Wybierz plik obrazu z kodem QR otrzymanym podczas eksportowania kont z Google Authenticator.\n!! Należy pamiętać, że zapisywanie kodu QR na urządzeniu nie jest bezpieczne, ponieważ tokeny nie są szyfrowane !!'; @override - String get importHintAuthenticatorProFile => 'Aby utworzyć kopię zapasową aplikacji Authenticator Pro, przejdź do ustawień i dotknij \"Automatyczna kopia zapasowa\". Wybierz lokalizację przechowywania i ustaw hasło. Następnie naciśnij \"Utwórz teraz kopię zapasową\", aby wyeksportować tokeny.'; + String get importHintAuthenticatorProFile => + 'Aby utworzyć kopię zapasową aplikacji Authenticator Pro, przejdź do ustawień i dotknij \"Automatyczna kopia zapasowa\". Wybierz lokalizację przechowywania i ustaw hasło. Następnie naciśnij \"Utwórz teraz kopię zapasową\", aby wyeksportować tokeny.'; @override String get importHintFreeOtpPlusQrScan => 'Zeskanuj kod QR otrzymany po naciśnięciu trzech kropek na kafelku tokena i wybierz \"Udostępnij kod QR\".'; @override - String get importHintFreeOtpPlusFile => 'Aby utworzyć kopię zapasową aplikacji FreeOTP+, dotknij trzech kropek w prawym górnym rogu i wybierz \"Eksportuj\". Można wybrać format JSON lub URI. Zalecamy usunięcie kopii zapasowej po jej zaimportowaniu, ponieważ nie jest ona szyfrowana.'; + String get importHintFreeOtpPlusFile => + 'Aby utworzyć kopię zapasową aplikacji FreeOTP+, dotknij trzech kropek w prawym górnym rogu i wybierz \"Eksportuj\". Można wybrać format JSON lub URI. Zalecamy usunięcie kopii zapasowej po jej zaimportowaniu, ponieważ nie jest ona szyfrowana.'; @override String get qrFileDecodeError => 'Nie można było zdekodować kodu QR z wybranego obrazu, zamiast tego użyj skanera kodów QR.'; @@ -700,7 +714,8 @@ class AppLocalizationsPl extends AppLocalizations { String get feedbackDescription => 'Jeśli masz jakieś pytania, sugestie lub problemy, daj nam znać.'; @override - String get feedbackHint => 'Otworzy się gotowa wiadomość e-mail, którą możesz do nas wysłać. W razie potrzeby dodane zostaną informacje o urządzeniu i wersji aplikacji. Możesz sprawdzić i edytować wiadomość e-mail przed jej wysłaniem.'; + String get feedbackHint => + 'Otworzy się gotowa wiadomość e-mail, którą możesz do nas wysłać. W razie potrzeby dodane zostaną informacje o urządzeniu i wersji aplikacji. Możesz sprawdzić i edytować wiadomość e-mail przed jej wysłaniem.'; @override String get feedbackPrivacyPolicy1 => 'Wysyłając opinię, zgadzasz się z naszą '; @@ -730,7 +745,8 @@ class AppLocalizationsPl extends AppLocalizations { String get noMailAppTitle => 'Nie znaleziono aplikacji pocztowej'; @override - String get noMailAppDescription => 'Na tym urządzeniu nie zainstalowano ani nie zainicjowano aplikacji poczty e-mail, spróbuj ponownie, gdy będziesz w stanie wysłać wiadomość e-mail'; + String get noMailAppDescription => + 'Na tym urządzeniu nie zainstalowano ani nie zainicjowano aplikacji poczty e-mail, spróbuj ponownie, gdy będziesz w stanie wysłać wiadomość e-mail'; @override String get authenticationRequest => 'Żądanie uwierzytelnienia'; diff --git a/lib/l10n/app_nl.arb b/lib/l10n/app_nl.arb index 561c50c34..799b4e33e 100644 --- a/lib/l10n/app_nl.arb +++ b/lib/l10n/app_nl.arb @@ -642,5 +642,9 @@ "example": "Name" } } + }, + "sendPushRequestResponseFailed": "Het verzenden van het antwoord is mislukt. ", + "@sendPushRequestResponseFailed": { + "description": "Error message when the response to a push request could not be sent." } } \ No newline at end of file diff --git a/lib/l10n/app_pl.arb b/lib/l10n/app_pl.arb index 25b267262..cc4a23449 100644 --- a/lib/l10n/app_pl.arb +++ b/lib/l10n/app_pl.arb @@ -639,5 +639,9 @@ "example": "Name" } } + }, + "sendPushRequestResponseFailed": "Nie udało się wysłać odpowiedzi.", + "@sendPushRequestResponseFailed": { + "description": "Error message when the response to a push request could not be sent." } } \ No newline at end of file diff --git a/lib/mains/main_customizer.dart b/lib/mains/main_customizer.dart index f11979325..7e31c8ce6 100644 --- a/lib/mains/main_customizer.dart +++ b/lib/mains/main_customizer.dart @@ -22,19 +22,19 @@ import 'package:easy_dynamic_theme/easy_dynamic_theme.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:privacyidea_authenticator/l10n/app_localizations.dart'; -import 'package:privacyidea_authenticator/utils/globals.dart'; -import 'package:privacyidea_authenticator/utils/logger.dart'; -import 'package:privacyidea_authenticator/utils/riverpod_providers.dart'; -import 'package:privacyidea_authenticator/views/add_token_manually_view/add_token_manually_view.dart'; -import 'package:privacyidea_authenticator/views/license_view/license_view.dart'; -import 'package:privacyidea_authenticator/views/main_view/main_view.dart'; -import 'package:privacyidea_authenticator/views/qr_scanner_view/qr_scanner_view.dart'; -import 'package:privacyidea_authenticator/views/settings_view/settings_view.dart'; -import 'package:privacyidea_authenticator/views/splash_screen/splash_screen.dart'; -import 'package:privacyidea_authenticator/widgets/app_wrapper.dart'; +import '../l10n/app_localizations.dart'; import '../model/enums/app_feature.dart'; +import '../utils/globals.dart'; +import '../utils/logger.dart'; +import '../utils/riverpod_providers.dart'; +import '../views/add_token_manually_view/add_token_manually_view.dart'; +import '../views/license_view/license_view.dart'; +import '../views/main_view/main_view.dart'; +import '../views/qr_scanner_view/qr_scanner_view.dart'; +import '../views/settings_view/settings_view.dart'; +import '../views/splash_screen/splash_screen.dart'; +import '../widgets/app_wrapper.dart'; void main() async { Logger.init( diff --git a/lib/model/extensions/sortable_list.dart b/lib/model/extensions/sortable_list.dart index 1c32c896b..eee5374b5 100644 --- a/lib/model/extensions/sortable_list.dart +++ b/lib/model/extensions/sortable_list.dart @@ -4,11 +4,6 @@ extension SortableList on List { List get sorted { var list = List.from(this); list.sort((a, b) => a.compareTo(b)); - print('-----------------------------------'); - list.forEach((element) { - print('sorted: ${element.runtimeType} Sortindex: ${element.sortIndex}'); - }); - print('-----------------------------------'); return list; } @@ -25,11 +20,6 @@ extension SortableList on List { list[i] = list[i].copyWith(sortIndex: highestIndex) as T; } } - print('-----------------------------------'); - list.forEach((element) { - print('fillNullIndices: ${element.runtimeType} Sortindex: ${element.sortIndex}'); - }); - print('-----------------------------------'); return list; } @@ -47,11 +37,6 @@ extension SortableList on List { : list.length; list.insert(newIndex, movedItem); list = list.withCurrentSortIndexSet(); - print('-----------------------------------'); - list.forEach((element) { - print('moveBetween: ${element.runtimeType} Sortindex: ${element.sortIndex}'); - }); - print('-----------------------------------'); return list; } diff --git a/lib/model/push_request.dart b/lib/model/push_request.dart index 6c7fa0dee..4a711c5ce 100644 --- a/lib/model/push_request.dart +++ b/lib/model/push_request.dart @@ -24,6 +24,8 @@ class PushRequest { final String serial; final String signature; final bool? accepted; + final List? possibleAnswers; + final String? selectedAnswer; const PushRequest({ required this.title, @@ -36,6 +38,8 @@ class PushRequest { this.serial = '', this.signature = '', this.accepted, + this.possibleAnswers, + this.selectedAnswer, }); PushRequest copyWith({ @@ -49,6 +53,8 @@ class PushRequest { String? serial, String? signature, bool? accepted, + List Function()? answers, + String? Function()? selectedAnswer, }) { return PushRequest( title: title ?? this.title, @@ -61,6 +67,8 @@ class PushRequest { serial: serial ?? this.serial, signature: signature ?? this.signature, accepted: accepted ?? this.accepted, + possibleAnswers: answers != null ? answers() : this.possibleAnswers, + selectedAnswer: selectedAnswer != null ? selectedAnswer() : this.selectedAnswer, ); } @@ -75,7 +83,8 @@ class PushRequest { return 'PushRequest{title: $title, question: $question, ' 'id: $id, uri: $uri, _nonce: $nonce, sslVerify: $sslVerify, ' 'expirationDate: $expirationDate, serial: $serial, ' - 'signature: $signature, accepted: $accepted}'; + 'signature: $signature, accepted: $accepted, ' + 'answers: $possibleAnswers, selectedAnswer: $selectedAnswer}'; } factory PushRequest.fromJson(Map json) => _$PushRequestFromJson(json); @@ -98,6 +107,7 @@ class PushRequest { serial: data[PUSH_REQUEST_SERIAL], expirationDate: DateTime.now().add(const Duration(minutes: 2)), signature: data[PUSH_REQUEST_SIGNATURE], + possibleAnswers: data[PUSH_REQUEST_ANSWERS] != null ? (data[PUSH_REQUEST_ANSWERS] as String).split(',') : null, ); } @@ -127,16 +137,22 @@ class PushRequest { if (data[PUSH_REQUEST_SIGNATURE] is! String) { throw ArgumentError('Push request signature is ${data[PUSH_REQUEST_SIGNATURE].runtimeType}. Expected String.'); } + if (data[PUSH_REQUEST_ANSWERS] is! String?) { + throw ArgumentError('Push request answers is ${data[PUSH_REQUEST_ANSWERS].runtimeType}. Expected List or null.'); + } } Future verifySignature(PushToken token, {LegacyUtils legacyUtils = const LegacyUtils(), RsaUtils rsaUtils = const RsaUtils()}) async { + //5NV6KJCFCLNQURT2ZTBRHHGY6FDXOCOR|http://192.168.178.22:5000/ttype/push|PIPU0000E793|Pick a Number!|privacyIDEA|0|["A", "B", "C"] Logger.info('Adding push request to token', name: 'push_request_notifier.dart#newRequest'); String signedData = '$nonce|' '$uri|' '$serial|' '$question|' '$title|' - '${sslVerify ? '1' : '0'}'; + '${sslVerify ? '1' : '0'}' + '${possibleAnswers != null ? '|${possibleAnswers!.join(",")}' : ''}'; + Logger.warning('Signed data: $signedData', name: 'push_request_notifier.dart#newRequest'); // Re-add url and sslverify to android legacy tokens: if (token.url == null) { diff --git a/lib/model/push_request.g.dart b/lib/model/push_request.g.dart index 5d2b4d409..1d6977b67 100644 --- a/lib/model/push_request.g.dart +++ b/lib/model/push_request.g.dart @@ -17,10 +17,11 @@ PushRequest _$PushRequestFromJson(Map json) => PushRequest( serial: json['serial'] as String? ?? '', signature: json['signature'] as String? ?? '', accepted: json['accepted'] as bool?, + possibleAnswers: (json['answers'] as List?)?.map((e) => e as String).toList(), + selectedAnswer: (json['selectedAnswer'] as String?), ); -Map _$PushRequestToJson(PushRequest instance) => - { +Map _$PushRequestToJson(PushRequest instance) => { 'title': instance.title, 'question': instance.question, 'id': instance.id, @@ -31,4 +32,6 @@ Map _$PushRequestToJson(PushRequest instance) => 'serial': instance.serial, 'signature': instance.signature, 'accepted': instance.accepted, + 'answers': instance.possibleAnswers, + 'selectedAnswer': instance.selectedAnswer, }; diff --git a/lib/processors/scheme_processors/token_import_scheme_processors/google_authenticator_qr_processor.dart b/lib/processors/scheme_processors/token_import_scheme_processors/google_authenticator_qr_processor.dart index a08006057..b1b3e24df 100644 --- a/lib/processors/scheme_processors/token_import_scheme_processors/google_authenticator_qr_processor.dart +++ b/lib/processors/scheme_processors/token_import_scheme_processors/google_authenticator_qr_processor.dart @@ -5,8 +5,8 @@ import 'dart:convert'; import 'dart:typed_data'; import 'package:base32/base32.dart'; -import 'package:privacyidea_authenticator/model/extensions/enums/token_origin_source_type.dart'; -import 'package:privacyidea_authenticator/utils/logger.dart'; +import '../../../model/extensions/enums/token_origin_source_type.dart'; +import '../../../utils/logger.dart'; import '../../../model/enums/token_origin_source_type.dart'; import '../../../model/processor_result.dart'; diff --git a/lib/processors/token_import_file_processor/aegis_import_file_processor.dart b/lib/processors/token_import_file_processor/aegis_import_file_processor.dart index 1fe1eb875..eb428c2ce 100644 --- a/lib/processors/token_import_file_processor/aegis_import_file_processor.dart +++ b/lib/processors/token_import_file_processor/aegis_import_file_processor.dart @@ -8,20 +8,20 @@ import 'package:cryptography/cryptography.dart' as crypto; import 'package:encrypt/encrypt.dart'; import 'package:file_selector/file_selector.dart'; import 'package:pointycastle/export.dart'; -import 'package:privacyidea_authenticator/model/enums/encodings.dart'; -import 'package:privacyidea_authenticator/model/enums/token_origin_source_type.dart'; -import 'package:privacyidea_authenticator/model/enums/token_types.dart'; -import 'package:privacyidea_authenticator/model/extensions/enums/encodings_extension.dart'; -import 'package:privacyidea_authenticator/model/extensions/enums/token_origin_source_type.dart'; -import 'package:privacyidea_authenticator/model/tokens/token.dart'; -import 'package:privacyidea_authenticator/utils/identifiers.dart'; -import 'package:privacyidea_authenticator/utils/logger.dart'; -import 'package:privacyidea_authenticator/utils/token_import_origins.dart'; import '../../l10n/app_localizations.dart'; +import '../../model/enums/encodings.dart'; +import '../../model/enums/token_origin_source_type.dart'; +import '../../model/enums/token_types.dart'; +import '../../model/extensions/enums/encodings_extension.dart'; +import '../../model/extensions/enums/token_origin_source_type.dart'; import '../../model/processor_result.dart'; +import '../../model/tokens/token.dart'; import '../../utils/errors.dart'; import '../../utils/globals.dart'; +import '../../utils/identifiers.dart'; +import '../../utils/logger.dart'; +import '../../utils/token_import_origins.dart'; import '../../utils/utils.dart'; import 'token_import_file_processor_interface.dart'; import 'two_fas_import_file_processor.dart'; diff --git a/lib/processors/token_import_file_processor/authenticator_pro_import_file_processor.dart b/lib/processors/token_import_file_processor/authenticator_pro_import_file_processor.dart index c8a260444..f8fe04004 100644 --- a/lib/processors/token_import_file_processor/authenticator_pro_import_file_processor.dart +++ b/lib/processors/token_import_file_processor/authenticator_pro_import_file_processor.dart @@ -4,17 +4,17 @@ import 'dart:convert'; import 'package:cryptography/cryptography.dart'; import 'package:file_selector/file_selector.dart'; -import 'package:privacyidea_authenticator/model/enums/algorithms.dart'; -import 'package:privacyidea_authenticator/model/enums/encodings.dart'; -import 'package:privacyidea_authenticator/model/enums/token_types.dart'; -import 'package:privacyidea_authenticator/model/extensions/enums/encodings_extension.dart'; -import 'package:privacyidea_authenticator/model/extensions/enums/token_origin_source_type.dart'; -import 'package:privacyidea_authenticator/model/tokens/token.dart'; -import 'package:privacyidea_authenticator/processors/scheme_processors/token_import_scheme_processors/otp_auth_processor.dart'; -import 'package:privacyidea_authenticator/processors/token_import_file_processor/two_fas_import_file_processor.dart'; -import 'package:privacyidea_authenticator/utils/identifiers.dart'; -import 'package:privacyidea_authenticator/utils/logger.dart'; -import 'package:privacyidea_authenticator/utils/token_import_origins.dart'; +import '../../model/enums/algorithms.dart'; +import '../../model/enums/encodings.dart'; +import '../../model/enums/token_types.dart'; +import '../../model/extensions/enums/encodings_extension.dart'; +import '../../model/extensions/enums/token_origin_source_type.dart'; +import '../../model/tokens/token.dart'; +import '../../processors/scheme_processors/token_import_scheme_processors/otp_auth_processor.dart'; +import '../../processors/token_import_file_processor/two_fas_import_file_processor.dart'; +import '../../utils/identifiers.dart'; +import '../../utils/logger.dart'; +import '../../utils/token_import_origins.dart'; import '../../l10n/app_localizations.dart'; import '../../model/encryption/aes_encrypted.dart'; diff --git a/lib/processors/token_import_file_processor/free_otp_plus_import_file_processor.dart b/lib/processors/token_import_file_processor/free_otp_plus_import_file_processor.dart index 587484185..922262da5 100644 --- a/lib/processors/token_import_file_processor/free_otp_plus_import_file_processor.dart +++ b/lib/processors/token_import_file_processor/free_otp_plus_import_file_processor.dart @@ -4,16 +4,16 @@ import 'dart:convert'; import 'dart:typed_data'; import 'package:file_selector/file_selector.dart'; -import 'package:privacyidea_authenticator/l10n/app_localizations.dart'; -import 'package:privacyidea_authenticator/model/enums/token_origin_source_type.dart'; -import 'package:privacyidea_authenticator/model/extensions/enums/token_origin_source_type.dart'; -import 'package:privacyidea_authenticator/model/processor_result.dart'; -import 'package:privacyidea_authenticator/model/tokens/token.dart'; -import 'package:privacyidea_authenticator/utils/globals.dart'; -import 'package:privacyidea_authenticator/utils/logger.dart'; +import '../../l10n/app_localizations.dart'; +import '../../model/enums/token_origin_source_type.dart'; +import '../../model/extensions/enums/token_origin_source_type.dart'; +import '../../model/processor_result.dart'; +import '../../model/tokens/token.dart'; import '../../utils/errors.dart'; +import '../../utils/globals.dart'; import '../../utils/identifiers.dart'; +import '../../utils/logger.dart'; import '../../utils/token_import_origins.dart'; import '../scheme_processors/token_import_scheme_processors/free_otp_plus_qr_processor.dart'; import 'token_import_file_processor_interface.dart'; diff --git a/lib/processors/token_import_file_processor/two_fas_import_file_processor.dart b/lib/processors/token_import_file_processor/two_fas_import_file_processor.dart index aa361c37d..dc225f4ba 100644 --- a/lib/processors/token_import_file_processor/two_fas_import_file_processor.dart +++ b/lib/processors/token_import_file_processor/two_fas_import_file_processor.dart @@ -4,20 +4,20 @@ import 'dart:convert'; import 'package:cryptography/cryptography.dart'; import 'package:file_selector/file_selector.dart'; -import 'package:privacyidea_authenticator/model/extensions/enums/encodings_extension.dart'; -import 'package:privacyidea_authenticator/model/extensions/enums/token_origin_source_type.dart'; -import 'package:privacyidea_authenticator/utils/token_import_origins.dart'; import '../../l10n/app_localizations.dart'; import '../../model/encryption/aes_encrypted.dart'; import '../../model/enums/encodings.dart'; import '../../model/enums/token_origin_source_type.dart'; +import '../../model/extensions/enums/encodings_extension.dart'; +import '../../model/extensions/enums/token_origin_source_type.dart'; import '../../model/processor_result.dart'; import '../../model/tokens/token.dart'; import '../../utils/errors.dart'; import '../../utils/globals.dart'; import '../../utils/identifiers.dart'; import '../../utils/logger.dart'; +import '../../utils/token_import_origins.dart'; import 'token_import_file_processor_interface.dart'; class TwoFasAuthenticatorImportFileProcessor extends TokenImportFileProcessor { diff --git a/lib/repo/secure_token_repository.dart b/lib/repo/secure_token_repository.dart index eb878bfe7..073ca5145 100644 --- a/lib/repo/secure_token_repository.dart +++ b/lib/repo/secure_token_repository.dart @@ -27,14 +27,14 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:mutex/mutex.dart'; -import 'package:privacyidea_authenticator/interfaces/repo/token_repository.dart'; -import 'package:privacyidea_authenticator/l10n/app_localizations.dart'; -import 'package:privacyidea_authenticator/model/tokens/token.dart'; -import 'package:privacyidea_authenticator/utils/logger.dart'; -import 'package:privacyidea_authenticator/utils/riverpod_providers.dart'; -import 'package:privacyidea_authenticator/utils/view_utils.dart'; +import '../interfaces/repo/token_repository.dart'; +import '../l10n/app_localizations.dart'; +import '../model/tokens/token.dart'; import '../utils/identifiers.dart'; +import '../utils/logger.dart'; +import '../utils/riverpod_providers.dart'; +import '../utils/view_utils.dart'; import '../views/settings_view/settings_view_widgets/send_error_dialog.dart'; import '../widgets/dialog_widgets/default_dialog.dart'; import '../widgets/dialog_widgets/default_dialog_button.dart'; @@ -100,9 +100,6 @@ class SecureTokenRepository implements TokenRepository { } if (valueJson == null || !valueJson.containsKey('type')) { - Logger.warning( - 'Could not deserialize token from secure storage. Value: $value\nserializedToken = $valueJson\ncontainsKey(type) = ${valueJson?.containsKey('type')} ', - name: 'secure_token_repository.dart#loadAllTokens'); // If valueJson is null or does not contain a type, it can't be a token. Skip it. continue; } diff --git a/lib/state_notifiers/push_request_notifier.dart b/lib/state_notifiers/push_request_notifier.dart index 67eb6e5f1..0510025bd 100644 --- a/lib/state_notifiers/push_request_notifier.dart +++ b/lib/state_notifiers/push_request_notifier.dart @@ -23,20 +23,21 @@ import 'dart:async'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:http/http.dart'; import 'package:mutex/mutex.dart'; -import 'package:privacyidea_authenticator/interfaces/repo/push_request_repository.dart'; -import 'package:privacyidea_authenticator/l10n/app_localizations.dart'; -import 'package:privacyidea_authenticator/model/push_request.dart'; -import 'package:privacyidea_authenticator/model/tokens/push_token.dart'; -import 'package:privacyidea_authenticator/utils/globals.dart'; -import 'package:privacyidea_authenticator/utils/logger.dart'; -import 'package:privacyidea_authenticator/utils/network_utils.dart'; -import 'package:privacyidea_authenticator/utils/push_provider.dart'; -import 'package:privacyidea_authenticator/utils/riverpod_providers.dart'; -import 'package:privacyidea_authenticator/utils/rsa_utils.dart'; +import '../interfaces/repo/push_request_repository.dart'; +import '../l10n/app_localizations.dart'; +import '../model/push_request.dart'; import '../model/states/push_request_state.dart'; +import '../model/tokens/push_token.dart'; import '../repo/secure_push_request_repository.dart'; import '../utils/custom_int_buffer.dart'; +import '../utils/globals.dart'; +import '../utils/logger.dart'; +import '../utils/network_utils.dart'; +import '../utils/push_provider.dart'; +import '../utils/riverpod_providers.dart'; +import '../utils/rsa_utils.dart'; +import '../utils/utils.dart'; class PushRequestNotifier extends StateNotifier { late final Future initState; @@ -217,15 +218,15 @@ class PushRequestNotifier extends StateNotifier { /// Accepts a push request and returns true if successful, false if not. /// An accepted push request is removed from the state. /// It should be still in the CustomIntBuffer of the state. - Future accept(PushToken pushToken, PushRequest pushRequest) async { + Future accept(PushToken pushToken, PushRequest pushRequest, {String? selectedAnswer}) async { if (pushRequest.accepted != null) { - Logger.warning('The push request is already accepted or declined.', name: 'push_request_notifier.dart#decline'); + Logger.warning('The push request is already accepted or declined.', name: 'push_request_notifier.dart#accept'); return false; } - Logger.info('Decline push request.', name: 'push_request_notifier.dart#decline'); + Logger.info('Accept push request.', name: 'push_request_notifier.dart#accept'); final updated = await _updatePushRequest(pushRequest, (p0) async { - final updated = p0.copyWith(accepted: true); + final updated = p0.copyWith(accepted: true, selectedAnswer: () => selectedAnswer); final success = await _handleReaction(pushRequest: updated, token: pushToken); if (!success) { return p0; @@ -244,7 +245,7 @@ class PushRequestNotifier extends StateNotifier { } Logger.info('Decline push request.', name: 'push_request_notifier.dart#decline'); final updated = await _updatePushRequest(pushRequest, (p0) async { - final updated = p0.copyWith(accepted: false); + final updated = p0.copyWith(accepted: false, selectedAnswer: () => null); final success = await _handleReaction(pushRequest: updated, token: pushToken); if (!success) { return p0; @@ -318,28 +319,35 @@ class PushRequestNotifier extends StateNotifier { Future _handleReaction({required PushRequest pushRequest, required PushToken token}) async { if (pushRequest.accepted == null) return false; Logger.info('Push auth request accepted=${pushRequest.accepted}, sending response to privacyidea', name: 'token_widgets.dart#handleReaction'); - // signature ::= {nonce}|{serial}[|decline] - String msg = '${pushRequest.nonce}|${token.serial}'; - if (pushRequest.accepted! == false) { - msg += '|decline'; - } - String? signature = await _rsaUtils.trySignWithToken(token, msg); - if (signature == null) { - return false; - } // POST https://privacyideaserver/validate/check // nonce= // serial= // signature= // decline=1 (optional) + // presence_answer= (optional) final Map body = { 'nonce': pushRequest.nonce, 'serial': token.serial, - 'signature': signature, }; + // signature ::= {nonce}|{serial}[|decline] + String msg = '${pushRequest.nonce}|${token.serial}'; if (pushRequest.accepted! == false) { - body["decline"] = "1"; + body['decline'] = '1'; + msg += '|decline'; } + if (pushRequest.possibleAnswers != null && pushRequest.selectedAnswer != null) { + body['presence_answer'] = pushRequest.selectedAnswer!; + msg += '|${pushRequest.selectedAnswer!}'; + } + Logger.warning('Signature message: $msg', name: 'token_widgets.dart#handleReaction'); + String? signature = await _rsaUtils.trySignWithToken(token, msg); + if (signature == null) { + Logger.warning('Failed to sign push request response.', name: 'token_widgets.dart#handleReaction'); + return false; + } + + body['signature'] = signature; + Response response; try { response = await _ioClient.doPost(sslVerify: pushRequest.sslVerify, url: pushRequest.uri, body: body); @@ -354,6 +362,11 @@ class PushRequestNotifier extends StateNotifier { } } if (response.statusCode != 200) { + final appLocalizations = AppLocalizations.of(await globalContext)!; + globalRef?.read(statusMessageProvider.notifier).state = ( + '${appLocalizations.sendPushRequestResponseFailed}\n${appLocalizations.statusCode(response.statusCode)}', + tryJsonDecode(response.body)?["result"]?["error"]?["message"], + ); Logger.warning('Sending push request response failed.', name: 'token_widgets.dart#handleReaction'); return false; } diff --git a/lib/state_notifiers/token_notifier.dart b/lib/state_notifiers/token_notifier.dart index 36e2a774b..8baf4e905 100644 --- a/lib/state_notifiers/token_notifier.dart +++ b/lib/state_notifiers/token_notifier.dart @@ -476,19 +476,20 @@ class TokenNotifier extends StateNotifier { // TODO What to do with poll only tokens if google-services is used? Logger.warning('SSLVerify: ${pushToken.sslVerify}', name: 'token_notifier.dart#rolloutPushToken'); + final fbToken = await _firebaseUtils.getFBToken(); Response response = await _ioClient.doPost( sslVerify: pushToken.sslVerify, url: pushToken.url!, body: { 'enrollment_credential': pushToken.enrollmentCredentials, 'serial': pushToken.serial, - 'fbtoken': await _firebaseUtils.getFBToken(), + 'fbtoken': fbToken, 'pubkey': _rsaUtils.serializeRSAPublicKeyPKCS8(pushToken.rsaPublicTokenKey!), }, ); if (response.statusCode == 200) { - pushToken = await _updateToken(pushToken, (p0) => p0.copyWith(rolloutState: PushTokenRollOutState.parsingResponse)); + pushToken = await _updateToken(pushToken, (p0) => p0.copyWith(rolloutState: PushTokenRollOutState.parsingResponse, fbToken: fbToken)); if (pushToken == null) { Logger.warning('Tried to update a token that does not exist.', name: 'token_notifier.dart#rolloutPushToken'); return false; @@ -620,7 +621,10 @@ class TokenNotifier extends StateNotifier { continue; } Response response = await _ioClient.doPost( - sslVerify: p.sslVerify, url: p.url!, body: {'new_fb_token': firebaseToken, 'serial': p.serial, 'timestamp': timestamp, 'signature': signature}); + url: p.url!, + body: {'new_fb_token': firebaseToken, 'serial': p.serial, 'timestamp': timestamp, 'signature': signature}, + sslVerify: p.sslVerify, + ); if (response.statusCode == 200) { Logger.info('Updating firebase token for push token succeeded!', name: 'push_provider.dart#updateFirebaseToken'); _updateToken(p, (p0) => p0.copyWith(fbToken: firebaseToken)); diff --git a/lib/utils/crypto_utils.dart b/lib/utils/crypto_utils.dart index 5915edd25..0d708768b 100644 --- a/lib/utils/crypto_utils.dart +++ b/lib/utils/crypto_utils.dart @@ -25,9 +25,9 @@ import 'dart:math' as math; import 'package:base32/base32.dart'; import 'package:flutter/foundation.dart'; import 'package:pointycastle/export.dart'; -import 'package:privacyidea_authenticator/model/extensions/enums/encodings_extension.dart'; import '../model/enums/encodings.dart'; +import '../model/extensions/enums/encodings_extension.dart'; Future pbkdf2({required Uint8List salt, required int iterations, required int keyLength, required Uint8List password}) async { ArgumentError.checkNotNull(salt); diff --git a/lib/utils/customization/application_customization.dart b/lib/utils/customization/application_customization.dart index ee57f2f16..b16fb062f 100644 --- a/lib/utils/customization/application_customization.dart +++ b/lib/utils/customization/application_customization.dart @@ -2,7 +2,7 @@ import 'dart:convert'; import 'dart:typed_data'; import 'package:flutter/material.dart'; -import 'package:privacyidea_authenticator/utils/customization/theme_customization.dart'; +import '../../../utils/customization/theme_customization.dart'; import '../../model/enums/app_feature.dart'; diff --git a/lib/utils/customization/theme_customization.dart b/lib/utils/customization/theme_customization.dart index 93818c883..ba22d818a 100644 --- a/lib/utils/customization/theme_customization.dart +++ b/lib/utils/customization/theme_customization.dart @@ -1,8 +1,9 @@ import 'dart:math'; import 'package:flutter/material.dart'; -import 'package:privacyidea_authenticator/utils/customization/action_theme.dart'; -import 'package:privacyidea_authenticator/utils/customization/extended_text_theme.dart'; + +import '../../../utils/customization/action_theme.dart'; +import '../../../utils/customization/extended_text_theme.dart'; class ThemeCustomization { static const ThemeCustomization defaultLightTheme = ThemeCustomization.defaultLightWith(); @@ -265,23 +266,25 @@ class ThemeCustomization { primaryColor: primaryColor, canvasColor: backgroundColor, textTheme: const TextTheme().copyWith( - bodyLarge: TextStyle(color: foregroundColor), - bodyMedium: TextStyle(color: foregroundColor), - titleMedium: TextStyle(color: foregroundColor), - titleSmall: TextStyle(color: foregroundColor), + bodyLarge: TextStyle(color: foregroundColor, fontSize: 18), + bodyMedium: TextStyle(color: foregroundColor, fontSize: 16), + bodySmall: TextStyle(color: subtitleColor, fontSize: 14), + titleLarge: TextStyle(color: primaryColor), + titleMedium: TextStyle(color: primaryColor), + titleSmall: TextStyle(color: primaryColor), displayLarge: TextStyle(color: foregroundColor), displayMedium: TextStyle(color: foregroundColor), displaySmall: TextStyle(color: foregroundColor), - headlineMedium: TextStyle(color: foregroundColor), - headlineSmall: TextStyle(color: foregroundColor), - titleLarge: TextStyle(color: primaryColor), - bodySmall: TextStyle(color: subtitleColor), + headlineMedium: TextStyle(color: primaryColor), + headlineLarge: TextStyle(color: primaryColor), + headlineSmall: TextStyle(color: primaryColor), labelLarge: TextStyle(color: foregroundColor), + labelMedium: TextStyle(color: foregroundColor), labelSmall: TextStyle(color: foregroundColor), ), iconButtonTheme: IconButtonThemeData( style: ButtonStyle( - foregroundColor: MaterialStateProperty.all(foregroundColor), + foregroundColor: WidgetStateProperty.all(foregroundColor), ), ), elevatedButtonTheme: ElevatedButtonThemeData( @@ -324,7 +327,7 @@ class ThemeCustomization { navigationBarTheme: const NavigationBarThemeData().copyWith( backgroundColor: navigationBarColor, shadowColor: shadowColor, - iconTheme: MaterialStatePropertyAll(IconThemeData(color: navigationBarIconColor)), + iconTheme: WidgetStatePropertyAll(IconThemeData(color: navigationBarIconColor)), elevation: 3, ), floatingActionButtonTheme: FloatingActionButtonThemeData( @@ -361,8 +364,8 @@ class ThemeCustomization { errorContainer: deleteColor, ), checkboxTheme: CheckboxThemeData( - checkColor: MaterialStateProperty.resolveWith((_) => onPrimary), - fillColor: MaterialStateProperty.resolveWith((Set states) { + checkColor: WidgetStateProperty.resolveWith((_) => onPrimary), + fillColor: WidgetStateProperty.resolveWith((Set states) { if (states.contains(MaterialState.disabled)) { return null; } @@ -373,7 +376,7 @@ class ThemeCustomization { }), ), radioTheme: RadioThemeData( - fillColor: MaterialStateProperty.resolveWith((Set states) { + fillColor: WidgetStateProperty.resolveWith((Set states) { if (states.contains(MaterialState.disabled)) { return null; } @@ -384,7 +387,7 @@ class ThemeCustomization { }), ), switchTheme: SwitchThemeData( - thumbColor: MaterialStateProperty.resolveWith((Set states) { + thumbColor: WidgetStateProperty.resolveWith((Set states) { if (states.contains(MaterialState.disabled)) { return null; } @@ -393,7 +396,7 @@ class ThemeCustomization { } return null; }), - trackColor: MaterialStateProperty.resolveWith((Set states) { + trackColor: WidgetStateProperty.resolveWith((Set states) { if (states.contains(MaterialState.disabled)) { return null; } diff --git a/lib/utils/home_widget_utils.dart b/lib/utils/home_widget_utils.dart index 0319e0653..a979c05c4 100644 --- a/lib/utils/home_widget_utils.dart +++ b/lib/utils/home_widget_utils.dart @@ -7,7 +7,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:home_widget/home_widget.dart'; import 'package:mutex/mutex.dart'; -import 'package:privacyidea_authenticator/utils/customization/theme_customization.dart'; +import '../utils/customization/theme_customization.dart'; import '../interfaces/repo/token_folder_repository.dart'; import '../interfaces/repo/token_repository.dart'; diff --git a/lib/utils/identifiers.dart b/lib/utils/identifiers.dart index e56679f64..3b3811ddc 100644 --- a/lib/utils/identifiers.dart +++ b/lib/utils/identifiers.dart @@ -63,6 +63,7 @@ const String PUSH_REQUEST_QUESTION = 'question'; // 4. const String PUSH_REQUEST_TITLE = 'title'; // 5. const String PUSH_REQUEST_SSL_VERIFY = 'sslverify'; // 6. const String PUSH_REQUEST_SIGNATURE = 'signature'; // 7. +const String PUSH_REQUEST_ANSWERS = 'require_presence'; // 8. const String GLOBAL_SECURE_REPO_PREFIX = 'app_v3_'; diff --git a/lib/utils/image_converter.dart b/lib/utils/image_converter.dart index fc6bb9e47..50ac981a9 100644 --- a/lib/utils/image_converter.dart +++ b/lib/utils/image_converter.dart @@ -5,7 +5,8 @@ import 'dart:ui'; import 'package:camera/camera.dart'; import 'package:flutter/material.dart'; import 'package:image/image.dart' as imglib; -import 'package:privacyidea_authenticator/utils/logger.dart'; + +import '../utils/logger.dart'; class ImageConverter { final imglib.Image image; diff --git a/lib/utils/logger.dart b/lib/utils/logger.dart index c5e75431e..53a40e504 100644 --- a/lib/utils/logger.dart +++ b/lib/utils/logger.dart @@ -11,10 +11,10 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:logger/logger.dart' as printer; import 'package:mutex/mutex.dart'; import 'package:path_provider/path_provider.dart'; -import 'package:privacyidea_authenticator/l10n/app_localizations.dart'; -import 'package:privacyidea_authenticator/utils/app_info_utils.dart'; -import 'package:privacyidea_authenticator/utils/pi_mailer.dart'; +import '../l10n/app_localizations.dart'; +import '../utils/app_info_utils.dart'; +import '../utils/pi_mailer.dart'; import '../views/settings_view/settings_view_widgets/send_error_dialog.dart'; import 'globals.dart'; import 'riverpod_providers.dart'; diff --git a/lib/utils/network_utils.dart b/lib/utils/network_utils.dart index 9d63c4103..c2ecf9768 100644 --- a/lib/utils/network_utils.dart +++ b/lib/utils/network_utils.dart @@ -25,11 +25,12 @@ import 'package:flutter/foundation.dart'; import 'package:http/http.dart'; import 'package:http/io_client.dart'; import 'package:package_info_plus/package_info_plus.dart'; -import 'package:privacyidea_authenticator/l10n/app_localizations.dart'; -import 'package:privacyidea_authenticator/utils/globals.dart'; -import 'package:privacyidea_authenticator/utils/logger.dart'; -import 'package:privacyidea_authenticator/utils/riverpod_providers.dart'; -import 'package:privacyidea_authenticator/utils/view_utils.dart'; + +import '../l10n/app_localizations.dart'; +import '../utils/globals.dart'; +import '../utils/logger.dart'; +import '../utils/riverpod_providers.dart'; +import '../utils/view_utils.dart'; class PrivacyIdeaIOClient { const PrivacyIdeaIOClient(); @@ -124,6 +125,7 @@ class PrivacyIdeaIOClient { 'Received unexpected response', name: 'utils.dart#doPost', error: 'Status code: ${response.statusCode}' '\nPosted body: $body' '\nResponse: ${response.body}\n', + stackTrace: StackTrace.current, ); } ioClient.close(); diff --git a/lib/utils/push_provider.dart b/lib/utils/push_provider.dart index 2e62c5473..fe7fc07cf 100644 --- a/lib/utils/push_provider.dart +++ b/lib/utils/push_provider.dart @@ -26,13 +26,13 @@ import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:http/http.dart'; import 'package:pi_authenticator_legacy/pi_authenticator_legacy.dart'; -import 'package:privacyidea_authenticator/repo/secure_push_request_repository.dart'; -import 'package:privacyidea_authenticator/utils/pi_notifications.dart'; import '../l10n/app_localizations.dart'; import '../model/push_request.dart'; import '../model/tokens/push_token.dart'; +import '../repo/secure_push_request_repository.dart'; import '../repo/secure_token_repository.dart'; +import '../utils/pi_notifications.dart'; import 'firebase_utils.dart'; import 'globals.dart'; import 'logger.dart'; @@ -144,7 +144,7 @@ class PushProvider { try { data = _getAndValidateDataFromRemoteMessage(remoteMessage); } on ArgumentError catch (_) { - Logger.info('Try requesting the challenge by polling.', name: 'push_provider.dart#_foregroundHandler'); + Logger.info('Failed to parse push request data. Trying to poll for challenges.', name: 'push_provider.dart#_foregroundHandler'); await pollForChallenges(isManually: true); return; } @@ -152,8 +152,12 @@ class PushProvider { try { return _handleIncomingRequestForeground(data); } catch (e, s) { - final errorMessage = AppLocalizations.of(globalNavigatorKey.currentContext!)!.unexpectedError; - Logger.error(errorMessage, name: 'push_provider.dart#_foregroundHandler', error: e, stackTrace: s); + Logger.error( + AppLocalizations.of(globalNavigatorKey.currentContext!)!.unexpectedError, + name: 'push_provider.dart#_foregroundHandler', + error: e, + stackTrace: s, + ); } } @@ -198,6 +202,7 @@ class PushProvider { Future _handleIncomingRequestForeground(Map data) async { Logger.info('Incoming push challenge.', name: 'push_provider.dart#_handleIncomingRequestForeground'); PushRequest pushRequest = PushRequest.fromMessageData(data); + Logger.info("PushRequest.possibleAnswers: ${pushRequest.possibleAnswers}", name: 'push_provider.dart#_handleIncomingRequestForeground'); Logger.info('Parsing data of push request succeeded.', name: 'push_provider.dart#_handleIncomingRequestForeground'); final pushToken = globalRef?.read(tokenProvider).getTokenBySerial(pushRequest.serial); if (pushToken == null) { diff --git a/lib/utils/rsa_utils.dart b/lib/utils/rsa_utils.dart index 270215dcb..5ca0105aa 100644 --- a/lib/utils/rsa_utils.dart +++ b/lib/utils/rsa_utils.dart @@ -25,12 +25,12 @@ import 'package:base32/base32.dart'; import 'package:flutter/foundation.dart'; import 'package:pi_authenticator_legacy/pi_authenticator_legacy.dart'; import 'package:pointycastle/export.dart'; -import 'package:privacyidea_authenticator/l10n/app_localizations.dart'; -import 'package:privacyidea_authenticator/model/tokens/push_token.dart'; -import 'package:privacyidea_authenticator/utils/crypto_utils.dart'; -import 'package:privacyidea_authenticator/utils/identifiers.dart'; -import 'package:privacyidea_authenticator/utils/logger.dart'; -import 'package:privacyidea_authenticator/utils/riverpod_providers.dart'; +import '../l10n/app_localizations.dart'; +import '../model/tokens/push_token.dart'; +import '../utils/crypto_utils.dart'; +import '../utils/identifiers.dart'; +import '../utils/logger.dart'; +import '../utils/riverpod_providers.dart'; import 'globals.dart'; diff --git a/lib/utils/utils.dart b/lib/utils/utils.dart index 87609834f..7d0a08387 100644 --- a/lib/utils/utils.dart +++ b/lib/utils/utils.dart @@ -125,3 +125,11 @@ bool doesThrow(Function() f) { } String getCurrentAppName() => PrivacyIDEAAuthenticator.currentCustomization?.appName ?? ApplicationCustomization.defaultCustomization.appName; + +dynamic tryJsonDecode(String json) { + try { + return jsonDecode(json); + } catch (_) { + return null; + } +} diff --git a/lib/views/add_token_manually_view/add_token_manually_view_widgets/labeled_dropdown_button.dart b/lib/views/add_token_manually_view/add_token_manually_view_widgets/labeled_dropdown_button.dart index 10a387e23..822d58eb7 100644 --- a/lib/views/add_token_manually_view/add_token_manually_view_widgets/labeled_dropdown_button.dart +++ b/lib/views/add_token_manually_view/add_token_manually_view_widgets/labeled_dropdown_button.dart @@ -50,7 +50,7 @@ class _LabeledDropdownButtonState extends State> { child: Text( '${value is Enum ? value.name : value}' '${widget.postFix}', - style: Theme.of(context).textTheme.titleMedium, + style: Theme.of(context).textTheme.bodyMedium, overflow: TextOverflow.fade, softWrap: false, ), diff --git a/lib/views/feedback_view/feedback_view.dart b/lib/views/feedback_view/feedback_view.dart index 8faeb446c..03f57451e 100644 --- a/lib/views/feedback_view/feedback_view.dart +++ b/lib/views/feedback_view/feedback_view.dart @@ -73,7 +73,7 @@ class _FeedbackViewState extends State { children: [ Text( AppLocalizations.of(context)!.feedbackDescription, - style: Theme.of(context).textTheme.titleMedium, + style: Theme.of(context).textTheme.bodyMedium, textAlign: TextAlign.justify, ), const SizedBox(height: 16), diff --git a/lib/views/import_tokens_view/pages/import_start_page.dart b/lib/views/import_tokens_view/pages/import_start_page.dart index c993a764f..c2f93973e 100644 --- a/lib/views/import_tokens_view/pages/import_start_page.dart +++ b/lib/views/import_tokens_view/pages/import_start_page.dart @@ -5,18 +5,18 @@ import 'dart:isolate'; import 'package:file_selector/file_selector.dart'; import 'package:flutter/material.dart'; import 'package:image/image.dart' as img; -import 'package:privacyidea_authenticator/model/enums/token_import_type.dart'; -import 'package:privacyidea_authenticator/model/enums/token_origin_source_type.dart'; -import 'package:privacyidea_authenticator/model/extensions/enums/token_import_type_extension.dart'; -import 'package:privacyidea_authenticator/model/extensions/enums/token_origin_source_type.dart'; -import 'package:privacyidea_authenticator/model/processor_result.dart'; -import 'package:privacyidea_authenticator/processors/scheme_processors/token_import_scheme_processors/token_import_scheme_processor_interface.dart'; import 'package:zxing2/qrcode.dart'; import '../../../l10n/app_localizations.dart'; +import '../../../model/enums/token_import_type.dart'; +import '../../../model/enums/token_origin_source_type.dart'; +import '../../../model/extensions/enums/token_import_type_extension.dart'; +import '../../../model/extensions/enums/token_origin_source_type.dart'; +import '../../../model/processor_result.dart'; import '../../../model/token_import/token_import_source.dart'; import '../../../model/tokens/token.dart'; import '../../../processors/mixins/token_import_processor.dart'; +import '../../../processors/scheme_processors/token_import_scheme_processors/token_import_scheme_processor_interface.dart'; import '../../../processors/token_import_file_processor/token_import_file_processor_interface.dart'; import '../../../utils/logger.dart'; import '../../qr_scanner_view/qr_scanner_view.dart'; diff --git a/lib/views/main_view/main_view.dart b/lib/views/main_view/main_view.dart index ab1007102..d7c7a862a 100644 --- a/lib/views/main_view/main_view.dart +++ b/lib/views/main_view/main_view.dart @@ -15,7 +15,7 @@ import 'main_view_widgets/main_view_navigation_bar.dart'; import 'main_view_widgets/main_view_tokens_list.dart'; import 'main_view_widgets/main_view_tokens_list_filtered.dart'; -export 'package:privacyidea_authenticator/views/main_view/main_view.dart'; +export '../../views/main_view/main_view.dart'; class MainView extends ConsumerStatefulView { static const routeName = '/mainView'; diff --git a/lib/views/main_view/main_view_widgets/no_token_screen.dart b/lib/views/main_view/main_view_widgets/no_token_screen.dart index ba0635593..3f97a6e42 100644 --- a/lib/views/main_view/main_view_widgets/no_token_screen.dart +++ b/lib/views/main_view/main_view_widgets/no_token_screen.dart @@ -22,7 +22,7 @@ class NoTokenScreen extends StatelessWidget { ), Text( AppLocalizations.of(context)!.noResultText1, - style: Theme.of(context).textTheme.titleMedium, + style: Theme.of(context).textTheme.bodyMedium, overflow: TextOverflow.fade, softWrap: false, ), @@ -32,7 +32,7 @@ class NoTokenScreen extends StatelessWidget { ), Text( AppLocalizations.of(context)!.noResultText2, - style: Theme.of(context).textTheme.titleMedium, + style: Theme.of(context).textTheme.bodyMedium, overflow: TextOverflow.fade, softWrap: false, ) diff --git a/lib/views/main_view/main_view_widgets/token_widgets/push_token_widgets/rollout_failed_widget.dart b/lib/views/main_view/main_view_widgets/token_widgets/push_token_widgets/rollout_failed_widget.dart index 1d8109319..d02c17569 100644 --- a/lib/views/main_view/main_view_widgets/token_widgets/push_token_widgets/rollout_failed_widget.dart +++ b/lib/views/main_view/main_view_widgets/token_widgets/push_token_widgets/rollout_failed_widget.dart @@ -26,7 +26,7 @@ class RolloutFailedWidget extends StatelessWidget { child: FittedBox( child: Text( token.rolloutState.rolloutMsg(localizations), - style: Theme.of(context).textTheme.titleMedium, + style: Theme.of(context).textTheme.bodyMedium, textAlign: TextAlign.center, ), ), @@ -50,7 +50,7 @@ class RolloutFailedWidget extends StatelessWidget { SizedBox( width: width * 0.35, child: PressButton( - style: ButtonStyle(backgroundColor: MaterialStateProperty.all(Theme.of(context).colorScheme.errorContainer)), + style: ButtonStyle(backgroundColor: WidgetStateProperty.all(Theme.of(context).colorScheme.errorContainer)), onPressed: () => _showDialog(), child: Text( localizations.delete, diff --git a/lib/views/qr_scanner_view/qr_scanner_view.dart b/lib/views/qr_scanner_view/qr_scanner_view.dart index 63edc62dd..8596f32a9 100644 --- a/lib/views/qr_scanner_view/qr_scanner_view.dart +++ b/lib/views/qr_scanner_view/qr_scanner_view.dart @@ -20,12 +20,12 @@ import 'package:flutter/material.dart'; import 'package:permission_handler/permission_handler.dart'; -import 'package:privacyidea_authenticator/l10n/app_localizations.dart'; -import 'package:privacyidea_authenticator/views/view_interface.dart'; -import 'package:privacyidea_authenticator/widgets/dialog_widgets/default_dialog.dart'; -import 'package:privacyidea_authenticator/widgets/dialog_widgets/default_dialog_button.dart'; +import '../../l10n/app_localizations.dart'; import '../../utils/logger.dart'; +import '../../views/view_interface.dart'; +import '../../widgets/dialog_widgets/default_dialog.dart'; +import '../../widgets/dialog_widgets/default_dialog_button.dart'; import 'qr_scanner_view_widgets/qr_scanner_widget.dart'; class QRScannerView extends StatefulView { diff --git a/lib/views/settings_view/settings_groups/import_export_tokens_widgets/dialogs/select_export_type_dialog.dart b/lib/views/settings_view/settings_groups/import_export_tokens_widgets/dialogs/select_export_type_dialog.dart index 7d5544091..443e820d4 100644 --- a/lib/views/settings_view/settings_groups/import_export_tokens_widgets/dialogs/select_export_type_dialog.dart +++ b/lib/views/settings_view/settings_groups/import_export_tokens_widgets/dialogs/select_export_type_dialog.dart @@ -17,12 +17,12 @@ class SelectExportTypeDialog extends StatelessWidget { mainAxisSize: MainAxisSize.min, children: [ SettingsListTileButton( - title: Text(AppLocalizations.of(context)!.toFile, style: Theme.of(context).textTheme.titleMedium), + title: Text(AppLocalizations.of(context)!.toFile, style: Theme.of(context).textTheme.bodyMedium), onPressed: () async => _selectTokensDialog(context), icon: const Icon(Icons.file_present, size: 24), ), SettingsListTileButton( - title: Text(AppLocalizations.of(context)!.asQrCode, style: Theme.of(context).textTheme.titleMedium), + title: Text(AppLocalizations.of(context)!.asQrCode, style: Theme.of(context).textTheme.bodyMedium), onPressed: () async => _selectTokenDialog(context), icon: const Icon(Icons.qr_code, size: 24)), ], diff --git a/lib/views/settings_view/settings_groups/import_export_tokens_widgets/dialogs/select_tokens_dialog.dart b/lib/views/settings_view/settings_groups/import_export_tokens_widgets/dialogs/select_tokens_dialog.dart index 0644817a0..dc55adc03 100644 --- a/lib/views/settings_view/settings_groups/import_export_tokens_widgets/dialogs/select_tokens_dialog.dart +++ b/lib/views/settings_view/settings_groups/import_export_tokens_widgets/dialogs/select_tokens_dialog.dart @@ -33,7 +33,7 @@ class _SelectTokensDialogState extends ConsumerState { ? Text( AppLocalizations.of(context)!.noTokensToExport, textAlign: TextAlign.center, - style: Theme.of(context).textTheme.titleMedium?.copyWith(color: Theme.of(context).colorScheme.secondary), + style: Theme.of(context).textTheme.bodyMedium?.copyWith(color: Theme.of(context).colorScheme.secondary), ) : Column( mainAxisSize: MainAxisSize.min, @@ -76,7 +76,7 @@ class _SelectTokensDialogState extends ConsumerState { child: TextButton( style: _selectedTokens.contains(token) ? ButtonStyle( - backgroundColor: MaterialStateProperty.all(Theme.of(context).colorScheme.secondary.withAlpha(80)), + backgroundColor: WidgetStateProperty.all(Theme.of(context).colorScheme.secondary.withAlpha(80)), ) : null, onPressed: () async { diff --git a/lib/views/settings_view/settings_groups/settings_group_error_log.dart b/lib/views/settings_view/settings_groups/settings_group_error_log.dart index 8d7e1a9f3..9536bb269 100644 --- a/lib/views/settings_view/settings_groups/settings_group_error_log.dart +++ b/lib/views/settings_view/settings_groups/settings_group_error_log.dart @@ -14,7 +14,7 @@ class SettingsGroupErrorLog extends StatelessWidget { ListTile( title: Text( AppLocalizations.of(context)!.logMenu, - style: Theme.of(context).textTheme.titleMedium, + style: Theme.of(context).textTheme.bodyMedium, overflow: TextOverflow.fade, softWrap: false, ), diff --git a/lib/views/settings_view/settings_groups/settings_group_general.dart b/lib/views/settings_view/settings_groups/settings_group_general.dart index bf37cf33d..c879ec942 100644 --- a/lib/views/settings_view/settings_groups/settings_group_general.dart +++ b/lib/views/settings_view/settings_groups/settings_group_general.dart @@ -26,7 +26,7 @@ class SettingsGroupGeneral extends StatelessWidget { }, title: Text( AppLocalizations.of(context)!.privacyPolicy, - style: Theme.of(context).textTheme.titleMedium, + style: Theme.of(context).textTheme.bodyMedium, overflow: TextOverflow.fade, softWrap: false, ), @@ -37,7 +37,7 @@ class SettingsGroupGeneral extends StatelessWidget { }, title: Text( AppLocalizations.of(context)!.licensesAndVersion, - style: Theme.of(context).textTheme.titleMedium, + style: Theme.of(context).textTheme.bodyMedium, overflow: TextOverflow.fade, softWrap: false, ), @@ -47,7 +47,7 @@ class SettingsGroupGeneral extends StatelessWidget { title: Text( AppLocalizations.of(context)!.thisAppIsOpenSource, //'This Application is a Open Source Project. Visit us on GitHub.', - style: Theme.of(context).textTheme.titleMedium, + style: Theme.of(context).textTheme.bodyMedium, maxLines: 2, ), icon: const Icon(SimpleIcons.github), @@ -58,7 +58,7 @@ class SettingsGroupGeneral extends StatelessWidget { }, title: Text( 'Feedback', - style: Theme.of(context).textTheme.titleMedium, + style: Theme.of(context).textTheme.bodyMedium, overflow: TextOverflow.fade, softWrap: false, ), diff --git a/lib/views/settings_view/settings_groups/settings_group_import_export_tokens.dart b/lib/views/settings_view/settings_groups/settings_group_import_export_tokens.dart index b2ae2b802..bf0d655d3 100644 --- a/lib/views/settings_view/settings_groups/settings_group_import_export_tokens.dart +++ b/lib/views/settings_view/settings_groups/settings_group_import_export_tokens.dart @@ -24,7 +24,7 @@ class _SettingsGroupImportExportTokensState extends ConsumerState SettingsGroup( - title: AppLocalizations.of(context)!.language, - children: [ - SwitchListTile( - title: Text( - AppLocalizations.of(context)!.useDeviceLocaleTitle, - style: Theme.of(context).textTheme.titleMedium, - ), - subtitle: Text( - AppLocalizations.of(context)!.useDeviceLocaleDescription, - overflow: TextOverflow.fade, - ), - value: ref.watch(settingsProvider).useSystemLocale, - onChanged: (value) => ref.read(settingsProvider.notifier).setUseSystemLocale(value)), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 20), - child: DropdownButton( - disabledHint: Text( - '${ref.watch(settingsProvider).currentLocale}', - style: Theme.of(context).textTheme.titleMedium?.copyWith(color: Colors.grey), - overflow: TextOverflow.fade, - softWrap: false, - ), - isExpanded: true, - value: ref.watch(settingsProvider).currentLocale, - items: AppLocalizations.supportedLocales.map>((Locale itemLocale) { - return DropdownMenuItem( - value: itemLocale, - child: Text( - '$itemLocale', - overflow: TextOverflow.fade, - softWrap: false, - ), - ); - }).toList(), - onChanged: ref.watch(settingsProvider).useSystemLocale ? null : (value) => ref.read(settingsProvider.notifier).setLocalePreference(value!), + Widget build(BuildContext context, WidgetRef ref) { + final localizations = AppLocalizations.of(context)!; + return SettingsGroup( + title: localizations.language, + children: [ + SwitchListTile( + title: Text( + localizations.useDeviceLocaleTitle, + style: Theme.of(context).textTheme.bodyMedium, ), + subtitle: Text( + localizations.useDeviceLocaleDescription, + overflow: TextOverflow.fade, + ), + value: ref.watch(settingsProvider).useSystemLocale, + onChanged: (value) => ref.read(settingsProvider.notifier).setUseSystemLocale(value)), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 20), + child: DropdownButton( + disabledHint: Text( + '${ref.watch(settingsProvider).currentLocale}', + style: Theme.of(context).textTheme.bodyMedium?.copyWith(color: Colors.grey), + overflow: TextOverflow.fade, + softWrap: false, + ), + isExpanded: true, + value: ref.watch(settingsProvider).currentLocale, + items: AppLocalizations.supportedLocales.map>((Locale itemLocale) { + return DropdownMenuItem( + value: itemLocale, + child: Text( + '$itemLocale', + overflow: TextOverflow.fade, + style: Theme.of(context).textTheme.bodyMedium?.copyWith(color: ref.watch(settingsProvider).useSystemLocale ? Colors.grey : null), + softWrap: false, + ), + ); + }).toList(), + onChanged: ref.watch(settingsProvider).useSystemLocale ? null : (value) => ref.read(settingsProvider.notifier).setLocalePreference(value!), ), - ], - ); + ), + ], + ); + } } diff --git a/lib/views/settings_view/settings_groups/settings_group_push_token.dart b/lib/views/settings_view/settings_groups/settings_group_push_token.dart index 4ca61c79f..c3979df0f 100644 --- a/lib/views/settings_view/settings_groups/settings_group_push_token.dart +++ b/lib/views/settings_view/settings_groups/settings_group_push_token.dart @@ -24,7 +24,7 @@ class SettingsGroupPushToken extends ConsumerWidget { ListTile( title: Text( AppLocalizations.of(context)!.synchronizePushTokens, - style: Theme.of(context).textTheme.titleMedium, + style: Theme.of(context).textTheme.bodyMedium, ), subtitle: Text( AppLocalizations.of(context)!.synchronizesTokensWithServer, @@ -54,7 +54,7 @@ class SettingsGroupPushToken extends ConsumerWidget { children: [ TextSpan( text: AppLocalizations.of(context)!.enablePolling, - style: Theme.of(context).textTheme.titleMedium, + style: Theme.of(context).textTheme.bodyMedium, ), // Add clickable icon to inform user of unsupported push tokens (for polling) WidgetSpan( @@ -89,7 +89,7 @@ class SettingsGroupPushToken extends ConsumerWidget { children: [ TextSpan( text: AppLocalizations.of(context)!.hidePushTokens, - style: Theme.of(context).textTheme.titleMedium, + style: Theme.of(context).textTheme.bodyMedium, ), ], ), diff --git a/lib/views/settings_view/settings_groups/settings_group_theme.dart b/lib/views/settings_view/settings_groups/settings_group_theme.dart index aca058ea2..77d32c44d 100644 --- a/lib/views/settings_view/settings_groups/settings_group_theme.dart +++ b/lib/views/settings_view/settings_groups/settings_group_theme.dart @@ -15,7 +15,7 @@ class SettingsGroupTheme extends StatelessWidget { RadioListTile( title: Text( AppLocalizations.of(context)!.lightTheme, - style: Theme.of(context).textTheme.titleMedium, + style: Theme.of(context).textTheme.bodyMedium, overflow: TextOverflow.fade, softWrap: false, ), @@ -30,7 +30,7 @@ class SettingsGroupTheme extends StatelessWidget { RadioListTile( title: Text( AppLocalizations.of(context)!.darkTheme, - style: Theme.of(context).textTheme.titleMedium, + style: Theme.of(context).textTheme.bodyMedium, overflow: TextOverflow.fade, softWrap: false, ), @@ -45,7 +45,7 @@ class SettingsGroupTheme extends StatelessWidget { RadioListTile( title: Text( AppLocalizations.of(context)!.systemTheme, - style: Theme.of(context).textTheme.titleMedium, + style: Theme.of(context).textTheme.bodyMedium, ), value: ThemeMode.system, groupValue: EasyDynamicTheme.of(context).themeMode, diff --git a/lib/views/settings_view/settings_view_widgets/logging_menu.dart b/lib/views/settings_view/settings_view_widgets/logging_menu.dart index 00e7924f6..466f4f08a 100644 --- a/lib/views/settings_view/settings_view_widgets/logging_menu.dart +++ b/lib/views/settings_view/settings_view_widgets/logging_menu.dart @@ -30,7 +30,7 @@ class LoggingMenu extends ConsumerWidget { ListTile( title: Text( AppLocalizations.of(context)!.verboseLogging, - style: Theme.of(context).textTheme.titleMedium, + style: Theme.of(context).textTheme.bodyMedium, textAlign: TextAlign.center, ), contentPadding: const EdgeInsets.all(0), diff --git a/lib/views/settings_view/settings_view_widgets/update_firebase_token_dialog.dart b/lib/views/settings_view/settings_view_widgets/update_firebase_token_dialog.dart index 5419b74dd..20f2bb288 100644 --- a/lib/views/settings_view/settings_view_widgets/update_firebase_token_dialog.dart +++ b/lib/views/settings_view/settings_view_widgets/update_firebase_token_dialog.dart @@ -20,13 +20,13 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:privacyidea_authenticator/l10n/app_localizations.dart'; -import 'package:privacyidea_authenticator/utils/logger.dart'; -import 'package:privacyidea_authenticator/utils/riverpod_providers.dart'; -import 'package:privacyidea_authenticator/utils/view_utils.dart'; +import '../../../l10n/app_localizations.dart'; import '../../../model/tokens/push_token.dart'; import '../../../utils/globals.dart'; +import '../../../utils/logger.dart'; +import '../../../utils/riverpod_providers.dart'; +import '../../../utils/view_utils.dart'; import '../../../widgets/dialog_widgets/default_dialog.dart'; class UpdateFirebaseTokenDialog extends ConsumerStatefulWidget { diff --git a/lib/views/splash_screen/splash_screen.dart b/lib/views/splash_screen/splash_screen.dart index c0b2545c5..c13ad8981 100644 --- a/lib/views/splash_screen/splash_screen.dart +++ b/lib/views/splash_screen/splash_screen.dart @@ -2,8 +2,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../model/enums/app_feature.dart'; -import '../../utils/customization/application_customization.dart'; import '../../utils/app_info_utils.dart'; +import '../../utils/customization/application_customization.dart'; import '../../utils/home_widget_utils.dart'; import '../../utils/logger.dart'; import '../../utils/riverpod_providers.dart'; diff --git a/lib/widgets/dialog_widgets/patch_notes_dialog.dart b/lib/widgets/dialog_widgets/patch_notes_dialog.dart index 288bbc726..8283e9f55 100644 --- a/lib/widgets/dialog_widgets/patch_notes_dialog.dart +++ b/lib/widgets/dialog_widgets/patch_notes_dialog.dart @@ -39,7 +39,7 @@ class PatchNotesDialog extends StatelessWidget { children: [ Text( '${localizations.version}: ${version.toString()}', - style: Theme.of(context).textTheme.titleMedium, + style: Theme.of(context).textTheme.bodyMedium, ), const SizedBox(height: 16), ...newNotes[version]!.entries.map( diff --git a/lib/widgets/dialog_widgets/push_request_dialog.dart b/lib/widgets/dialog_widgets/push_request_dialog.dart index f3a88453a..dc0c66ebc 100644 --- a/lib/widgets/dialog_widgets/push_request_dialog.dart +++ b/lib/widgets/dialog_widgets/push_request_dialog.dart @@ -1,3 +1,5 @@ +import 'dart:math'; + import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; @@ -7,6 +9,7 @@ import '../../model/push_request.dart'; import '../../model/tokens/push_token.dart'; import '../../utils/globals.dart'; import '../../utils/lock_auth.dart'; +import '../../utils/logger.dart'; import '../../utils/riverpod_providers.dart'; import '../press_button.dart'; import 'default_dialog.dart'; @@ -21,9 +24,14 @@ class PushRequestDialog extends ConsumerStatefulWidget { } class _PushRequestDialogState extends ConsumerState { - static const titleScale = 1.35; - static const questionScale = 1.1; double get lineHeight => Theme.of(context).textTheme.titleLarge?.fontSize ?? 16; + double get spacerHeight => lineHeight * 0.5; + + static WidgetStateProperty buttonShape(BuildContext context) => WidgetStateProperty.all( + Theme.of(context).elevatedButtonTheme.style?.shape?.resolve({})?.copyWith( + side: BorderSide(color: Theme.of(context).colorScheme.onPrimary, width: 2.5), + ), + ); bool isHandled = false; bool dialogIsOpen = false; @@ -44,60 +52,119 @@ class _PushRequestDialogState extends ConsumerState { @override Widget build(BuildContext context) { - final lineHeight = this.lineHeight; + final spacerHeight = this.spacerHeight; final question = widget.pushRequest.question; + final token = ref.watch(tokenProvider).getTokenBySerial(widget.pushRequest.serial); + final localizations = AppLocalizations.of(context)!; if (token == null) { WidgetsBinding.instance.addPostFrameCallback((_) async { - if (mounted) { - ref.read(pushRequestProvider.notifier).remove(widget.pushRequest); - } + if (mounted) ref.read(pushRequestProvider.notifier).remove(widget.pushRequest); }); } + return isHandled || token == null ? const SizedBox() : Container( color: Colors.transparent, child: DefaultDialog( + scrollable: false, title: Text( - AppLocalizations.of(context)!.authenticationRequest, - style: Theme.of(context).textTheme.titleLarge!, + localizations.authenticationRequest, + style: Theme.of(context).textTheme.headlineMedium!, textAlign: TextAlign.center, - textScaler: const TextScaler.linear(titleScale), ), content: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Text( - AppLocalizations.of(context)!.requestInfo( + localizations.requestInfo( token.issuer, token.label, ), - style: Theme.of(context).textTheme.bodyLarge?.copyWith(fontSize: Theme.of(context).textTheme.titleMedium?.fontSize), - textScaler: const TextScaler.linear(questionScale), + style: Theme.of(context).textTheme.bodyLarge!, textAlign: TextAlign.center, ), - SizedBox(height: lineHeight), + SizedBox(height: spacerHeight), ...[ Text( question, - style: Theme.of(context).textTheme.bodyLarge?.copyWith(fontSize: Theme.of(context).textTheme.titleMedium?.fontSize), - textScaler: const TextScaler.linear(questionScale), + style: Theme.of(context).textTheme.bodyLarge!, textAlign: TextAlign.center, ), - SizedBox(height: lineHeight), + SizedBox(height: spacerHeight), ], + widget.pushRequest.possibleAnswers != null + ? Flexible( + child: SingleChildScrollView( + child: AnswerSelectionWidget( + onAnswerSelected: (selectedAnswer) async { + if (token.isLocked && await lockAuth(localizedReason: localizations.authToAcceptPushRequest) == false) { + return; + } + ref.read(pushRequestProvider.notifier).accept(token, widget.pushRequest, selectedAnswer: selectedAnswer).then((success) { + Logger.info('accept push request success: $success', name: 'push_request_dialog.dart#AnswerSelectionWidget'); + if (!success && mounted) setState(() => isHandled = false); + }); + if (mounted) setState(() => isHandled = true); + }, + possibleAnswers: widget.pushRequest.possibleAnswers!, + ), + ), + ) + : SizedBox( + // Accept button + child: PressButton( + style: ButtonStyle(shape: buttonShape(context)), + onPressed: () async { + if (token.isLocked && await lockAuth(localizedReason: localizations.authToAcceptPushRequest) == false) { + return; + } + ref.read(pushRequestProvider.notifier).accept(token, widget.pushRequest).then((success) { + Logger.info('accept push request success: $success', name: 'push_request_dialog.dart#AnswerSelectionWidget'); + if (!success && mounted) setState(() => isHandled = false); + }); + if (mounted) setState(() => isHandled = true); + }, + child: Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Padding( + padding: EdgeInsets.symmetric(vertical: spacerHeight), + child: Text( + localizations.accept, + style: Theme.of(context).textTheme.headlineMedium?.copyWith(color: Theme.of(context).colorScheme.onPrimary), + textAlign: TextAlign.center, + maxLines: 1, + ), + ), + Icon( + Icons.check_outlined, + size: Theme.of(context).textTheme.headlineMedium?.fontSize ?? 16, + ), + ], + ), + ), + ), SizedBox( - // Accept button - height: lineHeight * titleScale * 2 + 16, + // Decline button child: PressButton( + style: ButtonStyle( + backgroundColor: WidgetStateProperty.all( + Theme.of(context).colorScheme.errorContainer, + ), + shape: buttonShape(context), + ), onPressed: () async { - if (token.isLocked && await lockAuth(localizedReason: AppLocalizations.of(context)!.authToAcceptPushRequest) == false) { + if (token.isLocked && await lockAuth(localizedReason: localizations.authToDeclinePushRequest) == false) { return; } - globalRef?.read(pushRequestProvider.notifier).accept(token, widget.pushRequest); - if (mounted) setState(() => isHandled = true); + dialogIsOpen = true; + await _showConfirmationDialog(token); + dialogIsOpen = false; }, child: Row( mainAxisSize: MainAxisSize.max, @@ -105,151 +172,207 @@ class _PushRequestDialogState extends ConsumerState { crossAxisAlignment: CrossAxisAlignment.center, children: [ Text( - AppLocalizations.of(context)!.accept, - style: Theme.of(context).textTheme.titleLarge?.copyWith(color: Theme.of(context).colorScheme.onPrimary), - textScaler: const TextScaler.linear(titleScale), + localizations.decline, + style: Theme.of(context).textTheme.headlineMedium?.copyWith(color: Theme.of(context).colorScheme.onPrimary), textAlign: TextAlign.center, - maxLines: 1, ), Icon( - Icons.check_outlined, - size: lineHeight * titleScale, + Icons.close_outlined, + size: Theme.of(context).textTheme.headlineMedium?.fontSize ?? 16, ), ], ), ), ), - SizedBox(height: lineHeight * 0.5), - SizedBox( - // Decline button - height: lineHeight * titleScale + 16, - child: PressButton( - style: ButtonStyle(backgroundColor: MaterialStateProperty.all(Theme.of(context).colorScheme.errorContainer)), + SizedBox(height: spacerHeight), + ], + ), + ), + ); + } + + Future _showConfirmationDialog(PushToken pushToken) { + final localizations = AppLocalizations.of(context)!; + return showDialog( + useRootNavigator: false, + context: globalNavigatorKey.currentContext!, + builder: (BuildContext context) { + final spacerHeight = this.spacerHeight; + return DefaultDialog( + title: Text( + localizations.authenticationRequest, + style: Theme.of(context).textTheme.titleLarge!, + textAlign: TextAlign.center, + ), + content: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Text( + localizations.requestTriggerdByUserQuestion, + style: Theme.of(context).textTheme.bodyLarge?.copyWith(fontSize: Theme.of(context).textTheme.titleMedium?.fontSize), + textAlign: TextAlign.center, + ), + SizedBox(height: spacerHeight), + Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + const Expanded(child: SizedBox()), + Expanded( + flex: 6, + child: PressButton( + style: ButtonStyle(shape: buttonShape(context)), onPressed: () async { - if (token.isLocked && await lockAuth(localizedReason: AppLocalizations.of(context)!.authToDeclinePushRequest) == false) { + if (pushToken.isLocked && await lockAuth(localizedReason: localizations.authToDeclinePushRequest) == false) { return; } - dialogIsOpen = true; - await _showConfirmationDialog(token); - dialogIsOpen = false; + + ref.read(pushRequestProvider.notifier).remove(widget.pushRequest).then((success) { + Logger.info('remove push request success: $success', name: 'push_request_dialog.dart#_showConfirmationDialog'); + if (!success && mounted) setState(() => isHandled = false); + }); + if (context.mounted) Navigator.of(context).pop(); + if (mounted) setState(() => isHandled = true); }, - child: Row( - mainAxisSize: MainAxisSize.max, - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - crossAxisAlignment: CrossAxisAlignment.center, + child: Column( + mainAxisSize: MainAxisSize.min, children: [ Text( - AppLocalizations.of(context)!.decline, - style: Theme.of(context).textTheme.titleLarge?.copyWith(color: Theme.of(context).colorScheme.onPrimary), - textScaler: const TextScaler.linear(titleScale), + localizations.yes, + style: Theme.of(context).textTheme.bodyLarge?.copyWith(color: Theme.of(context).colorScheme.onPrimary), textAlign: TextAlign.center, ), - Icon(Icons.close_outlined, size: lineHeight * titleScale), + FittedBox( + fit: BoxFit.scaleDown, + child: Text( + localizations.butDiscardIt, + style: Theme.of(context).textTheme.bodySmall?.copyWith( + color: Theme.of(context).colorScheme.onPrimary.mixWith(Colors.grey.shade800), + ), + textAlign: TextAlign.center, + softWrap: false, + ), + ), ], - )), - ), - ], - ), - ), - ); - } + ), + ), + ), + const Expanded(flex: 2, child: SizedBox()), + Expanded( + flex: 6, + child: PressButton( + style: ButtonStyle( + backgroundColor: WidgetStateProperty.all(Theme.of(context).colorScheme.errorContainer), + shape: buttonShape(context), + ), + onPressed: () async { + //TODO: Notify issuer + if (pushToken.isLocked && await lockAuth(localizedReason: localizations.authToDeclinePushRequest) == false) { + return; + } - Future _showConfirmationDialog(PushToken pushToken) => showDialog( - useRootNavigator: false, - context: globalNavigatorKey.currentContext!, - builder: (BuildContext context) { - final lineHeight = this.lineHeight; - return DefaultDialog( - title: Text( - AppLocalizations.of(context)!.authenticationRequest, - style: Theme.of(context).textTheme.titleLarge!, - textAlign: TextAlign.center, - textScaler: const TextScaler.linear(titleScale), - ), - content: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Text( - AppLocalizations.of(context)!.requestTriggerdByUserQuestion, - style: Theme.of(context).textTheme.bodyLarge?.copyWith(fontSize: Theme.of(context).textTheme.titleMedium?.fontSize), - textScaler: const TextScaler.linear(questionScale), - textAlign: TextAlign.center, - ), - SizedBox(height: lineHeight), - Row( - mainAxisSize: MainAxisSize.max, - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - const Expanded(child: SizedBox()), - Expanded( - flex: 6, - child: PressButton( - onPressed: () { - globalRef?.read(pushRequestProvider.notifier).decline(pushToken, widget.pushRequest); - Navigator.of(context).pop(); - if (mounted) setState(() => isHandled = true); - }, - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Text( - AppLocalizations.of(context)!.yes, - style: Theme.of(context).textTheme.bodyLarge?.copyWith(color: Theme.of(context).colorScheme.onPrimary), - textScaler: const TextScaler.linear(titleScale), - textAlign: TextAlign.center, - ), - FittedBox( - fit: BoxFit.scaleDown, - child: Text( - AppLocalizations.of(context)!.butDiscardIt, - style: Theme.of(context).textTheme.bodySmall?.copyWith( - color: Theme.of(context).colorScheme.onPrimary.mixWith(Colors.grey.shade800), - ), + ref.read(pushRequestProvider.notifier).decline(pushToken, widget.pushRequest).then((success) { + Logger.info('decline push request success: $success', name: 'push_request_dialog.dart#_showConfirmationDialog'); + if (!success && mounted) setState(() => isHandled = false); + }); + if (context.mounted) Navigator.of(context).pop(); + if (mounted) setState(() => isHandled = true); + }, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + localizations.no, + style: Theme.of(context).textTheme.bodyLarge?.copyWith(color: Theme.of(context).colorScheme.onPrimary), + textAlign: TextAlign.center, + ), + Text( + localizations.declineIt, + style: + Theme.of(context).textTheme.bodySmall?.copyWith(color: Theme.of(context).colorScheme.onPrimary.mixWith(Colors.grey.shade800)), textAlign: TextAlign.center, softWrap: false, ), - ), - ], + ], + ), ), ), - ), - const Expanded(flex: 2, child: SizedBox()), - Expanded( - flex: 6, - child: PressButton( - style: ButtonStyle(backgroundColor: MaterialStateProperty.all(Theme.of(context).colorScheme.errorContainer)), - onPressed: () { - //TODO: Notify issuer - globalRef?.read(pushRequestProvider.notifier).decline(pushToken, widget.pushRequest); - Navigator.of(context).pop(); - if (mounted) setState(() => isHandled = true); - }, - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Text( - AppLocalizations.of(context)!.no, - style: Theme.of(context).textTheme.bodyLarge?.copyWith(color: Theme.of(context).colorScheme.onPrimary), - textScaler: const TextScaler.linear(titleScale), - textAlign: TextAlign.center, - ), - Text( - AppLocalizations.of(context)!.declineIt, - style: - Theme.of(context).textTheme.bodySmall?.copyWith(color: Theme.of(context).colorScheme.onPrimary.mixWith(Colors.grey.shade800)), + const Expanded(child: SizedBox()), + ], + ), + ], + ), + ); + }); + } +} + +class AnswerSelectionWidget extends StatefulWidget { + final List possibleAnswers; + final void Function(T) onAnswerSelected; + const AnswerSelectionWidget({required this.possibleAnswers, super.key, required this.onAnswerSelected}); + + @override + State> createState() => _AnswerSelectionWidgetState(); +} + +class _AnswerSelectionWidgetState extends State> { + double get lineHeight => Theme.of(context).textTheme.titleLarge?.fontSize ?? 16; + double get spacerHeight => lineHeight * 0.5; + @override + Widget build(BuildContext context) { + final children = []; + final possibleAnswers = widget.possibleAnswers.toList(); + final totalAnswersNum = possibleAnswers.length; + const numPerRow = 3; + while (possibleAnswers.isNotEmpty) { + final maxThisRow = possibleAnswers.length == numPerRow + 1 ? min(possibleAnswers.length, (numPerRow / 2).ceil()) : min(possibleAnswers.length, numPerRow); + final answersThisRow = possibleAnswers.sublist(0, maxThisRow); + possibleAnswers.removeRange(0, maxThisRow); + final spacer = (maxThisRow != numPerRow && totalAnswersNum > maxThisRow) + ? Expanded(flex: (numPerRow - answersThisRow.length) * answersThisRow.length, child: const SizedBox()) + : const SizedBox(); + children.add( + Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + spacer, + for (final possibleAnswer in answersThisRow) + Expanded( + flex: answersThisRow.length * 2, + child: PressButton( + style: ButtonStyle(shape: _PushRequestDialogState.buttonShape(context)), + onPressed: () => widget.onAnswerSelected(possibleAnswer), + child: Padding( + padding: EdgeInsets.symmetric(vertical: spacerHeight), + child: SizedBox( + height: lineHeight * 2, + child: Center( + child: FittedBox( + fit: BoxFit.scaleDown, + child: Text( + possibleAnswer.toString(), + style: Theme.of(context).textTheme.headlineMedium?.copyWith(color: Theme.of(context).colorScheme.onPrimary), textAlign: TextAlign.center, - softWrap: false, ), - ], + ), ), ), ), - const Expanded(child: SizedBox()), - ], + ), ), - ], - ), - ); - }); + spacer, + ], + ), + ); + } + + return Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: children, + ); + } } diff --git a/lib/widgets/dialog_widgets/two_step_dialog.dart b/lib/widgets/dialog_widgets/two_step_dialog.dart index d87b43d5e..bb7beae82 100644 --- a/lib/widgets/dialog_widgets/two_step_dialog.dart +++ b/lib/widgets/dialog_widgets/two_step_dialog.dart @@ -22,13 +22,13 @@ import 'dart:typed_data'; import 'dart:ui'; import 'package:flutter/material.dart'; -import 'package:privacyidea_authenticator/l10n/app_localizations.dart'; -import 'package:privacyidea_authenticator/utils/crypto_utils.dart'; -import 'package:privacyidea_authenticator/utils/view_utils.dart'; -import 'package:privacyidea_authenticator/widgets/dialog_widgets/default_dialog.dart'; +import '../../l10n/app_localizations.dart'; +import '../../utils/crypto_utils.dart'; import '../../utils/logger.dart'; import '../../utils/utils.dart'; +import '../../utils/view_utils.dart'; +import '../../widgets/dialog_widgets/default_dialog.dart'; import '../widget_keys.dart'; class GenerateTwoStepDialog extends StatelessWidget { diff --git a/lib/widgets/press_button.dart b/lib/widgets/press_button.dart index a03dd7c7f..fb2dcbc5f 100644 --- a/lib/widgets/press_button.dart +++ b/lib/widgets/press_button.dart @@ -32,11 +32,12 @@ class _PressButtonState extends State { } @override - Widget build(BuildContext context) { - return ElevatedButton( - onPressed: isPressable ? press : null, - style: widget.style?.merge(Theme.of(context).elevatedButtonTheme.style), - child: widget.child, - ); - } + Widget build(BuildContext context) => Padding( + padding: Theme.of(context).elevatedButtonTheme.style?.padding?.resolve({}) ?? const EdgeInsets.all(0), + child: ElevatedButton( + onPressed: isPressable ? press : null, + style: widget.style?.merge(Theme.of(context).elevatedButtonTheme.style) ?? Theme.of(context).elevatedButtonTheme.style, + child: widget.child, + ), + ); }