mirror of
https://github.com/immich-app/immich.git
synced 2025-07-31 15:08:44 -04:00
chore: handle requeue upload when target albums changed (#20089)
* chore: handle requeue upload when target albums changed * chore: remove debug
This commit is contained in:
parent
f1cac122ed
commit
1011cdb376
@ -1330,6 +1330,7 @@
|
||||
"no_results": "No results",
|
||||
"no_results_description": "Try a synonym or more general keyword",
|
||||
"no_shared_albums_message": "Create an album to share photos and videos with people in your network",
|
||||
"no_uploads_in_progress": "No uploads in progress",
|
||||
"not_in_any_album": "Not in any album",
|
||||
"not_selected": "Not selected",
|
||||
"note_apply_storage_label_to_previously_uploaded assets": "Note: To apply the Storage Label to previously uploaded assets, run the",
|
||||
|
@ -44,9 +44,6 @@ class _DriftBackupPageState extends ConsumerState<DriftBackupPage> {
|
||||
(album) => album.backupSelection == BackupSelection.selected,
|
||||
)
|
||||
.toList();
|
||||
final uploadItems = ref.watch(
|
||||
driftBackupProvider.select((state) => state.uploadItems),
|
||||
);
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
@ -85,7 +82,6 @@ class _DriftBackupPageState extends ConsumerState<DriftBackupPage> {
|
||||
onStart: () async => await startBackup(),
|
||||
onStop: () async => await stopBackup(),
|
||||
),
|
||||
if (uploadItems.isNotEmpty)
|
||||
TextButton.icon(
|
||||
icon: const Icon(Icons.info_outline_rounded),
|
||||
onPressed: () => context.pushRoute(
|
||||
|
@ -9,6 +9,7 @@ import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||
import 'package:immich_mobile/extensions/translate_extensions.dart';
|
||||
import 'package:immich_mobile/providers/album/album.provider.dart';
|
||||
import 'package:immich_mobile/providers/backup/backup_album.provider.dart';
|
||||
import 'package:immich_mobile/providers/backup/drift_backup.provider.dart';
|
||||
import 'package:immich_mobile/services/app_settings.service.dart';
|
||||
import 'package:immich_mobile/providers/app_settings.provider.dart';
|
||||
import 'package:immich_mobile/widgets/backup/drift_album_info_list_tile.dart';
|
||||
@ -28,6 +29,8 @@ class _DriftBackupAlbumSelectionPageState
|
||||
extends ConsumerState<DriftBackupAlbumSelectionPage> {
|
||||
String _searchQuery = '';
|
||||
bool _isSearchMode = false;
|
||||
int _initialTotalAssetCount = 0;
|
||||
bool _hasPopped = false;
|
||||
late ValueNotifier<bool> _enableSyncUploadAlbum;
|
||||
late TextEditingController _searchController;
|
||||
late FocusNode _searchFocusNode;
|
||||
@ -43,6 +46,9 @@ class _DriftBackupAlbumSelectionPageState
|
||||
.read(appSettingsServiceProvider)
|
||||
.getSetting(AppSettingsEnum.syncAlbums);
|
||||
ref.read(backupAlbumProvider.notifier).getAll();
|
||||
|
||||
_initialTotalAssetCount =
|
||||
ref.read(driftBackupProvider.select((p) => p.totalCount));
|
||||
}
|
||||
|
||||
@override
|
||||
@ -79,10 +85,37 @@ class _DriftBackupAlbumSelectionPageState
|
||||
}
|
||||
}
|
||||
|
||||
return Scaffold(
|
||||
return PopScope(
|
||||
onPopInvokedWithResult: (didPop, result) async {
|
||||
// There is an issue with Flutter where the pop event
|
||||
// can be triggered multiple times, so we guard it with _hasPopped
|
||||
if (didPop && !_hasPopped) {
|
||||
_hasPopped = true;
|
||||
|
||||
await ref.read(driftBackupProvider.notifier).getBackupStatus();
|
||||
final currentTotalAssetCount =
|
||||
ref.read(driftBackupProvider.select((p) => p.totalCount));
|
||||
|
||||
if (currentTotalAssetCount != _initialTotalAssetCount) {
|
||||
final isBackupEnabled = ref
|
||||
.read(appSettingsServiceProvider)
|
||||
.getSetting(AppSettingsEnum.enableBackup);
|
||||
|
||||
if (!isBackupEnabled) {
|
||||
return;
|
||||
}
|
||||
final backupNotifier = ref.read(driftBackupProvider.notifier);
|
||||
|
||||
backupNotifier.cancel().then((_) {
|
||||
backupNotifier.backup();
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
leading: IconButton(
|
||||
onPressed: () => context.maybePop(),
|
||||
onPressed: () async => await context.maybePop(),
|
||||
icon: const Icon(Icons.arrow_back_ios_rounded),
|
||||
),
|
||||
title: _isSearchMode
|
||||
@ -154,8 +187,8 @@ class _DriftBackupAlbumSelectionPageState
|
||||
SettingsSwitchListTile(
|
||||
valueNotifier: _enableSyncUploadAlbum,
|
||||
title: "sync_albums".t(context: context),
|
||||
subtitle:
|
||||
"sync_upload_album_setting_subtitle".t(context: context),
|
||||
subtitle: "sync_upload_album_setting_subtitle"
|
||||
.t(context: context),
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
titleStyle: context.textTheme.bodyLarge?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
@ -253,6 +286,7 @@ class _DriftBackupAlbumSelectionPageState
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ class DriftUploadDetailPage extends ConsumerWidget {
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.cloud_upload_outlined,
|
||||
Icons.cloud_off_rounded,
|
||||
size: 80,
|
||||
color: context.colorScheme.onSurface.withValues(alpha: 0.3),
|
||||
),
|
||||
@ -79,7 +79,9 @@ class DriftUploadDetailPage extends ConsumerWidget {
|
||||
|
||||
return Card(
|
||||
elevation: 0,
|
||||
color: context.colorScheme.surfaceContainer,
|
||||
color: item.isFailed != null
|
||||
? context.colorScheme.errorContainer
|
||||
: context.colorScheme.surfaceContainer,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: const BorderRadius.all(
|
||||
Radius.circular(16),
|
||||
|
@ -41,6 +41,7 @@ class DriftUploadStatus {
|
||||
final double progress;
|
||||
final int fileSize;
|
||||
final String networkSpeedAsString;
|
||||
final bool? isFailed;
|
||||
|
||||
const DriftUploadStatus({
|
||||
required this.taskId,
|
||||
@ -48,6 +49,7 @@ class DriftUploadStatus {
|
||||
required this.progress,
|
||||
required this.fileSize,
|
||||
required this.networkSpeedAsString,
|
||||
this.isFailed,
|
||||
});
|
||||
|
||||
DriftUploadStatus copyWith({
|
||||
@ -56,6 +58,7 @@ class DriftUploadStatus {
|
||||
double? progress,
|
||||
int? fileSize,
|
||||
String? networkSpeedAsString,
|
||||
bool? isFailed,
|
||||
}) {
|
||||
return DriftUploadStatus(
|
||||
taskId: taskId ?? this.taskId,
|
||||
@ -63,12 +66,13 @@ class DriftUploadStatus {
|
||||
progress: progress ?? this.progress,
|
||||
fileSize: fileSize ?? this.fileSize,
|
||||
networkSpeedAsString: networkSpeedAsString ?? this.networkSpeedAsString,
|
||||
isFailed: isFailed ?? this.isFailed,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'DriftUploadStatus(taskId: $taskId, filename: $filename, progress: $progress, fileSize: $fileSize, networkSpeedAsString: $networkSpeedAsString)';
|
||||
return 'DriftUploadStatus(taskId: $taskId, filename: $filename, progress: $progress, fileSize: $fileSize, networkSpeedAsString: $networkSpeedAsString, isFailed: $isFailed)';
|
||||
}
|
||||
|
||||
@override
|
||||
@ -79,7 +83,8 @@ class DriftUploadStatus {
|
||||
other.filename == filename &&
|
||||
other.progress == progress &&
|
||||
other.fileSize == fileSize &&
|
||||
other.networkSpeedAsString == networkSpeedAsString;
|
||||
other.networkSpeedAsString == networkSpeedAsString &&
|
||||
other.isFailed == isFailed;
|
||||
}
|
||||
|
||||
@override
|
||||
@ -88,7 +93,8 @@ class DriftUploadStatus {
|
||||
filename.hashCode ^
|
||||
progress.hashCode ^
|
||||
fileSize.hashCode ^
|
||||
networkSpeedAsString.hashCode;
|
||||
networkSpeedAsString.hashCode ^
|
||||
isFailed.hashCode;
|
||||
}
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
@ -98,6 +104,7 @@ class DriftUploadStatus {
|
||||
'progress': progress,
|
||||
'fileSize': fileSize,
|
||||
'networkSpeedAsString': networkSpeedAsString,
|
||||
'isFailed': isFailed,
|
||||
};
|
||||
}
|
||||
|
||||
@ -108,6 +115,7 @@ class DriftUploadStatus {
|
||||
progress: map['progress'] as double,
|
||||
fileSize: map['fileSize'] as int,
|
||||
networkSpeedAsString: map['networkSpeedAsString'] as String,
|
||||
isFailed: map['isFailed'] != null ? map['isFailed'] as bool : null,
|
||||
);
|
||||
}
|
||||
|
||||
@ -235,6 +243,8 @@ class ExpBackupNotifier extends StateNotifier<DriftBackupState> {
|
||||
}
|
||||
|
||||
void _handleTaskStatusUpdate(TaskStatusUpdate update) {
|
||||
final taskId = update.task.taskId;
|
||||
|
||||
switch (update.status) {
|
||||
case TaskStatus.complete:
|
||||
if (update.task.group == kBackupGroup) {
|
||||
@ -245,14 +255,26 @@ class ExpBackupNotifier extends StateNotifier<DriftBackupState> {
|
||||
}
|
||||
|
||||
// Remove the completed task from the upload items
|
||||
final taskId = update.task.taskId;
|
||||
if (state.uploadItems.containsKey(taskId)) {
|
||||
Future.delayed(const Duration(milliseconds: 500), () {
|
||||
Future.delayed(const Duration(milliseconds: 1000), () {
|
||||
_removeUploadItem(taskId);
|
||||
});
|
||||
}
|
||||
|
||||
case TaskStatus.failed:
|
||||
final currentItem = state.uploadItems[taskId];
|
||||
if (currentItem == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
state = state.copyWith(
|
||||
uploadItems: {
|
||||
...state.uploadItems,
|
||||
taskId: currentItem.copyWith(
|
||||
isFailed: true,
|
||||
),
|
||||
},
|
||||
);
|
||||
break;
|
||||
|
||||
case TaskStatus.canceled:
|
||||
|
Loading…
x
Reference in New Issue
Block a user