Merge pull request #236 from zonble/master
Adds a validator for candidate keys in the preference window.
This commit is contained in:
commit
f2d3ca3c78
|
@ -146,36 +146,6 @@ struct ComposingBufferSize {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@propertyWrapper
|
|
||||||
struct ComposingKeys {
|
|
||||||
let key: String
|
|
||||||
let defaultValue: String? = kCandidateKeys
|
|
||||||
lazy var container: UserDefault = {
|
|
||||||
UserDefault(key: key, defaultValue: defaultValue) }()
|
|
||||||
|
|
||||||
var wrappedValue: String? {
|
|
||||||
mutating get {
|
|
||||||
let value = container.wrappedValue
|
|
||||||
if let value = value {
|
|
||||||
if value.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
set {
|
|
||||||
let value = newValue
|
|
||||||
if let value = value {
|
|
||||||
if value.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
|
|
||||||
container.wrappedValue = nil
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
container.wrappedValue = value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: -
|
// MARK: -
|
||||||
|
|
||||||
@objc enum KeyboardLayout: Int {
|
@objc enum KeyboardLayout: Int {
|
||||||
|
@ -293,12 +263,65 @@ class Preferences: NSObject {
|
||||||
@UserDefault(key: kCandidateKeyLabelFontName, defaultValue: nil)
|
@UserDefault(key: kCandidateKeyLabelFontName, defaultValue: nil)
|
||||||
@objc static var candidateKeyLabelFontName: String?
|
@objc static var candidateKeyLabelFontName: String?
|
||||||
|
|
||||||
@ComposingKeys(key: kCandidateKeys)
|
@UserDefault(key: kCandidateKeys, defaultValue: kDefaultKeys)
|
||||||
@objc static var candidateKeys: String?
|
@objc static var candidateKeys: String
|
||||||
|
|
||||||
@objc static var defaultKeys: String {
|
@objc static var defaultCandidateKeys: String {
|
||||||
kDefaultKeys
|
kDefaultKeys
|
||||||
}
|
}
|
||||||
|
@objc static var suggestedCandidateKeys: [String] {
|
||||||
|
[kDefaultKeys, "asdfghjkl", "asdfzxcvb"]
|
||||||
|
}
|
||||||
|
|
||||||
|
static func validate(candidateKeys: String) throws {
|
||||||
|
let trimmed = candidateKeys.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||||
|
if trimmed.isEmpty {
|
||||||
|
throw CandidateKeyError.empty
|
||||||
|
}
|
||||||
|
if !trimmed.canBeConverted(to: .ascii) {
|
||||||
|
throw CandidateKeyError.invalidCharacters
|
||||||
|
}
|
||||||
|
if trimmed.contains(" ") {
|
||||||
|
throw CandidateKeyError.containSpace
|
||||||
|
}
|
||||||
|
if trimmed.count < 4 {
|
||||||
|
throw CandidateKeyError.tooShort
|
||||||
|
}
|
||||||
|
if trimmed.count > 15 {
|
||||||
|
throw CandidateKeyError.tooLong
|
||||||
|
}
|
||||||
|
let set = Set(Array(trimmed))
|
||||||
|
if set.count != trimmed.count {
|
||||||
|
throw CandidateKeyError.duplicatedCharacters
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum CandidateKeyError: Error, LocalizedError {
|
||||||
|
case empty
|
||||||
|
case invalidCharacters
|
||||||
|
case containSpace
|
||||||
|
case duplicatedCharacters
|
||||||
|
case tooShort
|
||||||
|
case tooLong
|
||||||
|
|
||||||
|
var errorDescription: String? {
|
||||||
|
switch self {
|
||||||
|
case .empty:
|
||||||
|
return NSLocalizedString("Candidates keys cannot be empty.", comment: "")
|
||||||
|
case .invalidCharacters:
|
||||||
|
return NSLocalizedString("Candidate keys can only contain latin characters and numbers.", comment: "")
|
||||||
|
case .containSpace:
|
||||||
|
return NSLocalizedString("Candidate keys cannot contain space.", comment: "")
|
||||||
|
case .duplicatedCharacters:
|
||||||
|
return NSLocalizedString("There should not be duplicated keys.", comment: "")
|
||||||
|
case .tooShort:
|
||||||
|
return NSLocalizedString("The length of your candidate keys can not be less than 4 characters.", comment: "")
|
||||||
|
case .tooLong:
|
||||||
|
return NSLocalizedString("The length of your candidate keys can not be larger than 15 characters.", comment: "")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@UserDefault(key: kPhraseReplacementEnabledKey, defaultValue: false)
|
@UserDefault(key: kPhraseReplacementEnabledKey, defaultValue: false)
|
||||||
@objc static var phraseReplacementEnabled: Bool
|
@objc static var phraseReplacementEnabled: Bool
|
||||||
|
|
|
@ -126,11 +126,11 @@ import Carbon
|
||||||
basisKeyboardLayoutButton.select(chosenItem ?? usKeyboardLayoutItem)
|
basisKeyboardLayoutButton.select(chosenItem ?? usKeyboardLayoutItem)
|
||||||
selectionKeyComboBox.usesDataSource = false
|
selectionKeyComboBox.usesDataSource = false
|
||||||
selectionKeyComboBox.removeAllItems()
|
selectionKeyComboBox.removeAllItems()
|
||||||
selectionKeyComboBox.addItems(withObjectValues: [Preferences.defaultKeys, "asdfghjkl", "asdfzxcvb"])
|
selectionKeyComboBox.addItems(withObjectValues: Preferences.suggestedCandidateKeys)
|
||||||
|
|
||||||
var candidateSelectionKeys = Preferences.candidateKeys ?? Preferences.defaultKeys
|
var candidateSelectionKeys = Preferences.candidateKeys
|
||||||
if candidateSelectionKeys.isEmpty {
|
if candidateSelectionKeys.isEmpty {
|
||||||
candidateSelectionKeys = Preferences.defaultKeys
|
candidateSelectionKeys = Preferences.defaultCandidateKeys
|
||||||
}
|
}
|
||||||
|
|
||||||
selectionKeyComboBox.stringValue = candidateSelectionKeys
|
selectionKeyComboBox.stringValue = candidateSelectionKeys
|
||||||
|
@ -143,17 +143,25 @@ import Carbon
|
||||||
}
|
}
|
||||||
|
|
||||||
@IBAction func changeSelectionKeyAction(_ sender: Any) {
|
@IBAction func changeSelectionKeyAction(_ sender: Any) {
|
||||||
let keys = (sender as AnyObject).stringValue.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
|
guard let keys = (sender as AnyObject).stringValue?.trimmingCharacters(in: .whitespacesAndNewlines) else {
|
||||||
if keys.count != 9 || !keys.canBeConverted(to: .ascii) {
|
|
||||||
selectionKeyComboBox.stringValue = Preferences.defaultKeys
|
|
||||||
Preferences.candidateKeys = nil
|
|
||||||
NSSound.beep()
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
do {
|
||||||
selectionKeyComboBox.stringValue = keys
|
try Preferences.validate(candidateKeys: keys)
|
||||||
Preferences.candidateKeys = keys
|
Preferences.candidateKeys = keys
|
||||||
}
|
}
|
||||||
|
catch Preferences.CandidateKeyError.empty {
|
||||||
|
selectionKeyComboBox.stringValue = Preferences.candidateKeys
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
if let window = window {
|
||||||
|
let alert = NSAlert(error: error)
|
||||||
|
alert.beginSheetModal(for: window) { response in
|
||||||
|
self.selectionKeyComboBox.stringValue = Preferences.candidateKeys
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -76,3 +76,16 @@
|
||||||
"Edit Phrase Replacement Table" = "Edit Phrase Replacement Table";
|
"Edit Phrase Replacement Table" = "Edit Phrase Replacement Table";
|
||||||
|
|
||||||
"Use Phrase Replacement" = "Use Phrase Replacement";
|
"Use Phrase Replacement" = "Use Phrase Replacement";
|
||||||
|
|
||||||
|
"Candidates keys cannot be empty." = "Candidates keys cannot be empty.";
|
||||||
|
|
||||||
|
"Candidate keys can only contain latin characters and numbers." = "Candidate keys can only contain latin characters and numbers.";
|
||||||
|
|
||||||
|
"Candidate keys cannot contain space." = "Candidate keys cannot contain space.";
|
||||||
|
|
||||||
|
"There should not be duplicated keys." = "There should not be duplicated keys.";
|
||||||
|
|
||||||
|
"The length of your candidate keys can not be less than 4 characters." = "The length of your candidate keys can not be less than 4 characters.";
|
||||||
|
|
||||||
|
"The length of your candidate keys can not be larger than 15 characters." = "The length of your candidate keys can not be larger than 15 characters.";
|
||||||
|
|
||||||
|
|
|
@ -76,3 +76,15 @@
|
||||||
"Edit Phrase Replacement Table" = "編輯詞彙替換表格";
|
"Edit Phrase Replacement Table" = "編輯詞彙替換表格";
|
||||||
|
|
||||||
"Use Phrase Replacement" = "使用詞彙替換";
|
"Use Phrase Replacement" = "使用詞彙替換";
|
||||||
|
|
||||||
|
"Candidates keys cannot be empty." = "選字鍵不可為空。";
|
||||||
|
|
||||||
|
"Candidate keys can only contain latin characters and numbers." = "選字鍵只可包含英數與半型標點。";
|
||||||
|
|
||||||
|
"Candidate keys cannot contain space." = "選字鍵不可包含空白。";
|
||||||
|
|
||||||
|
"There should not be duplicated keys." = "選字鍵中不可包含重複的字元。";
|
||||||
|
|
||||||
|
"The length of your candidate keys can not be less than 4 characters." = "選字按鍵數量不可小於 4。";
|
||||||
|
|
||||||
|
"The length of your candidate keys can not be larger than 15 characters." = "選字按鍵數量不可大於 15。";
|
||||||
|
|
Loading…
Reference in New Issue