Repo // Introducing UpdateSputnik.
This commit is contained in:
parent
1cbcb446ee
commit
59b0cc1c45
|
@ -0,0 +1,159 @@
|
||||||
|
// (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
||||||
|
// ====================
|
||||||
|
// This code is released under the MIT license (SPDX-License-Identifier: MIT)
|
||||||
|
// ... with NTL restriction stating that:
|
||||||
|
// No trademark license is granted to use the trade names, trademarks, service
|
||||||
|
// marks, or product names of Contributor, except as required to fulfill notice
|
||||||
|
// requirements defined in MIT License.
|
||||||
|
|
||||||
|
import Cocoa
|
||||||
|
|
||||||
|
class UpdateSputnik: NSObject, URLSessionDataDelegate {
|
||||||
|
static let kUpdateInfoPageURLKey: String = "UpdateInfoSite"
|
||||||
|
static let kUpdateCheckDateKeyPrevious: String = "PreviousUpdateCheckDate"
|
||||||
|
static let kUpdateCheckDateKeyNext: String = "NextUpdateCheckDate"
|
||||||
|
static let kUpdateCheckInterval: TimeInterval = 114_514
|
||||||
|
static var shared = UpdateSputnik()
|
||||||
|
|
||||||
|
func checkForUpdate(forced: Bool = false) {
|
||||||
|
guard !busy else { return }
|
||||||
|
|
||||||
|
if !forced {
|
||||||
|
if !mgrPrefs.checkUpdateAutomatically { return }
|
||||||
|
if let nextCheckDate = nextUpdateCheckDate, Date().compare(nextCheckDate) == .orderedAscending {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
isCurrentCheckForced = forced // 留著用來生成錯誤報告
|
||||||
|
let request = URLRequest(
|
||||||
|
url: kUpdateInfoSourceURL, cachePolicy: .reloadIgnoringLocalCacheData, timeoutInterval: 5
|
||||||
|
)
|
||||||
|
|
||||||
|
let task = URLSession.shared.dataTask(with: request) { data, _, error in
|
||||||
|
if let error = error {
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
self.showError(message: error.localizedDescription)
|
||||||
|
self.currentTask = nil
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.data = data
|
||||||
|
}
|
||||||
|
task.resume()
|
||||||
|
currentTask = task
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Private properties
|
||||||
|
|
||||||
|
private var isCurrentCheckForced = false
|
||||||
|
var sessionConfiguration = URLSessionConfiguration.background(withIdentifier: Bundle.main.bundleIdentifier!)
|
||||||
|
|
||||||
|
private var busy: Bool { currentTask != nil }
|
||||||
|
private var currentTask: URLSessionDataTask?
|
||||||
|
private var data: Data? {
|
||||||
|
didSet {
|
||||||
|
if let data = data {
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
self.dataDidSet(data: data)
|
||||||
|
self.currentTask = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var nextUpdateCheckDate: Date? {
|
||||||
|
get {
|
||||||
|
UserDefaults.standard.object(forKey: UpdateSputnik.kUpdateCheckDateKeyNext) as? Date
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
UserDefaults.standard.set(newValue, forKey: UpdateSputnik.kUpdateCheckDateKeyNext)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Private functions.
|
||||||
|
|
||||||
|
internal func dataDidSet(data: Data) {
|
||||||
|
var plist: [AnyHashable: Any]?
|
||||||
|
plist = try? PropertyListSerialization.propertyList(from: data, options: [], format: nil) as? [AnyHashable: Any]
|
||||||
|
nextUpdateCheckDate = .init().addingTimeInterval(UpdateSputnik.kUpdateCheckInterval)
|
||||||
|
cleanUp()
|
||||||
|
|
||||||
|
guard let plist = plist else {
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
self.showError(message: "Plist downloaded is nil.")
|
||||||
|
self.currentTask = nil
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
NSLog("update check plist: \(plist)")
|
||||||
|
|
||||||
|
guard let intRemoteVersion = Int(plist[kCFBundleVersionKey] as? String ?? ""),
|
||||||
|
let strRemoteVersionShortened = plist["CFBundleShortVersionString"] as? String
|
||||||
|
else {
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
self.showError(message: "Plist downloaded cannot be parsed correctly.")
|
||||||
|
self.currentTask = nil
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
guard let dicMainBundle = Bundle.main.infoDictionary,
|
||||||
|
let intCurrentVersion = Int(dicMainBundle[kCFBundleVersionKey as String] as? String ?? ""),
|
||||||
|
let strCurrentVersionShortened = dicMainBundle["CFBundleShortVersionString"] as? String
|
||||||
|
else { return } // Shouldn't happen.
|
||||||
|
if intRemoteVersion <= intCurrentVersion, isCurrentCheckForced {
|
||||||
|
let alert = NSAlert()
|
||||||
|
alert.messageText = NSLocalizedString("Update Check Completed", comment: "")
|
||||||
|
alert.informativeText = NSLocalizedString("You are already using the latest version.", comment: "")
|
||||||
|
alert.addButton(withTitle: NSLocalizedString("OK", comment: ""))
|
||||||
|
alert.runModal()
|
||||||
|
NSApp.setActivationPolicy(.accessory)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let content = String(
|
||||||
|
format: NSLocalizedString(
|
||||||
|
"You're currently using vChewing %@ (%@), a new version %@ (%@) is now available. Do you want to visit vChewing's website to download the version?",
|
||||||
|
comment: ""
|
||||||
|
),
|
||||||
|
strCurrentVersionShortened,
|
||||||
|
intCurrentVersion.description,
|
||||||
|
strRemoteVersionShortened,
|
||||||
|
intRemoteVersion.description
|
||||||
|
)
|
||||||
|
let alert = NSAlert()
|
||||||
|
alert.messageText = NSLocalizedString("New Version Available", comment: "")
|
||||||
|
alert.informativeText = content
|
||||||
|
alert.addButton(withTitle: NSLocalizedString("Visit Website", comment: ""))
|
||||||
|
alert.addButton(withTitle: NSLocalizedString("Not Now", comment: ""))
|
||||||
|
NSApp.setActivationPolicy(.accessory)
|
||||||
|
let result = alert.runModal()
|
||||||
|
if result == NSApplication.ModalResponse.alertFirstButtonReturn {
|
||||||
|
if let siteInfoURLString = plist[UpdateSputnik.kUpdateInfoPageURLKey] as? String,
|
||||||
|
let siteURL = URL(string: siteInfoURLString)
|
||||||
|
{
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
NSWorkspace.shared.open(siteURL)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func cleanUp() {
|
||||||
|
currentTask = nil
|
||||||
|
data = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
private func showError(message: String = "") {
|
||||||
|
NSLog("Update check: plist error, forced check: \(isCurrentCheckForced)")
|
||||||
|
if !isCurrentCheckForced { return }
|
||||||
|
let alert = NSAlert()
|
||||||
|
let content = NSLocalizedString(message, comment: "")
|
||||||
|
alert.messageText = NSLocalizedString("Update Check Failed", comment: "")
|
||||||
|
alert.informativeText = content
|
||||||
|
alert.addButton(withTitle: NSLocalizedString("Dismiss", comment: ""))
|
||||||
|
alert.runModal()
|
||||||
|
NSApp.setActivationPolicy(.accessory)
|
||||||
|
}
|
||||||
|
}
|
|
@ -55,6 +55,15 @@ else {
|
||||||
exit(-1)
|
exit(-1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
guard let mainBundleInfoDict = Bundle.main.infoDictionary,
|
||||||
|
let strUpdateInfoSource = mainBundleInfoDict["UpdateInfoEndpoint"] as? String,
|
||||||
|
let urlUpdateInfoSource = URL(string: strUpdateInfoSource)
|
||||||
|
else {
|
||||||
|
NSLog("Fatal error: Info.plist wrecked It needs to have correct 'UpdateInfoEndpoint' value.")
|
||||||
|
exit(-1)
|
||||||
|
}
|
||||||
|
|
||||||
public let theServer = server
|
public let theServer = server
|
||||||
|
public let kUpdateInfoSourceURL = urlUpdateInfoSource
|
||||||
|
|
||||||
NSApp.run()
|
NSApp.run()
|
||||||
|
|
|
@ -1,4 +1,8 @@
|
||||||
"vChewing" = "vChewing";
|
"vChewing" = "vChewing";
|
||||||
|
"Update Check Completed" = "Update Check Completed";
|
||||||
|
"You are already using the latest version." = "You are already using the latest version.";
|
||||||
|
"Plist downloaded is nil." = "Plist downloaded is nil.";
|
||||||
|
"Plist downloaded cannot be parsed correctly." = "Plist downloaded cannot be parsed correctly.";
|
||||||
"vChewing crashed while handling previously loaded UOM observation data. These data files are cleaned now to ensure the usability." = "vChewing crashed while handling previously loaded UOM observation data. These data files are cleaned now to ensure the usability.";
|
"vChewing crashed while handling previously loaded UOM observation data. These data files are cleaned now to ensure the usability." = "vChewing crashed while handling previously loaded UOM observation data. These data files are cleaned now to ensure the usability.";
|
||||||
"About vChewing…" = "About vChewing…";
|
"About vChewing…" = "About vChewing…";
|
||||||
"vChewing Preferences…" = "vChewing Preferences…";
|
"vChewing Preferences…" = "vChewing Preferences…";
|
||||||
|
@ -17,7 +21,7 @@
|
||||||
"New Version Available" = "New Version Available";
|
"New Version Available" = "New Version Available";
|
||||||
"Not Now" = "Not Now";
|
"Not Now" = "Not Now";
|
||||||
"Visit Website" = "Visit Website";
|
"Visit Website" = "Visit Website";
|
||||||
"You're currently using vChewing %@ (%@), a new version %@ (%@) is now available. Do you want to visit vChewing's website to download the version?%@" = "You're currently using vChewing %@ (%@), a new version %@ (%@) is now available. Do you want to visit vChewing's website to download the version?%@";
|
"You're currently using vChewing %@ (%@), a new version %@ (%@) is now available. Do you want to visit vChewing's website to download the version?" = "You're currently using vChewing %@ (%@), a new version %@ (%@) is now available. Do you want to visit vChewing's website to download the version?";
|
||||||
"Force KangXi Writing" = "Force KangXi Writing";
|
"Force KangXi Writing" = "Force KangXi Writing";
|
||||||
"NotificationSwitchON" = "✔ ON";
|
"NotificationSwitchON" = "✔ ON";
|
||||||
"NotificationSwitchOFF" = "✘ OFF";
|
"NotificationSwitchOFF" = "✘ OFF";
|
||||||
|
|
|
@ -1,4 +1,8 @@
|
||||||
"vChewing" = "vChewing";
|
"vChewing" = "vChewing";
|
||||||
|
"Update Check Completed" = "Update Check Completed";
|
||||||
|
"You are already using the latest version." = "You are already using the latest version.";
|
||||||
|
"Plist downloaded is nil." = "Plist downloaded is nil.";
|
||||||
|
"Plist downloaded cannot be parsed correctly." = "Plist downloaded cannot be parsed correctly.";
|
||||||
"vChewing crashed while handling previously loaded UOM observation data. These data files are cleaned now to ensure the usability." = "vChewing crashed while handling previously loaded UOM observation data. These data files are cleaned now to ensure the usability.";
|
"vChewing crashed while handling previously loaded UOM observation data. These data files are cleaned now to ensure the usability." = "vChewing crashed while handling previously loaded UOM observation data. These data files are cleaned now to ensure the usability.";
|
||||||
"About vChewing…" = "About vChewing…";
|
"About vChewing…" = "About vChewing…";
|
||||||
"vChewing Preferences…" = "vChewing Preferences…";
|
"vChewing Preferences…" = "vChewing Preferences…";
|
||||||
|
@ -17,7 +21,7 @@
|
||||||
"New Version Available" = "New Version Available";
|
"New Version Available" = "New Version Available";
|
||||||
"Not Now" = "Not Now";
|
"Not Now" = "Not Now";
|
||||||
"Visit Website" = "Visit Website";
|
"Visit Website" = "Visit Website";
|
||||||
"You're currently using vChewing %@ (%@), a new version %@ (%@) is now available. Do you want to visit vChewing's website to download the version?%@" = "You're currently using vChewing %@ (%@), a new version %@ (%@) is now available. Do you want to visit vChewing's website to download the version?%@";
|
"You're currently using vChewing %@ (%@), a new version %@ (%@) is now available. Do you want to visit vChewing's website to download the version?" = "You're currently using vChewing %@ (%@), a new version %@ (%@) is now available. Do you want to visit vChewing's website to download the version?";
|
||||||
"Force KangXi Writing" = "Force KangXi Writing";
|
"Force KangXi Writing" = "Force KangXi Writing";
|
||||||
"NotificationSwitchON" = "✔ ON";
|
"NotificationSwitchON" = "✔ ON";
|
||||||
"NotificationSwitchOFF" = "✘ OFF";
|
"NotificationSwitchOFF" = "✘ OFF";
|
||||||
|
|
|
@ -1,4 +1,8 @@
|
||||||
"vChewing" = "威注音入力アプリ";
|
"vChewing" = "威注音入力アプリ";
|
||||||
|
"Update Check Completed" = "新バージョンチェック完了";
|
||||||
|
"You are already using the latest version." = "現在稼働中のは最新バージョンである。";
|
||||||
|
"Plist downloaded is nil." = "受けた新バージョンお知らせ情報データは Plist ではないため、失敗とみなす。";
|
||||||
|
"Plist downloaded cannot be parsed correctly." = "受けた新バージョンお知らせ情報 Plist データは解読できないため、失敗とみなす。";
|
||||||
"vChewing crashed while handling previously loaded UOM observation data. These data files are cleaned now to ensure the usability." = "臨時記憶モジュールの観測行為による威注音入力アプリの意外中止は発生した。威注音入力アプリの無事利用のために、既存臨時記憶データは全てお消しした。";
|
"vChewing crashed while handling previously loaded UOM observation data. These data files are cleaned now to ensure the usability." = "臨時記憶モジュールの観測行為による威注音入力アプリの意外中止は発生した。威注音入力アプリの無事利用のために、既存臨時記憶データは全てお消しした。";
|
||||||
"About vChewing…" = "威注音について…";
|
"About vChewing…" = "威注音について…";
|
||||||
"vChewing Preferences…" = "入力機能設定…";
|
"vChewing Preferences…" = "入力機能設定…";
|
||||||
|
@ -17,7 +21,7 @@
|
||||||
"New Version Available" = "最新版利用可能";
|
"New Version Available" = "最新版利用可能";
|
||||||
"Not Now" = "後で";
|
"Not Now" = "後で";
|
||||||
"Visit Website" = "公式サイト";
|
"Visit Website" = "公式サイト";
|
||||||
"You're currently using vChewing %@ (%@), a new version %@ (%@) is now available. Do you want to visit vChewing's website to download the version?%@" = "今のご使用していた威注音入力アプリのバージョンは「%1$@ (%2$@)」であり、ネットでもっと新しいバージョン「%3$@ (%4$@)」の下載せはできるらしい。公式サイトへバージョン「%5$@」を下載せますか?";
|
"You're currently using vChewing %@ (%@), a new version %@ (%@) is now available. Do you want to visit vChewing's website to download the version?" = "今のご使用していた威注音入力アプリのバージョンは「%1$@ (%2$@)」であり、ネットでもっと新しいバージョン「%3$@ (%4$@)」の下載せはできるらしい。お下載せしますか?";
|
||||||
"Force KangXi Writing" = "康熙文字変換モード";
|
"Force KangXi Writing" = "康熙文字変換モード";
|
||||||
"NotificationSwitchON" = "✔ 機能起動";
|
"NotificationSwitchON" = "✔ 機能起動";
|
||||||
"NotificationSwitchOFF" = "✘ 機能停止";
|
"NotificationSwitchOFF" = "✘ 機能停止";
|
||||||
|
|
|
@ -1,4 +1,8 @@
|
||||||
"vChewing" = "威注音输入法";
|
"vChewing" = "威注音输入法";
|
||||||
|
"Update Check Completed" = "更新检查完毕";
|
||||||
|
"You are already using the latest version." = "您正在使用目前最新的发行版。";
|
||||||
|
"Plist downloaded is nil." = "下载来的更新资讯并非 Plist 档案。";
|
||||||
|
"Plist downloaded cannot be parsed correctly." = "下载来的更新资讯 Plist 档案无法正常解析。";
|
||||||
"vChewing crashed while handling previously loaded UOM observation data. These data files are cleaned now to ensure the usability." = "威注音输入法的使用者半衰记忆模组在观测时崩溃,相关半衰记忆资料档案内容已全部清空。";
|
"vChewing crashed while handling previously loaded UOM observation data. These data files are cleaned now to ensure the usability." = "威注音输入法的使用者半衰记忆模组在观测时崩溃,相关半衰记忆资料档案内容已全部清空。";
|
||||||
"About vChewing…" = "关于威注音…";
|
"About vChewing…" = "关于威注音…";
|
||||||
"vChewing Preferences…" = "威注音偏好设定…";
|
"vChewing Preferences…" = "威注音偏好设定…";
|
||||||
|
@ -17,7 +21,7 @@
|
||||||
"New Version Available" = "有新版可下载";
|
"New Version Available" = "有新版可下载";
|
||||||
"Not Now" = "以后再说";
|
"Not Now" = "以后再说";
|
||||||
"Visit Website" = "前往网站";
|
"Visit Website" = "前往网站";
|
||||||
"You're currently using vChewing %@ (%@), a new version %@ (%@) is now available. Do you want to visit vChewing's website to download the version?%@" = "目前使用的威注音官方版本是 %1$@ (%2$@),网路上有更新版本 %3$@ (%4$@) 可供下载。是否要前往威注音网站下载新版来安装?%5$@";
|
"You're currently using vChewing %@ (%@), a new version %@ (%@) is now available. Do you want to visit vChewing's website to download the version?" = "目前使用的威注音官方版本是 %1$@ (%2$@),网路上有更新版本 %3$@ (%4$@) 可供下载。是否要前往威注音网站下载新版来安装?";
|
||||||
"Force KangXi Writing" = "康熙正体字模式";
|
"Force KangXi Writing" = "康熙正体字模式";
|
||||||
"NotificationSwitchON" = "✔ 已启用";
|
"NotificationSwitchON" = "✔ 已启用";
|
||||||
"NotificationSwitchOFF" = "✘ 已停用";
|
"NotificationSwitchOFF" = "✘ 已停用";
|
||||||
|
|
|
@ -1,4 +1,8 @@
|
||||||
"vChewing" = "威注音輸入法";
|
"vChewing" = "威注音輸入法";
|
||||||
|
"Update Check Completed" = "更新檢查完畢";
|
||||||
|
"You are already using the latest version." = "您正在使用目前最新的發行版。";
|
||||||
|
"Plist downloaded is nil." = "下載來的更新資訊並非 Plist 檔案。";
|
||||||
|
"Plist downloaded cannot be parsed correctly." = "下載來的更新資訊 Plist 檔案無法正常解析。";
|
||||||
"vChewing crashed while handling previously loaded UOM observation data. These data files are cleaned now to ensure the usability." = "威注音輸入法的使用者半衰記憶模組在觀測時崩潰,相關半衰記憶資料檔案內容已全部清空。";
|
"vChewing crashed while handling previously loaded UOM observation data. These data files are cleaned now to ensure the usability." = "威注音輸入法的使用者半衰記憶模組在觀測時崩潰,相關半衰記憶資料檔案內容已全部清空。";
|
||||||
"About vChewing…" = "關於威注音…";
|
"About vChewing…" = "關於威注音…";
|
||||||
"vChewing Preferences…" = "威注音偏好設定…";
|
"vChewing Preferences…" = "威注音偏好設定…";
|
||||||
|
@ -17,7 +21,7 @@
|
||||||
"New Version Available" = "有新版可下載";
|
"New Version Available" = "有新版可下載";
|
||||||
"Not Now" = "以後再說";
|
"Not Now" = "以後再說";
|
||||||
"Visit Website" = "前往網站";
|
"Visit Website" = "前往網站";
|
||||||
"You're currently using vChewing %@ (%@), a new version %@ (%@) is now available. Do you want to visit vChewing's website to download the version?%@" = "目前使用的威注音官方版本是 %1$@ (%2$@),網路上有更新版本 %3$@ (%4$@) 可供下載。是否要前往威注音網站下載新版來安裝?%5$@";
|
"You're currently using vChewing %@ (%@), a new version %@ (%@) is now available. Do you want to visit vChewing's website to download the version?" = "目前使用的威注音官方版本是 %1$@ (%2$@),網路上有更新版本 %3$@ (%4$@) 可供下載。是否要前往威注音網站下載新版來安裝?";
|
||||||
"Force KangXi Writing" = "康熙正體字模式";
|
"Force KangXi Writing" = "康熙正體字模式";
|
||||||
"NotificationSwitchON" = "✔ 已啟用";
|
"NotificationSwitchON" = "✔ 已啟用";
|
||||||
"NotificationSwitchOFF" = "✘ 已停用";
|
"NotificationSwitchOFF" = "✘ 已停用";
|
||||||
|
|
|
@ -85,6 +85,7 @@
|
||||||
5BBBB77527AED70B0023B93A /* MenuIcon-SCVIM.png in Resources */ = {isa = PBXBuildFile; fileRef = 5BBBB77127AED70B0023B93A /* MenuIcon-SCVIM.png */; };
|
5BBBB77527AED70B0023B93A /* MenuIcon-SCVIM.png in Resources */ = {isa = PBXBuildFile; fileRef = 5BBBB77127AED70B0023B93A /* MenuIcon-SCVIM.png */; };
|
||||||
5BBBB77627AED70B0023B93A /* MenuIcon-TCVIM.png in Resources */ = {isa = PBXBuildFile; fileRef = 5BBBB77227AED70B0023B93A /* MenuIcon-TCVIM.png */; };
|
5BBBB77627AED70B0023B93A /* MenuIcon-TCVIM.png in Resources */ = {isa = PBXBuildFile; fileRef = 5BBBB77227AED70B0023B93A /* MenuIcon-TCVIM.png */; };
|
||||||
5BBBB77A27AEDC690023B93A /* clsSFX.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BBBB77927AEDC690023B93A /* clsSFX.swift */; };
|
5BBBB77A27AEDC690023B93A /* clsSFX.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BBBB77927AEDC690023B93A /* clsSFX.swift */; };
|
||||||
|
5BBC9EFC28CA042500041196 /* UpdateSputnik.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BBC9EFB28CA042500041196 /* UpdateSputnik.swift */; };
|
||||||
5BC2652227E04B7E00700291 /* uninstall.sh in Resources */ = {isa = PBXBuildFile; fileRef = 5BC2652127E04B7B00700291 /* uninstall.sh */; };
|
5BC2652227E04B7E00700291 /* uninstall.sh in Resources */ = {isa = PBXBuildFile; fileRef = 5BC2652127E04B7B00700291 /* uninstall.sh */; };
|
||||||
5BC4479D2865686500EDC323 /* data-chs.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5BEDB71C283B4AEA0078EB25 /* data-chs.plist */; };
|
5BC4479D2865686500EDC323 /* data-chs.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5BEDB71C283B4AEA0078EB25 /* data-chs.plist */; };
|
||||||
5BC4479E2865686500EDC323 /* data-cht.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5BEDB720283B4AEA0078EB25 /* data-cht.plist */; };
|
5BC4479E2865686500EDC323 /* data-cht.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5BEDB720283B4AEA0078EB25 /* data-cht.plist */; };
|
||||||
|
@ -303,6 +304,7 @@
|
||||||
5BBBB77227AED70B0023B93A /* MenuIcon-TCVIM.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "MenuIcon-TCVIM.png"; sourceTree = "<group>"; };
|
5BBBB77227AED70B0023B93A /* MenuIcon-TCVIM.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "MenuIcon-TCVIM.png"; sourceTree = "<group>"; };
|
||||||
5BBBB77727AEDB290023B93A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/MainMenu.strings; sourceTree = "<group>"; };
|
5BBBB77727AEDB290023B93A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/MainMenu.strings; sourceTree = "<group>"; };
|
||||||
5BBBB77927AEDC690023B93A /* clsSFX.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = clsSFX.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
|
5BBBB77927AEDC690023B93A /* clsSFX.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = clsSFX.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
|
||||||
|
5BBC9EFB28CA042500041196 /* UpdateSputnik.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateSputnik.swift; sourceTree = "<group>"; };
|
||||||
5BBD627827B6C4D900271480 /* Update-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Update-Info.plist"; sourceTree = "<group>"; };
|
5BBD627827B6C4D900271480 /* Update-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Update-Info.plist"; sourceTree = "<group>"; };
|
||||||
5BC0AAC927F58472002D33E9 /* pkgPreInstall.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = pkgPreInstall.sh; sourceTree = "<group>"; };
|
5BC0AAC927F58472002D33E9 /* pkgPreInstall.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = pkgPreInstall.sh; sourceTree = "<group>"; };
|
||||||
5BC0AACA27F58472002D33E9 /* pkgPostInstall.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = pkgPostInstall.sh; sourceTree = "<group>"; };
|
5BC0AACA27F58472002D33E9 /* pkgPostInstall.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = pkgPostInstall.sh; sourceTree = "<group>"; };
|
||||||
|
@ -542,6 +544,7 @@
|
||||||
5B5E535127EF261400C6AA1E /* IME.swift */,
|
5B5E535127EF261400C6AA1E /* IME.swift */,
|
||||||
5B175FFA28C5CDDC0078D1B4 /* IMKHelper.swift */,
|
5B175FFA28C5CDDC0078D1B4 /* IMKHelper.swift */,
|
||||||
5B62A33527AE795800A19448 /* mgrPrefs.swift */,
|
5B62A33527AE795800A19448 /* mgrPrefs.swift */,
|
||||||
|
5BBC9EFB28CA042500041196 /* UpdateSputnik.swift */,
|
||||||
);
|
);
|
||||||
path = IMEModules;
|
path = IMEModules;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -1214,6 +1217,7 @@
|
||||||
5B40730C281672610023DFFF /* lmAssociates.swift in Sources */,
|
5B40730C281672610023DFFF /* lmAssociates.swift in Sources */,
|
||||||
D427F76C278CA2B0004A2160 /* AppDelegate.swift in Sources */,
|
D427F76C278CA2B0004A2160 /* AppDelegate.swift in Sources */,
|
||||||
5BA9FD4527FEF3C9002DE248 /* ToolbarItemStyleViewController.swift in Sources */,
|
5BA9FD4527FEF3C9002DE248 /* ToolbarItemStyleViewController.swift in Sources */,
|
||||||
|
5BBC9EFC28CA042500041196 /* UpdateSputnik.swift in Sources */,
|
||||||
5BA9FD4127FEF3C8002DE248 /* PreferencesStyle.swift in Sources */,
|
5BA9FD4127FEF3C8002DE248 /* PreferencesStyle.swift in Sources */,
|
||||||
5B7F225D2808501000DDD3CB /* KeyHandler_HandleInput.swift in Sources */,
|
5B7F225D2808501000DDD3CB /* KeyHandler_HandleInput.swift in Sources */,
|
||||||
5BA9FD1227FEDB6B002DE248 /* suiPrefPaneExperience.swift in Sources */,
|
5BA9FD1227FEDB6B002DE248 /* suiPrefPaneExperience.swift in Sources */,
|
||||||
|
|
Loading…
Reference in New Issue