// // KMAITranslationWindowController.swift // PDF Reader Pro // // Created by wanjun on 2023/5/24. // import Cocoa @objc enum KMAITranslationState: Int { case None = 0 case CanTranslate case CanAIRewriting case CanAIErrorCorrection case CanCopy case Copyed case Exceed case Error } class KMAITranslationWindowController: NSWindowController { @IBOutlet weak var closeButton: NSButton! @IBOutlet weak var aiTranslationTitleLabel: NSTextField! @IBOutlet weak var tipsButton: NSButton! @IBOutlet weak var translationLanguage: NSTextField! @IBOutlet weak var fromBox: NSBox! @IBOutlet weak var fromLabel: NSTextField! @IBOutlet weak var toBox: NSBox! @IBOutlet weak var toLabel: NSTextField! @IBOutlet weak var languageImageView: NSImageView! @IBOutlet weak var fromContentBox: NSBox! @IBOutlet weak var fromContentTextField: NSTextField! @IBOutlet weak var fromContentLabel: NSTextField! @IBOutlet weak var toContentBox: NSBox! @IBOutlet weak var toContentTextView: NSTextView! @IBOutlet weak var translateBox: KMBox! @IBOutlet weak var translateLabel: NSTextField! @IBOutlet weak var translateButton: NSButton! @IBOutlet weak var copyBox: KMBox! @IBOutlet weak var copyLabel: NSTextField! @IBOutlet weak var copyButton: NSButton! @IBOutlet weak var errorView: NSView! @IBOutlet weak var errorImageView: NSImageView! @IBOutlet weak var errorLabel: NSTextField! var fromStr: String = "auto" var toStr: String = "en" var fromLanguages: [String] = ["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"] var toLanguages: [String] = ["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 content: String = "" var popover: NSPopover? var popoverTips: NSPopover? var _state: KMAITranslationState = .None var progressController: SKProgressController? override func windowDidLoad() { super.windowDidLoad() self.window?.backgroundColor = .white self.initLocalization() self.initializeUI() } // MARK: initialize func initializeUI() -> Void { self.aiTranslationTitleLabel.textColor = NSColor.km_init(hex: "#252629") self.aiTranslationTitleLabel.font = NSFont.SFProTextSemiboldFont(16.0) self.translationLanguage.textColor = NSColor.km_init(hex: "#252629") self.translationLanguage.font = NSFont.SFProTextRegularFont(14.0) self.fromBox.fillColor = NSColor.km_init(hex: "#FFFFFF") self.fromBox.borderColor = NSColor.km_init(hex: "#DFE1E5") self.fromLabel.textColor = NSColor.km_init(hex: "#252629") self.fromLabel.font = NSFont.SFProTextRegularFont(14.0) self.toBox.fillColor = NSColor.km_init(hex: "#FFFFFF") self.toBox.borderColor = NSColor.km_init(hex: "#DFE1E5") self.toLabel.textColor = NSColor.km_init(hex: "#252629") self.toLabel.font = NSFont.SFProTextRegularFont(14.0) self.languageImageView.image = NSImage(named: "ic_transtate") self.fromContentBox.borderColor = NSColor.km_init(hex: "#1770F4") self.fromContentBox.fillColor = NSColor.km_init(hex: "#FFFFFF") self.fromContentTextField.textColor = NSColor.km_init(hex: "#252629") self.fromContentTextField.font = NSFont.SFProTextRegularFont(12.0) self.fromContentLabel.textColor = NSColor.km_init(hex: "#94989C") self.fromContentLabel.font = NSFont.SFProTextRegularFont(12.0) self.toContentBox.borderColor = NSColor.km_init(hex: "#DFE1E5") self.toContentBox.fillColor = NSColor.km_init(hex: "#FFFFFF") self.toContentTextView.textColor = .black self.toContentTextView.font = NSFont.SFProTextRegularFont(12.0) self.translateBox.fillColor = NSColor.km_init(hex: "#BDDFFD") self.translateBox.cornerRadius = 4.0 self.translateLabel.textColor = NSColor.km_init(hex: "#FFFFFF") self.translateLabel.font = NSFont.SFProTextRegularFont(12.0) self.copyBox.fillColor = NSColor.km_init(hex: "#EDEEF0") self.copyBox.borderColor = NSColor.km_init(hex: "#DFE1E5") self.copyBox.borderWidth = 1.0 self.copyBox.cornerRadius = 4.0 self.copyLabel.textColor = NSColor.km_init(hex: "#F7F8FA") self.copyLabel.font = NSFont.SFProTextRegularFont(12.0) self.errorView.isHidden = true self.errorImageView.image = NSImage(named: "icon_error") self.errorLabel.textColor = NSColor.km_init(hex: "#F3465B") self.errorLabel.font = NSFont.SFProTextRegularFont(12.0) if self.content.count > 0 { self.fromContentTextField.stringValue = self.content if self.content.count > 150 { self.state = .Exceed } else { self.state = .CanTranslate } } } func initLocalization() -> Void { self.aiTranslationTitleLabel.stringValue = "AI Translation" self.translationLanguage.stringValue = "Translation Language:" self.translateLabel.stringValue = "Translate" self.copyLabel.stringValue = "Copy" let languageArr = UserDefaults.standard.array(forKey: "KMAITranslationLanguageArrayKey") as? [String] ?? [] if (languageArr.count > 0) { self.fromLabel.stringValue = languageArr[0] self.toLabel.stringValue = languageArr[1] } else { self.fromLabel.stringValue = NSLocalizedString("Automatic", comment: "") self.toLabel.stringValue = NSLocalizedString("English", comment: "") let languages = [NSLocalizedString("Automatic", comment: ""), NSLocalizedString("English", comment: "")] UserDefaults.standard.set(languages, forKey: "KMAITranslationLanguageArrayKey") UserDefaults.standard.synchronize() } self.fromContentLabel.stringValue = NSLocalizedString("0/150", comment: "") } override func mouseDown(with event: NSEvent) { if self.popover != nil { self.popover?.close() self.popover = nil } if self.popoverTips != nil { self.popoverTips?.close() self.popoverTips = nil } } // MARK: Get、Set var state: KMAITranslationState { get { return _state } set { _state = newValue self.refreshAIUI() } } // MARK: Private Methods func languageAbbreviation(_ language: String) -> String { if language == "Automatic" { return "auto" } else if language == "English" { return "en" } else if language == "Simplified Chinese" { return "zh" } else if language == "Traditional Chinese" { return "cht" } else if language == "Japanese" { return "jp" } else if language == "Korean" { return "kor" } else if language == "French" { return "fra" } else if language == "Spanish" { return "spa" } else if language == "Italian" { return "it" } else if language == "German" { return "de" } else if language == "Portuguese" { return "pt" } else if language == "Russian" { return "ru" } else if language == "Vietnamese" { return "vie" } else if language == "Thai" { return "th" } else if language == "Arabic" { return "ara" } else if language == "Greek" { return "el" } else if language == "Bulgarian" { return "bul" } else if language == "Finnish" { return "fin" } else if language == "Slovene" { return "slo" } else if language == "Dutch" { return "nl" } else if language == "Czech" { return "cs" } else if language == "Swedish" { return "swe" } else if language == "Polish" { return "pl" } else if language == "Danish" { return "dan" } else if language == "Romanian" { return "rom" } else if language == "Hungarian" { return "hu" } return "auto" } func refreshAIUI() -> Void { self.fromContentLabel.stringValue = String(format: "%d/150", self.fromContentTextField.stringValue.count) self.copyLabel.stringValue = NSLocalizedString("Copy", comment: "") if self.state == .CanTranslate { self.fromContentLabel.textColor = NSColor.km_init(hex: "#94989C") self.translateBox.fillColor = NSColor.km_init(hex: "#1770F4") self.translateBox.borderWidth = 0.0 self.translateLabel.textColor = NSColor.km_init(hex: "#FFFFFF") self.copyBox.fillColor = NSColor.km_init(hex: "#EDEEF0") self.copyBox.borderWidth = 1.0 self.copyBox.borderColor = NSColor.km_init(hex: "#DFE1E5") self.copyLabel.textColor = NSColor.km_init(hex: "#B1B3B8") self.errorView.isHidden = true } else if self.state == .CanCopy { self.fromContentLabel.textColor = NSColor.km_init(hex: "#94989C") self.translateBox.fillColor = NSColor.km_init(hex: "#1770F4") self.translateBox.borderWidth = 0.0 self.translateLabel.textColor = NSColor.km_init(hex: "#FFFFFF") self.copyBox.fillColor = NSColor.km_init(hex: "#FFFFFF") self.copyBox.borderWidth = 1.0 self.copyBox.borderColor = NSColor.km_init(hex: "#DFE1E5") self.copyLabel.textColor = NSColor.km_init(hex: "#252629") self.errorView.isHidden = true } else if self.state == .Copyed { self.fromContentLabel.textColor = NSColor.km_init(hex: "#94989C") self.translateBox.fillColor = NSColor.km_init(hex: "#1770F4") self.translateBox.borderWidth = 0.0 self.translateLabel.textColor = NSColor.km_init(hex: "#FFFFFF") self.copyBox.fillColor = NSColor.km_init(hex: "#36383B") self.copyBox.borderWidth = 0.0 self.copyLabel.textColor = NSColor.km_init(hex: "#FFFFFF") self.copyLabel.stringValue = NSLocalizedString("Copied", comment: "") self.errorView.isHidden = true } else if self.state == .Exceed { // 是否超过 self.fromContentLabel.textColor = NSColor.km_init(hex: "#F3465B") self.translateBox.fillColor = NSColor.km_init(hex: "#1770F4") self.translateBox.borderWidth = 0.0 self.translateLabel.textColor = NSColor.km_init(hex: "#FFFFFF") self.copyBox.fillColor = NSColor.km_init(hex: "#EDEEF0") self.copyBox.borderWidth = 1.0 self.copyBox.borderColor = NSColor.km_init(hex: "#DFE1E5") self.copyLabel.textColor = NSColor.km_init(hex: "#B1B3B8") self.errorView.isHidden = true } else if self.state == .Error { if self.fromContentTextField.stringValue.count > 150 { self.fromContentLabel.textColor = NSColor.km_init(hex: "#F3465B") } else { self.fromContentLabel.textColor = NSColor.km_init(hex: "#94989C") } self.translateBox.fillColor = NSColor.km_init(hex: "#1770F4") self.translateBox.borderWidth = 0.0 self.translateLabel.textColor = NSColor.km_init(hex: "#FFFFFF") self.copyBox.fillColor = NSColor.km_init(hex: "#EDEEF0") self.copyBox.borderWidth = 1.0 self.copyBox.borderColor = NSColor.km_init(hex: "#DFE1E5") self.copyLabel.textColor = NSColor.km_init(hex: "#B1B3B8") self.errorView.isHidden = false } else { self.fromContentLabel.textColor = NSColor.km_init(hex: "#94989C") self.translateBox.fillColor = NSColor.km_init(hex: "#BDDFFD") self.translateBox.borderWidth = 0.0 self.translateLabel.textColor = NSColor.km_init(hex: "#F7F8FA") self.copyBox.fillColor = NSColor.km_init(hex: "#EDEEF0") self.copyBox.borderWidth = 1.0 self.copyBox.borderColor = NSColor.km_init(hex: "#DFE1E5") self.copyLabel.textColor = NSColor.km_init(hex: "#B1B3B8") self.errorView.isHidden = true } } func showProgressWindow() { let progress = SKProgressController() progress.window?.backgroundColor = NSColor.km_init(hex: "#36383B") progress.window?.contentView?.wantsLayer = true progress.window?.contentView?.layer?.backgroundColor = NSColor.km_init(hex: "#36383B").cgColor progress.progressField.textColor = NSColor.white progress.message = NSLocalizedString("Translating...", comment: "") progress.closeBlock = { [weak self] in self?.hiddenProgressWindow() } self.progressController = progress self.window?.beginSheet(progress.window!) } func hiddenProgressWindow() { if (self.progressController != nil) { self.window?.endSheet((self.progressController?.window)!) self.progressController = nil KMRequestServer.requestServer.task?.cancel() } } // MARK: Action @IBAction func fromLanguageAction(_ sender: NSButton) { self.languageAction(true) } @IBAction func toLanguageAction(_ sender: NSButton) { self.languageAction(false) } func languageAction(_ isFromLanguage: Bool) -> Void { if (self.popover != nil && self.popover!.isShown) { self.popover?.close() self.popover = nil return } var languages = self.fromLanguages if !isFromLanguage { languages = self.toLanguages } let vc: KMAILanguagePopVC = KMAILanguagePopVC().initWithPopViewDataArr(languages) let createFilePopover: NSPopover = NSPopover.init() self.popover = createFilePopover createFilePopover.contentViewController = vc createFilePopover.animates = true createFilePopover.behavior = .semitransient createFilePopover.setValue(true, forKey: "shouldHideAnchor") if isFromLanguage { vc.selectString = self.fromLabel.stringValue } else { vc.selectString = self.toLabel.stringValue } vc.downCallback = { [unowned self] (language: String) -> Void in createFilePopover.close() if isFromLanguage { self.fromLabel.stringValue = language self.fromStr = self.languageAbbreviation(language) } else { self.toLabel.stringValue = language self.toStr = self.languageAbbreviation(language) } self.toContentTextView.string = "" if self.fromContentTextField.stringValue.count > 0 { if self.fromContentTextField.stringValue.count > 150 { self.state = .Exceed } else { self.state = .CanTranslate } } else { self.state = .None } } if isFromLanguage { createFilePopover.show(relativeTo: CGRect(x: fromBox.bounds.origin.x, y: 10, width: fromBox.bounds.size.width, height: fromBox.bounds.size.height), of: fromBox, preferredEdge: .maxY) vc.customBoxWidthLayoutConstraint.constant = fromBox.frame.width } else { createFilePopover.show(relativeTo: CGRect(x: toBox.bounds.origin.x, y: 10, width: toBox.bounds.size.width, height: toBox.bounds.size.height), of: toBox, preferredEdge: .maxY) vc.customBoxWidthLayoutConstraint.constant = toBox.frame.width } } @IBAction func aiTranslationAction(_ sender: NSButton) { if self.state == .CanTranslate || self.state == .CanCopy || self.state == .Copyed || self.state == .Exceed || self.state == .Error { if !KMLightMemberManager.manager.isLogin() { KMLoginWindowController.show(window: NSApp.mainWindow!) return } self._aiTranslationAction(sender) // Task { @MainActor in // if await (KMLightMemberManager.manager.canPayFunction() == false) { // let _ = KMSubscribeWaterMarkWindowController.show(window: self.window!, type: .aiTranslate) { isSubscribeSuccess, _, isClose in // if (isClose) { // return // } // if (isSubscribeSuccess) { // self._aiTranslationAction(sender) // return // } // } // return // } // self._aiTranslationAction(sender) // } } } private func _aiTranslationAction(_ sender: NSButton) { DispatchQueue.main.async { self.showProgressWindow() } self.errorView.isHidden = true self.toContentTextView.string = "" let languages = [self.fromLabel.stringValue, self.toLabel.stringValue] UserDefaults.standard.set(languages, forKey: "KMAITranslationLanguageArrayKey") UserDefaults.standard.synchronize() self.fromStr = self.languageAbbreviation(self.fromLabel.stringValue) self.toStr = self.languageAbbreviation(self.toLabel.stringValue) let infoDictionary = Bundle .main.infoDictionary! let majorVersion = infoDictionary["CFBundleShortVersionString"] KMRequestServerManager.manager.aiTranslationTextTrans(q: self.fromContentTextField.stringValue, from: self.fromStr, to: self.toStr, version: majorVersion as! String) { [unowned self] success, result in DispatchQueue.main.async { self.hiddenProgressWindow() } if success { let result: NSDictionary = result!.result // let form: String = result["form"] as! String // let to: String = result["to"] as! String // let src: String = result["src"] as! String let dst: String = result["dst"] as! String DispatchQueue.main.async { self.state = .CanCopy self.toContentTextView.string = dst } } else { let result: String = result!.message DispatchQueue.main.async { self.errorLabel.stringValue = result self.state = .Error self.toContentTextView.string = "" } } } } @IBAction func copyAction(_ sender: NSButton) { if self.state == .CanCopy || self.state == .Copyed { if !KMLightMemberManager.manager.isLogin() { KMLoginWindowController.show(window: NSApp.mainWindow!) return } self._copyAction(sender) // Task { @MainActor in // if await (KMLightMemberManager.manager.canPayFunction() == false) { // let _ = KMSubscribeWaterMarkWindowController.show(window: self.window!, type: .aiTranslate) { isSubscribeSuccess, _, isClose in // if (isClose) { // return // } // if (isSubscribeSuccess) { // self._copyAction(sender) // return // } // } // return // } // // self._copyAction(sender) // } } } private func _copyAction(_ sender: NSButton) { let pasteboard = NSPasteboard.general pasteboard.clearContents() pasteboard.setString(self.toContentTextView.string, forType: .string) self.state = .Copyed } @IBAction func closeButtonAction(_ sender: NSButton) { if self.popover != nil { self.popover?.close() self.popover = nil } if self.popoverTips != nil { self.popoverTips?.close() self.popoverTips = nil } self.window?.close() } @IBAction func tipsButtonAction(_ sender: NSButton) { if (self.popoverTips != nil) { self.popoverTips?.close() self.popoverTips = nil return } let pop: NSPopover = NSPopover.init() self.popoverTips = pop let controller = KMSignatureHelpViewController.init() pop.contentViewController = controller controller.tipString = NSLocalizedString("Limit document size to 10M, document page number to 30, 10w characters per month.", comment: "") pop.setValue(true, forKey: "shouldHideAnchor") pop.show(relativeTo: NSRect(x: 0, y: -8, width: NSWidth(sender.bounds), height: NSHeight(sender.bounds)), of: sender, preferredEdge: .maxX) } } extension KMAITranslationWindowController: NSTextFieldDelegate { func controlTextDidEndEditing(_ obj: Notification) { _ = obj.object as! NSTextField } func controlTextDidChange(_ obj: Notification) { let object = obj.object as! NSTextField if object.stringValue.count > 0 { self.state = .CanTranslate } else { self.state = .None } if object.stringValue.count > 150 { self.state = .Exceed } self.toContentTextView.string = "" } }