156 lines
4.5 KiB
Dart
156 lines
4.5 KiB
Dart
import 'dart:async';
|
|
|
|
import 'package:flutter/foundation.dart';
|
|
|
|
import '../../features/calendar/data/repositories/calendar_repository.dart';
|
|
import '../../features/messages/data/repositories/inbox_repository.dart';
|
|
import '../../core/chat/chat_history_repository.dart';
|
|
|
|
enum AppPrewarmStatus { idle, running, completed, timedOut, failed }
|
|
|
|
class AppPrewarmOrchestrator extends ChangeNotifier {
|
|
AppPrewarmOrchestrator({
|
|
required CalendarRepository calendarRepository,
|
|
required InboxRepository inboxRepository,
|
|
required ChatHistoryRepository chatHistoryRepository,
|
|
this.bootBudget = const Duration(milliseconds: 1200),
|
|
Future<void> Function()? prewarmChatHistory,
|
|
Future<void> Function()? prewarmCalendarToday,
|
|
Future<void> Function()? prewarmCalendarReminderWindow,
|
|
Future<void> Function()? prewarmUnreadInbox,
|
|
}) : _calendarRepository = calendarRepository,
|
|
_inboxRepository = inboxRepository,
|
|
_chatHistoryRepository = chatHistoryRepository,
|
|
_prewarmChatHistory = prewarmChatHistory,
|
|
_prewarmCalendarToday = prewarmCalendarToday,
|
|
_prewarmCalendarReminderWindow = prewarmCalendarReminderWindow,
|
|
_prewarmUnreadInbox = prewarmUnreadInbox;
|
|
|
|
final CalendarRepository _calendarRepository;
|
|
final InboxRepository _inboxRepository;
|
|
final ChatHistoryRepository _chatHistoryRepository;
|
|
final Duration bootBudget;
|
|
final Future<void> Function()? _prewarmChatHistory;
|
|
final Future<void> Function()? _prewarmCalendarToday;
|
|
final Future<void> Function()? _prewarmCalendarReminderWindow;
|
|
final Future<void> Function()? _prewarmUnreadInbox;
|
|
|
|
AppPrewarmStatus _status = AppPrewarmStatus.idle;
|
|
AppPrewarmStatus get status => _status;
|
|
|
|
String? _userId;
|
|
Future<void>? _running;
|
|
int _runToken = 0;
|
|
|
|
bool get isBootBlocking => _status == AppPrewarmStatus.running;
|
|
|
|
Future<void> ensureStartedFor(String userId) {
|
|
if (_userId == userId &&
|
|
(_status == AppPrewarmStatus.completed ||
|
|
_status == AppPrewarmStatus.timedOut)) {
|
|
return Future<void>.value();
|
|
}
|
|
if (_userId == userId && _running != null) {
|
|
return _running!;
|
|
}
|
|
|
|
_userId = userId;
|
|
final runToken = ++_runToken;
|
|
_status = AppPrewarmStatus.running;
|
|
notifyListeners();
|
|
|
|
final tasks = Future.wait<void>([
|
|
_runPrewarmChatHistory(),
|
|
_runPrewarmCalendarToday(),
|
|
_runPrewarmCalendarReminderWindow(),
|
|
_runPrewarmUnreadInbox(),
|
|
]);
|
|
|
|
final running = _runWithBudget(tasks, userId: userId, runToken: runToken);
|
|
_running = running;
|
|
return running.whenComplete(() {
|
|
if (identical(_running, running)) {
|
|
_running = null;
|
|
}
|
|
});
|
|
}
|
|
|
|
Future<void> _runPrewarmChatHistory() {
|
|
final override = _prewarmChatHistory;
|
|
if (override != null) {
|
|
return override();
|
|
}
|
|
return _chatHistoryRepository.loadHistory();
|
|
}
|
|
|
|
Future<void> _runPrewarmCalendarToday() {
|
|
final override = _prewarmCalendarToday;
|
|
if (override != null) {
|
|
return override();
|
|
}
|
|
return _calendarRepository.getDayEvents(DateTime.now());
|
|
}
|
|
|
|
Future<void> _runPrewarmUnreadInbox() {
|
|
final override = _prewarmUnreadInbox;
|
|
if (override != null) {
|
|
return override();
|
|
}
|
|
return _inboxRepository.getMessages(isRead: false);
|
|
}
|
|
|
|
Future<void> _runPrewarmCalendarReminderWindow() {
|
|
final override = _prewarmCalendarReminderWindow;
|
|
if (override != null) {
|
|
return override();
|
|
}
|
|
final now = DateTime.now();
|
|
final start = DateTime(
|
|
now.year,
|
|
now.month,
|
|
now.day,
|
|
).subtract(const Duration(days: 1));
|
|
final end = start.add(const Duration(days: 90));
|
|
return _calendarRepository.listByRange(startAt: start, endAt: end);
|
|
}
|
|
|
|
Future<void> _runWithBudget(
|
|
Future<void> tasks, {
|
|
required String userId,
|
|
required int runToken,
|
|
}) async {
|
|
bool isLatestRun() => _runToken == runToken && _userId == userId;
|
|
|
|
try {
|
|
await tasks.timeout(bootBudget);
|
|
if (!isLatestRun()) {
|
|
return;
|
|
}
|
|
_status = AppPrewarmStatus.completed;
|
|
notifyListeners();
|
|
} on TimeoutException {
|
|
if (!isLatestRun()) {
|
|
return;
|
|
}
|
|
_status = AppPrewarmStatus.timedOut;
|
|
notifyListeners();
|
|
} catch (_) {
|
|
if (!isLatestRun()) {
|
|
return;
|
|
}
|
|
_status = AppPrewarmStatus.failed;
|
|
notifyListeners();
|
|
}
|
|
}
|
|
|
|
void reset() {
|
|
_userId = null;
|
|
_running = null;
|
|
_runToken += 1;
|
|
if (_status != AppPrewarmStatus.idle) {
|
|
_status = AppPrewarmStatus.idle;
|
|
notifyListeners();
|
|
}
|
|
}
|
|
}
|