// // KMAITranslationConfirmWindowController.swift // PDF Reader Pro // // Created by wanjun on 2023/5/25. // import Cocoa class KMAITranslationConfirmWindowController: NSWindowController { @IBOutlet weak var label: NSTextField! @IBOutlet weak var subLabel: NSTextField! @IBOutlet weak var cancelBox: NSBox! @IBOutlet weak var cancelLabel: NSTextField! @IBOutlet weak var cancelButton: NSButton! @IBOutlet weak var translateBox: NSBox! @IBOutlet weak var translateLabel: NSTextField! @IBOutlet weak var translateButton: NSButton! @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 tipsLabel1: NSTextField! @IBOutlet weak var tipsLabel2: NSTextField! @IBOutlet weak var prePDFView: KMCustomPDFView? var filePath: String = "" var progressController: SKProgressController? var timer: Timer? var timerCounter = 0.0 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 popover: NSPopover? var saveFileUrl: URL = URL(fileURLWithPath: "") deinit { self.prePDFView?.removeFromSuperview() self.prePDFView = nil } override func windowDidLoad() { super.windowDidLoad() self.initLocalization() self.initializeUI() let document = CPDFDocument(url: URL(fileURLWithPath: self.filePath)) self.prePDFView?.document = document! if (self.prePDFView?.documentView() != nil) { self.prePDFView?.documentView().enclosingScrollView?.hasVerticalScroller = false self.prePDFView?.documentView().enclosingScrollView?.hasHorizontalScroller = false } } func initializeUI() -> Void { self.label.textColor = NSColor.km_init(hex: "#252629") self.label.font = NSFont.SFProTextSemiboldFont(16.0) self.subLabel.textColor = NSColor.km_init(hex: "##616469") self.subLabel.font = NSFont.SFProTextRegularFont(12.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.tipsLabel1.textColor = NSColor.km_init(hex: "#94989C") self.tipsLabel1.font = NSFont.SFProTextRegularFont(12.0) self.tipsLabel2.textColor = NSColor.km_init(hex: "#94989C") self.tipsLabel2.font = NSFont.SFProTextRegularFont(12.0) self.cancelBox.fillColor = NSColor.km_init(hex: "#F5F5F5") self.cancelBox.cornerRadius = 5.0 self.cancelBox.borderWidth = 0.0 self.cancelLabel.textColor = NSColor.km_init(hex: "#4D4D4D") self.cancelLabel.font = NSFont.SFProTextRegularFont(13.0) self.translateBox.fillColor = NSColor.km_init(hex: "#4B91F7") self.translateBox.cornerRadius = 5.0 self.translateBox.borderWidth = 0.0 self.translateLabel.textColor = NSColor.km_init(hex: "#FFFFFF") self.translateLabel.font = NSFont.SFProTextRegularFont(13.0) self.prePDFView?.backgroundColor = NSColor.km_init(hex: "#F7F8FA") } func initLocalization() -> Void { self.label.stringValue = NSLocalizedString("AI Translation", comment: "") self.subLabel.stringValue = NSLocalizedString("Translation Language", comment: "") self.cancelLabel.stringValue = NSLocalizedString("Cancel", comment: "") self.translateLabel.stringValue = NSLocalizedString("Translate", comment: "") 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.tipsLabel1.stringValue = NSLocalizedString("Scanned PDF files are not supported", comment: "") self.tipsLabel2.stringValue = NSLocalizedString("Limit document size to 10M, document page number to 30, 10w characters per month.", comment: "") } override func mouseDown(with event: NSEvent) { if self.popover != nil { self.popover?.close() self.popover = nil } } // MARK: Private Methods // MARK: Action Methods @IBAction func translateAction(_ sender: NSButton) { // if !KMLightMemberManager.manager.isLogin() { // KMLoginWindowController.show(window: NSApp.mainWindow!) // // return // } // self._translateAction(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._translateAction(sender) // return // } // } // return // } if await (KMLightMemberManager.manager.canUseAdvanced() == false) { _ = KMComparativeTableViewController.show(window: self.window!, inputType: .aiTranslate) return } self._translateAction(sender) } } private func _translateAction(_ sender: NSButton) { let filePathUrl = URL(fileURLWithPath: self.filePath) let fileNameWithoutExtension = filePathUrl.deletingPathExtension().lastPathComponent let newFileName = fileNameWithoutExtension + "_aiTranslation" let outputSavePanel = NSSavePanel() outputSavePanel.title = NSLocalizedString("Translate", comment: "") outputSavePanel.allowedFileTypes = ["pdf"] outputSavePanel.nameFieldStringValue = newFileName outputSavePanel.directoryURL = filePathUrl.deletingLastPathComponent() let result = outputSavePanel.runModal() if result == .OK { self.saveFileUrl = outputSavePanel.url! DispatchQueue.main.async { self.showProgressWindow() self.progressController?.maxValue = Double(100) } timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(timerTick), userInfo: nil, repeats: true) 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.aiTranslationFileUpload(file: self.filePath, version: majorVersion as! String) { [weak self] success, result in if success { let result: NSDictionary = result!.result let fileKey = result["fileKey"] let fileName = result["fileName"] let pageCount = result["pageCount"] if fileKey != nil { self?.fileTranslateHandle(fileKey as! String) } } else { let result: String = result!.message DispatchQueue.main.async { self?.hiddenProgressWindow() let alert = NSAlert() alert.alertStyle = .critical alert.messageText = result alert.runModal() } } } } else { outputSavePanel.close() } } @IBAction func cancelAction(_ sender: NSButton) { NSApp.mainWindow!.endSheet(self.window!) self.window?.orderOut(self) } @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) } } 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 } } // MARK: Private Methods 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() { DispatchQueue.main.async { self.progressController?.doubleValue = 100.0 } self.stopTimer() if (self.progressController != nil) { self.window?.endSheet((self.progressController?.window)!) self.progressController = nil KMRequestServer.requestServer.task?.cancel() } } func fileTranslateHandle(_ fileKey: String) -> Void { let infoDictionary = Bundle .main.infoDictionary! let majorVersion = infoDictionary["CFBundleShortVersionString"] KMRequestServerManager.manager.aiTranslationFileTranslateHandle(fileKey: fileKey, from: self.fromStr, to: self.toStr, version: majorVersion as! String) { success, result in if success { let result: NSDictionary = result!.result let fileUrl: String = result["fileUrl"] as! String let downFileUrl: String = result["downFileUrl"] as! String let ossDownUrl: String = result["ossDownUrl"] as! String let fileName: String = result["fileName"] as! String let downFileName: String = result["downFileName"] as! String let from: String = result["from"] as! String let to: String = result["to"] as! String self.downloadFile(filePath: ossDownUrl, downFileName: downFileName) } else { let result: String = result!.message DispatchQueue.main.async { self.hiddenProgressWindow() let alert = NSAlert() alert.alertStyle = .critical alert.messageText = result alert.runModal() } } } } func downloadFile(filePath: String, downFileName: String) -> Void { guard let fileURL = URL(string: filePath) else { let alert = NSAlert() alert.alertStyle = .critical alert.messageText = NSLocalizedString("Invalid file link", comment: "") alert.runModal() return } // let filePathUrl = URL(fileURLWithPath: self.filePath) // let fileNameWithoutExtension = filePathUrl.deletingPathExtension().lastPathComponent // let fileExtension = filePathUrl.pathExtension // let newFileName = fileNameWithoutExtension + "_aiTranslation" + "." + fileExtension // let destinationURL = filePathUrl.deletingLastPathComponent().appendingPathComponent(newFileName) if FileManager.default.fileExists(atPath: self.saveFileUrl.path) { do { try FileManager.default.removeItem(at: self.saveFileUrl) KMPrint("删除旧文件成功") } catch { KMPrint("删除旧文件失败:\(error)") } } let sessionConfiguration = URLSessionConfiguration.default let session = URLSession(configuration: sessionConfiguration) let downloadTask = session.downloadTask(with: fileURL) { (tempLocalURL, response, error) in if let error = error { let alert = NSAlert() alert.alertStyle = .critical alert.messageText = String(format: "%@:\(error)", NSLocalizedString("Download failed", comment: "")) alert.runModal() return } guard let tempLocalURL = tempLocalURL else { let alert = NSAlert() alert.alertStyle = .critical alert.messageText = NSLocalizedString("Invalid temporary directory", comment: "") alert.runModal() return } DispatchQueue.main.async { self.hiddenProgressWindow() // NSApp.mainWindow!.endSheet(self.window!) self.window?.orderOut(self) } do { try FileManager.default.moveItem(at: tempLocalURL, to: self.saveFileUrl) NSDocumentController.shared.openDocument(withContentsOf: self.saveFileUrl, display: true) { document, documentWasAlreadyOpen, error in if error != nil { NSApp.presentError(error!) } else { } } } catch { let alert = NSAlert() alert.alertStyle = .critical alert.messageText = String(format: "%@:\(error)", NSLocalizedString("Failed to save file", comment: "")) alert.runModal() } } downloadTask.resume() } 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" } @objc func timerTick() { timerCounter += 1.0 self.progressController?.increment(by: 1.0) if timerCounter >= 95 { stopTimer() } } func stopTimer() { timer?.invalidate() timer = nil } }