diff options
| author | Christian Cleberg <[email protected]> | 2026-07-25 16:34:16 -0500 |
|---|---|---|
| committer | Christian Cleberg <[email protected]> | 2026-07-25 16:34:16 -0500 |
| commit | 1839c49700b079dbc7026cfadbe40a8336d38f93 (patch) | |
| tree | 0218543be57eabd4f6bcf41d1a0bc6f7eb38e2dc /DayByDay | |
| parent | 8f0f2b4b4f4b747b5d5fcc5a433f2f4b5109c940 (diff) | |
| download | daybyday-1839c49700b079dbc7026cfadbe40a8336d38f93.tar.gz daybyday-1839c49700b079dbc7026cfadbe40a8336d38f93.tar.bz2 daybyday-1839c49700b079dbc7026cfadbe40a8336d38f93.zip | |
feat: add haptic feedback on card tap
Fire a rigid impact haptic in SpeechSynthesizer.speak(), which every
card tap routes through, giving consistent tactile feedback across all
categories.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Diffstat (limited to 'DayByDay')
| -rw-r--r-- | DayByDay/SpeechSynthesizer.swift | 7 |
1 files changed, 7 insertions, 0 deletions
diff --git a/DayByDay/SpeechSynthesizer.swift b/DayByDay/SpeechSynthesizer.swift index ab6421b..fa0316c 100644 --- a/DayByDay/SpeechSynthesizer.swift +++ b/DayByDay/SpeechSynthesizer.swift @@ -4,6 +4,7 @@ // import AVFoundation +import UIKit /// Wrapper around AVSpeechSynthesizer that selects the highest-quality /// en-US neural voice available on the device. Falls back gracefully if @@ -13,6 +14,7 @@ final class SpeechSynthesizer { private let synthesizer = AVSpeechSynthesizer() private let voice: AVSpeechSynthesisVoice? + private let haptics = UIImpactFeedbackGenerator(style: .rigid) private init() { self.voice = Self.bestAvailableVoice() @@ -24,6 +26,11 @@ final class SpeechSynthesizer { } func speak(_ text: String) { + // Every speak() call is a card tap, so give a gentle tactile bump + // alongside the audio. Prepared just before firing for lowest latency. + haptics.prepare() + haptics.impactOccurred() + // Ensure speech plays through the speaker even when the silent switch is on. try? AVAudioSession.sharedInstance().setCategory(.playback, mode: .default) try? AVAudioSession.sharedInstance().setActive(true) |
