From 8ebe41f0e3d559bf69c709a827a2282003f25da0 Mon Sep 17 00:00:00 2001 From: Povilas Staskus <4062343+staskus@users.noreply.github.com> Date: Tue, 24 Sep 2024 11:42:28 +0300 Subject: [PATCH] Make calls to MainTabBarController through a protocol - Created MainTabBarControllerProtocol - Remove static methods - Always call MainTabBarController incorrectly through a protocol --- WooCommerce/Classes/AppDelegate.swift | 4 +- .../Epilogue/StorePickerCoordinator.swift | 2 +- .../BlazeLocalNotificationScheduler.swift | 2 +- ...iversalLinkRouter+JustInTimeMessages.swift | 2 +- .../Notifications/ApplicationAdapter.swift | 2 +- .../Classes/Spotlight/SpotlightManager.swift | 8 +- .../Universal Links/Routes/MyStoreRoute.swift | 2 +- .../Routes/OrderDetailsRoute.swift | 2 +- .../Universal Links/UniversalLinkRouter.swift | 2 +- .../Classes/ViewRelated/AppCoordinator.swift | 2 +- .../Customers/CustomerDetailViewModel.swift | 2 +- .../DashboardViewHostingController.swift | 4 +- .../Privacy/PrivacyBannerPresenter.swift | 4 +- .../ViewRelated/MainTabBarController.swift | 117 ++++++++---------- .../MainTabBarControllerProtocol.swift | 36 ++++++ .../AddOrderComponentsSection.swift | 2 +- .../WooCommerce.xcodeproj/project.pbxproj | 4 + .../System/TestingAppDelegate.swift | 4 +- .../MainTabBarControllerTests.swift | 4 +- 19 files changed, 116 insertions(+), 89 deletions(-) create mode 100644 WooCommerce/Classes/ViewRelated/MainTabBarControllerProtocol.swift diff --git a/WooCommerce/Classes/AppDelegate.swift b/WooCommerce/Classes/AppDelegate.swift index 440f3db1e99..54f38ca5a8f 100644 --- a/WooCommerce/Classes/AppDelegate.swift +++ b/WooCommerce/Classes/AppDelegate.swift @@ -42,7 +42,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { /// Tab Bar Controller /// - var tabBarController: MainTabBarController? { + var tabBarController: MainTabBarControllerProtocol? { appCoordinator?.tabBarController } @@ -203,7 +203,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { } switch quickAction { case QuickAction.addProduct: - MainTabBarController.presentAddProductFlow() + tabBarController.presentAddProductFlow() completionHandler(true) case QuickAction.addOrder: tabBarController.navigate(to: OrdersDestination.createOrder) diff --git a/WooCommerce/Classes/Authentication/Epilogue/StorePickerCoordinator.swift b/WooCommerce/Classes/Authentication/Epilogue/StorePickerCoordinator.swift index 644165d63c4..1c371016390 100644 --- a/WooCommerce/Classes/Authentication/Epilogue/StorePickerCoordinator.swift +++ b/WooCommerce/Classes/Authentication/Epilogue/StorePickerCoordinator.swift @@ -115,7 +115,7 @@ private extension StorePickerCoordinator { switchStoreUseCase.switchStore(with: storeID) { [weak self] siteChanged in guard let self = self else { return } if self.selectedConfiguration == .login { - MainTabBarController.switchToMyStoreTab(animated: true) + AppDelegate.shared.tabBarController?.switchToMyStoreTab(animated: true) } if siteChanged { diff --git a/WooCommerce/Classes/Blaze/BlazeLocalNotificationScheduler.swift b/WooCommerce/Classes/Blaze/BlazeLocalNotificationScheduler.swift index bfbb6b92111..b5d536d24ca 100644 --- a/WooCommerce/Classes/Blaze/BlazeLocalNotificationScheduler.swift +++ b/WooCommerce/Classes/Blaze/BlazeLocalNotificationScheduler.swift @@ -141,7 +141,7 @@ private extension DefaultBlazeLocalNotificationScheduler { guard let self, await isEligibleForBlaze() else { return } - MainTabBarController.navigateToBlazeCampaignCreation(for: siteID) + AppDelegate.shared.tabBarController?.navigateToBlazeCampaignCreation(for: siteID) } } } diff --git a/WooCommerce/Classes/JustInTimeMessages/UniversalLinkRouter+JustInTimeMessages.swift b/WooCommerce/Classes/JustInTimeMessages/UniversalLinkRouter+JustInTimeMessages.swift index 308e3eed8a8..ce46ff50431 100644 --- a/WooCommerce/Classes/JustInTimeMessages/UniversalLinkRouter+JustInTimeMessages.swift +++ b/WooCommerce/Classes/JustInTimeMessages/UniversalLinkRouter+JustInTimeMessages.swift @@ -2,7 +2,7 @@ import Foundation import Combine extension UniversalLinkRouter { - static func justInTimeMessagesUniversalLinkRouter(tabBarController: MainTabBarController?, + static func justInTimeMessagesUniversalLinkRouter(tabBarController: MainTabBarControllerProtocol?, urlOpener: URLOpener) -> UniversalLinkRouter { UniversalLinkRouter(routes: Self.defaultRoutes(navigator: tabBarController), bouncingURLOpener: urlOpener, diff --git a/WooCommerce/Classes/Notifications/ApplicationAdapter.swift b/WooCommerce/Classes/Notifications/ApplicationAdapter.swift index 09c72f8ea5a..c7f4f3479f6 100644 --- a/WooCommerce/Classes/Notifications/ApplicationAdapter.swift +++ b/WooCommerce/Classes/Notifications/ApplicationAdapter.swift @@ -33,7 +33,7 @@ extension UIApplication: ApplicationAdapter { /// Presents the Details for the specified Notification /// func presentNotificationDetails(notification: WooCommerce.PushNotification) { - MainTabBarController.switchStoreIfNeededAndPresentNotificationDetails(notification: notification) + AppDelegate.shared.tabBarController?.switchStoreIfNeededAndPresentNotificationDetails(notification: notification) } /// Presents a given Message with an "In App" notification diff --git a/WooCommerce/Classes/Spotlight/SpotlightManager.swift b/WooCommerce/Classes/Spotlight/SpotlightManager.swift index 68308c4e929..5974ee1e4e5 100644 --- a/WooCommerce/Classes/Spotlight/SpotlightManager.swift +++ b/WooCommerce/Classes/Spotlight/SpotlightManager.swift @@ -6,16 +6,16 @@ struct SpotlightManager { var type: WooActivityType? switch userActivity.activityType { case WooActivityType.dashboard.rawValue: - MainTabBarController.switchToMyStoreTab() + AppDelegate.shared.tabBarController?.switchToMyStoreTab(animated: false) type = WooActivityType.dashboard case WooActivityType.orders.rawValue: - MainTabBarController.switchToOrdersTab() + AppDelegate.shared.tabBarController?.switchToOrdersTab(completion: nil) type = WooActivityType.orders case WooActivityType.products.rawValue: - MainTabBarController.switchToProductsTab() + AppDelegate.shared.tabBarController?.switchToProductsTab(completion: nil) type = WooActivityType.products case WooActivityType.payments.rawValue: - MainTabBarController.presentPayments() + AppDelegate.shared.tabBarController?.presentPayments() type = WooActivityType.payments default: break diff --git a/WooCommerce/Classes/Universal Links/Routes/MyStoreRoute.swift b/WooCommerce/Classes/Universal Links/Routes/MyStoreRoute.swift index a5b0d0807e5..90897c390a4 100644 --- a/WooCommerce/Classes/Universal Links/Routes/MyStoreRoute.swift +++ b/WooCommerce/Classes/Universal Links/Routes/MyStoreRoute.swift @@ -9,7 +9,7 @@ struct MyStoreRoute: Route { } func perform(for subPath: String, with parameters: [String: String]) -> Bool { - MainTabBarController.switchToMyStoreTab() + AppDelegate.shared.tabBarController?.switchToMyStoreTab(animated: false) return true } diff --git a/WooCommerce/Classes/Universal Links/Routes/OrderDetailsRoute.swift b/WooCommerce/Classes/Universal Links/Routes/OrderDetailsRoute.swift index 80a4d0a3f91..a62d8b7b4f0 100644 --- a/WooCommerce/Classes/Universal Links/Routes/OrderDetailsRoute.swift +++ b/WooCommerce/Classes/Universal Links/Routes/OrderDetailsRoute.swift @@ -20,7 +20,7 @@ struct OrderDetailsRoute: Route { return false } - MainTabBarController.navigateToOrderDetails(with: orderId, siteID: storeId) + AppDelegate.shared.tabBarController?.navigateToOrderDetails(with: orderId, siteID: storeId) return true } diff --git a/WooCommerce/Classes/Universal Links/UniversalLinkRouter.swift b/WooCommerce/Classes/Universal Links/UniversalLinkRouter.swift index 93f65b2ff5b..de660202ee5 100644 --- a/WooCommerce/Classes/Universal Links/UniversalLinkRouter.swift +++ b/WooCommerce/Classes/Universal Links/UniversalLinkRouter.swift @@ -46,7 +46,7 @@ struct UniversalLinkRouter { return false } - static func defaultUniversalLinkRouter(tabBarController: MainTabBarController) -> UniversalLinkRouter { + static func defaultUniversalLinkRouter(tabBarController: MainTabBarControllerProtocol) -> UniversalLinkRouter { UniversalLinkRouter(routes: UniversalLinkRouter.defaultRoutes(navigator: tabBarController)) } diff --git a/WooCommerce/Classes/ViewRelated/AppCoordinator.swift b/WooCommerce/Classes/ViewRelated/AppCoordinator.swift index 2549a3c4293..0a9e5f1fa52 100644 --- a/WooCommerce/Classes/ViewRelated/AppCoordinator.swift +++ b/WooCommerce/Classes/ViewRelated/AppCoordinator.swift @@ -8,7 +8,7 @@ import protocol Storage.StorageManagerType import protocol WooFoundation.Analytics final class AppCoordinator { - let tabBarController: MainTabBarController + let tabBarController: MainTabBarControllerProtocol private let window: UIWindow private let stores: StoresManager diff --git a/WooCommerce/Classes/ViewRelated/Customers/CustomerDetailViewModel.swift b/WooCommerce/Classes/ViewRelated/Customers/CustomerDetailViewModel.swift index a53c02f17e0..2dcd60808db 100644 --- a/WooCommerce/Classes/ViewRelated/Customers/CustomerDetailViewModel.swift +++ b/WooCommerce/Classes/ViewRelated/Customers/CustomerDetailViewModel.swift @@ -167,7 +167,7 @@ final class CustomerDetailViewModel: ObservableObject { guard canCreateNewOrder else { return } - MainTabBarController.presentOrderCreationFlow(for: customerID, billing: billing, shipping: shipping) + AppDelegate.shared.tabBarController?.presentOrderCreationFlow(for: customerID, billing: billing, shipping: shipping) ServiceLocator.analytics.track(event: .CustomersHub.customerDetailNewOrder()) } } diff --git a/WooCommerce/Classes/ViewRelated/Dashboard/DashboardViewHostingController.swift b/WooCommerce/Classes/ViewRelated/Dashboard/DashboardViewHostingController.swift index bf3f99f7f25..d2edbb4567b 100644 --- a/WooCommerce/Classes/ViewRelated/Dashboard/DashboardViewHostingController.swift +++ b/WooCommerce/Classes/ViewRelated/Dashboard/DashboardViewHostingController.swift @@ -303,12 +303,12 @@ private extension DashboardViewHostingController { private extension DashboardViewHostingController { func configureLastOrdersView() { rootView.onViewAllOrders = { - MainTabBarController.switchToOrdersTab() + AppDelegate.shared.tabBarController?.switchToOrdersTab(completion: nil) } rootView.onViewOrderDetail = { [weak self] order in guard let self else { return } - MainTabBarController.navigateToOrderDetails(with: order.orderID, siteID: viewModel.siteID) + AppDelegate.shared.tabBarController?.navigateToOrderDetails(with: order.orderID, siteID: viewModel.siteID) } } } diff --git a/WooCommerce/Classes/ViewRelated/Dashboard/Settings/Privacy/PrivacyBannerPresenter.swift b/WooCommerce/Classes/ViewRelated/Dashboard/Settings/Privacy/PrivacyBannerPresenter.swift index 464b8886379..9d3f5f4cd98 100644 --- a/WooCommerce/Classes/ViewRelated/Dashboard/Settings/Privacy/PrivacyBannerPresenter.swift +++ b/WooCommerce/Classes/ViewRelated/Dashboard/Settings/Privacy/PrivacyBannerPresenter.swift @@ -45,7 +45,7 @@ final class PrivacyBannerPresenter { case .success(let destination): viewController.dismiss(animated: true) if destination == .settings { - MainTabBarController.navigateToPrivacySettings() + AppDelegate.shared.tabBarController?.navigateToPrivacySettings() } case .failure(let error): @@ -57,7 +57,7 @@ final class PrivacyBannerPresenter { /// Even if we fail, we should redirect the user to settings screen so they can further customize their privacy settings /// if intendedDestination == .settings { - MainTabBarController.navigateToPrivacySettings() + AppDelegate.shared.tabBarController?.navigateToPrivacySettings() } } } diff --git a/WooCommerce/Classes/ViewRelated/MainTabBarController.swift b/WooCommerce/Classes/ViewRelated/MainTabBarController.swift index 6e7638f1178..fc0615ad2bb 100644 --- a/WooCommerce/Classes/ViewRelated/MainTabBarController.swift +++ b/WooCommerce/Classes/ViewRelated/MainTabBarController.swift @@ -60,7 +60,7 @@ extension WooTab { /// /// TODO Migrate the `viewControllers` management from `Main.storyboard` to here (as code). /// -final class MainTabBarController: UITabBarController { +final class MainTabBarController: UITabBarController, MainTabBarControllerProtocol { /// For picking up the child view controller's status bar styling /// - returns: nil to let the tab bar control styling or `children.first` for VC control. @@ -306,28 +306,28 @@ extension MainTabBarController { /// Switches to the My Store tab and pops to the root view controller /// - static func switchToMyStoreTab(animated: Bool = false) { + func switchToMyStoreTab(animated: Bool = false) { navigateTo(.myStore, animated: animated) } /// Switches to the Orders tab and pops to the root view controller /// - static func switchToOrdersTab(completion: (() -> Void)? = nil) { + func switchToOrdersTab(completion: (() -> Void)? = nil) { navigateTo(.orders, completion: completion) } /// Switches to the Products tab and pops to the root view controller /// - static func switchToProductsTab(completion: (() -> Void)? = nil) { + func switchToProductsTab(completion: (() -> Void)? = nil) { navigateTo(.products, completion: completion) } /// Switches to the Hub Menu tab and pops to the root view controller /// - static func switchToHubMenuTab(completion: ((HubMenuViewController?) -> Void)? = nil) { + func switchToHubMenuTab(completion: ((HubMenuViewController?) -> Void)? = nil) { navigateTo(.hubMenu, completion: { - let hubMenuViewController: HubMenuViewController? = { - guard let hubMenuTabController = childViewController() as? TabContainerController, + let hubMenuViewController: HubMenuViewController? = { [weak self] in + guard let hubMenuTabController = self?.childViewController() as? TabContainerController, let navigationController = hubMenuTabController.wrappedController as? UINavigationController, let hubMenuViewController = navigationController.topViewController as? HubMenuViewController else { DDLogError("⛔️ Could not switch to the Hub Menu") @@ -339,20 +339,9 @@ extension MainTabBarController { }) } - /// Switches the TabBarController to the specified Tab - /// - private static func navigateTo(_ tab: WooTab, animated: Bool = false, completion: (() -> Void)? = nil) { - guard let tabBar = AppDelegate.shared.tabBarController else { - return - } - - tabBar.navigateTo(tab, animated: animated, completion: completion) - } - /// Returns the "Top Visible Child" of the specified type /// - private static func childViewController() -> T? { - let selectedViewController = AppDelegate.shared.tabBarController?.selectedViewController + private func childViewController() -> T? { guard let navController = selectedViewController as? UINavigationController else { return selectedViewController as? T } @@ -368,38 +357,39 @@ extension MainTabBarController { /// Syncs the notification given the ID, and handles the notification based on its notification kind. /// - static func presentNotificationDetails(for noteID: Int64) { - let action = NotificationAction.synchronizeNotification(noteID: noteID) { note, error in - guard let note = note, + func presentNotificationDetails(for noteID: Int64) { + let action = NotificationAction.synchronizeNotification(noteID: noteID) { [weak self] note, error in + guard let self, + let note = note, let siteID = note.meta.identifier(forKey: .site) else { return } showStore(with: Int64(siteID), onCompletion: { _ in - presentNotificationDetails(for: note) + self.presentNotificationDetails(for: note) }) } ServiceLocator.stores.dispatch(action) } /// Presents the details of a push notification. - static func switchStoreIfNeededAndPresentNotificationDetails(notification: WooCommerce.PushNotification) { + func switchStoreIfNeededAndPresentNotificationDetails(notification: WooCommerce.PushNotification) { guard let note = notification.note, let siteID = note.meta.identifier(forKey: .site) else { presentNotificationDetails(for: notification.noteID) return } - showStore(with: Int64(siteID), onCompletion: { _ in - presentNotificationDetails(for: note) + showStore(with: Int64(siteID), onCompletion: { [weak self] _ in + self?.presentNotificationDetails(for: note) }) } /// Presents the order details if the `note` is for an order push notification. /// - private static func presentNotificationDetails(for note: Note) { + private func presentNotificationDetails(for note: Note) { switch note.kind { case .storeOrder: - switchToOrdersTab { - ordersTabSplitViewWrapper()?.presentDetails(for: note) + switchToOrdersTab { [weak self] in + self?.ordersTabSplitViewWrapper()?.presentDetails(for: note) } case .blazeApprovedNote, .blazeRejectedNote, .blazeCancelledNote, .blazePerformedNote: navigateToBlazeCampaignDetails(using: note) @@ -411,7 +401,7 @@ extension MainTabBarController { "already_read": note.read ]) } - private static func showStore(with siteID: Int64, onCompletion: @escaping (Bool) -> Void) { + private func showStore(with siteID: Int64, onCompletion: @escaping (Bool) -> Void) { let stores = ServiceLocator.stores // Already showing that store, do nothing @@ -432,12 +422,13 @@ extension MainTabBarController { } } - static func presentAddProductFlow() { - switchToProductsTab { - let tabBar = AppDelegate.shared.tabBarController - let productsContainerController = tabBar?.productsContainerController + func presentAddProductFlow() { + switchToProductsTab { [weak self] in + guard let self else { return } - guard let productsSplitViewWrapperController = productsContainerController?.wrappedController as? ProductsSplitViewWrapperController else { + let productsContainerController = productsContainerController + + guard let productsSplitViewWrapperController = productsContainerController.wrappedController as? ProductsSplitViewWrapperController else { return } @@ -445,8 +436,9 @@ extension MainTabBarController { } } - static func navigateToOrderDetails(with orderID: Int64, siteID: Int64) { - showStore(with: siteID, onCompletion: { storeIsShown in + func navigateToOrderDetails(with orderID: Int64, siteID: Int64) { + showStore(with: siteID, onCompletion: { [weak self] storeIsShown in + guard let self else { return } switchToOrdersTab { // It failed to show the order's store. We navigate to the orders tab and stop, as we cannot show the order details screen guard storeIsShown else { @@ -454,13 +446,13 @@ extension MainTabBarController { } DispatchQueue.main.asyncAfter(deadline: .now() + Constants.screenTransitionsDelay) { - presentDetails(for: orderID, siteID: siteID) + self.presentDetails(for: orderID, siteID: siteID) } } }) } - static func navigateToBlazeCampaignDetails(using note: Note) { + func navigateToBlazeCampaignDetails(using note: Note) { guard note.kind.isBlaze else { return } @@ -475,41 +467,43 @@ extension MainTabBarController { return } - showStore(with: Int64(siteID), onCompletion: { storeIsShown in + showStore(with: Int64(siteID), onCompletion: { [weak self] storeIsShown in // It failed to show the campaign's store. - guard storeIsShown else { + guard let self, + storeIsShown else { return } DispatchQueue.main.asyncAfter(deadline: .now() + Constants.blazeScreenTransitionsDelay) { - switchToHubMenuTab() { hubMenuViewController in + self.switchToHubMenuTab() { hubMenuViewController in hubMenuViewController?.showBlazeCampaign("\(campaignID)") } } }) } - static func navigateToBlazeCampaignCreation(for siteID: Int64) { - showStore(with: Int64(siteID), onCompletion: { storeIsShown in + func navigateToBlazeCampaignCreation(for siteID: Int64) { + showStore(with: Int64(siteID), onCompletion: { [weak self] storeIsShown in // It failed to show the campaign's store. - guard storeIsShown else { + guard let self, storeIsShown else { return } DispatchQueue.main.asyncAfter(deadline: .now() + Constants.blazeScreenTransitionsDelay) { - switchToHubMenuTab() { hubMenuViewController in + self.switchToHubMenuTab() { hubMenuViewController in hubMenuViewController?.showBlazeCampaignCreation() } } }) } - static func presentOrderCreationFlow(for customerID: Int64, billing: Address?, shipping: Address?) { - switchToOrdersTab { - let tabBar = AppDelegate.shared.tabBarController - let ordersContainerController = tabBar?.ordersContainerController + func presentOrderCreationFlow(for customerID: Int64, billing: Address?, shipping: Address?) { + switchToOrdersTab { [weak self] in + guard let self else { return } + + let ordersContainerController = ordersContainerController - guard let ordersSplitViewWrapperController = ordersContainerController?.wrappedController as? OrdersSplitViewWrapperController else { + guard let ordersSplitViewWrapperController = ordersContainerController.wrappedController as? OrdersSplitViewWrapperController else { return } @@ -517,11 +511,11 @@ extension MainTabBarController { } } - private static func presentDetails(for orderID: Int64, siteID: Int64) { + private func presentDetails(for orderID: Int64, siteID: Int64) { ordersTabSplitViewWrapper()?.presentDetails(for: orderID, siteID: siteID) } - private static func ordersTabSplitViewWrapper() -> OrdersSplitViewWrapperController? { + private func ordersTabSplitViewWrapper() -> OrdersSplitViewWrapperController? { guard let ordersTabController = childViewController() as? TabContainerController, let ordersSplitViewWrapperController = ordersTabController.wrappedController as? OrdersSplitViewWrapperController else { return nil @@ -529,13 +523,13 @@ extension MainTabBarController { return ordersSplitViewWrapperController } - static func presentPayments() { + func presentPayments() { switchToHubMenuTab() { hubMenuViewController in hubMenuViewController?.showPaymentsMenu() } } - static func presentCoupons() { + func presentCoupons() { switchToHubMenuTab() { hubMenuViewController in hubMenuViewController?.showCoupons() } @@ -543,18 +537,11 @@ extension MainTabBarController { /// Switches to the hub Menu & Navigates to the Privacy Settings Screen. /// - static func navigateToPrivacySettings() { + func navigateToPrivacySettings() { switchToHubMenuTab { hubMenuViewController in hubMenuViewController?.showPrivacySettings() } } - - static func presentCollectPayment() { - guard let tabBar = AppDelegate.shared.tabBarController else { - return - } - tabBar.presentCollectPayment() - } } // MARK: - DeeplinkForwarder @@ -568,8 +555,8 @@ extension MainTabBarController: DeepLinkNavigator { self?.hubMenuTabCoordinator?.navigate(to: destination) } case is OrdersDestination: - navigateTo(.orders) { - Self.ordersTabSplitViewWrapper()?.navigate(to: destination) + navigateTo(.orders) { [weak self] in + self?.ordersTabSplitViewWrapper()?.navigate(to: destination) } default: return diff --git a/WooCommerce/Classes/ViewRelated/MainTabBarControllerProtocol.swift b/WooCommerce/Classes/ViewRelated/MainTabBarControllerProtocol.swift new file mode 100644 index 00000000000..adccab33e67 --- /dev/null +++ b/WooCommerce/Classes/ViewRelated/MainTabBarControllerProtocol.swift @@ -0,0 +1,36 @@ +import UIKit +import Combine +import Yosemite + +protocol MainTabBarControllerProtocol: UIViewController, UIViewControllerTransitioningDelegate, DeepLinkNavigator { + // Properties + var childForStatusBarStyle: UIViewController? { get } + var preferredStatusBarStyle: UIStatusBarStyle { get } + + // Methods + func navigateTo(_ tab: WooTab, animated: Bool, completion: (() -> Void)?) + func navigateToTabWithViewController(_ tab: WooTab, animated: Bool, completion: ((UIViewController) -> Void)?) + func removeViewControllers() + func presentCollectPayment() + + func switchToMyStoreTab(animated: Bool) + func switchToOrdersTab(completion: (() -> Void)?) + func switchToProductsTab(completion: (() -> Void)?) + func switchToHubMenuTab(completion: ((HubMenuViewController?) -> Void)?) + func presentNotificationDetails(for noteID: Int64) + func switchStoreIfNeededAndPresentNotificationDetails(notification: WooCommerce.PushNotification) + func presentAddProductFlow() + func navigateToOrderDetails(with orderID: Int64, siteID: Int64) + func navigateToBlazeCampaignDetails(using note: Note) + func navigateToBlazeCampaignCreation(for siteID: Int64) + func presentOrderCreationFlow(for customerID: Int64, billing: Address?, shipping: Address?) + func presentPayments() + func presentCoupons() + func navigateToPrivacySettings() + + // Protocol Methods + func navigate(to destination: any DeepLinkDestinationProtocol) + func presentationController(forPresented presented: UIViewController, + presenting: UIViewController?, + source: UIViewController) -> UIPresentationController? +} diff --git a/WooCommerce/Classes/ViewRelated/Orders/Order Creation/AddOrderComponentsSection/AddOrderComponentsSection.swift b/WooCommerce/Classes/ViewRelated/Orders/Order Creation/AddOrderComponentsSection/AddOrderComponentsSection.swift index a2d9526a56d..a7e2f0b4088 100644 --- a/WooCommerce/Classes/ViewRelated/Orders/Order Creation/AddOrderComponentsSection/AddOrderComponentsSection.swift +++ b/WooCommerce/Classes/ViewRelated/Orders/Order Creation/AddOrderComponentsSection/AddOrderComponentsSection.swift @@ -106,7 +106,7 @@ private extension AddOrderComponentsSection { message: Text(Localization.goToCouponsAlertMessage), primaryButton: .default(Text(Localization.goToCouponsAlertButtonTitle), action: { viewModel.onGoToCouponsClosure() - MainTabBarController.presentCoupons() + AppDelegate.shared.tabBarController?.presentCoupons() }), secondaryButton: .cancel()) }) diff --git a/WooCommerce/WooCommerce.xcodeproj/project.pbxproj b/WooCommerce/WooCommerce.xcodeproj/project.pbxproj index 255f003d669..9efac97fc72 100644 --- a/WooCommerce/WooCommerce.xcodeproj/project.pbxproj +++ b/WooCommerce/WooCommerce.xcodeproj/project.pbxproj @@ -24,6 +24,7 @@ 010C9A8F2C75C2BF00EBA228 /* Color+Inverted.swift in Sources */ = {isa = PBXBuildFile; fileRef = 010C9A8E2C75C2BF00EBA228 /* Color+Inverted.swift */; }; 011DF3442C53A5CF000AFDD9 /* PointOfSaleCardPresentPaymentValidatingOrderMessageViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 011DF3432C53A5CF000AFDD9 /* PointOfSaleCardPresentPaymentValidatingOrderMessageViewModel.swift */; }; 011DF3462C53A919000AFDD9 /* PointOfSaleCardPresentPaymentActivityIndicatingMessageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 011DF3452C53A919000AFDD9 /* PointOfSaleCardPresentPaymentActivityIndicatingMessageView.swift */; }; + 012006152CA2A5000091F0FB /* MainTabBarControllerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 012006142CA2A5000091F0FB /* MainTabBarControllerProtocol.swift */; }; 014BD4B82C64E2BA0011A66E /* PointOfSaleOrderSyncErrorMessageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 014BD4B72C64E2BA0011A66E /* PointOfSaleOrderSyncErrorMessageView.swift */; }; 014BD4BA2C64FC0E0011A66E /* PointOfSaleOrderSyncErrorMessageViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 014BD4B92C64FC0E0011A66E /* PointOfSaleOrderSyncErrorMessageViewModel.swift */; }; 0157A9962C4FEA7200866FFD /* PointOfSaleLoadingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0157A9952C4FEA7200866FFD /* PointOfSaleLoadingView.swift */; }; @@ -3114,6 +3115,7 @@ 010C9A8E2C75C2BF00EBA228 /* Color+Inverted.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Color+Inverted.swift"; sourceTree = ""; }; 011DF3432C53A5CF000AFDD9 /* PointOfSaleCardPresentPaymentValidatingOrderMessageViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PointOfSaleCardPresentPaymentValidatingOrderMessageViewModel.swift; sourceTree = ""; }; 011DF3452C53A919000AFDD9 /* PointOfSaleCardPresentPaymentActivityIndicatingMessageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PointOfSaleCardPresentPaymentActivityIndicatingMessageView.swift; sourceTree = ""; }; + 012006142CA2A5000091F0FB /* MainTabBarControllerProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainTabBarControllerProtocol.swift; sourceTree = ""; }; 014BD4B72C64E2BA0011A66E /* PointOfSaleOrderSyncErrorMessageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PointOfSaleOrderSyncErrorMessageView.swift; sourceTree = ""; }; 014BD4B92C64FC0E0011A66E /* PointOfSaleOrderSyncErrorMessageViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PointOfSaleOrderSyncErrorMessageViewModel.swift; sourceTree = ""; }; 0157A9952C4FEA7200866FFD /* PointOfSaleLoadingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PointOfSaleLoadingView.swift; sourceTree = ""; }; @@ -10251,6 +10253,7 @@ CE63023B2BAAEF0800E3325C /* Customers */, 3F587020281B9494004F7556 /* LaunchScreen.storyboard */, 3F58701E281B947E004F7556 /* Main.storyboard */, + 012006142CA2A5000091F0FB /* MainTabBarControllerProtocol.swift */, CE263DE7206ACE3E0015A693 /* MainTabBarController.swift */, D8736B5222EF4F5900A14A29 /* NotificationsBadgeController.swift */, 025FA38A2522CB4D0054CA57 /* AppCoordinator.swift */, @@ -15710,6 +15713,7 @@ 0263E3BB290BB21800E5F88F /* WooAnalyticsEvent+StoreCreation.swift in Sources */, 4A68E3E32941D4CE004AC3DC /* WordPressLibraryLogger.swift in Sources */, 174CA86E27DBFD2D00126524 /* ShareAppTextItemActivitySource.swift in Sources */, + 012006152CA2A5000091F0FB /* MainTabBarControllerProtocol.swift in Sources */, 262C921F26EEF8B100011F92 /* Binding.swift in Sources */, CE14DEE82C3D8D1D002A90B5 /* GoogleAdsCampaignReportCard.swift in Sources */, DE4FB7732812AE96003D20D6 /* FilterListView.swift in Sources */, diff --git a/WooCommerce/WooCommerceTests/System/TestingAppDelegate.swift b/WooCommerce/WooCommerceTests/System/TestingAppDelegate.swift index fee227eed35..e2659d3954a 100644 --- a/WooCommerce/WooCommerceTests/System/TestingAppDelegate.swift +++ b/WooCommerce/WooCommerceTests/System/TestingAppDelegate.swift @@ -5,9 +5,9 @@ import Yosemite @objc(TestingAppDelegate) class TestingAppDelegate: AppDelegate { /// Enables mocking of `tabBarController` property in unit tests. It is strongly recommended to reset it back to `nil` after each test case that sets this. - static var mockTabBarController: MainTabBarController? + static var mockTabBarController: MainTabBarControllerProtocol? - override var tabBarController: MainTabBarController? { + override var tabBarController: MainTabBarControllerProtocol? { Self.mockTabBarController ?? super.tabBarController } diff --git a/WooCommerce/WooCommerceTests/ViewRelated/MainTabBarControllerTests.swift b/WooCommerce/WooCommerceTests/ViewRelated/MainTabBarControllerTests.swift index 578d2239ac4..f51f8b3c18d 100644 --- a/WooCommerce/WooCommerceTests/ViewRelated/MainTabBarControllerTests.swift +++ b/WooCommerce/WooCommerceTests/ViewRelated/MainTabBarControllerTests.swift @@ -484,7 +484,7 @@ final class MainTabBarControllerTests: XCTestCase { XCTAssertNotNil(tabBarController.view) // When - MainTabBarController.navigateToOrderDetails(with: 155, siteID: siteID) + tabBarController.navigateToOrderDetails(with: 155, siteID: siteID) waitUntil { tabBarController.selectedViewController is TabContainerController } @@ -527,7 +527,7 @@ final class MainTabBarControllerTests: XCTestCase { XCTAssertNotNil(tabBarController.view) // When - MainTabBarController.presentNotificationDetails(for: 1) + tabBarController.presentNotificationDetails(for: 1) waitUntil { tabBarController.selectedViewController is TabContainerController }