Ver Fonte

Implement DeeplinksCoordinator to always present screens by deeplinks received

Pavel Yurchenko há 1 ano atrás
pai
commit
c827060d0f

+ 4 - 0
CoordinatorSUI/Sources/CoordinatorSUI/BaseCoordinator.swift

@@ -44,9 +44,13 @@ open class BaseCoordinator: Coordinator, ObservableObject {
         _ = childCoordinators.popLast()
     }
 
+    // MARK: - Lifecycle
+
     public init() { }
 
     deinit {
         print("\(self.self) deinit")
     }
+
+    public func onDismissPresentation() { }
 }

+ 16 - 0
CoordinatorSUIExamples/CoordinatorSUIExamples/Application/ApplicationCoordinator.swift

@@ -23,14 +23,30 @@ final class ApplicationCoordinator: BaseCoordinator {
     let mainCoordinator = MainCoordinator()
     let productsCoordinator = ProductsCoordinator()
     let feedbackCoordinator = FeedbackCoordinator()
+    let deeplinksCoordinator = DeeplinksCoordinator()
+
+    // MARK: - Private properties
 
     private var cancellables = Set<AnyCancellable>()
 
+    // MARK: - Lifecycle
+
     override init() {
         super.init()
         setupBindings()
     }
 
+    func simulateDeeplink() {
+        let link = [
+            "example://cart",
+            "example://products",
+            "example://product/1"
+        ].randomElement()
+        self.deeplinksCoordinator.run(link)
+    }
+
+    // MARK: - Private methods
+
     private func setupBindings() {
         $tabSelection.sink { tab in
             print("\(tab) tab selected")

+ 46 - 0
CoordinatorSUIExamples/CoordinatorSUIExamples/Application/DeeplinksCoordinator.swift

@@ -0,0 +1,46 @@
+//
+//  DeeplinksCoordinator.swift
+//  CoordinatorSUIExamples
+//
+//  Created by Pavel Yurchenko on 05.12.2024.
+//
+
+import CoordinatorSUI
+import SwiftUI
+
+final class DeeplinksCoordinator: BaseCoordinator {
+
+    @Published
+    var modalPresentation: Route?
+
+    func run(_ link: String?) {
+        guard
+            let link,
+            let url = URL(string: link)
+        else {
+            alertPresenter.showSimpleAlert("Invalid deeplink!", action: {})
+            return
+        }
+
+        switch url.host {
+        case "products":
+            modalPresentation = .products
+        case "cart":
+            modalPresentation = .cart
+        default:
+            alertPresenter.showSimpleAlert("Deeplink \(link) is not supported", action: {})
+        }
+    }
+
+    @ViewBuilder
+    func buildPresentation(_ route: Route) -> some View {
+        switch route {
+        case .products:
+            ModalProductsNavigationView(ModalProductsCoordinator())
+        case .cart:
+            ModalCartNavigationView(ModalCartCoordinator())
+        default:
+            fatalError("This must not happen!")
+        }
+    }
+}

+ 17 - 1
CoordinatorSUIExamples/CoordinatorSUIExamples/Application/SUIExamplesApp.swift

@@ -16,8 +16,16 @@ struct SUIExamplesApp: App {
     @StateObject private var feedbackRouter = applicationCoordinator.feedbackCoordinator.currentRouter
     @StateObject private var appCoordinator = applicationCoordinator
 
+    @StateObject private var deeplinksCoordinator = applicationCoordinator.deeplinksCoordinator
+    @StateObject private var deeplinksAlertPresenter = applicationCoordinator.deeplinksCoordinator.alertPresenter
+
     var body: some Scene {
         WindowGroup {
+            HStack {
+                Button("Simulate deeplink") {
+                    appCoordinator.simulateDeeplink()
+                }
+            }
             VStack {
                 TabView(selection: $appCoordinator.tabSelection) {
                     Tab(ApplicationTab.main.rawValue, systemImage: "tray.and.arrow.down.fill", value: ApplicationTab.main) {
@@ -32,7 +40,15 @@ struct SUIExamplesApp: App {
                         FeedbackNavigationView(appCoordinator.feedbackCoordinator)
                     }
                 }
-            }
+            }.sheet(
+                item: $deeplinksCoordinator.modalPresentation,
+                onDismiss: deeplinksCoordinator.onDismissPresentation,
+                content: deeplinksCoordinator.buildPresentation
+            ).alert(
+                deeplinksAlertPresenter.title,
+                isPresented: $deeplinksAlertPresenter.isPresenting,
+                actions: deeplinksAlertPresenter.buildButtons
+            )
         }
     }
 }

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

@@ -11,7 +11,7 @@ import SwiftUI
 final class MainCoordinator: BaseCoordinator {
 
     @Published
-    var presentation: Route?
+    var modalPresentation: Route?
 
     func run() -> some View {
         showMainModule()
@@ -45,10 +45,6 @@ final class MainCoordinator: BaseCoordinator {
         }
     }
 
-    func onDismissPresentation() {
-
-    }
-
     // MARK: - Private methods
 
     private func showMainModule() -> some View {
@@ -67,10 +63,10 @@ final class MainCoordinator: BaseCoordinator {
                     self?.currentRouter.push(Route.feedback)
                 },
                 onModalProducts: { [weak self] in
-                    self?.presentation = .products
+                    self?.modalPresentation = .products
                 },
                 onModalCart: { [weak self] in
-                    self?.presentation = .cart
+                    self?.modalPresentation = .cart
                 },
                 onConfirmationDialog: { [weak self] in
                     self?.confirmationDialogPresenter.showDialog(
@@ -166,7 +162,7 @@ struct MainNavigationView: View {
                     destination: coordinator.buildDestination
                 )
         }.sheet(
-            item: $coordinator.presentation,
+            item: $coordinator.modalPresentation,
             onDismiss: coordinator.onDismissPresentation,
             content: coordinator.buildPresentation
         ).alert(