200 lines
6.2 KiB
Swift
200 lines
6.2 KiB
Swift
//
|
|
// 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?.globalDisplay == true 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
|
|
}
|
|
}
|