Explorar o código

First version of router implementation (wo coordinators)

Pavel Yurchenko hai 1 ano
pai
achega
875f17de9b

+ 1 - 1
SUIExamples/Core/DI.swift

@@ -10,5 +10,5 @@ import Foundation
 final class DI {
 final class DI {
     static var shared: DI = .init()
     static var shared: DI = .init()
 
 
-    let navigationStack = NavigatorStack()
+    let router = Router()
 }
 }

+ 5 - 4
SUIExamples/Modules/Main/MainBuilder.swift

@@ -9,12 +9,13 @@ import SwiftUI
 
 
 struct MainBuilder {
 struct MainBuilder {
 
 
-    func build() -> some View {
-        let navigatorStack = DI.shared.navigationStack
-        return MainView()
+    typealias Output = MainVM.Output
+
+    func build(with output: Output) -> some View {
+        MainView()
             .environment(
             .environment(
                 MainVM(
                 MainVM(
-                    navigatorStack: navigatorStack
+                    output: output
                 )
                 )
             )
             )
     }
     }

+ 14 - 4
SUIExamples/Modules/Main/MainVM.swift

@@ -7,12 +7,22 @@
 
 
 import SwiftUI
 import SwiftUI
 
 
+typealias Action = () -> Void
+typealias IntAction = (Int) -> Void
+
 @Observable
 @Observable
 final class MainVM {
 final class MainVM {
-    
-    private(set) var navigatorStack: NavigatorStack
 
 
-    init(navigatorStack: NavigatorStack) {
-        self.navigatorStack = navigatorStack
+    struct Output {
+        var onProducts: Action?
+        var onProduct: IntAction?
+        var onCart: Action?
+        var onFeedback: Action?
+    }
+
+    let output: Output
+
+    init(output: Output) {
+        self.output = output
     }
     }
 }
 }

+ 5 - 5
SUIExamples/Modules/Main/MainView.swift

@@ -13,16 +13,16 @@ struct MainView: View {
     var body: some View {
     var body: some View {
         VStack {
         VStack {
             Button("Products") {
             Button("Products") {
-                vm.navigatorStack.push(.products)
+                vm.output.onProducts?()
             }
             }
             Button("Product 1") {
             Button("Product 1") {
-                vm.navigatorStack.push(.product(id: 1))
+                vm.output.onProduct?(1)
             }
             }
             Button("Cart") {
             Button("Cart") {
-                vm.navigatorStack.push(.cart)
+                vm.output.onCart?()
             }
             }
             Button("Feedback") {
             Button("Feedback") {
-                vm.navigatorStack.push(.feedback)
+                vm.output.onFeedback?()
             }
             }
         }
         }
         .padding()
         .padding()
@@ -30,5 +30,5 @@ struct MainView: View {
 }
 }
 
 
 #Preview {
 #Preview {
-    MainBuilder().build()
+    MainBuilder().build(with: .init())
 }
 }

+ 22 - 0
SUIExamples/Modules/Products/ProductsBuilder.swift

@@ -0,0 +1,22 @@
+//
+//  ProductsBuilder.swift
+//  SUIExamples
+//
+//  Created by Pavel Yurchenko on 27.11.2024.
+//
+
+import SwiftUI
+
+struct ProductsBuilder {
+
+    typealias Output = ProductsVM.Output
+
+    func build(with output: Output) -> some View {
+        ProductsView()
+            .environment(
+                ProductsVM(
+                    output: output
+                )
+            )
+    }
+}

+ 22 - 0
SUIExamples/Modules/Products/ProductsVM.swift

@@ -0,0 +1,22 @@
+//
+//  ProductsVM.swift
+//  SUIExamples
+//
+//  Created by Pavel Yurchenko on 27.11.2024.
+//
+
+import SwiftUI
+
+@Observable
+final class ProductsVM {
+
+    struct Output {
+        var onProduct: IntAction?
+    }
+
+    let output: Output
+
+    init(output: Output) {
+        self.output = output
+    }
+}

+ 37 - 0
SUIExamples/Modules/Products/ProductsView.swift

@@ -0,0 +1,37 @@
+//
+//  ProductsView.swift
+//  SUIExamples
+//
+//  Created by Pavel Yurchenko on 17.08.2024.
+//
+
+import SwiftUI
+
+struct ProductsView: View {
+    @Environment(ProductsVM.self) private var vm
+
+    var body: some View {
+        VStack {
+            Button("Product 1") {
+                vm.output.onProduct?(1)
+            }
+            Button("Product 2") {
+                vm.output.onProduct?(2)
+            }
+            Button("Product 3") {
+                vm.output.onProduct?(3)
+            }
+            Button("Product 4") {
+                vm.output.onProduct?(4)
+            }
+            Button("Product 5") {
+                vm.output.onProduct?(5)
+            }
+        }
+        .padding()
+    }
+}
+
+#Preview {
+    ProductsBuilder().build(with: .init())
+}

+ 0 - 23
SUIExamples/Navigator/NavigatorStack.swift

@@ -1,23 +0,0 @@
-//
-//  NavigatorStack.swift
-//  SUIExamples
-//
-//  Created by Pavel Yurchenko on 27.11.2024.
-//
-
-import Foundation
-import SwiftUI
-
-final class NavigatorStack: ObservableObject {
-
-    @Published
-    var path = NavigationPath()
-
-    func push(_ route: Route) {
-        path.append(route)
-    }
-
-    func pop() {
-        path.removeLast()
-    }
-}

+ 0 - 15
SUIExamples/Navigator/Route.swift

@@ -13,19 +13,4 @@ enum Route: Hashable {
     case product(id: Int)
     case product(id: Int)
     case cart
     case cart
     case feedback
     case feedback
-
-    func buildModule() -> some View {
-        return switch self {
-        case .main:
-            MainBuilder().build()
-        case .products:
-            MainBuilder().build()
-        case .product:
-            MainBuilder().build()
-        case .cart:
-            MainBuilder().build()
-        case .feedback:
-            MainBuilder().build()
-        }
-    }
 }
 }

+ 41 - 0
SUIExamples/Navigator/Router.swift

@@ -0,0 +1,41 @@
+//
+//  Router.swift
+//  SUIExamples
+//
+//  Created by Pavel Yurchenko on 27.11.2024.
+//
+
+import Foundation
+import SwiftUI
+
+final class Router: ObservableObject {
+
+    @Published
+    var path = NavigationPath()
+
+    func push(_ route: Route) {
+        path.append(route)
+    }
+
+    func pop() {
+        path.removeLast()
+    }
+
+    @ViewBuilder
+    func buildDestination(_ route: Route) -> some View {
+        switch route {
+        case .main:
+            MainBuilder().build(with: .init(onProducts: { [weak self] in
+                self?.push(.products)
+            }))
+        case .products:
+            ProductsBuilder().build(with: .init())
+        case .product:
+            MainBuilder().build(with: .init())
+        case .cart:
+            MainBuilder().build(with: .init())
+        case .feedback:
+            MainBuilder().build(with: .init())
+        }
+    }
+}

+ 14 - 6
SUIExamples/SUIExamplesApp.swift

@@ -10,15 +10,23 @@ import SwiftUI
 @main
 @main
 struct SUIExamplesApp: App {
 struct SUIExamplesApp: App {
 
 
-    @StateObject private var navigatorStack: NavigatorStack = DI.shared.navigationStack
+    @StateObject private var router: Router = DI.shared.router
 
 
     var body: some Scene {
     var body: some Scene {
         WindowGroup {
         WindowGroup {
-            NavigationStack(path: $navigatorStack.path){
-                MainBuilder().build()
-            }
-            .navigationDestination(for: Route.self) {
-                $0.buildModule()
+            NavigationStack(path: $router.path){
+                MainBuilder().build(
+                    with: .init(
+                        onProducts: {
+                            router.push(
+                                .products
+                            )
+                        })
+                )
+                .navigationDestination(
+                    for: Route.self,
+                    destination: router.buildDestination
+                )
             }
             }
         }
         }
     }
     }