refactor(apps): 主题系统迁移至 ColorScheme + 扩展架构并支持 Dark Mode
This commit is contained in:
+107
@@ -0,0 +1,107 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'cache_entry.dart';
|
||||
import 'cache_policy.dart';
|
||||
import 'hybrid_cache_store.dart';
|
||||
|
||||
abstract class CachedRepository<T> {
|
||||
final HybridCacheStore store;
|
||||
final CachePolicy policy;
|
||||
final DateTime Function() now;
|
||||
final Map<String, Future<void>> _refreshInFlight = <String, Future<void>>{};
|
||||
|
||||
CachedRepository({
|
||||
required this.store,
|
||||
required this.policy,
|
||||
DateTime Function()? now,
|
||||
}) : now = now ?? DateTime.now;
|
||||
|
||||
Future<T> getOrLoad({
|
||||
required String key,
|
||||
required Future<T> Function() loadFromRemote,
|
||||
bool Function(T loaded)? shouldWriteLoaded,
|
||||
bool forceRefresh = false,
|
||||
}) async {
|
||||
if (forceRefresh) {
|
||||
return _refreshAndWrite(
|
||||
key,
|
||||
loadFromRemote,
|
||||
shouldWriteLoaded: shouldWriteLoaded,
|
||||
);
|
||||
}
|
||||
|
||||
final cached = await readCacheEntry(key);
|
||||
if (cached == null) {
|
||||
return _refreshAndWrite(
|
||||
key,
|
||||
loadFromRemote,
|
||||
shouldWriteLoaded: shouldWriteLoaded,
|
||||
);
|
||||
}
|
||||
|
||||
final decision = policy.evaluate(now: now(), fetchedAt: cached.fetchedAt);
|
||||
if (decision.shouldRefreshInBackground) {
|
||||
refreshInBackground(
|
||||
key: key,
|
||||
loadFromRemote: loadFromRemote,
|
||||
shouldWriteLoaded: shouldWriteLoaded,
|
||||
);
|
||||
}
|
||||
if (decision.mustBlockForNetwork || !decision.canUseCached) {
|
||||
return _refreshAndWrite(
|
||||
key,
|
||||
loadFromRemote,
|
||||
shouldWriteLoaded: shouldWriteLoaded,
|
||||
);
|
||||
}
|
||||
return cached.value;
|
||||
}
|
||||
|
||||
Future<CacheEntry<T>?> readCacheEntry(String key) {
|
||||
return store.read<CacheEntry<T>>(key);
|
||||
}
|
||||
|
||||
Future<void> writeCacheEntry(String key, T value) {
|
||||
return store.write<CacheEntry<T>>(
|
||||
key,
|
||||
CacheEntry<T>(value: value, fetchedAt: now()),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> removeCacheKey(String key) {
|
||||
return store.remove(key);
|
||||
}
|
||||
|
||||
void refreshInBackground({
|
||||
required String key,
|
||||
required Future<T> Function() loadFromRemote,
|
||||
bool Function(T loaded)? shouldWriteLoaded,
|
||||
}) {
|
||||
if (_refreshInFlight.containsKey(key)) {
|
||||
return;
|
||||
}
|
||||
final task = _refreshAndWrite(
|
||||
key,
|
||||
loadFromRemote,
|
||||
shouldWriteLoaded: shouldWriteLoaded,
|
||||
).then((_) {});
|
||||
final tracked = task.whenComplete(() {
|
||||
_refreshInFlight.remove(key);
|
||||
});
|
||||
_refreshInFlight[key] = tracked;
|
||||
unawaited(tracked);
|
||||
}
|
||||
|
||||
Future<T> _refreshAndWrite(
|
||||
String key,
|
||||
Future<T> Function() loadFromRemote, {
|
||||
bool Function(T loaded)? shouldWriteLoaded,
|
||||
}) async {
|
||||
final remote = await loadFromRemote();
|
||||
if (shouldWriteLoaded != null && !shouldWriteLoaded(remote)) {
|
||||
return remote;
|
||||
}
|
||||
await writeCacheEntry(key, remote);
|
||||
return remote;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user