Fix fingerprint: adaptive auth screen (login/register by state), auto-prompt biometric on open, optimistic switch, real error messages

This commit is contained in:
cania
2026-08-13 09:52:03 +02:00
parent 0fd595d8a6
commit 6a9c4da0c7
3 changed files with 108 additions and 58 deletions

View File

@@ -19,6 +19,7 @@ class _SettingsScreenState extends State<SettingsScreen> {
final _oldCtrl = TextEditingController();
final _newCtrl = TextEditingController();
String? _msg;
Color _msgColor = Colors.green;
bool _biometricOn = false;
bool _biometricAvailable = false;
int _timeout = 3;
@@ -48,35 +49,53 @@ class _SettingsScreenState extends State<SettingsScreen> {
final oldP = _oldCtrl.text;
final newP = _newCtrl.text;
if (newP.isEmpty) {
setState(() => _msg = 'Password baru wajib diisi');
setState(() {
_msg = 'Password baru wajib diisi';
_msgColor = Colors.red;
});
return;
}
final stored = await widget.auth.getAppPassword();
if (stored != null && stored != '__google__' && stored != oldP) {
setState(() => _msg = 'Password lama salah');
setState(() {
_msg = 'Password lama salah';
_msgColor = Colors.red;
});
return;
}
await widget.auth.changePassword(newP);
setState(() => _msg = 'Password aplikasi berhasil diubah');
setState(() {
_msg = 'Password aplikasi berhasil diubah';
_msgColor = Colors.green;
});
_oldCtrl.clear();
_newCtrl.clear();
}
Future<void> _toggleBiometric(bool value) async {
if (value && !_biometricAvailable) {
setState(() => _msg = 'Perangkat tidak mendukung biometrik');
setState(() {
_msg = 'Perangkat tidak mendukung biometrik';
_msgColor = Colors.red;
});
return;
}
// optimistic: move switch immediately so it feels responsive
if (mounted) setState(() => _biometricOn = value);
if (value) {
String? err;
final ok = await widget.auth.authenticateWithBiometrics(errorOut: err);
final (ok, err) = await widget.auth.authenticateWithBiometrics();
if (!ok) {
setState(() => _msg = 'Verifikasi biometrik gagal: ${err ?? "dibatalkan"}');
if (mounted) {
setState(() {
_biometricOn = false;
_msg = 'Verifikasi biometrik gagal: ${err ?? "dibatalkan"}';
_msgColor = Colors.red;
});
}
return;
}
}
await widget.auth.setBiometricEnabled(value);
if (mounted) setState(() => _biometricOn = value);
}
Future<void> _setTimeout(int? value) async {
@@ -121,12 +140,19 @@ class _SettingsScreenState extends State<SettingsScreen> {
ListTile(
title: const Text('Timeout (tanpa aktivitas)'),
subtitle: Text('Logout otomatis setelah: ${_timeoutLabel(_timeout)}'),
trailing: DropdownButton<int>(
value: _timeout,
items: _timeoutOptions
.map((m) => DropdownMenuItem(value: m, child: Text(_timeoutLabel(m))))
trailing: PopupMenuButton<int>(
initialValue: _timeoutOptions.contains(_timeout) ? _timeout : _timeoutOptions.first,
onSelected: _setTimeout,
itemBuilder: (ctx) => _timeoutOptions
.map((m) => PopupMenuItem(value: m, child: Text(_timeoutLabel(m))))
.toList(),
onChanged: _setTimeout,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(_timeoutLabel(_timeout)),
const Icon(Icons.arrow_drop_down),
],
),
),
),
SwitchListTile(
@@ -158,7 +184,7 @@ class _SettingsScreenState extends State<SettingsScreen> {
if (_msg != null)
Padding(
padding: const EdgeInsets.only(top: 8),
child: Text(_msg!, style: const TextStyle(color: Colors.green)),
child: Text(_msg!, style: TextStyle(color: _msgColor)),
),
const Divider(),
ListTile(