import 'dart:developer'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import '../state/app/modules/timetable/bloc/timetable_state.dart'; import '../storage/settings.dart'; import 'widget_data_mapper.dart'; import 'widget_sync.dart'; /// Pushes timetable state to the native widget whenever the foreground bloc /// has fresh data, so the widget doesn't have to wait for the next periodic /// background fetch. class WidgetPublisher { /// Debug-only "now" offset. Gated by [kDebugMode] so a stray non-zero /// value cannot ship in release. static const Duration debugTimeShift = Duration.zero; static DateTime widgetNow() => kDebugMode ? DateTime.now().add(debugTimeShift) : DateTime.now(); static Future publishFromBlocState( TimetableState state, { Settings? settings, }) async { try { final connectDouble = settings?.timetableSettings.connectDoubleLessons ?? true; // Mirror into widget storage so the background isolate sees the same // value the user just toggled. await WidgetSync.setConnectDoubleLessons(connectDouble); await WidgetSync.setThemeMode(_themeName(settings?.appTheme)); final lessons = state.getAllKnownLessons(); final now = widgetNow(); final dayData = WidgetDataMapper.buildDayData( now: now, lessons: lessons, subjects: state.subjects, rooms: state.rooms, holidays: state.schoolHolidays, timegrid: state.timegrid, customEvents: state.customEvents, connectDoubleLessons: connectDouble, ); final weekData = WidgetDataMapper.buildWeekData( now: now, lessons: lessons, subjects: state.subjects, rooms: state.rooms, holidays: state.schoolHolidays, timegrid: state.timegrid, customEvents: state.customEvents, connectDoubleLessons: connectDouble, ); await WidgetSync.writeDayData(dayData); await WidgetSync.writeWeekData(weekData); await WidgetSync.setLoggedIn(true); await WidgetSync.triggerUpdate(); } on Object catch (e, s) { // Catch Object: non-Exception Errors (RangeError, StateError) from the // bloc layer must not escape into the stream listener. log('WidgetPublisher.publishFromBlocState failed: $e', stackTrace: s); } } static String _themeName(ThemeMode? mode) { switch (mode) { case ThemeMode.light: return 'light'; case ThemeMode.dark: return 'dark'; case ThemeMode.system: case null: return 'system'; } } }