108 lines
3.0 KiB
Swift
108 lines
3.0 KiB
Swift
//
|
|
// ContentView.swift
|
|
// Gemini
|
|
//
|
|
// Created by Shadowfacts on 7/12/20.
|
|
//
|
|
|
|
import SwiftUI
|
|
import GeminiFormat
|
|
import GeminiRenderer
|
|
import GeminiProtocol
|
|
|
|
public struct BrowserView: View {
|
|
let navigator: NavigationManager
|
|
let scrollingEnabled: Bool
|
|
@State var task: GeminiDataTask?
|
|
@State var state: ViewState = .loading
|
|
|
|
public init(navigator: NavigationManager, scrollingEnabled: Bool = true) {
|
|
self.navigator = navigator
|
|
self.scrollingEnabled = scrollingEnabled
|
|
}
|
|
|
|
public var body: some View {
|
|
mainView
|
|
.onReceive(navigator.$currentURL, perform: self.urlChanged)
|
|
}
|
|
|
|
@ViewBuilder
|
|
private var mainView: some View {
|
|
VStack {
|
|
switch state {
|
|
case .loading:
|
|
Spacer()
|
|
loadingView
|
|
.onAppear(perform: self.loadDocument)
|
|
Spacer()
|
|
case let .error(message):
|
|
Text("An error occurred")
|
|
.font(.headline)
|
|
Text(message)
|
|
.lineLimit(nil)
|
|
case let .document(doc):
|
|
DocumentView(document: doc, scrollingEnabled: scrollingEnabled, changeURL: navigator.changeURL)
|
|
Spacer()
|
|
}
|
|
}
|
|
}
|
|
|
|
@ViewBuilder
|
|
private var loadingView: some View {
|
|
if #available(macOS 10.16, iOS 14.0, *) {
|
|
ProgressView("Loading...")
|
|
} else {
|
|
Text("Loading...")
|
|
}
|
|
}
|
|
|
|
private func loadDocument() {
|
|
let url = navigator.currentURL
|
|
task = try! GeminiDataTask(url: url, completion: { (response) in
|
|
self.task = nil
|
|
switch response {
|
|
case let .failure(error):
|
|
state = .error(error.localizedDescription)
|
|
case let .success(response):
|
|
if response.status.isRedirect {
|
|
if let redirect = URL(string: response.meta) {
|
|
navigator.changeURL(redirect)
|
|
loadDocument()
|
|
} else {
|
|
state = .error("Invalid redirect URL: '\(response.meta)'")
|
|
}
|
|
} else if response.status.isSuccess,
|
|
let text = response.bodyText {
|
|
state = .document(GeminiParser.parse(text: text, baseURL: url))
|
|
} else {
|
|
state = .error("Unknown error: \(response.header)")
|
|
}
|
|
}
|
|
})
|
|
task!.resume()
|
|
}
|
|
|
|
private func urlChanged(_ newValue: URL) {
|
|
if case .loading = state {
|
|
task?.cancel()
|
|
loadDocument()
|
|
} else {
|
|
state = .loading
|
|
}
|
|
}
|
|
}
|
|
|
|
extension BrowserView {
|
|
enum ViewState {
|
|
case loading
|
|
case document(Document)
|
|
case error(String)
|
|
}
|
|
}
|
|
|
|
struct ContentView_Previews: PreviewProvider {
|
|
static var previews: some View {
|
|
BrowserView(navigator: NavigationManager(url: URL(string: "gemini://localhost/overview.gmi")!))
|
|
}
|
|
}
|