|
@@ -0,0 +1,918 @@
|
|
|
+//
|
|
|
+// AIConfigWindowController.swift
|
|
|
+// PDF Reader Pro Edition
|
|
|
+//
|
|
|
+// Created by Niehaoyu on 2024/1/17.
|
|
|
+//
|
|
|
+
|
|
|
+import Cocoa
|
|
|
+
|
|
|
+@objcMembers class AIConfigWindowController: NSWindowController, NSTextFieldDelegate, NSTextViewDelegate {
|
|
|
+
|
|
|
+ @IBOutlet weak var contendBox: NSBox!
|
|
|
+ @IBOutlet weak var titleLabel: NSTextField!
|
|
|
+ @IBOutlet weak var titleTipBtn: KMButton!
|
|
|
+
|
|
|
+ @IBOutlet weak var uploadBGView: NSView!
|
|
|
+ @IBOutlet weak var uploadItemBox: KMBox!
|
|
|
+ @IBOutlet weak var uploadDesLabel: NSTextField!
|
|
|
+ @IBOutlet weak var uploadPDFBtn: KMButton!
|
|
|
+
|
|
|
+ @IBOutlet weak var fileBGView: NSView!
|
|
|
+ @IBOutlet weak var fileEmptyImage: NSImageView!
|
|
|
+ @IBOutlet weak var fileActionView: NSView!
|
|
|
+ @IBOutlet weak var fileActionLabel: NSTextField!
|
|
|
+ @IBOutlet weak var fileActionBtn: KMButton!
|
|
|
+ @IBOutlet weak var filePDFBGView: NSView!
|
|
|
+ @IBOutlet weak var filePDFHoverBtn: KMButton!
|
|
|
+ @IBOutlet weak var pdfCoverView: NSView!
|
|
|
+ @IBOutlet weak var pdfCoverImageView: NSImageView!
|
|
|
+ @IBOutlet weak var removePDFBtn: NSButton!
|
|
|
+ @IBOutlet weak var inputTextCountLabel: NSTextField!
|
|
|
+ @IBOutlet weak var fileSizeTipView: NSView!
|
|
|
+ @IBOutlet weak var fileSizeTipLabel: NSTextField!
|
|
|
+ @IBOutlet weak var pdfNameLbl: NSTextField!
|
|
|
+ @IBOutlet var fileEmptyTextView: NSTextView!
|
|
|
+ @IBOutlet weak var filePlaceholdLabel: NSTextField!
|
|
|
+
|
|
|
+
|
|
|
+ @IBOutlet weak var fileContendViewTopConst: NSLayoutConstraint!
|
|
|
+
|
|
|
+ @IBOutlet weak var translateSepLineView: NSView!
|
|
|
+ @IBOutlet weak var translateConfigView: NSView!
|
|
|
+
|
|
|
+ @IBOutlet weak var fromLanguageView: NSView!
|
|
|
+ @IBOutlet weak var fromLanguageLabel: NSTextField!
|
|
|
+ @IBOutlet weak var fromLanguageBtn: NSButton!
|
|
|
+
|
|
|
+ @IBOutlet weak var toLanguageView: NSView!
|
|
|
+ @IBOutlet weak var toLanguageLabel: NSTextField!
|
|
|
+ @IBOutlet weak var toLanguageBtn: NSButton!
|
|
|
+
|
|
|
+ @IBOutlet weak var translateResultView: NSView!
|
|
|
+ @IBOutlet weak var translateResultLabel: NSTextField!
|
|
|
+ @IBOutlet weak var translateResultSubLabel: NSTextField!
|
|
|
+
|
|
|
+
|
|
|
+ @IBOutlet weak var resultBGView: NSView!
|
|
|
+ @IBOutlet weak var resultEmptyImage: NSImageView!
|
|
|
+// @IBOutlet weak var resultLabel: NSTextField!
|
|
|
+ @IBOutlet var aiResultTextView: NSTextView!
|
|
|
+
|
|
|
+ @IBOutlet weak var cancelBtn: NSButton!
|
|
|
+ @IBOutlet weak var saveAsTextBtn: NSButton!
|
|
|
+ @IBOutlet weak var saveAsPDFBtn: NSButton!
|
|
|
+
|
|
|
+ static var currentWindowController: AIConfigWindowController!
|
|
|
+
|
|
|
+ var popOver: NSPopover!
|
|
|
+
|
|
|
+ var configType: AIConfigType = .none
|
|
|
+
|
|
|
+ var cancelHandle: ((_ windowVC: AIConfigWindowController) -> Void)?
|
|
|
+
|
|
|
+ var fileActionenAble: Bool = false
|
|
|
+
|
|
|
+ var aiConvertFinish: Bool = true
|
|
|
+ var filePath: String = ""
|
|
|
+
|
|
|
+ var fromLanguage: String = ""
|
|
|
+ var toLanguage: String = ""
|
|
|
+
|
|
|
+ var translateFinish: Bool = false
|
|
|
+ var translateFile: Bool = false
|
|
|
+ var translateResultPath: String = ""
|
|
|
+
|
|
|
+ @objc static func currentWC() -> AIConfigWindowController {
|
|
|
+ if currentWindowController != nil {
|
|
|
+ return currentWindowController
|
|
|
+ } else {
|
|
|
+ let configWC: AIConfigWindowController = AIConfigWindowController.init(windowNibName: "AIConfigWindowController")
|
|
|
+ currentWindowController = configWC;
|
|
|
+ return currentWindowController
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ 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.SFProTextSemiboldFont(13)
|
|
|
+
|
|
|
+ self.titleTipBtn.mouseMoveCallback = {[unowned self] mouseEntered in
|
|
|
+ if mouseEntered {
|
|
|
+ var tipString = NSLocalizedString("Recommended file size: 10M or less.", comment: "")
|
|
|
+ if self.configType == .reWriting {
|
|
|
+ tipString = NSLocalizedString("No more than 2000 characters.", comment: "")
|
|
|
+ } else if self.configType == .proofreading {
|
|
|
+ tipString = NSLocalizedString("No more than 2000 characters.", comment: "")
|
|
|
+ } else if self.configType == .translate {
|
|
|
+ tipString = NSLocalizedString("No more than 30 pages of a document.", comment: "")
|
|
|
+ }
|
|
|
+ let popViewController = KMToolbarItemPopViewController.init()
|
|
|
+ if self.popOver == nil {
|
|
|
+ self.popOver = NSPopover.init()
|
|
|
+ }
|
|
|
+ self.popOver.contentViewController = popViewController
|
|
|
+ self.popOver.animates = false
|
|
|
+ self.popOver.behavior = .semitransient
|
|
|
+ self.popOver.contentSize = (popViewController.view.frame.size)
|
|
|
+ popViewController.updateWithHelpTip(helpTip: tipString)
|
|
|
+ self.popOver.show(relativeTo: self.titleTipBtn.frame, of: (self.window?.contentView)!, preferredEdge: .maxY)
|
|
|
+ } else {
|
|
|
+ self.popOver.close()
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ self.uploadItemBox.borderWidth = 0
|
|
|
+ self.uploadItemBox.cornerRadius = 1
|
|
|
+ self.uploadItemBox.fillColor = KMAppearance.KMColor_Interactive_S0()
|
|
|
+ self.uploadDesLabel.font = NSFont.SFProTextRegularFont(13)
|
|
|
+ self.uploadDesLabel.textColor = KMAppearance.KMColor_Layout_H0()
|
|
|
+ self.uploadDesLabel.stringValue = NSLocalizedString("Choose", comment: "")
|
|
|
+
|
|
|
+ self.uploadPDFBtn.mouseMoveCallback = {[unowned self] mouseEntered in
|
|
|
+ if mouseEntered {
|
|
|
+ self.uploadItemBox.fillColor = KMAppearance.KMColor_Interactive_S_1()
|
|
|
+ } else {
|
|
|
+ self.uploadItemBox.fillColor = KMAppearance.KMColor_Interactive_S0()
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ self.fileBGView.wantsLayer = true
|
|
|
+ self.fileBGView.layer?.cornerRadius = 6
|
|
|
+ self.fileBGView.layer?.masksToBounds = true
|
|
|
+ self.fileBGView.layer?.borderWidth = 1
|
|
|
+ self.fileBGView.layer?.borderColor = KMAppearance.KMColor_Layout_L_2().cgColor
|
|
|
+
|
|
|
+ self.fileSizeTipView.wantsLayer = true
|
|
|
+ self.fileSizeTipLabel.font = NSFont.SFProTextRegularFont(12)
|
|
|
+ self.fileSizeTipLabel.textColor = KMAppearance.KMColor_Layout_H0()
|
|
|
+ self.fileSizeTipLabel.stringValue = NSLocalizedString("Please upload a file smaller than 10M.", comment: "")
|
|
|
+ self.fileSizeTipView.isHidden = true
|
|
|
+
|
|
|
+ self.pdfNameLbl.font = NSFont.SFProTextRegularFont(12)
|
|
|
+ self.pdfNameLbl.textColor = KMAppearance.KMColor_Layout_H0()
|
|
|
+
|
|
|
+ self.resultBGView.wantsLayer = true
|
|
|
+ self.resultBGView.layer?.cornerRadius = 6
|
|
|
+ self.resultBGView.layer?.masksToBounds = true
|
|
|
+
|
|
|
+ self.fileActionView.wantsLayer = true
|
|
|
+ self.fileActionView.layer?.cornerRadius = 1
|
|
|
+ self.fileActionView.layer?.masksToBounds = true
|
|
|
+ self.fileActionLabel.font = NSFont.SFProTextRegularFont(13)
|
|
|
+
|
|
|
+ self.fileActionBtn.mouseMoveCallback = {[unowned self] mouseEntered in
|
|
|
+ if self.fileActionenAble == true {
|
|
|
+ if mouseEntered {
|
|
|
+ self.fileActionView.layer?.backgroundColor = KMAppearance.KMColor_Interactive_M_1().cgColor
|
|
|
+ } else {
|
|
|
+ self.fileActionView.layer?.backgroundColor = KMAppearance.KMColor_Interactive_M0().cgColor
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ self.translateSepLineView.wantsLayer = true
|
|
|
+
|
|
|
+ self.pdfCoverView.wantsLayer = true
|
|
|
+ self.pdfCoverView.layer?.cornerRadius = 2
|
|
|
+ self.pdfCoverView.layer?.borderWidth = 2
|
|
|
+
|
|
|
+ let countFormatter = TextFieldFormatter.init()
|
|
|
+ countFormatter.setMaximumLength(2000)
|
|
|
+ self.inputTextCountLabel.formatter = countFormatter
|
|
|
+ self.inputTextCountLabel.delegate = self
|
|
|
+
|
|
|
+ if KMAppearance.isDarkMode() {
|
|
|
+ self.contendBox.fillColor = NSColor(red: 44/255, green: 44/255, blue: 44/255, alpha: 1)
|
|
|
+ self.titleLabel.textColor = NSColor.white
|
|
|
+ self.resultBGView.layer?.backgroundColor = NSColor(red: 49/255, green: 49/255, blue: 49/255, alpha: 1).cgColor
|
|
|
+ self.inputTextCountLabel.textColor = KMAppearance.KMColor_Layout_W30()
|
|
|
+ self.fileSizeTipView.layer?.backgroundColor = NSColor(red: 251/255, green: 166/255, blue: 0, alpha: 1).cgColor
|
|
|
+ self.translateSepLineView.layer?.backgroundColor = NSColor.white.withAlphaComponent(0.05).cgColor
|
|
|
+ self.translateResultView.layer?.backgroundColor = NSColor.white.withAlphaComponent(0.05).cgColor
|
|
|
+
|
|
|
+ self.pdfCoverView.layer?.borderColor = NSColor.white.withAlphaComponent(0.2).cgColor
|
|
|
+ self.pdfCoverView.layer?.backgroundColor = NSColor.white.withAlphaComponent(0.1).cgColor
|
|
|
+ } else {
|
|
|
+ self.contendBox.fillColor = NSColor.white
|
|
|
+ self.titleLabel.textColor = NSColor.black
|
|
|
+ self.resultBGView.layer?.backgroundColor = NSColor(red: 0, green: 0, blue: 0, alpha: 0.05).cgColor
|
|
|
+ self.inputTextCountLabel.textColor = KMAppearance.KMColor_Layout_B30()
|
|
|
+ self.fileSizeTipView.layer?.backgroundColor = NSColor(red: 253/255, green: 239/255, blue: 212/255, alpha: 1).cgColor
|
|
|
+ self.translateSepLineView.layer?.backgroundColor = NSColor.black.withAlphaComponent(0.05).cgColor
|
|
|
+ self.translateResultView.layer?.backgroundColor = NSColor.black.withAlphaComponent(0.05).cgColor
|
|
|
+ self.pdfCoverView.layer?.borderColor = NSColor.black.withAlphaComponent(0.12).cgColor
|
|
|
+ self.pdfCoverView.layer?.backgroundColor = NSColor.black.withAlphaComponent(0.04).cgColor
|
|
|
+ }
|
|
|
+
|
|
|
+ self.fileEmptyTextView.backgroundColor = NSColor.clear
|
|
|
+ self.fileEmptyTextView.delegate = self
|
|
|
+
|
|
|
+ self.window?.makeFirstResponder(nil)
|
|
|
+
|
|
|
+ var languages = ["Automatic", "English", "Simplified Chinese", "Traditional Chinese", "Japanese", "Korean", "French", "Spanish", "Italian", "German", "Portuguese", "Russian", "Vietnamese", "Thai", "Arabic", "Greek", "Bulgarian", "Finnish", "Slovene", "Dutch", "Czech", "Swedish", "Polish", "Danish", "Romanian", "Hungarian"]
|
|
|
+ let menu = NSMenu.init()
|
|
|
+ for idx in 0...languages.count-1 {
|
|
|
+ let string = languages[idx]
|
|
|
+ let menuItem = NSMenuItem.init(title: string, action: #selector(menuItemClick(_:)), keyEquivalent: "")
|
|
|
+ menuItem.tag = 1000 + idx
|
|
|
+ menu.addItem(menuItem)
|
|
|
+ }
|
|
|
+ self.fromLanguageView?.menu = menu
|
|
|
+ self.fromLanguage = "Automatic"
|
|
|
+
|
|
|
+ languages = ["English", "Simplified Chinese", "Traditional Chinese", "Japanese", "Korean", "French", "Spanish", "Italian", "German", "Portuguese", "Russian", "Vietnamese", "Thai", "Arabic", "Greek", "Bulgarian", "Finnish", "Slovene", "Dutch", "Czech", "Swedish", "Polish", "Danish", "Romanian", "Hungarian"]
|
|
|
+ var toMenu = NSMenu.init()
|
|
|
+ for idx in 0...languages.count-1 {
|
|
|
+ let string = languages[idx]
|
|
|
+ let menuItem = NSMenuItem.init(title: string, action: #selector(menuItemClick(_:)), keyEquivalent: "")
|
|
|
+ menuItem.tag = 3000 + idx
|
|
|
+ toMenu.addItem(menuItem)
|
|
|
+ }
|
|
|
+ self.toLanguageView?.menu = toMenu
|
|
|
+ self.toLanguage = "English"
|
|
|
+
|
|
|
+ self.fromLanguageLabel.font = NSFont.SFProTextRegularFont(13)
|
|
|
+ self.toLanguageLabel.font = NSFont.SFProTextRegularFont(13)
|
|
|
+ self.fromLanguageLabel.textColor = KMAppearance.KMColor_Layout_H0()
|
|
|
+ self.toLanguageLabel.textColor = KMAppearance.KMColor_Layout_H0()
|
|
|
+
|
|
|
+ self.fromLanguageLabel.stringValue = self.fromLanguage
|
|
|
+ self.toLanguageLabel.stringValue = self.toLanguage
|
|
|
+
|
|
|
+ self.removePDFBtn.isHidden = true
|
|
|
+ self.filePDFHoverBtn.mouseMoveCallback = {[unowned self] mouseEntered in
|
|
|
+ if mouseEntered {
|
|
|
+ self.removePDFBtn.isHidden = false
|
|
|
+ } else {
|
|
|
+ self.removePDFBtn.isHidden = true
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ self.cancelBtn.title = NSLocalizedString("Cancel", comment: "")
|
|
|
+ self.saveAsTextBtn.title = NSLocalizedString("Save as TXT", comment: "")
|
|
|
+ self.saveAsPDFBtn.title = NSLocalizedString("Save as PDF", comment: "")
|
|
|
+ self.translateResultLabel.stringValue = NSLocalizedString("Translation Completion", comment: "")
|
|
|
+ self.translateResultSubLabel.stringValue = NSLocalizedString("Click \"Save as PDF\" to save the result as a PDF file.", comment: "")
|
|
|
+
|
|
|
+ self.translateResultView.isHidden = true
|
|
|
+ self.translateResultView.wantsLayer = true
|
|
|
+
|
|
|
+
|
|
|
+ if KMAppearance.isDarkMode() {
|
|
|
+ self.translateResultLabel.textColor = NSColor.white
|
|
|
+ self.translateResultSubLabel.textColor = NSColor.white
|
|
|
+ } else {
|
|
|
+ self.translateResultLabel.textColor = NSColor.black.withAlphaComponent(0.5)
|
|
|
+ self.translateResultSubLabel.textColor = NSColor.black.withAlphaComponent(0.5)
|
|
|
+ }
|
|
|
+
|
|
|
+ self.translateResultLabel.font = NSFont.SFProTextSemiboldFont(13)
|
|
|
+ self.translateResultSubLabel.font = NSFont.SFProTextRegularFont(13)
|
|
|
+
|
|
|
+ self.aiResultTextView.font = NSFont.SFProTextRegularFont(14)
|
|
|
+ self.aiResultTextView.textColor = KMAppearance.KMColor_Layout_H0()
|
|
|
+ self.aiResultTextView.backgroundColor = NSColor.clear
|
|
|
+ self.aiResultTextView.isEditable = false
|
|
|
+
|
|
|
+ self.fileEmptyTextView.font = NSFont.SFProTextRegularFont(14)
|
|
|
+ self.fileEmptyTextView.textColor = KMAppearance.KMColor_Layout_H0()
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ func getFileSize(atPath filePath : String) -> CGFloat {
|
|
|
+ guard let dict = try? FileManager.default.attributesOfItem(atPath: filePath) as NSDictionary else {
|
|
|
+ return 0
|
|
|
+ }
|
|
|
+ return CGFloat(dict.fileSize())
|
|
|
+ }
|
|
|
+
|
|
|
+ func refreshUI() -> Void {
|
|
|
+ if self.configType == .summarize {
|
|
|
+ self.titleLabel.stringValue = NSLocalizedString("AI Summarize", comment: "")
|
|
|
+ self.fileEmptyImage.image = NSImage(named: "ai_summary_Empty")
|
|
|
+ } else if self.configType == .reWriting {
|
|
|
+ self.titleLabel.stringValue = NSLocalizedString("AI Rewrite", comment: "")
|
|
|
+ self.fileEmptyImage.image = NSImage(named: "ai_rewriting_empty")
|
|
|
+ } else if self.configType == .proofreading {
|
|
|
+ self.titleLabel.stringValue = NSLocalizedString("AI Proofread", comment: "")
|
|
|
+ self.fileEmptyImage.image = NSImage(named: "ai_proofreading_empty")
|
|
|
+ } else if self.configType == .translate {
|
|
|
+ self.titleLabel.stringValue = NSLocalizedString("AI Translate", comment: "")
|
|
|
+ self.fileEmptyImage.image = NSImage(named: "ai_translate_empty")
|
|
|
+ }
|
|
|
+
|
|
|
+ self.translateResultView.isHidden = true
|
|
|
+ self.translateConfigView.isHidden = true
|
|
|
+ self.translateSepLineView.isHidden = true
|
|
|
+
|
|
|
+ if self.configType == .reWriting ||
|
|
|
+ self.configType == .proofreading {
|
|
|
+ self.uploadBGView.isHidden = true
|
|
|
+ self.fileContendViewTopConst.constant = 52
|
|
|
+ self.filePDFBGView.isHidden = true
|
|
|
+ } else {
|
|
|
+ self.uploadBGView.isHidden = false
|
|
|
+
|
|
|
+ self.fileContendViewTopConst.constant = 92
|
|
|
+ self.filePDFBGView.isHidden = false
|
|
|
+ if self.configType == .translate {
|
|
|
+ self.fileContendViewTopConst.constant = 137
|
|
|
+ self.translateConfigView.isHidden = false
|
|
|
+ self.translateSepLineView.isHidden = false
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ self.reloadData()
|
|
|
+ }
|
|
|
+
|
|
|
+ func clearData() -> Void {
|
|
|
+ self.fileEmptyTextView.string = ""
|
|
|
+ self.aiResultTextView.string = ""
|
|
|
+ self.filePath = ""
|
|
|
+
|
|
|
+ self.translateFinish = false
|
|
|
+ self.translateFile = false
|
|
|
+ }
|
|
|
+
|
|
|
+ func reloadData() -> Void {
|
|
|
+ self.clearData()
|
|
|
+
|
|
|
+ self.fileEmptyTextView.isEditable = true
|
|
|
+ self.inputTextCountLabel.isHidden = true
|
|
|
+ if self.configType == .summarize {
|
|
|
+ self.fileEmptyTextView.isEditable = false
|
|
|
+ self.filePlaceholdLabel.placeholderString = NSLocalizedString("Start by uploading a document (pdf).", comment: "")
|
|
|
+ } else if self.configType == .reWriting {
|
|
|
+ self.inputTextCountLabel.isHidden = false
|
|
|
+ self.filePlaceholdLabel.placeholderString = NSLocalizedString("Start by typing, pasting (⌘ + V) text", comment: "")
|
|
|
+ } else if self.configType == .proofreading {
|
|
|
+ self.inputTextCountLabel.isHidden = false
|
|
|
+ self.filePlaceholdLabel.placeholderString = NSLocalizedString("Start by typing, pasting (⌘ + V) text", comment: "")
|
|
|
+ } else if self.configType == .translate {
|
|
|
+ self.inputTextCountLabel.isHidden = false
|
|
|
+ self.filePlaceholdLabel.placeholderString = NSLocalizedString("Start by typing, pasting (⌘ + V) text, or uploading a document (pdf).", comment: "")
|
|
|
+ }
|
|
|
+
|
|
|
+ self.updateActionViewUI()
|
|
|
+
|
|
|
+ self.updateResultViewUI()
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ //MARK: 更新左侧UI
|
|
|
+ func updateActionViewUI() -> Void{
|
|
|
+ self.fileSizeTipView.isHidden = true
|
|
|
+
|
|
|
+ if self.filePath.count > 0 || self.fileEmptyTextView.string.count > 0 {
|
|
|
+ self.enableActionView(true)
|
|
|
+ self.filePlaceholdLabel.isHidden = true
|
|
|
+ } else {
|
|
|
+ self.enableActionView(false)
|
|
|
+ self.filePlaceholdLabel.isHidden = false
|
|
|
+ }
|
|
|
+
|
|
|
+ if self.filePath.count > 0 {
|
|
|
+ self.fileEmptyTextView.isHidden = true
|
|
|
+ self.filePDFBGView.isHidden = false
|
|
|
+
|
|
|
+ let document = CPDFDocument.init(url: URL(fileURLWithPath: self.filePath))
|
|
|
+ if document?.isLocked == true || document == nil {
|
|
|
+ self.filePath = ""
|
|
|
+ self.updateActionViewUI()
|
|
|
+ return
|
|
|
+ }
|
|
|
+ DispatchQueue.main.async {
|
|
|
+ let page = document?.page(at: 0)
|
|
|
+ let image = page?.thumbnail(of: page!.size)
|
|
|
+ self.pdfCoverImageView.image = image
|
|
|
+ }
|
|
|
+
|
|
|
+ let filePathURL = URL(fileURLWithPath: self.filePath)
|
|
|
+ let parentDirectory = filePathURL.lastPathComponent
|
|
|
+ self.pdfNameLbl.stringValue = parentDirectory
|
|
|
+
|
|
|
+ self.inputTextCountLabel.isHidden = true
|
|
|
+ } else {
|
|
|
+ self.fileEmptyTextView.isHidden = false
|
|
|
+ self.filePDFBGView.isHidden = true
|
|
|
+
|
|
|
+ self.pdfCoverImageView.image = nil
|
|
|
+
|
|
|
+ self.inputTextCountLabel.isHidden = false
|
|
|
+ if self.configType == .summarize {
|
|
|
+ self.inputTextCountLabel.isHidden = true
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ self.inputTextCountLabel.stringValue = String(format: "%ld", self.fileEmptyTextView.string.count) + "/2000"
|
|
|
+ if self.fileEmptyTextView.string.count == 2000 {
|
|
|
+ self.inputTextCountLabel.textColor = KMAppearance.KMColor_Status_Err()
|
|
|
+ } else {
|
|
|
+ if KMAppearance.isDarkMode() {
|
|
|
+ self.inputTextCountLabel.textColor = KMAppearance.KMColor_Layout_W30()
|
|
|
+ } else {
|
|
|
+ self.inputTextCountLabel.textColor = KMAppearance.KMColor_Layout_B30()
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if self.aiResultTextView.string.count > 0 && (self.fileEmptyTextView.string.count > 0 || self.filePath.count > 0){
|
|
|
+ self.fileActionLabel.stringValue = NSLocalizedString("Redo (1 credit)", comment: "")
|
|
|
+ self.fileActionLabel.stringValue = NSLocalizedString("Redo (1 credit)", comment: "")
|
|
|
+ } else {
|
|
|
+ if self.configType == .summarize {
|
|
|
+ self.fileActionLabel.stringValue = NSLocalizedString("Summarize", comment: "") + NSLocalizedString("(1 credit)", comment: "")
|
|
|
+ } else if self.configType == .reWriting {
|
|
|
+ self.fileActionLabel.stringValue = NSLocalizedString("Rewrite", comment: "") + NSLocalizedString("(1 credit)", comment: "")
|
|
|
+ } else if self.configType == .proofreading {
|
|
|
+ self.fileActionLabel.stringValue = NSLocalizedString("Proofread", comment: "") + NSLocalizedString("(1 credit)", comment: "")
|
|
|
+ } else if self.configType == .translate {
|
|
|
+ self.fileActionLabel.stringValue = NSLocalizedString("Translate", comment: "") + NSLocalizedString("(1 credit)", comment: "")
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ func enableActionView(_ enable: Bool) -> Void {
|
|
|
+ if enable {
|
|
|
+ self.fileActionView.layer?.backgroundColor = KMAppearance.KMColor_Interactive_M0().cgColor
|
|
|
+ self.fileActionLabel.textColor = NSColor.white
|
|
|
+ self.fileActionBtn.isEnabled = true
|
|
|
+ } else {
|
|
|
+ self.fileActionView.layer?.backgroundColor = KMAppearance.KMColor_Interactive_M0().withAlphaComponent(0.4).cgColor
|
|
|
+ self.fileActionLabel.textColor = NSColor.white.withAlphaComponent(0.4)
|
|
|
+ self.fileActionBtn.isEnabled = false
|
|
|
+ }
|
|
|
+ self.fileActionenAble = enable
|
|
|
+
|
|
|
+ if self.filePath.count > 0 || self.fileEmptyTextView.string.count > 0 {
|
|
|
+ self.filePlaceholdLabel.isHidden = true
|
|
|
+ self.fileEmptyImage.isHidden = true
|
|
|
+ } else {
|
|
|
+ self.filePlaceholdLabel.isHidden = false
|
|
|
+ self.fileEmptyImage.isHidden = false
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ func updateResultViewUI() -> Void{
|
|
|
+ if self.aiResultTextView.string.count > 0 {
|
|
|
+ self.resultEmptyImage.isHidden = true
|
|
|
+ self.saveAsTextBtn.isEnabled = true
|
|
|
+ self.saveAsPDFBtn.isEnabled = true
|
|
|
+ } else {
|
|
|
+ self.resultEmptyImage.isHidden = false
|
|
|
+ self.saveAsTextBtn.isEnabled = false
|
|
|
+ self.saveAsPDFBtn.isEnabled = false
|
|
|
+ }
|
|
|
+
|
|
|
+ if self.configType == .translate && self.translateFinish == true {
|
|
|
+ self.saveAsTextBtn.isEnabled = true
|
|
|
+ self.saveAsPDFBtn.isEnabled = true
|
|
|
+
|
|
|
+ if self.translateFile == true {
|
|
|
+ self.translateResultView.isHidden = false
|
|
|
+ self.saveAsTextBtn.isEnabled = false
|
|
|
+ } else {
|
|
|
+ self.translateResultView.isHidden = true
|
|
|
+
|
|
|
+ }
|
|
|
+ if translateResultView.isHidden == false {
|
|
|
+ self.resultEmptyImage.isHidden = true
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ 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 chooseFileAction(_ sender: KMButton) {
|
|
|
+ let openPanel = NSOpenPanel()
|
|
|
+ openPanel.canChooseDirectories = true
|
|
|
+ openPanel.canChooseFiles = true
|
|
|
+ openPanel.allowsMultipleSelection = false;
|
|
|
+ openPanel.allowedFileTypes = ["pdf"]
|
|
|
+ openPanel.beginSheetModal(for: self.window!) { result in
|
|
|
+ if result == .OK {
|
|
|
+ let fileURL = openPanel.urls.first
|
|
|
+ let fileSize = self.getFileSize(atPath: fileURL!.path)
|
|
|
+
|
|
|
+ if fileSize/(1024*1024) > 10 {
|
|
|
+ self.fileSizeTipView.isHidden = false
|
|
|
+ DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 5) {
|
|
|
+ self.fileSizeTipView.isHidden = true
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ self.filePath = fileURL!.path
|
|
|
+ self.fileEmptyTextView.string = ""
|
|
|
+ self.updateActionViewUI()
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @IBAction func chooseLanguageAction(_ sender: NSButton) {
|
|
|
+ if sender == self.fromLanguageBtn {
|
|
|
+ let menu = self.fromLanguageView?.menu
|
|
|
+ menu?.popUp(positioning: menu?.item(at: 0), at: CGPoint(x: 0, y: 15), in: sender)
|
|
|
+ } else if sender == self.toLanguageBtn {
|
|
|
+ let menu = self.toLanguageView?.menu
|
|
|
+ menu?.popUp(positioning: menu?.item(at: 0), at: CGPoint(x: 0, y: 15), in: sender)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @objc func menuItemClick(_ item: NSMenuItem) {
|
|
|
+ if item.tag < 2000 {
|
|
|
+ self.fromLanguage = item.title
|
|
|
+ } else {
|
|
|
+ self.toLanguage = item.title
|
|
|
+ }
|
|
|
+ self.fromLanguageLabel.stringValue = self.fromLanguage
|
|
|
+ self.toLanguageLabel.stringValue = self.toLanguage
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ @IBAction func removePDFAction(_ sender: NSButton) {
|
|
|
+ self.filePath = ""
|
|
|
+ self.updateActionViewUI()
|
|
|
+ self.updateResultViewUI()
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ @IBAction func startAIFunction(_ sender: KMButton) {
|
|
|
+
|
|
|
+ let newStatus: Bool = KMCloudServer.isConnectionAvailable()
|
|
|
+ if !newStatus {
|
|
|
+ let alert = NSAlert()
|
|
|
+ alert.alertStyle = .critical
|
|
|
+ alert.messageText = NSLocalizedString("Please make sure your internet connection is available.", comment: "")
|
|
|
+ alert.runModal()
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ if self.configType == .summarize {
|
|
|
+ if FileManager.default.fileExists(atPath: self.filePath) {
|
|
|
+ self.aiResultTextView.string = ""
|
|
|
+ self.addWaingView(self.resultBGView)
|
|
|
+ self.enableActionView(false)
|
|
|
+ self.removePDFBtn.isEnabled = false
|
|
|
+ self.aiConvertFinish = false
|
|
|
+// DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1) {
|
|
|
+ KMAIRequestServerManager.defaultManager.aiAction(content: self.filePath, state: .extractSummaryFile) { wrapper in
|
|
|
+ DispatchQueue.main.async {
|
|
|
+ self.aiConvertFinish = true
|
|
|
+ self.removePDFBtn.isEnabled = true
|
|
|
+ self.removeWaitingView(self.resultBGView)
|
|
|
+ self.updateActionViewUI()
|
|
|
+
|
|
|
+ let success = wrapper.success
|
|
|
+ if success {
|
|
|
+ let resultStr = wrapper.content
|
|
|
+ self.aiResultTextView.string = resultStr
|
|
|
+ self.updateActionViewUI()
|
|
|
+ self.updateResultViewUI()
|
|
|
+ } else {
|
|
|
+ let alert = NSAlert()
|
|
|
+ alert.alertStyle = .critical
|
|
|
+ alert.messageText = wrapper.content
|
|
|
+ alert.runModal()
|
|
|
+ return
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else if self.configType == .reWriting {
|
|
|
+ self.aiResultTextView.string = ""
|
|
|
+ self.addWaingView(self.resultBGView)
|
|
|
+ self.enableActionView(false)
|
|
|
+ self.removePDFBtn.isEnabled = false
|
|
|
+ self.aiConvertFinish = false
|
|
|
+// DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1) {
|
|
|
+ KMAIRequestServerManager.defaultManager.aiAction(content: self.fileEmptyTextView.string,
|
|
|
+ state: .rewrite) { wrapper in
|
|
|
+ DispatchQueue.main.async {
|
|
|
+ self.aiConvertFinish = true
|
|
|
+ self.removePDFBtn.isEnabled = true
|
|
|
+ self.removeWaitingView(self.resultBGView)
|
|
|
+ self.updateActionViewUI()
|
|
|
+
|
|
|
+ let success = wrapper.success
|
|
|
+ if success {
|
|
|
+ let resultStr = wrapper.content
|
|
|
+ self.aiResultTextView.string = resultStr
|
|
|
+ self.updateActionViewUI()
|
|
|
+ self.updateResultViewUI()
|
|
|
+ } else {
|
|
|
+ let alert = NSAlert()
|
|
|
+ alert.alertStyle = .critical
|
|
|
+ alert.messageText = wrapper.content
|
|
|
+ alert.runModal()
|
|
|
+ return
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else if self.configType == .proofreading {
|
|
|
+ self.aiResultTextView.string = ""
|
|
|
+ self.addWaingView(self.resultBGView)
|
|
|
+ self.enableActionView(false)
|
|
|
+ self.removePDFBtn.isEnabled = false
|
|
|
+ self.aiConvertFinish = false
|
|
|
+// DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1) {
|
|
|
+ KMAIRequestServerManager.defaultManager.aiAction(content: self.fileEmptyTextView.string,
|
|
|
+ state: .correctTypos) { wrapper in
|
|
|
+ DispatchQueue.main.async {
|
|
|
+ self.aiConvertFinish = true
|
|
|
+ self.removePDFBtn.isEnabled = true
|
|
|
+ self.removeWaitingView(self.resultBGView)
|
|
|
+ self.updateActionViewUI()
|
|
|
+
|
|
|
+ let success = wrapper.success
|
|
|
+ if success {
|
|
|
+ let resultStr = wrapper.content
|
|
|
+ self.aiResultTextView.string = resultStr
|
|
|
+ self.updateActionViewUI()
|
|
|
+ self.updateResultViewUI()
|
|
|
+ } else {
|
|
|
+ let alert = NSAlert()
|
|
|
+ alert.alertStyle = .critical
|
|
|
+ alert.messageText = wrapper.content
|
|
|
+ alert.runModal()
|
|
|
+ return
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else if self.configType == .translate {
|
|
|
+ self.aiResultTextView.string = ""
|
|
|
+ self.addWaingView(self.resultBGView)
|
|
|
+ self.enableActionView(false)
|
|
|
+ self.translateFinish = false
|
|
|
+ self.translateResultView.isHidden = true
|
|
|
+// if self.filePath.count > 0 {
|
|
|
+ self.translateFile = true
|
|
|
+ self.removePDFBtn.isEnabled = false
|
|
|
+ self.aiConvertFinish = false
|
|
|
+ DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1) {
|
|
|
+// KMAIRequestServerManager.defaultManager.aiAction(content: self.filePath,
|
|
|
+// state: .fileTranslate,
|
|
|
+// from: self.fromLanguage,
|
|
|
+// to: self.toLanguage) { wrapper in
|
|
|
+ DispatchQueue.main.async {
|
|
|
+ self.aiConvertFinish = true
|
|
|
+ self.removePDFBtn.isEnabled = true
|
|
|
+ self.removeWaitingView(self.resultBGView)
|
|
|
+ self.updateActionViewUI()
|
|
|
+
|
|
|
+// let success = wrapper.success
|
|
|
+// if success {
|
|
|
+ self.translateFinish = true
|
|
|
+ self.translateResultView.isHidden = false
|
|
|
+// let resultStr = wrapper.content
|
|
|
+ let resultStr = "wrapper.content"
|
|
|
+
|
|
|
+ self.translateResultPath = resultStr
|
|
|
+ self.updateActionViewUI()
|
|
|
+ self.updateResultViewUI()
|
|
|
+// } else {
|
|
|
+// let alert = NSAlert()
|
|
|
+// alert.alertStyle = .critical
|
|
|
+// alert.messageText = wrapper.content
|
|
|
+// alert.runModal()
|
|
|
+// return
|
|
|
+// }
|
|
|
+ }
|
|
|
+ };
|
|
|
+// } else {
|
|
|
+// self.translateFile = false
|
|
|
+// self.removePDFBtn.isEnabled = false
|
|
|
+// self.aiConvertFinish = false
|
|
|
+//// DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1) {
|
|
|
+// KMAIRequestServerManager.defaultManager.aiAction(content: self.fileEmptyTextView.string,
|
|
|
+// state: .textTranslate,
|
|
|
+// from: self.fromLanguage,
|
|
|
+// to: self.toLanguage) { wrapper in
|
|
|
+// DispatchQueue.main.async {
|
|
|
+// self.aiConvertFinish = true
|
|
|
+// self.removePDFBtn.isEnabled = true
|
|
|
+// self.removeWaitingView(self.resultBGView)
|
|
|
+// self.updateActionViewUI()
|
|
|
+//
|
|
|
+// let success = wrapper.success
|
|
|
+// if success {
|
|
|
+// self.translateFinish = true
|
|
|
+// self.translateResultView.isHidden = false
|
|
|
+//
|
|
|
+// let resultStr = wrapper.content
|
|
|
+// self.aiResultTextView.string = resultStr
|
|
|
+//
|
|
|
+// self.updateActionViewUI()
|
|
|
+// self.updateResultViewUI()
|
|
|
+// } else {
|
|
|
+// let alert = NSAlert()
|
|
|
+// alert.alertStyle = .critical
|
|
|
+// alert.messageText = wrapper.content
|
|
|
+// alert.runModal()
|
|
|
+//
|
|
|
+// self.updateResultViewUI()
|
|
|
+// return
|
|
|
+// }
|
|
|
+// }
|
|
|
+// };
|
|
|
+// }
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @IBAction func languageChangeAction(_ sender: Any) {
|
|
|
+ let curLan = self.fromLanguage
|
|
|
+ self.fromLanguage = self.toLanguage
|
|
|
+ self.toLanguage = curLan
|
|
|
+
|
|
|
+
|
|
|
+ self.fromLanguageLabel.stringValue = self.fromLanguage
|
|
|
+ self.toLanguageLabel.stringValue = self.toLanguage
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ @IBAction func cancelAction(_ sender: NSButton) {
|
|
|
+ DispatchQueue.main.async {
|
|
|
+ self.removeWaitingView(self.resultBGView)
|
|
|
+ self.updateActionViewUI()
|
|
|
+ }
|
|
|
+ if self.aiConvertFinish == false {
|
|
|
+ let alert = NSAlert()
|
|
|
+ alert.alertStyle = .critical
|
|
|
+ alert.messageText = NSLocalizedString("The task is already in process, if you cancel the process, AI Credit will not be returned, please confirm if you still need to cancel?", comment: "")
|
|
|
+ alert.addButton(withTitle: NSLocalizedString("Back ", comment: ""))
|
|
|
+ alert.addButton(withTitle: NSLocalizedString("Confirm Cancel", comment: ""))
|
|
|
+ let response = alert.runModal()
|
|
|
+ if response.rawValue == 1001 {
|
|
|
+ self.confirmCancelAction()
|
|
|
+ }
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if self.aiResultTextView.string.count > 0 {
|
|
|
+ if KMFunctionGuideWindowController.availableShow(.aiInfoResultSave) == true {
|
|
|
+ KMFunctionGuideWindowController.setDidShowFor(.aiInfoResultSave)
|
|
|
+ let alert = NSAlert()
|
|
|
+ alert.alertStyle = .critical
|
|
|
+ alert.messageText = NSLocalizedString("The results are not saved. Do you want to save them in other formats?", comment: "")
|
|
|
+ alert.addButton(withTitle: NSLocalizedString("Yes", comment: ""))
|
|
|
+ alert.addButton(withTitle: NSLocalizedString("No", comment: ""))
|
|
|
+ let response = alert.runModal()
|
|
|
+ if response.rawValue == 1001 {
|
|
|
+ self.cancelAction(self.cancelBtn)
|
|
|
+ }
|
|
|
+ return
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ self.clearData()
|
|
|
+
|
|
|
+ guard let callBack = self.cancelHandle else {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ callBack(self)
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ func confirmCancelAction() -> Void {
|
|
|
+ self.clearData()
|
|
|
+
|
|
|
+ guard let callBack = self.cancelHandle else {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ callBack(self)
|
|
|
+ }
|
|
|
+
|
|
|
+ @IBAction func saveAsTextAction(_ sender: Any) {
|
|
|
+
|
|
|
+ let fileName = "Untitled"
|
|
|
+ let outputSavePanel = NSSavePanel()
|
|
|
+ outputSavePanel.allowedFileTypes = ["txt"]
|
|
|
+ outputSavePanel.nameFieldStringValue = fileName
|
|
|
+ let result = outputSavePanel.runModal()
|
|
|
+ if result == .OK {
|
|
|
+ let filePath = outputSavePanel.url?.path
|
|
|
+ do {
|
|
|
+ try self.aiResultTextView.string.write(to: outputSavePanel.url!, atomically: true, encoding: .utf8)
|
|
|
+
|
|
|
+ NSWorkspace.shared.activateFileViewerSelecting([URL(fileURLWithPath: filePath!)])
|
|
|
+ KMFunctionGuideWindowController.setDidShowFor(.aiInfoResultSave)
|
|
|
+ } catch {
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ @IBAction func saveAsPDFAction(_ sender: Any) {
|
|
|
+ let fileName = "Untitled"
|
|
|
+ let outputSavePanel = NSSavePanel()
|
|
|
+ outputSavePanel.allowedFileTypes = ["pdf"]
|
|
|
+ outputSavePanel.nameFieldStringValue = fileName
|
|
|
+ let result = outputSavePanel.runModal()
|
|
|
+ if result == .OK {
|
|
|
+ let filePath = outputSavePanel.url?.path
|
|
|
+ do {
|
|
|
+ if self.translateFile == true {
|
|
|
+ do {
|
|
|
+ if self.translateResultPath.count > 0 {
|
|
|
+ if FileManager.default.fileExists(atPath: filePath!) {
|
|
|
+ do {
|
|
|
+ try FileManager.default.removeItem(atPath: filePath!)
|
|
|
+// print("删除旧文件成功")
|
|
|
+ } catch {
|
|
|
+// print("删除旧文件失败:\(error)")
|
|
|
+ }
|
|
|
+ }
|
|
|
+ try FileManager.default.copyItem(atPath: self.translateResultPath, toPath: filePath!)
|
|
|
+ NSWorkspace.shared.activateFileViewerSelecting([URL(fileURLWithPath: filePath!)])
|
|
|
+ }
|
|
|
+ } catch {
|
|
|
+
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ let text = self.aiResultTextView.string
|
|
|
+ self.createPDF(from: text, saveTo: filePath!)
|
|
|
+
|
|
|
+ NSWorkspace.shared.activateFileViewerSelecting([URL(fileURLWithPath: filePath!)])
|
|
|
+ }
|
|
|
+ KMFunctionGuideWindowController.setDidShowFor(.aiInfoResultSave)
|
|
|
+ } catch {
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ func textDidChange(_ notification: Notification) {
|
|
|
+ if let textView = notification.object as? NSTextView, textView == self.fileEmptyTextView {
|
|
|
+ // 获取文本字段的当前字符数
|
|
|
+ let currentText = textView.string
|
|
|
+ let currentCount = currentText.count
|
|
|
+
|
|
|
+ // 如果超过最大字符数,将文本截断为最大字符数,并设置回文本字段
|
|
|
+ if currentCount > 2000 {
|
|
|
+ let endIndex = currentText.index(currentText.startIndex, offsetBy: 2000)
|
|
|
+ let truncatedText = String(currentText[..<endIndex])
|
|
|
+ textView.string = truncatedText
|
|
|
+ }
|
|
|
+ }
|
|
|
+ self.updateActionViewUI()
|
|
|
+ }
|
|
|
+
|
|
|
+ override func mouseDown(with event: NSEvent) {
|
|
|
+ super.mouseDown(with: event)
|
|
|
+
|
|
|
+ self.window?.makeFirstResponder(nil)
|
|
|
+ }
|
|
|
+
|
|
|
+ func createPDF(from text: String, saveTo path: String) {
|
|
|
+ let attributedText = NSAttributedString(string: text)
|
|
|
+ let pdfData = NSMutableData()
|
|
|
+
|
|
|
+ let pdfConsumer = CGDataConsumer(data: pdfData)!
|
|
|
+ var mediaBox = CGRect(x: 0, y: 0, width: 612, height: 792) // 设置页面尺寸,这里使用默认的美国信纸尺寸
|
|
|
+
|
|
|
+ let pdfContext = CGContext(consumer: pdfConsumer, mediaBox: &mediaBox, nil)!
|
|
|
+ pdfContext.beginPage(mediaBox: &mediaBox)
|
|
|
+ pdfContext.textMatrix = .identity
|
|
|
+ pdfContext.setShouldAntialias(true)
|
|
|
+
|
|
|
+ let frame = mediaBox.insetBy(dx: 20, dy: 20) // 设置文字边距
|
|
|
+
|
|
|
+ let framesetter = CTFramesetterCreateWithAttributedString(attributedText as CFAttributedString)
|
|
|
+ let framePath = CGPath(rect: frame, transform: nil)
|
|
|
+ let frameRef = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, attributedText.length), framePath, nil)
|
|
|
+ CTFrameDraw(frameRef, pdfContext)
|
|
|
+
|
|
|
+ pdfContext.endPage()
|
|
|
+ pdfContext.closePDF()
|
|
|
+
|
|
|
+ pdfData.write(toFile: path, atomically: true)
|
|
|
+ print("PDF 文件已保存至:\(path)")
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+}
|