58 lines
1.6 KiB
Dart
58 lines
1.6 KiB
Dart
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<String> _memory = <String>{};
|
|
bool _hydrated = false;
|
|
|
|
Future<void> 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<String>());
|
|
}
|
|
}
|
|
} catch (_) {}
|
|
_hydrated = true;
|
|
}
|
|
|
|
bool contains(String? uuid) {
|
|
if (uuid == null || uuid.isEmpty) return false;
|
|
return _memory.contains(uuid);
|
|
}
|
|
|
|
Future<void> 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<void> clear() async {
|
|
_memory.clear();
|
|
try {
|
|
await _storage.delete(key: _key);
|
|
} catch (_) {}
|
|
}
|
|
}
|