diff --git a/Keyboards/KeyboardsBase/KeyboardViewController.swift b/Keyboards/KeyboardsBase/KeyboardViewController.swift index 61dfee62..89c41058 100644 --- a/Keyboards/KeyboardsBase/KeyboardViewController.swift +++ b/Keyboards/KeyboardsBase/KeyboardViewController.swift @@ -1982,6 +1982,15 @@ class KeyboardViewController: UIInputViewController { } } + func hapticFeedbackIsEnabled() -> Bool { + let langCode = languagesAbbrDict[controllerLanguage] ?? "unknown" + if let userDefaults = UserDefaults(suiteName: "group.be.scri.userDefaultsContainer") { + let dictionaryKey = langCode + "HapticFeedback" + return userDefaults.bool(forKey: dictionaryKey) + } + return false // default off + } + // MARK: Button Actions /// Triggers actions based on the press of a key. @@ -2542,6 +2551,32 @@ class KeyboardViewController: UIInputViewController { } else { sender.backgroundColor = keyPressedColor } + + // Haptic feedback on key press. + // Heavy: destructive/dismiss actions. + // Medium: command, navigation, and action keys. + // Light: all regular character keys. + guard hapticFeedbackIsEnabled() else { return } + let heavyKeys = ["delete", "hideKeyboard"] + let mediumKeys = [ + "shift", "return", "Translate", "Conjugate", "Plural", + "AutoAction0", "AutoAction1", "AutoAction2", + "EmojiKey0", "EmojiKey1", "EmojiKey2", + "GetAnnotationInfo", "ScribeAnnotation", + "shiftFormsDisplayLeft", "shiftFormsDisplayRight", + "ABC", "АБВ", "123", "#+=", ".?123", "selectKeyboard", + SpecialKeys.indent, SpecialKeys.capsLock, + spaceBar, languageTextForSpaceBar + ] + let style: UIImpactFeedbackGenerator.FeedbackStyle + if heavyKeys.contains(originalKey) { + style = .heavy + } else if mediumKeys.contains(originalKey) { + style = .medium + } else { + style = .light + } + UIImpactFeedbackGenerator(style: style).impactOccurred() } /// Shows the conjugation view for verbs. diff --git a/Scribe/ParentTableCellModel.swift b/Scribe/ParentTableCellModel.swift index 1c87cfea..8e494492 100644 --- a/Scribe/ParentTableCellModel.swift +++ b/Scribe/ParentTableCellModel.swift @@ -71,6 +71,7 @@ enum UserInteractiveState { case toggleAccentCharacters case toggleWordForWordDeletion case increaseTextSize + case hapticFeedback case none } diff --git a/Scribe/SettingsTab/SettingsTableData.swift b/Scribe/SettingsTab/SettingsTableData.swift index cfbe92d8..9494e334 100644 --- a/Scribe/SettingsTab/SettingsTableData.swift +++ b/Scribe/SettingsTab/SettingsTableData.swift @@ -153,6 +153,12 @@ enum SettingsTableData { value: "Delete text word by word when the delete key is pressed and held.", comment: "" ) + ), + Section( + sectionTitle: "Haptic feedback", + hasToggle: true, + sectionState: .none(.hapticFeedback), + shortDescription: "Enable haptic feedback on key press." ) ], hasDynamicData: nil diff --git a/Scribe/Views/Cells/InfoChildTableViewCell/InfoChildTableViewCell.swift b/Scribe/Views/Cells/InfoChildTableViewCell/InfoChildTableViewCell.swift index 5af6de00..645fc043 100644 --- a/Scribe/Views/Cells/InfoChildTableViewCell/InfoChildTableViewCell.swift +++ b/Scribe/Views/Cells/InfoChildTableViewCell/InfoChildTableViewCell.swift @@ -158,6 +158,10 @@ final class InfoChildTableViewCell: UITableViewCell { let dictionaryKey = languageCode + "WordForWordDeletion" userDefaults.setValue(toggleSwitch.isOn, forKey: dictionaryKey) + case .hapticFeedback: + let dictionaryKey = languageCode + "HapticFeedback" + userDefaults.setValue(toggleSwitch.isOn, forKey: dictionaryKey) + case .increaseTextSize: userDefaults.setValue(toggleSwitch.isOn, forKey: "increaseTextSize") initializeFontSize() @@ -211,6 +215,14 @@ final class InfoChildTableViewCell: UITableViewCell { toggleSwitch.isOn = false // default off } + case .hapticFeedback: + let dictionaryKey = languageCode + "HapticFeedback" + if let toggleValue = userDefaults.object(forKey: dictionaryKey) as? Bool { + toggleSwitch.isOn = toggleValue + } else { + toggleSwitch.isOn = false // default off + } + case .increaseTextSize: if let toggleValue = userDefaults.object(forKey: "increaseTextSize") as? Bool { toggleSwitch.isOn = toggleValue