Repo // Upgrade ClientListMgr to mk2.

This commit is contained in:
ShikiSuen 2023-02-16 04:04:59 +08:00
parent ce9138028a
commit 87bc36aa9e
14 changed files with 176 additions and 64 deletions

View File

@ -41,7 +41,7 @@ public protocol PrefMgrProtocol {
var hardenVerticalPunctuations: Bool { get set }
var trimUnfinishedReadingsOnCommit: Bool { get set }
var alwaysShowTooltipTextsHorizontally: Bool { get set }
var clientsIMKTextInputIncapable: [String] { get set }
var clientsIMKTextInputIncapable: [String: Bool] { get set }
var onlyLoadFactoryLangModelsIfNeeded: Bool { get set }
var useIMKCandidateWindow: Bool { get set }
var handleDefaultCandidateFontsByLangIdentifier: Bool { get set }

View File

@ -61,6 +61,7 @@ public protocol InputHandlerDelegate {
var selectionKeys: String { get }
var state: IMEStateProtocol { get set }
var clientBundleIdentifier: String { get }
var clientMitigationLevel: Int { get }
func callError(_ logMessage: String)
func updateVerticalTypingStatus()
func switchState(_ newState: IMEStateProtocol)
@ -540,8 +541,8 @@ extension InputHandler {
var commitOverflownComposition: String {
guard !compositor.walkedNodes.isEmpty,
compositor.length > compositorWidthLimit,
let identifier = delegate?.clientBundleIdentifier,
prefs.clientsIMKTextInputIncapable.contains(identifier)
let delegate = delegate,
delegate.clientMitigationLevel >= 2
else { return "" }
// Steam Client Identifier
var textToCommit = ""

View File

@ -22,8 +22,8 @@ public class PrefMgr: PrefMgrProtocol {
return "com.apple.keylayout.US"
}()
public static let kDefaultClientsIMKTextInputIncapable: [String] = [
"com.valvesoftware.steam", "jp.naver.line.mac",
public static let kDefaultClientsIMKTextInputIncapable: [String: Bool] = [
"com.valvesoftware.steam": true, "jp.naver.line.mac": true,
]
// MARK: - Settings (Tier 1)
@ -144,7 +144,7 @@ public class PrefMgr: PrefMgrProtocol {
public var alwaysShowTooltipTextsHorizontally: Bool
@AppProperty(key: UserDef.kClientsIMKTextInputIncapable.rawValue, defaultValue: kDefaultClientsIMKTextInputIncapable)
public var clientsIMKTextInputIncapable: [String]
public var clientsIMKTextInputIncapable: [String: Bool]
@AppProperty(key: UserDef.kOnlyLoadFactoryLangModelsIfNeeded.rawValue, defaultValue: true)
public var onlyLoadFactoryLangModelsIfNeeded: Bool {

View File

@ -23,8 +23,16 @@ public extension PrefMgr {
}
// ( didSet )
candidateKeys = candidateKeys
//
clientsIMKTextInputIncapable = Array(Set(clientsIMKTextInputIncapable)).sorted()
//
if let clients = UserDefaults.standard.object(
forKey: UserDef.kClientsIMKTextInputIncapable.rawValue
) as? [String] {
UserDefaults.standard.removeObject(forKey: UserDef.kClientsIMKTextInputIncapable.rawValue)
clients.forEach { neta in
guard !clientsIMKTextInputIncapable.keys.contains(neta) else { return }
clientsIMKTextInputIncapable[neta] = true
}
}
//
var isKeyboardParserOptionValid = false
KeyboardParser.allCases.forEach {

View File

@ -11,6 +11,15 @@ import Shared
// MARK: - InputHandler Delegate
extension SessionCtl: InputHandlerDelegate {
public var clientMitigationLevel: Int {
guard
let result = PrefMgr.shared.clientsIMKTextInputIncapable[clientBundleIdentifier]
else {
return 0
}
return result ? 2 : 1
}
public func candidateController() -> CtlCandidateProtocol? { candidateUI }
public func candidateSelectionCalledByInputHandler(at index: Int) {

View File

@ -16,8 +16,8 @@ public extension SessionCtl {
// App 使
// App App
// 使 20
var attributedStringSecured: (NSAttributedString, NSRange) {
PrefMgr.shared.clientsIMKTextInputIncapable.contains(clientBundleIdentifier)
var attributedStringSecured: (value: NSAttributedString, range: NSRange) {
clientMitigationLevel >= 2
? (state.data.attributedStringPlaceholder, NSRange(location: 0, length: 0))
: (state.attributedString, NSRange(state.u16MarkedRange))
}

View File

@ -87,7 +87,7 @@ public extension SessionCtl {
showCandidates()
}
//
if newState.hasComposition, PrefMgr.shared.clientsIMKTextInputIncapable.contains(clientBundleIdentifier) {
if newState.hasComposition, clientMitigationLevel >= 2 {
updateVerticalTypingStatus()
popupCompositionBuffer.isTypingDirectionVertical = isVerticalTyping
popupCompositionBuffer.show(
@ -100,12 +100,25 @@ public extension SessionCtl {
/// /
func setInlineDisplayWithCursor() {
var attrStr: NSAttributedString = attributedStringSecured.value
var theRange: NSRange = attributedStringSecured.range
// QQNT client.setMarkedText() .thick
mitigation: if clientMitigationLevel == 1, state.type == .ofMarking {
if !PrefMgr.shared.disableSegmentedThickUnderlineInMarkingModeForManagedClients { break mitigation }
let neo = NSMutableAttributedString(attributedString: attributedStringSecured.value)
neo.setAttributes(
[
.underlineStyle: NSUnderlineStyle.thick.rawValue,
.markedClauseSegment: 0,
], range: NSRange(location: 0, length: neo.string.utf16.count)
)
attrStr = neo
theRange = NSRange.zero
}
/// selectionRange
/// 0 replacementRangeNSNotFound
///
doSetMarkedText(
attributedStringSecured.0, selectionRange: attributedStringSecured.1
)
doSetMarkedText(attrStr, selectionRange: theRange)
}
/// 使

View File

@ -34,15 +34,30 @@ class CtlClientListMgr: NSWindowController, NSTableViewDelegate, NSTableViewData
tblClients.delegate = self
tblClients.allowsMultipleSelection = true
tblClients.dataSource = self
tblClients.action = #selector(onItemClicked(_:))
tblClients.target = self
tblClients.reloadData()
}
}
// MARK: - UserDefaults Handlers
extension CtlClientListMgr {
public static var clientsList: [String] { PrefMgr.shared.clientsIMKTextInputIncapable.keys.sorted() }
public static func removeClient(at index: Int) {
guard index < Self.clientsList.count else { return }
let key = Self.clientsList[index]
var dict = PrefMgr.shared.clientsIMKTextInputIncapable
dict[key] = nil
PrefMgr.shared.clientsIMKTextInputIncapable = dict
}
}
// MARK: - Implementations
extension CtlClientListMgr {
func numberOfRows(in _: NSTableView) -> Int {
PrefMgr.shared.clientsIMKTextInputIncapable.count
Self.clientsList.count
}
@IBAction func btnAddClientClicked(_: Any) {
@ -105,8 +120,8 @@ extension CtlClientListMgr {
switch result {
case .OK:
for url in dlgOpenPath.urls {
var title = NSLocalizedString(
"The selected item is not a valid macOS application bundle, nor not having a valid app bundle identifier.",
let title = NSLocalizedString(
"The selected item is either not a valid macOS application bundle or not having a valid app bundle identifier.",
comment: ""
)
let text = url.path + "\n\n" + NSLocalizedString("Please try again.", comment: "")
@ -118,14 +133,21 @@ extension CtlClientListMgr {
self.window?.callAlert(title: title, text: text)
return
}
if PrefMgr.shared.clientsIMKTextInputIncapable.contains(identifier) {
title = NSLocalizedString(
"The selected item's identifier is already in the list.", comment: ""
)
self.window?.callAlert(title: title, text: identifier + "\n\n" + url.path)
return
let isIdentifierAlreadyRegistered = Self.clientsList.contains(identifier)
let alert2 = NSAlert()
alert2.messageText =
"Do you want to enable the popup composition buffer for this client?".localized
alert2.informativeText = "\(identifier)\n\n"
+ "Some client apps may have different compatibility issues in IMKTextInput implementation.".localized
alert2.addButton(withTitle: "Yes".localized)
alert2.addButton(withTitle: "No".localized)
alert2.beginSheetModal(for: window) { result2 in
let oldValue = PrefMgr.shared.clientsIMKTextInputIncapable[identifier]
let newValue = result2 == .alertFirstButtonReturn
if !(isIdentifierAlreadyRegistered && oldValue == newValue) {
self.applyNewValue(identifier, highMitigation: newValue)
}
}
self.applyNewValue(identifier)
}
default: return
}
@ -135,50 +157,71 @@ extension CtlClientListMgr {
}
}
private func applyNewValue(_ newValue: String) {
private func applyNewValue(_ newValue: String, highMitigation mitigation: Bool = true) {
guard !newValue.isEmpty else { return }
var arrResult = PrefMgr.shared.clientsIMKTextInputIncapable
arrResult.append(newValue)
PrefMgr.shared.clientsIMKTextInputIncapable = arrResult.sorted()
var dict = PrefMgr.shared.clientsIMKTextInputIncapable
dict[newValue] = mitigation
PrefMgr.shared.clientsIMKTextInputIncapable = dict
tblClients.reloadData()
btnRemoveClient.isEnabled = (0 ..< PrefMgr.shared.clientsIMKTextInputIncapable.count).contains(
btnRemoveClient.isEnabled = (0 ..< Self.clientsList.count).contains(
tblClients.selectedRow)
}
@IBAction func btnRemoveClientClicked(_: Any) {
guard let minIndexSelected = tblClients.selectedRowIndexes.min() else { return }
if minIndexSelected >= PrefMgr.shared.clientsIMKTextInputIncapable.count { return }
if minIndexSelected >= Self.clientsList.count { return }
if minIndexSelected < 0 { return }
var isLastRow = false
tblClients.selectedRowIndexes.sorted().reversed().forEach { index in
isLastRow = {
if PrefMgr.shared.clientsIMKTextInputIncapable.count < 2 { return false }
return minIndexSelected == PrefMgr.shared.clientsIMKTextInputIncapable.count - 1
if Self.clientsList.count < 2 { return false }
return minIndexSelected == Self.clientsList.count - 1
}()
if index < PrefMgr.shared.clientsIMKTextInputIncapable.count {
PrefMgr.shared.clientsIMKTextInputIncapable.remove(at: index)
if index < Self.clientsList.count {
Self.removeClient(at: index)
}
}
if isLastRow {
tblClients.selectRowIndexes(.init(arrayLiteral: minIndexSelected - 1), byExtendingSelection: false)
}
tblClients.reloadData()
btnRemoveClient.isEnabled = (0 ..< PrefMgr.shared.clientsIMKTextInputIncapable.count).contains(minIndexSelected)
btnRemoveClient.isEnabled = (0 ..< Self.clientsList.count).contains(minIndexSelected)
}
func tableView(_: NSTableView, objectValueFor _: NSTableColumn?, row: Int) -> Any? {
@objc func onItemClicked(_: Any!) {
guard tblClients.clickedColumn == 0 else { return }
PrefMgr.shared.clientsIMKTextInputIncapable[Self.clientsList[tblClients.clickedRow]]?.toggle()
tblClients.reloadData()
}
func tableView(_: NSTableView, shouldEdit _: NSTableColumn?, row _: Int) -> Bool {
false
}
func tableView(_: NSTableView, objectValueFor column: NSTableColumn?, row: Int) -> Any? {
defer {
self.btnRemoveClient.isEnabled = (0 ..< PrefMgr.shared.clientsIMKTextInputIncapable.count).contains(
self.btnRemoveClient.isEnabled = (0 ..< Self.clientsList.count).contains(
self.tblClients.selectedRow)
}
return PrefMgr.shared.clientsIMKTextInputIncapable[row]
guard row < Self.clientsList.count else { return "" }
if let column = column {
let colName = column.identifier.rawValue
switch colName {
case "colPCBEnabled":
let tick = PrefMgr.shared.clientsIMKTextInputIncapable[Self.clientsList[row]] ?? true
return tick
case "colClient": return Self.clientsList[row]
default: return ""
}
}
return Self.clientsList[row]
}
private func localize() {
guard let window = window else { return }
window.title = NSLocalizedString("Client Manager", comment: "")
lblClientMgrWindow.stringValue = NSLocalizedString(
"Please manage the list of those clients here which are: 1) IMKTextInput-incompatible; 2) suspected from abusing the contents of the inline composition buffer. Clients listed here will only use popup composition buffer with maximum 20 reading counts holdable.",
"Please manage the list of those clients here which are: 1) IMKTextInput-incompatible; 2) suspected from abusing the contents of the inline composition buffer. A client listed here, if checked, will use popup composition buffer with maximum 20 reading counts holdable.",
comment: ""
)
btnAddClient.title = NSLocalizedString("Add Client", comment: "")

View File

@ -1,4 +1,8 @@
"vChewing" = "vChewing";
"Do you want to enable the popup composition buffer for this client?" = "Do you want to enable the popup composition buffer for this client?";
"Some client apps may have different compatibility issues in IMKTextInput implementation." = "Some client apps may have different compatibility issues in IMKTextInput implementation.";
"Yes" = "Yes";
"No" = "No";
"Hanin Keyboard Symbol Input." = "Hanin Keyboard Symbol Input.";
"Open App Support Folder" = "Open App Support Folder";
"Invalid Code Point." = "Invalid Code Point.";
@ -58,11 +62,11 @@
"One record per line. Use Option+Enter to break lines.\nBlank lines will be dismissed." = "One record per line. Use Option+Enter to break lines.\nBlank lines will be dismissed.";
"Just Select" = "Just Select";
"Client Manager" = "Client Manager";
"Please manage the list of those clients here which are: 1) IMKTextInput-incompatible; 2) suspected from abusing the contents of the inline composition buffer. Clients listed here will only use popup composition buffer with maximum 20 reading counts holdable." = "Please manage the list of those clients here which are: 1) IMKTextInput-incompatible; 2) suspected from abusing the contents of the inline composition buffer. Clients listed here will only use popup composition buffer with maximum 20 reading counts holdable.";
"Please manage the list of those clients here which are: 1) IMKTextInput-incompatible; 2) suspected from abusing the contents of the inline composition buffer. A client listed here, if checked, will use popup composition buffer with maximum 20 reading counts holdable." = "Please manage the list of those clients here which are: 1) IMKTextInput-incompatible; 2) suspected from abusing the contents of the inline composition buffer. A client listed here, if checked, will use popup composition buffer with maximum 20 reading counts holdable.";
"Add Client" = "Add Client";
"Remove Selected" = "Remove Selected";
"Choose the target application bundle." = "Choose the target application bundle.";
"The selected item is not a valid macOS application bundle, nor not having a valid app bundle identifier." = "The selected item is not a valid macOS application bundle, nor not having a valid app bundle identifier.";
"The selected item is either not a valid macOS application bundle or not having a valid app bundle identifier." = "The selected item is either not a valid macOS application bundle or not having a valid app bundle identifier.";
"Please try again." = "Please try again.";
"The selected item's identifier is already in the list." = "The selected item's identifier is already in the list.";
"Update Check Completed" = "Update Check Completed";

View File

@ -1,4 +1,8 @@
"vChewing" = "vChewing";
"Do you want to enable the popup composition buffer for this client?" = "Do you want to enable the popup composition buffer for this client?";
"Some client apps may have different compatibility issues in IMKTextInput implementation." = "Some client apps may have different compatibility issues in IMKTextInput implementation.";
"Yes" = "Yes";
"No" = "No";
"Hanin Keyboard Symbol Input." = "Hanin Keyboard Symbol Input.";
"Open App Support Folder" = "Open App Support Folder";
"Invalid Code Point." = "Invalid Code Point.";
@ -58,11 +62,11 @@
"One record per line. Use Option+Enter to break lines.\nBlank lines will be dismissed." = "One record per line. Use Option+Enter to break lines.\nBlank lines will be dismissed.";
"Just Select" = "Just Select";
"Client Manager" = "Client Manager";
"Please manage the list of those clients here which are: 1) IMKTextInput-incompatible; 2) suspected from abusing the contents of the inline composition buffer. Clients listed here will only use popup composition buffer with maximum 20 reading counts holdable." = "Please manage the list of those clients here which are: 1) IMKTextInput-incompatible; 2) suspected from abusing the contents of the inline composition buffer. Clients listed here will only use popup composition buffer with maximum 20 reading counts holdable.";
"Please manage the list of those clients here which are: 1) IMKTextInput-incompatible; 2) suspected from abusing the contents of the inline composition buffer. A client listed here, if checked, will use popup composition buffer with maximum 20 reading counts holdable." = "Please manage the list of those clients here which are: 1) IMKTextInput-incompatible; 2) suspected from abusing the contents of the inline composition buffer. A client listed here, if checked, will use popup composition buffer with maximum 20 reading counts holdable.";
"Add Client" = "Add Client";
"Remove Selected" = "Remove Selected";
"Choose the target application bundle." = "Choose the target application bundle.";
"The selected item is not a valid macOS application bundle, nor not having a valid app bundle identifier." = "The selected item is not a valid macOS application bundle, nor not having a valid app bundle identifier.";
"The selected item is either not a valid macOS application bundle or not having a valid app bundle identifier." = "The selected item is either not a valid macOS application bundle or not having a valid app bundle identifier.";
"Please try again." = "Please try again.";
"The selected item's identifier is already in the list." = "The selected item's identifier is already in the list.";
"Update Check Completed" = "Update Check Completed";

View File

@ -1,4 +1,8 @@
"vChewing" = "威注音入力アプリ";
"Do you want to enable the popup composition buffer for this client?" = "この客体アプリに「吹き出し入力緩衝列ウィンドウ」を起用しますか?";
"Some client apps may have different compatibility issues in IMKTextInput implementation." = "それぞれの客体アプリには、それぞれの IMKTextInput 不具合はあるかもしれません。";
"Yes" = "うむ";
"No" = "いな";
"Hanin Keyboard Symbol Input." = "漢音キーボード符号入力。";
"Open App Support Folder" = "App Support フォルダーを開く";
"Invalid Code Point." = "コードポイントは正しくない。";
@ -58,11 +62,11 @@
"One record per line. Use Option+Enter to break lines.\nBlank lines will be dismissed." = "毎行はつ記録とみなす。Option+Enter キーで改行。\n空白の記録値は無視される。";
"Just Select" = "直接に選ぶ";
"Client Manager" = "客体アプリの管理";
"Please manage the list of those clients here which are: 1) IMKTextInput-incompatible; 2) suspected from abusing the contents of the inline composition buffer. Clients listed here will only use popup composition buffer with maximum 20 reading counts holdable." = "下記の種類の客体アプリはここでご登録くださいIMKTextInput 議定規約に反するもの;2)文脈内入力緩衝列の内容の不正利用の疑いのあるもの。登録済みのアプリには、威注音入力アプリは「吹き出し入力緩衝列ウィンドウ」と「緩衝列容量制限」を起用し、容量制限は最大限音読み20箇とする。";
"Please manage the list of those clients here which are: 1) IMKTextInput-incompatible; 2) suspected from abusing the contents of the inline composition buffer. A client listed here, if checked, will use popup composition buffer with maximum 20 reading counts holdable." = "下記の客体アプリはここでご登録をIMKTextInput 議定規約に反するもの;2)文脈内入力緩衝列の内容の不正利用容疑のあるもの。「登録済みのアプリ」にチェックを入れると、「吹き出し入力緩衝列ウィンドウ」と「緩衝列容量制限」を起用し、容量制限は最大限音読み20箇とする。";
"Add Client" = "入れる";
"Remove Selected" = "外す";
"Choose the target application bundle." = "登録したいアプリのバンドルのお選びを。";
"The selected item is not a valid macOS application bundle, nor not having a valid app bundle identifier." = "今選んだんのは正しい macOS アプリバンドルではないと考えられる。少なくとも、唯一識別子は検出できぬ。";
"The selected item is either not a valid macOS application bundle or not having a valid app bundle identifier." = "今選んだんのは正しい macOS アプリバンドルではないと考えられる。少なくとも、唯一識別子は検出できぬ。";
"Please try again." = "お選び直しください。";
"The selected item's identifier is already in the list." = "今選んだバンドルの唯一識別子Bundle Identifierは既に登録済みである。";
"Update Check Completed" = "新バージョンチェック完了";

View File

@ -1,4 +1,8 @@
"vChewing" = "威注音输入法";
"Do you want to enable the popup composition buffer for this client?" = "您要對該客體啟用浮動組字窗嗎?";
"Some client apps may have different compatibility issues in IMKTextInput implementation." = "有些客體應用可能會有不同的 IMKTextInput 實作相容問題。";
"Yes" = "是";
"No" = "否";
"Hanin Keyboard Symbol Input." = "汉音键盘符号模式。";
"Open App Support Folder" = "开启 App Support 目录";
"Invalid Code Point." = "内码不正确。";
@ -58,11 +62,11 @@
"One record per line. Use Option+Enter to break lines.\nBlank lines will be dismissed." = "每行一笔记录,用 Option+Enter 换行。\n空白值会被无视。";
"Just Select" = "直接选取";
"Client Manager" = "管理客体应用";
"Please manage the list of those clients here which are: 1) IMKTextInput-incompatible; 2) suspected from abusing the contents of the inline composition buffer. Clients listed here will only use popup composition buffer with maximum 20 reading counts holdable." = "请在此管理这两类客体应用1) 不遵守 IMKTextInput 协定2有滥用内文组字区的嫌疑。威注音输入法对于任何位列在此的客体应用均启用浮动组字窗、且对组字区内容设定容量上限(最多二十个读音)。";
"Please manage the list of those clients here which are: 1) IMKTextInput-incompatible; 2) suspected from abusing the contents of the inline composition buffer. A client listed here, if checked, will use popup composition buffer with maximum 20 reading counts holdable." = "请在此管理这两类客体应用1) 不遵守 IMKTextInput 协定2有滥用内文组字区的嫌疑。您可以勾选上述客体应用、以启用下述特性:启用浮动组字窗、且对组字区内容设定容量上限(最多二十个读音)。";
"Add Client" = "登记新客体";
"Remove Selected" = "移除所选条目";
"Choose the target application bundle." = "请选择要登记的应用程式的封包。";
"The selected item is not a valid macOS application bundle, nor not having a valid app bundle identifier." = "当前所选之物并非 macOS 应用程式封包至少无法发现其唯一标帜Bundle Identifier。";
"The selected item is either not a valid macOS application bundle or not having a valid app bundle identifier." = "当前所选之物并非 macOS 应用程式封包至少无法发现其唯一标帜Bundle Identifier。";
"Please try again." = "请重试。";
"The selected item's identifier is already in the list." = "当前所选之封包的唯一标帜Bundle Identifier已被登记。";
"Update Check Completed" = "更新检查完毕";

View File

@ -1,4 +1,8 @@
"vChewing" = "威注音輸入法";
"Do you want to enable the popup composition buffer for this client?" = "您要对该客体启用浮动组字窗吗?";
"Some client apps may have different compatibility issues in IMKTextInput implementation." = "有些客体应用可能会有不同的 IMKTextInput 实作相容问题。";
"Yes" = "是";
"No" = "否";
"Hanin Keyboard Symbol Input." = "漢音鍵盤符號模式。";
"Open App Support Folder" = "開啟 App Support 目錄";
"Invalid Code Point." = "內碼不正確。";
@ -58,11 +62,11 @@
"One record per line. Use Option+Enter to break lines.\nBlank lines will be dismissed." = "每行一筆記錄,用 Option+Enter 換行。\n空白值會被無視。";
"Just Select" = "直接選取";
"Client Manager" = "管理客體應用";
"Please manage the list of those clients here which are: 1) IMKTextInput-incompatible; 2) suspected from abusing the contents of the inline composition buffer. Clients listed here will only use popup composition buffer with maximum 20 reading counts holdable." = "請在此管理這兩類客體應用1) 不遵守 IMKTextInput 協定2有濫用內文組字區的嫌疑。威注音輸入法對於任何位列在此的客體應用均啟用浮動組字窗、且對組字區內容設定容量上限(最多二十個讀音)。";
"Please manage the list of those clients here which are: 1) IMKTextInput-incompatible; 2) suspected from abusing the contents of the inline composition buffer. A client listed here, if checked, will use popup composition buffer with maximum 20 reading counts holdable." = "請在此管理這兩類客體應用1) 不遵守 IMKTextInput 協定2有濫用內文組字區的嫌疑。您可以勾選上述客體應用、以啟用下述特性:啟用浮動組字窗、且對組字區內容設定容量上限(最多二十個讀音)。";
"Add Client" = "登記新客體";
"Remove Selected" = "移除所選條目";
"Choose the target application bundle." = "請選擇要登記的應用程式的封包。";
"The selected item is not a valid macOS application bundle, nor not having a valid app bundle identifier." = "當前所選之物並非 macOS 應用程式封包至少無法發現其唯一標幟Bundle Identifier。";
"The selected item is either not a valid macOS application bundle or not having a valid app bundle identifier." = "當前所選之物並非 macOS 應用程式封包至少無法發現其唯一標幟Bundle Identifier。";
"Please try again." = "請重試。";
"The selected item's identifier is already in the list." = "當前所選之封包的唯一標幟Bundle Identifier已被登記。";
"Update Check Completed" = "更新檢查完畢";

View File

@ -1,7 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="21225" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="21507" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="21225"/>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="21507"/>
<capability name="System colors introduced in macOS 10.14" minToolsVersion="10.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
@ -20,17 +21,17 @@
<window title="Client Manager" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" animationBehavior="default" titlebarAppearsTransparent="YES" id="F0z-JX-Cv5">
<windowStyleMask key="styleMask" titled="YES" closable="YES" fullSizeContentView="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="196" y="240" width="664" height="335"/>
<rect key="contentRect" x="196" y="240" width="770" height="335"/>
<rect key="screenRect" x="0.0" y="0.0" width="1920" height="1055"/>
<view key="contentView" id="se5-gp-TjO" customClass="NSVisualEffectView" customModule="vChewing" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="664" height="335"/>
<rect key="frame" x="0.0" y="0.0" width="770" height="335"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="3ev-ns-FKY" userLabel="lblClientMgrWindow">
<rect key="frame" x="18" y="20" width="494" height="46"/>
<rect key="frame" x="18" y="20" width="600" height="46"/>
<constraints>
<constraint firstAttribute="height" constant="46" id="HDu-vv-Kcv"/>
<constraint firstAttribute="width" constant="490" id="LhL-fH-PVL"/>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="46" id="HDu-vv-Kcv"/>
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="490" id="LhL-fH-PVL"/>
</constraints>
<textFieldCell key="cell" title="Placeholder for description texts." id="hvd-Wx-n7n">
<font key="font" metaFont="smallSystem"/>
@ -39,19 +40,30 @@
</textFieldCell>
</textField>
<scrollView autohidesScrollers="YES" horizontalLineScroll="24" horizontalPageScroll="10" verticalLineScroll="24" verticalPageScroll="10" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="MUP-Im-g6c">
<rect key="frame" x="20" y="76" width="624" height="232"/>
<rect key="frame" x="20" y="76" width="730" height="232"/>
<clipView key="contentView" drawsBackground="NO" id="wKQ-IV-k62">
<rect key="frame" x="1" y="1" width="622" height="230"/>
<autoresizingMask key="autoresizingMask"/>
<rect key="frame" x="1" y="1" width="728" height="230"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" tableStyle="inset" multipleSelection="NO" autosaveColumns="NO" rowHeight="24" id="vIw-vc-WKJ" userLabel="tblClients">
<rect key="frame" x="0.0" y="0.0" width="622" height="230"/>
<rect key="frame" x="0.0" y="0.0" width="728" height="230"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<size key="intercellSpacing" width="17" height="0.0"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
<color key="gridColor" name="separatorColor" catalog="System" colorSpace="catalog"/>
<tableColumns>
<tableColumn identifier="AutomaticTableColumnIdentifier.0" width="590" minWidth="40" maxWidth="1000" id="kWw-Lj-EFx">
<tableColumn identifier="colPCBEnabled" width="20" minWidth="20" maxWidth="20" id="6D6-O8-Zrc">
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border">
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
</tableHeaderCell>
<buttonCell key="dataCell" type="check" bezelStyle="regularSquare" imagePosition="left" controlSize="large" inset="2" id="5Bp-jJ-Sf1">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
</tableColumn>
<tableColumn identifier="colClient" width="546" minWidth="40" maxWidth="1000" id="kWw-Lj-EFx">
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border">
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
@ -69,7 +81,7 @@
<nil key="backgroundColor"/>
</clipView>
<scroller key="horizontalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="YES" id="6Wq-mB-m8K">
<rect key="frame" x="2" y="214" width="620" height="16"/>
<rect key="frame" x="1" y="215" width="622" height="16"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
<scroller key="verticalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="NO" id="rYb-HR-4th">
@ -78,10 +90,13 @@
</scroller>
</scrollView>
<customView translatesAutoresizingMaskIntoConstraints="NO" id="qCN-8Z-3x3">
<rect key="frame" x="518" y="20" width="126" height="46"/>
<rect key="frame" x="624" y="20" width="126" height="46"/>
<subviews>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="JcI-Ff-tDM" userLabel="btnAddClient">
<rect key="frame" x="-7" y="19" width="140" height="32"/>
<constraints>
<constraint firstAttribute="width" constant="126" id="YS5-dM-Awj"/>
</constraints>
<buttonCell key="cell" type="push" title="Add" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="7rO-JZ-kgV">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
@ -92,6 +107,9 @@
</button>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="UNR-wG-8n1" userLabel="btnRemoveClient">
<rect key="frame" x="-7" y="-7" width="140" height="32"/>
<constraints>
<constraint firstAttribute="width" constant="126" id="t4F-yV-r4E"/>
</constraints>
<buttonCell key="cell" type="push" title="Remove" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="wNc-xy-U4i">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
@ -127,7 +145,7 @@
<connections>
<outlet property="delegate" destination="-2" id="0bl-1N-AYu"/>
</connections>
<point key="canvasLocation" x="231" y="176.5"/>
<point key="canvasLocation" x="284" y="176.5"/>
</window>
</objects>
</document>