Add API Server (Go/PocketBase), Web App (Go BFF + Vue), Fly App (Flutter/DJI MSDK), Adobe Plugin, and Docker/Docker AIO deployment configs. Design assets and build artifacts are gitignored. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
59 lines
2.2 KiB
Dart
59 lines
2.2 KiB
Dart
import 'package:local_auth/local_auth.dart';
|
|
|
|
/// Thin wrapper over [LocalAuthentication] for the login screen. Exposes what
|
|
/// the device can do (fingerprint vs. face) and a single [authenticate] call.
|
|
class BiometricAuth {
|
|
final LocalAuthentication _auth = LocalAuthentication();
|
|
|
|
bool _supported = false;
|
|
bool _canCheck = false;
|
|
List<BiometricType> _types = const <BiometricType>[];
|
|
|
|
/// Whether any biometric login can be offered (device supports it and the
|
|
/// user has at least one biometric enrolled).
|
|
bool get available => _supported && _canCheck;
|
|
|
|
/// The device advertises a face enrolment. On some Androids the platform only
|
|
/// reports weak/strong instead of the specific modality — see [showFace].
|
|
bool get hasFace => _types.contains(BiometricType.face);
|
|
|
|
bool get _hasFingerprint =>
|
|
_types.contains(BiometricType.fingerprint) ||
|
|
_types.contains(BiometricType.strong) ||
|
|
_types.contains(BiometricType.weak);
|
|
|
|
/// Show the face button when face is reported, or when the device supports
|
|
/// biometrics but reports no specific modality (BiometricPrompt still lets the
|
|
/// user use whatever strong biometric — often face — is enrolled).
|
|
bool get showFace => available && (hasFace || _types.isEmpty);
|
|
|
|
/// Show the fingerprint button when fingerprint is reported, or as the generic
|
|
/// fallback when no specific modality is advertised.
|
|
bool get showFingerprint => available && (_hasFingerprint || _types.isEmpty);
|
|
|
|
/// Refreshes the capability flags. Safe to call repeatedly.
|
|
Future<void> refresh() async {
|
|
try {
|
|
_supported = await _auth.isDeviceSupported();
|
|
_canCheck = await _auth.canCheckBiometrics;
|
|
_types = _supported ? await _auth.getAvailableBiometrics() : const <BiometricType>[];
|
|
} catch (_) {
|
|
_supported = false;
|
|
_canCheck = false;
|
|
_types = const <BiometricType>[];
|
|
}
|
|
}
|
|
|
|
/// Prompts the OS biometric sheet. Returns true only on a verified match.
|
|
Future<bool> authenticate({required String reason}) {
|
|
return _auth.authenticate(
|
|
localizedReason: reason,
|
|
options: const AuthenticationOptions(
|
|
biometricOnly: true,
|
|
stickyAuth: true,
|
|
useErrorDialogs: true,
|
|
),
|
|
);
|
|
}
|
|
}
|