import 'package:flutter/widgets.dart'; import 'package:flutter_foreground_task/flutter_foreground_task.dart'; import '../l10n/app_localizations.dart'; import '../utils/platform_info.dart'; class BackgroundService { bool _initialized = false; String? Function()? _languageOverrideProvider; /// Allows the app to expose its current language override (e.g. from /// AppSettingsService) so the foreground notification matches the app UI /// language instead of only the system locale. void setLanguageOverrideProvider(String? Function()? provider) { _languageOverrideProvider = provider; } Future initialize() async { if (!PlatformInfo.isAndroid || _initialized) return; FlutterForegroundTask.init( androidNotificationOptions: AndroidNotificationOptions( channelId: 'meshcore_background', channelName: 'MeshCore Background', channelDescription: 'Keeps MeshCore running in the background.', channelImportance: NotificationChannelImportance.LOW, priority: NotificationPriority.LOW, ), iosNotificationOptions: const IOSNotificationOptions( showNotification: false, playSound: false, ), foregroundTaskOptions: ForegroundTaskOptions( eventAction: ForegroundTaskEventAction.repeat(5000), autoRunOnBoot: false, allowWifiLock: false, ), ); _initialized = true; } Future start() async { if (!PlatformInfo.isAndroid) return; if (!_initialized) { await initialize(); } final running = await FlutterForegroundTask.isRunningService; if (running) return; final l10n = await _loadLocalizations(); await FlutterForegroundTask.startService( notificationTitle: l10n.background_serviceTitle, notificationText: l10n.background_serviceText, callback: startCallback, ); } Future _loadLocalizations() async { final supported = AppLocalizations.supportedLocales; final override = _languageOverrideProvider?.call(); if (override != null && override.isNotEmpty) { final overrideLocale = Locale(override); final isSupported = supported.any( (l) => l.languageCode == overrideLocale.languageCode, ); if (isSupported) { return AppLocalizations.delegate.load(overrideLocale); } } final preferred = WidgetsBinding.instance.platformDispatcher.locales; final match = basicLocaleListResolution(preferred, supported); return AppLocalizations.delegate.load(match); } Future stop() async { if (!PlatformInfo.isAndroid) return; final running = await FlutterForegroundTask.isRunningService; if (!running) return; await FlutterForegroundTask.stopService(); } } @pragma('vm:entry-point') void startCallback() { FlutterForegroundTask.setTaskHandler(_MeshCoreTaskHandler()); } class _MeshCoreTaskHandler extends TaskHandler { @override Future onStart(DateTime timestamp, TaskStarter starter) async {} @override void onRepeatEvent(DateTime timestamp) {} @override Future onDestroy(DateTime timestamp, bool isTimeout) async {} @override void onNotificationButtonPressed(String id) {} @override void onNotificationPressed() { FlutterForegroundTask.launchApp('/'); } }