Trying to implement a simple drag-drop of a text file:
struct ContentView: View {
@State private var drag = false
var body: some View {
Text("Hello, world!")
.frame(width: 300, height: 300)
.onDrop(of: [.url], isTargeted: $drag) { (providers, location) in
print("Can load", providers.first?.canLoadObject(ofClass: NSURL.self) == true) // Always false
providers.first?.loadItem(forTypeIdentifier: UTType.url.identifier, options: nil, completionHandler: { secureCoding, error in
if let error = error {
print(error) // Cannot load representation of type ...
}
if let item = secureCoding as? Data { // Always nil
print("got data")
}
})
return true
}
}
}
Tried to play with both the UTType of the file dropped (public.url,public.data) and the loadItem(forTypeIdentifier)
.
Nothing I tried worked. Found similar questions, but they're not working and the answers looks out dated.
I have old Cocoa code, with registerForDraggedTypes
, this looks much simpler, if it worked..
CodePudding user response:
Just modified and tested with plain .txt file. Xcode 13.3 / macOS 12.3.1
@State private var text = "Drop Here"
var body: some View {
Text(text)
.frame(width: 200, height: 200).border(.red)
.onDrop(of: ["public.file-url"], isTargeted: $dragOver) { providers -> Bool in
providers.first?.loadDataRepresentation(forTypeIdentifier: "public.file-url", completionHandler: { (data, error) in
if let data = data, let path = NSString(data: data, encoding: 4), let url = URL(string: path as String) {
if let value = try? String(contentsOf: url, encoding: .utf8) {
DispatchQueue.main.async {
self.text = value
}
}
}
})
return true
}
*Note: I cannot remember exactly where but I met in Apple's documentation that we must use concrete UTTypes for specific use-cases instead of generic, ie. fileURL is really URL but for matching it must be specified exactly!
CodePudding user response:
I wanted to post my own answer, just to point out the pitfalls. Thanks to @Asperi, I got a working sample.
.onDrop(of: [.fileURL]
, needs to beUTType.fileURL
(orpublic.file-url
), notUTType.url
.- I was using
providers.first?.loadItem(forTypeIdentifier:...
, needs to beloadDataRepresentation(forTypeIdentifier:...
- Reading the data:
Usinglet path = String(data: data, encoding: .utf8)
works. The next step is important, I needed to useURL(string:)
. notURL(fileURLWithPath:)
UsingURL(fileURLWithPath:)
will produce something that looks like URL with secure scope.
Other minor notes:
Using let path = String(data: data, encoding: .utf8)
works, no need for NNString
.
Using UTType.fileURL
(and UTType.fileURL.identifier
for String
) also works, no need for hard coding "public.file-url"