From 1b5424c2307277b72475184be60b0cad0f311d98 Mon Sep 17 00:00:00 2001 From: Encotric Date: Tue, 24 Sep 2024 22:11:31 +0200 Subject: [PATCH 1/3] fix: remove .gitignore entry "**/*sync" to include background sync swift files --- mobile/ios/.gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/mobile/ios/.gitignore b/mobile/ios/.gitignore index f312f249a39ff..e32cadbf686e0 100644 --- a/mobile/ios/.gitignore +++ b/mobile/ios/.gitignore @@ -4,7 +4,6 @@ *.moved-aside *.pbxuser *.perspectivev3 -**/*sync/ .sconsign.dblite .tags* **/.vagrant/ From 67df25cc9e56cb17cc63b731068d31fd4317801a Mon Sep 17 00:00:00 2001 From: Encotric Date: Tue, 24 Sep 2024 22:12:39 +0200 Subject: [PATCH 2/3] dev: iOS app intent for background sync --- mobile/ios/Runner.xcodeproj/project.pbxproj | 31 +++++++++++++++++++ mobile/ios/Runner/AppDelegate.swift | 4 +++ .../BackgroundSyncAppShortcut.swift | 20 ++++++++++++ .../BackgroundSyncShortcutIntent.swift | 24 ++++++++++++++ mobile/ios/Runner/Info.plist | 4 +++ mobile/ios/Runner/Runner.entitlements | 5 ++- mobile/ios/Runner/RunnerProfile.entitlements | 2 ++ 7 files changed, 89 insertions(+), 1 deletion(-) create mode 100644 mobile/ios/Runner/BackgroundSync/BackgroundSyncAppShortcut.swift create mode 100644 mobile/ios/Runner/BackgroundSync/BackgroundSyncShortcutIntent.swift diff --git a/mobile/ios/Runner.xcodeproj/project.pbxproj b/mobile/ios/Runner.xcodeproj/project.pbxproj index 2d7cdc153cab8..19d1217d6e370 100644 --- a/mobile/ios/Runner.xcodeproj/project.pbxproj +++ b/mobile/ios/Runner.xcodeproj/project.pbxproj @@ -11,6 +11,8 @@ 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 65F32F31299BD2F800CE9261 /* BackgroundServicePlugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65F32F30299BD2F800CE9261 /* BackgroundServicePlugin.swift */; }; 65F32F33299D349D00CE9261 /* BackgroundSyncWorker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65F32F32299D349D00CE9261 /* BackgroundSyncWorker.swift */; }; + 6FC4C0DB2CA3268700D44B0C /* BackgroundSyncShortcutIntent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FC4C0DA2CA3268700D44B0C /* BackgroundSyncShortcutIntent.swift */; }; + 6FC4C0DD2CA32AF000D44B0C /* BackgroundSyncAppShortcut.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FC4C0DC2CA32AF000D44B0C /* BackgroundSyncAppShortcut.swift */; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; @@ -19,6 +21,16 @@ /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ + 6FC4C0D82CA324C200D44B0C /* Embed Foundation Extensions */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 13; + files = ( + ); + name = "Embed Foundation Extensions"; + runOnlyForDeploymentPostprocessing = 0; + }; 9705A1C41CF9048500538489 /* Embed Frameworks */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; @@ -38,6 +50,11 @@ 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 65F32F30299BD2F800CE9261 /* BackgroundServicePlugin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackgroundServicePlugin.swift; sourceTree = ""; }; 65F32F32299D349D00CE9261 /* BackgroundSyncWorker.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BackgroundSyncWorker.swift; sourceTree = ""; }; + 6FC4C0AE2CA322AB00D44B0C /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = ""; }; + 6FC4C0B62CA324C100D44B0C /* Intents.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Intents.framework; path = System/Library/Frameworks/Intents.framework; sourceTree = SDKROOT; }; + 6FC4C0C12CA324C200D44B0C /* IntentsUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IntentsUI.framework; path = System/Library/Frameworks/IntentsUI.framework; sourceTree = SDKROOT; }; + 6FC4C0DA2CA3268700D44B0C /* BackgroundSyncShortcutIntent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackgroundSyncShortcutIntent.swift; sourceTree = ""; }; + 6FC4C0DC2CA32AF000D44B0C /* BackgroundSyncAppShortcut.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackgroundSyncAppShortcut.swift; sourceTree = ""; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; @@ -80,6 +97,8 @@ isa = PBXGroup; children = ( 886774DBDDE6B35BF2B4F2CD /* Pods_Runner.framework */, + 6FC4C0B62CA324C100D44B0C /* Intents.framework */, + 6FC4C0C12CA324C200D44B0C /* IntentsUI.framework */, ); name = Frameworks; sourceTree = ""; @@ -87,8 +106,10 @@ 65DD438629917FAD0047FFA8 /* BackgroundSync */ = { isa = PBXGroup; children = ( + 6FC4C0DA2CA3268700D44B0C /* BackgroundSyncShortcutIntent.swift */, 65F32F32299D349D00CE9261 /* BackgroundSyncWorker.swift */, 65F32F30299BD2F800CE9261 /* BackgroundServicePlugin.swift */, + 6FC4C0DC2CA32AF000D44B0C /* BackgroundSyncAppShortcut.swift */, ); path = BackgroundSync; sourceTree = ""; @@ -126,6 +147,7 @@ 97C146F01CF9000F007C117D /* Runner */ = { isa = PBXGroup; children = ( + 6FC4C0AE2CA322AB00D44B0C /* Runner.entitlements */, 65DD438629917FAD0047FFA8 /* BackgroundSync */, FAC7416727DB9F5500C668D8 /* RunnerProfile.entitlements */, 97C146FA1CF9000F007C117D /* Main.storyboard */, @@ -156,6 +178,7 @@ 3B06AD1E1E4923F5004D2608 /* Thin Binary */, D218A34AEE62BC1EF119F5B0 /* [CP] Embed Pods Frameworks */, 6724EEB7D74949FA08581154 /* [CP] Copy Pods Resources */, + 6FC4C0D82CA324C200D44B0C /* Embed Foundation Extensions */, ); buildRules = ( ); @@ -173,6 +196,7 @@ isa = PBXProject; attributes = { BuildIndependentTargetsInParallel = YES; + LastSwiftUpdateCheck = 1530; LastUpgradeCheck = 1510; ORGANIZATIONNAME = ""; TargetAttributes = { @@ -313,6 +337,8 @@ 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, 65F32F33299D349D00CE9261 /* BackgroundSyncWorker.swift in Sources */, + 6FC4C0DB2CA3268700D44B0C /* BackgroundSyncShortcutIntent.swift in Sources */, + 6FC4C0DD2CA32AF000D44B0C /* BackgroundSyncAppShortcut.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -396,6 +422,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/RunnerProfile.entitlements; @@ -539,8 +566,10 @@ isa = XCBuildConfiguration; baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 175; @@ -567,8 +596,10 @@ isa = XCBuildConfiguration; baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 175; diff --git a/mobile/ios/Runner/AppDelegate.swift b/mobile/ios/Runner/AppDelegate.swift index 05cb061ca58b2..42c5eaad20756 100644 --- a/mobile/ios/Runner/AppDelegate.swift +++ b/mobile/ios/Runner/AppDelegate.swift @@ -42,6 +42,10 @@ import permission_handler_apple } } + if #available(iOS 16.0, *) { + BackgroundSyncAppShortcut.updateAppShortcutParameters() + } + return super.application(application, didFinishLaunchingWithOptions: launchOptions) } diff --git a/mobile/ios/Runner/BackgroundSync/BackgroundSyncAppShortcut.swift b/mobile/ios/Runner/BackgroundSync/BackgroundSyncAppShortcut.swift new file mode 100644 index 0000000000000..a7d3e2ee7ed79 --- /dev/null +++ b/mobile/ios/Runner/BackgroundSync/BackgroundSyncAppShortcut.swift @@ -0,0 +1,20 @@ +// +// BackgroundSyncAppShortcut.swift +// Runner +// +// Created by Encotric on 24/09/2024. +// + +import AppIntents + + +@available(iOS 16.0, *) +struct BackgroundSyncAppShortcut: AppShortcutsProvider { + + @AppShortcutsBuilder static var appShortcuts: [AppShortcut] { + AppShortcut(intent: BackgroundSyncShortcutIntent(), phrases: [ + "Upload gallery using \(.applicationName)"], systemImageName: "square.and.arrow.up.on.square") + } + +} + diff --git a/mobile/ios/Runner/BackgroundSync/BackgroundSyncShortcutIntent.swift b/mobile/ios/Runner/BackgroundSync/BackgroundSyncShortcutIntent.swift new file mode 100644 index 0000000000000..3480344d511e2 --- /dev/null +++ b/mobile/ios/Runner/BackgroundSync/BackgroundSyncShortcutIntent.swift @@ -0,0 +1,24 @@ +// +// BackgroundSyncShortcutIntent.swift +// Runner +// +// Created by Encotric on 24/09/2024. +// + +import AppIntents +import SwiftUI + +@available(iOS 16.0, *) +struct BackgroundSyncShortcutIntent: AppIntent { + + static var title: LocalizedStringResource = "Sync gallery" + + func perform() async throws -> some IntentResult { + + let backgroundWorker = BackgroundSyncWorker { _ in () } + backgroundWorker.run(maxSeconds: nil) + + return .result() + } + +} diff --git a/mobile/ios/Runner/Info.plist b/mobile/ios/Runner/Info.plist index 1831798a4288e..79755b7093771 100644 --- a/mobile/ios/Runner/Info.plist +++ b/mobile/ios/Runner/Info.plist @@ -90,6 +90,10 @@ We need to manage backup your photos album NSPhotoLibraryUsageDescription We need to manage backup your photos album + NSUserActivityTypes + + IntentIntent + UIApplicationSupportsIndirectInputEvents UIBackgroundModes diff --git a/mobile/ios/Runner/Runner.entitlements b/mobile/ios/Runner/Runner.entitlements index 0c67376ebacb4..21d95c45f32e1 100644 --- a/mobile/ios/Runner/Runner.entitlements +++ b/mobile/ios/Runner/Runner.entitlements @@ -1,5 +1,8 @@ - + + com.apple.developer.siri + + diff --git a/mobile/ios/Runner/RunnerProfile.entitlements b/mobile/ios/Runner/RunnerProfile.entitlements index 903def2af5306..434a016c89f92 100644 --- a/mobile/ios/Runner/RunnerProfile.entitlements +++ b/mobile/ios/Runner/RunnerProfile.entitlements @@ -4,5 +4,7 @@ aps-environment development + com.apple.developer.siri + From 7135f986b72816f7a066d002aa7b0d9dac1f12d4 Mon Sep 17 00:00:00 2001 From: Sebastian Wilke Date: Thu, 26 Sep 2024 18:27:17 +0200 Subject: [PATCH 3/3] dev: switch from pub cancellation_token_http to background_downloader to use URLSessionTasks on iOS for background sync --- .../BackgroundSyncAppShortcut.swift | 1 + .../BackgroundSyncShortcutIntent.swift | 5 + mobile/lib/services/backup.service.dart | 117 +++++++++--------- mobile/pubspec.lock | 12 +- mobile/pubspec.yaml | 3 +- 5 files changed, 79 insertions(+), 59 deletions(-) diff --git a/mobile/ios/Runner/BackgroundSync/BackgroundSyncAppShortcut.swift b/mobile/ios/Runner/BackgroundSync/BackgroundSyncAppShortcut.swift index a7d3e2ee7ed79..71b9f2ea451c0 100644 --- a/mobile/ios/Runner/BackgroundSync/BackgroundSyncAppShortcut.swift +++ b/mobile/ios/Runner/BackgroundSync/BackgroundSyncAppShortcut.swift @@ -13,6 +13,7 @@ struct BackgroundSyncAppShortcut: AppShortcutsProvider { @AppShortcutsBuilder static var appShortcuts: [AppShortcut] { AppShortcut(intent: BackgroundSyncShortcutIntent(), phrases: [ + // TODO: localized title "Upload gallery using \(.applicationName)"], systemImageName: "square.and.arrow.up.on.square") } diff --git a/mobile/ios/Runner/BackgroundSync/BackgroundSyncShortcutIntent.swift b/mobile/ios/Runner/BackgroundSync/BackgroundSyncShortcutIntent.swift index 3480344d511e2..97cf3d31fa32d 100644 --- a/mobile/ios/Runner/BackgroundSync/BackgroundSyncShortcutIntent.swift +++ b/mobile/ios/Runner/BackgroundSync/BackgroundSyncShortcutIntent.swift @@ -11,7 +11,12 @@ import SwiftUI @available(iOS 16.0, *) struct BackgroundSyncShortcutIntent: AppIntent { + // TODO: localized title and description static var title: LocalizedStringResource = "Sync gallery" + + static var openAppWhenRun: Bool = true + + static var isDiscoverable: Bool = true func perform() async throws -> some IntentResult { diff --git a/mobile/lib/services/backup.service.dart b/mobile/lib/services/backup.service.dart index 19d731d773d75..a7328231e7318 100644 --- a/mobile/lib/services/backup.service.dart +++ b/mobile/lib/services/backup.service.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'dart:convert'; import 'dart:io'; +import 'package:background_downloader/background_downloader.dart'; import 'package:cancellation_token_http/http.dart' as http; import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; @@ -339,31 +340,29 @@ class BackupService { } } - final fileStream = file.openRead(); - final assetRawUploadData = http.MultipartFile( - "assetData", - fileStream, - file.lengthSync(), + final fileLength = file.lengthSync(); + + final (baseDir, dir, _) = await Task.split(file: file); + + final backgroundRequest = UploadTask( filename: originalFileName, - ); + baseDirectory: baseDir, + directory: dir, + url: '$savedEndpoint/assets', + httpRequestMethod: 'POST', + priority: 10, + ); // Priority 10 for testing purposes; maybe we could change that to a lower value later - final baseRequest = MultipartRequest( - 'POST', - Uri.parse('$savedEndpoint/assets'), - onProgress: ((bytes, totalBytes) => onProgress(bytes, totalBytes)), - ); - - baseRequest.headers.addAll(ApiService.getRequestHeaders()); - baseRequest.headers["Transfer-Encoding"] = "chunked"; - baseRequest.fields['deviceAssetId'] = asset.localId!; - baseRequest.fields['deviceId'] = deviceId; - baseRequest.fields['fileCreatedAt'] = + backgroundRequest.headers.addAll(ApiService.getRequestHeaders()); + backgroundRequest.headers["Transfer-Encoding"] = "chunked"; + backgroundRequest.fields['deviceAssetId'] = asset.localId!; + backgroundRequest.fields['deviceId'] = deviceId; + backgroundRequest.fields['fileCreatedAt'] = asset.fileCreatedAt.toUtc().toIso8601String(); - baseRequest.fields['fileModifiedAt'] = + backgroundRequest.fields['fileModifiedAt'] = asset.fileModifiedAt.toUtc().toIso8601String(); - baseRequest.fields['isFavorite'] = asset.isFavorite.toString(); - baseRequest.fields['duration'] = asset.duration.toString(); - baseRequest.files.add(assetRawUploadData); + backgroundRequest.fields['isFavorite'] = asset.isFavorite.toString(); + backgroundRequest.fields['duration'] = asset.duration.toString(); onCurrentAsset( CurrentUploadAsset( @@ -383,29 +382,37 @@ class BackupService { livePhotoVideoId = await uploadLivePhotoVideo( originalFileName, livePhotoFile, - baseRequest, + backgroundRequest, cancelToken, ); } if (livePhotoVideoId != null) { - baseRequest.fields['livePhotoVideoId'] = livePhotoVideoId; + backgroundRequest.fields['livePhotoVideoId'] = livePhotoVideoId; } - final response = await httpClient.send( - baseRequest, - cancellationToken: cancelToken, + final response = await FileDownloader().upload( + backgroundRequest, + onProgress: (percentage) => { + // onProgress returns a double in [0.0;1.0] for percentage + if (percentage > 0) + onProgress( + (percentage * fileLength).toInt(), + fileLength, + ), + }, ); - final responseBody = - jsonDecode(await response.stream.bytesToString()); + final responseBody = jsonDecode(response.responseBody ?? "{}"); - if (![200, 201].contains(response.statusCode)) { - final error = responseBody; - final errorMessage = error['message'] ?? error['error']; + if (response.status == TaskStatus.failed || + ![200, 201].contains(response.responseStatusCode)) { + final error = response.exception != null + ? response.exception!.description + : responseBody; debugPrint( - "Error(${error['statusCode']}) uploading ${asset.localId} | $originalFileName | Created on ${asset.fileCreatedAt} | ${error['error']}", + "Error(${response.responseStatusCode}) uploading ${asset.localId} | $originalFileName | Created on ${asset.fileCreatedAt} | $error", ); onError( @@ -415,11 +422,11 @@ class BackupService { fileCreatedAt: asset.fileCreatedAt, fileName: originalFileName, fileType: _getAssetType(candidate.asset.type), - errorMessage: errorMessage, + errorMessage: error, ), ); - if (errorMessage == "Quota has been exceeded!") { + if (error == "Quota has been exceeded!") { anyErrors = true; break; } @@ -428,7 +435,7 @@ class BackupService { } bool isDuplicate = false; - if (response.statusCode == 200) { + if (response.responseStatusCode == 200) { isDuplicate = true; duplicatedAssetIds.add(asset.localId!); } @@ -478,7 +485,7 @@ class BackupService { Future uploadLivePhotoVideo( String originalFileName, File? livePhotoVideoFile, - MultipartRequest baseRequest, + UploadTask baseRequest, http.CancellationToken cancelToken, ) async { if (livePhotoVideoFile == null) { @@ -488,35 +495,33 @@ class BackupService { originalFileName, p.extension(livePhotoVideoFile.path), ); - final fileStream = livePhotoVideoFile.openRead(); - final livePhotoRawUploadData = http.MultipartFile( - "assetData", - fileStream, - livePhotoVideoFile.lengthSync(), + + final (baseDir, dir, _) = await Task.split(file: livePhotoVideoFile); + + final backgroundRequest = UploadTask( filename: livePhotoTitle, - ); - final livePhotoReq = MultipartRequest( - baseRequest.method, - baseRequest.url, - onProgress: baseRequest.onProgress, + baseDirectory: baseDir, + directory: dir, + url: baseRequest.url, + httpRequestMethod: baseRequest.httpRequestMethod, + priority: baseRequest.priority, ) ..headers.addAll(baseRequest.headers) ..fields.addAll(baseRequest.fields); - livePhotoReq.files.add(livePhotoRawUploadData); + final response = await FileDownloader() + .upload(backgroundRequest); //TODO: onProgress callback? - var response = await httpClient.send( - livePhotoReq, - cancellationToken: cancelToken, - ); + var responseBody = jsonDecode(response.responseBody ?? "{}"); - var responseBody = jsonDecode(await response.stream.bytesToString()); - - if (![200, 201].contains(response.statusCode)) { - var error = responseBody; + if (response.status == TaskStatus.failed || + ![200, 201].contains(response.responseStatusCode)) { + final error = response.exception != null + ? response.exception!.description + : responseBody; debugPrint( - "Error(${error['statusCode']}) uploading livePhoto for assetId | $livePhotoTitle | ${error['error']}", + "Error(${error['statusCode']}) uploading livePhoto for assetId | $livePhotoTitle | $error", ); } diff --git a/mobile/pubspec.lock b/mobile/pubspec.lock index aaea00d699bbe..9dadbd1028a64 100644 --- a/mobile/pubspec.lock +++ b/mobile/pubspec.lock @@ -78,6 +78,14 @@ packages: url: "https://pub.dev" source: hosted version: "9.0.0" + background_downloader: + dependency: "direct main" + description: + name: background_downloader + sha256: "6a945db1a1c7727a4bc9c1d7c882cfb1a819f873b77e01d5e5dd6a3fb231cb28" + url: "https://pub.dev" + source: hosted + version: "8.5.5" boolean_selector: dependency: transitive description: @@ -744,10 +752,10 @@ packages: dependency: "direct main" description: name: http - sha256: "5895291c13fa8a3bd82e76d5627f69e0d85ca6a30dcac95c4ea19a5d555879c2" + sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010 url: "https://pub.dev" source: hosted - version: "0.13.6" + version: "1.2.2" http_multi_server: dependency: transitive description: diff --git a/mobile/pubspec.yaml b/mobile/pubspec.yaml index 0f75463547d6b..a66453a5fcd93 100644 --- a/mobile/pubspec.yaml +++ b/mobile/pubspec.yaml @@ -32,7 +32,7 @@ dependencies: flutter_svg: ^2.0.9 package_info_plus: ^8.0.1 url_launcher: ^6.2.4 - http: ^0.13.6 + http: ^1.1.0 cancellation_token_http: ^2.0.0 easy_localization: ^3.0.3 share_plus: ^10.0.0 @@ -56,6 +56,7 @@ dependencies: thumbhash: 0.1.0+1 async: ^2.11.0 dynamic_color: ^1.7.0 #package to apply system theme + background_downloader: ^8.5.5 #image editing packages crop_image: ^1.0.13