Skip to content

Commit

Permalink
4.15.0
Browse files Browse the repository at this point in the history
  • Loading branch information
dankinsoid committed Mar 15, 2024
1 parent f16bed0 commit 88d23c4
Show file tree
Hide file tree
Showing 8 changed files with 329 additions and 124 deletions.
20 changes: 11 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,34 +25,36 @@ struct TabSteps {

var tab1
var tab2 = SomeTab2Data()
var tab3 = NavigationSteps()
var tab3: NavigationSteps = .screen1
var none
}

@Steps
struct NavigationSteps {

var screen1
var screen2 = PickerSteps()
var screen2: PickerSteps = .none
}

@Steps
struct PickerSteps {

var text1
var text2
var none
}
```
```swift
var steps = TabSteps()
var steps: TabSteps = .tab1
```
If you want to open `Tab2` you need mark `tab2` as selected. You have several ways to do it:
1. Set `selected` property:
```swift
steps.selected = .tab2
```
2. Just mutate `.tab2`:
2. Use auto-generated static functions:
```swift
steps.tab2 = SomeTab2Data()
steps = .tab2(SomeTab2Data())
```
You can check which property is selected:
1. With `selected` property:
Expand All @@ -61,12 +63,12 @@ $steps.selected == .tab2
```
Also you can set initial selected property:
```swift
var screen3 = PickerSteps(.text1)
var screen3: PickerSteps = .text1
```
### Deeplink
Then you got a deep link for example and you need to change `Tab2` to third tab with `NavigationView`, push to `Push2View` and select `Text2` in `PickerView`.
```swift
steps.tab3.screen2.text2.select()
steps.tab3.screen2 = .text2
```
Now `tab3`, `screen3`, `text2` properties are marked as selected.
### Integration with UI
Expand All @@ -78,7 +80,7 @@ SwiftUI is a state driven framework, so it's easy to implement navigation with `
```swift
struct RootTabView: View {

@StateStep var step = TabSteps(.tab1)
@StateStep var step: TabSteps = .tab1

var body: some View {
TabView(selection: $step.selected) {
Expand Down Expand Up @@ -205,7 +207,7 @@ import PackageDescription
let package = Package(
name: "SomeProject",
dependencies: [
.package(url: "https://github.com/dankinsoid/VDFlow.git", from: "4.14.0")
.package(url: "https://github.com/dankinsoid/VDFlow.git", from: "4.15.0")
],
targets: [
.target(name: "SomeProject", dependencies: ["VDFlow"])
Expand Down
4 changes: 0 additions & 4 deletions Sources/VDFlow/EmptyStep.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,4 @@ public struct EmptyStep: Hashable, Codable, CustomStringConvertible, Sendable {
public var description: String { "EmptyStep" }

public init() {}

public mutating func select() {
updater.toggle()
}
}
10 changes: 5 additions & 5 deletions Sources/VDFlow/NavigationView+Ext.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ public extension NavigationLink {
step: StepBinding<T, D>,
@ViewBuilder destination: () -> Dest,
@ViewBuilder label: () -> Label
) where Destination == NavigationStepDestination<Dest, D> {
) where Destination == NavigationStepDestination<Dest, D>, T.Steps: OptionalStep, T: StepsCollection {
self.init(isActive: step.isSelected) {
NavigationStepDestination(content: destination(), stepBinding: step.binding)
} label: {
Expand All @@ -29,21 +29,21 @@ public struct NavigationStepDestination<Content: View, Value>: View {
@available(iOS 16.0, macOS 13.0, watchOS 9.0, *)
public extension View {

func navigationDestination<Root, Value>(
func navigationDestination<Root: StepsCollection, Value>(
_ root: Binding<Root>,
for step: WritableKeyPath<Root, StepWrapper<Root, Value>>,
@ViewBuilder destination: @escaping () -> some View
) -> some View {
) -> some View where Root.Steps: OptionalStep {
navigationDestination(
step: StepBinding(root: root, keyPath: step),
destination: destination
)
}

func navigationDestination<Root, Value>(
func navigationDestination<Root: StepsCollection, Value>(
step: StepBinding<Root, Value>,
@ViewBuilder destination: @escaping () -> some View
) -> some View {
) -> some View where Root.Steps: OptionalStep {
navigationDestination(isPresented: step.isSelected) {
destination()
.stepEnvironment(step.binding)
Expand Down
11 changes: 9 additions & 2 deletions Sources/VDFlow/StateStep.swift
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,14 @@ public extension View {
binding[dynamicMember: keyPath.appending(path: \.wrappedValue)]
)
.transformEnvironment(\.unselectStep) {
$0.insert({ binding.wrappedValue.selected = nil }, at: 0)
$0.insert(
{
if let none = (Root.Steps.self as? OptionalStep.Type)?.none as? Root.Steps {
binding.wrappedValue.selected = none
}
},
at: 0
)
}
.tag(binding.wrappedValue[keyPath: keyPath].id)
.stepTag(binding.wrappedValue[keyPath: keyPath].id)
Expand All @@ -112,7 +119,7 @@ public extension View {
}
}

public extension Binding where Value: StepsCollection {
public extension Binding where Value: StepsCollection ,Value.Steps: OptionalStep {

func isSelected(_ step: Value.Steps) -> Binding<Bool> {
Binding<Bool> {
Expand Down
35 changes: 19 additions & 16 deletions Sources/VDFlow/StepBinding.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,22 +22,6 @@ public struct StepBinding<Root: StepsCollection, Value> {
self.keyPath = keyPath
}

public var isSelected: Binding<Bool> {
$root.isSelected(step)
}

public func isSelected(_ value: Value) -> Binding<Bool> {
Binding {
$root.isSelected(step).wrappedValue
} set: {
if $0 {
$root.wrappedValue[keyPath: keyPath].wrappedValue = value
} else {
$root.wrappedValue.selected = nil
}
}
}

public func callAsFunction(_ value: Value) -> StepBinding {
StepBinding(
root: Binding {
Expand All @@ -52,6 +36,25 @@ public struct StepBinding<Root: StepsCollection, Value> {
}
}

extension StepBinding where Root.Steps: OptionalStep {

public var isSelected: Binding<Bool> {
$root.isSelected(step)
}

public func isSelected(_ value: Value) -> Binding<Bool> {
Binding {
$root.isSelected(step).wrappedValue
} set: {
if $0 {
$root.wrappedValue[keyPath: keyPath].wrappedValue = value
} else {
$root.wrappedValue.selected = nil
}
}
}
}

extension Binding where Value: StepsCollection {

subscript<A>(dynamicMember keyPath: WritableKeyPath<Value, StepWrapper<Value, A>>) -> StepBinding<Value, A> {
Expand Down
25 changes: 10 additions & 15 deletions Sources/VDFlow/StepsCollection.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,17 @@ import Foundation
public protocol StepsCollection where Steps.RawValue == String {

associatedtype Steps: RawRepresentable & CaseIterable & Hashable & Codable & Sendable
var selected: Steps? { get set }
var selected: Steps { get set }
}

public extension StepsCollection {
public protocol OptionalStep: ExpressibleByNilLiteral {

static var none: Self { get }
}

@discardableResult
mutating func move(_ offset: Int = 1) -> Bool {
let steps = Steps.allCases
guard
let selected,
let i = steps.firstIndex(of: selected),
steps.indices.contains(steps.index(i, offsetBy: offset))
else {
return false
}
self.selected = steps[steps.index(i, offsetBy: offset)]
return true
}
extension OptionalStep {

public init(nilLiteral: ()) {
self = .none
}
}
Loading

0 comments on commit 88d23c4

Please sign in to comment.