refactor(apps): 主题系统迁移至 ColorScheme + 扩展架构并支持 Dark Mode

This commit is contained in:
qzl
2026-03-27 19:07:39 +08:00
parent ecc1ec6ce4
commit ae29a8209b
146 changed files with 4301 additions and 3200 deletions
@@ -1,144 +0,0 @@
import 'dart:async';
import '../../../../core/cache/cache_entry.dart';
import '../../../../core/cache/cache_policy.dart';
import '../../../../core/cache/hybrid_cache_store.dart';
import '../models/schedule_item_model.dart';
class CalendarRepository {
final HybridCacheStore store;
final CachePolicy policy;
final DateTime Function() now;
final Future<List<ScheduleItemModel>> Function(DateTime date)
loadDayFromRemote;
final Future<List<ScheduleItemModel>> Function(DateTime start, DateTime end)
loadMonthFromRemote;
final Map<String, Future<void>> _refreshInFlight = <String, Future<void>>{};
CalendarRepository({
required this.store,
required this.loadDayFromRemote,
required this.loadMonthFromRemote,
CachePolicy? policy,
DateTime Function()? now,
}) : policy =
policy ??
const CachePolicy(
softTtl: Duration(minutes: 2),
hardTtl: Duration(minutes: 30),
minRefreshInterval: Duration(minutes: 1),
),
now = now ?? DateTime.now;
static String dayKey(DateTime date) {
final day =
'${date.year}-${date.month.toString().padLeft(2, '0')}-${date.day.toString().padLeft(2, '0')}';
return 'calendar:day:$day';
}
static String monthKey(DateTime date) {
return 'calendar:month:${date.year}-${date.month.toString().padLeft(2, '0')}';
}
Future<List<ScheduleItemModel>> getDayEvents(
DateTime date, {
bool forceRefresh = false,
}) async {
final key = dayKey(date);
if (forceRefresh) {
return _refreshDayAndRead(date, key);
}
final cached = await store.read<CacheEntry<List<ScheduleItemModel>>>(key);
if (cached == null) {
return _refreshDayAndRead(date, key);
}
final decision = policy.evaluate(now: now(), fetchedAt: cached.fetchedAt);
if (decision.shouldRefreshInBackground) {
_refreshDayInBackground(date, key);
}
if (decision.mustBlockForNetwork || !decision.canUseCached) {
return _refreshDayAndRead(date, key);
}
return cached.value;
}
Future<List<ScheduleItemModel>> getMonthEvents(
DateTime monthStart, {
bool forceRefresh = false,
}) async {
final key = monthKey(monthStart);
if (forceRefresh) {
return _refreshMonthAndRead(monthStart, key);
}
final cached = await store.read<CacheEntry<List<ScheduleItemModel>>>(key);
if (cached == null) {
return _refreshMonthAndRead(monthStart, key);
}
final decision = policy.evaluate(now: now(), fetchedAt: cached.fetchedAt);
if (decision.shouldRefreshInBackground) {
_refreshMonthInBackground(monthStart, key);
}
if (decision.mustBlockForNetwork || !decision.canUseCached) {
return _refreshMonthAndRead(monthStart, key);
}
return cached.value;
}
Future<List<ScheduleItemModel>> _refreshDayAndRead(
DateTime date,
String key,
) async {
await _refreshDay(date, key);
final cached = await store.read<CacheEntry<List<ScheduleItemModel>>>(key);
return cached?.value ?? const <ScheduleItemModel>[];
}
Future<List<ScheduleItemModel>> _refreshMonthAndRead(
DateTime monthStart,
String key,
) async {
await _refreshMonth(monthStart, key);
final cached = await store.read<CacheEntry<List<ScheduleItemModel>>>(key);
return cached?.value ?? const <ScheduleItemModel>[];
}
Future<void> _refreshDay(DateTime date, String key) async {
final remote = await loadDayFromRemote(date);
await store.write<CacheEntry<List<ScheduleItemModel>>>(
key,
CacheEntry<List<ScheduleItemModel>>(value: remote, fetchedAt: now()),
);
}
Future<void> _refreshMonth(DateTime monthStart, String key) async {
final start = DateTime(monthStart.year, monthStart.month, 1);
final end = DateTime(monthStart.year, monthStart.month + 1, 0, 23, 59, 59);
final remote = await loadMonthFromRemote(start, end);
await store.write<CacheEntry<List<ScheduleItemModel>>>(
key,
CacheEntry<List<ScheduleItemModel>>(value: remote, fetchedAt: now()),
);
}
void _refreshDayInBackground(DateTime date, String key) {
_refreshInBackground(key, () => _refreshDay(date, key));
}
void _refreshMonthInBackground(DateTime monthStart, String key) {
_refreshInBackground(key, () => _refreshMonth(monthStart, key));
}
void _refreshInBackground(String key, Future<void> Function() taskFactory) {
if (_refreshInFlight.containsKey(key)) {
return;
}
final task = taskFactory().whenComplete(() {
_refreshInFlight.remove(key);
});
_refreshInFlight[key] = task;
unawaited(task);
}
}
@@ -1,92 +0,0 @@
import 'package:social_app/core/network/i_api_client.dart';
import 'package:social_app/core/cache/cache_invalidator.dart';
import 'package:social_app/app/di/injection.dart';
import '../calendar_api.dart';
import '../models/schedule_item_model.dart';
class CalendarService {
final IApiClient _apiClient;
CalendarApi? _calendarApi;
CalendarService({required IApiClient apiClient}) : _apiClient = apiClient;
CalendarApi get _api {
final api = _calendarApi;
if (api != null) {
return api;
}
final created = CalendarApi(_apiClient);
_calendarApi = created;
return created;
}
Future<List<ScheduleItemModel>> getEventsForDay(DateTime date) async {
final start = DateTime(date.year, date.month, date.day);
final end = DateTime(date.year, date.month, date.day, 23, 59, 59);
return getEventsForRange(start, end);
}
Future<List<ScheduleItemModel>> getEventsForRange(
DateTime start,
DateTime end,
) async {
return _api.listByRange(startAt: start, endAt: end);
}
Future<ScheduleItemModel?> getEventById(String id) async {
return _api.getById(id);
}
Future<ScheduleItemModel> addEvent(ScheduleItemModel event) async {
final created = await _api.create(event);
_invalidateEventCache(created);
return created;
}
Future<ScheduleItemModel> updateEvent(ScheduleItemModel event) async {
final updated = await _api.update(event);
_invalidateEventCache(updated);
return updated;
}
Future<ScheduleItemModel?> archiveEvent(String id) async {
final event = await getEventById(id);
if (event == null) {
return null;
}
final updatedEvent = await updateEvent(
event.copyWith(status: ScheduleStatus.archived),
);
_invalidateEventCache(updatedEvent);
return updatedEvent;
}
void _invalidateEventCache(ScheduleItemModel event) {
try {
final invalidator = sl<CacheInvalidator>();
var current = DateTime(
event.startAt.year,
event.startAt.month,
event.startAt.day,
);
final end = DateTime(
event.endAt?.year ?? event.startAt.year,
event.endAt?.month ?? event.startAt.month,
event.endAt?.day ?? event.startAt.day,
);
while (!current.isAfter(end)) {
invalidator.invalidateCalendarDay(current);
current = current.add(const Duration(days: 1));
}
} catch (_) {}
}
Future<void> deleteEvent(String id) async {
final event = await getEventById(id);
if (event != null) {
_invalidateEventCache(event);
}
await _api.delete(id);
}
}