|
import SwiftUI |
|
|
|
func safeAt<T>(array: [T], position: Int) -> T? { |
|
return (position <= array.count - 1) ? array[position] : nil |
|
} |
|
|
|
protocol Navigator { |
|
func push(url: String) -> Void |
|
func pop() -> Void |
|
} |
|
|
|
class CoreNimbusView { |
|
let navigator: Navigator |
|
private var listener: ((String) -> Void)? |
|
private var lateUrl: String? |
|
|
|
init(navigator: Navigator) { |
|
self.navigator = navigator |
|
} |
|
|
|
func onChange(listener: @escaping (String) -> Void) { |
|
self.listener = listener |
|
if (lateUrl != nil) { |
|
listener(lateUrl!) |
|
lateUrl = nil |
|
} |
|
} |
|
|
|
func paint(url: String) { |
|
if (listener == nil) { |
|
lateUrl = url |
|
} else { |
|
listener!(url) |
|
} |
|
} |
|
} |
|
|
|
func pushActionHandler(url: String, view: CoreNimbusView) { |
|
view.navigator.push(url: url) |
|
} |
|
func popActionHandler(view: CoreNimbusView) { |
|
view.navigator.pop() |
|
} |
|
|
|
class HistoryItem: ObservableObject { |
|
let url: String |
|
var linkActive = false |
|
let coreView: CoreNimbusView |
|
|
|
init(url: String, coreView: CoreNimbusView) { |
|
self.url = url |
|
self.coreView = coreView |
|
} |
|
} |
|
|
|
class History: ObservableObject { |
|
@Published var pages: [HistoryItem] = [] |
|
@Published var current = -1 |
|
} |
|
|
|
struct NimbusView: View, Identifiable { |
|
let id: Int |
|
|
|
@State var url = "" |
|
@EnvironmentObject var history: History |
|
|
|
var body: some View { |
|
let page = safeAt(array: history.pages, position: id) |
|
if (page == nil) { |
|
EmptyView() |
|
} else { |
|
let page = page! |
|
VStack { |
|
// navigation logic |
|
UseMemo(key: page.linkActive) { linkActive in |
|
VStack { |
|
NavigationLink( |
|
destination: NimbusView(id: id + 1), |
|
isActive: $history.pages[id].linkActive |
|
) { |
|
EmptyView() |
|
} |
|
} |
|
} |
|
|
|
// view content |
|
UseMemo(key: url) { keys in |
|
VStack { |
|
if (url.isEmpty) { |
|
Text("No URL yet") |
|
} else { |
|
Text(url) |
|
Button("Next") { pushActionHandler(url: "url \(id)", view: page.coreView) } |
|
Button("Previous") { popActionHandler(view: page.coreView) } |
|
//Button("Previous") { history.forceUpdate.toggle() } |
|
} |
|
} |
|
} |
|
}.onAppear() { |
|
page.coreView.onChange(listener: { content in url = content }) |
|
} |
|
} |
|
} |
|
} |
|
|
|
struct NimbusNavigator: View, Navigator { |
|
let initialUrl: String |
|
@StateObject var history = History() |
|
|
|
func push(url: String) { |
|
if (history.current >= 0) { |
|
history.pages[history.current].linkActive = true |
|
} |
|
let newPage = HistoryItem(url: url, coreView: CoreNimbusView(navigator: self)) |
|
history.pages.removeLast(history.pages.count - 1 - history.current) |
|
history.pages.append(newPage) |
|
newPage.coreView.paint(url: url) |
|
history.current += 1 |
|
} |
|
|
|
func pop() { |
|
if (history.current <= 0) { |
|
return print("Can't pop single view") |
|
} |
|
history.pages[history.current - 1].linkActive = false |
|
history.current -= 1 |
|
} |
|
|
|
var body: some View { |
|
NavigationView { NimbusView(id: 0) } |
|
.environmentObject(history) |
|
.onAppear() { |
|
push(url: initialUrl) |
|
} |
|
} |
|
} |
|
|
|
struct ContentView: View { |
|
var body: some View { |
|
NimbusNavigator(initialUrl: "initial") |
|
} |
|
} |