SwiftUI on macOS: Drag and drop, Source Code

This is the Swift source code to accompany the article SwiftUI on macOS: Drag and drop, and more.

App

import SwiftUI

@main
struct DroperaApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
        
        Window("Help Window", id: "help") {
            HelpView()
        }
        
        .commands {
            HelpCommands()
        }
    }
}

Menu Commands

import SwiftUI

struct HelpCommands: Commands {
    @Environment(\.openWindow) var openWindow

    var body: some Commands {
        CommandGroup(replacing: .help) {
            Button("Dropera Help", action: showHelpWindow)
        }
    }
    
    func showHelpWindow() {
        openWindow(id: "help")
    }
}

Content View

import SwiftUI

struct ContentView: View {
    @State private var fileInfo: [String] = []
    
    var body: some View {
        let dropDelegate = DroperaDropDelegate(fileInfo: $fileInfo)
        
        ScrollView {
            Text(fileInfo.joined(separator: "\n\n"))
        }
        
        .frame(minWidth: 600, minHeight: 200, alignment: .center)
        .onDrop(of: ["public.file-url"], delegate: dropDelegate)
        
        .background(alignment: .center) {
            if fileInfo.isEmpty {
                Image(systemName: "doc.badge.plus")
                    .resizable()
                    .frame(width: 150.0, height: 150.0)
                    .symbolRenderingMode(.multicolor)
            }
        }
    }
}

#Preview {
    ContentView()
}

Drop Delegate

import SwiftUI

struct DroperaDropDelegate: DropDelegate {
    @Binding var fileInfo: [String]
    
    func validateDrop(info: DropInfo) -> Bool {
        return info.hasItemsConforming(to: ["public.file-url"])
    }

/*
    func dropEntered(info: DropInfo) {
        NSSound(named: "Tink")?.play()
    }
*/
    
    func performDrop(info: DropInfo) -> Bool {
//        NSSound(named: "Sosumi")?.play()
        fileInfo = []
        var gotFile = false
        for itemProvider in info.itemProviders(for: ["public.file-url"]) {
            itemProvider.loadItem(forTypeIdentifier: "public.file-url", options: nil) { (item, error) in
                if let data = item as? Data {
                    if let url = URL(dataRepresentation: data, relativeTo: nil) {
                        let theInfo = "File: " + url.lastPathComponent + "\nPath: " + url.path + "\n"
                        let theSizes = FileInfo().reportSizes(url: url)
                        DispatchQueue.main.async {
                            fileInfo.append(theInfo + theSizes)
                            gotFile = true
                        }
                    }
                }
            }
        }
        return gotFile
    }
    
/*    
    func dropUpdated(info: DropInfo) -> DropProposal? {
        return nil
    }
    
    func dropExited(info: DropInfo) {
        
    }
*/
    
}

Help View

import SwiftUI

struct HelpView: View {

    var text: AttributedString {
        var text = AttributedString("empty")
        let strUrl = Bundle.main.url(forResource: "Help", withExtension: "rtf")!
        if let data = try? Data(contentsOf: strUrl) {
            if let contents = NSAttributedString(rtf: data, documentAttributes: nil) {
                text = AttributedString(contents)
            }
        }
        return text
    }
    
    var body: some View {
        ScrollView {
            Text(text)
        }
    }
}

#Preview {
    HelpView()
}

End of code supplement.