downloadFile method
Downloads a file from a remotePath
to a localPath
on the device.
Implementation
@override
Future<String> downloadFile({
required String remotePath,
required String localPath,
}) async {
final completer = Completer<String>();
StreamSubscription? progressSubscription;
try {
await _icloudSync.download(
containerId: _containerId,
relativePath: _sanitizePath(remotePath),
destinationFilePath: localPath,
onProgress: (stream) {
// This listener is now for in-progress updates and potential mid-stream errors.
progressSubscription = stream.listen(
(progress) {
// You can handle progress updates here if needed.
debugPrint('Download progress: $progress');
},
onError: (error) {
// This handles errors that might occur *during* the download stream.
if (!completer.isCompleted) {
// You can still keep your original checks here as a fallback.
if (error is PlatformException &&
error.toString().contains('NSURLErrorDomain Code=-1009')) {
completer
.completeError(NoConnectionException(error.toString()));
} else if (error
.toString()
.contains('NSCocoaErrorDomain Code=4')) {
completer.completeError(NotFoundException(error.toString()));
} else {
completer.completeError(Exception(
'iCloud download failed during stream: $error'));
}
}
},
onDone: () {
if (!completer.isCompleted) {
completer.complete(localPath);
}
},
cancelOnError: true,
);
},
);
// If the download call completes without an error but the completer is still not done,
// it means we are waiting for the onDone callback from the stream.
} on PlatformException catch (e) {
// **FIX:** Handle initial errors, like "file not found", here.
if (!completer.isCompleted) {
if (e.toString().contains('NSCocoaErrorDomain Code=4')) {
completer.completeError(
NotFoundException('File not found at path: $remotePath'));
} else if (e.toString().contains('NSURLErrorDomain Code=-1009')) {
completer.completeError(NoConnectionException(
'Failed to download from iCloud. Check your internet connection.'));
} else {
completer.completeError(e); // Rethrow other platform exceptions.
}
}
} catch (e) {
// Catch any other general exceptions.
if (!completer.isCompleted) {
completer.completeError(e);
}
}
try {
return await completer.future;
} finally {
// Ensure the subscription is cancelled to prevent memory leaks.
await progressSubscription?.cancel();
}
}