// // AIPurchaseWindowController.swift // PDF Reader Pro Edition // // Created by Niehaoyu on 2024/1/18. // import Cocoa class AIPurchaseWindowController: NSWindowController, NSWindowDelegate { @IBOutlet weak var contendBox: NSBox! @IBOutlet weak var tipImage: NSImageView! @IBOutlet weak var titleLabel: NSTextField! @IBOutlet weak var subTitleLabel: NSTextField! @IBOutlet weak var purchaseBox: NSBox! @IBOutlet weak var purchaseButton: KMButton! @IBOutlet weak var priceLabel: NSTextField! @IBOutlet weak var priceDesLabel: NSTextField! @IBOutlet weak var restoreButton: HyperLinkButton! @IBOutlet weak var privacyButton: HyperLinkButton! @IBOutlet weak var termOfButton: HyperLinkButton! static var currentWindowController: AIPurchaseWindowController! @objc static func currentWC() -> AIPurchaseWindowController { if currentWindowController != nil { return currentWindowController } else { let guideInfoWC: AIPurchaseWindowController = AIPurchaseWindowController.init(windowNibName: "AIPurchaseWindowController") currentWindowController = guideInfoWC; return guideInfoWC } } override func showWindow(_ sender: Any?) { super.showWindow(sender) if let window = self.window { window.center() self.reloadData() } } deinit { NotificationCenter.default.removeObserver(self) } override func windowDidLoad() { super.windowDidLoad() // Implement this method to handle any initialization after your window controller's window has been loaded from its nib file. self.titleLabel.font = NSFont.UbuntuBoldFontWithSize(20) self.subTitleLabel.font = NSFont.SFProTextRegularFont(14) self.priceLabel.font = NSFont.UbuntuBoldFontWithSize(20) self.priceDesLabel.font = NSFont.SFProTextSemiboldFont(13) self.restoreButton.font = NSFont.SFProTextRegularFont(14) self.privacyButton.font = NSFont.SFProTextRegularFont(14) self.termOfButton.font = NSFont.SFProTextRegularFont(14) self.titleLabel.stringValue = NSLocalizedString("Purchase AI Tools", comment: "") self.subTitleLabel.stringValue = NSLocalizedString("Level up your PDF workflow with AI assistant. Unlock advanced features like AI Summarize, AI Translate, AI Rewrite, AI Proofread. ", comment: "") self.priceDesLabel.stringValue = NSLocalizedString("Purchase for 50 credits within 30 days", comment: "") self.restoreButton.title = NSLocalizedString("Restore", comment: "") self.privacyButton.title = NSLocalizedString("Privacy Policy", comment: "") self.termOfButton.title = NSLocalizedString("Terms of Service", comment: "") self.purchaseBox.wantsLayer = true self.purchaseBox.layer?.cornerRadius = CGRectGetHeight(self.purchaseBox.frame)/2 self.purchaseBox.layer?.masksToBounds = true self.purchaseButton.wantsLayer = true self.purchaseButton.mouseMoveCallback = {[unowned self] mouseEntered in if self.purchaseButton.isEnabled == false { return } if mouseEntered { self.purchaseButton.layer?.backgroundColor = NSColor.white.withAlphaComponent(0.2).cgColor } else { self.purchaseButton.layer?.backgroundColor = NSColor.clear.cgColor } } self.restoreButton.mouseMoveCallback = {[unowned self] mouseEntered in if mouseEntered { if KMAppearance.isDarkMode() { self.restoreButton.setTitleColor(NSColor(red: 1, green: 1, blue: 1, alpha: 0.7)) } else { self.restoreButton.setTitleColor(NSColor(red: 0, green: 0, blue: 0, alpha: 0.7)) } } else { self.restoreButton.setTitleColor(KMAppearance.KMColor_Layout_H2()) } } self.privacyButton.mouseMoveCallback = {[weak self] mouseEntered in if mouseEntered { if KMAppearance.isDarkMode() { self?.privacyButton.setTitleColor(NSColor(red: 1, green: 1, blue: 1, alpha: 0.7)) } else { self?.privacyButton.setTitleColor(NSColor(red: 0, green: 0, blue: 0, alpha: 0.7)) } } else { self?.privacyButton.setTitleColor(KMAppearance.KMColor_Layout_H2()) } } self.termOfButton.mouseMoveCallback = {[weak self] mouseEntered in if mouseEntered { if KMAppearance.isDarkMode() { self?.termOfButton.setTitleColor(NSColor(red: 1, green: 1, blue: 1, alpha: 0.7)) } else { self?.termOfButton.setTitleColor(NSColor(red: 0, green: 0, blue: 0, alpha: 0.7)) } } else { self?.termOfButton.setTitleColor(KMAppearance.KMColor_Layout_H2()) } } self.refreshUI() self.addNotiObserver() } func addNotiObserver() -> Void { NotificationCenter.default.addObserver(self, selector: #selector(IAPProductLoadedNotification), name: NSNotification.Name(rawValue: NSNotification.Name.KMIAPProductLoaded.rawValue), object: nil) NotificationCenter.default.addObserver(self, selector: #selector(IAPSubscriptionLoadedNotification), name: NSNotification.Name(rawValue: NSNotification.Name.KMIAPSubscriptionLoaded.rawValue), object: nil) NotificationCenter.default.addObserver(self, selector: #selector(IAPProductPurchasedNotification), name: NSNotification.Name(rawValue: NSNotification.Name.KMIAPProductPurchased.rawValue), object: nil) NotificationCenter.default.addObserver(self, selector: #selector(IAPProductFailedNotification), name: NSNotification.Name(rawValue: NSNotification.Name.KMIAPProductFailed.rawValue), object: nil) NotificationCenter.default.addObserver(self, selector: #selector(IAPProductRestoreFinishedNotification), name: NSNotification.Name(rawValue: NSNotification.Name.KMIAPProductRestoreFinished.rawValue), object: nil) NotificationCenter.default.addObserver(self, selector: #selector(IAPProductRestoreFailedNotification), name: NSNotification.Name(rawValue: NSNotification.Name.KMIAPProductRestoreFailed.rawValue), object: nil) NotificationCenter.default.addObserver(self, selector: #selector(AIDeviceStatusChangeNotification), name: NSNotification.Name(rawValue: "kDeviceAIStatusChangeNotification"), object: nil) } func refreshUI() -> Void { if KMAppearance.isDarkMode() { self.contendBox.fillColor = NSColor(red: 24/255, green: 22/255, blue: 31/255, alpha: 1) } else { self.contendBox.fillColor = NSColor(red: 247/255, green: 245/255, blue: 1, alpha: 1) } } func reloadData() -> Void { self.purchaseButton.isEnabled = true #if VERSION_FREE let priceLabel = IAPProductsManager.default().liteAIProduct.price() #else let priceLabel = IAPProductsManager.default().proAIProduct.price() #endif let aiInfoValid = AIInfoManager.default().aiInfoValid if aiInfoValid { self.purchaseButton.isEnabled = false self.purchaseButton.layer?.backgroundColor = NSColor.white.withAlphaComponent(0.2).cgColor } else { self.purchaseButton.isEnabled = true self.purchaseButton.layer?.backgroundColor = NSColor.clear.cgColor } self.priceLabel.stringValue = priceLabel! } func appStoreRestoreFinish() -> Void { var didPurchased: Bool = false #if VERSION_FREE didPurchased = IAPProductsManager.default().liteAIProduct.isSubscribed #else didPurchased = IAPProductsManager.default().proAIProduct.isSubscribed #endif if didPurchased { AIInfoManager.default().restoreAI(withInfo: ["receipt_str":IAPProductsManager.default().temptransactioReceipt as Any]) { dict, error in if AIInfoManager.default().aiInfo.infoDict.keys.count > 0 { let alert = NSAlert.init() alert.messageText = NSLocalizedString("Restore successfully", comment: "") alert.addButton(withTitle: NSLocalizedString("OK", comment: "")) alert.runModal() } self.removeWaitingView((self.window?.contentView)!) } } } func addWaingView(_ view: NSView) -> Void { self.removeWaitingView(view) let wView = WaitingView.init(frame: view.bounds) wView.autoresizingMask = [.width, .height] view.addSubview(wView) wView.startAnimation() } func removeWaitingView(_ view: NSView) -> Void { for view in view.subviews { if view.className == WaitingView.className() { view.removeFromSuperview() break } } } //MARK: - IBAction @IBAction func purchaseAction(_ sender: KMButton) { #if VERSION_FREE IAPProductsManager.default().make(IAPProductsManager.default().liteAIProduct) #else IAPProductsManager.default().make(IAPProductsManager.default().proAIProduct) #endif self.addWaingView((self.window?.contentView)!) FMTrackEventManager.defaultManager.trackOnceEvent(event: "PUW", withProperties: ["PUW_Btn":"PUW_Btn_BuyAITools"]) } @IBAction func restoreAction(_ sender: Any) { IAPProductsManager.default().restoreSubscriptions() self.addWaingView((self.window?.contentView)!) } @IBAction func privacyAction(_ sender: Any) { var url = URL(string:"https://www.pdfreaderpro.com/privacy-policy")! NSWorkspace.shared.open(url) } @IBAction func termOfAction(_ sender: Any) { var url = URL(string:"https://www.pdfreaderpro.com/terms_of_service")! NSWorkspace.shared.open(url) } //MARK: - Notification func windowWillClose(_ notification: Notification) { FMTrackEventManager.defaultManager.trackOnceEvent(event: "PUW", withProperties: ["PUW_Btn":"PUW_Btn_BuyAITools_Cancel"]) AIPurchaseWindowController.currentWindowController = nil } @objc func IAPProductLoadedNotification() { DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.3) { self.reloadData() } } @objc func IAPSubscriptionLoadedNotification() { DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.3) { self.removeWaitingView((self.window?.contentView)!) self.reloadData() } } @objc func IAPProductPurchasedNotification() { DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.3) { self.removeWaitingView((self.window?.contentView)!) self.reloadData() //Appstore购买结束后绑定票据信息 #if VERSION_FREE if IAPProductsManager.default().liteAIProduct.isSubscribed { AIInfoManager.default().activateAI(withInfo: ["receipt_str":IAPProductsManager.default().temptransactioReceipt as Any]) { dict, error in self.reloadData() if AIInfoManager.default().aiInfoValid { self.close() } } } #else if IAPProductsManager.default().proAIProduct.isSubscribed { AIInfoManager.default().activateAI(withInfo: ["receipt_str":IAPProductsManager.default().temptransactioReceipt as Any]) { dict, error in self.reloadData() if AIInfoManager.default().aiInfoValid { self.close() } } } #endif } } @objc func IAPProductFailedNotification() { DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.3) { self.removeWaitingView((self.window?.contentView)!) } } @objc func IAPProductRestoreFinishedNotification() { self.reloadData() self.appStoreRestoreFinish() } @objc func IAPProductRestoreFailedNotification() { DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.3) { self.removeWaitingView((self.window?.contentView)!) } } @objc func AIDeviceStatusChangeNotification() { DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.3) { self.reloadData() if AIInfoManager.default().aiInfoValid { self.close() } } } }