diff --git a/assets/custom-icons/_data/custom-icons.json b/assets/custom-icons/_data/custom-icons.json
index ee7dac8f64..96cada4285 100644
--- a/assets/custom-icons/_data/custom-icons.json
+++ b/assets/custom-icons/_data/custom-icons.json
@@ -95,6 +95,12 @@
"title": "La Poste",
"slug": "laposte"
},
+ {
+ "title": "Mastodon",
+ "altNames": ["mstdn", "fediscience", "mathstodon", "fosstodon"],
+ "slug": "mastodon",
+ "hex": "6364FF"
+ },
{
"title": "Microsoft"
},
diff --git a/assets/custom-icons/icons/mastodon.svg b/assets/custom-icons/icons/mastodon.svg
new file mode 100644
index 0000000000..5e3b7e13cf
--- /dev/null
+++ b/assets/custom-icons/icons/mastodon.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/assets/simple-icons b/assets/simple-icons
index 7e1ad45175..8e7701d6a4 160000
--- a/assets/simple-icons
+++ b/assets/simple-icons
@@ -1 +1 @@
-Subproject commit 7e1ad4517598f36ba625741a4dfbc33610d105d8
+Subproject commit 8e7701d6a40462733043f54b3849faf35af70a83
diff --git a/lib/l10n/arb/app_en.arb b/lib/l10n/arb/app_en.arb
index 0e883b1c0a..7d516c5b42 100644
--- a/lib/l10n/arb/app_en.arb
+++ b/lib/l10n/arb/app_en.arb
@@ -1,5 +1,6 @@
{
"account": "Account",
+ "unlock": "Unlock",
"recoveryKey": "Recovery key",
"counterAppBarTitle": "Counter",
"@counterAppBarTitle": {
@@ -85,6 +86,7 @@
"importSelectJsonFile": "Select JSON file",
"importEnteEncGuide": "Select the encrypted JSON file exported from ente",
"importRaivoGuide": "Use the \"Export OTPs to Zip archive\" option in Raivo's Settings.\n\nExtract the zip file and import the JSON file.",
+ "importBitwardenGuide": "Use the \"Export vault\" option within Bitwarden Tools and import the unencrypted JSON file.",
"importAegisGuide": "Use the \"Export the vault\" option in Aegis's Settings.\n\nIf your vault is encrypted, you will need to enter vault password to decrypt the vault.",
"exportCodes": "Export codes",
"importLabel": "Import",
@@ -97,6 +99,7 @@
"authToViewYourRecoveryKey": "Please authenticate to view your recovery key",
"authToChangeYourEmail": "Please authenticate to change your email",
"authToChangeYourPassword": "Please authenticate to change your password",
+ "authToViewSecrets": "Please authenticate to view your secrets",
"ok": "Ok",
"cancel": "Cancel",
"yes": "Yes",
@@ -336,5 +339,57 @@
"deleteCodeAuthMessage": "Authenticate to delete code",
"showQRAuthMessage": "Authenticate to show QR code",
"confirmAccountDeleteTitle": "Confirm account deletion",
- "confirmAccountDeleteMessage": "This account is linked to other ente apps, if you use any.\n\nYour uploaded data, across all ente apps, will be scheduled for deletion, and your account will be permanently deleted."
+ "confirmAccountDeleteMessage": "This account is linked to other ente apps, if you use any.\n\nYour uploaded data, across all ente apps, will be scheduled for deletion, and your account will be permanently deleted.",
+ "androidBiometricHint": "Verify identity",
+ "@androidBiometricHint": {
+ "description": "Hint message advising the user how to authenticate with biometrics. It is used on Android side. Maximum 60 characters."
+ },
+ "androidBiometricNotRecognized": "Not recognized. Try again.",
+ "@androidBiometricNotRecognized": {
+ "description": "Message to let the user know that authentication was failed. It is used on Android side. Maximum 60 characters."
+ },
+ "androidBiometricSuccess": "Success",
+ "@androidBiometricSuccess": {
+ "description": "Message to let the user know that authentication was successful. It is used on Android side. Maximum 60 characters."
+ },
+ "androidCancelButton": "Cancel",
+ "@androidCancelButton": {
+ "description": "Message showed on a button that the user can click to leave the current dialog. It is used on Android side. Maximum 30 characters."
+ },
+ "androidSignInTitle": "Authentication required",
+ "@androidSignInTitle": {
+ "description": "Message showed as a title in a dialog which indicates the user that they need to scan biometric to continue. It is used on Android side. Maximum 60 characters."
+ },
+ "androidBiometricRequiredTitle": "Biometric required",
+ "@androidBiometricRequiredTitle": {
+ "description": "Message showed as a title in a dialog which indicates the user has not set up biometric authentication on their device. It is used on Android side. Maximum 60 characters."
+ },
+ "androidDeviceCredentialsRequiredTitle": "Device credentials required",
+ "@androidDeviceCredentialsRequiredTitle": {
+ "description": "Message showed as a title in a dialog which indicates the user has not set up credentials authentication on their device. It is used on Android side. Maximum 60 characters."
+ },
+ "androidDeviceCredentialsSetupDescription": "Device credentials required",
+ "@androidDeviceCredentialsSetupDescription": {
+ "description": "Message advising the user to go to the settings and configure device credentials on their device. It shows in a dialog on Android side."
+ },
+ "goToSettings": "Go to settings",
+ "@goToSettings": {
+ "description": "Message showed on a button that the user can click to go to settings pages from the current dialog. It is used on both Android and iOS side. Maximum 30 characters."
+ },
+ "androidGoToSettingsDescription": "Biometric authentication is not set up on your device. Go to 'Settings > Security' to add biometric authentication.",
+ "@androidGoToSettingsDescription": {
+ "description": "Message advising the user to go to the settings and configure biometric on their device. It shows in a dialog on Android side."
+ },
+ "iOSLockOut": "Biometric authentication is disabled. Please lock and unlock your screen to enable it.",
+ "@iOSLockOut": {
+ "description": "Message advising the user to re-enable biometrics on their device. It shows in a dialog on iOS side."
+ },
+ "iOSGoToSettingsDescription": "Biometric authentication is not set up on your device. Please either enable Touch ID or Face ID on your phone.",
+ "@iOSGoToSettingsDescription": {
+ "description": "Message advising the user to go to the settings and configure Biometrics for their device. It shows in a dialog on iOS side."
+ },
+ "iOSOkButton": "OK",
+ "@iOSOkButton": {
+ "description": "Message showed on a button that the user can click to leave the current dialog. It is used on iOS side. Maximum 30 characters."
+ }
}
diff --git a/lib/l10n/arb/app_zh.arb b/lib/l10n/arb/app_zh.arb
index d2b14477e7..4f510e7de1 100644
--- a/lib/l10n/arb/app_zh.arb
+++ b/lib/l10n/arb/app_zh.arb
@@ -1,5 +1,6 @@
{
"account": "账户",
+ "unlock": "解锁",
"recoveryKey": "恢复密钥",
"counterAppBarTitle": "计数器",
"@counterAppBarTitle": {
@@ -97,6 +98,7 @@
"authToViewYourRecoveryKey": "请验证以查看您的恢复密钥",
"authToChangeYourEmail": "请验证以更改您的电子邮件",
"authToChangeYourPassword": "请验证以更改密码",
+ "authToViewSecrets": "请进行身份验证以查看您的秘密",
"ok": "好的",
"cancel": "取消",
"yes": "是",
@@ -336,5 +338,57 @@
"deleteCodeAuthMessage": "删除代码需要身份验证",
"showQRAuthMessage": "显示QR码需要身份验证",
"confirmAccountDeleteTitle": "确认删除账户",
- "confirmAccountDeleteMessage": "该账户已链接到其他ente旗下的应用程序(如果您使用任何相关的应用程序)。\n\n您在所有ente旗下应用程序中上传的数据都将被安排删除,并且您的账户将被永久删除。"
+ "confirmAccountDeleteMessage": "该账户已链接到其他ente旗下的应用程序(如果您使用任何相关的应用程序)。\n\n您在所有ente旗下应用程序中上传的数据都将被安排删除,并且您的账户将被永久删除。",
+ "androidBiometricHint": "验证身份",
+ "@androidBiometricHint": {
+ "description": "Hint message advising the user how to authenticate with biometrics. It is used on Android side. Maximum 60 characters."
+ },
+ "androidBiometricNotRecognized": "未能识别。再试一次。",
+ "@androidBiometricNotRecognized": {
+ "description": "Message to let the user know that authentication was failed. It is used on Android side. Maximum 60 characters."
+ },
+ "androidBiometricSuccess": "成功",
+ "@androidBiometricSuccess": {
+ "description": "Message to let the user know that authentication was successful. It is used on Android side. Maximum 60 characters."
+ },
+ "androidCancelButton": "取消",
+ "@androidCancelButton": {
+ "description": "Message showed on a button that the user can click to leave the current dialog. It is used on Android side. Maximum 30 characters."
+ },
+ "androidSignInTitle": "需要进行身份验证",
+ "@androidSignInTitle": {
+ "description": "Message showed as a title in a dialog which indicates the user that they need to scan biometric to continue. It is used on Android side. Maximum 60 characters."
+ },
+ "androidBiometricRequiredTitle": "需要进行生物识别认证",
+ "@androidBiometricRequiredTitle": {
+ "description": "Message showed as a title in a dialog which indicates the user has not set up biometric authentication on their device. It is used on Android side. Maximum 60 characters."
+ },
+ "androidDeviceCredentialsRequiredTitle": "需要设备凭据",
+ "@androidDeviceCredentialsRequiredTitle": {
+ "description": "Message showed as a title in a dialog which indicates the user has not set up credentials authentication on their device. It is used on Android side. Maximum 60 characters."
+ },
+ "androidDeviceCredentialsSetupDescription": "需要设备凭据",
+ "@androidDeviceCredentialsSetupDescription": {
+ "description": "Message advising the user to go to the settings and configure device credentials on their device. It shows in a dialog on Android side."
+ },
+ "goToSettings": "前往设置",
+ "@goToSettings": {
+ "description": "Message showed on a button that the user can click to go to settings pages from the current dialog. It is used on both Android and iOS side. Maximum 30 characters."
+ },
+ "androidGoToSettingsDescription": "您的设备上未设置生物识别身份验证。转到“设置 > 安全”以添加生物识别身份验证。",
+ "@androidGoToSettingsDescription": {
+ "description": "Message advising the user to go to the settings and configure biometric on their device. It shows in a dialog on Android side."
+ },
+ "iOSLockOut": "生物识别身份验证已禁用。请锁定再解锁您的屏幕以启用它。",
+ "@iOSLockOut": {
+ "description": "Message advising the user to re-enable biometrics on their device. It shows in a dialog on iOS side."
+ },
+ "iOSGoToSettingsDescription": "您的设备上未设置生物识别身份验证。请在您的手机上启用 触控 ID 或 面容 ID。",
+ "@iOSGoToSettingsDescription": {
+ "description": "Message advising the user to go to the settings and configure Biometrics for their device. It shows in a dialog on iOS side."
+ },
+ "iOSOkButton": "好的",
+ "@iOSOkButton": {
+ "description": "Message showed on a button that the user can click to leave the current dialog. It is used on iOS side. Maximum 30 characters."
+ }
}
\ No newline at end of file
diff --git a/lib/services/local_authentication_service.dart b/lib/services/local_authentication_service.dart
index f161bb89fa..d21d1bcb26 100644
--- a/lib/services/local_authentication_service.dart
+++ b/lib/services/local_authentication_service.dart
@@ -1,5 +1,3 @@
-
-
import 'package:ente_auth/core/configuration.dart';
import 'package:ente_auth/ui/tools/app_lock.dart';
import 'package:ente_auth/utils/auth_util.dart';
@@ -19,7 +17,7 @@ class LocalAuthenticationService {
) async {
if (await _isLocalAuthSupportedOnDevice()) {
AppLock.of(context)!.setEnabled(false);
- final result = await requestAuthentication(infoMessage);
+ final result = await requestAuthentication(context, infoMessage);
AppLock.of(context)!.setEnabled(
Configuration.instance.shouldShowLockScreen(),
);
@@ -43,6 +41,7 @@ class LocalAuthenticationService {
if (await LocalAuthentication().isDeviceSupported()) {
AppLock.of(context)!.disable();
final result = await requestAuthentication(
+ context,
infoMessage,
);
if (result) {
diff --git a/lib/ui/settings/data/import/bitwarden_import.dart b/lib/ui/settings/data/import/bitwarden_import.dart
new file mode 100644
index 0000000000..ce2dce3f2a
--- /dev/null
+++ b/lib/ui/settings/data/import/bitwarden_import.dart
@@ -0,0 +1,103 @@
+import 'dart:async';
+import 'dart:convert';
+import 'dart:io';
+
+import 'package:ente_auth/l10n/l10n.dart';
+import 'package:ente_auth/models/code.dart';
+import 'package:ente_auth/services/authenticator_service.dart';
+import 'package:ente_auth/store/code_store.dart';
+import 'package:ente_auth/ui/components/buttons/button_widget.dart';
+import 'package:ente_auth/ui/components/dialog_widget.dart';
+import 'package:ente_auth/ui/components/models/button_type.dart';
+import 'package:ente_auth/ui/settings/data/import/import_success.dart';
+import 'package:ente_auth/utils/dialog_util.dart';
+import 'package:file_picker/file_picker.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+
+Future showBitwardenImportInstruction(BuildContext context) async {
+ final l10n = context.l10n;
+ final result = await showDialogWidget(
+ context: context,
+ title: l10n.importFromApp("Bitwarden"),
+ body: l10n.importBitwardenGuide,
+ buttons: [
+ ButtonWidget(
+ buttonType: ButtonType.primary,
+ labelText: l10n.importSelectJsonFile,
+ isInAlert: true,
+ buttonSize: ButtonSize.large,
+ buttonAction: ButtonAction.first,
+ ),
+ ButtonWidget(
+ buttonType: ButtonType.secondary,
+ labelText: context.l10n.cancel,
+ buttonSize: ButtonSize.large,
+ isInAlert: true,
+ buttonAction: ButtonAction.second,
+ ),
+ ],
+ );
+ if (result?.action != null && result!.action != ButtonAction.cancel) {
+ if (result.action == ButtonAction.first) {
+ await _pickBitwardenJsonFile(context);
+ }
+ }
+}
+
+Future _pickBitwardenJsonFile(BuildContext context) async {
+ final l10n = context.l10n;
+ FilePickerResult? result = await FilePicker.platform.pickFiles();
+ if (result == null) {
+ return;
+ }
+ final progressDialog = createProgressDialog(context, l10n.pleaseWait);
+ await progressDialog.show();
+ try {
+ String path = result.files.single.path!;
+ int? count = await _processBitwardenExportFile(context, path);
+ await progressDialog.hide();
+ if (count != null) {
+ await importSuccessDialog(context, count);
+ }
+ } catch (e) {
+ await progressDialog.hide();
+ await showErrorDialog(
+ context,
+ context.l10n.sorry,
+ context.l10n.importFailureDesc,
+ );
+ }
+}
+
+Future _processBitwardenExportFile(
+ BuildContext context,
+ String path,
+) async {
+ File file = File(path);
+ final jsonString = await file.readAsString();
+ final data = jsonDecode(jsonString);
+ List jsonArray = data['items'];
+ final parsedCodes = [];
+ for (var item in jsonArray) {
+ if (item['login']['totp'] != null) {
+ var issuer = item['name'];
+ var account = item['login']['username'];
+ var secret = item['login']['totp'];
+
+ parsedCodes.add(
+ Code.fromAccountAndSecret(
+ account,
+ issuer,
+ secret,
+ ),
+ );
+ }
+ }
+
+ for (final code in parsedCodes) {
+ await CodeStore.instance.addCode(code, shouldSync: false);
+ }
+ unawaited(AuthenticatorService.instance.onlineSync());
+ return parsedCodes.length;
+}
diff --git a/lib/ui/settings/data/import/import_service.dart b/lib/ui/settings/data/import/import_service.dart
index 514eb9362f..79f047c7fd 100644
--- a/lib/ui/settings/data/import/import_service.dart
+++ b/lib/ui/settings/data/import/import_service.dart
@@ -1,5 +1,6 @@
import 'package:ente_auth/ui/settings/data/import/aegis_import.dart';
import 'package:ente_auth/ui/settings/data/import/analyze_qr_code.dart';
+import 'package:ente_auth/ui/settings/data/import/bitwarden_import.dart';
import 'package:ente_auth/ui/settings/data/import/encrypted_ente_import.dart';
import 'package:ente_auth/ui/settings/data/import/google_auth_import.dart';
import 'package:ente_auth/ui/settings/data/import/plain_text_import.dart';
@@ -40,6 +41,8 @@ class ImportService {
},
),
);
+ case ImportType.bitwarden:
+ showBitwardenImportInstruction(context);
break;
}
}
diff --git a/lib/ui/settings/data/import_page.dart b/lib/ui/settings/data/import_page.dart
index b7e1211b01..bebcb0a89c 100644
--- a/lib/ui/settings/data/import_page.dart
+++ b/lib/ui/settings/data/import_page.dart
@@ -15,7 +15,8 @@ enum ImportType {
ravio,
googleAuthenticator,
aegis,
- googleAuthenticatorImage
+ googleAuthenticatorImage,
+ bitwarden,
}
class ImportCodePage extends StatelessWidget {
@@ -26,6 +27,7 @@ class ImportCodePage extends StatelessWidget {
ImportType.aegis,
ImportType.googleAuthenticator,
ImportType.googleAuthenticatorImage,
+ ImportType.bitwarden,
];
ImportCodePage({super.key});
@@ -45,6 +47,8 @@ class ImportCodePage extends StatelessWidget {
return 'Aegis Authenticator';
case ImportType.googleAuthenticatorImage:
return 'Google Authenticator (saved image)';
+ case ImportType.bitwarden:
+ return 'Bitwarden';
}
}
diff --git a/lib/ui/tools/lock_screen.dart b/lib/ui/tools/lock_screen.dart
index a1389fc4ec..202a8291e2 100644
--- a/lib/ui/tools/lock_screen.dart
+++ b/lib/ui/tools/lock_screen.dart
@@ -1,5 +1,4 @@
-
-
+import 'package:ente_auth/l10n/l10n.dart';
import 'package:ente_auth/ui/common/gradient_button.dart';
import 'package:ente_auth/ui/tools/app_lock.dart';
import 'package:ente_auth/utils/auth_util.dart';
@@ -13,13 +12,19 @@ class LockScreen extends StatefulWidget {
State createState() => _LockScreenState();
}
-class _LockScreenState extends State {
+class _LockScreenState extends State with WidgetsBindingObserver {
final _logger = Logger("LockScreen");
+ bool _isShowingLockScreen = false;
+ bool _hasPlacedAppInBackground = false;
+ bool _hasAuthenticationFailed = false;
+ int? lastAuthenticatingTime;
@override
void initState() {
- _showLockScreen();
+ _logger.info("initState");
super.initState();
+ _showLockScreen(source: "initState");
+ WidgetsBinding.instance.addObserver(this);
}
@override
@@ -34,16 +39,16 @@ class _LockScreenState extends State {
alignment: Alignment.center,
children: [
Opacity(
- opacity: 0.3,
+ opacity: 0.2,
child: Image.asset('assets/loading_photos_background.png'),
),
SizedBox(
- width: 142,
+ width: 180,
child: GradientButton(
- text: "Unlock",
+ text: context.l10n.unlock,
iconData: Icons.lock_open_outlined,
onTap: () async {
- _showLockScreen();
+ _showLockScreen(source: "tapUnlock");
},
),
),
@@ -55,16 +60,67 @@ class _LockScreenState extends State {
);
}
- Future _showLockScreen() async {
- _logger.info("Showing lockscreen");
+ @override
+ void didChangeAppLifecycleState(AppLifecycleState state) {
+ _logger.info(state.toString());
+ if (state == AppLifecycleState.resumed && !_isShowingLockScreen) {
+ // This is triggered either when the lock screen is dismissed or when
+ // the app is brought to foreground
+ _hasPlacedAppInBackground = false;
+ final bool didAuthInLast5Seconds = lastAuthenticatingTime != null &&
+ DateTime.now().millisecondsSinceEpoch - lastAuthenticatingTime! <
+ 5000;
+ if (!_hasAuthenticationFailed && !didAuthInLast5Seconds) {
+ // Show the lock screen again only if the app is resuming from the
+ // background, and not when the lock screen was explicitly dismissed
+ Future.delayed(
+ Duration.zero,
+ () => _showLockScreen(source: "lifeCycle"),
+ );
+ } else {
+ _hasAuthenticationFailed = false; // Reset failure state
+ }
+ } else if (state == AppLifecycleState.paused ||
+ state == AppLifecycleState.inactive) {
+ // This is triggered either when the lock screen pops up or when
+ // the app is pushed to background
+ if (!_isShowingLockScreen) {
+ _hasPlacedAppInBackground = true;
+ _hasAuthenticationFailed = false; // reset failure state
+ }
+ }
+ }
+
+ @override
+ void dispose() {
+ WidgetsBinding.instance.removeObserver(this);
+ super.dispose();
+ }
+
+ Future _showLockScreen({String source = ''}) async {
+ final int id = DateTime.now().millisecondsSinceEpoch;
+ _logger.info("Showing lock screen $source $id");
try {
+ _isShowingLockScreen = true;
final result = await requestAuthentication(
- "Please authenticate to view your secrets",
+ context,
+ context.l10n.authToViewSecrets,
);
+ _logger.finest("LockScreen Result $result $id");
+ _isShowingLockScreen = false;
if (result) {
+ lastAuthenticatingTime = DateTime.now().millisecondsSinceEpoch;
AppLock.of(context)!.didUnlock();
+ } else {
+ if (!_hasPlacedAppInBackground) {
+ // Treat this as a failure only if user did not explicitly
+ // put the app in background
+ _hasAuthenticationFailed = true;
+ _logger.info("Authentication failed");
+ }
}
} catch (e, s) {
+ _isShowingLockScreen = false;
_logger.severe(e, s);
}
}
diff --git a/lib/ui/utils/icon_utils.dart b/lib/ui/utils/icon_utils.dart
index 27da8752ba..7cb1299ac5 100644
--- a/lib/ui/utils/icon_utils.dart
+++ b/lib/ui/utils/icon_utils.dart
@@ -93,6 +93,14 @@ class IconUtils {
icon["slug"],
icon["hex"],
);
+ if (icon["altNames"] != null) {
+ for (final name in icon["altNames"]) {
+ _customIcons[name] = CustomIconData(
+ icon["slug"],
+ icon["hex"],
+ );
+ }
+ }
}
} catch (e) {
Logger("IconUtils").severe("Error loading icons", e);
diff --git a/lib/utils/auth_util.dart b/lib/utils/auth_util.dart
index 77f9732041..0a63201912 100644
--- a/lib/utils/auth_util.dart
+++ b/lib/utils/auth_util.dart
@@ -1,25 +1,37 @@
+import 'package:ente_auth/l10n/l10n.dart';
+import 'package:flutter/cupertino.dart';
import 'package:local_auth/local_auth.dart';
import 'package:local_auth_android/local_auth_android.dart';
+import 'package:local_auth_ios/types/auth_messages_ios.dart';
import 'package:logging/logging.dart';
-Future requestAuthentication(String reason) async {
+Future requestAuthentication(BuildContext context, String reason) async {
Logger("AuthUtil").info("Requesting authentication");
await LocalAuthentication().stopAuthentication();
+ final l10n = context.l10n;
return await LocalAuthentication().authenticate(
localizedReason: reason,
authMessages: [
- const AndroidAuthMessages(
- biometricHint: "Verify identity",
- biometricNotRecognized: "Not recognized, try again",
- biometricRequiredTitle: "Biometric required",
- biometricSuccess: "Successfully verified",
- cancelButton: "Cancel",
- deviceCredentialsRequiredTitle: "Device credentials required",
- deviceCredentialsSetupDescription: "Device credentials required",
- goToSettingsButton: "Go to settings",
- goToSettingsDescription:
- "Authentication is not setup on your device, go to Settings > Security to set it up",
- signInTitle: "Authentication required",
+ AndroidAuthMessages(
+ biometricHint: l10n.androidBiometricHint,
+ biometricNotRecognized: l10n.androidBiometricNotRecognized,
+ biometricRequiredTitle: l10n.androidBiometricRequiredTitle,
+ biometricSuccess: l10n.androidBiometricSuccess,
+ cancelButton: l10n.androidCancelButton,
+ deviceCredentialsRequiredTitle:
+ l10n.androidDeviceCredentialsRequiredTitle,
+ deviceCredentialsSetupDescription:
+ l10n.androidDeviceCredentialsSetupDescription,
+ goToSettingsButton: l10n.goToSettings,
+ goToSettingsDescription: l10n.androidGoToSettingsDescription,
+ signInTitle: l10n.androidSignInTitle,
+ ),
+ IOSAuthMessages(
+ goToSettingsButton: l10n.goToSettings,
+ goToSettingsDescription: l10n.goToSettings,
+ lockOut: l10n.iOSLockOut,
+ // cancelButton default value is "Ok"
+ cancelButton: l10n.iOSOkButton,
),
],
);
diff --git a/pubspec.lock b/pubspec.lock
index 53c93804c5..9dd3376236 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -792,7 +792,7 @@ packages:
source: hosted
version: "2.1.7"
local_auth_android:
- dependency: transitive
+ dependency: "direct main"
description:
name: local_auth_android
sha256: "523dd636ce061ddb296cbc3db410cb8f21efb7d8798f7b9532c8038ce2f8bad5"
@@ -800,7 +800,7 @@ packages:
source: hosted
version: "1.0.31"
local_auth_ios:
- dependency: transitive
+ dependency: "direct main"
description:
name: local_auth_ios
sha256: edc2977c5145492f3451db9507a2f2f284ee4f408950b3e16670838726761940
diff --git a/pubspec.yaml b/pubspec.yaml
index fc8bba25fa..811900f44d 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,6 +1,6 @@
name: ente_auth
description: ente two-factor authenticator
-version: 2.0.15+215
+version: 2.0.17+217
publish_to: none
environment:
@@ -54,6 +54,9 @@ dependencies:
intl: ^0.18.0
json_annotation: ^4.5.0
local_auth: ^2.1.7
+
+ local_auth_android: ^1.0.31
+ local_auth_ios: ^1.1.3
logging: ^1.0.1
mobile_scanner: ^3.5.2
modal_bottom_sheet: ^3.0.0-pre