Skip to content

Commit

Permalink
Minor refactoring
Browse files Browse the repository at this point in the history
* Minor refactoring

* Update version

Co-authored-by: amisha <[email protected]>
  • Loading branch information
jimmy0251 and cp-amisha-i authored Sep 1, 2022
1 parent 9c2cb59 commit ff7e5f9
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 65 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ Once you have your Swift package set up, adding UIPilot as a dependency is as ea

```swift
dependencies: [
.package(url: "https://github.com/canopas/UIPilot.git", .upToNextMajor(from: "1.3.0"))
.package(url: "https://github.com/canopas/UIPilot.git", .upToNextMajor(from: "1.3.1"))
]
```

Expand All @@ -47,7 +47,7 @@ dependencies: [
[CocoaPods][] is a dependency manager for Cocoa projects. For usage and installation instructions, visit their website. To integrate UIPilot into your Xcode project using CocoaPods, specify it in your Podfile:

target 'YourAppName' do
pod 'UIPilot', '~> 1.3.0'
pod 'UIPilot', '~> 1.3.1'
end

[CocoaPods]: https://cocoapods.org
Expand Down
109 changes: 49 additions & 60 deletions Sources/UIPilot/UIPilot.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ import Combine
public class UIPilot<T: Equatable>: ObservableObject {

private let logger: Logger
private let viewGenerator = PathViewGenerator<T>()


@Published var paths: [UIPilotPath<T>] = []

public var stack: [T] {
Expand All @@ -16,13 +15,6 @@ public class UIPilot<T: Equatable>: ObservableObject {
logger = debug ? DebugLog() : EmptyLog()
logger.log("UIPilot - Pilot Initialized.")

viewGenerator.onPop = { [weak self] path in
if let self = self, self.paths.count > 1
&& path.id == self.paths[self.paths.count - 2].id {
self.pop()
}
}

push(initial)
}

Expand Down Expand Up @@ -59,10 +51,14 @@ public class UIPilot<T: Equatable>: ObservableObject {
logger.log("UIPilot - Popping \(numToPop) routes")
paths.removeLast(numToPop)
}

func getView<Screen: View>(_ paths: [UIPilotPath<T>], _ routeMap: RouteMap<T, Screen>, _ pathViews: [UIPilotPath<T>: Screen]) -> (PathView<Screen>?, [UIPilotPath<T>: Screen]) {
return viewGenerator.generate(paths, routeMap, pathViews)

func systemPop(path: UIPilotPath<T>) {
if paths.count > 1
&& path.id == self.paths[self.paths.count - 2].id {
self.pop()
}
}

}

struct UIPilotPath<T: Equatable>: Equatable, Hashable {
Expand Down Expand Up @@ -125,22 +121,51 @@ class PathViewState<Screen: View>: ObservableObject {
}
}

class PathViewGenerator<T: Equatable> {
public struct UIPilotHost<T: Equatable, Screen: View>: View {

@ObservedObject
private var pilot: UIPilot<T>
@ViewBuilder
private let routeMap: (T) -> Screen

@State
private var viewGenerator = ViewGenerator<T, Screen>()

public init(_ pilot: UIPilot<T>, @ViewBuilder _ routeMap: @escaping (T) -> Screen) {
self.pilot = pilot
self.routeMap = routeMap
self.viewGenerator.onPop = { path in
pilot.systemPop(path: path)
}
}

public var body: some View {
NavigationView {
viewGenerator.build(pilot.paths, routeMap)
}
#if !os(macOS)
.navigationViewStyle(.stack)
#endif
.environmentObject(pilot)
}
}

var onPop: ((UIPilotPath<T>) -> Void)?
class ViewGenerator<T: Equatable, Screen: View>: ObservableObject {
var onPop: ((UIPilotPath<T>) -> Void)? = nil

private var pathViews = [UIPilotPath<T>: Screen]()

func generate<Screen: View>(
func build(
_ paths: [UIPilotPath<T>],
@ViewBuilder _ routeMap: RouteMap<T, Screen>,
_ pathViews: [UIPilotPath<T>: Screen]) -> (PathView<Screen>?,
[UIPilotPath<T>: Screen]) {
var pathViews = recycleViews(paths, pathViews: pathViews)
@ViewBuilder _ routeMap: (T) -> Screen) -> PathView<Screen>? {

recycleViews(paths)

var current: PathView<Screen>?
for path in paths.reversed() {
let view = pathViews[path] ?? routeMap(path.route)
pathViews[path] = view

let content = PathView(view, state: PathViewState())

content.state.next = current
Expand All @@ -151,53 +176,17 @@ class PathViewGenerator<T: Equatable> {
}
current = content
}
return (current, pathViews)
return current
}

private func recycleViews<Screen: View>(_ paths: [UIPilotPath<T>], pathViews: [UIPilotPath<T>: Screen]) -> [UIPilotPath<T>: Screen] {
var pathViews = pathViews
private func recycleViews(_ paths: [UIPilotPath<T>]){
var pathViews = self.pathViews
for key in pathViews.keys {
if !paths.contains(key) {
pathViews.removeValue(forKey: key)
}
}
return pathViews
}
}

public typealias RouteMap<T, Screen> = (T) -> Screen

public struct UIPilotHost<T: Equatable, Screen: View>: View {

@ObservedObject
private var pilot: UIPilot<T>

@ViewBuilder
let routeMap: RouteMap<T, Screen>

@State
var pathViews = [UIPilotPath<T>: Screen]()
@State
var content: PathView<Screen>?

public init(_ pilot: UIPilot<T>, @ViewBuilder _ routeMap: @escaping RouteMap<T, Screen>) {
self.pilot = pilot
self.routeMap = routeMap
}

public var body: some View {
NavigationView {
content
}
#if !os(macOS)
.navigationViewStyle(.stack)
#endif
.environmentObject(pilot)
.onReceive(pilot.$paths) { paths in
let (newContent, newPathViews) = pilot.getView(paths, routeMap, pathViews)
self.content = newContent
self.pathViews = newPathViews
}
self.pathViews = pathViews
}
}

Expand Down
2 changes: 1 addition & 1 deletion UIPilot.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "UIPilot"
s.version = "1.3.0"
s.version = "1.3.1"
s.summary = "The missing type-safe, SwiftUI navigation library."

s.description = <<-DESC
Expand Down
4 changes: 2 additions & 2 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ Once you have your Swift package set up, adding UIPilot as a dependency is as ea

```swift
dependencies: [
.package(url: "https://github.com/canopas/UIPilot.git", .upToNextMajor(from: "1.3.0"))
.package(url: "https://github.com/canopas/UIPilot.git", .upToNextMajor(from: "1.3.1"))
]
```

Expand All @@ -326,7 +326,7 @@ dependencies: [
[CocoaPods][] is a dependency manager for Cocoa projects. For usage and installation instructions, visit their website. To integrate UIPilot into your Xcode project using CocoaPods, specify it in your Podfile:

target 'YourAppName' do
pod 'UIPilot', '~> 1.3.0'
pod 'UIPilot', '~> 1.3.1'
end

[CocoaPods]: https://cocoapods.org
Expand Down

0 comments on commit ff7e5f9

Please sign in to comment.