import 'dart:convert'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; /// Local persistence of story content-uuids the user has already viewed. /// Backend's `isRead` may lag or reset on next fetch; this cache guarantees /// the ring turns grey right after viewing and stays grey across refetches. class StoryReadCache { StoryReadCache._(); static final StoryReadCache instance = StoryReadCache._(); static const String _key = 'story_read_uuids'; static const int _maxEntries = 500; static const FlutterSecureStorage _storage = FlutterSecureStorage(); final Set _memory = {}; bool _hydrated = false; Future hydrate() async { if (_hydrated) return; try { final raw = await _storage.read(key: _key); if (raw != null && raw.isNotEmpty) { final decoded = jsonDecode(raw); if (decoded is List) { _memory.addAll(decoded.whereType()); } } } catch (_) {} _hydrated = true; } bool contains(String? uuid) { if (uuid == null || uuid.isEmpty) return false; return _memory.contains(uuid); } Future add(String? uuid) async { if (uuid == null || uuid.isEmpty) return; if (!_memory.add(uuid)) return; if (_memory.length > _maxEntries) { final excess = _memory.length - _maxEntries; final toRemove = _memory.take(excess).toList(); _memory.removeAll(toRemove); } try { await _storage.write(key: _key, value: jsonEncode(_memory.toList())); } catch (_) {} } Future clear() async { _memory.clear(); try { await _storage.delete(key: _key); } catch (_) {} } }