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

@@ -4,7 +4,7 @@ import 'package:login_vault_app/auth_service.dart';
import 'package:login_vault_app/dashboard_screen.dart';
import 'package:login_vault_app/theme_provider.dart';
/// First screen: register, or (if registered) re-authenticate.
/// First screen: register (if not yet), or re-authenticate (if registered).
/// If a valid session exists, skip straight to the Dashboard.
class AuthScreen extends StatefulWidget {
final AuthService auth;
@@ -24,9 +24,39 @@ class _AuthScreenState extends State<AuthScreen> {
@override
void initState() {
super.initState();
_initMode();
}
/// Decide login vs register based on whether an account exists.
Future<void> _initMode() async {
final registered = await widget.auth.isRegistered();
if (!mounted) return;
setState(() => _isLogin = registered);
// If already registered and biometric is enabled, prompt fingerprint
// automatically (unless a valid session already skips to dashboard).
if (registered && await widget.auth.isBiometricEnabled()) {
final timeout = await widget.auth.getTimeoutMinutes();
final valid = await widget.auth.hasValidSession(timeout);
if (!valid) {
_promptBiometricOnOpen();
return; // skip silent-auth path; biometric handles entry
}
}
_trySilentAuth();
}
/// Auto-prompt fingerprint on open when enabled; on success go to dashboard
/// (email may be empty for google-less accounts, fallback to stored email).
Future<void> _promptBiometricOnOpen() async {
final (ok, err) = await widget.auth.authenticateWithBiometrics();
if (!mounted) return;
if (ok) {
final email = await widget.auth.getEmail() ?? '';
_goToDashboard(email);
}
// on failure, the auth screen stays; user can tap Masuk manually
}
/// On open: if a valid session is present, go straight to Dashboard.
Future<void> _trySilentAuth() async {
final timeout = await widget.auth.getTimeoutMinutes();
@@ -51,7 +81,7 @@ class _AuthScreenState extends State<AuthScreen> {
);
}
Future<void> _submitEmail() async {
Future<void> _submit() async {
setState(() => _busy = true);
final email = _emailCtrl.text.trim();
final pass = _passCtrl.text;
@@ -113,20 +143,9 @@ class _AuthScreenState extends State<AuthScreen> {
const SizedBox(height: 12),
_busy
? const CircularProgressIndicator()
: Column(
children: [
ElevatedButton(
onPressed: _submitEmail,
child: Text(_isLogin ? 'Masuk' : 'Daftar'),
),
TextButton(
onPressed: () =>
setState(() => _isLogin = !_isLogin),
child: Text(_isLogin
? 'Belum punya akun? Daftar'
: 'Sudah punya akun? Masuk'),
),
],
: ElevatedButton(
onPressed: _submit,
child: Text(_isLogin ? 'Masuk' : 'Daftar'),
),
],
),