Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make a SwiftUI DocumentGroup app without starting on the file picker?

If a user uses the Document App template in Xcode to create a SwiftUI app, macOS starts them off with a new document. This is good. I can work with that to present onboarding UI within a new document.

However, with that same app running on iOS, the user is instead greeted by the stock document view controller to create or pick a document.

This is not helpful in that I don't have a way to present onboarding or any other custom information.

I did notice that if you add a WindowGroup to the Scene, the app will display that window group. But then I don't know how to get the user to the picker UI.

Has anyone figured out how to do things like present onboarding on top of this DocumentGroup-based app?

Here is a full document app

import SwiftUI
import UniformTypeIdentifiers

@main
struct DocumentTestApp: App {
    var body: some Scene {
        DocumentGroup(newDocument: DocumentTestDocument()) { file in
            ContentView(document: file.$document)
        }
    }
}

struct ContentView: View {
    @Binding var document: DocumentTestDocument

    var body: some View {
        TextEditor(text: $document.text)
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView(document: .constant(DocumentTestDocument()))
    }
}

extension UTType {
    static var exampleText: UTType {
        UTType(importedAs: "com.example.plain-text")
    }
}

struct DocumentTestDocument: FileDocument {
    var text: String

    init(text: String = "Hello, world!") {
        self.text = text
    }

    static var readableContentTypes: [UTType] { [.exampleText] }

    init(configuration: ReadConfiguration) throws {
        guard let data = configuration.file.regularFileContents,
              let string = String(data: data, encoding: .utf8)
        else {
            throw CocoaError(.fileReadCorruptFile)
        }
        text = string
    }
    
    func fileWrapper(configuration: WriteConfiguration) throws -> FileWrapper {
        let data = text.data(using: .utf8)!
        return .init(regularFileWithContents: data)
    }
}
like image 675
MScottWaller Avatar asked Aug 30 '20 02:08

MScottWaller


1 Answers

App shows first window scene by default, so place first on-boarding window scene and afterwards a DocumentGroup. Somewhere at the end of on boarding process (success path) call document controller to create new document (DocumentGroup is based on same NSDocumentController engine inside).

Update: below is for macOS

*just recognised that original question is for iOS

So a possible approach is

@main
struct DocumentTestApp: App {
    var body: some Scene {
        WindowGroup("On-Boarding") {
          // ContentView()

          // In some action at the end of this scene flow
          // just close current window and open new document
          Button("Demo") {
            NSApp.sendAction(#selector(NSWindow.performClose(_:)), to: nil, from: nil)
            NSDocumentController.shared.newDocument(nil)
          }
        }

        DocumentGroup(newDocument: DocumentTestDocument()) { file in
            ContentView(document: file.$document)
        }
    }
}
like image 194
Asperi Avatar answered Nov 16 '22 10:11

Asperi