Просмотр исходного кода

Implement one module in UIKit and see how it integrates into current CoordinatorSUI flows

Pavel Yurchenko 1 год назад
Родитель
Сommit
0e1fecf18e

+ 1 - 0
CoordinatorSUIExamples/CoordinatorSUIExamples/Flows/Route.swift

@@ -14,6 +14,7 @@ enum Route: Hashable {
     case product(id: Int)
     case cart
     case feedback
+    case onboarding
 }
 
 extension Route: Identifiable {

+ 16 - 0
CoordinatorSUIExamples/CoordinatorSUIExamples/Flows/Tabs/MainCoordinator.swift

@@ -28,6 +28,8 @@ final class MainCoordinator: BaseCoordinator {
             showCartModule()
         case .feedback:
             showFeedbackModule()
+        case .onboarding:
+            showOnboardingModule()
         default:
             fatalError("This should not happen!")
         }
@@ -80,6 +82,9 @@ final class MainCoordinator: BaseCoordinator {
                             })
                         ]
                     )
+                },
+                onOnboarding: { [weak self] in
+                    self?.currentRouter.push(Route.onboarding)
                 }
             )
         )
@@ -136,6 +141,17 @@ final class MainCoordinator: BaseCoordinator {
     private func showFeedbackModule() -> some View {
         FeedbackBuilder().build(with: .init())
     }
+
+    private func showOnboardingModule() -> some View {
+        OnboardingBuilder().build(
+            with: .init(title: "Title from main", message: "Welcome message from Main", closeButtonTitle: "Закрыть"),
+            output: .init(
+                onClose: { [weak self] in
+                    self?.currentRouter.pop()
+                }
+            )
+        )
+    }
 }
 
 // MARK: - Navigation View

+ 1 - 0
CoordinatorSUIExamples/CoordinatorSUIExamples/Modules/Main/MainVM.swift

@@ -21,6 +21,7 @@ final class MainVM {
         var onModalProducts: Action?
         var onModalCart: Action?
         var onConfirmationDialog: Action?
+        var onOnboarding: Action?
     }
 
     let output: Output

+ 3 - 0
CoordinatorSUIExamples/CoordinatorSUIExamples/Modules/Main/MainView.swift

@@ -33,6 +33,9 @@ struct MainView: View {
             Button("Confirmation Dialog") {
                 vm.output.onConfirmationDialog?()
             }
+            Button("Onboarding") {
+                vm.output.onOnboarding?()
+            }
         }
         .padding()
     }

+ 25 - 0
CoordinatorSUIExamples/CoordinatorSUIExamples/Modules/Onboarding/OnboardingBuilder.swift

@@ -0,0 +1,25 @@
+//
+//  OnboardingBuilder.swift
+//  CoordinatorSUIExamples
+//
+//  Created by Pavel Yurchenko on 05.12.2024.
+//
+
+import SwiftUI
+import UIKit
+
+struct OnboardingBuilder {
+
+    typealias Input = OnboardingVM.Input
+    typealias Output = OnboardingVM.Output
+
+    func buildViewController(with input: Input, output: Output) -> OnboardingViewController {
+        let viewController = OnboardingViewController()
+        viewController.viewModel = OnboardingVM(input: input, output: output)
+        return viewController
+    }
+
+    func build(with input: Input, output: Output) -> some View {
+        OnboardingView(with: input, output: output)
+    }
+}

+ 32 - 0
CoordinatorSUIExamples/CoordinatorSUIExamples/Modules/Onboarding/OnboardingVM.swift

@@ -0,0 +1,32 @@
+//
+//  OnboardingVM.swift
+//  CoordinatorSUIExamples
+//
+//  Created by Pavel Yurchenko on 05.12.2024.
+//
+
+final class OnboardingVM {
+
+    struct Input {
+        let title: String
+        let message: String
+        let closeButtonTitle: String
+    }
+
+    struct Output {
+        let onClose: Action?
+    }
+
+    var title: String { input.title }
+    var message: String { input.message }
+    var closeButtonTitle: String { input.closeButtonTitle }
+
+    let output: Output
+
+    private let input: Input
+
+    init(input: Input, output: Output) {
+        self.input = input
+        self.output = output
+    }
+}

+ 34 - 0
CoordinatorSUIExamples/CoordinatorSUIExamples/Modules/Onboarding/OnboardingView.swift

@@ -0,0 +1,34 @@
+//
+//  OnboardingView.swift
+//  CoordinatorSUIExamples
+//
+//  Created by Pavel Yurchenko on 05.12.2024.
+//
+
+import SwiftUI
+import UIKit
+
+struct OnboardingView: UIViewControllerRepresentable {
+    typealias UIViewControllerType = OnboardingViewController
+    typealias Input = OnboardingBuilder.Input
+    typealias Output = OnboardingBuilder.Output
+
+    private let input: Input
+    private let output: Output
+
+    init(with input: Input, output: Output) {
+        self.input = input
+        self.output = output
+    }
+
+    func makeUIViewController(context: Context) -> OnboardingViewController {
+        OnboardingBuilder().buildViewController(
+            with: input,
+            output: output
+        )
+    }
+    
+    func updateUIViewController(_ uiViewController: OnboardingViewController, context: Context) {
+        // empty
+    }
+}

+ 55 - 0
CoordinatorSUIExamples/CoordinatorSUIExamples/Modules/Onboarding/OnboardingViewController.swift

@@ -0,0 +1,55 @@
+//
+//  OnboardingViewController.swift
+//  CoordinatorSUIExamples
+//
+//  Created by Pavel Yurchenko on 05.12.2024.
+//
+
+import UIKit
+
+final class OnboardingViewController: UIViewController {
+
+    var viewModel: OnboardingVM!
+
+    // MARK: - Outlets
+
+    private lazy var titleLabel = UILabel()
+
+    private lazy var messageLabel = UILabel()
+
+    private lazy var closeButton = UIButton(type: .system)
+
+    private lazy var stackView = UIStackView(arrangedSubviews: [titleLabel, messageLabel, closeButton])
+
+    // MRK: - Lifecycle
+
+    override func viewDidLoad() {
+        super.viewDidLoad()
+        setupUI()
+        setupLayout()
+    }
+
+    // MARK: - Private methods
+
+    @objc
+    private func onCloseButton() {
+        viewModel.output.onClose?()
+    }
+
+    private func setupUI() {
+        view.addSubview(stackView)
+
+        titleLabel.text = viewModel.title
+        messageLabel.text = viewModel.message
+        closeButton.setTitle(viewModel.closeButtonTitle, for: .normal)
+        closeButton.addTarget(self, action: #selector(onCloseButton), for: .touchUpInside)
+
+        stackView.axis = .vertical
+    }
+
+    private func setupLayout() {
+        stackView.translatesAutoresizingMaskIntoConstraints = false
+        stackView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
+        stackView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
+    }
+}