Last active
January 11, 2023 10:49
-
-
Save uchcode/110a998387267e791fdb04c6a621d2f0 to your computer and use it in GitHub Desktop.
Developing a Document-Based App in SwiftUI
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import SwiftUI | |
struct ContentView: View { | |
@ObservedObject var browser = { () -> DocumentBrowserObject in | |
let dbo = DocumentBrowserObject ( | |
forOpeningFilesWithContentTypes: [ | |
"public.png", | |
"public.jpeg" | |
] | |
) | |
return dbo | |
}() | |
@State var presenting = false | |
var body: some View { | |
ObservableControllerView(object: browser) | |
.fullScreen(isPresented: $presenting) { | |
DocumentView(url: self.browser.documentURLs.first) | |
} | |
.onReceive(browser.$documentURLs) { urls in | |
if urls.isEmpty { return } | |
if urls.count != 1 { fatalError() } | |
self.presenting.toggle() | |
} | |
} | |
} | |
struct FullScreenModifier<IncomingView: View>: ViewModifier { | |
@Binding var isPresented: Bool | |
@State var content: () -> IncomingView | |
func body(content: Content) -> some View { | |
ZStack { | |
content | |
if isPresented { | |
NavigationView { | |
self.content().navigationBarItems(leading: | |
Button(action: { | |
self.isPresented.toggle() | |
}) { | |
Text("Done") | |
} | |
) | |
} | |
.navigationViewStyle(StackNavigationViewStyle()) | |
.animation(.default) | |
.transition(.move(edge:.bottom)) | |
.zIndex(1) | |
} | |
} | |
} | |
} | |
extension View { | |
public func fullScreen<Content: View> ( | |
isPresented: Binding<Bool>, | |
content: @escaping () -> Content | |
) -> some View { | |
modifier ( | |
FullScreenModifier(isPresented: isPresented, content: content) | |
) | |
} | |
} | |
class Document: UIDocument, ObservableObject { | |
@Published var image = UIImage() | |
override func load(fromContents contents: Any, ofType typeName: String?) throws { | |
guard let data = contents as? Data else { | |
fatalError() | |
} | |
guard let image = UIImage(data: data) else { | |
fatalError() | |
} | |
self.image = image | |
} | |
} | |
struct DocumentView: View { | |
@ObservedObject var document: Document | |
init(url: URL?) { | |
guard let url = url else { fatalError() } | |
document = Document(fileURL: url) | |
document.open { guard $0 else { fatalError() } } | |
} | |
func done() { | |
document.close { guard $0 else { fatalError() } } | |
} | |
var body: some View { | |
Image(uiImage: document.image).onDisappear(perform: done) | |
} | |
} | |
open class DocumentBrowserObject: UIDocumentBrowserViewController, ObservableObject { | |
@Published open var documentURLs: [URL] = [] | |
} | |
extension DocumentBrowserObject { | |
open override func loadView() { | |
super.loadView() | |
delegate = self | |
} | |
} | |
extension DocumentBrowserObject: UIDocumentBrowserViewControllerDelegate { | |
open func documentBrowser(_ controller: UIDocumentBrowserViewController, didPickDocumentsAt documentURLs: [URL]) { | |
self.documentURLs = documentURLs | |
} | |
} | |
public struct ObservableControllerView: UIViewControllerRepresentable { | |
public var uiViewController: UIViewController | |
public init<ObservableController>(object: ObservableController) where ObservableController: UIViewController, ObservableController: ObservableObject { | |
self.uiViewController = object | |
} | |
public func makeUIViewController(context: Self.Context) -> UIViewController { | |
uiViewController | |
} | |
public func updateUIViewController(_ uiViewController: UIViewController, context: Self.Context) { | |
// | |
} | |
} | |
import PlaygroundSupport | |
PlaygroundPage.current.wantsFullScreenLiveView = true | |
PlaygroundPage.current.setLiveView(ContentView()) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment