refactor(apps): 重构数据层目录结构并新增启动预热编排器

This commit is contained in:
zl-q
2026-03-29 20:26:30 +08:00
parent 33340de8f9
commit 4db9a13bfe
108 changed files with 1653 additions and 1320 deletions
@@ -0,0 +1,86 @@
import '../../../../data/cache/cache_policy.dart';
import '../../../../data/cache/cached_repository.dart';
import '../../../contacts/data/models/user_profile.dart';
class UserProfileCacheRepository extends CachedRepository<UserProfile> {
static const String cacheKey = 'settings:user_profile';
final Future<UserProfile> Function() remoteLoader;
UserProfile? _cachedUser;
int _generation = 0;
UserProfileCacheRepository({
required super.store,
required this.remoteLoader,
CachePolicy? policy,
super.now,
}) : super(
policy:
policy ??
const CachePolicy(
softTtl: Duration(minutes: 2),
hardTtl: Duration(minutes: 30),
minRefreshInterval: Duration(minutes: 1),
),
encodeValue: _encodeUserProfile,
decodeValue: _decodeUserProfile,
);
UserProfile? get cachedUser => _cachedUser;
Future<UserProfile> getProfile({bool forceRefresh = false}) async {
final generation = _generation;
final user = await getOrLoad(
key: cacheKey,
forceRefresh: forceRefresh,
loadFromRemote: _loadAndRemember,
shouldWriteLoaded: (_) => generation == _generation,
);
if (generation == _generation) {
_cachedUser = user;
}
return user;
}
Future<void> setCached(UserProfile user) async {
final generation = _generation;
_cachedUser = user;
await writeCacheEntry(cacheKey, user);
if (generation != _generation) {
_cachedUser = null;
await removeCacheKey(cacheKey);
}
}
Future<void> invalidate() async {
_generation += 1;
_cachedUser = null;
await removeCacheKey(cacheKey);
}
Future<UserProfile> _loadAndRemember() async {
final generation = _generation;
final remote = await remoteLoader();
if (generation == _generation) {
_cachedUser = remote;
}
return remote;
}
static Object? _encodeUserProfile(UserProfile user) {
return <String, Object?>{
'id': user.id,
'username': user.username,
'phone': user.phone,
'avatar_url': user.avatarUrl,
'bio': user.bio,
};
}
static UserProfile _decodeUserProfile(Object? raw) {
if (raw is! Map) {
throw const FormatException('Invalid cached user profile payload');
}
return UserProfile.fromJson(Map<String, dynamic>.from(raw));
}
}