// // PopupQueueManager.swift // QuickLocation // // Created by 八条 on 2026/7/3. // import UIKit class PopupQueueManager { private weak var sourceVC: UIViewController? private var currentStep = 0 private var stepGeneration = 0 private var countdownTimer: Timer? private var isPaused = false init() { NotificationCenter.default.addObserver(self, selector: #selector(handlePause), name: .pausePopupQueue, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(handleResume), name: .resumePopupQueue, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(handleInvalidate), name: .invalidatePopupQueue, object: nil) } deinit { NotificationCenter.default.removeObserver(self) } func start(from vc: UIViewController) { sourceVC = vc currentStep = 0 executeNextStep() } @objc private func handlePause() { countdownTimer?.invalidate() countdownTimer = nil isPaused = true } @objc private func handleResume() { guard isPaused else { return } isPaused = false executeNextStep() } @objc private func handleInvalidate() { countdownTimer?.invalidate() countdownTimer = nil isPaused = true currentStep = 3 } private func executeNextStep() { guard AppContextManager.shared.systemConfig?.isIntercept == false else { return } switch currentStep { case 0: tryStartPromotionalActivities() case 1: tryStartSearchPopup() case 2: tryStartRegisterOrVipPopup() default: break } } // MARK: - Step 0: PromotionalActivities private func tryStartPromotionalActivities() { guard let config = AppContextManager.shared.systemConfig else { skipToNext() return } guard config.popupConfig?.pay_pop == true, AppContextManager.shared.vip == 1, let timeConfig = config.timeConfig else { skipToNext() return } let gen = stepGeneration startCountdown(seconds: timeConfig.pay_pop_time) { [weak self] in guard let self = self, self.currentStep == 0, self.stepGeneration == gen else { return } let vc = PromotionalActivitiesVC() vc.onDismiss = { [weak self] in self?.skipToNext() } self.push(vc) } } // MARK: - Step 1: Search PopupWindow private func tryStartSearchPopup() { guard let config = AppContextManager.shared.systemConfig else { skipToNext() return } guard config.popupConfig?.search_phone == true, let timeConfig = config.timeConfig else { skipToNext() return } let gen = stepGeneration startCountdown(seconds: timeConfig.search_phone) { guard self.currentStep == 1, self.stepGeneration == gen else { return } PopupWindow.show(popupType: .search) { self.skipToNext() } } } // MARK: - Step 2: Register or VIP PopupWindow (mutually exclusive) private func tryStartRegisterOrVipPopup() { guard let config = AppContextManager.shared.systemConfig, let timeConfig = config.timeConfig else { return } if AppContextManager.shared.isGuest { let gen = stepGeneration startCountdown(seconds: timeConfig.signup_tip) { guard self.currentStep == 2, self.stepGeneration == gen else { return } PopupWindow.show(popupType: .register) { // done } } } else if AppContextManager.shared.vip == 1 { let gen = stepGeneration startCountdown(seconds: timeConfig.buy_vip_tip) { guard self.currentStep == 2, self.stepGeneration == gen else { return } PopupWindow.show(popupType: .vip) { // done } } } } // MARK: - Helpers private func skipToNext() { stepGeneration += 1 currentStep += 1 executeNextStep() } private func startCountdown(seconds: Int, onExpired: @escaping () -> Void) { guard seconds > 0 else { onExpired() return } countdownTimer?.invalidate() var remaining = seconds countdownTimer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { [weak self] timer in remaining -= 1 if remaining <= 0 { timer.invalidate() self?.countdownTimer = nil onExpired() } } } private func push(_ vc: UIViewController) { let topVC = topViewController() guard let nav = topVC?.navigationController else { return } if nav.viewControllers.contains(where: { type(of: $0) == type(of: vc) }) { return } nav.pushViewController(vc, animated: true) } private func topViewController() -> UIViewController? { guard let rootVC = kKeyWindow?.rootViewController else { return nil } return topViewController(from: rootVC) } private func topViewController(from root: UIViewController) -> UIViewController { if let presented = root.presentedViewController { return topViewController(from: presented) } if let nav = root as? UINavigationController, let visible = nav.visibleViewController { return topViewController(from: visible) } if let tab = root as? UITabBarController, let selected = tab.selectedViewController { return topViewController(from: selected) } return root } }