diff --git a/.changeset/tasty-plums-carry.md b/.changeset/tasty-plums-carry.md new file mode 100644 index 00000000..0bca6b70 --- /dev/null +++ b/.changeset/tasty-plums-carry.md @@ -0,0 +1,5 @@ +--- +"@react-native-documents/picker": patch +--- + +refactor(ios): simplify file moves diff --git a/packages/document-picker/ios/swift/DocPicker.swift b/packages/document-picker/ios/swift/DocPicker.swift index 33fa0882..1964b191 100644 --- a/packages/document-picker/ios/swift/DocPicker.swift +++ b/packages/document-picker/ios/swift/DocPicker.swift @@ -28,10 +28,10 @@ import MobileCoreServices } public func getMetadataFor(url: URL) throws -> DocumentMetadataBuilder { - if (currentOptions?.isOpenMode() == true) { - return try self.getOpenedDocumentInfo(url: url, requestLongTermAccess: currentOptions?.requestLongTermAccess ?? false) + return if (currentOptions?.isOpenMode() == true) { + try self.getOpenedDocumentInfo(url: url, requestLongTermAccess: currentOptions?.requestLongTermAccess ?? false) } else { - return try self.getAnyModeMetadata(url: url) + try self.getAnyModeMetadata(url: url) } } diff --git a/packages/document-picker/ios/swift/FileOperations.swift b/packages/document-picker/ios/swift/FileOperations.swift index 67d453ba..6f1682ff 100644 --- a/packages/document-picker/ios/swift/FileOperations.swift +++ b/packages/document-picker/ios/swift/FileOperations.swift @@ -4,45 +4,47 @@ import Foundation @objc public class FileOperations: NSObject { - @objc public static func keepLocalCopyAtUniqueDestination(from: Array>, destinationPreset: String, resolve: @escaping RNDPPromiseResolveBlock) { - Task { - let results = await moveFiles(from: from, destinationPreset: destinationPreset) + @objc public static func keepLocalCopyAtUniqueDestination(from: [[String: String]], destinationPreset: String, resolve: @escaping RNDPPromiseResolveBlock) { + DispatchQueue.global(qos: .utility).async { + let results = moveFiles(from: from, destinationPreset: destinationPreset) resolve(results) } } - static func moveFiles(from: Array>, destinationPreset: String) async -> [[String: String?]] { + static func moveFiles(from: [[String: String]], destinationPreset: String) -> [[String: String?]] { let destinationRootDir = getDirectoryForFileDestination(destinationPreset) let uniqueSubDirName = UUID().uuidString - let destinationDir: URL = destinationRootDir.appendingPathComponent("\(uniqueSubDirName)/", isDirectory: true) - // TODO do we need all of this Task dance? + let destinationDir = destinationRootDir.appendingPathComponent(uniqueSubDirName, isDirectory: true) - return await withTaskGroup(of: LocalCopyResponse.self) { group in - var results: Array> = [[String: String?]]() - - for dictionary in from { - group.addTask { - do { - guard let uriString = dictionary["uri"], let uri = URL(string: uriString) else { - return LocalCopyResponse.error(sourceUri: dictionary["uri"], copyError: "Invalid URI") - } - guard let fileName = dictionary["fileName"] else { - return LocalCopyResponse.error(sourceUri: uri.absoluteString, copyError: "Invalid fileName") - } - - let destinationUrl = try moveToDestination(from: uri, usingFilename: fileName, destinationDir: destinationDir) - return LocalCopyResponse.success(sourceUri: uri.absoluteString, localUri: destinationUrl.absoluteString) - } catch { - return LocalCopyResponse.error(sourceUri: dictionary["uri"]!, copyError: error.localizedDescription) - } - } + do { + try FileManager.default.createDirectory(at: destinationDir, withIntermediateDirectories: true, attributes: nil) + } catch { + return from.map { dictionary in + LocalCopyResponse.error(sourceUri: dictionary["uri"], copyError: "Failed to create destination directory: \(error.localizedDescription)").dictionaryRepresentation } - - for await result in group { - results.append(result.dictionaryRepresentation) - } - - return results + } + + // move files + return from.map { dictionary in + moveSingleFile(dictionary: dictionary, destinationDir: destinationDir).dictionaryRepresentation + } + } + + private static func moveSingleFile(dictionary: [String: String], destinationDir: URL) -> LocalCopyResponse { + guard let uriString = dictionary["uri"], + let uri = URL(string: uriString), + let fileName = dictionary["fileName"] else { + return LocalCopyResponse.error( + sourceUri: dictionary["uri"], + copyError: "Invalid URI or fileName" + ) + } + + do { + let destinationUrl = try moveToDestination(from: uri, usingFilename: fileName, destinationDir: destinationDir) + return LocalCopyResponse.success(sourceUri: uri.absoluteString, localUri: destinationUrl.absoluteString) + } catch { + return LocalCopyResponse.error(sourceUri: uriString, copyError: error.localizedDescription) } } @@ -50,19 +52,20 @@ import Foundation let destinationFile = destinationDir.appendingPathComponent(fileName).standardized guard destinationFile.path.hasPrefix(destinationDir.standardized.path) else { - throw NSError(domain: "PathTraversalPrevention", code: 400, userInfo: [NSLocalizedDescriptionKey: "The copied file is attempting to write outside of the target directory."]) + throw NSError( + domain: "PathTraversalPrevention", + code: 400, + userInfo: [NSLocalizedDescriptionKey: "The copied file is attempting to write outside of the target directory."] + ) } - try FileManager.default.createDirectory(at: destinationDir, withIntermediateDirectories: true, attributes: nil) try FileManager.default.moveItem(at: from, to: destinationFile) return destinationFile } static func getDirectoryForFileDestination(_ copyToDirectory: String) -> URL { - if copyToDirectory == "documentDirectory" { - return FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first! - } - return FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first! + let searchPath: FileManager.SearchPathDirectory = copyToDirectory == "documentDirectory" ? .documentDirectory : .cachesDirectory + return FileManager.default.urls(for: searchPath, in: .userDomainMask).first! } } diff --git a/packages/document-picker/ios/swift/IsKnownTypeImpl.swift b/packages/document-picker/ios/swift/IsKnownTypeImpl.swift index 703bb878..871525c4 100644 --- a/packages/document-picker/ios/swift/IsKnownTypeImpl.swift +++ b/packages/document-picker/ios/swift/IsKnownTypeImpl.swift @@ -28,14 +28,10 @@ import UniformTypeIdentifiers static func createUTType(kind: String, value: String) -> UTType? { switch kind { - case "UTType": - return UTType(value) - case "mimeType": - return UTType(mimeType: value) - case "extension": - return UTType(filenameExtension: value) - default: - return nil + case "UTType": UTType(value) + case "mimeType": UTType(mimeType: value) + case "extension": UTType(filenameExtension: value) + default: nil } } }