Skip to content

Commit 12a472e

Browse files
committed
fix: filename interpretation
1 parent 3ccde45 commit 12a472e

File tree

8 files changed

+173
-49
lines changed

8 files changed

+173
-49
lines changed

mobile/lib/main.dart

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,21 @@ class ImmichAppState extends ConsumerState<ImmichApp>
156156
}
157157

158158
void _configureFileDownloaderNotifications() {
159-
FileDownloader().configureNotification(
159+
FileDownloader().configureNotificationForGroup(
160+
downloadGroupImage,
161+
running: TaskNotification(
162+
'downloading_media'.tr(),
163+
'${'file_name'.tr()}: {filename}',
164+
),
165+
complete: TaskNotification(
166+
'download_finished'.tr(),
167+
'${'file_name'.tr()}: {filename}',
168+
),
169+
progressBar: true,
170+
);
171+
172+
FileDownloader().configureNotificationForGroup(
173+
downloadGroupVideo,
160174
running: TaskNotification(
161175
'downloading_media'.tr(),
162176
'${'file_name'.tr()}: {filename}',

mobile/lib/pages/backup/exp_backup_controller.page.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ class ExpBackupPage extends HookConsumerWidget {
197197
const RemainderCard(),
198198
const Divider(),
199199
buildControlButtons(),
200-
const CurrentUploadingAssetInfoBox(),
200+
// const CurrentUploadingAssetInfoBox(),
201201
]
202202
: [
203203
const BackupAlbumSelectionCard(),

mobile/lib/providers/backup/exp_backup.provider.dart

Lines changed: 110 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,35 +2,99 @@
22
import 'dart:convert';
33

44
import 'package:background_downloader/background_downloader.dart';
5+
import 'package:collection/collection.dart';
56
import 'package:flutter/cupertino.dart';
67
import 'package:hooks_riverpod/hooks_riverpod.dart';
7-
import 'package:immich_mobile/constants/constants.dart';
8+
89
import 'package:immich_mobile/domain/utils/background_sync.dart';
910
import 'package:immich_mobile/providers/background_sync.provider.dart';
10-
1111
import 'package:immich_mobile/services/exp_backup.service.dart';
1212
import 'package:immich_mobile/services/upload.service.dart';
1313

14+
class ExpUploadStatus {
15+
final String taskId;
16+
final String filename;
17+
final double progress;
18+
ExpUploadStatus({
19+
required this.taskId,
20+
required this.filename,
21+
required this.progress,
22+
});
23+
24+
ExpUploadStatus copyWith({
25+
String? taskId,
26+
String? filename,
27+
double? progress,
28+
}) {
29+
return ExpUploadStatus(
30+
taskId: taskId ?? this.taskId,
31+
filename: filename ?? this.filename,
32+
progress: progress ?? this.progress,
33+
);
34+
}
35+
36+
Map<String, dynamic> toMap() {
37+
return <String, dynamic>{
38+
'taskId': taskId,
39+
'filename': filename,
40+
'progress': progress,
41+
};
42+
}
43+
44+
factory ExpUploadStatus.fromMap(Map<String, dynamic> map) {
45+
return ExpUploadStatus(
46+
taskId: map['taskId'] as String,
47+
filename: map['filename'] as String,
48+
progress: map['progress'] as double,
49+
);
50+
}
51+
52+
String toJson() => json.encode(toMap());
53+
54+
factory ExpUploadStatus.fromJson(String source) =>
55+
ExpUploadStatus.fromMap(json.decode(source) as Map<String, dynamic>);
56+
57+
@override
58+
String toString() =>
59+
'ExpUploadStatus(taskId: $taskId, filename: $filename, progress: $progress)';
60+
61+
@override
62+
bool operator ==(covariant ExpUploadStatus other) {
63+
if (identical(this, other)) return true;
64+
65+
return other.taskId == taskId &&
66+
other.filename == filename &&
67+
other.progress == progress;
68+
}
69+
70+
@override
71+
int get hashCode => taskId.hashCode ^ filename.hashCode ^ progress.hashCode;
72+
}
73+
1474
class ExpBackupState {
1575
final int totalCount;
1676
final int backupCount;
1777
final int remainderCount;
78+
final Map<String, ExpUploadStatus> uploadItems;
1879

1980
ExpBackupState({
2081
required this.totalCount,
2182
required this.backupCount,
2283
required this.remainderCount,
84+
required this.uploadItems,
2385
});
2486

2587
ExpBackupState copyWith({
2688
int? totalCount,
2789
int? backupCount,
2890
int? remainderCount,
91+
Map<String, ExpUploadStatus>? uploadItems,
2992
}) {
3093
return ExpBackupState(
3194
totalCount: totalCount ?? this.totalCount,
3295
backupCount: backupCount ?? this.backupCount,
3396
remainderCount: remainderCount ?? this.remainderCount,
97+
uploadItems: uploadItems ?? this.uploadItems,
3498
);
3599
}
36100

@@ -39,6 +103,7 @@ class ExpBackupState {
39103
'totalCount': totalCount,
40104
'backupCount': backupCount,
41105
'remainderCount': remainderCount,
106+
'uploadItems': uploadItems,
42107
};
43108
}
44109

@@ -47,6 +112,14 @@ class ExpBackupState {
47112
totalCount: map['totalCount'] as int,
48113
backupCount: map['backupCount'] as int,
49114
remainderCount: map['remainderCount'] as int,
115+
uploadItems: Map<String, ExpUploadStatus>.from(
116+
(map['uploadItems'] as Map<String, dynamic>).map(
117+
(key, value) => MapEntry(
118+
key,
119+
ExpUploadStatus.fromMap(value as Map<String, dynamic>),
120+
),
121+
),
122+
),
50123
);
51124
}
52125

@@ -56,21 +129,28 @@ class ExpBackupState {
56129
ExpBackupState.fromMap(json.decode(source) as Map<String, dynamic>);
57130

58131
@override
59-
String toString() =>
60-
'ExpBackupState(totalCount: $totalCount, backupCount: $backupCount, remainderCount: $remainderCount)';
132+
String toString() {
133+
return 'ExpBackupState(totalCount: $totalCount, backupCount: $backupCount, remainderCount: $remainderCount, uploadItems: $uploadItems)';
134+
}
61135

62136
@override
63137
bool operator ==(covariant ExpBackupState other) {
64138
if (identical(this, other)) return true;
139+
final mapEquals = const DeepCollectionEquality().equals;
65140

66141
return other.totalCount == totalCount &&
67142
other.backupCount == backupCount &&
68-
other.remainderCount == remainderCount;
143+
other.remainderCount == remainderCount &&
144+
mapEquals(other.uploadItems, uploadItems);
69145
}
70146

71147
@override
72-
int get hashCode =>
73-
totalCount.hashCode ^ backupCount.hashCode ^ remainderCount.hashCode;
148+
int get hashCode {
149+
return totalCount.hashCode ^
150+
backupCount.hashCode ^
151+
remainderCount.hashCode ^
152+
uploadItems.hashCode;
153+
}
74154
}
75155

76156
final expBackupProvider =
@@ -92,6 +172,7 @@ class ExpBackupNotifier extends StateNotifier<ExpBackupState> {
92172
totalCount: 0,
93173
backupCount: 0,
94174
remainderCount: 0,
175+
uploadItems: {},
95176
),
96177
) {
97178
{
@@ -120,8 +201,6 @@ class ExpBackupNotifier extends StateNotifier<ExpBackupState> {
120201
remainderCount: state.remainderCount - 1,
121202
);
122203

123-
// TODO: find a better place to call this.
124-
_backgroundSyncManager.syncRemote();
125204
break;
126205

127206
default:
@@ -130,10 +209,30 @@ class ExpBackupNotifier extends StateNotifier<ExpBackupState> {
130209
}
131210

132211
void _taskProgressCallback(TaskProgressUpdate update) {
133-
debugPrint("[_taskProgressCallback] $update");
212+
final uploadStatus = ExpUploadStatus(
213+
taskId: update.task.taskId,
214+
filename: update.task.displayName,
215+
progress: update.progress,
216+
);
217+
218+
state = state.copyWith(
219+
uploadItems: {
220+
for (final entry in state.uploadItems.entries)
221+
if (entry.key == update.task.taskId)
222+
entry.key: uploadStatus
223+
else
224+
entry.key: entry.value,
225+
if (!state.uploadItems.containsKey(update.task.taskId))
226+
update.task.taskId: uploadStatus,
227+
},
228+
);
229+
230+
print(update.task.taskId);
134231
}
135232

136233
Future<void> getBackupStatus() async {
234+
await _backgroundSyncManager.syncRemote();
235+
137236
final [totalCount, backupCount, remainderCount] = await Future.wait([
138237
_backupService.getTotalCount(),
139238
_backupService.getBackupCount(),
@@ -152,7 +251,6 @@ class ExpBackupNotifier extends StateNotifier<ExpBackupState> {
152251
}
153252

154253
Future<void> cancel() async {
155-
await _uploadService.cancel();
156-
debugPrint("Cancel uploads");
254+
await _backupService.cancel();
157255
}
158256
}

mobile/lib/services/exp_backup.service.dart

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ class ExpBackupService {
2626
final IBackupRepository _backupRepository;
2727
final IStorageRepository _storageRepository;
2828
final UploadService _uploadService;
29+
bool shouldCancel = false;
2930

3031
Future<int> getTotalCount() {
3132
return _backupRepository.getTotalCount();
@@ -40,13 +41,19 @@ class ExpBackupService {
4041
}
4142

4243
Future<void> backup() async {
44+
shouldCancel = false;
45+
4346
final candidates = await _backupRepository.getCandidates();
4447
if (candidates.isEmpty) {
4548
return;
4649
}
4750

4851
const batchSize = 5;
4952
for (int i = 0; i < candidates.length; i += batchSize) {
53+
if (shouldCancel) {
54+
break;
55+
}
56+
5057
final batch = candidates.skip(i).take(batchSize).toList();
5158

5259
List<UploadTask> tasks = [];
@@ -57,7 +64,7 @@ class ExpBackupService {
5764
}
5865
}
5966

60-
if (tasks.isNotEmpty) {
67+
if (tasks.isNotEmpty && !shouldCancel) {
6168
_uploadService.enqueueTasks(tasks);
6269
}
6370
}
@@ -82,6 +89,7 @@ class ExpBackupService {
8289
}
8390

8491
Future<void> cancel() async {
92+
shouldCancel = true;
8593
await _uploadService.cancel();
8694
}
8795
}

mobile/lib/services/upload.service.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ class UploadService {
108108

109109
return UploadTask(
110110
taskId: id,
111-
displayName: filename,
111+
displayName: originalFileName ?? filename,
112112
httpRequestMethod: 'POST',
113113
url: url,
114114
headers: headers,

mobile/lib/widgets/backup/current_backup_asset_info_box.dart

Lines changed: 37 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,43 +2,53 @@ import 'dart:io';
22

33
import 'package:easy_localization/easy_localization.dart';
44
import 'package:flutter/material.dart';
5+
import 'package:hooks_riverpod/hooks_riverpod.dart';
56
import 'package:immich_mobile/extensions/build_context_extensions.dart';
7+
import 'package:immich_mobile/providers/backup/exp_backup.provider.dart';
68
import 'package:immich_mobile/widgets/backup/asset_info_table.dart';
79
import 'package:immich_mobile/widgets/backup/error_chip.dart';
810
import 'package:immich_mobile/widgets/backup/icloud_download_progress_bar.dart';
911
import 'package:immich_mobile/widgets/backup/upload_progress_bar.dart';
1012
import 'package:immich_mobile/widgets/backup/upload_stats.dart';
1113

12-
class CurrentUploadingAssetInfoBox extends StatelessWidget {
14+
class CurrentUploadingAssetInfoBox extends ConsumerWidget {
1315
const CurrentUploadingAssetInfoBox({super.key});
1416

1517
@override
16-
Widget build(BuildContext context) {
17-
return ListTile(
18-
isThreeLine: true,
19-
leading: Icon(
20-
Icons.image_outlined,
21-
color: context.primaryColor,
22-
size: 30,
23-
),
24-
title: Row(
25-
mainAxisAlignment: MainAxisAlignment.spaceBetween,
26-
children: [
27-
Text(
28-
"backup_controller_page_uploading_file_info",
29-
style: context.textTheme.titleSmall,
30-
).tr(),
31-
const BackupErrorChip(),
32-
],
33-
),
34-
subtitle: Column(
35-
children: [
36-
if (Platform.isIOS) const IcloudDownloadProgressBar(),
37-
const BackupUploadProgressBar(),
38-
const BackupUploadStats(),
39-
const BackupAssetInfoTable(),
40-
],
41-
),
18+
Widget build(BuildContext context, WidgetRef ref) {
19+
final uploadItems =
20+
ref.watch(expBackupProvider.select((state) => state.uploadItems));
21+
22+
return Column(
23+
children: [
24+
if (uploadItems.isNotEmpty)
25+
Container(
26+
constraints: const BoxConstraints(maxHeight: 200),
27+
child: ListView.builder(
28+
shrinkWrap: true,
29+
itemCount: uploadItems.length,
30+
itemBuilder: (context, index) {
31+
final uploadItem = uploadItems.values.elementAt(index);
32+
return ListTile(
33+
dense: true,
34+
leading: CircularProgressIndicator(
35+
value: uploadItem.progress,
36+
strokeWidth: 2,
37+
),
38+
title: Text(
39+
uploadItem.filename,
40+
style: context.textTheme.bodySmall,
41+
overflow: TextOverflow.ellipsis,
42+
),
43+
trailing: Text(
44+
'${(uploadItem.progress * 100).toInt()}%',
45+
style: context.textTheme.bodySmall,
46+
),
47+
);
48+
},
49+
),
50+
),
51+
],
4252
);
4353
}
4454
}

server/src/middleware/file-upload.interceptor.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -103,10 +103,6 @@ export class FileUploadInterceptor implements NestInterceptor {
103103
}
104104

105105
private filename(request: AuthRequest, file: Express.Multer.File, callback: DiskStorageCallback) {
106-
console.log(
107-
'FileUploadInterceptor.filename called with file:',
108-
this.assetService.getUploadFilename(asRequest(request, file)),
109-
);
110106
return callbackify(
111107
() => this.assetService.getUploadFilename(asRequest(request, file)),
112108
callback as Callback<string>,

0 commit comments

Comments
 (0)