Converts AppDelegate to Swift.

This commit is contained in:
zonble 2022-01-11 02:22:13 +08:00
parent 52bf2d67c5
commit a7b2edcf26
6 changed files with 224 additions and 333 deletions

View File

@ -9,7 +9,6 @@
/* Begin PBXBuildFile section */
6A0421A815FEF3F50061ED63 /* FastLM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6A0421A615FEF3F50061ED63 /* FastLM.cpp */; };
6A0D4EA715FC0D2D00ABF4B3 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6A0D4EA615FC0D2D00ABF4B3 /* Cocoa.framework */; };
6A0D4ED015FC0D6400ABF4B3 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 6A0D4EC415FC0D6400ABF4B3 /* AppDelegate.m */; };
6A0D4ED215FC0D6400ABF4B3 /* InputMethodController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 6A0D4EC715FC0D6400ABF4B3 /* InputMethodController.mm */; };
6A0D4ED315FC0D6400ABF4B3 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 6A0D4EC815FC0D6400ABF4B3 /* main.m */; };
6A0D4F0815FC0DA600ABF4B3 /* Bopomofo.tiff in Resources */ = {isa = PBXBuildFile; fileRef = 6A0D4EEF15FC0DA600ABF4B3 /* Bopomofo.tiff */; };
@ -39,6 +38,7 @@
6AFF97F2253B299E007F1C49 /* NonModalAlertWindowController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 6AFF97F0253B299E007F1C49 /* NonModalAlertWindowController.xib */; };
D427A9C125ED28CC005D43E0 /* OpenCCBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = D427A9C025ED28CC005D43E0 /* OpenCCBridge.swift */; };
D427F76A278C9E29004A2160 /* CandidateUI in Frameworks */ = {isa = PBXBuildFile; productRef = D427F769278C9E29004A2160 /* CandidateUI */; };
D427F76C278CA2B0004A2160 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D427F76B278CA1BA004A2160 /* AppDelegate.swift */; };
D47F7DCE278BFB57002F9DD7 /* PreferencesWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D47F7DCD278BFB57002F9DD7 /* PreferencesWindowController.swift */; };
D47F7DD0278C0897002F9DD7 /* NonModalAlertWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D47F7DCF278C0897002F9DD7 /* NonModalAlertWindowController.swift */; };
D47F7DD3278C1263002F9DD7 /* UserOverrideModel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D47F7DD2278C1263002F9DD7 /* UserOverrideModel.cpp */; };
@ -71,8 +71,6 @@
6A0D4EA615FC0D2D00ABF4B3 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
6A0D4EA915FC0D2D00ABF4B3 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; };
6A0D4EAB15FC0D2D00ABF4B3 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
6A0D4EC315FC0D6400ABF4B3 /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
6A0D4EC415FC0D6400ABF4B3 /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
6A0D4EC615FC0D6400ABF4B3 /* InputMethodController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InputMethodController.h; sourceTree = "<group>"; };
6A0D4EC715FC0D6400ABF4B3 /* InputMethodController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = InputMethodController.mm; sourceTree = "<group>"; };
6A0D4EC815FC0D6400ABF4B3 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
@ -160,6 +158,7 @@
D427A9BF25ED28CC005D43E0 /* McBopomofo-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "McBopomofo-Bridging-Header.h"; sourceTree = "<group>"; };
D427A9C025ED28CC005D43E0 /* OpenCCBridge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenCCBridge.swift; sourceTree = "<group>"; };
D427F768278C9D0D004A2160 /* CandidateUI */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = CandidateUI; path = Packages/CandidateUI; sourceTree = "<group>"; };
D427F76B278CA1BA004A2160 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
D47F7DCD278BFB57002F9DD7 /* PreferencesWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesWindowController.swift; sourceTree = "<group>"; };
D47F7DCF278C0897002F9DD7 /* NonModalAlertWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NonModalAlertWindowController.swift; sourceTree = "<group>"; };
D47F7DD1278C1263002F9DD7 /* UserOverrideModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UserOverrideModel.h; sourceTree = "<group>"; };
@ -227,11 +226,10 @@
6A0D4F1215FC0EB100ABF4B3 /* Engine */,
6ACA41E715FC1D9000935EF6 /* Installer */,
6A0D4F4715FC0EB900ABF4B3 /* Resources */,
6A0D4EC315FC0D6400ABF4B3 /* AppDelegate.h */,
6A0D4EC415FC0D6400ABF4B3 /* AppDelegate.m */,
6A0D4EC615FC0D6400ABF4B3 /* InputMethodController.h */,
6A0D4EC715FC0D6400ABF4B3 /* InputMethodController.mm */,
6A0D4EC815FC0D6400ABF4B3 /* main.m */,
D427F76B278CA1BA004A2160 /* AppDelegate.swift */,
D47F7DD4278C25A0002F9DD7 /* InputSourceHelper.swift */,
D47F7DCF278C0897002F9DD7 /* NonModalAlertWindowController.swift */,
D47F7DCD278BFB57002F9DD7 /* PreferencesWindowController.swift */,
@ -543,7 +541,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
6A0D4ED015FC0D6400ABF4B3 /* AppDelegate.m in Sources */,
D427F76C278CA2B0004A2160 /* AppDelegate.swift in Sources */,
6A0D4ED315FC0D6400ABF4B3 /* main.m in Sources */,
D47F7DD5278C25A0002F9DD7 /* InputSourceHelper.swift in Sources */,
D47F7DD0278C0897002F9DD7 /* NonModalAlertWindowController.swift in Sources */,

View File

@ -1,54 +0,0 @@
//
// AppDelegate.h
//
// Copyright (c) 2011 The McBopomofo Project.
//
// Contributors:
// Mengjuei Hsieh (@mjhsieh)
// Weizhong Yang (@zonble)
//
// Based on the Syrup Project and the Formosana Library
// by Lukhnos Liu (@lukhnos).
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
//
#import <Cocoa/Cocoa.h>
@class PreferencesWindowController;
@interface AppDelegate : NSObject <NSApplicationDelegate>
{
@private
NSURLConnection *_updateCheckConnection;
BOOL _currentUpdateCheckIsForced;
NSMutableData *_receivingData;
NSURL *_updateNextStepURL;
PreferencesWindowController *_preferencesWindowController;
}
- (void)checkForUpdate;
- (void)checkForUpdateForced:(BOOL)forced;
- (void)showPreferences;
@property (weak, nonatomic) IBOutlet NSWindow *window;
@end

View File

@ -1,272 +0,0 @@
//
// AppDelegate.m
//
// Copyright (c) 2011 The McBopomofo Project.
//
// Contributors:
// Mengjuei Hsieh (@mjhsieh)
// Weizhong Yang (@zonble)
//
// Based on the Syrup Project and the Formosana Library
// by Lukhnos Liu (@lukhnos).
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
//
#import "AppDelegate.h"
#import "McBopomofo-Swift.h"
extern void LTLoadLanguageModel(void);
extern void LTLoadUserLanguageModelFile(void);
static NSString *kCheckUpdateAutomatically = @"CheckUpdateAutomatically";
static NSString *kNextUpdateCheckDateKey = @"NextUpdateCheckDate";
static NSString *kUpdateInfoEndpointKey = @"UpdateInfoEndpoint";
static NSString *kUpdateInfoSiteKey = @"UpdateInfoSite";
static const NSTimeInterval kNextCheckInterval = 86400.0;
static const NSTimeInterval kTimeoutInterval = 60.0;
@interface AppDelegate () <NSURLConnectionDataDelegate, NonModalAlertWindowControllerDelegate>
@end
@implementation AppDelegate
@synthesize window = _window;
- (void)dealloc
{
_preferencesWindowController = nil;
_updateCheckConnection = nil;
}
- (void)applicationDidFinishLaunching:(NSNotification *)inNotification
{
LTLoadLanguageModel();
LTLoadUserLanguageModelFile();
if (![[NSUserDefaults standardUserDefaults] objectForKey:kCheckUpdateAutomatically]) {
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:kCheckUpdateAutomatically];
[[NSUserDefaults standardUserDefaults] synchronize];
}
[self checkForUpdate];
}
- (void)checkForUpdate
{
[self checkForUpdateForced:NO];
}
- (void)checkForUpdateForced:(BOOL)forced
{
if (_updateCheckConnection) {
// busy
return;
}
_currentUpdateCheckIsForced = forced;
// time for update?
if (!forced) {
if (![[NSUserDefaults standardUserDefaults] boolForKey:kCheckUpdateAutomatically]) {
return;
}
NSDate *now = [NSDate date];
NSDate *date = [[NSUserDefaults standardUserDefaults] objectForKey:kNextUpdateCheckDateKey];
if (![date isKindOfClass:[NSDate class]]) {
date = now;
}
if ([now compare:date] == NSOrderedAscending) {
return;
}
}
NSDate *nextUpdateDate = [NSDate dateWithTimeInterval:kNextCheckInterval sinceDate:[NSDate date]];
[[NSUserDefaults standardUserDefaults] setObject:nextUpdateDate forKey:kNextUpdateCheckDateKey];
NSDictionary *infoDict = [[NSBundle mainBundle] infoDictionary];
NSString *updateInfoURLString = [infoDict objectForKey:kUpdateInfoEndpointKey];
if (![updateInfoURLString length]) {
return;
}
NSURL *updateInfoURL = [NSURL URLWithString:updateInfoURLString];
if (!updateInfoURL) {
return;
}
NSURLRequest *request = [NSURLRequest requestWithURL:updateInfoURL cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:kTimeoutInterval];
if (!request) {
return;
}
#if DEBUG
NSLog(@"about to request update url %@ ",updateInfoURL);
#endif
if (_receivingData) {
_receivingData = nil;
}
// create a new data buffer and connection
_receivingData = [[NSMutableData alloc] init];
_updateCheckConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[_updateCheckConnection start];
}
- (void)showPreferences
{
if (!_preferencesWindowController) {
_preferencesWindowController = [[PreferencesWindowController alloc] initWithWindowNibName:@"preferences"];
}
[[_preferencesWindowController window] center];
[[_preferencesWindowController window] orderFront:self];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
BOOL isForcedCheck = _currentUpdateCheckIsForced;
_receivingData = nil;
_updateCheckConnection = nil;
_currentUpdateCheckIsForced = NO;
if (isForcedCheck) {
[[NonModalAlertWindowController sharedInstance] showWithTitle:NSLocalizedString(@"Update Check Failed", nil) content:[NSString stringWithFormat:NSLocalizedString(@"There may be no internet connection or the server failed to respond.\n\nError message: %@", nil), [error localizedDescription]] confirmButtonTitle:NSLocalizedString(@"Dismiss", nil) cancelButtonTitle:nil cancelAsDefault:NO delegate:nil];
}
}
- (void)showNoUpdateAvailableAlert
{
[[NonModalAlertWindowController sharedInstance] showWithTitle:NSLocalizedString(@"Check for Update Completed", nil) content:NSLocalizedString(@"You are already using the latest version of McBopomofo.", nil) confirmButtonTitle:NSLocalizedString(@"OK", nil) cancelButtonTitle:nil cancelAsDefault:NO delegate:nil];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
id plist = [NSPropertyListSerialization propertyListWithData:_receivingData options:NSPropertyListImmutable format:NULL error:NULL];
#if DEBUG
NSLog(@"plist %@",plist);
#endif
BOOL isForcedCheck = _currentUpdateCheckIsForced;
_receivingData = nil;
_updateCheckConnection = nil;
_currentUpdateCheckIsForced = NO;
if (!plist) {
if (isForcedCheck) {
[self showNoUpdateAvailableAlert];
}
return;
}
NSString *remoteVersion = [plist objectForKey:(id)kCFBundleVersionKey];
#if DEBUG
NSLog(@"the remoteversion is %@",remoteVersion);
#endif
if (!remoteVersion) {
if (isForcedCheck) {
[self showNoUpdateAvailableAlert];
}
return;
}
// TODO: Validate info (e.g. bundle identifier)
// TODO: Use HTML to display change log, need a new key like UpdateInfoChangeLogURL for this
NSDictionary *infoDict = [[NSBundle mainBundle] infoDictionary];
NSString *currentVersion = [infoDict objectForKey:(id)kCFBundleVersionKey];
NSComparisonResult result = [currentVersion compare:remoteVersion options:NSNumericSearch];
if (result != NSOrderedAscending) {
if (isForcedCheck) {
[self showNoUpdateAvailableAlert];
}
return;
}
NSString *siteInfoURLString = [plist objectForKey:kUpdateInfoSiteKey];
if (!siteInfoURLString) {
if (isForcedCheck) {
[self showNoUpdateAvailableAlert];
}
return;
}
NSURL *siteInfoURL = [NSURL URLWithString:siteInfoURLString];
if (!siteInfoURL) {
if (isForcedCheck) {
[self showNoUpdateAvailableAlert];
}
return;
}
_updateNextStepURL = siteInfoURL;
NSDictionary *versionDescriptions = [plist objectForKey:@"Description"];
NSString *versionDescription = @"";
if ([versionDescriptions isKindOfClass:[NSDictionary class]]) {
NSString *locale = @"en";
NSArray *supportedLocales = [NSArray arrayWithObjects:@"en", @"zh-Hant", @"zh-Hans", nil];
NSArray *preferredTags = [NSBundle preferredLocalizationsFromArray:supportedLocales];
if ([preferredTags count]) {
locale = [preferredTags objectAtIndex:0];
}
versionDescription = [versionDescriptions objectForKey:locale];
if (!versionDescription) {
versionDescription = [versionDescriptions objectForKey:@"en"];
}
if (!versionDescription) {
versionDescription = @"";
}
else {
versionDescription = [@"\n\n" stringByAppendingString:versionDescription];
}
}
NSString *content = [NSString stringWithFormat:NSLocalizedString(@"You're currently using McBopomofo %@ (%@), a new version %@ (%@) is now available. Do you want to visit McBopomofo's website to download the version?%@", nil), [infoDict objectForKey:@"CFBundleShortVersionString"], currentVersion, [plist objectForKey:@"CFBundleShortVersionString"], remoteVersion, versionDescription];
[[NonModalAlertWindowController sharedInstance] showWithTitle:NSLocalizedString(@"New Version Available", nil) content:content confirmButtonTitle:NSLocalizedString(@"Visit Website", nil) cancelButtonTitle:NSLocalizedString(@"Not Now", nil) cancelAsDefault:NO delegate:self];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[_receivingData appendData:data];
}
- (void)nonModalAlertWindowControllerDidConfirm:(NonModalAlertWindowController *)controller
{
if (_updateNextStepURL) {
[[NSWorkspace sharedWorkspace] openURL:_updateNextStepURL];
}
_updateNextStepURL = nil;
}
- (void)nonModalAlertWindowControllerDidCancel:(NonModalAlertWindowController *)controller
{
_updateNextStepURL = nil;
}
@end

216
Source/AppDelegate.swift Normal file
View File

@ -0,0 +1,216 @@
//
// AppDelegate.swift
//
// Copyright (c) 2011 The McBopomofo Project.
//
// Contributors:
// Mengjuei Hsieh (@mjhsieh)
// Weizhong Yang (@zonble)
//
// Based on the Syrup Project and the Formosana Library
// by Lukhnos Liu (@lukhnos).
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
//
import Cocoa
import InputMethodKit
private let kCheckUpdateAutomatically = "CheckUpdateAutomatically"
private let kNextUpdateCheckDateKey = "NextUpdateCheckDate"
private let kUpdateInfoEndpointKey = "UpdateInfoEndpoint"
private let kUpdateInfoSiteKey = "UpdateInfoSite"
private let kNextCheckInterval: TimeInterval = 86400.0
private let kTimeoutInterval: TimeInterval = 60.0
@objc(AppDelegate)
class AppDelegate: NSObject, NSApplicationDelegate, NonModalAlertWindowControllerDelegate {
@IBOutlet weak var window: NSWindow?
private var preferencesWindowController: PreferencesWindowController?
private var checkTask: URLSessionTask?
private var updateNextStepURL: URL?
func applicationDidFinishLaunching(_ notification: Notification) {
LTLoadLanguageModel()
LTLoadUserLanguageModelFile()
if UserDefaults.standard.object(forKey: kCheckUpdateAutomatically) == nil {
UserDefaults.standard.set(true, forKey: kCheckUpdateAutomatically)
UserDefaults.standard.synchronize()
}
checkForUpdate()
}
@objc func showPreferences() {
if preferencesWindowController == nil {
preferencesWindowController = PreferencesWindowController(windowNibName: "preferences")
}
preferencesWindowController?.window?.center()
preferencesWindowController?.window?.orderFront(self)
}
@objc(checkForUpdate)
func checkForUpdate() {
checkForUpdate(forced: false)
}
@objc(checkForUpdateForced:)
func checkForUpdate(forced: Bool) {
if checkTask != nil {
// busy
return
}
// time for update?
if !forced {
if UserDefaults.standard.bool(forKey: kCheckUpdateAutomatically) == false {
return
}
let now = Date()
let date = UserDefaults.standard.object(forKey: kNextUpdateCheckDateKey) as? Date ?? now
if now.compare(date) == .orderedAscending {
return
}
}
let nextUpdateDate = Date(timeInterval: kNextCheckInterval, since: Date())
UserDefaults.standard.set(nextUpdateDate, forKey: kNextUpdateCheckDateKey)
guard let infoDict = Bundle.main.infoDictionary,
let updateInfoURLString = infoDict[kUpdateInfoEndpointKey] as? String,
let updateInfoURL = URL(string: updateInfoURLString) else {
return
}
let request = URLRequest(url: updateInfoURL, cachePolicy: .reloadIgnoringLocalCacheData, timeoutInterval: kTimeoutInterval)
func showNoUpdateAvailableAlert() {
}
let task = URLSession.shared.dataTask(with: request) { data, response, error in
defer {
self.checkTask = nil
}
if let error = error {
if forced {
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: ""), error.localizedDescription)
let buttonTitle = NSLocalizedString("Dismiss", comment: "")
DispatchQueue.main.async {
NonModalAlertWindowController.shared.show(title:title , content: content, confirmButtonTitle: buttonTitle, cancelButtonTitle: nil, cancelAsDefault: false, delegate: nil)
}
}
return
}
do {
guard let plist = try PropertyListSerialization.propertyList(from: data ?? Data(), options: [], format: nil) as? [AnyHashable: Any],
let remoteVersion = plist[kCFBundleVersionKey] as? String,
let infoDict = Bundle.main.infoDictionary
else {
if forced {
DispatchQueue.main.async {
showNoUpdateAvailableAlert()
}
}
return
}
// TODO: Validate info (e.g. bundle identifier)
// TODO: Use HTML to display change log, need a new key like UpdateInfoChangeLogURL for this
let currentVersion = infoDict[kCFBundleVersionKey as String] as? String ?? ""
let result = currentVersion.compare(remoteVersion, options: .numeric, range: nil, locale: nil)
if result != .orderedAscending {
if forced {
DispatchQueue.main.async {
showNoUpdateAvailableAlert()
}
}
}
guard let siteInfoURLString = plist[kUpdateInfoSiteKey] as? String,
let siteInfoURL = URL(string: siteInfoURLString) else {
if forced {
DispatchQueue.main.async {
showNoUpdateAvailableAlert()
}
}
return
}
self.updateNextStepURL = siteInfoURL
var versionDescription = ""
let versionDescriptions = plist["Description"] as? [AnyHashable: Any]
if let versionDescriptions = versionDescriptions {
var locale = "en"
let supportedLocales = ["en", "zh-Hant", "zh-Hans"]
let preferredTags = Bundle.preferredLocalizations(from: supportedLocales)
if let first = preferredTags.first {
locale = first
}
versionDescription = versionDescriptions[locale] as? String ?? versionDescriptions["en"] as? String ?? ""
if !versionDescription.isEmpty {
versionDescription = "\n\n" + versionDescription
}
}
let content = String(format: NSLocalizedString("You're currently using McBopomofo %@ (%@), a new version %@ (%@) is now available. Do you want to visit McBopomofo's website to download the version?%@", comment: ""),
infoDict["CFBundleShortVersionString"] as? String ?? "",
currentVersion,
plist["CFBundleShortVersionString"] as? String ?? "",
remoteVersion,
versionDescription)
DispatchQueue.main.async {
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)
}
} catch {
if forced {
DispatchQueue.main.async {
showNoUpdateAvailableAlert()
}
}
}
}
checkTask = task
task.resume()
}
func nonModalAlertWindowControllerDidConfirm(_ controller: NonModalAlertWindowController) {
if let updateNextStepURL = updateNextStepURL {
NSWorkspace.shared.open(updateNextStepURL)
}
updateNextStepURL = nil
}
func nonModalAlertWindowControllerDidCancel(_ controller: NonModalAlertWindowController) {
updateNextStepURL = nil
}
}

View File

@ -38,7 +38,6 @@
#import <set>
#import "OVStringHelper.h"
#import "OVUTF8Helper.h"
#import "AppDelegate.h"
#import "McBopomofo-Swift.h"
@import CandidateUI;

View File

@ -2,3 +2,7 @@
// Use this file to import your target's public headers that you would like to expose to Swift.
//
extern void LTLoadLanguageModel(void);
extern void LTLoadUserLanguageModelFile(void);