diff --git a/Source/Modules/AppDelegate.swift b/Source/Modules/AppDelegate.swift index d0647f18..f5a5664a 100644 --- a/Source/Modules/AppDelegate.swift +++ b/Source/Modules/AppDelegate.swift @@ -92,7 +92,7 @@ struct VersionUpdateApi { let versionDescriptions = plist["Description"] as? [AnyHashable: Any] if let versionDescriptions = versionDescriptions { var locale = "en" - let supportedLocales = ["en", "zh-Hant", "zh-Hans"] + let supportedLocales = ["en", "zh-Hant", "zh-Hans", "ja"] let preferredTags = Bundle.preferredLocalizations(from: supportedLocales) if let first = preferredTags.first { locale = first @@ -122,14 +122,33 @@ struct VersionUpdateApi { } @objc(AppDelegate) -class AppDelegate: NSObject, NSApplicationDelegate, NonModalAlertWindowControllerDelegate { +class AppDelegate: NSObject, NSApplicationDelegate, ctlNonModalAlertWindowDelegate, FSEventStreamHelperDelegate { + func helper(_ helper: FSEventStreamHelper, didReceive events: [FSEventStreamHelper.Event]) { + DispatchQueue.main.async { + if Preferences.shouldAutoReloadUserDataFiles { + mgrLangModel.loadUserPhrases() + mgrLangModel.loadUserPhraseReplacement() + } + } + } @IBOutlet weak var window: NSWindow? private var ctlPrefWindowInstance: ctlPrefWindow? + private var ctlAboutWindowInstance: ctlAboutWindow? // New About Window private var checkTask: URLSessionTask? private var updateNextStepURL: URL? private var fsStreamHelper = FSEventStreamHelper(path: mgrLangModel.dataFolderPath, queue: DispatchQueue(label: "User Phrases")) + // 補上 dealloc + deinit { + ctlPrefWindowInstance = nil + ctlAboutWindowInstance = nil + checkTask = nil + updateNextStepURL = nil + fsStreamHelper.stop() + fsStreamHelper.delegate = nil + } + func applicationDidFinishLaunching(_ notification: Notification) { mgrLangModel.setupDataModelValueConverter() mgrLangModel.loadUserPhrases() @@ -137,19 +156,21 @@ class AppDelegate: NSObject, NSApplicationDelegate, NonModalAlertWindowControlle fsStreamHelper.delegate = self _ = fsStreamHelper.start() - if UserDefaults.standard.object(forKey: kCheckUpdateAutomatically) == nil { - UserDefaults.standard.set(true, forKey: kCheckUpdateAutomatically) - UserDefaults.standard.synchronize() + Preferences.setMissingDefaults() + + // 只要使用者沒有勾選檢查更新、沒有主動做出要檢查更新的操作,就不要檢查更新。 + if (UserDefaults.standard.object(forKey: kCheckUpdateAutomatically) != nil) == true { + checkForUpdate() } - checkForUpdate() } @objc func showPreferences() { if ctlPrefWindowInstance == nil { - ctlPrefWindowInstance = ctlPrefWindow(windowNibName: "frmPrefWIndow") + ctlPrefWindowInstance = ctlPrefWindow.init(windowNibName: "frmPrefWindow") } ctlPrefWindowInstance?.window?.center() - ctlPrefWindowInstance?.window?.orderFront(self) + ctlPrefWindowInstance?.window?.orderFrontRegardless() // 逼著屬性視窗往最前方顯示 + } } @objc(checkForUpdate) @@ -195,7 +216,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NonModalAlertWindowControlle report.remoteShortVersion, report.remoteVersion, report.versionDescription) - NonModalAlertWindowController.shared.show(title: NSLocalizedString("New Version Available", comment: ""), content: content, confirmButtonTitle: NSLocalizedString("Visit Website", comment: ""), cancelButtonTitle: NSLocalizedString("Not Now", comment: ""), cancelAsDefault: false, delegate: self) + ctlNonModalAlertWindow.shared.show(title: NSLocalizedString("New Version Available", comment: ""), content: content, confirmButtonTitle: NSLocalizedString("Visit Website", comment: ""), cancelButtonTitle: NSLocalizedString("Not Now", comment: ""), cancelAsDefault: false, delegate: self) case .noNeedToUpdate, .ignored: break } @@ -205,7 +226,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NonModalAlertWindowControlle let title = NSLocalizedString("Update Check Failed", comment: "") let content = String(format: NSLocalizedString("There may be no internet connection or the server failed to respond.\n\nError message: %@", comment: ""), message) let buttonTitle = NSLocalizedString("Dismiss", comment: "") - NonModalAlertWindowController.shared.show(title: title, content: content, confirmButtonTitle: buttonTitle, cancelButtonTitle: nil, cancelAsDefault: false, delegate: nil) + ctlNonModalAlertWindow.shared.show(title: title, content: content, confirmButtonTitle: buttonTitle, cancelButtonTitle: nil, cancelAsDefault: false, delegate: nil) default: break } @@ -213,23 +234,14 @@ class AppDelegate: NSObject, NSApplicationDelegate, NonModalAlertWindowControlle } } - func nonModalAlertWindowControllerDidConfirm(_ controller: NonModalAlertWindowController) { + func ctlNonModalAlertWindowDidConfirm(_ controller: ctlNonModalAlertWindow) { if let updateNextStepURL = updateNextStepURL { NSWorkspace.shared.open(updateNextStepURL) } updateNextStepURL = nil } - func nonModalAlertWindowControllerDidCancel(_ controller: NonModalAlertWindowController) { + func ctlNonModalAlertWindowDidCancel(_ controller: ctlNonModalAlertWindow) { updateNextStepURL = nil } } - -extension AppDelegate: FSEventStreamHelperDelegate { - func helper(_ helper: FSEventStreamHelper, didReceive events: [FSEventStreamHelper.Event]) { - DispatchQueue.main.async { - mgrLangModel.loadUserPhrases() - mgrLangModel.loadUserPhraseReplacement() - } - } -} diff --git a/Source/Modules/IMEModules/ctlInputMethod.swift b/Source/Modules/IMEModules/ctlInputMethod.swift index c3087e1d..7ab67aa3 100644 --- a/Source/Modules/IMEModules/ctlInputMethod.swift +++ b/Source/Modules/IMEModules/ctlInputMethod.swift @@ -192,7 +192,7 @@ class ctlInputMethod: IMKInputController { func checkIfUserFilesExist() -> Bool { if !mgrLangModel.checkIfUserLanguageModelFilesExist() { let content = String(format: NSLocalizedString("Please check the permission of at \"%@\".", comment: ""), mgrLangModel.dataFolderPath) - NonModalAlertWindowController.shared.show(title: NSLocalizedString("Unable to create the user phrase file.", comment: ""), content: content, confirmButtonTitle: NSLocalizedString("OK", comment: ""), cancelButtonTitle: nil, cancelAsDefault: false, delegate: nil) + ctlNonModalAlertWindow.shared.show(title: NSLocalizedString("Unable to create the user phrase file.", comment: ""), content: content, confirmButtonTitle: NSLocalizedString("OK", comment: ""), cancelButtonTitle: nil, cancelAsDefault: false, delegate: nil) return false } return true diff --git a/Source/Modules/LangModelRelated/mgrLangModel.mm b/Source/Modules/LangModelRelated/mgrLangModel.mm index 040321c7..a8345d7d 100644 --- a/Source/Modules/LangModelRelated/mgrLangModel.mm +++ b/Source/Modules/LangModelRelated/mgrLangModel.mm @@ -7,7 +7,7 @@ using namespace std; using namespace vChewing; static const int kUserOverrideModelCapacity = 500; -static const double kObservedOverrideHalflife = 5400.0; // 1.5 hr. +static const double kObservedOverrideHalflife = 5400.0; static vChewingLM gLangModelCHT; static vChewingLM gLangModelCHS; diff --git a/Source/WindowControllers/ctlNonModalAlertWindow.swift b/Source/WindowControllers/ctlNonModalAlertWindow.swift index e3930d58..409c5541 100644 --- a/Source/WindowControllers/ctlNonModalAlertWindow.swift +++ b/Source/WindowControllers/ctlNonModalAlertWindow.swift @@ -1,24 +1,24 @@ import Cocoa -@objc protocol NonModalAlertWindowControllerDelegate: AnyObject { - func nonModalAlertWindowControllerDidConfirm(_ controller: NonModalAlertWindowController) - func nonModalAlertWindowControllerDidCancel(_ controller: NonModalAlertWindowController) +@objc protocol ctlNonModalAlertWindowDelegate: AnyObject { + func ctlNonModalAlertWindowDidConfirm(_ controller: ctlNonModalAlertWindow) + func ctlNonModalAlertWindowDidCancel(_ controller: ctlNonModalAlertWindow) } -class NonModalAlertWindowController: NSWindowController { +class ctlNonModalAlertWindow: NSWindowController { @objc(sharedInstance) - static let shared = NonModalAlertWindowController(windowNibName: "NonModalAlertWindowController") + static let shared = ctlNonModalAlertWindow(windowNibName: "ctlNonModalAlertWindow") @IBOutlet weak var titleTextField: NSTextField! @IBOutlet weak var contentTextField: NSTextField! @IBOutlet weak var confirmButton: NSButton! @IBOutlet weak var cancelButton: NSButton! - weak var delegate: NonModalAlertWindowControllerDelegate? + weak var delegate: ctlNonModalAlertWindowDelegate? - @objc func show(title: String, content: String, confirmButtonTitle: String, cancelButtonTitle: String?, cancelAsDefault: Bool, delegate: NonModalAlertWindowControllerDelegate?) { + @objc func show(title: String, content: String, confirmButtonTitle: String, cancelButtonTitle: String?, cancelAsDefault: Bool, delegate: ctlNonModalAlertWindowDelegate?) { if window?.isVisible == true { - self.delegate?.nonModalAlertWindowControllerDidCancel(self) + self.delegate?.ctlNonModalAlertWindowDidCancel(self) } self.delegate = delegate @@ -83,7 +83,7 @@ class NonModalAlertWindowController: NSWindowController { } @IBAction func confirmButtonAction(_ sender: Any) { - delegate?.nonModalAlertWindowControllerDidConfirm(self) + delegate?.ctlNonModalAlertWindowDidConfirm(self) window?.orderOut(self) } @@ -92,7 +92,7 @@ class NonModalAlertWindowController: NSWindowController { } func cancel(_ sender: Any) { - delegate?.nonModalAlertWindowControllerDidCancel(self) + delegate?.ctlNonModalAlertWindowDidCancel(self) delegate = nil window?.orderOut(self) } diff --git a/vChewing.xcodeproj/project.pbxproj b/vChewing.xcodeproj/project.pbxproj index f9bdd1f8..96222fea 100644 --- a/vChewing.xcodeproj/project.pbxproj +++ b/vChewing.xcodeproj/project.pbxproj @@ -33,7 +33,7 @@ 5BBBB75F27AED54C0023B93A /* Beep.m4a in Resources */ = {isa = PBXBuildFile; fileRef = 5BBBB75D27AED54C0023B93A /* Beep.m4a */; }; 5BBBB76027AED54C0023B93A /* Fart.m4a in Resources */ = {isa = PBXBuildFile; fileRef = 5BBBB75E27AED54C0023B93A /* Fart.m4a */; }; 5BBBB76B27AED5DB0023B93A /* frmNonModalAlertWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5BBBB76527AED5DB0023B93A /* frmNonModalAlertWindow.xib */; }; - 5BBBB76C27AED5DB0023B93A /* frmPreferences.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5BBBB76727AED5DB0023B93A /* frmPreferences.xib */; }; + 5BBBB76C27AED5DB0023B93A /* frmPrefWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5BBBB76727AED5DB0023B93A /* frmPrefWindow.xib */; }; 5BBBB76D27AED5DB0023B93A /* frmAboutWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5BBBB76927AED5DB0023B93A /* frmAboutWindow.xib */; }; 5BBBB77327AED70B0023B93A /* MenuIcon-TCVIM@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 5BBBB76F27AED70B0023B93A /* MenuIcon-TCVIM@2x.png */; }; 5BBBB77427AED70B0023B93A /* MenuIcon-SCVIM@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 5BBBB77027AED70B0023B93A /* MenuIcon-SCVIM@2x.png */; }; @@ -128,7 +128,7 @@ 5BBBB75D27AED54C0023B93A /* Beep.m4a */ = {isa = PBXFileReference; lastKnownFileType = file; path = Beep.m4a; sourceTree = ""; }; 5BBBB75E27AED54C0023B93A /* Fart.m4a */ = {isa = PBXFileReference; lastKnownFileType = file; path = Fart.m4a; sourceTree = ""; }; 5BBBB76627AED5DB0023B93A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/frmNonModalAlertWindow.xib; sourceTree = ""; }; - 5BBBB76827AED5DB0023B93A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/frmPreferences.xib; sourceTree = ""; }; + 5BBBB76827AED5DB0023B93A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/frmPrefWindow.xib; sourceTree = ""; }; 5BBBB76A27AED5DB0023B93A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/frmAboutWindow.xib; sourceTree = ""; }; 5BBBB76F27AED70B0023B93A /* MenuIcon-TCVIM@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "MenuIcon-TCVIM@2x.png"; sourceTree = ""; }; 5BBBB77027AED70B0023B93A /* MenuIcon-SCVIM@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "MenuIcon-SCVIM@2x.png"; sourceTree = ""; }; @@ -406,7 +406,7 @@ children = ( 5BBBB76927AED5DB0023B93A /* frmAboutWindow.xib */, 5BBBB76527AED5DB0023B93A /* frmNonModalAlertWindow.xib */, - 5BBBB76727AED5DB0023B93A /* frmPreferences.xib */, + 5BBBB76727AED5DB0023B93A /* frmPrefWindow.xib */, 6A187E2816004C5900466B2E /* MainMenu.xib */, ); path = WindowNIBs; @@ -694,7 +694,7 @@ files = ( 5BBBB77427AED70B0023B93A /* MenuIcon-SCVIM@2x.png in Resources */, D4E33D8A27A838CF006DB1CF /* Localizable.strings in Resources */, - 5BBBB76C27AED5DB0023B93A /* frmPreferences.xib in Resources */, + 5BBBB76C27AED5DB0023B93A /* frmPrefWindow.xib in Resources */, 5BBBB76027AED54C0023B93A /* Fart.m4a in Resources */, 6A2E40F6253A69DA00D1AE1D /* Images.xcassets in Resources */, D4E33D8F27A838F0006DB1CF /* InfoPlist.strings in Resources */, @@ -826,12 +826,12 @@ name = frmNonModalAlertWindow.xib; sourceTree = ""; }; - 5BBBB76727AED5DB0023B93A /* frmPreferences.xib */ = { + 5BBBB76727AED5DB0023B93A /* frmPrefWindow.xib */ = { isa = PBXVariantGroup; children = ( 5BBBB76827AED5DB0023B93A /* Base */, ); - name = frmPreferences.xib; + name = frmPrefWindow.xib; sourceTree = ""; }; 5BBBB76927AED5DB0023B93A /* frmAboutWindow.xib */ = {