123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578 |
- //
- // KMWinBackWindowController.swift
- // PDF Reader Pro
- //
- // Created by User-Tangchao on 2025/1/13.
- //
- import Cocoa
- import StoreKit
- import SwiftUI
- @objcMembers class KMIAPTransaction: NSObject {
- var transactionIdentifier: String?
- var productIdentifier: String?
-
- override init() {
- super.init()
- self.transactionIdentifier = ""
- self.productIdentifier = ""
- }
- }
- let KMWinBackIAPProductPurchasedNotificationName = "KMWinBackIAPProductPurchasedNotification"
- //class KMWinBackWindowController: KMBaseWindowController {
- // @IBOutlet weak var contentBox: NSBox!
- // @IBOutlet weak var backgroundIv: NSImageView!
- // @IBOutlet weak var iconIv: NSImageView!
- // @IBOutlet weak var titleLabel: NSTextField!
- // @IBOutlet weak var subTitleLabel: NSTextField!
- // @IBOutlet weak var despBox: NSBox!
- // @IBOutlet weak var buttonBox: NSBox!
- //
- // static let shared = KMWinBackWindowController(windowNibName: "KMWinBackWindowController")
- //
- // private lazy var despView_: KMWinBackDespView = {
- // let view = KMWinBackDespView()
- // return view
- // }()
- //
- // private lazy var buttonView_: KMWinBackButtonView = {
- // let view = KMWinBackButtonView()
- // return view
- // }()
- //
- // private let showCountKey_ = "WinBackWindowShowCount"
- // private let lastShowTimeKey_ = "WinBackWindowLastShowTime"
- //
- // private var origialPrice_: String = ""
- //
- // private var offerId_: String?
- // private var displayPriceString_: String = ""
- //
- // override func windowDidLoad() {
- // super.windowDidLoad()
- //
- // window?.standardWindowButton(.zoomButton)?.isHidden = true
- // window?.standardWindowButton(.miniaturizeButton)?.isHidden = true
- // window?.delegate = self
- // let closeButton = window?.standardWindowButton(.closeButton)
- // closeButton?.target = self
- // closeButton?.action = #selector(closeAction)
- //
- // despBox.borderWidth = 0
- // despBox.cornerRadius = 4
- // despBox.contentView = despView_
- // buttonBox.borderWidth = 0
- // buttonBox.cornerRadius = 4
- // buttonBox.contentView = buttonView_
- //
- // backgroundIv.image = NSImage(named: "KMImageNameWinBackBg")
- // backgroundIv.image?.size = window?.frame.size ?? NSMakeSize(520, 540)
- // iconIv.image = NSImage(named: "KMImageNameWinBackIcon")
- //
- // titleLabel.stringValue = NSLocalizedString("PDF Reader Pro", comment: "")
- // titleLabel.font = .SFProTextRegularFont(20)
- //
- // despView_.titleLabel.stringValue = NSLocalizedString("PDF Reader Pro Advanced\n - 6 Months Plan", comment: "")
- // despView_.tipLabel.stringValue = NSLocalizedString("Because you were previously subscribed to PDF Reader Pro, we are now delivering a special offer to you. ", comment: "")
- // despView_.iconIv.image = NSImage(named: "KMImageNameWinBackDespIcon")
- //
- // buttonView_.backgroundView.xRadius = 4
- // buttonView_.backgroundView.yRadius = 4
- //
- // buttonView_.button.font = .SFProTextRegularFont(16)
- // buttonView_.itemClick = { [weak self] idx, _ in
- // self?.trackEvent_free(eventName: "PUW_3", params: ["PUW_Btn" : "WinBackPuw_Purchase_Click"], platform: .firebase)
- //
- // self?.purchase()
- // }
- //
- // origialPrice_ = _fetchOrigialPrice() ?? ""
- //
- // interfaceThemeDidChanged(self.window?.appearance?.name ?? .aqua)
- //
- // if #available(macOS 15.0, *) {
- // var rootView = CPDFOfferSubscriptionStoreView()
- // rootView.eligibleOffersCallback = { offertIds in
- // KMPrint("你符合赢回的优惠卷:")
- // KMPrint(offertIds)
- // if offertIds.isEmpty == false {
- // if let data = offertIds.first, data.isEmpty == false {
- // if let data = self.offerId_, data.isEmpty == false {
- // return
- // }
- //
- // if self.needShow() {
- // self.trackEvent_free(eventName: "PUW_3", params: ["PUW_Exposure" : "WinBackPuw_Exposure"], platform: .firebase)
- //
- // self._selectOffer(offerId: data)
- //
- // self.showWindow(nil)
- //
- // self._saveRecord()
- //
- // self.window?.makeKeyAndOrderFront(nil)
- // } else {
- // KMPrint("Win Back:不需要显示")
- //
- // self.window?.close()
- // }
- // }
- // }
- // }
- // let hostingView = NSHostingView(rootView: rootView)
- //
- // hostingView.frame = NSRect(x: 0, y: 0, width: 1000, height: 1000)
- // contentBox.addSubview(hostingView, positioned: .below, relativeTo: backgroundIv)
- //
- // hostingView.isHidden = true
- // } else {
- // self.window?.close()
- // }
- //
- //// https://api.storekit.itunes.apple.com/inApps/v1/subscriptions/{transactionId}
- //// https://api.storekit-sandbox.itunes.apple.com/inApps/v1/subscriptions/{transactionId}
- //
- // // /2000000828945111
- //// let url = "https://api.storekit-sandbox.itunes.apple.com/inApps/v1/subscriptions"
- ////// let urlString = KMMemberCenterConfig().activityBaseURL() + url
- //// // ["transactionId" : "2000000828945111"]
- //// KMRequestServer.requestServer.request(urlString: url, method: .get, params: nil) { requestSerializer in
- ////// requestSerializer.setValue("Bearer " + token, forHTTPHeaderField: "Authorization")
- //// } completion: { task, responseObject, error in
- //// guard let dict = responseObject as? [String : Any] else {
- ////// callback(false, nil, error)
- //// return
- //// }
- ////
- //// let model = KMRequestResultModel(dict: dict)
- ////// callback(model.isSuccess(), model, error)
- //// }
- //// KMRequestServer.requestServer.request(urlString: url, method: .get, params: nil, completion:?)
- //
- //// Self.GET(urlString: url, parameter: nil) { success , result , err in
- //// KMPrint("")
- //// }
- // }
- //
- // public class func GET(urlString: String, parameter: [String : String]? = nil, headers: [String : String]? = nil, callback:@escaping ((Bool, [String : Any]?, String?)->Void)) {
- //// var _urlString = "\(self.baseUrl)"+urlString
- // var _urlString = urlString
- // if let data = parameter, !data.isEmpty {
- // _urlString.append("?")
- // var i = 0
- // for (key, value) in data {
- // _urlString.append("\(key)=\(value)")
- // if (data.count > 1 && i != data.count-1) {
- // _urlString.append("&")
- // }
- // i += 1
- // }
- // }
- //
- // let url: URL = URL(string: _urlString)!
- //
- // let session = URLSession.shared
- // var request = URLRequest(url: url)
- // request.httpMethod = "GET"
- // request.setValue("application/json; charset=UTF-8", forHTTPHeaderField: "Content-Type")
- // if let _headers = headers {
- // for (key, value) in _headers {
- // request.setValue(value, forHTTPHeaderField: key)
- // }
- // }
- // request.timeoutInterval = 60.0
- // session.configuration.timeoutIntervalForRequest = 30.0
- //
- // let task: URLSessionDataTask = session.dataTask(with: request) { data , response, error in
- // DispatchQueue.main.async {
- // if let _ = error {
- // callback(false, nil, error.debugDescription)
- // return
- // }
- // guard let _data = data else {
- // callback(false, nil, error.debugDescription)
- // return
- // }
- // if let result = self.JsonDataParse(data: _data) {
- //// let resultMap = KMRequestResultModel(dict: result)
- //// var dataDict: [String : Any] = [:]
- //// if let data = resultMap.data as? [String : Any] {
- //// dataDict = data
- //// } else {
- //// if let dataArray = resultMap.data as? [Any] {
- //// var i = 0
- //// for dict in dataArray {
- //// dataDict["\(i)"] = dict
- //// i += 1
- //// }
- //// }
- //// }
- ////
- //// callback(resultMap.isSuccess(), dataDict, error.debugDescription)
- //// return
- // }
- //// callback(false, nil, error.debugDescription)
- // }
- // }
- // task.resume()
- // }
- //
- // private class func JsonDataParse(data: Data) -> Dictionary<String,Any>? {
- // let result = try?JSONSerialization.jsonObject(with: data, options: .mutableContainers)
- // return result as? Dictionary<String, Any>
- // }
- //
- // @objc func closeAction() {
- // self.trackEvent_free(eventName: "PUW_3", params: ["PUW_Btn" : "WinBackPuw_Cancel_Click"], platform: .firebase)
- //
- // window?.close()
- // }
- //
- // override func interfaceThemeDidChanged(_ appearance: NSAppearance.Name) {
- // super.interfaceThemeDidChanged(appearance)
- //
- // KMMainThreadExecute {
- // if KMAppearance.isDarkMode() {
- // self.titleLabel.textColor = .white
- //
- // let attri = NSMutableAttributedString(string: NSLocalizedString("Special Offer - ", comment: ""), attributes: [.font : NSFont.SFProTextRegularFont(32), .foregroundColor : NSColor.white])
- // attri.append(.init(string: self.displayPriceString_, attributes: [.font : NSFont.SFProTextRegularFont(32), .foregroundColor : NSColor(hex: "#FD7272")]))
- // attri.append(.init(string: self.origialPrice_, attributes: [.font : NSFont.SFProTextRegularFont(24), .foregroundColor : NSColor(hex: "#7E7F85"), .strikethroughStyle : NSUnderlineStyle.single.rawValue]))
- // let style = NSMutableParagraphStyle()
- // style.alignment = .center
- // attri.addAttribute(.paragraphStyle, value: style, range: NSMakeRange(0, attri.length))
- // self.subTitleLabel.attributedStringValue = attri
- //
- // self.despBox.fillColor = NSColor.white.withAlphaComponent(0.15)
- // self.despView_.titleLabel.textColor = .white
- //
- // let despAttri = NSMutableAttributedString(string: NSLocalizedString("First 6 months", comment: "")+" ", attributes: [.font : NSFont.SFProTextRegularFont(14), .foregroundColor : NSColor.white])
- // despAttri.append(.init(string: self.displayPriceString_, attributes: [.font : NSFont.SFProTextRegularFont(14), .foregroundColor : NSColor(hex: "#227AFF")]))
- // let string = ", " + String(format: NSLocalizedString("then %@ for 6 months.", comment: ""), self.origialPrice_)
- // despAttri.append(.init(string: string, attributes: [.font : NSFont.SFProTextRegularFont(14), .foregroundColor : NSColor.white]))
- // self.despView_.subTitleLabel.attributedStringValue = despAttri
- //
- // self.despView_.hLine.layer?.backgroundColor = NSColor.white.withAlphaComponent(0.15).cgColor
- //
- // self.despView_.tipLabel.textColor = NSColor(hex: "#C8C9CC")
- // } else {
- // self.titleLabel.textColor = NSColor(hex: "#0E1114")
- //
- // let attri = NSMutableAttributedString(string: NSLocalizedString("Special Offer - ", comment: ""), attributes: [.font : NSFont.SFProTextRegularFont(32), .foregroundColor : NSColor(hex: "#000150")])
- // attri.append(.init(string: self.displayPriceString_, attributes: [.font : NSFont.SFProTextRegularFont(32), .foregroundColor : NSColor(hex: "#FD7272")]))
- // attri.append(.init(string: self.origialPrice_, attributes: [.font : NSFont.SFProTextRegularFont(24), .foregroundColor : NSColor(hex: "#757780"), .strikethroughStyle : NSUnderlineStyle.single.rawValue]))
- // let style = NSMutableParagraphStyle()
- // style.alignment = .center
- // attri.addAttribute(.paragraphStyle, value: style, range: NSMakeRange(0, attri.length))
- // self.subTitleLabel.attributedStringValue = attri
- //
- // self.despBox.fillColor = .white
- // self.despView_.titleLabel.textColor = NSColor(hex: "#0E1114")
- //
- // let despAttri = NSMutableAttributedString(string: NSLocalizedString("First 6 months", comment: "")+" ", attributes: [.font : NSFont.SFProTextRegularFont(14), .foregroundColor : NSColor(hex: "#000150")])
- // despAttri.append(.init(string: self.displayPriceString_, attributes: [.font : NSFont.SFProTextRegularFont(14), .foregroundColor : NSColor(hex: "#4982E6")]))
- // let string = ", " + String(format: NSLocalizedString("then %@ for 6 months.", comment: ""), self.origialPrice_)
- // despAttri.append(.init(string: string, attributes: [.font : NSFont.SFProTextRegularFont(14), .foregroundColor : NSColor(hex: "#000150")]))
- // self.despView_.subTitleLabel.attributedStringValue = despAttri
- //
- // self.despView_.hLine.layer?.backgroundColor = NSColor.black.withAlphaComponent(0.15).cgColor
- //
- // self.despView_.tipLabel.textColor = NSColor(hex: "#757780")
- // }
- //
- // self.buttonView_.backgroundView.colors = [NSColor(hex: "#F8965A"), NSColor(hex: "#FD7171")]
- //
- // self.buttonView_.button.title = NSLocalizedString("Get Special Offer - Advanced 6 Mos", comment: "")
- // self.buttonView_.button.setTitleColor(.white)
- // }
- // }
- //
- // // MARK: - Private Methods
- //
- // private func _showCenter(animate: Bool){
- // guard let screenFrame = NSScreen.main?.frame else {
- // return
- // }
- // guard let win = self.window else {
- // return
- // }
- //
- // var frame = win.frame
- // frame.origin.y = (screenFrame.size.height-frame.size.height)*0.5
- // frame.origin.x = (screenFrame.size.width-frame.size.width)*0.5
- // win.setFrame(frame, display: true, animate: animate)
- // }
- //
- // // MARK: - Private Methods
- //
- // private func _saveRecord() {
- // let lastShowTime = KMDataManager.ud_double(forKey: lastShowTimeKey_)
- // if lastShowTime <= 0 {
- // let cnt = KMDataManager.ud_integer(forKey: showCountKey_)
- // KMDataManager.ud_set(cnt+1, forKey: showCountKey_)
- //
- // let date = Date().timeIntervalSince1970
- // KMDataManager.ud_set(date, forKey: lastShowTimeKey_)
- // return
- // }
- //
- // let date = Date(timeIntervalSince1970: lastShowTime)
- //
- // let calendar = Calendar.current
- // let unit: Set<Calendar.Component> = [.day,.month,.year]
- // let nowComps = calendar.dateComponents(unit, from: Date())
- // let selfCmps = calendar.dateComponents(unit, from: date)
- //
- // let theYear = selfCmps.year ?? 0
- // let theMonth = selfCmps.month ?? 0
- // let theDay = selfCmps.day ?? 0
- // let otherYear = nowComps.year ?? 0
- // let otherMonth = nowComps.month ?? 0
- // let otherDay = nowComps.day ?? 0
- //
- // if otherYear > theYear || otherMonth > theMonth {
- // let cnt = KMDataManager.ud_integer(forKey: showCountKey_)
- // KMDataManager.ud_set(cnt+1, forKey: showCountKey_)
- //
- // let date = Date().timeIntervalSince1970
- // KMDataManager.ud_set(date, forKey: lastShowTimeKey_)
- // return
- // }
- //
- // if otherDay - theDay >= 1 {
- // let cnt = KMDataManager.ud_integer(forKey: showCountKey_)
- // KMDataManager.ud_set(cnt+1, forKey: showCountKey_)
- //
- // let date = Date().timeIntervalSince1970
- // KMDataManager.ud_set(date, forKey: lastShowTimeKey_)
- // return
- // }
- // }
- //
- // private func _fetchOrigialPrice() -> String? {
- // return IAPProductsManager.default().fourDevicesAllAccessPackNew6Months_lite?.price()
- // }
- //
- // private func _selectOffer(offerId: String) {
- // offerId_ = offerId
- // if #available(macOS 12.0, *) {
- // winbackOffers(productId: "com.pdfreaderpro.mac_free.member.all_access_pack_advanced_6months.001") { offsers in
- // for offse in offsers {
- // let data = offse.id
- // if data == offerId {
- // self.displayPriceString_ = offse.displayPrice
- //
- // self.origialPrice_ = self._fetchOrigialPrice() ?? ""
- //
- // self.interfaceThemeDidChanged(self.window?.appearance?.name ?? .aqua)
- // }
- // }
- // }
- // } else {
- //
- // }
- // }
- //
- // private func _showAlert(message: String) {
- // KMMainThreadExecute {
- // let alert = NSAlert()
- // alert.alertStyle = .critical
- // alert.messageText = message
- // alert.addButton(withTitle: NSLocalizedString("OK", comment: ""))
- // alert.runModal()
- // }
- // }
- //
- // private func _beginLoading() {
- // self.window?.contentView?.beginLoading()
- // }
- //
- // private func _endLoading() {
- // self.window?.contentView?.endLoading()
- // }
- //
- // // MARK: - Public Methods
- //
- // public func openWindow() {
- //// self.showWindow(nil)
- //
- // if #available(macOS 12.0, *) {
- // winbackOffers(productId: "com.pdfreaderpro.mac_free.member.all_access_pack_advanced_6months.001") { [weak self] offers in
- // if offers.isEmpty { // 商品没有配置 Win Back 优惠卷
- // self?.window?.setIsVisible(false)
- // self?.window?.close()
- // } else {
- // if let data = self?.offerId_, data.isEmpty == false {
- // // no things
- // } else {
- // self?.showWindow(nil)
- //
- // self?.window?.setIsVisible(false)
- // self?.window?.close()
- // }
- // }
- // }
- // } else {
- // window?.setIsVisible(false)
- // window?.close()
- // }
- // }
- //
- // public func needShow() -> Bool {
- // if #available(macOS 15.0, iOS 18.0, *) {
- // if KMDataManager.ud_integer(forKey: showCountKey_) >= 3 {
- //#if DEBUG
- // return true
- //#else
- // return false
- //#endif
- // }
- //
- // let lastShowTime = KMDataManager.ud_double(forKey: lastShowTimeKey_)
- // if lastShowTime > 0 {
- // let date = Date(timeIntervalSince1970: lastShowTime)
- // if date.isToday() {
- //#if DEBUG
- //#else
- // return false
- //#endif
- // }
- // }
- //
- // if KMNewUserGiftManager.default.loginProgressState == .none || KMNewUserGiftManager.default.fetchReceiptProgressState == .none {
- // return false
- // }
- //
- // let member = KMMemberInfo.shared
- //// if member.isLogin {
- //// if member.is_advanced() && member.is_subscribe() && (member.is_year() || member.is_half_year()) {
- //// return false
- //// }
- //// }
- // if member.isMemberAllFunction { // 有本地或账号权益
- // return false
- // }
- //
- // return true
- // }
- // return false
- // }
- //
- // public func clearRecord() {
- // KMDataManager.ud_set(0, forKey: showCountKey_)
- // KMDataManager.ud_set(0, forKey: lastShowTimeKey_)
- // }
- //
- // @available(macOS 12.0, *)
- // public func winbackOffers(productId: String?, callback: (([Product.SubscriptionOffer])->Void)?) {
- // if #available(macOS 15.0, iOS 18.0, *) {
- // guard let theProductId = productId else {
- // callback?([])
- // return
- // }
- //
- // Task {
- // let products = try await Product.products(for: [theProductId])
- // guard let product = products.first else {
- // callback?([])
- // return
- // }
- //
- // guard let subscriptionInfo = product.subscription else {
- // callback?([])
- // return
- // }
- //
- // callback?(subscriptionInfo.winBackOffers)
- // }
- // } else {
- // callback?([])
- // }
- // }
- //
- // public func purchase() {
- // Task { @MainActor in
- // // 加载产品
- // if #available(macOS 15.0, *) {
- // let products = try? await Product.products(for: ["com.pdfreaderpro.mac_free.member.all_access_pack_advanced_6months.001"])
- // guard let product = products?.first else {
- // _showAlert(message: "未找到指定的产品")
- // return
- // }
- //
- // // 确保产品为订阅类型
- // guard let subscriptionInfo = product.subscription else {
- // _showAlert(message: "该产品不是订阅类型")
- // return
- // }
- //
- // // 查找可用的 Win-Back Offer
- // KMPrint("product:\(product)")
- // KMPrint("subscriptionInfo.winBackOffers:\(subscriptionInfo.winBackOffers)")
- // let offers = subscriptionInfo.winBackOffers
- //
- // var off: Product.SubscriptionOffer?
- // for offer in offers {
- // if self.offerId_ == offer.id {
- // off = offer
- // break
- // }
- // }
- //
- // guard let winBackOffer = off else {
- // KMPrint("没有找到适合用户的 Win-Back Offer")
- // _showAlert(message: "No Offer")
- // return
- // }
- //
- // // 使用 Win-Back Offer 创建购买选项
- // let purchaseOption = Product.PurchaseOption.winBackOffer(winBackOffer)
- //
- // self._beginLoading()
- // // 发起购买
- // let purchaseResult = try await product.purchase(options: [purchaseOption])
- // switch purchaseResult {
- // case .success(let verificationResult):
- // self._endLoading()
- //
- // switch verificationResult {
- // case .verified(let transaction):
- // KMPrint("购买成功:\(transaction.id)")
- // await transaction.finish()
- //
- // DispatchQueue.main.asyncAfter(deadline: .now()+1) {
- // self.window?.close()
- //
- // let man = IAPProductsManager.default()
- // man?.winbackIAPPurchased(withProdcutId: transaction.productID, transactionId: "\(transaction.id)")
- // }
- //
- // case .unverified(_, let error):
- // KMPrint("验证失败:\(error)")
- // }
- // case .userCancelled:
- // KMPrint("用户取消了购买")
- // self._endLoading()
- // case .pending:
- // KMPrint("购买失败")
- // @unknown default:
- // KMPrint("购买失败")
- // }
- // }
- // }
- // }
- //}
- //
- //// MARK: - NSWindowDelegate
- //
- //extension KMWinBackWindowController: NSWindowDelegate {
- // func windowDidResize(_ notification: Notification) {
- // guard let data = window?.isEqual(to: notification.object), data == true else {
- // return
- // }
- // backgroundIv.image?.size = window?.frame.size ?? NSMakeSize(520, 540)
- // }
- //}
|