diff --git a/mobile/android/app/build.gradle b/mobile/android/app/build.gradle index 8c3148fae8..e96f0456e1 100644 --- a/mobile/android/app/build.gradle +++ b/mobile/android/app/build.gradle @@ -142,4 +142,14 @@ dependencies { testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test:runner:1.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' + + + constraints { + implementation("androidx.work:work-runtime:2.8.1") { + because("Align work-runtime versions") + } + implementation("androidx.work:work-runtime-ktx:2.8.1") { + because("Align work-runtime-ktx versions") + } + } } \ No newline at end of file diff --git a/mobile/android/build.gradle b/mobile/android/build.gradle index 5f335a8ac0..2bcf235131 100644 --- a/mobile/android/build.gradle +++ b/mobile/android/build.gradle @@ -9,9 +9,6 @@ allprojects { jcenter() mavenCentral() // mavenLocal() // for FDroid - maven { - url "${project(':background_fetch').projectDir}/libs" - } maven { url "${project(':ffmpeg_kit_flutter').projectDir}/libs" } diff --git a/mobile/ios/Podfile.lock b/mobile/ios/Podfile.lock index d1bd0b1e53..fe25d4471e 100644 --- a/mobile/ios/Podfile.lock +++ b/mobile/ios/Podfile.lock @@ -1,8 +1,6 @@ PODS: - app_links (0.0.2): - Flutter - - background_fetch (1.3.7): - - Flutter - battery_info (0.0.1): - Flutter - connectivity_plus (0.0.1): @@ -129,9 +127,6 @@ PODS: - libwebp/sharpyuv (1.5.0) - libwebp/webp (1.5.0): - libwebp/sharpyuv - - local_auth_darwin (0.0.1): - - Flutter - - FlutterMacOS - local_auth_ios (0.0.1): - Flutter - Mantle (2.2.0): @@ -193,7 +188,7 @@ PODS: - libwebp (~> 1.0) - SDWebImage/Core (~> 5.17) - Sentry/HybridSDK (8.46.0) - - sentry_flutter (8.14.1): + - sentry_flutter (8.14.2): - Flutter - FlutterMacOS - Sentry/HybridSDK (= 8.46.0) @@ -242,10 +237,11 @@ PODS: - Flutter - wakelock_plus (0.0.1): - Flutter + - workmanager (0.0.1): + - Flutter DEPENDENCIES: - app_links (from `.symlinks/plugins/app_links/ios`) - - background_fetch (from `.symlinks/plugins/background_fetch/ios`) - battery_info (from `.symlinks/plugins/battery_info/ios`) - connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`) - cupertino_http (from `.symlinks/plugins/cupertino_http/darwin`) @@ -270,7 +266,6 @@ DEPENDENCIES: - in_app_purchase_storekit (from `.symlinks/plugins/in_app_purchase_storekit/darwin`) - integration_test (from `.symlinks/plugins/integration_test/ios`) - launcher_icon_switcher (from `.symlinks/plugins/launcher_icon_switcher/ios`) - - local_auth_darwin (from `.symlinks/plugins/local_auth_darwin/darwin`) - local_auth_ios (from `.symlinks/plugins/local_auth_ios/ios`) - maps_launcher (from `.symlinks/plugins/maps_launcher/ios`) - media_extension (from `.symlinks/plugins/media_extension/ios`) @@ -302,9 +297,10 @@ DEPENDENCIES: - video_thumbnail (from `.symlinks/plugins/video_thumbnail/ios`) - volume_controller (from `.symlinks/plugins/volume_controller/ios`) - wakelock_plus (from `.symlinks/plugins/wakelock_plus/ios`) + - workmanager (from `.symlinks/plugins/workmanager/ios`) SPEC REPOS: - https://github.com/ente-io/ffmpeg-kit-custom-repo-ios.git: + https://github.com/ente-io/ffmpeg-kit-custom-repo-ios: - ffmpeg_kit_custom trunk: - Firebase @@ -329,8 +325,6 @@ SPEC REPOS: EXTERNAL SOURCES: app_links: :path: ".symlinks/plugins/app_links/ios" - background_fetch: - :path: ".symlinks/plugins/background_fetch/ios" battery_info: :path: ".symlinks/plugins/battery_info/ios" connectivity_plus: @@ -379,8 +373,6 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/integration_test/ios" launcher_icon_switcher: :path: ".symlinks/plugins/launcher_icon_switcher/ios" - local_auth_darwin: - :path: ".symlinks/plugins/local_auth_darwin/darwin" local_auth_ios: :path: ".symlinks/plugins/local_auth_ios/ios" maps_launcher: @@ -443,85 +435,86 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/volume_controller/ios" wakelock_plus: :path: ".symlinks/plugins/wakelock_plus/ios" + workmanager: + :path: ".symlinks/plugins/workmanager/ios" SPEC CHECKSUMS: - app_links: f3e17e4ee5e357b39d8b95290a9b2c299fca71c6 - background_fetch: 39f11371c0dce04b001c4bfd5e782bcccb0a85e2 - battery_info: b6c551049266af31556b93c9d9b9452cfec0219f - connectivity_plus: 2a701ffec2c0ae28a48cf7540e279787e77c447d - cupertino_http: 947a233f40cfea55167a49f2facc18434ea117ba - dart_ui_isolate: d5bcda83ca4b04f129d70eb90110b7a567aece14 - device_info_plus: c6fb39579d0f423935b0c9ce7ee2f44b71b9fce6 + app_links: 76b66b60cc809390ca1ad69bfd66b998d2387ac7 + battery_info: 83f3aae7be2fccefab1d2bf06b8aa96f11c8bcdd + connectivity_plus: cb623214f4e1f6ef8fe7403d580fdad517d2f7dd + cupertino_http: 94ac07f5ff090b8effa6c5e2c47871d48ab7c86c + dart_ui_isolate: 46f6714abe6891313267153ef6f9748d8ecfcab1 + device_info_plus: 335f3ce08d2e174b9fdc3db3db0f4e3b1f66bd89 ffmpeg_kit_custom: 682b4f2f1ff1f8abae5a92f6c3540f2441d5be99 - ffmpeg_kit_flutter: 9dce4803991478c78c6fb9f972703301101095fe - file_saver: 503e386464dbe118f630e17b4c2e1190fa0cf808 + ffmpeg_kit_flutter: 915b345acc97d4142e8a9a8549d177ff10f043f5 + file_saver: 6cdbcddd690cb02b0c1a0c225b37cd805c2bf8b6 Firebase: d80354ed7f6df5f9aca55e9eb47cc4b634735eaf - firebase_core: 6e223dfa350b2edceb729cea505eaaef59330682 - firebase_messaging: 07fde77ae28c08616a1d4d870450efc2b38cf40d + firebase_core: 6cbed78b4f298ed103a9fd034e6dbc846320480f + firebase_messaging: 5e0adf2eb18b0ee59aa0c109314c091a0497ecac FirebaseCore: 99fe0c4b44a39f37d99e6404e02009d2db5d718d FirebaseCoreInternal: df24ce5af28864660ecbd13596fc8dd3a8c34629 FirebaseInstallations: 6c963bd2a86aca0481eef4f48f5a4df783ae5917 FirebaseMessaging: 487b634ccdf6f7b7ff180fdcb2a9935490f764e8 Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 - flutter_email_sender: e03bdda7637bcd3539bfe718fddd980e9508efaa - flutter_image_compress_common: ec1d45c362c9d30a3f6a0426c297f47c52007e3e - flutter_inappwebview_ios: 6f63631e2c62a7c350263b13fa5427aedefe81d4 - flutter_local_notifications: ff50f8405aaa0ccdc7dcfb9022ca192e8ad9688f - flutter_native_splash: f71420956eb811e6d310720fee915f1d42852e7a - flutter_secure_storage: 23fc622d89d073675f2eaa109381aefbcf5a49be - flutter_sodium: a00383520fc689c688b66fd3092984174712493e - flutter_timezone: ac3da59ac941ff1c98a2e1f0293420e020120282 - fluttertoast: 21eecd6935e7064cc1fcb733a4c5a428f3f24f0f + flutter_email_sender: aa1e9772696691d02cd91fea829856c11efb8e58 + flutter_image_compress_common: 1697a328fd72bfb335507c6bca1a65fa5ad87df1 + flutter_inappwebview_ios: b89ba3482b96fb25e00c967aae065701b66e9b99 + flutter_local_notifications: a5a732f069baa862e728d839dd2ebb904737effb + flutter_native_splash: 6cad9122ea0fad137d23137dd14b937f3e90b145 + flutter_secure_storage: 2c2ff13db9e0a5647389bff88b0ecac56e3f3418 + flutter_sodium: 7e4621538491834eba53bd524547854bcbbd6987 + flutter_timezone: 7c838e17ffd4645d261e87037e5bebf6d38fe544 + fluttertoast: 2c67e14dce98bbdb200df9e1acf610d7a6264ea1 GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7 GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1 - home_widget: 0434835a4c9a75704264feff6be17ea40e0f0d57 - image_editor_common: d6f6644ae4a6de80481e89fe6d0a8c49e30b4b43 - in_app_purchase_storekit: a1ce04056e23eecc666b086040239da7619cd783 - integration_test: 252f60fa39af5e17c3aa9899d35d908a0721b573 - launcher_icon_switcher: 8e0ad2131a20c51c1dd939896ee32e70cd845b37 + home_widget: f169fc41fd807b4d46ab6615dc44d62adbf9f64f + image_editor_common: 3de87e7c4804f4ae24c8f8a998362b98c105cac1 + in_app_purchase_storekit: d1a48cb0f8b29dbf5f85f782f5dd79b21b90a5e6 + integration_test: 4a889634ef21a45d28d50d622cf412dc6d9f586e + launcher_icon_switcher: 84c218d233505aa7d8655d8fa61a3ba802c022da libwebp: 02b23773aedb6ff1fd38cec7a77b81414c6842a8 - local_auth_darwin: 66e40372f1c29f383a314c738c7446e2f7fdadc3 - local_auth_ios: 5046a18c018dd973247a0564496c8898dbb5adf9 + local_auth_ios: f7a1841beef3151d140a967c2e46f30637cdf451 Mantle: c5aa8794a29a022dfbbfc9799af95f477a69b62d - maps_launcher: 2e5b6a2d664ec6c27f82ffa81b74228d770ab203 - media_extension: 6618f07abd762cdbfaadf1b0c56a287e820f0c84 - media_kit_libs_ios_video: a5fe24bc7875ccd6378a0978c13185e1344651c1 - media_kit_video: 5da63f157170e5bf303bf85453b7ef6971218a2e - motion_sensors: 03f55b7c637a7e365a0b5f9697a449f9059d5d91 - motionphoto: 8b65ce50c7d7ff3c767534fc3768b2eed9ac24e4 - move_to_background: cd3091014529ec7829e342ad2d75c0a11f4378a5 + maps_launcher: edf829809ba9e894d70e569bab11c16352dedb45 + media_extension: 671e2567880d96c95c65c9a82ccceed8f2e309fd + media_kit_libs_ios_video: 5a18affdb97d1f5d466dc79988b13eff6c5e2854 + media_kit_video: 1746e198cb697d1ffb734b1d05ec429d1fcd1474 + motion_sensors: 741e702c17467b9569a92165dda8d4d88c6167f1 + motionphoto: 23e2aeb5c6380112f69468d71f970fa7438e5ed1 + move_to_background: 7e3467dd2a1d1013e98c9c1cb93fd53cd7ef9d84 nanopb: fad817b59e0457d11a5dfbde799381cd727c1275 - native_video_player: 5d36066807b680e181473e6890dde643ac85380d - objective_c: 77e887b5ba1827970907e10e832eec1683f3431d - onnxruntime: e7c2ae44385191eaad5ae64c935a72debaddc997 + native_video_player: e363dd14f6a498ad8a8f7e6486a0db046ad19f13 + objective_c: 89e720c30d716b036faf9c9684022048eee1eee2 + onnxruntime: f9b296392c96c42882be020a59dbeac6310d81b2 onnxruntime-c: a909204639a1f035f575127ac406f781ac797c9c onnxruntime-objc: b6fab0f1787aa6f7190c2013f03037df4718bd8b - open_mail_app: 70273c53f768beefdafbe310c3d9086e4da3cb02 + open_mail_app: 7314a609e88eed22d53671279e189af7a0ab0f11 OrderedSet: e539b66b644ff081c73a262d24ad552a69be3a94 - package_info_plus: c0502532a26c7662a62a356cebe2692ec5fe4ec4 - path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 - permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2 - photo_manager: ff695c7a1dd5bc379974953a2b5c0a293f7c4c8a - privacy_screen: 1a131c052ceb3c3659934b003b0d397c2381a24e + package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499 + path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564 + permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d + photo_manager: d2fbcc0f2d82458700ee6256a15018210a81d413 + privacy_screen: 3159a541f5d3a31bea916cfd4e58f9dc722b3fd4 PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47 - receive_sharing_intent: 79c848f5b045674ad60b9fea3bafea59962ad2c1 + receive_sharing_intent: 222384f00ffe7e952bbfabaa9e3967cb87e5fe00 SDWebImage: f29024626962457f3470184232766516dee8dfea SDWebImageWebPCoder: e38c0a70396191361d60c092933e22c20d5b1380 Sentry: da60d980b197a46db0b35ea12cb8f39af48d8854 - sentry_flutter: 6a134f9d381e49f22ea25a67736cf0cf4d02ec9c - share_plus: 8b6f8b3447e494cca5317c8c3073de39b3600d1f - shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78 - sqflite_darwin: 5a7236e3b501866c1c9befc6771dfd73ffb8702d + sentry_flutter: 27892878729f42701297c628eb90e7c6529f3684 + share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a + shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7 + sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0 sqlite3: 3c950dc86011117c307eb0b28c4a7bb449dce9f1 - sqlite3_flutter_libs: 069c435986dd4b63461aecd68f4b30be4a9e9daa - system_info_plus: 5393c8da281d899950d751713575fbf91c7709aa - thermal: a9261044101ae8f532fa29cab4e8270b51b3f55c - ua_client_hints: aeabd123262c087f0ce151ef96fa3ab77bfc8b38 - url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe - video_player_avfoundation: 7c6c11d8470e1675df7397027218274b6d2360b3 - video_thumbnail: 94ba6705afbaa120b77287080424930f23ea0c40 - volume_controller: 2e3de73d6e7e81a0067310d17fb70f2f86d71ac7 - wakelock_plus: 373cfe59b235a6dd5837d0fb88791d2f13a90d56 + sqlite3_flutter_libs: 3c323550ef3b928bc0aa9513c841e45a7d242832 + system_info_plus: 555ce7047fbbf29154726db942ae785c29211740 + thermal: d4c48be750d1ddbab36b0e2dcb2471531bc8df41 + ua_client_hints: 92fe0d139619b73ec9fcb46cc7e079a26178f586 + url_launcher_ios: 694010445543906933d732453a59da0a173ae33d + video_player_avfoundation: 2cef49524dd1f16c5300b9cd6efd9611ce03639b + video_thumbnail: 584ccfa55d8fd2f3d5507218b0a18d84c839c620 + volume_controller: 3657a1f65bedb98fa41ff7dc5793537919f31b12 + wakelock_plus: 04623e3f525556020ebd4034310f20fe7fda8b49 + workmanager: 01be2de7f184bd15de93a1812936a2b7f42ef07e PODFILE CHECKSUM: a8ef88ad74ba499756207e7592c6071a96756d18 diff --git a/mobile/ios/Runner.xcodeproj/project.pbxproj b/mobile/ios/Runner.xcodeproj/project.pbxproj index be98e8f1ef..8640b17d3a 100644 --- a/mobile/ios/Runner.xcodeproj/project.pbxproj +++ b/mobile/ios/Runner.xcodeproj/project.pbxproj @@ -527,7 +527,6 @@ "${BUILT_PRODUCTS_DIR}/SDWebImageWebPCoder/SDWebImageWebPCoder.framework", "${BUILT_PRODUCTS_DIR}/Sentry/Sentry.framework", "${BUILT_PRODUCTS_DIR}/app_links/app_links.framework", - "${BUILT_PRODUCTS_DIR}/background_fetch/background_fetch.framework", "${BUILT_PRODUCTS_DIR}/battery_info/battery_info.framework", "${BUILT_PRODUCTS_DIR}/connectivity_plus/connectivity_plus.framework", "${BUILT_PRODUCTS_DIR}/cupertino_http/cupertino_http.framework", @@ -549,7 +548,6 @@ "${BUILT_PRODUCTS_DIR}/integration_test/integration_test.framework", "${BUILT_PRODUCTS_DIR}/launcher_icon_switcher/launcher_icon_switcher.framework", "${BUILT_PRODUCTS_DIR}/libwebp/libwebp.framework", - "${BUILT_PRODUCTS_DIR}/local_auth_darwin/local_auth_darwin.framework", "${BUILT_PRODUCTS_DIR}/local_auth_ios/local_auth_ios.framework", "${BUILT_PRODUCTS_DIR}/maps_launcher/maps_launcher.framework", "${BUILT_PRODUCTS_DIR}/media_extension/media_extension.framework", @@ -581,6 +579,7 @@ "${BUILT_PRODUCTS_DIR}/video_thumbnail/video_thumbnail.framework", "${BUILT_PRODUCTS_DIR}/volume_controller/volume_controller.framework", "${BUILT_PRODUCTS_DIR}/wakelock_plus/wakelock_plus.framework", + "${BUILT_PRODUCTS_DIR}/workmanager/workmanager.framework", "${PODS_XCFRAMEWORKS_BUILD_DIR}/ffmpeg_kit_custom/ffmpegkit.framework/ffmpegkit", "${PODS_XCFRAMEWORKS_BUILD_DIR}/ffmpeg_kit_custom/libavcodec.framework/libavcodec", "${PODS_XCFRAMEWORKS_BUILD_DIR}/ffmpeg_kit_custom/libavdevice.framework/libavdevice", @@ -623,7 +622,6 @@ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImageWebPCoder.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Sentry.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/app_links.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/background_fetch.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/battery_info.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/connectivity_plus.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/cupertino_http.framework", @@ -645,7 +643,6 @@ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/integration_test.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/launcher_icon_switcher.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/libwebp.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/local_auth_darwin.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/local_auth_ios.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/maps_launcher.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/media_extension.framework", @@ -677,6 +674,7 @@ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/video_thumbnail.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/volume_controller.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/wakelock_plus.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/workmanager.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ffmpegkit.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/libavcodec.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/libavdevice.framework", diff --git a/mobile/ios/Runner/AppDelegate.swift b/mobile/ios/Runner/AppDelegate.swift index f1a6bbe1bf..cbf287bc52 100644 --- a/mobile/ios/Runner/AppDelegate.swift +++ b/mobile/ios/Runner/AppDelegate.swift @@ -2,6 +2,7 @@ import AVFoundation import Flutter import UIKit import app_links +import workmanager @main @objc class AppDelegate: FlutterAppDelegate { @@ -15,6 +16,14 @@ import app_links } GeneratedPluginRegistrant.register(with: self) + WorkmanagerPlugin.setPluginRegistrantCallback { registry in + GeneratedPluginRegistrant.register(with: registry) + } + var freqInMinutes = 30 * 60 + // Register a periodic task in iOS 13+ + WorkmanagerPlugin.registerPeriodicTask( + withIdentifier: "io.ente.frame.iOSBackgroundAppRefresh", + frequency: NSNumber(value: freqInMinutes)) // Retrieve the link from parameters if let url = AppLinks.shared.getLink(launchOptions: launchOptions) { diff --git a/mobile/ios/Runner/Info.plist b/mobile/ios/Runner/Info.plist index 6443cc98c8..5e9b8a7005 100644 --- a/mobile/ios/Runner/Info.plist +++ b/mobile/ios/Runner/Info.plist @@ -4,7 +4,7 @@ BGTaskSchedulerPermittedIdentifiers - com.transistorsoft.fetch + io.ente.frame.iOSBackgroundAppRefresh CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) diff --git a/mobile/lib/app.dart b/mobile/lib/app.dart index 798f5e4ba9..55491085c4 100644 --- a/mobile/lib/app.dart +++ b/mobile/lib/app.dart @@ -2,7 +2,6 @@ import "dart:async"; 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'; @@ -24,18 +23,15 @@ import "package:photos/services/people_home_widget_service.dart"; import 'package:photos/services/sync/sync_service.dart'; import 'package:photos/ui/tabs/home_widget.dart'; import "package:photos/ui/viewer/actions/file_viewer.dart"; +import "package:photos/utils/bg_task_utils.dart"; import "package:photos/utils/intent_util.dart"; import "package:photos/utils/standalone/debouncer.dart"; class EnteApp extends StatefulWidget { - final Future Function(String) runBackgroundTask; - final Future Function(String) killBackgroundTask; final AdaptiveThemeMode? savedThemeMode; final Locale? locale; const EnteApp( - this.runBackgroundTask, - this.killBackgroundTask, this.locale, this.savedThemeMode, { super.key, @@ -51,9 +47,9 @@ class EnteApp extends StatefulWidget { } class _EnteAppState extends State with WidgetsBindingObserver { - final _logger = Logger("EnteAppState"); late Locale? locale; late StreamSubscription _memoriesChangedSubscription; + final _logger = Logger("EnteAppState"); late StreamSubscription _peopleChangedSubscription; late Debouncer _changeCallbackDebouncer; @@ -112,7 +108,7 @@ class _EnteAppState extends State with WidgetsBindingObserver { : MediaExtentionAction(action: IntentAction.main); AppLifecycleService.instance.setMediaExtensionAction(mediaExtentionAction); if (mediaExtentionAction.action == IntentAction.main) { - _configureBackgroundFetch(); + await BgTaskUtils.configureWorkmanager(); } } @@ -197,29 +193,4 @@ class _EnteAppState extends State with WidgetsBindingObserver { 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'); - }); - } } diff --git a/mobile/lib/core/network/network.dart b/mobile/lib/core/network/network.dart index 2179dc7850..b73f548b63 100644 --- a/mobile/lib/core/network/network.dart +++ b/mobile/lib/core/network/network.dart @@ -1,7 +1,7 @@ import 'dart:io'; import 'package:dio/dio.dart'; -import 'package:native_dio_adapter/native_dio_adapter.dart'; +import "package:native_dio_adapter/native_dio_adapter.dart"; import 'package:package_info_plus/package_info_plus.dart'; import "package:photos/core/configuration.dart"; import "package:photos/core/event_bus.dart"; diff --git a/mobile/lib/main.dart b/mobile/lib/main.dart index b8e72c0dd0..2e59b78812 100644 --- a/mobile/lib/main.dart +++ b/mobile/lib/main.dart @@ -2,7 +2,6 @@ import 'dart:async'; import 'dart:io'; import "package:adaptive_theme/adaptive_theme.dart"; -import 'package:background_fetch/background_fetch.dart'; import "package:computer/computer.dart"; import 'package:ente_crypto/ente_crypto.dart'; import 'package:firebase_messaging/firebase_messaging.dart'; @@ -22,7 +21,6 @@ import 'package:photos/core/error-reporting/super_logging.dart'; import 'package:photos/core/errors.dart'; import 'package:photos/core/network/network.dart'; import "package:photos/db/ml/db.dart"; -import 'package:photos/db/upload_locks_db.dart'; import 'package:photos/ente_theme_data.dart'; import "package:photos/extensions/stop_watch.dart"; import "package:photos/l10n/l10n.dart"; @@ -53,13 +51,12 @@ import 'package:shared_preferences/shared_preferences.dart'; final _logger = Logger("main"); -bool _isProcessRunning = false; const kLastBGTaskHeartBeatTime = "bg_task_hb_time"; const kLastFGTaskHeartBeatTime = "fg_task_hb_time"; const kHeartBeatFrequency = Duration(seconds: 1); const kFGSyncFrequency = Duration(minutes: 5); const kFGHomeWidgetSyncFrequency = Duration(minutes: 15); -const kBGTaskTimeout = Duration(seconds: 25); +const kBGTaskTimeout = Duration(seconds: 28); const kBGPushTimeout = Duration(seconds: 28); const kFGTaskDeathTimeoutInMicroseconds = 5000000; @@ -71,7 +68,6 @@ void main() async { final savedThemeMode = await AdaptiveTheme.getThemeMode(); await _runInForeground(savedThemeMode); - unawaited(BackgroundFetch.registerHeadlessTask(_headlessTaskHandler)); if (Platform.isAndroid) FlutterDisplayMode.setHighRefreshRate().ignore(); SystemChrome.setSystemUIOverlayStyle( const SystemUiOverlayStyle( @@ -87,14 +83,13 @@ void main() async { } Future _runInForeground(AdaptiveThemeMode? savedThemeMode) async { - return await _runWithLogs(() async { + return await runWithLogs(() async { _logger.info("Starting app in foreground"); await _init(false, via: 'mainMethod'); final Locale? locale = await getLocale(noFallback: true); runApp( AppLock( - builder: (args) => - EnteApp(_runBackgroundTask, _killBGTask, locale, savedThemeMode), + builder: (args) => EnteApp(locale, savedThemeMode), lockScreen: const LockScreen(), enabled: await Configuration.instance.shouldShowLockScreen() || localSettings.isOnGuestView(), @@ -115,7 +110,12 @@ ThemeMode _themeMode(AdaptiveThemeMode? savedThemeMode) { return ThemeMode.system; } -Future _homeWidgetSync() async { +Future _homeWidgetSync([bool isBackground = false]) async { + if (isBackground && Platform.isIOS) { + _logger.info("Home widget sync skipped in background on iOS"); + return; + } + try { await HomeWidgetService.instance.initHomeWidget(); } catch (e, s) { @@ -123,59 +123,59 @@ Future _homeWidgetSync() async { } } -Future _runBackgroundTask(String taskId, {String mode = 'normal'}) async { - if (_isProcessRunning) { - _logger.info("Background task triggered when process was already running"); - await _sync('bgTaskActiveProcess'); - await BackgroundFetch.finish(taskId); - } else { - _runWithLogs( - () async { - _logger.info("Starting background task in $mode mode"); - // ignore: unawaited_futures - _runInBackground(taskId); - }, - prefix: "[bg]", - ).ignore(); - } +Future runBackgroundTask( + String taskId, + TimeLogger tlog, { + String mode = 'normal', +}) async { + await _runMinimally(taskId, tlog); } -Future _runInBackground(String taskId) async { - await Future.delayed(const Duration(seconds: 3)); - if (await _isRunningInForeground()) { - _logger.info("FG task running, skipping BG taskID: $taskId"); - await BackgroundFetch.finish(taskId); - return; - } else { - _logger.info("FG task is not running"); - } - _logger.info("[BackgroundFetch] Event received: $taskId"); - _scheduleBGTaskKill(taskId); - if (Platform.isIOS) { - _scheduleSuicide(kBGTaskTimeout, taskId); // To prevent OS from punishing us - } - await _init(true, via: 'runViaBackgroundTask'); - await Future.wait( - [ - _homeWidgetSync(), - () async { - updateService.showUpdateNotification().ignore(); - await _sync('bgSync'); - }(), - ], +Future _runMinimally(String taskId, TimeLogger tlog) async { + final PackageInfo packageInfo = await PackageInfo.fromPlatform(); + final SharedPreferences prefs = await SharedPreferences.getInstance(); + + await Configuration.instance.init(); + + // App LifeCycle + AppLifecycleService.instance.init(prefs); + AppLifecycleService.instance.onAppInBackground('init via: WorkManager $tlog'); + + // Crypto rel. + await Computer.shared().turnOn(workersCount: 4); + CryptoUtil.init(); + + // Init Network Utils + await NetworkClient.instance.init(packageInfo); + + // Global Services + ServiceLocator.instance.init( + prefs, + NetworkClient.instance.enteDio, + NetworkClient.instance.getDio(), + packageInfo, ); - await BackgroundFetch.finish(taskId); -} -// https://stackoverflow.com/a/73796478/546896 -@pragma('vm:entry-point') -void _headlessTaskHandler(HeadlessTask task) { - debugPrint("_headlessTaskHandler"); - if (task.timeout) { - BackgroundFetch.finish(task.taskId); - } else { - _runBackgroundTask(task.taskId, mode: "headless"); - } + await CollectionsService.instance.init(prefs); + + // Upload & Sync Related + await FileUploader.instance.init(prefs, true); + LocalFileUpdateService.instance.init(prefs); + await LocalSyncService.instance.init(prefs); + RemoteSyncService.instance.init(prefs); + await SyncService.instance.init(prefs); + + // Misc Services + await UserService.instance.init(); + NotificationService.instance.init(prefs); + if (Platform.isAndroid) HomeWidgetService.instance.init(prefs); + + // Begin Execution + // only runs for android + updateService.showUpdateNotification().ignore(); + await _sync('bgTaskActiveProcess'); + // only runs for android + await _homeWidgetSync(true); } Future _init(bool isBackground, {String via = ''}) async { @@ -193,7 +193,6 @@ Future _init(bool isBackground, {String via = ''}) async { } }); if (!isBackground) _heartBeatOnInit(0); - _isProcessRunning = true; _logger.info("Initializing... inBG =$isBackground via: $via $tlog"); final SharedPreferences preferences = await SharedPreferences.getInstance(); final PackageInfo packageInfo = await PackageInfo.fromPlatform(); @@ -263,12 +262,11 @@ Future _init(bool isBackground, {String via = ''}) async { } if (Platform.isIOS) { - // ignore: unawaited_futures PushService.instance.init().then((_) { FirebaseMessaging.onBackgroundMessage( _firebaseMessagingBackgroundHandler, ); - }); + }).ignore(); } _logger.info("PushService/HomeWidget done $tlog"); VideoPreviewService.instance.init(preferences); @@ -330,7 +328,7 @@ Future _sync(String caller) async { } } -Future _runWithLogs(Function() function, {String prefix = ""}) async { +Future runWithLogs(Function() function, {String prefix = ""}) async { await SuperLogging.main( LogConfig( body: function, @@ -378,17 +376,6 @@ Future _scheduleFGSync(String caller) async { }); } -void _scheduleBGTaskKill(String taskId) async { - if (await _isRunningInForeground()) { - _logger.info("Found app in FG, committing seppuku. $taskId"); - await _killBGTask(taskId); - return; - } - Future.delayed(kHeartBeatFrequency, () async { - _scheduleBGTaskKill(taskId); - }); -} - Future _isRunningInForeground() async { final prefs = await SharedPreferences.getInstance(); await prefs.reload(); @@ -400,22 +387,10 @@ Future _isRunningInForeground() async { (currentTime - kFGTaskDeathTimeoutInMicroseconds); } -Future _killBGTask([String? taskId]) async { - await UploadLocksDB.instance.releaseLocksAcquiredByOwnerBefore( - ProcessType.background.toString(), - DateTime.now().microsecondsSinceEpoch, - ); - final prefs = await SharedPreferences.getInstance(); - await prefs.remove(kLastBGTaskHeartBeatTime); - if (taskId != null) { - await BackgroundFetch.finish(taskId); - } -} - Future _firebaseMessagingBackgroundHandler(RemoteMessage message) async { final bool isRunningInFG = await _isRunningInForeground(); // hb final bool isInForeground = AppLifecycleService.instance.isForeground; - if (_isProcessRunning) { + if (await _isRunningInForeground()) { _logger.info( "Background push received when app is alive and runningInFS: $isRunningInFG inForeground: $isInForeground", ); @@ -424,20 +399,16 @@ Future _firebaseMessagingBackgroundHandler(RemoteMessage message) async { } } else { // App is dead - // ignore: unawaited_futures - _runWithLogs( + runWithLogs( () async { _logger.info("Background push received"); - if (Platform.isIOS) { - _scheduleSuicide(kBGPushTimeout); // To prevent OS from punishing us - } await _init(true, via: 'firebasePush'); if (PushService.shouldSync(message)) { await _sync('firebaseBgSyncNoActiveProcess'); } }, prefix: "[fbg]", - ); + ).ignore(); } } @@ -450,12 +421,3 @@ Future _logFGHeartBeatInfo(SharedPreferences prefs) async { : DateTime.fromMicrosecondsSinceEpoch(lastFGTaskHeartBeatTime).toString(); _logger.info('isAlreadyRunningFG: $isRunningInFG, last Beat: $lastRun'); } - -void _scheduleSuicide(Duration duration, [String? taskID]) { - final taskIDVal = taskID ?? 'no taskID'; - _logger.warning("Schedule seppuku taskID: $taskIDVal"); - Future.delayed(duration, () { - _logger.warning("TLE, committing seppuku for taskID: $taskIDVal"); - _killBGTask(taskID); - }); -} diff --git a/mobile/lib/module/upload/service/multipart.dart b/mobile/lib/module/upload/service/multipart.dart index d547a45938..ad429e5e77 100644 --- a/mobile/lib/module/upload/service/multipart.dart +++ b/mobile/lib/module/upload/service/multipart.dart @@ -236,6 +236,7 @@ class MultiPartUploader { options: Options( headers: { Headers.contentLengthHeader: fileSize, + Headers.contentTypeHeader: "application/octet-stream", }, ), ); diff --git a/mobile/lib/services/sync/remote_sync_service.dart b/mobile/lib/services/sync/remote_sync_service.dart index 2f1b59c1c1..f3baa4277d 100644 --- a/mobile/lib/services/sync/remote_sync_service.dart +++ b/mobile/lib/services/sync/remote_sync_service.dart @@ -127,12 +127,16 @@ class RemoteSyncService { await syncDeviceCollectionFilesForUpload(); } - fileDataService.syncFDStatus().then((_) { - if (!flagService.hasGrantedMLConsent) { - VideoPreviewService.instance - .queueFiles(); // Only in case ML is disabled. if ML is enabled the MLService will queue streaming when ML is done - } - }).ignore(); + if ( + // Only Uploading Previews in fg to prevent heating issues + AppLifecycleService.instance.isForeground && + // if ML is enabled the MLService will queue when ML is done + !flagService.hasGrantedMLConsent) { + fileDataService.syncFDStatus().then((_) { + VideoPreviewService.instance.queueFiles(); + }).ignore(); + } + final filesToBeUploaded = await _getFilesToBeUploaded(); final hasUploadedFiles = await _uploadFiles(filesToBeUploaded); if (filesToBeUploaded.isNotEmpty) { @@ -152,8 +156,7 @@ class RemoteSyncService { if (hasMoreFilesToBackup && !_shouldThrottleSync()) { // Skipping a resync to ensure that files that were ignored in this // session are not processed now - // ignore: unawaited_futures - sync(); + await sync(); } else { _logger.info("Fire backup completed event"); Bus.instance.fire(SyncStatusUpdate(SyncStatus.completedBackup)); @@ -175,20 +178,19 @@ class RemoteSyncService { } catch (e, s) { _existingSync?.complete(); _existingSync = null; - // rethrow whitelisted error so that UI status can be updated correctly. - if (e is UnauthorizedError || - e is NoActiveSubscriptionError || - e is WiFiUnavailableError || - e is StorageLimitExceededError || - e is SyncStopRequestedError || - e is NoMediaLocationAccessError) { - _logger.warning("Error executing remote sync", e, s); + _logger.warning("Error executing remote sync", e, s); + + if (flagService.internalUser || + // rethrow whitelisted error so that UI status can be updated correctly. + { + UnauthorizedError, + NoActiveSubscriptionError, + WiFiUnavailableError, + StorageLimitExceededError, + SyncStopRequestedError, + NoMediaLocationAccessError, + }.contains(e.runtimeType)) { rethrow; - } else { - _logger.severe("Error executing remote sync ", e, s); - if (flagService.internalUser) { - rethrow; - } } } finally { _isExistingSyncSilent = false; @@ -602,6 +604,22 @@ class RemoteSyncService { await _uploader.fetchUploadURLs(toBeUploaded); } final List futures = []; + + for (final file in filesToBeUploaded) { + if (_shouldThrottleSync() && + futures.length >= kMaximumPermissibleUploadsInThrottledMode) { + _logger.info("Skipping some new files as we are throttling uploads"); + break; + } + // prefer existing collection ID for manually uploaded files. + // See https://github.com/ente-io/photos-app/pull/187 + final collectionID = file.collectionID ?? + (await _collectionsService + .getOrCreateForPath(file.deviceFolder ?? 'Unknown Folder')) + .id; + _uploadFile(file, collectionID, futures); + } + for (final uploadedFileID in updatedFileIDs) { if (_shouldThrottleSync() && futures.length >= kMaximumPermissibleUploadsInThrottledMode) { @@ -633,21 +651,6 @@ class RemoteSyncService { } } - for (final file in filesToBeUploaded) { - if (_shouldThrottleSync() && - futures.length >= kMaximumPermissibleUploadsInThrottledMode) { - _logger.info("Skipping some new files as we are throttling uploads"); - break; - } - // prefer existing collection ID for manually uploaded files. - // See https://github.com/ente-io/photos-app/pull/187 - final collectionID = file.collectionID ?? - (await _collectionsService - .getOrCreateForPath(file.deviceFolder ?? 'Unknown Folder')) - .id; - _uploadFile(file, collectionID, futures); - } - try { await Future.wait(futures); } on InvalidFileError { @@ -933,26 +936,24 @@ class RemoteSyncService { } bool _shouldThrottleSync() { - return Platform.isIOS && !AppLifecycleService.instance.isForeground; + return !flagService.enableMobMultiPart || + !localSettings.userEnabledMultiplePart; } // _sortByTime sort by creation time (desc). // This is done to upload most recent photo first. void _sortByTime(List file) { file.sort((first, second) { + // 1. fileType: move videos to end when in bg + if (!AppLifecycleService.instance.isForeground && + first.fileType != second.fileType) { + if (first.fileType == FileType.video) return 1; + if (second.fileType == FileType.video) return -1; + } + + // 2. creationTime descending return second.creationTime!.compareTo(first.creationTime!); }); - // move updated files towards the end - file.sort((first, second) { - if (first.updationTime == second.updationTime) { - return 0; - } - if (first.updationTime == -1) { - return 1; - } else { - return -1; - } - }); } bool _shouldShowNotification(int collectionID) { diff --git a/mobile/lib/utils/bg_task_utils.dart b/mobile/lib/utils/bg_task_utils.dart new file mode 100644 index 0000000000..573996625a --- /dev/null +++ b/mobile/lib/utils/bg_task_utils.dart @@ -0,0 +1,106 @@ +import "dart:io"; + +import "package:logging/logging.dart"; +import "package:permission_handler/permission_handler.dart"; +import "package:photos/db/upload_locks_db.dart"; +import "package:photos/extensions/stop_watch.dart"; +import "package:photos/main.dart"; +import "package:photos/utils/file_uploader.dart"; +import "package:shared_preferences/shared_preferences.dart"; +import "package:workmanager/workmanager.dart" as workmanager; + +@pragma('vm:entry-point') +void callbackDispatcher() { + workmanager.Workmanager().executeTask((taskName, inputData) async { + final TimeLogger tlog = TimeLogger(); + Future result = Future.error("Task didn't run"); + final prefs = await SharedPreferences.getInstance(); + + await runWithLogs( + () async { + try { + BgTaskUtils.$.info('Task started $tlog'); + await runBackgroundTask(taskName, tlog).timeout( + Platform.isIOS ? kBGTaskTimeout : const Duration(hours: 1), + onTimeout: () async { + BgTaskUtils.$.warning( + "TLE, committing seppuku for taskID: $taskName", + ); + await BgTaskUtils.releaseResourcesForKill(taskName, prefs); + }, + ); + BgTaskUtils.$.info('Task run successful $tlog'); + result = Future.value(true); + } catch (e) { + BgTaskUtils.$.warning('Task error: $e'); + await BgTaskUtils.releaseResourcesForKill(taskName, prefs); + result = Future.error(e.toString()); + } + }, + prefix: "[bg]", + ).onError((_, __) { + result = Future.error("Didn't finished correctly!"); + return; + }); + + return result; + }); +} + +class BgTaskUtils { + static final $ = Logger("BgTaskUtils"); + + static Future releaseResourcesForKill( + String taskId, + SharedPreferences prefs, + ) async { + await UploadLocksDB.instance.releaseLocksAcquiredByOwnerBefore( + ProcessType.background.toString(), + DateTime.now().microsecondsSinceEpoch, + ); + await prefs.remove(kLastBGTaskHeartBeatTime); + } + + static Future configureWorkmanager() async { + if (Platform.isIOS) { + final status = await Permission.backgroundRefresh.status; + if (status != PermissionStatus.granted) { + $.warning( + "Background refresh permission is not granted. Please grant it to start the background service.", + ); + return; + } + } + $.warning("Configuring Work Manager for background tasks"); + const iOSBackgroundAppRefresh = "io.ente.frame.iOSBackgroundAppRefresh"; + const androidPeriodicTask = "io.ente.photos.androidPeriodicTask"; + final backgroundTaskIdentifier = + Platform.isIOS ? iOSBackgroundAppRefresh : androidPeriodicTask; + try { + await workmanager.Workmanager().initialize( + callbackDispatcher, + isInDebugMode: false, + ); + await workmanager.Workmanager().registerPeriodicTask( + backgroundTaskIdentifier, + backgroundTaskIdentifier, + frequency: Platform.isIOS + ? const Duration(minutes: 30) + : const Duration(minutes: 15), + initialDelay: const Duration(minutes: 10), + constraints: workmanager.Constraints( + networkType: workmanager.NetworkType.connected, + requiresCharging: false, + requiresStorageNotLow: false, + requiresDeviceIdle: false, + ), + existingWorkPolicy: workmanager.ExistingWorkPolicy.append, + backoffPolicy: workmanager.BackoffPolicy.linear, + backoffPolicyDelay: const Duration(minutes: 15), + ); + $.info("WorkManager configured"); + } catch (e) { + $.warning("Failed to configure WorkManager: $e"); + } + } +} diff --git a/mobile/pubspec.lock b/mobile/pubspec.lock index ff0c782525..8107f30d4f 100644 --- a/mobile/pubspec.lock +++ b/mobile/pubspec.lock @@ -5,10 +5,10 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: f256b0c0ba6c7577c15e2e4e114755640a875e885099367bf6e012b19314c834 + sha256: "16e298750b6d0af7ce8a3ba7c18c69c3785d11b15ec83f6dcd0ad2a0009b3cab" url: "https://pub.dev" source: hosted - version: "72.0.0" + version: "76.0.0" _flutterfire_internals: dependency: transitive description: @@ -21,7 +21,7 @@ packages: dependency: transitive description: dart source: sdk - version: "0.3.2" + version: "0.3.3" adaptive_theme: dependency: "direct main" description: @@ -34,10 +34,10 @@ packages: dependency: transitive description: name: analyzer - sha256: b652861553cd3990d8ed361f7979dc6d7053a9ac8843fa73820ab68ce5410139 + sha256: "1f14db053a8c23e260789e9b0980fa27f2680dd640932cae5e1137cce0e46e1e" url: "https://pub.dev" source: hosted - version: "6.7.0" + version: "6.11.0" android_intent_plus: dependency: "direct main" description: @@ -127,21 +127,13 @@ packages: source: hosted version: "1.5.8" async: - dependency: transitive + dependency: "direct main" description: name: async sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" url: "https://pub.dev" source: hosted version: "2.11.0" - background_fetch: - dependency: "direct main" - description: - name: background_fetch - sha256: e9f26ae54d88310b7ac2a68f2f9fcee0081a4d5f11100f233a70702021e7ac4f - url: "https://pub.dev" - source: hosted - version: "1.3.7" battery_info: dependency: "direct main" description: @@ -325,10 +317,10 @@ packages: dependency: "direct main" description: name: collection - sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf url: "https://pub.dev" source: hosted - version: "1.18.0" + version: "1.19.0" computer: dependency: "direct main" description: @@ -1424,18 +1416,18 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" + sha256: "7bb2830ebd849694d1ec25bf1f44582d6ac531a57a365a803a6034ff751d2d06" url: "https://pub.dev" source: hosted - version: "10.0.5" + version: "10.0.7" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" + sha256: "9491a714cca3667b60b5c420da8217e6de0d1ba7a5ec322fab01758f6998f379" url: "https://pub.dev" source: hosted - version: "3.0.5" + version: "3.0.8" leak_tracker_testing: dependency: transitive description: @@ -1544,10 +1536,10 @@ packages: dependency: transitive description: name: macros - sha256: "0acaed5d6b7eab89f63350bccd82119e6c602df0f391260d0e32b5e23db79536" + sha256: "1d9e801cd66f7ea3663c45fc708450db1fa57f988142c64289142c9b7ee80656" url: "https://pub.dev" source: hosted - version: "0.1.2-main.4" + version: "0.1.3-main.0" maps_launcher: dependency: "direct main" description: @@ -2197,18 +2189,18 @@ packages: dependency: "direct main" description: name: sentry - sha256: "077b03f9ee44cfb1eaadbf8af58255e670de62b3f240ca154ce96a5591dc3885" + sha256: "599701ca0693a74da361bc780b0752e1abc98226cf5095f6b069648116c896bb" url: "https://pub.dev" source: hosted - version: "8.14.1" + version: "8.14.2" sentry_flutter: dependency: "direct main" description: name: sentry_flutter - sha256: a348e2a365a8ad7682dd09db54f50f19f1c87180b8278f088bc393c511aea5e0 + sha256: "5ba2cf40646a77d113b37a07bd69f61bb3ec8a73cbabe5537b05a7c89d2656f8" url: "https://pub.dev" source: hosted - version: "8.14.1" + version: "8.14.2" share_plus: dependency: "direct main" description: @@ -2317,7 +2309,7 @@ packages: dependency: transitive description: flutter source: sdk - version: "0.0.99" + version: "0.0.0" source_gen: dependency: transitive description: @@ -2442,10 +2434,10 @@ packages: dependency: transitive description: name: stack_trace - sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377" url: "https://pub.dev" source: hosted - version: "1.11.1" + version: "1.12.0" step_progress_indicator: dependency: "direct main" description: @@ -2474,10 +2466,10 @@ packages: dependency: transitive description: name: string_scanner - sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3" url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.3.0" styled_text: dependency: "direct main" description: @@ -2538,26 +2530,26 @@ packages: dependency: "direct dev" description: name: test - sha256: "7ee44229615f8f642b68120165ae4c2a75fe77ae2065b1e55ae4711f6cf0899e" + sha256: "713a8789d62f3233c46b4a90b174737b2c04cb6ae4500f2aa8b1be8f03f5e67f" url: "https://pub.dev" source: hosted - version: "1.25.7" + version: "1.25.8" test_api: dependency: transitive description: name: test_api - sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" + sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c" url: "https://pub.dev" source: hosted - version: "0.7.2" + version: "0.7.3" test_core: dependency: transitive description: name: test_core - sha256: "55ea5a652e38a1dfb32943a7973f3681a60f872f8c3a05a14664ad54ef9c6696" + sha256: "12391302411737c176b0b5d6491f466b0dd56d4763e347b6714efbaa74d7953d" url: "https://pub.dev" source: hosted - version: "0.6.4" + version: "0.6.5" thermal: dependency: "direct main" description: @@ -2821,10 +2813,10 @@ packages: dependency: transitive description: name: vm_service - sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" + sha256: f6be3ed8bd01289b34d679c2b62226f63c0e69f9fd2e50a6b3c1c729a961041b url: "https://pub.dev" source: hosted - version: "14.2.5" + version: "14.3.0" volume_controller: dependency: transitive description: @@ -2885,10 +2877,10 @@ packages: dependency: transitive description: name: webdriver - sha256: "003d7da9519e1e5f329422b36c4dcdf18d7d2978d1ba099ea4e45ba490ed845e" + sha256: "3d773670966f02a646319410766d3b5e1037efb7f07cc68f844d5e06cd4d61c8" url: "https://pub.dev" source: hosted - version: "3.0.3" + version: "3.0.4" webkit_inspection_protocol: dependency: transitive description: @@ -2945,6 +2937,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.0" + workmanager: + dependency: "direct main" + description: + name: workmanager + sha256: f3c3ce6d79cce53eee4a29dd2e8328c25db5ba5d9062fcc5e8f3c71e0af9b7e4 + url: "https://pub.dev" + source: hosted + version: "0.6.0" xdg_directories: dependency: transitive description: diff --git a/mobile/pubspec.yaml b/mobile/pubspec.yaml index a5800f0156..c943f3f6af 100644 --- a/mobile/pubspec.yaml +++ b/mobile/pubspec.yaml @@ -12,7 +12,7 @@ description: ente photos application # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 1.1.01+1054 +version: 1.1.1+1054 publish_to: none environment: @@ -24,7 +24,7 @@ dependencies: animated_list_plus: ^0.5.2 app_links: ^6.4.0 archive: ^3.6.1 - background_fetch: ^1.3.7 + async: ^2.11.0 battery_info: # replace with battery_plus git: url: https://github.com/ente-io/battery_info @@ -212,6 +212,7 @@ dependencies: wakelock_plus: ^1.1.1 wechat_assets_picker: ^9.5.1 widgets_to_image: ^0.0.2 + workmanager: ^0.6.0 xml: ^6.3.0 dependency_overrides: