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 '../../features/chat/data/repositories/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 Function()? prewarmChatHistory, Future Function()? prewarmCalendarToday, Future Function()? prewarmUnreadInbox, }) : _calendarRepository = calendarRepository, _inboxRepository = inboxRepository, _chatHistoryRepository = chatHistoryRepository, _prewarmChatHistory = prewarmChatHistory, _prewarmCalendarToday = prewarmCalendarToday, _prewarmUnreadInbox = prewarmUnreadInbox; final CalendarRepository _calendarRepository; final InboxRepository _inboxRepository; final ChatHistoryRepository _chatHistoryRepository; final Duration bootBudget; final Future Function()? _prewarmChatHistory; final Future Function()? _prewarmCalendarToday; final Future Function()? _prewarmUnreadInbox; AppPrewarmStatus _status = AppPrewarmStatus.idle; AppPrewarmStatus get status => _status; String? _userId; Future? _running; bool get isBootBlocking => _status == AppPrewarmStatus.running; Future ensureStartedFor(String userId) { if (_userId == userId && (_status == AppPrewarmStatus.completed || _status == AppPrewarmStatus.timedOut)) { return Future.value(); } if (_userId == userId && _running != null) { return _running!; } _userId = userId; _status = AppPrewarmStatus.running; notifyListeners(); final tasks = Future.wait([ _runPrewarmChatHistory(), _runPrewarmCalendarToday(), _runPrewarmUnreadInbox(), ]); final running = _runWithBudget(tasks); _running = running; return running.whenComplete(() { if (identical(_running, running)) { _running = null; } }); } Future _runPrewarmChatHistory() { final override = _prewarmChatHistory; if (override != null) { return override(); } return _chatHistoryRepository.loadHistory(); } Future _runPrewarmCalendarToday() { final override = _prewarmCalendarToday; if (override != null) { return override(); } return _calendarRepository.getDayEvents(DateTime.now()); } Future _runPrewarmUnreadInbox() { final override = _prewarmUnreadInbox; if (override != null) { return override(); } return _inboxRepository.getMessages(isRead: false); } Future _runWithBudget(Future tasks) async { try { await tasks.timeout(bootBudget); _status = AppPrewarmStatus.completed; notifyListeners(); } on TimeoutException { _status = AppPrewarmStatus.timedOut; notifyListeners(); } catch (_) { _status = AppPrewarmStatus.failed; notifyListeners(); } } void reset() { _userId = null; _running = null; if (_status != AppPrewarmStatus.idle) { _status = AppPrewarmStatus.idle; notifyListeners(); } } }