// // KMHomeViewController+UI.swift // PDF Master // // Created by wanjun on 2022/10/13. // import Foundation extension KMHomeViewController { // MARK: Private Methods func productPromotionShow(_ pdfProSeries: NSArray, withOthers others: NSArray, isInitialize initialize: Bool) { // if pdfProSeries.count > 0 { // if (self.pdfProSeriesBoxHeightConstraint.constant == 0.0) || initialize { // var height = CGFloat(pdfProSeries.count) * 32.0 // for name in pdfProSeries { // height -= 32.0 // // let dict: Dictionary = self.productPromotionData[name] as! Dictionary // let subBox = KMBox(frame: CGRect(origin: CGPoint(x: 0, y: height), size: CGSize(width: self.pdfProSeriesBox.frame.width, height: 32.0))) // subBox.boxType = .custom // subBox.borderWidth = 0.0 // self.pdfProSeriesBox.contentView?.addSubview(subBox) // subBox.downCallback = {(downEntered, mouseBox, event) -> Void in // if downEntered { // self.productPromotionClickAction(dict["Name"]!) // } // } // // let subImageView = NSImageView(frame: NSZeroRect) // subImageView.image = NSImage(named: dict["Image"]! as NSImage.Name) // subBox.addSubview(subImageView) // subImageView.mas_makeConstraints { (make) in // make?.width.height().equalTo()(16) // make?.centerY.equalTo()(0) // make?.left.equalTo()(18) // } // // let subLabel = NSTextField(frame: NSZeroRect) // subLabel.isBezeled = false // subLabel.isEditable = false // subLabel.backgroundColor = .clear // let paragraphStyle = NSMutableParagraphStyle() // paragraphStyle.lineSpacing = 22.0 // subLabel.attributedStringValue = NSAttributedString(string: dict["Name"]! as String, attributes: [NSAttributedString.Key.paragraphStyle: paragraphStyle]) // subLabel.font = NSFont(name: "SFProText-Regular", size: 14) // subLabel.textColor = NSColor.km_init(hex: "#616469") // subLabel.sizeToFit() // subBox.addSubview(subLabel) // subLabel.mas_makeConstraints { (make) in // make?.left.equalTo()(subImageView.mas_right)?.offset()(10) // make?.centerY.equalTo()(0) // } // } // // pdfSeriesButtonVC.image = NSImage(named: "icon_btn_expand_lv2_down_false")! // self.pdfProSeriesBoxHeightConstraint.constant = CGFloat(pdfProSeries.count) * 32.0 // } // } else { // pdfSeriesButtonVC.image = NSImage(named: "icon_btn_expand_lv2_right_false")! // self.pdfProSeriesBox.contentView = NSView.init() // self.pdfProSeriesBoxHeightConstraint.constant = 0.0 // } // // if others.count > 0 { // if (self.othersBoxHeightConstraint.constant == 0.0) || initialize { // var height = CGFloat(others.count) * 32.0 // for name in others { // height -= 32.0 // // let dict: Dictionary = self.productPromotionData[name] as! Dictionary // let subBox = KMBox(frame: CGRect(x: 0, y: height, width: self.othersBox.frame.width, height: 32.0)) // subBox.boxType = .custom // subBox.borderWidth = 0.0 // self.othersBox.contentView?.addSubview(subBox) // subBox.downCallback = {(downEntered, mouseBox, event) -> Void in // if downEntered { // self.productPromotionClickAction(dict["Name"]!) // } // } // // let subImageView = NSImageView(frame: NSZeroRect) // subImageView.image = NSImage(named: dict["Image"]! as NSImage.Name) // subImageView.imageScaling = .scaleProportionallyDown // subImageView.imageAlignment = .alignCenter // subImageView.sizeToFit() // subBox.addSubview(subImageView) // subImageView.mas_makeConstraints { (make) in // make?.width.height().equalTo()(16) // make?.centerY.equalTo()(0) // make?.left.equalTo()(18) // } // // let subLabel = NSTextField(frame: NSZeroRect) // subLabel.isBezeled = false // subLabel.isEditable = false // subLabel.backgroundColor = .clear // let paragraphStyle = NSMutableParagraphStyle() // paragraphStyle.lineSpacing = 22.0 // subLabel.attributedStringValue = NSAttributedString(string: dict["Name"]! as String, attributes: [NSAttributedString.Key.paragraphStyle: paragraphStyle]) // subLabel.font = NSFont(name: "SFProText-Regular", size: 14) // subLabel.textColor = NSColor(red: 0.38, green: 0.392, blue: 0.412, alpha: 1.0) // subLabel.sizeToFit() // subBox.addSubview(subLabel) // subLabel.mas_makeConstraints { (make) in // make?.left.equalTo()(subImageView.mas_right)?.offset()(10) // make?.centerY.equalTo()(0) // } // } // // self.pdfOthersButtonVC.image = NSImage(named: "icon_btn_expand_lv2_down_false")! // self.othersBoxHeightConstraint.constant = CGFloat(others.count) * 32.0 // } // } else { // self.pdfOthersButtonVC.image = NSImage(named: "icon_btn_expand_lv2_right_false")! // self.othersBox.contentView = NSView.init() // self.othersBoxHeightConstraint.constant = 0.0 // } // // pdfSeriesButtonVC.updateUI() // pdfOthersButtonVC.updateUI() } func refreshRightBoxUI(_ state: KMHomeToolState) { rightFullBox.isHidden = true rightTopBox.isHidden = true rightBottomBox.isHidden = true homeButtonVC.state = .Norm pdfToolsButtonVC.state = .Norm cloudDocumentsButtonVC.state = .Norm switch state { case .Home: rightTopBox.isHidden = false rightBottomBox.isHidden = false rightTopBox.contentView = fastToolViewController.view rightBottomBox.contentView = historyFileViewController.view rightFullBox.contentView = nil let isQuickToolsType:Bool = UserDefaults.standard.bool(forKey: "kHomeQucikToolsTypeKey") if isQuickToolsType { rightTopBoxHeightConstraint.constant = 230 + ScrollerViewWidget } else { rightTopBoxHeightConstraint.constant = 326 + ScrollerViewWidget } homeButtonVC.state = .Sel refreshUI() break case .PDFTools: rightFullBox.isHidden = false rightFullBox.contentView = pdfToolsViewController.view rightTopBox.contentView = nil rightBottomBox.contentView = nil pdfToolsButtonVC.state = .Sel refreshUI() break case .CloudDocuments: rightFullBox.isHidden = false rightFullBox.contentView = cloudDocumentsViewController.view rightTopBox.contentView = nil rightBottomBox.contentView = nil cloudDocumentsButtonVC.state = .Sel refreshUI() break default: break } } func showConvertWindow(type: KMPDFConvertType) { Task { @MainActor in // #if VERSION_DMG // if await (KMLightMemberManager.manager.canUseAdvanced() == false) { // let _ = KMComparativeTableViewController.show(window: self.view.window!, .merge) // return // } // #endif // if await (KMLightMemberManager.manager.canPayFunction() == false) { // let _ = KMSubscribeWaterMarkWindowController.show(window: self.view.window!, isContinue: true, type: type.toSubscribeWaterMarkType()) { isSubscribeSuccess, isWaterMarkExport, isClose in // if (isClose) { // return // } // self.km_secure_openPanel_convert(type: type) // } // return // } self.km_secure_openPanel_convert(type: type) } } func km_secure_openPanel_convert(type: KMPDFConvertType) { DispatchQueue.main.async { NSOpenPanel.km_secure_openPanel_success(window: self.view.window!) { url, password in if (url.path.isPDFValid() == false) { let alert = NSAlert() alert.alertStyle = .critical alert.messageText = NSLocalizedString("An error occurred while opening this document. The file is damaged and could not be repaired.", comment: "") alert.runModal() return } self._showConvertWindow(type: type, url: url, password: password) } } } func showSecurityWindow() { Task { @MainActor in #if VERSION_DMG if await (KMLightMemberManager.manager.canUseAdvanced() == false) { let _ = KMComparativeTableViewController.show(window: self.view.window!, .merge) return } #endif if await (KMLightMemberManager.manager.canPayFunction() == false) { let _ = KMSubscribeWaterMarkWindowController.show(window: self.view.window!, isContinue: true) { isSubscribeSuccess, isWaterMarkExport, isClose in if (isClose) { return } self.km_secure_openPanel_security(limit: true) } return } self.km_secure_openPanel_security() } } func km_secure_openPanel_security(limit: Bool = false) { DispatchQueue.main.async { NSOpenPanel.km_secure_openPanel_success(window: self.view.window!, needOwner: true) { url, password in self._showSecurityWindow(url: url, password: password, limit: limit) } } } func refreshScrollView() -> Void { let rect = self.homeSplitView.frame let rightWidth = Int(rect.width) - 271 if self.aiOpenPDFFilesViewController != nil { if rightWidth >= (360 + 20 + 328) { self.rightTopBoxHeightConstraint.constant = 348 self.aiOpenPDFFilesViewController.refreshLayout(isLimit: false) } else { self.rightTopBoxHeightConstraint.constant = 348 * 2 self.aiOpenPDFFilesViewController.refreshLayout(isLimit: true) } // let scrollView: NSScrollView = self.homeRightScrollViewView // let targetOrigin: NSPoint = NSPoint(x: 271, y: (self.homeRightScrollViewView.documentView?.frame.height)!) // // let documentVisibleRect = scrollView.documentVisibleRect // let documentSize = scrollView.documentView?.frame.size ?? .zero // // // 确保 targetOrigin 在有效的滚动范围内 // let maxX = max(0, documentSize.width - documentVisibleRect.size.width) // let maxY = max(0, documentSize.height - documentVisibleRect.size.height) // let clampedOrigin = NSPoint(x: min(targetOrigin.x, maxX), y: min(targetOrigin.y, maxY)) // // //// self.homeRightScrollViewView.documentView?.layoutSubtreeIfNeeded() // self.homeRightScrollViewView.contentView.scroll(to:clampedOrigin) } var contentViewHeight = 0 if self.historyFileViewController.files.count > 0 { if self.historyFileViewController.showMode == .Thumbnail { if self.historyFileViewController.thumbnailSCrollView != nil { var count = rightWidth/(226 + 32) if count <= 0 { count = 1 } var row = self.historyFileViewController.files.count/count if self.historyFileViewController.files.count%count > 0 { row += 1 } let height2 = (248 + 16) * row contentViewHeight = Int(self.rightTopBoxHeightConstraint.constant + CGFloat(height2) + 76) self.rightBottonHeight.constant = CGFloat(height2) + 76 } } else { if self.historyFileViewController.listScrollView != nil { let height2 = self.historyFileViewController.files.count * 72 + 32 contentViewHeight = Int(self.rightTopBoxHeightConstraint.constant + CGFloat(height2) + 76) self.rightBottonHeight.constant = CGFloat(height2) + 76 } } } else { contentViewHeight = Int(rect.height - self.rightTopBox.frame.height) self.rightBottonHeight.constant = CGFloat(contentViewHeight) } if contentViewHeight < Int(rect.height) { contentViewHeight = Int(rect.height) self.rightBottonHeight.constant = rect.height - self.rightTopBoxHeightConstraint.constant } self.homeRightScrollViewView.documentView!.frame = NSRect(x: 271, y: 0, width: rightWidth, height: contentViewHeight) let scrollView: NSScrollView = self.homeRightScrollViewView let targetOrigin: NSPoint = NSPoint(x: 271, y: (self.homeRightScrollViewView.documentView?.frame.height)!) let documentVisibleRect = scrollView.documentVisibleRect let documentSize = scrollView.documentView?.frame.size ?? .zero // 确保 targetOrigin 在有效的滚动范围内 let maxX = max(271, documentSize.width - documentVisibleRect.size.width) let maxY = max(0, documentSize.height - documentVisibleRect.size.height) let clampedOrigin = NSPoint(x: min(targetOrigin.x, maxX), y: min(targetOrigin.y, maxY)) self.homeRightScrollViewView.contentView.scroll(to:clampedOrigin) } // MARK: - Private Methods fileprivate func _showConvertWindow(type: KMPDFConvertType, url: URL, password: String? = nil) { var windowController: KMConvertBaseWindowController? if (type == .word) { /// Word windowController = KMConvertWordWindowController() } else if (type == .excel) { windowController = KMConvertExcelWindowController() } else if (type == .ppt || type == .rtf || type == .html || type == .text) { windowController = KMConvertPPTsWindowController() if (type == .ppt) { windowController?.subType = 1 } else if (type == .rtf) { windowController?.subType = 2 } else if (type == .html) { windowController?.subType = 3 } else if (type == .text) { windowController?.subType = 4 } } else if (type == .csv) { windowController = KMConvertCSVWindowController() } else if (type == .image) { windowController = KMConvertImageWindowController() } windowController?.subscribeWaterMarkType = type.toSubscribeWaterMarkType() let model = KMDocumentModel(url: url) if (password != nil) { let _ = model.unlock(password!) } windowController?.documentModel = model windowController?.itemClick = { [weak self] _ in self?.km_endSheet() } self.km_safe_beginSheet(windowC: windowController) } fileprivate func _showSecurityWindow(url: URL, password: String?, limit: Bool = false) { // 安全 let windowC = KMSecureEncryptWindowController(windowNibName: "KMSecureEncryptWindowController") windowC.documentURL = url windowC.myDocument = CPDFDocument(url: url) if let _password = password { windowC.myDocument.unlock(withPassword: _password) } let newDocument: CPDFDocument = CPDFDocument(url: url) windowC.itemClick = { [weak self] _ in self?.km_endSheet() } windowC.resultCallback = { [weak self] _ in let windowController_secure: KMSecureEncryptWindowController = self?.kmCurrentWindowC as! KMSecureEncryptWindowController self?.km_endSheet() if let _password = password { newDocument.unlock(withPassword: _password) } if (!limit) { newDocument.setPasswordOptions(windowController_secure.options) let result = KMPasswordInputWindow.saveDocument(newDocument) if result { NSWorkspace.shared.activateFileViewerSelecting([newDocument.documentURL]) } else { let alert = NSAlert() alert.messageText = NSLocalizedString("Failure", comment: "") alert.runModal() } return } NSPanel.savePanel((self?.view.window)!, panel: { panel in panel.nameFieldStringValue = url.lastPathComponent }) { response, saveUrl in if (response == .cancel) { return } if let fileUrl = KMTools.saveWatermarkDocument(document: newDocument, to: saveUrl!, secureOptions: windowController_secure.options) { NSWorkspace.shared.activateFileViewerSelecting([fileUrl]) } else { let alert = NSAlert() alert.messageText = NSLocalizedString("Failure", comment: "") alert.runModal() } } } self.km_beginSheet(windowC: windowC) } } // MARK: - NSSplitViewDelegate extension KMHomeViewController: NSSplitViewDelegate { func splitView(_ splitView: NSSplitView, constrainMinCoordinate proposedMinimumPosition: CGFloat, ofSubviewAt dividerIndex: Int) -> CGFloat { return 270.0 } func splitView(_ splitView: NSSplitView, constrainMaxCoordinate proposedMaximumPosition: CGFloat, ofSubviewAt dividerIndex: Int) -> CGFloat { return 270.0 } func splitView(_ splitView: NSSplitView, shouldAdjustSizeOfSubview view: NSView) -> Bool { return false } func splitViewDidResizeSubviews(_ notification: Notification) { let rect = self.homeSplitView.frame self.leftBox.setFrameSize(CGSize(width: 270, height: rect.size.height)) self.rightBox.frame = CGRect(origin: CGPoint(x: 271.0, y: 0), size: CGSize(width: rect.width - 271.0, height: rect.height)) refreshProductActiveSpacing() // refreshScrollView() } func splitView(_ splitView: NSSplitView, constrainSplitPosition proposedPosition: CGFloat, ofSubviewAt dividerIndex: Int) -> CGFloat { return proposedPosition } func splitView(_ splitView: NSSplitView, canCollapseSubview subview: NSView) -> Bool { return false } func splitView(_ splitView: NSSplitView, shouldCollapseSubview subview: NSView, forDoubleClickOnDividerAt dividerIndex: Int) -> Bool { return false } func splitView(_ splitView: NSSplitView, shouldHideDividerAt dividerIndex: Int) -> Bool { return splitView.isEqual(to: self.homeSplitView) } func splitView(_ splitView: NSSplitView, effectiveRect proposedEffectiveRect: NSRect, forDrawnRect drawnRect: NSRect, ofDividerAt dividerIndex: Int) -> NSRect { return proposedEffectiveRect } func splitView(_ splitView: NSSplitView, additionalEffectiveRectOfDividerAt dividerIndex: Int) -> NSRect { return NSMakeRect(0, 0, 0, 0) } } // MARK: - KMHomeFastToolViewControllerDelegate extension KMHomeViewController: KMHomeFastToolViewControllerDelegate { func fastToolViewController(_ viewController: KMHomeFastToolViewController, foldChangeState: Bool) { if foldChangeState { rightTopBoxHeightConstraint.constant = 230.0 + ScrollerViewWidget } else { rightTopBoxHeightConstraint.constant = 326.0 + ScrollerViewWidget } } func fastToolDidSelectAllTools(_ viewController: KMHomeFastToolViewController) { fastToolDidSelectAllTools() } func fastToolViewController(_ viewController: KMHomeFastToolViewController, didSelectItemsAt indexPaths: [Int]) { for index in indexPaths { fastToolItemAction(DataNavigationViewButtonActionType(rawValue: index) ?? .Batch) } } } // MARK: - KMHomeHistoryFileViewControllerDelegate extension KMHomeViewController: KMHomeHistoryFileViewControllerDelegate { func historyFileViewController(_ viewController: KMHomeHistoryFileViewController, deleteDocuments indexPaths: [URL]) { historyFile(deleteDocuments: indexPaths) } func historyFileViewController(_ viewController: KMHomeHistoryFileViewController, didSelectItemsAt indexPaths: [URL]) { for url in indexPaths { openHistoryFilePath(url: url) } } func historyFileViewController(_ viewController: KMHomeHistoryFileViewController, refreshLayout refresh: Bool) { self.refreshScrollView() } } // MARK: - KMPDFToolsViewControllerDelegate extension KMHomeViewController: KMPDFToolsViewControllerDelegate { func pdfToolsViewController(_ viewController: KMPDFToolsViewController, didSelectItemsAt indexPaths: [Int]) { for index in indexPaths { fastToolItemAction(DataNavigationViewButtonActionType(rawValue: index) ?? .Batch) } } } // MARK: - KMHomeDragViewDelegate extension KMHomeViewController: KMHomeDragViewDelegate { func homeDragView(_ viewController: KMHomeDragView, filePath: URL) { if self.aiHomeState == .AITranslation { self.aiTranslation(withFilePath: filePath.path) } else { self.openFile(withFilePath: filePath) } } func homeDragView(_ viewController: KMHomeDragView, notSupport: Bool) { if notSupport { let alert = NSAlert() alert.alertStyle = .critical alert.messageText = NSLocalizedString("This file format is not supported. Please enter PDF, picture, or Office file", comment: "") alert.runModal() } } }