implemented a comprehensive client-side demo mode triggered by a "demo@" username prefix, serving curated fixture data for all app modules

This commit is contained in:
2026-07-07 20:24:16 +02:00
parent 2668b111f1
commit 9b74c9fd81
45 changed files with 1409 additions and 43 deletions
+26
View File
@@ -18,6 +18,10 @@ class AccountData {
// token, so two registrations need two app passwords.
static const _appPasswordField = 'nextcloud_app_password';
static const _appPasswordTalkField = 'nextcloud_app_password_talk';
// Persists the demo session across cold starts (see DemoMode).
static const _demoField = 'is_demo';
// Keeps isPopulated()/getPassword() valid; demo mode never uses a real one.
static const _demoPasswordPlaceholder = 'demo';
static const FlutterSecureStorage _secureStorage = FlutterSecureStorage();
@@ -34,6 +38,10 @@ class AccountData {
String? _password;
String? _appPassword;
String? _appPasswordTalk;
bool _isDemo = false;
/// True while the active session is a local demo session (see DemoMode).
bool get isDemo => _isDemo;
String getUsername() {
if (_username == null) throw Exception('Username not initialized');
@@ -65,14 +73,31 @@ class AccountData {
if (!_populated.isCompleted) _populated.complete();
}
/// Enters a local demo session for [username] — no real credentials or token;
/// every backend is served from fixtures while [isDemo] is true (see DemoMode).
Future<void> setDemo(String username) async {
await _secureStorage.write(key: _usernameField, value: username);
await _secureStorage.write(
key: _passwordField,
value: _demoPasswordPlaceholder,
);
await _secureStorage.write(key: _demoField, value: 'true');
_username = username;
_password = _demoPasswordPlaceholder;
_isDemo = true;
if (!_populated.isCompleted) _populated.complete();
}
Future<void> removeData() async {
_populated = Completer();
_username = null;
_password = null;
_appPassword = null;
_appPasswordTalk = null;
_isDemo = false;
await _secureStorage.delete(key: _usernameField);
await _secureStorage.delete(key: _passwordField);
await _secureStorage.delete(key: _demoField);
await _clearAppPasswordStorage();
await _clearAppPasswordTalkStorage();
}
@@ -139,6 +164,7 @@ class AccountData {
await _migrateFromLegacyStorage();
_username = await _secureStorage.read(key: _usernameField);
_password = await _secureStorage.read(key: _passwordField);
_isDemo = (await _secureStorage.read(key: _demoField)) == 'true';
try {
_appPassword = await pushSecureStorage.read(key: _appPasswordField);
_appPasswordTalk = await pushSecureStorage.read(