// // KMPDFToolsViewController.swift // PDF Reader Pro // // Created by wanjun on 2022/11/16. // import Cocoa @objc protocol KMPDFToolsViewControllerDelegate { @objc optional func pdfToolsViewController(_ viewController: KMPDFToolsViewController, didSelectItemsAt indexPaths: [Int]) } class KMPDFToolsViewController: NSViewController { @IBOutlet weak var topBox: NSBox! @IBOutlet weak var pdfToolLabel: NSTextField! @IBOutlet weak var customizeBox: NSBox! @IBOutlet weak var customizeBoxHeight: NSLayoutConstraint! @IBOutlet weak var foldOrUnflodBox: NSBox! @IBOutlet weak var foldOrUnflodBoxHeight: NSLayoutConstraint! @IBOutlet weak var middleBox: NSBox! @IBOutlet weak var homeFastToolLabel: NSTextField! @IBOutlet weak var confirmBox: NSBox! @IBOutlet weak var confirmBoxHeight: NSLayoutConstraint! @IBOutlet weak var cancelBox: NSBox! @IBOutlet weak var cancelBoxHeight: NSLayoutConstraint! @IBOutlet weak var homeFastToolBox: NSBox! @IBOutlet weak var homeFastToolScrollView: NSScrollView! @IBOutlet weak var homeFastToolCollectionView: KMPDFToolsCollectionView! @IBOutlet weak var bottomBox: NSBox! @IBOutlet weak var moreToolLabel: NSTextField! @IBOutlet weak var moreToolBox: NSBox! @IBOutlet weak var moreToolScrollView: NSScrollView! @IBOutlet weak var moreToolCollectionView: KMPDFToolsCollectionView! @IBOutlet var homeViewController: KMHomeViewController! @IBOutlet weak var homeFastToolBoxHeightConstraint: NSLayoutConstraint! @IBOutlet weak var moreToolBoxHeightConstraint: NSLayoutConstraint! @IBOutlet weak var moreToolBoxTopConstraint: NSLayoutConstraint! var customizeVC: KMDesignButton! var foldOrUnflodVC: KMDesignButton! var confirmVC: KMDesignButton! var cancelVC: KMDesignButton! var isFold: Bool! var isCustomize: Bool! = false var quickToolsItemMutableArray: [Int] = [] var moreToolsItemMutableArray: [Int] = [] open weak var delete: KMPDFToolsViewControllerDelegate? var collectionItemWidth: Int! = 230 var homeFastToolItemsDragged: Set = [] var moreTooltemsDragged: Set = [] var createFilePopover: NSPopover = NSPopover.init() override func viewDidLoad() { super.viewDidLoad() // Do view setup here. customizeVC = KMDesignButton.init(withType: .Text) foldOrUnflodVC = KMDesignButton.init(withType: .Image) confirmVC = KMDesignButton.init(withType: .Text) cancelVC = KMDesignButton.init(withType: .Text) homeFastToolCollectionView.register(KMFastToolCollectionViewItem.self, forItemWithIdentifier: NSUserInterfaceItemIdentifier(rawValue: "KMFastToolCollectionViewItem")) moreToolCollectionView.register(KMFastToolCollectionViewItem.self, forItemWithIdentifier: NSUserInterfaceItemIdentifier(rawValue: "KMFastToolCollectionViewItem")) isFold = UserDefaults.standard.bool(forKey: "kHomeQucikToolsTypeKey") let moreToolsArray = UserDefaults.standard.array(forKey: "MoreToolsItemArrayKey") as? [Int] ?? [] if (moreToolsArray.count > 0) { moreToolsItemMutableArray = moreToolsArray } else { moreToolsItemMutableArray = moreToolsFullArray() UserDefaults.standard.set(moreToolsItemMutableArray, forKey: "MoreToolsItemArrayKey") UserDefaults.standard.synchronize() } let quickToolsArray = UserDefaults.standard.array(forKey: "HomeQucikToolsItemArrayKey") as? [Int] ?? [] if (quickToolsArray.count > 0) { quickToolsItemMutableArray = quickToolsArray } else { quickToolsItemMutableArray = quickToolsFullArray() UserDefaults.standard.set(quickToolsItemMutableArray, forKey: "HomeQucikToolsItemArrayKey") UserDefaults.standard.synchronize() } registerForCollectionViewDragAndDrop() } override func viewDidAppear() { super.viewDidAppear() isFold = UserDefaults.standard.bool(forKey: "kHomeQucikToolsTypeKey") customStateChange(isCustomize) foldStateChange(isFold) self.view.postsBoundsChangedNotifications = true NotificationCenter.default.addObserver(self, selector: #selector(boundsDidChangeNotification), name: NSView.frameDidChangeNotification, object: self.view) reloadData() } // MARK: Init func initializeUI() -> Void { topBox.fillColor = .clear middleBox.fillColor = .clear bottomBox.fillColor = .clear customizeBox.fillColor = .clear customizeBox.contentView = customizeVC.view customizeVC.target = self customizeVC.action = #selector(customButtonAction(_:)) customizeVC.button(type: .Sec, size: .m, height: customizeBoxHeight) foldOrUnflodBox.fillColor = .clear foldOrUnflodBox.contentView = foldOrUnflodVC.view foldOrUnflodVC.image = NSImage(named: "icon_btn_more_false_false")! foldOrUnflodVC.target = self foldOrUnflodVC.action = #selector(foldOrUnflodButtonAction(_:)) foldOrUnflodVC.button(type: .Sec, size: .m, height: foldOrUnflodBoxHeight) pdfToolLabel.textColor = NSColor.km_init(hex: "#000000") pdfToolLabel.font = NSFont(name: "PingFangSC-Semibold", size: 16.0) homeFastToolLabel.font = NSFont(name: "SFProText-Semibold", size: 14.0) homeFastToolLabel.textColor = NSColor.km_init(hex: "#616469") moreToolLabel.font = NSFont(name: "SFProText-Semibold", size: 14.0) moreToolLabel.textColor = NSColor.km_init(hex: "#616469") confirmBox.fillColor = .clear confirmBox.contentView = confirmVC.view confirmVC.target = self confirmVC.action = #selector(confirmAction(_:)) confirmVC.button(type: .Cta, size: .m, height: confirmBoxHeight) cancelBox.fillColor = .clear cancelBox.contentView = cancelVC.view cancelVC.target = self cancelVC.action = #selector(cancelAction(_:)) cancelVC.button(type: .Sec, size: .m, height: cancelBoxHeight) } func initLocalization() -> Void { pdfToolLabel.stringValue = NSLocalizedString("PDF Tools", comment: "") customizeVC.stringValue = NSLocalizedString("Custom", comment: "") customizeVC.toolTip = NSLocalizedString("Custom", comment: "") if isFold { foldOrUnflodVC.title = NSLocalizedString("Expand", comment: "") foldOrUnflodVC.toolTip = NSLocalizedString("Expand", comment: "") } else { foldOrUnflodVC.title = NSLocalizedString("Collapse", comment: "") foldOrUnflodVC.toolTip = NSLocalizedString("Collapse", comment: "") } homeFastToolLabel.stringValue = NSLocalizedString("Quick Tools", comment: "") confirmVC.stringValue = NSLocalizedString("Apply", comment: "") confirmVC.toolTip = NSLocalizedString("Apply", comment: "") cancelVC.stringValue = NSLocalizedString("Cancel", comment: "") cancelVC.toolTip = NSLocalizedString("Cancel", comment: "") moreToolLabel.stringValue = NSLocalizedString("More Tools", comment: "") } // MARK: private func quickToolsFullArray() -> [Int] { return [DataNavigationViewButtonActionType.PDFToWord.rawValue, DataNavigationViewButtonActionType.PDFToExcel.rawValue, DataNavigationViewButtonActionType.PDFToPPT.rawValue, DataNavigationViewButtonActionType.PDFToImage.rawValue, DataNavigationViewButtonActionType.Compression.rawValue, DataNavigationViewButtonActionType.Security.rawValue, DataNavigationViewButtonActionType.MergePDF.rawValue, DataNavigationViewButtonActionType.ImageToPDF.rawValue] } func moreToolsFullArray() -> [Int] { return [DataNavigationViewButtonActionType.Watermark.rawValue, DataNavigationViewButtonActionType.Background.rawValue, DataNavigationViewButtonActionType.HeaderAndFooter.rawValue, DataNavigationViewButtonActionType.BatesCode.rawValue, DataNavigationViewButtonActionType.BatchRemove.rawValue, DataNavigationViewButtonActionType.MarkCipher.rawValue, DataNavigationViewButtonActionType.Print.rawValue, DataNavigationViewButtonActionType.PageEdit.rawValue, DataNavigationViewButtonActionType.Insert.rawValue, DataNavigationViewButtonActionType.BreakUp.rawValue, DataNavigationViewButtonActionType.Extract.rawValue, DataNavigationViewButtonActionType.Batch.rawValue, DataNavigationViewButtonActionType.ConvertPDF.rawValue] } @IBAction func boundsDidChangeNotification(_ notification: NSNotification) -> Void { reloadData() } func reloadData() -> Void { initializeUI() initLocalization() collectionItemWidth = Int((homeFastToolCollectionView.bounds.width - (20 * 3))/4) dynamicsChangeMoreToolBoxHeight() homeFastToolCollectionView.reloadData() moreToolCollectionView.reloadData() } func customStateChange(_ custom: Bool) -> Void { confirmBox.isHidden = true cancelBox.isHidden = true customizeVC.isHidden = true foldOrUnflodVC.isHidden = true if custom { confirmBox.isHidden = false cancelBox.isHidden = false } else { customizeVC.isHidden = false foldOrUnflodVC.isHidden = false } reloadData() } func foldStateChange(_ fold: Bool) -> Void { if fold { homeFastToolBoxHeightConstraint.constant = 152 dynamicsChangeMoreToolBoxHeight() UserDefaults.standard.setValue(true, forKey: "kHomeQucikToolsTypeKey") } else { homeFastToolBoxHeightConstraint.constant = 248 dynamicsChangeMoreToolBoxHeight() UserDefaults.standard.setValue(false, forKey: "kHomeQucikToolsTypeKey") } UserDefaults.standard.synchronize() reloadData() } func dynamicsChangeMoreToolBoxHeight() -> Void { let height = self.view.frame.height - middleBox.frame.height - topBox.frame.height - moreToolBoxTopConstraint.constant if isFold { if height > 320 { moreToolBoxHeightConstraint.constant = 320 } else { moreToolBoxHeightConstraint.constant = height } } else { if height > 512 { moreToolBoxHeightConstraint.constant = 512 } else { moreToolBoxHeightConstraint.constant = height } } } func registerForCollectionViewDragAndDrop() -> Void { homeFastToolCollectionView.registerForDraggedTypes([.string]) homeFastToolCollectionView.setDraggingSourceOperationMask(.every, forLocal: false) homeFastToolCollectionView.setDraggingSourceOperationMask(.every, forLocal: true) moreToolCollectionView.registerForDraggedTypes([.string]) moreToolCollectionView.setDraggingSourceOperationMask(.every, forLocal: false) moreToolCollectionView.setDraggingSourceOperationMask(.every, forLocal: true) } func moveCell(index fromIndex: Int, toIndex: Int, collectionView: NSCollectionView) -> Void { if collectionView.isEqual(to: homeFastToolCollectionView) { let currentIndex: Int = quickToolsItemMutableArray[fromIndex] if fromIndex <= toIndex { } } else if collectionView.isEqual(to: moreToolCollectionView) { } } func createPopoverAction(_ data: [String], view: NSView) { let vc: KMHomePopViewController = KMHomePopViewController().initWithPopViewDataArr(data) self.createFilePopover.contentViewController = vc self.createFilePopover.animates = true self.createFilePopover.behavior = .semitransient self.createFilePopover.setValue(true, forKey: "shouldHideAnchor") self.createFilePopover.show(relativeTo: CGRect(x: view.bounds.origin.x, y: 10, width: view.bounds.size.width, height: view.bounds.size.height), of: view, preferredEdge: .minY) vc.downCallback = {(downEntered: Bool, count: String) -> Void in if downEntered { self.moreToolsAction(vc) } } } // MARK: Action // 是否开启自定义模式 @IBAction func customButtonAction(_ sender: NSButton) { isCustomize = !isCustomize customStateChange(isCustomize) } @IBAction func foldOrUnflodButtonAction(_ sender: NSButton) { if self.createFilePopover.isShown { self.createFilePopover.close() } else { if isFold { self.createPopoverAction([NSLocalizedString("Expand", comment: "")], view: foldOrUnflodBox) } else { self.createPopoverAction([NSLocalizedString("Collapse", comment: "")], view: foldOrUnflodBox) } } } func moreToolsAction(_ viewController: KMHomePopViewController) { isFold = !isFold foldStateChange(isFold) if isFold { viewController.changePopViewCellData(0, content: NSLocalizedString("Expand", comment: "")) } else { viewController.changePopViewCellData(0, content: NSLocalizedString("Collapse", comment: "")) } } @IBAction func cancelAction(_ sender: Any) { isCustomize = !isCustomize customStateChange(isCustomize) } @IBAction func confirmAction(_ sender: Any) { UserDefaults.standard.set(moreToolsItemMutableArray, forKey: "MoreToolsItemArrayKey") UserDefaults.standard.set(quickToolsItemMutableArray, forKey: "HomeQucikToolsItemArrayKey") UserDefaults.standard.synchronize() isCustomize = !isCustomize customStateChange(isCustomize) } } // MARK: - NSCollectionViewDataSource extension KMPDFToolsViewController: NSCollectionViewDataSource { func collectionView(_ collectionView: NSCollectionView, numberOfItemsInSection section: Int) -> Int { if collectionView.isEqual(to: homeFastToolCollectionView) { return quickToolsItemMutableArray.count } else if collectionView.isEqual(to: moreToolCollectionView) { return moreToolsItemMutableArray.count } return 0 } func collectionView(_ collectionView: NSCollectionView, itemForRepresentedObjectAt indexPath: IndexPath) -> NSCollectionViewItem { if collectionView.isEqual(to: homeFastToolCollectionView) { let item: KMFastToolCollectionViewItem = collectionView.makeItem(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "KMFastToolCollectionViewItem"), for: indexPath) as! KMFastToolCollectionViewItem item.card(bg: "card.has-desc.bg.norm", titleText: "card.mac-text.title", descText: "card.mac-text.desc", spacing: "card.item-spacing") item.card(bg: "card.has-desc.bg.hov", titleText: "card.mac-text.title", descText: "card.mac-text.desc", spacing: "card.item-spacing", state: .Hov) item.card(bg: "card.has-desc.bg.sel", titleText: "card.mac-text.title", descText: "card.mac-text.desc", spacing: "card.item-spacing", state: .Sel) item.card(bg: "card.has-desc.bg.custom", titleText: "card.mac-text.title", descText: "card.mac-text.desc", spacing: "card.item-spacing", state: .Custom) item.card(bg: "card.has-desc.bg.none", state: .None) item.card(bg: "card.has-desc.bg.change", titleText: "card.win-text.title", descText: "card.win-text.desc", spacing: "card.item-spacing", state: .Change) let i: Int = indexPath.item let index: Int = quickToolsItemMutableArray[i] item.quickToolsCollectionCellItem(type: DataNavigationViewButtonActionType(rawValue: index) ?? .Batch) item.refreshHoverStatus(!isCustomize, !isCustomize) item.refreshUIColor(isCustomize) return item } else if collectionView.isEqual(to: moreToolCollectionView) { let item: KMFastToolCollectionViewItem = collectionView.makeItem(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "KMFastToolCollectionViewItem"), for: indexPath) as! KMFastToolCollectionViewItem item.card(bg: "card.has-desc.bg.norm", titleText: "card.mac-text.title", descText: "card.mac-text.desc", spacing: "card.item-spacing") item.card(bg: "card.has-desc.bg.hov", titleText: "card.mac-text.title", descText: "card.mac-text.desc", spacing: "card.item-spacing", state: .Hov) item.card(bg: "card.has-desc.bg.sel", titleText: "card.mac-text.title", descText: "card.mac-text.desc", spacing: "card.item-spacing", state: .Sel) item.card(bg: "card.has-desc.bg.custom", titleText: "card.mac-text.title", descText: "card.mac-text.desc", spacing: "card.item-spacing", state: .Custom) item.card(bg: "card.has-desc.bg.none", state: .None) item.card(bg: "card.has-desc.bg.change", titleText: "card.win-text.title", descText: "card.win-text.desc", spacing: "card.item-spacing", state: .Change) let i: Int = indexPath.item let index: Int = moreToolsItemMutableArray[i] item.quickToolsCollectionCellItem(type: DataNavigationViewButtonActionType(rawValue: index) ?? .Batch) item.refreshHoverStatus(!isCustomize, !isCustomize) return item } return NSCollectionViewItem.init() } } // MARK: - NSCollectionViewDelegate extension KMPDFToolsViewController: NSCollectionViewDelegate { func collectionView(_ collectionView: NSCollectionView, didSelectItemsAt indexPaths: Set) { if !isCustomize { var indexs: [Int] = [] if collectionView.isEqual(to: homeFastToolCollectionView) { for index in indexPaths { let i: Int = index.item let index: Int = quickToolsItemMutableArray[i] indexs.append(index) } } else if collectionView.isEqual(to: moreToolCollectionView) { for index in indexPaths { let i: Int = index.item let index: Int = moreToolsItemMutableArray[i] indexs.append(index) } } self.delete?.pdfToolsViewController!(self, didSelectItemsAt: indexs) collectionView.deselectAll([]) } } func collectionView(_ collectionView: NSCollectionView, canDragItemsAt indexPaths: Set, with event: NSEvent) -> Bool { if isCustomize { return true } return false } func collectionView(_ collectionView: NSCollectionView, pasteboardWriterForItemAt indexPath: IndexPath) -> NSPasteboardWriting? { guard let model = indexPath as? IndexPath else { return nil } let pastBoard = NSPasteboardItem.init() pastBoard.setString(String(format: "%ld", model.item), forType: NSPasteboard.PasteboardType.string) return pastBoard } func collectionView(_ collectionView: NSCollectionView, draggingSession session: NSDraggingSession, willBeginAt screenPoint: NSPoint, forItemsAt indexPaths: Set) { if collectionView.isEqual(to: homeFastToolCollectionView) { homeFastToolItemsDragged = indexPaths } else if collectionView.isEqual(to: moreToolCollectionView) { moreTooltemsDragged = indexPaths } } func collectionView(_ collectionView: NSCollectionView, validateDrop draggingInfo: NSDraggingInfo, proposedIndexPath proposedDropIndexPath: AutoreleasingUnsafeMutablePointer, dropOperation proposedDropOperation: UnsafeMutablePointer) -> NSDragOperation { if collectionView.isEqual(to: homeFastToolCollectionView) { if !homeFastToolItemsDragged.isEmpty { return .move } else { return .copy } } else if collectionView.isEqual(to: moreToolCollectionView) { if !moreTooltemsDragged.isEmpty { return .move } else { return .copy } } return [] } func collectionView(_ collectionView: NSCollectionView, acceptDrop draggingInfo: NSDraggingInfo, indexPath: IndexPath, dropOperation: NSCollectionView.DropOperation) -> Bool { var result: Bool = false if collectionView.isEqual(to: homeFastToolCollectionView) { if !homeFastToolItemsDragged.isEmpty { var toItemIndex = indexPath.item for fromIndexPath in homeFastToolItemsDragged.sorted() { let fromItemIndex = fromIndexPath.item if fromItemIndex > toItemIndex { homeFastToolCollectionView.animator().moveItem(at: IndexPath(item: fromItemIndex, section: indexPath.section), to: IndexPath(item: toItemIndex, section: indexPath.section)) toItemIndex += 1 } } var adjustedToItemIndex = indexPath.item for fromIndexPath in homeFastToolItemsDragged.sorted(by: >) { let fromItemIndex = fromIndexPath.item if fromItemIndex < adjustedToItemIndex { if adjustedToItemIndex >= quickToolsItemMutableArray.count { adjustedToItemIndex = quickToolsItemMutableArray.count - 1; } let adjustedToIndexPath = IndexPath(item: adjustedToItemIndex, section: indexPath.section) homeFastToolCollectionView.animator().moveItem(at: IndexPath(item: fromItemIndex, section: indexPath.section), to: adjustedToIndexPath) adjustedToItemIndex -= 1 } } result = true } else if !moreTooltemsDragged.isEmpty { let array = Array(moreTooltemsDragged) let toItemIndex = array[0].item let insertIndex = quickToolsItemMutableArray[indexPath.item] quickToolsItemMutableArray.remove(at: indexPath.item) quickToolsItemMutableArray.insert(moreToolsItemMutableArray[toItemIndex], at: indexPath.item) moreToolsItemMutableArray.remove(at: toItemIndex) // moreToolsItemMutableArray.insert(insertIndex, at: toItemIndex) moreToolsItemMutableArray.insert(insertIndex, at: 0) result = true } } else if collectionView.isEqual(to: moreToolCollectionView) { if !moreTooltemsDragged.isEmpty { var toItemIndex = indexPath.item for fromIndexPath in moreTooltemsDragged.sorted() { let fromItemIndex = fromIndexPath.item if fromItemIndex > toItemIndex { moreToolCollectionView.animator().moveItem(at: IndexPath(item: fromItemIndex, section: indexPath.section), to: IndexPath(item: toItemIndex, section: indexPath.section)) toItemIndex += 1 } } var adjustedToItemIndex = indexPath.item - 1 for fromIndexPath in moreTooltemsDragged.sorted(by: >) { let fromItemIndex = fromIndexPath.item if fromItemIndex < adjustedToItemIndex { if adjustedToItemIndex >= quickToolsItemMutableArray.count { adjustedToItemIndex = quickToolsItemMutableArray.count - 1 } let adjustedToIndexPath = IndexPath(item: adjustedToItemIndex, section: indexPath.section) moreToolCollectionView.animator().moveItem(at: IndexPath(item: fromItemIndex, section: indexPath.section), to: adjustedToIndexPath) adjustedToItemIndex -= 1 } } result = true } else if !homeFastToolItemsDragged.isEmpty { let array = Array(homeFastToolItemsDragged) let toItemIndex = array[0].item let insertIndex = moreToolsItemMutableArray[indexPath.item] moreToolsItemMutableArray.remove(at: indexPath.item) moreToolsItemMutableArray.insert(quickToolsItemMutableArray[toItemIndex], at: indexPath.item) quickToolsItemMutableArray.remove(at: toItemIndex) // quickToolsItemMutableArray.insert(insertIndex, at: toItemIndex) quickToolsItemMutableArray.insert(insertIndex, at: 0) result = true } } return result } func collectionView(_ collectionView: NSCollectionView, draggingSession session: NSDraggingSession, endedAt screenPoint: NSPoint, dragOperation operation: NSDragOperation) { if collectionView.isEqual(to: homeFastToolCollectionView) { homeFastToolItemsDragged = Set() } else if collectionView.isEqual(to: moreToolCollectionView) { moreTooltemsDragged = Set() } homeFastToolCollectionView.reloadSections(IndexSet(integer: 0)) moreToolCollectionView.reloadSections(IndexSet(integer: 0)) } } // MARK: - NSCollectionViewDelegateFlowLayout extension KMPDFToolsViewController: NSCollectionViewDelegateFlowLayout { func collectionView(_ collectionView: NSCollectionView, layout collectionViewLayout: NSCollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> NSSize { if collectionView.isEqual(to: homeFastToolCollectionView) { if isFold { return CGSize(width: collectionItemWidth, height: 68) } else { return CGSize(width: collectionItemWidth, height: 116) } } else if collectionView.isEqual(to: moreToolCollectionView) { if isFold { return CGSize(width: collectionItemWidth, height: 68) } else { return CGSize(width: collectionItemWidth, height: 116) } } return CGSize(width: collectionItemWidth, height: 116) } func collectionView(_ collectionView: NSCollectionView, layout collectionViewLayout: NSCollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat { if collectionView.isEqual(to: homeFastToolCollectionView) { return 16 } else if collectionView.isEqual(to: moreToolCollectionView) { return 16 } return 16 } func collectionView(_ collectionView: NSCollectionView, layout collectionViewLayout: NSCollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat { if collectionView.isEqual(to: homeFastToolCollectionView) { return 0 } else if collectionView.isEqual(to: moreToolCollectionView) { return 0 } return 0 } }