Merge 7135f986b72816f7a066d002aa7b0d9dac1f12d4 into 4d20b11f256c40e3894c229ed638d7ea04ebdc44

This commit is contained in:
Sebastian 2024-10-01 20:23:24 +02:00 committed by GitHub
commit 3fad65d7b6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 156 additions and 58 deletions

View File

@ -4,7 +4,6 @@
*.moved-aside *.moved-aside
*.pbxuser *.pbxuser
*.perspectivev3 *.perspectivev3
**/*sync/
.sconsign.dblite .sconsign.dblite
.tags* .tags*
**/.vagrant/ **/.vagrant/

View File

@ -11,6 +11,8 @@
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
65F32F31299BD2F800CE9261 /* BackgroundServicePlugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65F32F30299BD2F800CE9261 /* BackgroundServicePlugin.swift */; }; 65F32F31299BD2F800CE9261 /* BackgroundServicePlugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65F32F30299BD2F800CE9261 /* BackgroundServicePlugin.swift */; };
65F32F33299D349D00CE9261 /* BackgroundSyncWorker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65F32F32299D349D00CE9261 /* BackgroundSyncWorker.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 */; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
@ -19,6 +21,16 @@
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase 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 */ = { 9705A1C41CF9048500538489 /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase; isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647; 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 = "<group>"; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
65F32F30299BD2F800CE9261 /* BackgroundServicePlugin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackgroundServicePlugin.swift; sourceTree = "<group>"; }; 65F32F30299BD2F800CE9261 /* BackgroundServicePlugin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackgroundServicePlugin.swift; sourceTree = "<group>"; };
65F32F32299D349D00CE9261 /* BackgroundSyncWorker.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BackgroundSyncWorker.swift; sourceTree = "<group>"; }; 65F32F32299D349D00CE9261 /* BackgroundSyncWorker.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BackgroundSyncWorker.swift; sourceTree = "<group>"; };
6FC4C0AE2CA322AB00D44B0C /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = "<group>"; };
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 = "<group>"; };
6FC4C0DC2CA32AF000D44B0C /* BackgroundSyncAppShortcut.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackgroundSyncAppShortcut.swift; sourceTree = "<group>"; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
@ -80,6 +97,8 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
886774DBDDE6B35BF2B4F2CD /* Pods_Runner.framework */, 886774DBDDE6B35BF2B4F2CD /* Pods_Runner.framework */,
6FC4C0B62CA324C100D44B0C /* Intents.framework */,
6FC4C0C12CA324C200D44B0C /* IntentsUI.framework */,
); );
name = Frameworks; name = Frameworks;
sourceTree = "<group>"; sourceTree = "<group>";
@ -87,8 +106,10 @@
65DD438629917FAD0047FFA8 /* BackgroundSync */ = { 65DD438629917FAD0047FFA8 /* BackgroundSync */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
6FC4C0DA2CA3268700D44B0C /* BackgroundSyncShortcutIntent.swift */,
65F32F32299D349D00CE9261 /* BackgroundSyncWorker.swift */, 65F32F32299D349D00CE9261 /* BackgroundSyncWorker.swift */,
65F32F30299BD2F800CE9261 /* BackgroundServicePlugin.swift */, 65F32F30299BD2F800CE9261 /* BackgroundServicePlugin.swift */,
6FC4C0DC2CA32AF000D44B0C /* BackgroundSyncAppShortcut.swift */,
); );
path = BackgroundSync; path = BackgroundSync;
sourceTree = "<group>"; sourceTree = "<group>";
@ -126,6 +147,7 @@
97C146F01CF9000F007C117D /* Runner */ = { 97C146F01CF9000F007C117D /* Runner */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
6FC4C0AE2CA322AB00D44B0C /* Runner.entitlements */,
65DD438629917FAD0047FFA8 /* BackgroundSync */, 65DD438629917FAD0047FFA8 /* BackgroundSync */,
FAC7416727DB9F5500C668D8 /* RunnerProfile.entitlements */, FAC7416727DB9F5500C668D8 /* RunnerProfile.entitlements */,
97C146FA1CF9000F007C117D /* Main.storyboard */, 97C146FA1CF9000F007C117D /* Main.storyboard */,
@ -156,6 +178,7 @@
3B06AD1E1E4923F5004D2608 /* Thin Binary */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */,
D218A34AEE62BC1EF119F5B0 /* [CP] Embed Pods Frameworks */, D218A34AEE62BC1EF119F5B0 /* [CP] Embed Pods Frameworks */,
6724EEB7D74949FA08581154 /* [CP] Copy Pods Resources */, 6724EEB7D74949FA08581154 /* [CP] Copy Pods Resources */,
6FC4C0D82CA324C200D44B0C /* Embed Foundation Extensions */,
); );
buildRules = ( buildRules = (
); );
@ -173,6 +196,7 @@
isa = PBXProject; isa = PBXProject;
attributes = { attributes = {
BuildIndependentTargetsInParallel = YES; BuildIndependentTargetsInParallel = YES;
LastSwiftUpdateCheck = 1530;
LastUpgradeCheck = 1510; LastUpgradeCheck = 1510;
ORGANIZATIONNAME = ""; ORGANIZATIONNAME = "";
TargetAttributes = { TargetAttributes = {
@ -313,6 +337,8 @@
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
65F32F33299D349D00CE9261 /* BackgroundSyncWorker.swift in Sources */, 65F32F33299D349D00CE9261 /* BackgroundSyncWorker.swift in Sources */,
6FC4C0DB2CA3268700D44B0C /* BackgroundSyncShortcutIntent.swift in Sources */,
6FC4C0DD2CA32AF000D44B0C /* BackgroundSyncAppShortcut.swift in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@ -396,6 +422,7 @@
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = { buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/RunnerProfile.entitlements; CODE_SIGN_ENTITLEMENTS = Runner/RunnerProfile.entitlements;
@ -539,8 +566,10 @@
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = { buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 177; CURRENT_PROJECT_VERSION = 177;
@ -567,8 +596,10 @@
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = { buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 177; CURRENT_PROJECT_VERSION = 177;

View File

@ -42,6 +42,10 @@ import permission_handler_apple
} }
} }
if #available(iOS 16.0, *) {
BackgroundSyncAppShortcut.updateAppShortcutParameters()
}
return super.application(application, didFinishLaunchingWithOptions: launchOptions) return super.application(application, didFinishLaunchingWithOptions: launchOptions)
} }

View File

@ -0,0 +1,21 @@
//
// 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: [
// TODO: localized title
"Upload gallery using \(.applicationName)"], systemImageName: "square.and.arrow.up.on.square")
}
}

View File

@ -0,0 +1,29 @@
//
// BackgroundSyncShortcutIntent.swift
// Runner
//
// Created by Encotric on 24/09/2024.
//
import AppIntents
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 {
let backgroundWorker = BackgroundSyncWorker { _ in () }
backgroundWorker.run(maxSeconds: nil)
return .result()
}
}

View File

@ -90,6 +90,10 @@
<string>We need to manage backup your photos album</string> <string>We need to manage backup your photos album</string>
<key>NSPhotoLibraryUsageDescription</key> <key>NSPhotoLibraryUsageDescription</key>
<string>We need to manage backup your photos album</string> <string>We need to manage backup your photos album</string>
<key>NSUserActivityTypes</key>
<array>
<string>IntentIntent</string>
</array>
<key>UIApplicationSupportsIndirectInputEvents</key> <key>UIApplicationSupportsIndirectInputEvents</key>
<true/> <true/>
<key>UIBackgroundModes</key> <key>UIBackgroundModes</key>

View File

@ -1,5 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
<dict/> <dict>
<key>com.apple.developer.siri</key>
<true/>
</dict>
</plist> </plist>

View File

@ -4,5 +4,7 @@
<dict> <dict>
<key>aps-environment</key> <key>aps-environment</key>
<string>development</string> <string>development</string>
<key>com.apple.developer.siri</key>
<true/>
</dict> </dict>
</plist> </plist>

View File

@ -2,6 +2,7 @@ import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'package:background_downloader/background_downloader.dart';
import 'package:cancellation_token_http/http.dart' as http; import 'package:cancellation_token_http/http.dart' as http;
import 'package:collection/collection.dart'; import 'package:collection/collection.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -338,31 +339,29 @@ class BackupService {
} }
} }
final fileStream = file.openRead(); final fileLength = file.lengthSync();
final assetRawUploadData = http.MultipartFile(
"assetData", final (baseDir, dir, _) = await Task.split(file: file);
fileStream,
file.lengthSync(), final backgroundRequest = UploadTask(
filename: originalFileName, 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( backgroundRequest.headers.addAll(ApiService.getRequestHeaders());
'POST', backgroundRequest.headers["Transfer-Encoding"] = "chunked";
Uri.parse('$savedEndpoint/assets'), backgroundRequest.fields['deviceAssetId'] = asset.localId!;
onProgress: ((bytes, totalBytes) => onProgress(bytes, totalBytes)), backgroundRequest.fields['deviceId'] = deviceId;
); backgroundRequest.fields['fileCreatedAt'] =
baseRequest.headers.addAll(ApiService.getRequestHeaders());
baseRequest.headers["Transfer-Encoding"] = "chunked";
baseRequest.fields['deviceAssetId'] = asset.localId!;
baseRequest.fields['deviceId'] = deviceId;
baseRequest.fields['fileCreatedAt'] =
asset.fileCreatedAt.toUtc().toIso8601String(); asset.fileCreatedAt.toUtc().toIso8601String();
baseRequest.fields['fileModifiedAt'] = backgroundRequest.fields['fileModifiedAt'] =
asset.fileModifiedAt.toUtc().toIso8601String(); asset.fileModifiedAt.toUtc().toIso8601String();
baseRequest.fields['isFavorite'] = asset.isFavorite.toString(); backgroundRequest.fields['isFavorite'] = asset.isFavorite.toString();
baseRequest.fields['duration'] = asset.duration.toString(); backgroundRequest.fields['duration'] = asset.duration.toString();
baseRequest.files.add(assetRawUploadData);
onCurrentAsset( onCurrentAsset(
CurrentUploadAsset( CurrentUploadAsset(
@ -382,29 +381,37 @@ class BackupService {
livePhotoVideoId = await uploadLivePhotoVideo( livePhotoVideoId = await uploadLivePhotoVideo(
originalFileName, originalFileName,
livePhotoFile, livePhotoFile,
baseRequest, backgroundRequest,
cancelToken, cancelToken,
); );
} }
if (livePhotoVideoId != null) { if (livePhotoVideoId != null) {
baseRequest.fields['livePhotoVideoId'] = livePhotoVideoId; backgroundRequest.fields['livePhotoVideoId'] = livePhotoVideoId;
} }
final response = await httpClient.send( final response = await FileDownloader().upload(
baseRequest, backgroundRequest,
cancellationToken: cancelToken, onProgress: (percentage) => {
// onProgress returns a double in [0.0;1.0] for percentage
if (percentage > 0)
onProgress(
(percentage * fileLength).toInt(),
fileLength,
),
},
); );
final responseBody = final responseBody = jsonDecode(response.responseBody ?? "{}");
jsonDecode(await response.stream.bytesToString());
if (![200, 201].contains(response.statusCode)) { if (response.status == TaskStatus.failed ||
final error = responseBody; ![200, 201].contains(response.responseStatusCode)) {
final errorMessage = error['message'] ?? error['error']; final error = response.exception != null
? response.exception!.description
: responseBody;
debugPrint( 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( onError(
@ -414,11 +421,11 @@ class BackupService {
fileCreatedAt: asset.fileCreatedAt, fileCreatedAt: asset.fileCreatedAt,
fileName: originalFileName, fileName: originalFileName,
fileType: _getAssetType(candidate.asset.type), fileType: _getAssetType(candidate.asset.type),
errorMessage: errorMessage, errorMessage: error,
), ),
); );
if (errorMessage == "Quota has been exceeded!") { if (error == "Quota has been exceeded!") {
anyErrors = true; anyErrors = true;
break; break;
} }
@ -427,7 +434,7 @@ class BackupService {
} }
bool isDuplicate = false; bool isDuplicate = false;
if (response.statusCode == 200) { if (response.responseStatusCode == 200) {
isDuplicate = true; isDuplicate = true;
duplicatedAssetIds.add(asset.localId!); duplicatedAssetIds.add(asset.localId!);
} }
@ -477,7 +484,7 @@ class BackupService {
Future<String?> uploadLivePhotoVideo( Future<String?> uploadLivePhotoVideo(
String originalFileName, String originalFileName,
File? livePhotoVideoFile, File? livePhotoVideoFile,
MultipartRequest baseRequest, UploadTask baseRequest,
http.CancellationToken cancelToken, http.CancellationToken cancelToken,
) async { ) async {
if (livePhotoVideoFile == null) { if (livePhotoVideoFile == null) {
@ -487,35 +494,33 @@ class BackupService {
originalFileName, originalFileName,
p.extension(livePhotoVideoFile.path), p.extension(livePhotoVideoFile.path),
); );
final fileStream = livePhotoVideoFile.openRead();
final livePhotoRawUploadData = http.MultipartFile( final (baseDir, dir, _) = await Task.split(file: livePhotoVideoFile);
"assetData",
fileStream, final backgroundRequest = UploadTask(
livePhotoVideoFile.lengthSync(),
filename: livePhotoTitle, filename: livePhotoTitle,
); baseDirectory: baseDir,
final livePhotoReq = MultipartRequest( directory: dir,
baseRequest.method, url: baseRequest.url,
baseRequest.url, httpRequestMethod: baseRequest.httpRequestMethod,
onProgress: baseRequest.onProgress, priority: baseRequest.priority,
) )
..headers.addAll(baseRequest.headers) ..headers.addAll(baseRequest.headers)
..fields.addAll(baseRequest.fields); ..fields.addAll(baseRequest.fields);
livePhotoReq.files.add(livePhotoRawUploadData); final response = await FileDownloader()
.upload(backgroundRequest); //TODO: onProgress callback?
var response = await httpClient.send( var responseBody = jsonDecode(response.responseBody ?? "{}");
livePhotoReq,
cancellationToken: cancelToken,
);
var responseBody = jsonDecode(await response.stream.bytesToString()); if (response.status == TaskStatus.failed ||
![200, 201].contains(response.responseStatusCode)) {
if (![200, 201].contains(response.statusCode)) { final error = response.exception != null
var error = responseBody; ? response.exception!.description
: responseBody;
debugPrint( debugPrint(
"Error(${error['statusCode']}) uploading livePhoto for assetId | $livePhotoTitle | ${error['error']}", "Error(${error['statusCode']}) uploading livePhoto for assetId | $livePhotoTitle | $error",
); );
} }