import 'dart:async'; import 'dart:convert'; import 'dart:developer'; import 'package:home_widget/home_widget.dart'; import 'widget_data.dart'; /// Bridge to the native widget host. All keys/names live here so the Kotlin /// and Swift sides stay in sync. class WidgetSync { static const String iosAppGroupId = 'group.eu.mhsl.marianum.mobile.client.widget'; static const String iosWidgetKind = 'TimetableWidget'; static const String androidDayProvider = 'TimetableDayWidget'; static const String androidWeekProvider = 'TimetableWeekWidget'; // `_v1` suffix lets a future schema change invalidate stale snapshots // by bumping the key instead of risking a parse crash. static const String dayDataKey = 'widget_data_day_v1'; static const String weekDataKey = 'widget_data_week_v1'; static const String fetchedAtKey = 'widget_data_fetched_at_v1'; static const String loggedInKey = 'widget_data_logged_in_v1'; // Mirrored into widget storage so the background isolate can read it // without reopening HydratedBloc storage. static const String connectDoubleLessonsKey = 'widget_setting_connect_double_lessons_v1'; static const String themeModeKey = 'widget_setting_theme_mode_v1'; static bool _initialised = false; static Future ensureInitialized() async { if (_initialised) return; await HomeWidget.setAppGroupId(iosAppGroupId); _initialised = true; } static Future writeDayData(WidgetTimetableData data) async { await ensureInitialized(); await HomeWidget.saveWidgetData(dayDataKey, jsonEncode(data.toJson())); await HomeWidget.saveWidgetData( fetchedAtKey, data.fetchedAt.toIso8601String(), ); } static Future writeWeekData(WidgetTimetableData data) async { await ensureInitialized(); await HomeWidget.saveWidgetData( weekDataKey, jsonEncode(data.toJson()), ); await HomeWidget.saveWidgetData( fetchedAtKey, data.fetchedAt.toIso8601String(), ); } static Future setLoggedIn(bool loggedIn) async { await ensureInitialized(); await HomeWidget.saveWidgetData(loggedInKey, loggedIn); } static Future setConnectDoubleLessons(bool value) async { await ensureInitialized(); await HomeWidget.saveWidgetData(connectDoubleLessonsKey, value); } /// Default `true` matches `default_settings.dart` — fresh install behaves /// like the in-app calendar. static Future getConnectDoubleLessons() async { await ensureInitialized(); final value = await HomeWidget.getWidgetData( connectDoubleLessonsKey, defaultValue: true, ); return value ?? true; } static Future setThemeMode(String mode) async { await ensureInitialized(); await HomeWidget.saveWidgetData(themeModeKey, mode); } static Future clear() async { await ensureInitialized(); await HomeWidget.saveWidgetData(dayDataKey, null); await HomeWidget.saveWidgetData(weekDataKey, null); await HomeWidget.saveWidgetData(fetchedAtKey, null); await HomeWidget.saveWidgetData(loggedInKey, false); } static Future triggerUpdate() async { await ensureInitialized(); try { await HomeWidget.updateWidget( androidName: androidDayProvider, iOSName: iosWidgetKind, ); await HomeWidget.updateWidget( androidName: androidWeekProvider, iOSName: iosWidgetKind, ); } on Exception catch (e) { log('WidgetSync.triggerUpdate failed: $e'); } } }