Swift Drag and Drop Mail on OS X 10.13
Asked Answered
H

0

7

I have had dragging and dropping working for Mail working for a while now. That was until I upgraded to OSX 10.13.

Here is my code:

class DropView: NSView
{
    var filePath: String?

    required init?(coder: NSCoder) {
        super.init(coder: coder)

        self.wantsLayer = true
        self.layer?.backgroundColor = NSColor.red.cgColor

        registerForDraggedTypes([NSPasteboard.PasteboardType
            .fileNameType(forPathExtension: ".eml"), NSPasteboard.PasteboardType.filePromise])
    }

    override func draggingEntered(_ sender: NSDraggingInfo) -> NSDragOperation {
        if true
        {
            self.layer?.backgroundColor = NSColor.blue.cgColor
            return .copy
        }
    }

     override func draggingExited(_ sender: NSDraggingInfo?)
    {
        self.layer?.backgroundColor = NSColor.red.cgColor
    }

    override func draggingEnded(_ sender: NSDraggingInfo)
    {
        self.layer?.backgroundColor = NSColor.gray.cgColor
    }

    override func performDragOperation(_ sender: NSDraggingInfo) -> Bool
    {
        let pasteboard: NSPasteboard = sender.draggingPasteboard()

        let filePromises = pasteboard.readObjects(forClasses: [NSFilePromiseReceiver.self], options: nil) as? [NSFilePromiseReceiver]

        let folderPath = NSHomeDirectory()+"/Drop Stuff/"
        if (!FileManager.default.fileExists(atPath: folderPath))
        {
            do
            {
                try FileManager.default.createDirectory(atPath: folderPath, withIntermediateDirectories: true, attributes: nil)
            }
            catch
            {
                print ("error")
            }
        }

        let folderURL = NSURL(fileURLWithPath: folderPath)
        let f = sender.namesOfPromisedFilesDropped(atDestination: folderURL as URL)
        print (f!)
        print ("Copied to \(folderPath)")
        return true
    }
}

The problem is that namesOfPromisedFilesDropped is returning the name of the parent folder not the name of the file as it did on previous version of the OS.

The compiler warns that namesOfPromisedFilesDropped is deprecated. Good job Apple for not providing any documentation on the new stuff. Thanks to StackOverflow I managed to piece this together which works using the new APIs, but still exhibits the same problem as above.

class DropView2: NSView
{
    var filePath: String?

    required init?(coder: NSCoder) {
        super.init(coder: coder)

        self.wantsLayer = true
        self.layer?.backgroundColor = NSColor.red.cgColor

        registerForDraggedTypes([NSPasteboard.PasteboardType
            .fileNameType(forPathExtension: ".eml"), NSPasteboard.PasteboardType.filePromise])
    }

    override func draggingEntered(_ sender: NSDraggingInfo) -> NSDragOperation {
        if true
        {
            self.layer?.backgroundColor = NSColor.blue.cgColor
            return .copy
        }
    }

    override func draggingExited(_ sender: NSDraggingInfo?)
    {
        self.layer?.backgroundColor = NSColor.red.cgColor
    }

    override func draggingEnded(_ sender: NSDraggingInfo)
    {
        self.layer?.backgroundColor = NSColor.gray.cgColor
    }

    override func performDragOperation(_ sender: NSDraggingInfo) -> Bool
    {

        let pasteboard: NSPasteboard = sender.draggingPasteboard()

        guard let filePromises = pasteboard.readObjects(forClasses: [NSFilePromiseReceiver.self], options: nil) as? [NSFilePromiseReceiver] else {
            return false
        }

        print ("Files dropped")
        var files = [URL]()

        let filePromiseGroup = DispatchGroup()
        let operationQueue = OperationQueue()
        let destURL = URL(fileURLWithPath: "/Users/andrew/Temporary", isDirectory: true)
        print ("Destination URL: \(destURL)")

        filePromises.forEach ({ filePromiseReceiver in
            print (filePromiseReceiver)
            filePromiseGroup.enter()

            filePromiseReceiver.receivePromisedFiles(atDestination: destURL,
                                                     options: [:],
                                                     operationQueue: operationQueue,
                                                     reader:
                { (url, error) in
                    print ("Received URL: \(url)")
                    if let error = error
                    {
                        print ("Error: \(error)")
                    }
                    else
                    {
                        files.append(url)
                    }
                    print (filePromiseReceiver.fileNames, filePromiseReceiver.fileTypes)

                    filePromiseGroup.leave()
            })
        })

        filePromiseGroup.notify(queue: DispatchQueue.main,
                                execute:
            {
                print ("Files: \(files)")
                print ("Done")
        })
        return true
    }
}

I'm using 10.13.2. Am I doing something wrong or is this a bug?

It's driving me nuts.

Halfprice answered 29/1, 2018 at 3:52 Comment(1)
Were you ever able to find a solution to this? I have a similar issue where I'm trying to drag an image from me view. to an app icon like preview. But the filePromiseProvider writePromiseTo does not work as namesOfPromisedFilesDropped used to. And the drag is unsuccessful. Also, I used to drag directly into a notebook in evernote but this also no longer works and I can't find assistance anywhere on this issue. Thanks a lotBackhouse

© 2022 - 2024 — McMap. All rights reserved.