Skip to content

Instantly share code, notes, and snippets.

@uchcode
Last active January 11, 2023 10:49
Show Gist options
  • Save uchcode/110a998387267e791fdb04c6a621d2f0 to your computer and use it in GitHub Desktop.
Save uchcode/110a998387267e791fdb04c6a621d2f0 to your computer and use it in GitHub Desktop.
Developing a Document-Based App in SwiftUI
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