Skip to content

Commit

Permalink
(WIP): skip success uploads
Browse files Browse the repository at this point in the history
  • Loading branch information
thiagocarvalhodev committed May 8, 2024
1 parent b3a441e commit 4b98d59
Show file tree
Hide file tree
Showing 4 changed files with 160 additions and 47 deletions.
2 changes: 1 addition & 1 deletion lib/blocs/upload/enums/conflicting_files_actions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
/// `Skip` Will ignore the files and don't upload them.
///
/// `Replace` will upload the conflicting file and replace the existent.
enum UploadActions { skip, replace }
enum UploadActions { skip, skipSuccessfullyUploads, replace }
54 changes: 53 additions & 1 deletion lib/blocs/upload/upload_cubit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ class UploadCubit extends Cubit<UploadState> {
/// Map of conflicting file ids keyed by their file names.
final Map<String, String> conflictingFiles = {};
final List<String> conflictingFolders = [];
List<String> failedFiles = [];

UploadCubit({
required this.driveId,
Expand Down Expand Up @@ -301,7 +302,9 @@ class UploadCubit extends Cubit<UploadState> {
checkConflicts();
}

Future<void> checkConflictingFiles() async {
Future<void> checkConflictingFiles({
bool checkFailedFiles = true,
}) async {
emit(UploadPreparationInProgress());

_removeFilesWithFolderNameConflicts();
Expand All @@ -322,11 +325,52 @@ class UploadCubit extends Cubit<UploadState> {
conflictingFiles[file.getIdentifier()] = existingFileId;
}
}

if (conflictingFiles.isNotEmpty) {
if (checkFailedFiles) {
failedFiles.clear();

conflictingFiles.forEach((key, value) {
logger.d('Checking if file $key has failed');
});

for (final fileNameKey in conflictingFiles.keys) {
final fileId = conflictingFiles[fileNameKey];

final fileRevision = await _driveDao
.latestFileRevisionByFileId(
driveId: driveId,
fileId: fileId!,
)
.getSingleOrNull();

final status = _driveDao.select(_driveDao.networkTransactions)
..where((tbl) => tbl.id.equals(fileRevision!.metadataTxId));

final transaction = await status.getSingleOrNull();

if (transaction?.status == 'pending') {
failedFiles.add(fileNameKey);
}
}

if (failedFiles.isNotEmpty) {
emit(
UploadConflictWithFailedFiles(
areAllFilesConflicting: conflictingFiles.length == files.length,
conflictingFileNames: conflictingFiles.keys.toList(),
conflictingFileNamesForFailedFiles: failedFiles,
),
);
return;
}
}

emit(
UploadFileConflict(
areAllFilesConflicting: conflictingFiles.length == files.length,
conflictingFileNames: conflictingFiles.keys.toList(),
conflictingFileNamesForFailedFiles: const [],
),
);
} else {
Expand Down Expand Up @@ -408,6 +452,8 @@ class UploadCubit extends Cubit<UploadState> {

if (uploadAction == UploadActions.skip) {
_removeFilesWithFileNameConflicts();
} else if (uploadAction == UploadActions.skipSuccessfullyUploads) {
_removeSuccessfullyUploadedFiles();
}

logger.d(
Expand Down Expand Up @@ -919,6 +965,12 @@ class UploadCubit extends Cubit<UploadState> {
);
}

void _removeSuccessfullyUploadedFiles() {
files.removeWhere(
(file) => !failedFiles.contains(file.getIdentifier()),
);
}

void _removeFilesWithFolderNameConflicts() {
files.removeWhere((file) => conflictingFolders.contains(file.ioFile.name));
}
Expand Down
12 changes: 12 additions & 0 deletions lib/blocs/upload/upload_state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -27,21 +27,33 @@ class UploadSigningInProgress extends UploadState {

class UploadFileConflict extends UploadState {
final List<String> conflictingFileNames;
final List<String> conflictingFileNamesForFailedFiles;

final bool areAllFilesConflicting;

UploadFileConflict({
required this.conflictingFileNames,
required this.areAllFilesConflicting,
required this.conflictingFileNamesForFailedFiles,
});

@override
List<Object> get props => [conflictingFileNames];
}

class UploadConflictWithFailedFiles extends UploadFileConflict {
UploadConflictWithFailedFiles({
required super.conflictingFileNames,
required super.areAllFilesConflicting,
super.conflictingFileNamesForFailedFiles = const <String>[],
});
}

class UploadFolderNameConflict extends UploadFileConflict {
UploadFolderNameConflict({
required super.conflictingFileNames,
required super.areAllFilesConflicting,
super.conflictingFileNamesForFailedFiles = const <String>[],
});
}

Expand Down
139 changes: 94 additions & 45 deletions lib/components/upload_form.dart
Original file line number Diff line number Diff line change
Expand Up @@ -287,63 +287,112 @@ class _UploadFormState extends State<UploadForm> {
),
],
);
} else if (state is UploadFileConflict) {
} else if (state is UploadConflictWithFailedFiles) {
return ArDriveStandardModal(
title: appLocalizationsOf(context)
.duplicateFiles(state.conflictingFileNames.length),
content: SizedBox(
width: kMediumDialogWidth,
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
appLocalizationsOf(context)
.filesWithTheSameNameAlreadyExists(
state.conflictingFileNames.length,
title: 'Retry Failed Uploads?',
content: SizedBox(
width: kMediumDialogWidth,
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'There are ${state.conflictingFileNamesForFailedFiles.length} file(s) marked with a red dot, indicating they failed to upload. Would you like to retry uploading these files by replacing the failed versions? This action will only affect the failed uploads and will not alter any successfully uploaded files. Alternatively, you can choose to skip these files and proceed with the others.',
style: ArDriveTypography.body.buttonNormalRegular(),
),
const SizedBox(height: 16),
Text(
'Conflicting files',
style: ArDriveTypography.body.buttonNormalRegular(),
),
const SizedBox(height: 8),
ConstrainedBox(
constraints: const BoxConstraints(maxHeight: 320),
child: SingleChildScrollView(
child: Text(
state.conflictingFileNamesForFailedFiles
.join(', \n'),
style: ArDriveTypography.body.buttonNormalRegular(),
),
style: ArDriveTypography.body.buttonNormalRegular(),
),
const SizedBox(height: 16),
Text(
appLocalizationsOf(context).conflictingFiles,
style: ArDriveTypography.body.buttonNormalRegular(),
),
],
),
),
actions: [
ModalAction(
action: () => context
.read<UploadCubit>()
.checkConflictingFiles(checkFailedFiles: false),
title: appLocalizationsOf(context).skipEmphasized,
),
ModalAction(
action: () => context
.read<UploadCubit>()
.prepareUploadPlanAndCostEstimates(
uploadAction:
UploadActions.skipSuccessfullyUploads),
title: 'Replace failed uploads',
),
],
);
} else if (state is UploadFileConflict) {
return ArDriveStandardModal(
title: appLocalizationsOf(context)
.duplicateFiles(state.conflictingFileNames.length),
content: SizedBox(
width: kMediumDialogWidth,
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
appLocalizationsOf(context)
.filesWithTheSameNameAlreadyExists(
state.conflictingFileNames.length,
),
const SizedBox(height: 8),
ConstrainedBox(
constraints: const BoxConstraints(maxHeight: 320),
child: SingleChildScrollView(
child: Text(
state.conflictingFileNames.join(', \n'),
style:
ArDriveTypography.body.buttonNormalRegular(),
),
style: ArDriveTypography.body.buttonNormalRegular(),
),
const SizedBox(height: 16),
Text(
appLocalizationsOf(context).conflictingFiles,
style: ArDriveTypography.body.buttonNormalRegular(),
),
const SizedBox(height: 8),
ConstrainedBox(
constraints: const BoxConstraints(maxHeight: 320),
child: SingleChildScrollView(
child: Text(
state.conflictingFileNames.join(', \n'),
style: ArDriveTypography.body.buttonNormalRegular(),
),
),
],
),
),
actions: [
if (!state.areAllFilesConflicting)
ModalAction(
action: () => context
.read<UploadCubit>()
.prepareUploadPlanAndCostEstimates(
uploadAction: UploadActions.skip),
title: appLocalizationsOf(context).skipEmphasized,
),
ModalAction(
action: () => Navigator.of(context).pop(false),
title: appLocalizationsOf(context).cancelEmphasized,
),
],
),
),
actions: [
if (!state.areAllFilesConflicting)
ModalAction(
action: () => context
.read<UploadCubit>()
.prepareUploadPlanAndCostEstimates(
uploadAction: UploadActions.replace),
title: appLocalizationsOf(context).replaceEmphasized,
uploadAction: UploadActions.skip),
title: appLocalizationsOf(context).skipEmphasized,
),
]);
ModalAction(
action: () => Navigator.of(context).pop(false),
title: appLocalizationsOf(context).cancelEmphasized,
),
ModalAction(
action: () => context
.read<UploadCubit>()
.prepareUploadPlanAndCostEstimates(
uploadAction: UploadActions.replace),
title: appLocalizationsOf(context).replaceEmphasized,
),
],
);
} else if (state is UploadFileTooLarge) {
return ArDriveStandardModal(
title: appLocalizationsOf(context)
Expand Down

0 comments on commit 4b98d59

Please sign in to comment.