瀏覽代碼

Refactoring to have modal cart coordinator

Pavel Yurchenko 1 年之前
父節點
當前提交
4223814e9b

+ 11 - 9
CoordinatorSUIExamples/CoordinatorSUIExamples/Application/SUIExamplesApp.swift

@@ -18,17 +18,19 @@ struct SUIExamplesApp: App {
 
     var body: some Scene {
         WindowGroup {
-            TabView(selection: $appCoordinator.tabSelection) {
-                Tab(ApplicationTab.main.rawValue, systemImage: "tray.and.arrow.down.fill", value: ApplicationTab.main) {
-                    MainNavigationView(appCoordinator.mainCoordinator)
-                }
+            VStack {
+                TabView(selection: $appCoordinator.tabSelection) {
+                    Tab(ApplicationTab.main.rawValue, systemImage: "tray.and.arrow.down.fill", value: ApplicationTab.main) {
+                        MainNavigationView(appCoordinator.mainCoordinator)
+                    }
 
-                Tab(ApplicationTab.products.rawValue, systemImage: "tray.and.arrow.down.fill", value: ApplicationTab.products) {
-                    ProductsNavigationView(appCoordinator.productsCoordinator)
-                }
+                    Tab(ApplicationTab.products.rawValue, systemImage: "tray.and.arrow.down.fill", value: ApplicationTab.products) {
+                        ProductsNavigationView(appCoordinator.productsCoordinator)
+                    }
 
-                Tab(ApplicationTab.feedback.rawValue, systemImage: "tray.and.arrow.down.fill", value: ApplicationTab.feedback) {
-                    FeedbackNavigationView(appCoordinator.feedbackCoordinator)
+                    Tab(ApplicationTab.feedback.rawValue, systemImage: "tray.and.arrow.down.fill", value: ApplicationTab.feedback) {
+                        FeedbackNavigationView(appCoordinator.feedbackCoordinator)
+                    }
                 }
             }
         }

+ 88 - 0
CoordinatorSUIExamples/CoordinatorSUIExamples/Flows/Modal/ModalCartCoordinator.swift

@@ -0,0 +1,88 @@
+//
+//  ModalCartCoordinator.swift
+//  CoordinatorSUIExamples
+//
+//  Created by Pavel Yurchenko on 05.12.2024.
+//
+
+import CoordinatorSUI
+import SwiftUI
+
+final class ModalCartCoordinator: BaseCoordinator {
+
+    func run() -> some View {
+        showCartModule()
+    }
+
+    @ViewBuilder
+    func buildDestination(_ route: Route) -> some View {
+        switch route {
+        case .product(let id):
+            showProductModule(with: id)
+        case .cart:
+            showCartModule()
+        default:
+            EmptyView()
+        }
+    }
+
+    // MARK: - Private methods
+
+    private func showProductModule(with id: Int) -> some View {
+        ProductBuilder().build(
+            with: .init(
+                id: id,
+                showCart: false,
+                showProducts: false
+            ),
+            output: .init(
+                onAlert: { [weak self] title in
+                    self?.alertPresenter.showSimpleAlert(title) {
+                        print("On alert OK!")
+                    }
+                }
+            )
+        )
+    }
+
+    private func showCartModule() -> some View {
+        CartBuilder().build(
+            with: .init(products: [1, 2, 3]),
+            output: .init(
+                onProduct: { [weak self] in
+                    self?.currentRouter.push(Route.product(id: $0))
+                }
+            )
+        )
+    }
+}
+
+// MARK: - Navigation View
+
+struct ModalCartNavigationView: View {
+
+    @StateObject private var coordinator: ModalCartCoordinator
+    @StateObject private var router: Router
+    @StateObject private var alertPresenter: AlertPresenter
+
+    init(_ coordinator: ModalCartCoordinator) {
+        _coordinator = StateObject(wrappedValue: coordinator)
+        _router = StateObject(wrappedValue: coordinator.currentRouter)
+        _alertPresenter = StateObject(wrappedValue: coordinator.alertPresenter)
+    }
+
+    var body: some View {
+        NavigationStack(path: $router.path) {
+            coordinator.run()
+            .navigationDestination(
+                for: Route.self,
+                destination: coordinator.buildDestination
+            )
+        }.alert(
+            alertPresenter.title,
+            isPresented: $alertPresenter.isPresenting,
+            actions: alertPresenter.buildButtons
+        )
+    }
+}
+

+ 0 - 0
CoordinatorSUIExamples/CoordinatorSUIExamples/Flows/ModalProductsCoordinator.swift → CoordinatorSUIExamples/CoordinatorSUIExamples/Flows/Modal/ModalProductsCoordinator.swift


+ 5 - 4
CoordinatorSUIExamples/CoordinatorSUIExamples/Flows/Tabs/MainCoordinator.swift

@@ -39,7 +39,7 @@ final class MainCoordinator: BaseCoordinator {
         case .products:
             ModalProductsNavigationView(ModalProductsCoordinator())
         case .cart:
-            showCartModule()
+            ModalCartNavigationView(ModalCartCoordinator())
         default:
             fatalError("This should not happen!")
         }
@@ -105,9 +105,10 @@ final class MainCoordinator: BaseCoordinator {
 
     private func showCartModule() -> some View {
         CartBuilder().build(
-            with: .init(
-                onProducts: { [weak self] in
-                    self?.currentRouter.push(Route.products)
+            with: .init(products: [5, 6]),
+            output: .init(
+                onProduct: { [weak self] in
+                    self?.currentRouter.push(Route.product(id: $0))
                 }
             )
         )

+ 4 - 3
CoordinatorSUIExamples/CoordinatorSUIExamples/Flows/Tabs/ProductsCoordinator.swift

@@ -46,9 +46,10 @@ final class ProductsCoordinator: BaseCoordinator {
 
     private func showCartModule() -> some View {
         CartBuilder().build(
-            with: .init(
-                onProducts: { [weak self] in
-                    self?.currentRouter.push(Route.products)
+            with: .init(products: [1,2,3,4,5,6]),
+            output: .init(
+                onProduct: { [weak self] in
+                    self?.currentRouter.push(Route.product(id: $0))
                 }
             )
         )

+ 3 - 1
CoordinatorSUIExamples/CoordinatorSUIExamples/Modules/Cart/CartBuilder.swift

@@ -9,10 +9,12 @@ import SwiftUI
 
 struct CartBuilder {
 
+    typealias Input = CartVM.Input
     typealias Output = CartVM.Output
 
-    func build(with output: Output) -> some View {
+    func build(with input: Input, output: Output) -> some View {
         let vm = CartVM(
+            input: input,
             output: output
         )
         return CartView().environment(vm)

+ 8 - 2
CoordinatorSUIExamples/CoordinatorSUIExamples/Modules/Cart/CartVM.swift

@@ -10,13 +10,19 @@ import SwiftUI
 @Observable
 final class CartVM {
 
+    struct Input {
+        let products: [Int]
+    }
+
     struct Output {
-        var onProducts: Action?
+        var onProduct: IntAction?
     }
 
+    let input: Input
     let output: Output
 
-    init(output: Output) {
+    init(input: Input, output: Output) {
+        self.input = input
         self.output = output
     }
 }

+ 5 - 3
CoordinatorSUIExamples/CoordinatorSUIExamples/Modules/Cart/CartView.swift

@@ -14,8 +14,10 @@ struct CartView: View {
         VStack {
             Text("Cart")
             Spacer()
-            Button("Products") {
-                vm.output.onProducts?()
+            ForEach(vm.input.products, id: \.self) { productId in
+                Button("Product #\(productId)") {
+                    vm.output.onProduct?(productId)
+                }
             }
         }
         .padding()
@@ -23,5 +25,5 @@ struct CartView: View {
 }
 
 #Preview {
-    CartBuilder().build(with: .init())
+    CartBuilder().build(with: .init(products: [1, 2, 3, 4, 5, 6, 6, 7, 8, 9, 10]), output: .init())
 }