import 'dart:io'; import 'package:adaptive_theme/adaptive_theme.dart'; import 'package:background_fetch/background_fetch.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:logging/logging.dart'; import 'package:media_extension/media_extension_action_types.dart'; import 'package:photos/ente_theme_data.dart'; import 'package:photos/services/app_lifecycle_service.dart'; import 'package:photos/services/sync_service.dart'; import 'package:photos/ui/home_widget.dart'; import "package:photos/ui/viewer/actions/file_viewer.dart"; import "package:photos/utils/intent_util.dart"; class EnteApp extends StatefulWidget { final Future Function(String) runBackgroundTask; final Future Function(String) killBackgroundTask; const EnteApp( this.runBackgroundTask, this.killBackgroundTask, { Key? key, }) : super(key: key); @override State createState() => _EnteAppState(); } class _EnteAppState extends State with WidgetsBindingObserver { final _logger = Logger("EnteAppState"); @override void initState() { _logger.info('init App'); super.initState(); setupIntentAction(); WidgetsBinding.instance.addObserver(this); } void setupIntentAction() async { final mediaExtentionAction = await initIntentAction(); AppLifecycleService.instance.setMediaExtensionAction(mediaExtentionAction); if (mediaExtentionAction.action == IntentAction.main) { _configureBackgroundFetch(); } } @override Widget build(BuildContext context) { if (Platform.isAndroid || kDebugMode) { return AdaptiveTheme( light: lightThemeData, dark: darkThemeData, initial: AdaptiveThemeMode.system, builder: (lightTheme, dartTheme) => MaterialApp( title: "ente", themeMode: ThemeMode.system, theme: lightTheme, darkTheme: dartTheme, home: AppLifecycleService.instance.mediaExtensionAction.action == IntentAction.view ? const FileViewer() : const HomeWidget(), debugShowCheckedModeBanner: false, builder: EasyLoading.init(), supportedLocales: AppLocalizations.supportedLocales, localizationsDelegates: AppLocalizations.localizationsDelegates, ), ); } else { return MaterialApp( title: "ente", themeMode: ThemeMode.system, theme: lightThemeData, darkTheme: darkThemeData, home: const HomeWidget(), debugShowCheckedModeBanner: false, builder: EasyLoading.init(), supportedLocales: AppLocalizations.supportedLocales, localizationsDelegates: AppLocalizations.localizationsDelegates, ); } } @override void dispose() { WidgetsBinding.instance.removeObserver(this); super.dispose(); } @override void didChangeAppLifecycleState(AppLifecycleState state) { final String stateChangeReason = 'app -> $state'; if (state == AppLifecycleState.resumed) { AppLifecycleService.instance .onAppInForeground(stateChangeReason + ': sync now'); SyncService.instance.sync(); } else { AppLifecycleService.instance.onAppInBackground(stateChangeReason); } } void _configureBackgroundFetch() { BackgroundFetch.configure( BackgroundFetchConfig( minimumFetchInterval: 15, forceAlarmManager: false, stopOnTerminate: false, startOnBoot: true, enableHeadless: true, requiresBatteryNotLow: true, requiresCharging: false, requiresStorageNotLow: false, requiresDeviceIdle: false, requiredNetworkType: NetworkType.ANY, ), (String taskId) async { await widget.runBackgroundTask(taskId); }, (taskId) { _logger.info("BG task timeout taskID: $taskId"); widget.killBackgroundTask(taskId); }).then((int status) { _logger.info('[BackgroundFetch] configure success: $status'); }).catchError((e) { _logger.info('[BackgroundFetch] configure ERROR: $e'); }); } }