import '../security/secret_store.dart'; /// A suggested community server the user can join with one tap. class RelayPreset { const RelayPreset(this.name, this.url); final String name; final String url; } /// User choices for the (Block 2) social layer: the coarse area to publish/ /// browse offers in, and which community relays to talk to. Backed by the OS /// keystore (via [SecretStore]) to honour "no plaintext at rest" — no /// shared_preferences. /// /// Relays default to a small set of well-known public servers so the market /// works out of the box; the exposure is minimal (offers are opt-in and carry /// only a coarse geohash) and the user can swap them for a community server. /// The area stays unset until the user picks one (it's inherently personal). class SocialSettings { SocialSettings(this._store); final SecretStore _store; static const _areaKey = 'tane.social.area_geohash'; static const _relaysKey = 'tane.social.relays'; /// Suggested servers shown as one-tap options in the sharing setup. static const List presets = [ RelayPreset('nos.lol', 'wss://nos.lol'), RelayPreset('Damus', 'wss://relay.damus.io'), RelayPreset('Primal', 'wss://relay.primal.net'), ]; /// Applied automatically for new users (a subset of [presets]) so sharing /// works from the first launch, until the user changes it. static const List defaultRelays = ['wss://nos.lol', 'wss://relay.damus.io']; /// The user's coarse area as a low-precision geohash (may be empty). Set /// manually or from device location; the transport coarsens it further. Future areaGeohash() async => (await _store.read(_areaKey)) ?? ''; Future setAreaGeohash(String geohash) => _store.write(_areaKey, geohash.trim().toLowerCase()); /// The relays to talk to. When the user has never configured any, falls back /// to [defaultRelays]. Once they save a choice (even an empty one), that wins /// — so a privacy-minded user can turn the network off entirely. Future> relayUrls() async { final raw = await _store.read(_relaysKey); if (raw == null) return const [...defaultRelays]; // never configured return raw.split('\n').where((s) => s.trim().isNotEmpty).toList(); } Future setRelayUrls(List urls) => _store.write( _relaysKey, urls.map((u) => u.trim()).where((u) => u.isNotEmpty).join('\n'), ); /// Whether the social layer has enough config to attempt going online. Future get isConfigured async => (await relayUrls()).isNotEmpty && (await areaGeohash()).isNotEmpty; }