Persistence + wiring the offers screen needs, per the product decisions: - SocialSettings (keystore-backed, no plaintext): coarse area geohash + configurable relay URLs, both empty by default (no bundled public relays — don't leak metadata to third parties). Registered in DI. - createOffersCubit(): opens a SocialSession on the first configured relay when online, else a null-transport cubit that degrades gracefully. OffersCubit now closes the owning session on dispose. 4 settings tests green; offers/social suites still green.
41 lines
1.7 KiB
Dart
41 lines
1.7 KiB
Dart
import '../security/secret_store.dart';
|
|
|
|
/// 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.
|
|
///
|
|
/// Both default to "unset": empty area and no relays mean the social layer is
|
|
/// simply unavailable, and the app stays fully usable offline.
|
|
class SocialSettings {
|
|
SocialSettings(this._store);
|
|
|
|
final SecretStore _store;
|
|
|
|
static const _areaKey = 'tane.social.area_geohash';
|
|
static const _relaysKey = 'tane.social.relays';
|
|
|
|
/// 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<String> areaGeohash() async => (await _store.read(_areaKey)) ?? '';
|
|
|
|
Future<void> setAreaGeohash(String geohash) =>
|
|
_store.write(_areaKey, geohash.trim().toLowerCase());
|
|
|
|
/// Configured community relay URLs (empty by default — the user adds their
|
|
/// own; we bundle none, to avoid leaking metadata to third-party relays).
|
|
Future<List<String>> relayUrls() async {
|
|
final raw = await _store.read(_relaysKey);
|
|
if (raw == null || raw.isEmpty) return const [];
|
|
return raw.split('\n').where((s) => s.trim().isNotEmpty).toList();
|
|
}
|
|
|
|
Future<void> setRelayUrls(List<String> 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<bool> get isConfigured async =>
|
|
(await relayUrls()).isNotEmpty && (await areaGeohash()).isNotEmpty;
|
|
}
|