Add app lock, multi-account support, and redesigned account settings
App lock (local_auth) gates the app behind the OS's biometric/device credential prompt via a new lock screen, layered on top of the existing Nextcloud session rather than replacing it. Multi-account support lets users save several Nextcloud logins and switch between them (AccountStore, per-account browsing prefs, avatar swipe-to- cycle); logout() now keeps an account's saved credentials/prefs intact so it can be resumed from a "Continue as..." list, while removeAccount() stays the only destructive path. The account settings screen is redesigned around a single profile card (avatar/name/email, server host, storage quota with groups) with Refresh Cache/Logout/Remove actions, replacing the old separate "Server Connection Info" section. Also fixes activity-tab timestamps: the OCS Activity API reports time as an ISO 8601 `datetime` string, not the numeric `timestamp` field the code incorrectly assumed, which made every activity render as Jan 1 1970. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
import 'package:local_auth/local_auth.dart';
|
||||
|
||||
/// Thin wrapper around `local_auth`. Deliberately doesn't implement its own
|
||||
/// PIN storage/hashing - `authenticate` delegates to whatever the OS
|
||||
/// already has configured (fingerprint/face, or the device's own PIN/
|
||||
/// pattern/password as a fallback when `biometricOnly` is false), which is
|
||||
/// both simpler and more secure than reimplementing credential storage.
|
||||
class AppLockService {
|
||||
static final LocalAuthentication _auth = LocalAuthentication();
|
||||
|
||||
/// Whether this device can do *some* form of local auth - biometric
|
||||
/// enrolled, or at minimum a device PIN/pattern/password set up.
|
||||
static Future<bool> isDeviceSupported() async {
|
||||
try {
|
||||
final canCheckBiometrics = await _auth.canCheckBiometrics;
|
||||
if (canCheckBiometrics) return true;
|
||||
return await _auth.isDeviceSupported();
|
||||
} catch (_) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// Prompts for biometric or device-credential auth. Returns false (never
|
||||
/// throws) on cancellation, failure, or any platform error, so callers
|
||||
/// can treat every non-true result the same way: stay locked/blocked.
|
||||
static Future<bool> authenticate(String reason) async {
|
||||
try {
|
||||
return await _auth.authenticate(
|
||||
localizedReason: reason,
|
||||
options: const AuthenticationOptions(
|
||||
biometricOnly: false,
|
||||
stickyAuth: true,
|
||||
// Default (true) requires an extra manual confirmation tap after
|
||||
// a *passive* modality like face/iris recognizes you - Android's
|
||||
// own guidance reserves that for confirming risky actions
|
||||
// (a purchase); unlocking the app is exactly the "lower-risk"
|
||||
// case they say to pass false for, and on some devices/Android
|
||||
// versions it also determines whether face is offered as an
|
||||
// option in the prompt at all, not just whether it needs a
|
||||
// second tap to accept.
|
||||
sensitiveTransaction: false,
|
||||
),
|
||||
);
|
||||
} catch (_) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user