Skip to content
1 change: 1 addition & 0 deletions Keyboards/KeyboardsBase/InterfaceVariables.swift
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ enum CommandState {
case alreadyPlural
case invalid
case displayInformation
case colonToEmoji
}

/// States of the keyboard corresponding to which auto actions should be presented.
Expand Down
392 changes: 243 additions & 149 deletions Keyboards/KeyboardsBase/KeyboardViewController.swift

Large diffs are not rendered by default.

43 changes: 43 additions & 0 deletions Keyboards/KeyboardsBase/LanguageDBManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,49 @@ extension LanguageDBManager {
return queryDBRow(query: query, outputCols: outputCols, args: StatementArguments(args))
}

/// Query emojis of word in `emoji_keywords` using pattern matching.
func queryEmojisPatternMatching(of word: String) -> [String] {
var outputValues = [String]()
let query = """
SELECT
emoji_keyword_0, emoji_keyword_1, emoji_keyword_2

FROM
emoji_keywords

WHERE
word LIKE ?

ORDER BY
LENGTH(word) ASC

LIMIT
3
"""
let args = StatementArguments(["\(word.lowercased())%"])
do {
try database?.read { db in
let rows = try Row.fetchAll(db, sql: query, arguments: args)
for row in rows {
for col in ["emoji_keyword_0", "emoji_keyword_1", "emoji_keyword_2"] {
if let val = row[col] as? String, !val.isEmpty {
if !outputValues.contains(val) {
outputValues.append(val)
}
if outputValues.count == 6 { return }
}
}
}
}
} catch {}

while outputValues.count < 6 {
outputValues.append("")
}

return Array(outputValues.prefix(6))
}

/// Query the noun form of word in `nonuns`.
func queryNounForm(of word: String) -> [String] {
let query = """
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,20 @@ var autoAction0Visible = true
var autoAction2Visible = true

/// States of the emoji display corresponding to the number to show.
enum EmojisToShow {
case zero
case one
case two
case three
enum EmojisToShow: Int {
case zero = 0
case one = 1
case two = 2
case three = 3
case four = 4
case five = 5
case six = 6
}

var emojisToShow: EmojisToShow = .zero
var currentEmojiTriggerWord = ""
var emojiAutoActionRepeatPossible = false
var colonSearchString = ""

var firstCompletionIsHighlighted = false
var spaceAutoInsertIsPossible = false
Expand Down
1 change: 1 addition & 0 deletions Scribe/ParentTableCellModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ enum UserInteractiveState {
case autosuggestEmojis
case toggleAccentCharacters
case toggleWordForWordDeletion
case colonToEmoji
case none
}

Expand Down
34 changes: 28 additions & 6 deletions Scribe/SettingsTab/SettingsTableData.swift
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,34 @@ enum SettingsTableData {
sectionState: .none(.autosuggestEmojis),
shortDescription: NSLocalizedString("i18n.app.settings.keyboard.functionality.auto_suggest_emoji_description", value: "Turn on emoji suggestions and completions for more expressive typing.", comment: "")
),
Section(
sectionTitle: NSLocalizedString("i18n.app.word_for_word", value: "Word for word deletion on long press", comment: ""),
hasToggle: true,
sectionState: .none(.toggleWordForWordDeletion),
shortDescription: NSLocalizedString("i18n.app.word_for_word.description", value: "Word for word deletion.", comment: "")
)
Section(
sectionTitle: NSLocalizedString(
"i18n.app.settings.keyboard.functionality.delete_word_by_word",
value: "Word for word deletion on long press",
comment: ""
),
hasToggle: true,
sectionState: .none(.toggleWordForWordDeletion),
shortDescription: NSLocalizedString(
"i18n.app.settings.keyboard.functionality.delete_word_by_word_description",
value: "Delete text word by word when the delete key is pressed and held.",
comment: ""
)
),
Section(
sectionTitle: NSLocalizedString(
"i18n.app.settings.keyboard.functionality.colon_to_emoji",
value: "Colon to emoji entry",
comment: ""
),
hasToggle: true,
sectionState: .none(.colonToEmoji),
shortDescription: NSLocalizedString(
"i18n.app.settings.keyboard.functionality.colon_to_emoji_description",
value: "Type : followed by a keyword to suggest emojis.",
comment: ""
)
)
],
hasDynamicData: nil
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,10 @@ final class InfoChildTableViewCell: UITableViewCell {
let dictionaryKey = languageCode + "WordForWordDeletion"
userDefaults.setValue(toggleSwitch.isOn, forKey: dictionaryKey)

case .colonToEmoji:
let dictionaryKey = languageCode + "ColonToEmoji"
userDefaults.setValue(toggleSwitch.isOn, forKey: dictionaryKey)

case .none: break
}

Expand All @@ -164,39 +168,47 @@ final class InfoChildTableViewCell: UITableViewCell {
if let toggleValue = userDefaults.object(forKey: dictionaryKey) as? Bool {
toggleSwitch.isOn = toggleValue
} else {
toggleSwitch.isOn = false // Default value
toggleSwitch.isOn = false // default value
}

case .toggleAccentCharacters:
let dictionaryKey = languageCode + "AccentCharacters"
if let toggleValue = userDefaults.object(forKey: dictionaryKey) as? Bool {
toggleSwitch.isOn = toggleValue
} else {
toggleSwitch.isOn = false // Default value
toggleSwitch.isOn = false // default value
}

case .doubleSpacePeriods:
let dictionaryKey = languageCode + "DoubleSpacePeriods"
if let toggleValue = userDefaults.object(forKey: dictionaryKey) as? Bool {
toggleSwitch.isOn = toggleValue
} else {
toggleSwitch.isOn = true // Default value
toggleSwitch.isOn = true // default value
}

case .autosuggestEmojis:
let dictionaryKey = languageCode + "EmojiAutosuggest"
if let toggleValue = userDefaults.object(forKey: dictionaryKey) as? Bool {
toggleSwitch.isOn = toggleValue
} else {
toggleSwitch.isOn = true // Default value
toggleSwitch.isOn = true // default value
}

case .toggleWordForWordDeletion:
let dictionaryKey = languageCode + "WordForWordDeletion"
if let toggleValue = userDefaults.object(forKey: dictionaryKey) as? Bool {
toggleSwitch.isOn = toggleValue
} else {
toggleSwitch.isOn = false // Default value
toggleSwitch.isOn = false // default value
}

case .colonToEmoji:
let dictionaryKey = languageCode + "ColonToEmoji"
if let toggleValue = userDefaults.object(forKey: dictionaryKey) as? Bool {
toggleSwitch.isOn = toggleValue
} else {
toggleSwitch.isOn = true // default value
}

case .none: break
Expand Down
33 changes: 33 additions & 0 deletions Tests/Keyboards/KeyboardsBase/EmojiQueryTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// SPDX-License-Identifier: GPL-3.0-or-later

import Foundation
@testable import Scribe
import XCTest

class EmojiQueryTests: XCTestCase {

func testQueryEmojisPatternMatchingWithCommonKeyword() {
// This test assumes the database is populated with some emojis.
// If not, it might return empty, which we also handle.
let keyword = "happ"
let results = LanguageDBManager.shared.queryEmojisPatternMatching(of: keyword)

XCTAssertEqual(results.count, 6, "Should always return 6 elements (including empty strings)")
}

func testQueryEmojisPatternMatchingWithEmptyKeyword() {
let results = LanguageDBManager.shared.queryEmojisPatternMatching(of: "")
XCTAssertEqual(results.count, 6)
}

func testQueryEmojisPatternMatchingWithNonExistentKeyword() {
let results = LanguageDBManager.shared.queryEmojisPatternMatching(of: "nonexistentkeyword12345")
XCTAssertEqual(results.count, 6)
XCTAssertEqual(results[0], "")
XCTAssertEqual(results[1], "")
XCTAssertEqual(results[2], "")
XCTAssertEqual(results[3], "")
XCTAssertEqual(results[4], "")
XCTAssertEqual(results[5], "")
}
}
14 changes: 14 additions & 0 deletions Tests/Keyboards/KeyboardsBase/KeyboardCommandTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// SPDX-License-Identifier: GPL-3.0-or-later

import Foundation
@testable import Scribe
import XCTest

class KeyboardCommandTests: XCTestCase {

func testColonToEmojiIsEnabled() {
let keyboard = KeyboardViewController()
// Default should be true as per the implementation.
XCTAssertTrue(keyboard.colonToEmojiIsEnabled())
}
}