import 'package:flutter_secure_storage/flutter_secure_storage.dart'; /// A Subsonic server connection. The password is only ever held in memory and /// in the platform secure store — never in plain app storage (mirrors Ratune's /// keyring-first secret handling). class SubsonicCredentials { const SubsonicCredentials({ required this.url, required this.username, required this.password, this.alias, }); final String url; final String username; final String password; /// Optional display label shown instead of the raw URL (Ratune `[server].alias`). final String? alias; String get display => alias?.isNotEmpty == true ? alias! : Uri.parse(url).host; } /// Persists [SubsonicCredentials] to the platform secure store /// (Keychain / Keystore / libsecret). class CredentialStore { CredentialStore([FlutterSecureStorage? storage]) : _storage = storage ?? const FlutterSecureStorage(); final FlutterSecureStorage _storage; static const _kUrl = 'subsonic_url'; static const _kUser = 'subsonic_username'; static const _kPass = 'subsonic_password'; static const _kAlias = 'subsonic_alias'; Future save(SubsonicCredentials creds) async { await _storage.write(key: _kUrl, value: creds.url); await _storage.write(key: _kUser, value: creds.username); await _storage.write(key: _kPass, value: creds.password); await _storage.write(key: _kAlias, value: creds.alias ?? ''); } Future load() async { final url = await _storage.read(key: _kUrl); final user = await _storage.read(key: _kUser); final pass = await _storage.read(key: _kPass); if (url == null || user == null || pass == null) return null; final alias = await _storage.read(key: _kAlias); return SubsonicCredentials( url: url, username: user, password: pass, alias: (alias == null || alias.isEmpty) ? null : alias, ); } Future clear() async { await _storage.delete(key: _kUrl); await _storage.delete(key: _kUser); await _storage.delete(key: _kPass); await _storage.delete(key: _kAlias); } }