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: -
|
||||
|
||||
@objc enum KeyboardLayout: Int {
|
||||
|
@ -293,12 +263,65 @@ class Preferences: NSObject {
|
|||
@UserDefault(key: kCandidateKeyLabelFontName, defaultValue: nil)
|
||||
@objc static var candidateKeyLabelFontName: String?
|
||||
|
||||
@ComposingKeys(key: kCandidateKeys)
|
||||
@objc static var candidateKeys: String?
|
||||
@UserDefault(key: kCandidateKeys, defaultValue: kDefaultKeys)
|
||||
@objc static var candidateKeys: String
|
||||
|
||||
@objc static var defaultKeys: String {
|
||||
@objc static var defaultCandidateKeys: String {
|
||||
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)
|
||||
@objc static var phraseReplacementEnabled: Bool
|
||||
|
|
|
@ -126,11 +126,11 @@ import Carbon
|
|||
basisKeyboardLayoutButton.select(chosenItem ?? usKeyboardLayoutItem)
|
||||
selectionKeyComboBox.usesDataSource = false
|
||||
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 {
|
||||
candidateSelectionKeys = Preferences.defaultKeys
|
||||
candidateSelectionKeys = Preferences.defaultCandidateKeys
|
||||
}
|
||||
|
||||
selectionKeyComboBox.stringValue = candidateSelectionKeys
|
||||
|
@ -143,16 +143,24 @@ import Carbon
|
|||
}
|
||||
|
||||
@IBAction func changeSelectionKeyAction(_ sender: Any) {
|
||||
let keys = (sender as AnyObject).stringValue.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
|
||||
if keys.count != 9 || !keys.canBeConverted(to: .ascii) {
|
||||
selectionKeyComboBox.stringValue = Preferences.defaultKeys
|
||||
Preferences.candidateKeys = nil
|
||||
NSSound.beep()
|
||||
guard let keys = (sender as AnyObject).stringValue?.trimmingCharacters(in: .whitespacesAndNewlines) else {
|
||||
return
|
||||
}
|
||||
|
||||
selectionKeyComboBox.stringValue = keys
|
||||
Preferences.candidateKeys = keys
|
||||
do {
|
||||
try Preferences.validate(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";
|
||||
|
||||
"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" = "編輯詞彙替換表格";
|
||||
|
||||
"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