Skip to content

Commit b11cfa9

Browse files
committed
refactor: Added an AppUnlockInteraction mixin to avoid using BuildContext in lib/model.
1 parent 696f0e2 commit b11cfa9

23 files changed

Lines changed: 100 additions & 60 deletions

lib/i18n/de/app_unlock.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
"button": {
1212
"disable": "Deaktivieren",
1313
"changeMasterPassword": "Master-Passwort ändern",
14-
"unlock": "Entsperren"
14+
"unlock": "Entsperren",
15+
"cancel": "Abbrechen"
1516
}
1617
}

lib/i18n/en/app_unlock.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
"button": {
1212
"disable": "Disable",
1313
"changeMasterPassword": "Change master password",
14-
"unlock": "Unlock"
14+
"unlock": "Unlock",
15+
"cancel": "Cancel"
1516
}
1617
}

lib/i18n/fr/app_unlock.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
"button": {
1212
"disable": "Désactiver",
1313
"changeMasterPassword": "Changer le mot de passe maître",
14-
"unlock": "Déverrouiller"
14+
"unlock": "Déverrouiller",
15+
"cancel": "Annuler"
1516
}
1617
}

lib/i18n/it/app_unlock.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
"button": {
1212
"disable": "Disabilitare",
1313
"changeMasterPassword": "Cambiare la password principale",
14-
"unlock": "Sbloccare"
14+
"unlock": "Sbloccare",
15+
"cancel": "Annulla"
1516
}
1617
}

lib/i18n/pt/app_unlock.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
"button": {
1212
"disable": "Desativar",
1313
"changeMasterPassword": "Alterar a senha mestra",
14-
"unlock": "Desbloquear"
14+
"unlock": "Desbloquear",
15+
"cancel": "Cancelar"
1516
}
1617
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
/// Allows to interact with the app unlock.
2+
mixin AppUnlockInteraction {
3+
/// Prompts the user for a master password.
4+
Future<String?> promptMasterPassword({String? message});
5+
6+
/// Whether the app can be unlocked.
7+
bool get canInteract;
8+
}

lib/model/app_unlock/methods/local_auth.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ class LocalAuthenticationAppUnlockMethod extends AppUnlockMethod {
1313
);
1414

1515
@override
16-
Future<Result> _tryUnlock(BuildContext context, UnlockReason reason) async {
17-
bool result = await LocalAuthentication.instance.authenticate(context, reason);
16+
Future<Result> _tryUnlock(AppUnlockInteraction interaction, UnlockReason reason) async {
17+
bool result = await LocalAuthentication.instance.authenticate(reason);
1818
return result ? const ResultSuccess() : const ResultCancelled();
1919
}
2020

lib/model/app_unlock/methods/master_password.dart

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,18 @@ class MasterPasswordAppUnlockMethod extends AppUnlockMethod<String> {
1313
);
1414

1515
@override
16-
Future<Result<String>> _tryUnlock(BuildContext context, UnlockReason reason) async {
16+
Future<Result<String>> _tryUnlock(AppUnlockInteraction interaction, UnlockReason reason) async {
1717
if (reason != .openApp && reason != .sensibleAction) {
1818
List<Totp> totps = await _ref.read(totpRepositoryProvider.future);
1919
if (totps.isEmpty) {
2020
return const ResultSuccess();
2121
}
2222
}
23-
if (!context.mounted) {
23+
if (!interaction.canInteract) {
2424
return const ResultCancelled();
2525
}
2626

27-
Result<String> result = await _promptMasterPasswordForUnlock(context, reason == .openApp ? translations.appUnlock.masterPasswordDialogMessage : null);
27+
Result<String> result = await _promptMasterPasswordForUnlock(interaction, reason == .openApp ? translations.appUnlock.masterPasswordDialogMessage : null);
2828
if (result is! ResultSuccess<String>) {
2929
return result;
3030
}
@@ -73,9 +73,8 @@ class MasterPasswordAppUnlockMethod extends AppUnlockMethod<String> {
7373
}
7474

7575
/// Prompts master password for unlock.
76-
Future<Result<String>> _promptMasterPasswordForUnlock(BuildContext context, String? message) async {
77-
String? password = await MasterPasswordInputDialog.prompt(
78-
context,
76+
Future<Result<String>> _promptMasterPasswordForUnlock(AppUnlockInteraction interaction, String? message) async {
77+
String? password = await interaction.promptMasterPassword(
7978
message: message,
8079
);
8180
if (password == null) {

lib/model/app_unlock/methods/method.dart

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import 'package:flutter/material.dart';
21
import 'package:flutter_riverpod/flutter_riverpod.dart';
32
import 'package:local_auth/local_auth.dart' hide LocalAuthentication;
43
import 'package:open_authenticator/i18n/localizable_exception.dart';
54
import 'package:open_authenticator/i18n/translations.g.dart';
5+
import 'package:open_authenticator/model/app_unlock/interaction.dart';
66
import 'package:open_authenticator/model/app_unlock/reason.dart';
77
import 'package:open_authenticator/model/crypto/derived_key.dart';
88
import 'package:open_authenticator/model/crypto/salt.dart';
@@ -13,7 +13,6 @@ import 'package:open_authenticator/model/totp/repository.dart';
1313
import 'package:open_authenticator/model/totp/totp.dart';
1414
import 'package:open_authenticator/utils/local_authentication/local_authentication.dart';
1515
import 'package:open_authenticator/utils/result/result.dart';
16-
import 'package:open_authenticator/widgets/dialog/text_input_dialog.dart';
1716

1817
part 'local_auth.dart';
1918
part 'master_password.dart';
@@ -44,17 +43,16 @@ sealed class AppUnlockMethod<T> {
4443
}) : _ref = ref;
4544

4645
/// Unlock the app, handling errors.
47-
/// [context] is required so that we can interact with the user.
48-
Future<Result<T>> unlock(BuildContext context, UnlockReason reason) async {
46+
Future<Result<T>> unlock(AppUnlockInteraction interaction, UnlockReason reason) async {
4947
try {
5048
CannotUnlockException? cannotUnlockException = await canUnlock(reason);
5149
if (cannotUnlockException != null) {
5250
throw cannotUnlockException;
5351
}
54-
if (!context.mounted) {
52+
if (!interaction.canInteract) {
5553
return const ResultCancelled();
5654
}
57-
return await _tryUnlock(context, reason);
55+
return await _tryUnlock(interaction, reason);
5856
} catch (ex, stackTrace) {
5957
if (ex is LocalAuthException) {
6058
if (ex.code == LocalAuthExceptionCode.userCanceled || ex.code == LocalAuthExceptionCode.systemCanceled) {
@@ -69,8 +67,7 @@ sealed class AppUnlockMethod<T> {
6967
}
7068

7169
/// Tries to unlock the app.
72-
/// [context] is required so that we can interact with the user.
73-
Future<Result<T>> _tryUnlock(BuildContext context, UnlockReason reason);
70+
Future<Result<T>> _tryUnlock(AppUnlockInteraction interaction, UnlockReason reason);
7471

7572
/// The default app lock state.
7673
AppLockState get defaultAppLockState => AppLockState.locked;

lib/model/app_unlock/methods/none.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ class NoneAppUnlockMethod extends AppUnlockMethod {
1313
);
1414

1515
@override
16-
Future<Result> _tryUnlock(BuildContext context, UnlockReason reason) => Future.value(const ResultSuccess());
16+
Future<Result> _tryUnlock(AppUnlockInteraction interaction, UnlockReason reason) => Future.value(const ResultSuccess());
1717

1818
@override
1919
AppLockState get defaultAppLockState => AppLockState.unlocked;

0 commit comments

Comments
 (0)