// // NavigationManager.swift // Gemini // // Created by Shadowfacts on 7/14/20. // import Foundation public protocol NavigationManagerDelegate: class { func loadNonGeminiURL(_ url: URL) } public class NavigationManager: NSObject, ObservableObject { public weak var delegate: NavigationManagerDelegate? @Published public var currentURL: URL @Published public var backStack = [URL]() @Published public var forwardStack = [URL]() public var displayURL: String { var components = URLComponents(url: currentURL, resolvingAgainstBaseURL: false)! if components.port == 1965 { components.port = nil } return components.string! } public init(url: URL) { self.currentURL = url } public func changeURL(_ url: URL) { var components = URLComponents(url: url, resolvingAgainstBaseURL: false)! if let scheme = url.scheme { if scheme != "gemini" { delegate?.loadNonGeminiURL(url) return } } else { components.scheme = "gemini" } // Foundation parses bare hosts (e.g. `example.com`) as having no host and a path of `example.com` if components.host == nil { components.host = components.path components.path = "/" } // Some Gemini servers break on empty paths if components.path.isEmpty { components.path = "/" } let url = components.url! backStack.append(currentURL) currentURL = url forwardStack = [] } public func reload() { let url = currentURL currentURL = url } @objc public func back() { guard !backStack.isEmpty else { return } forwardStack.insert(currentURL, at: 0) currentURL = backStack.removeLast() } public func back(count: Int) { guard count <= backStack.count else { return } var removed = backStack.suffix(count) backStack.removeLast(count) forwardStack.insert(currentURL, at: 0) currentURL = removed.removeFirst() forwardStack.insert(contentsOf: removed, at: 0) } @objc public func forward() { guard !forwardStack.isEmpty else { return } backStack.append(currentURL) currentURL = forwardStack.removeFirst() } public func forward(count: Int) { guard count <= forwardStack.count else { return } var removed = forwardStack.prefix(count) forwardStack.removeFirst(count) backStack.append(currentURL) currentURL = removed.removeLast() backStack.append(contentsOf: removed) } }