summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Cleberg <[email protected]>2026-07-25 16:34:16 -0500
committerChristian Cleberg <[email protected]>2026-07-25 16:34:16 -0500
commit1839c49700b079dbc7026cfadbe40a8336d38f93 (patch)
tree0218543be57eabd4f6bcf41d1a0bc6f7eb38e2dc
parent8f0f2b4b4f4b747b5d5fcc5a433f2f4b5109c940 (diff)
downloaddaybyday-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]>
-rw-r--r--DayByDay.xcodeproj/project.pbxproj8
-rw-r--r--DayByDay.xcodeproj/project.xcworkspace/xcuserdata/cmc.xcuserdatad/UserInterfaceState.xcuserstatebin0 -> 12344 bytes
-rw-r--r--DayByDay/SpeechSynthesizer.swift7
3 files changed, 11 insertions, 4 deletions
diff --git a/DayByDay.xcodeproj/project.pbxproj b/DayByDay.xcodeproj/project.pbxproj
index a2d2497..f81c41f 100644
--- a/DayByDay.xcodeproj/project.pbxproj
+++ b/DayByDay.xcodeproj/project.pbxproj
@@ -338,7 +338,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 6;
+ CURRENT_PROJECT_VERSION = 7;
DEVELOPMENT_TEAM = ZCNAX3VL9D;
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
@@ -353,7 +353,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
- MARKETING_VERSION = 1.3.2;
+ MARKETING_VERSION = 1.3.3;
PRODUCT_BUNDLE_IDENTIFIER = net.cleberg.DayByDay;
PRODUCT_NAME = "$(TARGET_NAME)";
STRING_CATALOG_GENERATE_SYMBOLS = YES;
@@ -372,7 +372,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 6;
+ CURRENT_PROJECT_VERSION = 7;
DEVELOPMENT_TEAM = ZCNAX3VL9D;
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
@@ -387,7 +387,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
- MARKETING_VERSION = 1.3.2;
+ MARKETING_VERSION = 1.3.3;
PRODUCT_BUNDLE_IDENTIFIER = net.cleberg.DayByDay;
PRODUCT_NAME = "$(TARGET_NAME)";
STRING_CATALOG_GENERATE_SYMBOLS = YES;
diff --git a/DayByDay.xcodeproj/project.xcworkspace/xcuserdata/cmc.xcuserdatad/UserInterfaceState.xcuserstate b/DayByDay.xcodeproj/project.xcworkspace/xcuserdata/cmc.xcuserdatad/UserInterfaceState.xcuserstate
new file mode 100644
index 0000000..e151aff
--- /dev/null
+++ b/DayByDay.xcodeproj/project.xcworkspace/xcuserdata/cmc.xcuserdatad/UserInterfaceState.xcuserstate
Binary files differ
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)