// // TSPurchaseVC.swift // TSLiveWallpaper // // Created by 100Years on 2025/1/14. // import Combine import SwiftUI import SwiftUIX class PurchaseViewModel : ObservableObject{ @Published var selectedType: PremiumPeriod = .year /// 订阅publisher let buyPublisher = PassthroughSubject() /// 隐私 let privacyPublisher = PassthroughSubject() /// term let termPublisher = PassthroughSubject() /// restore let restorePublisher = PassthroughSubject() } class TSPurchaseVC: TSBaseVC { var closePageBlock:(()->Void)? var viewModel: PurchaseViewModel = .init() var cancellabel: [AnyCancellable] = [] var buyPeriod:PremiumPeriod = .year lazy var purchaseManager: PurchaseManager = { let purchaseManager = PurchaseManager.default return purchaseManager }() var isHandlePurchaseStateChanged = true //是否处理购买状态变化 func createImageScroll(imageName:String,direction:ImagesAnimateScrollView.`Direction`)->ImagesAnimateScrollView{ let imageScroll1: ImagesAnimateScrollView = ImagesAnimateScrollView() imageScroll1.direction = direction imageScroll1.animationImageName = imageName imageScroll1.transform = CGAffineTransform(rotationAngle: CGFloat.pi/12) return imageScroll1 } lazy var imageComparisonView: TYCycleImageComparisonView = { let imageComparisonView = TYCycleImageComparisonView() imageComparisonView.frame = CGRect(x: 0, y: 0, width: k_ScreenWidth, height: 532*kDesignScale) imageComparisonView.itemModelArray = [ TSImageComparisonModel(oldImage: UIImage(named: "image_comparison_old_0")!, newImage: UIImage(named: "image_comparison_new_0")!), TSImageComparisonModel(oldImage: UIImage(named: "image_comparison_old_1")!, newImage: UIImage(named: "image_comparison_new_1")!), TSImageComparisonModel(oldImage: UIImage(named: "image_comparison_old_2")!, newImage: UIImage(named: "image_comparison_new_2")!), TSImageComparisonModel(oldImage: UIImage(named: "image_comparison_old_3")!, newImage: UIImage(named: "image_comparison_new_3")!), TSImageComparisonModel(oldImage: UIImage(named: "image_comparison_old_4")!, newImage: UIImage(named: "image_comparison_new_4")!) ] return imageComparisonView }() lazy var bgView: UIView = { let bgView = UIView() bgView.backgroundColor = .clear let imageView = UIImageView.createImageView(imageName: "purchase_bj",contentMode: .scaleAspectFill) bgView.addSubview(imageView) imageView.snp.makeConstraints { make in make.edges.equalToSuperview() } return bgView }() lazy var hostVc: UIHostingController = { //增加月付费 // if PurchaseManager.default.vipType == .none { // viewModel.selectedType = .month // } if PurchaseManager.default.vipType == .none { viewModel.selectedType = .week(.week) } let vc = UIHostingController(rootView: PurchaseView(viewModel: viewModel)) vc.view.backgroundColor = .clear return vc }() override func createView() { addNormalNavBarView() _ = setNavigationItem("", imageName: "close_gray", direction: .left, action: #selector(closePage)) view.insertSubview(bgView, at: 0) bgView.snp.makeConstraints { make in make.leading.trailing.bottom.top.equalToSuperview() } bgView.insertSubview(imageComparisonView, at: 0) // setViewBgImageNamed(named: "purchase_bj") contentView.addSubview(hostVc.view) hostVc.view.snp.makeConstraints { make in make.leading.trailing.bottom.top.equalToSuperview() } } @objc func closePage(){ TSToastShared.hideLoading() closePageBlock?() self.dismiss(animated: true) kPurchaseCountDownTime.isNeedCheck = true NotificationCenter.default.post(name: .kCloseTSPurchaseVC, object: nil) } override func dealThings() { //周会员和月会员不自动处理变化,必须点击购买后才处理 let vipType = purchaseManager.vipType if vipType.isWeekType || vipType == .month { isHandlePurchaseStateChanged = false } addNotifaction() onPurchaseStateChanged() NotificationCenter.default.addObserver(forName: .kPurchasePrepared, object: nil, queue: OperationQueue.main) { [weak self] _ in guard let self = self else { return } viewModel.selectedType = viewModel.selectedType } } func addNotifaction() { viewModel.buyPublisher.receive(on: DispatchQueue.main).sink { [weak self] _ in guard let self = self else { return } isHandlePurchaseStateChanged = true PurchaseManager.default.pay(for: self.viewModel.selectedType) }.store(in: &cancellabel) viewModel.privacyPublisher.receive(on: DispatchQueue.main).sink { [weak self] _ in guard let self = self else { return } let vc = TSBusinessWebVC(urlType: .privacy) vc.hidesBottomBarWhenPushed = true kPresentModalVC(target: self, modelVC: vc) }.store(in: &cancellabel) viewModel.termPublisher.receive(on: DispatchQueue.main).sink { [weak self] _ in guard let self = self else { return } let vc = TSBusinessWebVC(urlType: .terms) vc.hidesBottomBarWhenPushed = true kPresentModalVC(target: self, modelVC: vc) }.store(in: &cancellabel) viewModel.restorePublisher.receive(on: DispatchQueue.main).sink { [weak self] _ in guard let self = self else { return } restorePremium() }.store(in: &cancellabel) } func restorePremium(){ isHandlePurchaseStateChanged = true PurchaseManager.default.restorePremium() } func onPurchaseStateChanged(){ purchaseManager.onPurchaseStateChanged = { [weak self] manager,state,object in guard let self = self else { return } if isHandlePurchaseStateChanged == false { debugPrint("purchaseManager.onPurchaseStateChanged 不处理") return } DispatchQueue.main.async { switch state { case .none: break case .loading: TSToastShared.showLoading(text: "Getting price".localized,containerView: self.view) case .loadSuccess: TSToastShared.hideLoading() case .loadFail: TSToastShared.hideLoading() let message = "Failed to get the price, will automatically retry in 5 seconds".localized TSToastShared.showToast(text: message) DispatchQueue.main.asyncAfter(deadline: .now() + 5) { PurchaseManager.default.requestProducts() } case .paying: TSToastShared.showLoading(text: "Purchasing now".localized,containerView: self.view) case .paySuccess: TSToastShared.hideLoading() var loadingText = "Finish".localized if manager.isVip { loadingText = manager.vipType == .year ? "Congratulations on being VIP of the Year!".localized : "Congratulation you have become VIP".localized } TSToastShared.showToast(text:loadingText) if manager.isVip { DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { self.closePage() } } case .payFail: TSToastShared.hideLoading() if let str = object as? String { TSToastShared.showToast(text: str) } case .restoreing: TSToastShared.showLoading(text: "Restoring now".localized,containerView: self.view) case .restoreSuccess: TSToastShared.hideLoading() // let loadingText = manager.isVip ? "Congratulation you have become VIP".localized : "Couldn't Restore Subscription".localized let loadingText = manager.vipType == .year ? "Congratulations on being VIP of the Year!".localized : "Congratulation you have become VIP".localized debugPrint(loadingText) TSToastShared.showToast(text:loadingText) if manager.isVip { DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { self.closePage() } } case .restoreFail: TSToastShared.hideLoading() let loadingText = (object as? String) ?? "Failed to restore subscribe, please try again".localized debugPrint(loadingText) TSToastShared.showToast(text: loadingText) case .verifying: #if DEBUG TSToastShared.showLoading(text: "Verifying receipt...".localized,containerView: self.view) #endif case .verifySuccess: break case .verifyFail: #if DEBUG TSToastShared.hideLoading() let message = (object as? String) ?? "Failed to validate receipt".localized TSToastShared.showToast(text:message) #endif } } debugPrint("PurchaseManager onPurchaseStateChanged=\(String(describing: state))") } } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) // 禁用右滑返回手势 navigationController?.interactivePopGestureRecognizer?.isEnabled = false } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) // 恢复右滑返回手势 navigationController?.interactivePopGestureRecognizer?.isEnabled = true } deinit { cancellabel.removeAll() } } func kJudgeVipFreeType(vipFreeNumType:VipFreeNumType, vc:UIViewController? = nil, closePageBlock:(()->Void)? = nil) -> Bool { //判断 vip return kJudgeVip(externalBool: kPurchaseDefault.freeNumAvailable(type: vipFreeNumType) == false, vc: vc ,closePageBlock: closePageBlock) } func kJudgeVip(externalBool:Bool, vc:UIViewController? = nil, closePageBlock:(()->Void)? = nil) -> Bool { //判断 vip if externalBool, PurchaseManager.default.isVip == false { if let vc = vc { TSPurchaseVC.show(target: vc, closePageBlock: nil) }else if let rootVC = WindowHelper.getRootViewController() { TSPurchaseVC.show(target: rootVC, closePageBlock: nil) } return true } return false } extension TSPurchaseVC{ static func show(target:UIViewController,closePageBlock:(()->Void)? = nil){ kDelayMainShort { let vc = TSPurchaseVC() vc.closePageBlock = closePageBlock let navi = TSBaseNavigationC(rootViewController: vc) navi.modalPresentationStyle = .overFullScreen target.present(navi, animated: true) } } }