Skip to content

Commit

Permalink
Update routing for redux pattern
Browse files Browse the repository at this point in the history
  • Loading branch information
rafaelesantos committed Apr 12, 2024
1 parent de6aaf5 commit 1e49f6b
Show file tree
Hide file tree
Showing 6 changed files with 156 additions and 0 deletions.
File renamed without changes.
File renamed without changes.
22 changes: 22 additions & 0 deletions Sources/RefdsRouter/Redux/RefdsRoutableRedux.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import SwiftUI
import RefdsRedux

public protocol RefdsRoutableRedux: Hashable, Identifiable {
associatedtype State: RefdsReduxState
associatedtype ViewType: View
var navigationType: RefdsNavigationType { get }

func view(
router: RefdsRouterRedux<Self>,
state: Binding<State>,
action: (RefdsReduxAction) -> Void
) -> ViewType
}

extension RefdsRoutableRedux {
public var id: Self { self }

func hash(into hasher: inout Hasher) {
hasher.combine(id)
}
}
86 changes: 86 additions & 0 deletions Sources/RefdsRouter/Redux/RefdsRouterRedux.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import SwiftUI
import RefdsRedux

public class RefdsRouterRedux<
Destination: RefdsRoutableRedux
>: ObservableObject {
@Published public var path: NavigationPath = NavigationPath()
@Published public var presentingSheet: Destination?
@Published public var presentingFullScreenCover: Destination?
@Published public var isPresented: Binding<Destination?>

public var isPresenting: Bool {
presentingSheet != nil || presentingFullScreenCover != nil
}

public init(isPresented: Binding<Destination?>) {
self.isPresented = isPresented
}

@ViewBuilder
public func view(
for route: Destination,
state: Binding<Destination.State>,
action: (RefdsReduxAction) -> Void
) -> some View {
let router = router(type: route.navigationType)
route.view(router: router, state: state, action: action)
}

public func route(to destination: Destination) {
switch destination.navigationType {
case .push: push(destination)
case .sheet: presentSheet(destination)
case .fullScreenCover: presentFullScreen(destination)
}
}

public func popToRoot() {
path.removeLast(path.count)
}

public func dismiss() {
if !path.isEmpty {
path.removeLast()
} else if presentingSheet != nil {
presentingSheet = nil
} else if presentingFullScreenCover != nil {
presentingFullScreenCover = nil
} else {
isPresented.wrappedValue = nil
}
}

private func push(_ appRoute: Destination) {
path.append(appRoute)
}

private func presentSheet(_ route: Destination) {
self.presentingSheet = route
}

private func presentFullScreen(_ route: Destination) {
self.presentingFullScreenCover = route
}

private func router(type: RefdsNavigationType) -> RefdsRouterRedux {
switch type {
case .push:
return self
case .sheet:
return RefdsRouterRedux(
isPresented: Binding(
get: { self.presentingSheet },
set: { self.presentingSheet = $0 }
)
)
case .fullScreenCover:
return RefdsRouterRedux(
isPresented: Binding(
get: { self.presentingFullScreenCover },
set: { self.presentingFullScreenCover = $0 }
)
)
}
}
}
48 changes: 48 additions & 0 deletions Sources/RefdsRouter/Redux/RefdsRoutingReduxView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import SwiftUI
import RefdsRedux

public struct RefdsRoutingReduxView<
Content: View,
Destination: RefdsRoutableRedux
>: View {
@Binding var router: RefdsRouterRedux<Destination>
@Binding var store: RefdsReduxStore<Destination.State>
private let content: (RefdsRouterRedux<Destination>) -> Content

public init(
router: Binding<RefdsRouterRedux<Destination>>,
store: Binding<RefdsReduxStore<Destination.State>>,
@ViewBuilder content: @escaping (RefdsRouterRedux<Destination>) -> Content
) {
self._router = router
self._store = store
self.content = content
}

public var body: some View {
NavigationStack(path: $router.path) {
content(router)
.navigationDestination(for: Destination.self) {
router.view(
for: $0,
state: $store.state,
action: store.dispatch(action:)
)
}
}
.sheet(item: $router.presentingSheet) {
router.view(
for: $0,
state: $store.state,
action: store.dispatch(action:)
)
}
.refdsFullScreenCover(item: $router.presentingFullScreenCover) {
router.view(
for: $0,
state: $store.state,
action: store.dispatch(action:)
)
}
}
}

0 comments on commit 1e49f6b

Please sign in to comment.