diff --git a/lib/auth_service.dart b/lib/auth_service.dart index acbf2e2..400440c 100644 --- a/lib/auth_service.dart +++ b/lib/auth_service.dart @@ -61,16 +61,36 @@ class AuthService { } /// Prompt the OS biometric dialog. Returns true on success. - Future authenticateWithBiometrics() async { + /// [errorOut] receives a human-readable reason when it fails. + Future authenticateWithBiometrics({String? errorOut}) async { try { - return await _localAuth.authenticate( - localizedReason: 'Gunakan sidik jari untuk membuka Login Vault', - options: const AuthenticationOptions( - biometricOnly: true, - stickyAuth: true, - ), - ); - } catch (_) { + // Prefer strict biometric (fingerprint). If the device only has + // weaker biometrics (face) or none enrolled, fall back to allowing + // device credentials so the user isn't hard-blocked. + bool ok = false; + try { + ok = await _localAuth.authenticate( + localizedReason: 'Gunakan biometrik untuk membuka Login Vault', + options: const AuthenticationOptions( + biometricOnly: true, + stickyAuth: true, + ), + ); + } catch (_) { + ok = false; + } + if (!ok) { + ok = await _localAuth.authenticate( + localizedReason: 'Gunakan biometrik / kredensial perangkat', + options: const AuthenticationOptions( + biometricOnly: false, + stickyAuth: true, + ), + ); + } + return ok; + } catch (e) { + if (errorOut != null) errorOut = e.toString(); return false; } } diff --git a/lib/settings_screen.dart b/lib/settings_screen.dart index db7ccb2..e40b3e6 100644 --- a/lib/settings_screen.dart +++ b/lib/settings_screen.dart @@ -64,13 +64,14 @@ class _SettingsScreenState extends State { Future _toggleBiometric(bool value) async { if (value && !_biometricAvailable) { - setState(() => _msg = 'Perangkat tidak mendukung sidik jari'); + setState(() => _msg = 'Perangkat tidak mendukung biometrik'); return; } if (value) { - final ok = await widget.auth.authenticateWithBiometrics(); + String? err; + final ok = await widget.auth.authenticateWithBiometrics(errorOut: err); if (!ok) { - setState(() => _msg = 'Verifikasi sidik jari gagal'); + setState(() => _msg = 'Verifikasi biometrik gagal: ${err ?? "dibatalkan"}'); return; } }