Looking for a sample project (SwiftUI, macOS, standard osx file-dialog

a beginner is looking for a sample project

  • osx (not iOS!)
    -SwiftUI
  • VStack with a TextEditor object and 2 buttons ('open' and 'save', maybe in a HStack)
  • only pure text-files (.txt, .tab, .log, .xml (text-only))

Pressing the 'save' button should show the standard osx file-dialog, letting the user type-in a filename and saving the contents of the TextEditor to disk, location freely choosable

The 'open' button should let the user choose a file somewhere on the disk

I would be so happy to find a sample project!

Thank You very much and kind regards

markus

1 Like

I feel with you. It is sometimes hard to find a small sample for simple tasks.
I hope the code below is helpful. Note that I included alerts on "Cancel" to show how an error message works, too.

import SwiftUI

func openFile() -> URL? {
    func showOpenPanel() -> URL? {
        let openpanel = NSOpenPanel()
        openpanel.title                = "Text öffnen"
        openpanel.isExtensionHidden    = false
        openpanel.canChooseDirectories = false
        openpanel.canChooseFiles       = true
        openpanel.allowedContentTypes  = [.text]
        
        let response = openpanel.runModal()
        return response == .OK ? openpanel.url : nil
    }
    
    return showOpenPanel()
}

func saveFile(appData : String, saveAs : Bool) -> Bool {
    func showSavePanel() -> URL? {
        let savePanel = NSSavePanel()
        savePanel.allowedContentTypes  = [.text]
        savePanel.canCreateDirectories = false
        savePanel.isExtensionHidden    = false
        savePanel.title                = "Speichern"
        savePanel.nameFieldLabel       = "Dateiname:"
        
        let response = savePanel.runModal()
        return response == .OK ? savePanel.url : nil
    }
    
    if let url = showSavePanel() {
        print("Save the file to \(url.debugDescription)")
        return true
    } else {
        return false
    }
}

struct ContentView: View {
    @State private var showOpenErrorAlert : Bool = false
    @State private var showSaveErrorAlert : Bool = false

    var body: some View {
        VStack {
            Text("Open/Save Sample")
                .font(.title)
            Button("Open…") {
                if let url = openFile() {
                    print("Open file \(url.debugDescription)")
                } else {
                    showOpenErrorAlert = true
                }
            }
            Button("Save…") {
                if !saveFile(appData: "Saved content sample string", saveAs: false) {
                    showSaveErrorAlert = true
                }
            }
        }
        .alert("User clicked cancel.", isPresented: $showOpenErrorAlert) {
            Button("OK", role: .cancel) { }
        }
        .alert("User clicked cancel.", isPresented: $showSaveErrorAlert) {
            Button("OK", role: .cancel) { }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
3 Likes

BTW: You used the wrong Topics. I should be "Using Swift" and "SwiftUI".
It is not related to the development of the Swift Language or Compiler improvements.

1 Like

Thank You so much! Seems to be one big step forward!

You could also use the SwiftUI fileImporter, for opening files, e.g. (just a snippet from existing app):

	@State private var showImportTSV = false
	@State private var isError = false
	@State private var errorString = ""
	@State private var importURL: URL? = nil

...

   .fileImporter(isPresented: $showImportTSV, allowedContentTypes: [.tabSeparatedText], onCompletion: { result in
      switch result {
            case .success(let url):
                if url.isFileURL {
                   importURL = url
                }
            case .failure(let error):
                  isError.toggle()
                  errorString = error.localizedDescription
      }
   })

...

   .onChange(of: importURL) {
			handleFileSelection()
   }

and fileExporter:

	.fileExporter(isPresented: $showExportJSONSheet, document: exportedJSON, contentType: .json, defaultFilename: category.viewSubject, onCompletion: { result in
		switch result {
			case .success(let fileURL):
				print("Successful export to \(fileURL)")
			case .failure(let error):
				errorString = error.localizedDescription
				isError.toggle()
				break
		}
		exportedJSON = nil
	})