mirror of
https://github.com/immich-app/immich.git
synced 2025-06-03 21:54:21 -04:00
feat: new mobile upload
This commit is contained in:
parent
aa68588b1d
commit
054aa8e386
@ -235,7 +235,6 @@ EXTERNAL SOURCES:
|
||||
:path: ".symlinks/plugins/wakelock_plus/ios"
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
background_downloader: 50e91d979067b82081aba359d7d916b3ba5fadad
|
||||
background_downloader: 50e91d979067b82081aba359d7d916b3ba5fadad
|
||||
connectivity_plus: cb623214f4e1f6ef8fe7403d580fdad517d2f7dd
|
||||
device_info_plus: 21fcca2080fbcd348be798aa36c3e5ed849eefbe
|
||||
@ -275,6 +274,6 @@ SPEC CHECKSUMS:
|
||||
url_launcher_ios: 694010445543906933d732453a59da0a173ae33d
|
||||
wakelock_plus: 04623e3f525556020ebd4034310f20fe7fda8b49
|
||||
|
||||
PODFILE CHECKSUM: 04655a9b6714fa7a2b4fb559982ee8bed4b3b718
|
||||
PODFILE CHECKSUM: 7ce312f2beab01395db96f6969d90a447279cf45
|
||||
|
||||
COCOAPODS: 1.16.2
|
||||
|
@ -4,8 +4,11 @@ abstract interface class IUploadRepository {
|
||||
void Function(TaskStatusUpdate)? onUploadStatus;
|
||||
void Function(TaskProgressUpdate)? onTaskProgress;
|
||||
|
||||
void enqueue(UploadTask task);
|
||||
void enqueueAll(List<UploadTask> tasks);
|
||||
Future<bool> cancel(String id);
|
||||
void cancelAll();
|
||||
Future<void> pauseAll();
|
||||
Future<void> deleteAllTrackingRecords();
|
||||
Future<void> deleteRecordsWithIds(List<String> id);
|
||||
Future<List<TaskRecord>> getRecords([TaskStatus? status]);
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ import 'package:immich_mobile/providers/backup/ios_background_settings.provider.
|
||||
import 'package:immich_mobile/providers/backup/manual_upload.provider.dart';
|
||||
import 'package:immich_mobile/providers/websocket.provider.dart';
|
||||
import 'package:immich_mobile/routing/router.dart';
|
||||
import 'package:immich_mobile/services/upload.service.dart';
|
||||
import 'package:immich_mobile/widgets/backup/backup_info_card.dart';
|
||||
import 'package:immich_mobile/widgets/backup/current_backup_asset_info_box.dart';
|
||||
import 'package:wakelock_plus/wakelock_plus.dart';
|
||||
@ -333,6 +334,32 @@ class BackupControllerPage extends HookConsumerWidget {
|
||||
const CurrentUploadingAssetInfoBox(),
|
||||
if (!hasExclusiveAccess) buildBackgroundBackupInfo(),
|
||||
buildBackupButton(),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
ref.watch(uploadServiceProvider).getRecords();
|
||||
},
|
||||
child: const Text(
|
||||
"get record",
|
||||
),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
ref
|
||||
.watch(uploadServiceProvider)
|
||||
.deleteAllUploadTasks();
|
||||
},
|
||||
child: const Text(
|
||||
"clear records",
|
||||
),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
ref.watch(uploadServiceProvider).cancelAllUpload();
|
||||
},
|
||||
child: const Text(
|
||||
"cancel all uploads",
|
||||
),
|
||||
),
|
||||
]
|
||||
: [
|
||||
buildFolderSelectionTile(),
|
||||
|
@ -134,7 +134,7 @@ class ShareIntentUploadStateNotifier
|
||||
}
|
||||
|
||||
Future<void> upload(File file) {
|
||||
return _uploadService.upload(file);
|
||||
return _uploadService.buildUploadTask(file);
|
||||
}
|
||||
|
||||
Future<bool> cancelUpload(String id) {
|
||||
|
@ -580,15 +580,15 @@ class BackupNotifier extends StateNotifier<BackUpState> {
|
||||
|
||||
switch (update.status) {
|
||||
case TaskStatus.complete:
|
||||
if (update.responseStatusCode == 200) {
|
||||
if (kDebugMode) {
|
||||
debugPrint("[COMPLETE] ${update.task.taskId} - DUPLICATE");
|
||||
}
|
||||
} else {
|
||||
if (kDebugMode) {
|
||||
debugPrint("[COMPLETE] ${update.task.taskId}");
|
||||
}
|
||||
}
|
||||
// if (update.responseStatusCode == 200) {
|
||||
// if (kDebugMode) {
|
||||
// debugPrint("[COMPLETE] ${update.task.taskId} - DUPLICATE");
|
||||
// }
|
||||
// } else {
|
||||
// if (kDebugMode) {
|
||||
// debugPrint("[COMPLETE] ${update.task.taskId}");
|
||||
// }
|
||||
// }
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -1,4 +1,5 @@
|
||||
import 'package:background_downloader/background_downloader.dart';
|
||||
import 'package:flutter_cache_manager/file.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/interfaces/upload.interface.dart';
|
||||
import 'package:immich_mobile/utils/upload.dart';
|
||||
@ -19,15 +20,15 @@ class UploadRepository implements IUploadRepository {
|
||||
taskQueue.maxConcurrent = 5;
|
||||
FileDownloader().addTaskQueue(taskQueue);
|
||||
FileDownloader().registerCallbacks(
|
||||
group: uploadGroup,
|
||||
group: kUploadGroup,
|
||||
taskStatusCallback: (update) => onUploadStatus?.call(update),
|
||||
taskProgressCallback: (update) => onTaskProgress?.call(update),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void enqueue(UploadTask task) {
|
||||
taskQueue.add(task);
|
||||
void enqueueAll(List<UploadTask> tasks) {
|
||||
taskQueue.addAll(tasks);
|
||||
}
|
||||
|
||||
@override
|
||||
@ -40,8 +41,27 @@ class UploadRepository implements IUploadRepository {
|
||||
return FileDownloader().cancelTaskWithId(id);
|
||||
}
|
||||
|
||||
@override
|
||||
void cancelAll() {
|
||||
return taskQueue.removeAll();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> pauseAll() {
|
||||
return FileDownloader().pauseAll(group: kUploadGroup);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> deleteRecordsWithIds(List<String> ids) {
|
||||
return FileDownloader().database.deleteRecordsWithIds(ids);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<TaskRecord>> getRecords([TaskStatus? status]) {
|
||||
if (status == null) {
|
||||
return FileDownloader().database.allRecords(group: kUploadGroup);
|
||||
}
|
||||
|
||||
return FileDownloader().database.allRecordsWithStatus(status);
|
||||
}
|
||||
}
|
||||
|
@ -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';
|
||||
@ -262,6 +263,8 @@ class BackupService {
|
||||
}
|
||||
|
||||
List<BackupCandidate> candidates = assets.toList();
|
||||
print("Found ${candidates.length} assets to upload");
|
||||
List<UploadTask> uploadTasks = [];
|
||||
for (final candidate in candidates) {
|
||||
final Asset asset = candidate.asset;
|
||||
File? file;
|
||||
@ -278,13 +281,24 @@ class BackupService {
|
||||
await _assetMediaRepository.getOriginalFilename(asset.localId!) ??
|
||||
asset.fileName;
|
||||
|
||||
await _uploadService.upload(
|
||||
final task = await _uploadService.buildUploadTask(
|
||||
file,
|
||||
originalFileName: originalFileName,
|
||||
deviceAssetId: asset.localId,
|
||||
);
|
||||
|
||||
uploadTasks.add(task);
|
||||
}
|
||||
}
|
||||
|
||||
if (uploadTasks.isEmpty) {
|
||||
debugPrint("No assets to upload");
|
||||
return false;
|
||||
}
|
||||
|
||||
print("Uploading ${uploadTasks.length} assets");
|
||||
|
||||
_uploadService.upload(uploadTasks);
|
||||
}
|
||||
|
||||
Future<bool> backupAsset(
|
||||
|
@ -42,23 +42,47 @@ class UploadService {
|
||||
return FileDownloader().cancelTaskWithId(id);
|
||||
}
|
||||
|
||||
Future<void> upload(
|
||||
void cancelAllUpload() {
|
||||
return _uploadRepository.cancelAll();
|
||||
}
|
||||
|
||||
Future<void> pauseAllUploads() {
|
||||
return _uploadRepository.pauseAll();
|
||||
}
|
||||
|
||||
Future<void> deleteAllUploadTasks() {
|
||||
return _uploadRepository.deleteAllTrackingRecords();
|
||||
}
|
||||
|
||||
Future<List<TaskRecord>> getRecords() async {
|
||||
final all = await _uploadRepository.getRecords();
|
||||
print('all record: all: ${all.length} records found');
|
||||
final enqueue = await _uploadRepository.getRecords(TaskStatus.enqueued);
|
||||
print(
|
||||
'all record: enqueue: ${enqueue.length} records found',
|
||||
);
|
||||
return all;
|
||||
}
|
||||
|
||||
void upload(List<UploadTask> tasks) {
|
||||
_uploadRepository.enqueueAll(tasks);
|
||||
}
|
||||
|
||||
Future<UploadTask> buildUploadTask(
|
||||
File file, {
|
||||
Map<String, String>? fields,
|
||||
String? originalFileName,
|
||||
String? deviceAssetId,
|
||||
}) async {
|
||||
final task = await _buildUploadTask(
|
||||
return _buildTask(
|
||||
deviceAssetId ?? hash(file.path).toString(),
|
||||
file,
|
||||
fields: fields,
|
||||
originalFileName: originalFileName,
|
||||
);
|
||||
|
||||
_uploadRepository.enqueue(task);
|
||||
}
|
||||
|
||||
Future<UploadTask> _buildUploadTask(
|
||||
Future<UploadTask> _buildTask(
|
||||
String id,
|
||||
File file, {
|
||||
Map<String, String>? fields,
|
||||
@ -95,7 +119,7 @@ class UploadService {
|
||||
baseDirectory: baseDirectory,
|
||||
directory: directory,
|
||||
fileField: 'assetData',
|
||||
group: uploadGroup,
|
||||
group: kUploadGroup,
|
||||
updates: Updates.statusAndProgress,
|
||||
);
|
||||
}
|
||||
|
@ -1 +1 @@
|
||||
const uploadGroup = 'upload_group';
|
||||
const kUploadGroup = 'upload_group';
|
||||
|
@ -102,6 +102,10 @@ export class FileUploadInterceptor implements NestInterceptor {
|
||||
}
|
||||
|
||||
private filename(request: AuthRequest, file: Express.Multer.File, callback: DiskStorageCallback) {
|
||||
console.log(
|
||||
'FileUploadInterceptor.filename called with file:',
|
||||
this.assetService.getUploadFilename(asRequest(request, file)),
|
||||
);
|
||||
return callbackify(
|
||||
() => this.assetService.getUploadFilename(asRequest(request, file)),
|
||||
callback as Callback<string>,
|
||||
|
Loading…
x
Reference in New Issue
Block a user