// // KMCheckInWindowController.swift // PDF Reader Pro // // Created by User-Tangchao on 2024/12/18. // import Cocoa class KMCheckInWindowController: KMBaseWindowController { @IBOutlet weak var contentBox: NSBox! @IBOutlet weak var backgroundIv: NSImageView! @IBOutlet weak var titleLabel: NSTextField! @IBOutlet weak var subTitleBox: NSBox! @IBOutlet weak var giftIv: NSImageView! @IBOutlet weak var subTitleLabel: NSTextField! @IBOutlet weak var despScrollView: NSScrollView! @IBOutlet var despTextView: NSTextView! @IBOutlet weak var checkInBox: NSBox! @IBOutlet weak var checkTopBox: NSBox! @IBOutlet weak var checkInLabel: NSTextField! @IBOutlet weak var checkInTotalLabel: NSTextField! @IBOutlet weak var checkInBackgroundIv: NSImageView! @IBOutlet weak var checkInBackgroundIv2: NSImageView! @IBOutlet weak var checkInScrollView: NSScrollView! @IBOutlet weak var checkInCollectionView: NSCollectionView! @IBOutlet weak var ipIv: NSImageView! static let shared = KMCheckInWindowController(windowNibName: "KMCheckInWindowController") private var dayNum_: Int = 0 private var learnMoreActionString_ = "action://LearnMore" private var cellItemIdentifier_ = NSUserInterfaceItemIdentifier(rawValue: "CellID") private var showPopGuideing_ = false private var datas_: [KMCheckInModel] = [] override func windowDidLoad() { super.windowDidLoad() window?.standardWindowButton(.zoomButton)?.isHidden = true window?.standardWindowButton(.miniaturizeButton)?.isHidden = true let closeButton = window?.standardWindowButton(.closeButton) closeButton?.target = self closeButton?.action = #selector(closeAction) window?.delegate = self backgroundIv.image = NSImage(named: "KMImageNameCheckInBg") backgroundIv.image?.size = window?.frame.size ?? NSMakeSize(661, 442) titleLabel.font = .UbuntuMediumFontWithSize(30) subTitleBox.borderWidth = 0 giftIv.image = NSImage(named: "KMImageNameCheckInGift") subTitleLabel.font = .UbuntuMediumFontWithSize(20) despScrollView.drawsBackground = false despScrollView.backgroundColor = .clear despScrollView.hasVerticalScroller = false despScrollView.hasHorizontalScroller = false _initDespAttriText() despTextView.isSelectable = true despTextView.isEditable = false despTextView.delegate = self despTextView.backgroundColor = .clear checkInBox.borderWidth = 0 checkInBackgroundIv.image = NSImage(named: "KMImageNameCheckInListBg") checkInBackgroundIv2.image = NSImage(named: "KMImageNameCheckInListBg2") checkTopBox.borderWidth = 0 checkInLabel.stringValue = NSLocalizedString("Cumulatively Sign in to Get AI Credits", comment: "") checkInLabel.font = .SFProTextRegularFont(16) checkInTotalLabel.font = .SFProTextRegularFont(12) checkInTotalLabel.alignment = .center checkInScrollView.drawsBackground = false checkInScrollView.borderType = .noBorder checkInCollectionView.wantsLayer = true checkInCollectionView.backgroundColors = [.clear] checkInCollectionView.delegate = self checkInCollectionView.dataSource = self checkInCollectionView.register(KMCheckInViewItem.self, forItemWithIdentifier: cellItemIdentifier_) let layout = checkInCollectionView.collectionViewLayout as? NSCollectionViewFlowLayout layout?.itemSize = NSMakeSize(84, 115) layout?.minimumLineSpacing = 0 layout?.minimumInteritemSpacing = 0 layout?.sectionInset = .init(top: 0, left: 12, bottom: 0, right: 12) ipIv.image = NSImage(named: "KMImageNameCheckInIP") _initData() self.checkInCollectionView.reloadData() interfaceThemeDidChanged(self.window?.appearance?.name ?? .aqua) } override func interfaceThemeDidChanged(_ appearance: NSAppearance.Name) { super.interfaceThemeDidChanged(appearance) KMMainThreadExecute { if KMAppearance.isDarkMode() { self.titleLabel.textColor = .white self.subTitleLabel.textColor = .white } else { self.titleLabel.textColor = NSColor(hex: "#00071D") self.subTitleLabel.textColor = NSColor(hex: "#0E1114") } self.checkInLabel.textColor = NSColor(hex: "#42464D") self.checkInTotalLabel.textColor = NSColor(hex: "#42464D") self._initDespAttriText() } } // MARK: - Private Methods private func _initData() { datas_.removeAll() for i in 1 ... 7 { let model = KMCheckInModel() model.dayNum = i if i == 1 || i == 3 || i == 7 { model.isGift = true if i == 7 { model.creditNum = 20 } else { model.creditNum = 10 } } datas_.append(model) } } private func _initDespAttriText() { let string = NSLocalizedString("PDF Reader Pro AI Tools: With AI Summarize, Translate, Proofread, and Rewrite", comment: "") let linkString = NSLocalizedString("Learn More", comment: "") let textString = String(format: "%@ %@", string, linkString) let style = NSMutableParagraphStyle() var textColor = NSColor(hex: "#0E1114") var linkColor = NSColor(hex: "#4982E6") if KMAppearance.isDarkMode() { textColor = .white linkColor = NSColor(hex: "#227AFF") } let font = NSFont.SFProTextRegularFont(14) let attriText = NSMutableAttributedString(string: textString, attributes: [ .foregroundColor: textColor, .font: font, .paragraphStyle: style ]) let range = (textString as NSString).range(of: linkString) attriText.addAttributes([ .foregroundColor: linkColor, .underlineStyle: NSUnderlineStyle.single.rawValue, .link: learnMoreActionString_, .font: font ], range: range) despTextView.textStorage?.setAttributedString(attriText) } private func _openAIWindow() { let winC = AINewConfigWindowController.currentWC() winC.chooseCurFileHandle = { windowVC in if AIChatInfoManager.defaultManager.currentFilePath.isEmpty == false { var didFileEdit = false var curDoc: KMMainDocument? = nil for document in NSDocumentController.shared.documents { if document.fileURL?.path == AIChatInfoManager.defaultManager.currentFilePath { didFileEdit = document.isDocumentEdited curDoc = document as? KMMainDocument break } } if didFileEdit { let tempFileURL = FileManager.default.temporaryDirectory.appendingPathComponent(AIChatInfoManager.defaultManager.currentFilePath.lastPathComponent) if FileManager.default.fileExists(atPath: tempFileURL.path) { do { try FileManager.default.removeItem(at: tempFileURL) } catch { } } curDoc?.mainViewController?.SaveTempPDFDocumentToURLPath(tempPath: tempFileURL.path) } winC.window?.becomeMain() } } if winC.window?.isVisible == true && winC.didSetOriginFrame == true { } else { winC.window?.center() winC.didSetOriginFrame = true } winC.eventLabel = "AITools_Onboard" winC.showWindow(nil) } private func _updateItemView(_ itemView: KMCheckInItemView, model: KMCheckInModel) { itemView.backgroundView.wantsLayer = true itemView.backgroundView.layer?.cornerRadius = 8 let selectedBgColor = NSColor(hex: "#FEE4EC") let unSelectedBgColor = NSColor(hex: "#FCFDFF") let unSelectedBgBorderColor = NSColor(hex: "#EBECF0") if model.isGift { let itemView = itemView as? KMCheckInGiftItemView itemView?.numLabel.stringValue = "+\(model.creditNum)" itemView?.numLabel.font = .SFProTextRegularFont(14) itemView?.creditsLabel.stringValue = NSLocalizedString("Credits", comment: "") itemView?.creditsLabel.font = .SFProTextRegularFont(14) itemView?.giftIv.image = NSImage(named: "KMImageNameCheckInGift") if model.isSelected { if dayNum_ == model.dayNum { itemView?.numLabel.textColor = NSColor(hex: "#FCFDFF") itemView?.creditsLabel.textColor = NSColor(hex: "#FCFDFF") itemView?.backgroundView.layer?.backgroundColor = NSColor(hex: "#F76959").cgColor itemView?.gradientView.colors = [NSColor(hex: "#FA388C"), NSColor(hex: "#F76959")] itemView?.gradientView.angle = -90 } else { itemView?.gradientView.isHidden = true itemView?.numLabel.textColor = NSColor(hex: "#FA1E5D") itemView?.creditsLabel.textColor = NSColor(hex: "#FA1E5D") itemView?.backgroundView.layer?.backgroundColor = selectedBgColor.cgColor } } else { itemView?.gradientView.isHidden = true itemView?.numLabel.textColor = NSColor(hex: "#757780") itemView?.creditsLabel.textColor = NSColor(hex: "#757780") itemView?.backgroundView.layer?.borderWidth = 1 itemView?.backgroundView.layer?.borderColor = unSelectedBgBorderColor.cgColor itemView?.backgroundView.layer?.backgroundColor = unSelectedBgColor.cgColor } } else { if model.isSelected { itemView.checkIv.image = NSImage(named: "KMImageNameCheckInSelected") itemView.backgroundView.layer?.backgroundColor = selectedBgColor.cgColor } else { itemView.checkIv.image = NSImage(named: "KMImageNameCheckInNormal") itemView.backgroundView.layer?.borderWidth = 1 itemView.backgroundView.layer?.borderColor = unSelectedBgBorderColor.cgColor itemView.backgroundView.layer?.backgroundColor = unSelectedBgColor.cgColor } } itemView.nameLabel.stringValue = String(format: NSLocalizedString("Day %d", comment: ""), model.dayNum) itemView.nameLabel.font = .SFProTextRegularFont(12) itemView.nameLabel.textColor = NSColor(hex: "#757780") } private func _trackEvent(dayNum: Int) { if dayNum == 1 { trackEvent(eventName: "PUW_2", params: ["PUW_Exposure" : "CumulativeOnline_1Day"], platform: .AppCenter) } else if dayNum == 3 { trackEvent(eventName: "PUW_2", params: ["PUW_Exposure" : "CumulativeOnline_3Day"], platform: .AppCenter) } else if dayNum == 7 { trackEvent(eventName: "PUW_2", params: ["PUW_Exposure" : "CumulativeOnline_7Day"], platform: .AppCenter) } } private func _fetchBrowserWindowC() -> KMBrowserWindowController? { if let win = NSApp.mainWindow as? CTBrowserWindow { return win.windowController as? KMBrowserWindowController } if let win = NSApp.keyWindow as? CTBrowserWindow { return win.windowController as? KMBrowserWindowController } for win in NSApp.windows { if win.isVisible == false { continue } guard let winC = win.windowController as? KMBrowserWindowController else { continue } if winC.browser == nil { continue } return winC } return nil } private func _showPopGuide() { if KMMemberInfo.shared.isLogin == false { // 未登陆 return } guard let winC = _fetchBrowserWindowC() else { // 没找到有效的窗口 return } guard let doc = winC.browser.activeTabContents() as? KMMainDocument else { return } if doc.isHome || doc.isNewTab { return } if showPopGuideing_ { // 正在显示,避免出现多个 return } showPopGuideing_ = true doc.mainViewController?.loadOpenFileFunctionGuide(.aiToolForCheckIn) } // MARK: - Actions @objc func closeAction() { _showPopGuide() closeWindow() } // MARK: - Public Methods public func openWindow(num: Int) { showWindow(nil) showPopGuideing_ = false dayNum_ = num if dayNum_ == 1 { titleLabel.stringValue = NSLocalizedString("Welcome to Becoming a Member of PDF Reader Pro", comment: "") } else { titleLabel.stringValue = String(format: NSLocalizedString("Cumulatively Online for %d Days!", comment: ""), dayNum_) } if datas_.isEmpty { _initData() } var creditNum = 0 for model in datas_ { model.isSelected = model.dayNum <= dayNum_ if model.dayNum == dayNum_ { if dayNum_ == 1 { subTitleLabel.stringValue = String(format: NSLocalizedString("First Meeting Gift - %d AI Credits", comment: ""), model.creditNum) } else { subTitleLabel.stringValue = String(format: NSLocalizedString("%d AI Credits Giveaway", comment: ""), model.creditNum) } } if model.dayNum <= dayNum_ { creditNum += model.creditNum } } checkInTotalLabel.stringValue = String(format: NSLocalizedString("Total AI Credits", comment: "")+": %d", creditNum) checkInCollectionView.reloadData() _trackEvent(dayNum: dayNum_) } public func closeWindow() { window?.close() } public func learnMoreAction() { closeWindow() _openAIWindow() } public func needShow() -> Bool { let member = KMMemberInfo.shared if member.isLogin == false { return false } #if DEBUG return true #endif if member.is_advanced_year_subscribe() == false { // 不是高级版年订阅 return false } if member.isCancelSubscribe() { // 已经退订 return false } // 高级版年订阅 var isTrail = false for vip in member.activeVips { if vip.levels == "3" && vip.paymentModel == "1" && vip.cycle == 4 { isTrail = vip.isTrail == "1" break } } if isTrail == false { return false } return true } } // MARK: - NSWindowDelegate extension KMCheckInWindowController: NSWindowDelegate { func windowDidResize(_ notification: Notification) { guard let data = window?.isEqual(to: notification.object), data == true else { return } backgroundIv.image?.size = window?.frame.size ?? NSMakeSize(661, 442) } } // MARK: - NSTextViewDelegate extension KMCheckInWindowController: NSTextViewDelegate { func textView(_ textView: NSTextView, clickedOnLink link: Any, at charIndex: Int) -> Bool { if let data = link as? String, data == learnMoreActionString_ { learnMoreAction() return true } return false } } // MARK: - NSCollectionViewDelegate, NSCollectionViewDataSource extension KMCheckInWindowController: NSCollectionViewDelegate, NSCollectionViewDataSource { func collectionView(_ collectionView: NSCollectionView, numberOfItemsInSection section: Int) -> Int { return datas_.count } func collectionView(_ collectionView: NSCollectionView, itemForRepresentedObjectAt indexPath: IndexPath) -> NSCollectionViewItem { let model = datas_[indexPath.item] if model.isGift { let cell = collectionView.makeItem(withIdentifier: cellItemIdentifier_, for: indexPath) as? KMCheckInViewItem let itemView = KMCheckInGiftItemView() cell?.contentBox.contentView = itemView _updateItemView(itemView, model: model) return cell ?? NSCollectionViewItem() } let cell = collectionView.makeItem(withIdentifier: cellItemIdentifier_, for: indexPath) as? KMCheckInViewItem let itemView = KMCheckInItemView() cell?.contentBox.contentView = itemView _updateItemView(itemView, model: model) return cell ?? NSCollectionViewItem() } }