fix: play notification sound when focused

This commit is contained in:
Lawrence Chen 2026-03-20 00:49:42 -07:00 committed by Lawrence Chen
parent d7db13a140
commit 60b6d8badc

View file

@ -42,6 +42,9 @@ enum NotificationSoundSettings {
)
private static let pendingCustomSoundPreparationLock = NSLock()
private static var pendingCustomSoundPreparationPaths: Set<String> = []
private static let activePlaybackSoundsLock = NSLock()
private static var activePlaybackSounds: [ObjectIdentifier: NSSound] = [:]
private static let activePlaybackSoundDelegate = ActivePlaybackSoundDelegate()
private static let notificationSoundSupportedExtensions: Set<String> = [
"aif",
"aiff",
@ -49,6 +52,12 @@ enum NotificationSoundSettings {
"wav",
]
private final class ActivePlaybackSoundDelegate: NSObject, NSSoundDelegate {
func sound(_ sound: NSSound, didFinishPlaying finishedPlaying: Bool) {
NotificationSoundSettings.releaseActivePlaybackSound(sound)
}
}
private struct CustomSoundSourceMetadata: Codable, Equatable {
let sourcePath: String
let sourceSize: UInt64
@ -260,7 +269,16 @@ enum NotificationSoundSettings {
playSoundFile(at: url)
}
static func playSelectedSound(defaults: UserDefaults = .standard) {
let value = defaults.string(forKey: key) ?? defaultValue
playSound(value: value, defaults: defaults)
}
static func previewSound(value: String, defaults: UserDefaults = .standard) {
playSound(value: value, defaults: defaults)
}
private static func playSound(value: String, defaults: UserDefaults) {
switch value {
case "default":
NSSound.beep()
@ -331,10 +349,26 @@ enum NotificationSoundSettings {
NSLog("Notification custom sound failed to load from path: \(url.path)")
return
}
sound.play()
retainActivePlaybackSound(sound)
sound.delegate = activePlaybackSoundDelegate
if !sound.play() {
releaseActivePlaybackSound(sound)
}
}
}
private static func retainActivePlaybackSound(_ sound: NSSound) {
activePlaybackSoundsLock.lock()
activePlaybackSounds[ObjectIdentifier(sound)] = sound
activePlaybackSoundsLock.unlock()
}
private static func releaseActivePlaybackSound(_ sound: NSSound) {
activePlaybackSoundsLock.lock()
activePlaybackSounds.removeValue(forKey: ObjectIdentifier(sound))
activePlaybackSoundsLock.unlock()
}
private static func cleanupStaleStagedSoundFiles(
in directoryURL: URL,
keeping fileName: String,
@ -694,8 +728,9 @@ final class TerminalNotificationStore: ObservableObject {
store.scheduleUserNotification(notification)
}
private var suppressedNotificationFeedbackHandler: (TerminalNotificationStore, TerminalNotification) -> Void = {
_,
_ in
store,
notification in
store.playSuppressedNotificationFeedback(for: notification)
}
private var indexes = NotificationIndexes()
@ -881,7 +916,9 @@ final class TerminalNotificationStore: ObservableObject {
center.removeDeliveredNotificationsOffMain(withIdentifiers: idsToClear)
center.removePendingNotificationRequestsOffMain(withIdentifiers: idsToClear)
}
if !shouldSuppressExternalDelivery {
if shouldSuppressExternalDelivery {
suppressedNotificationFeedbackHandler(self, notification)
} else {
notificationDeliveryHandler(self, notification)
}
}
@ -1050,6 +1087,11 @@ final class TerminalNotificationStore: ObservableObject {
}
}
private func playSuppressedNotificationFeedback(for notification: TerminalNotification) {
_ = notification
NotificationSoundSettings.playSelectedSound()
}
private func ensureAuthorization(
origin: AuthorizationRequestOrigin,
_ completion: @escaping (Bool) -> Void
@ -1273,7 +1315,9 @@ final class TerminalNotificationStore: ObservableObject {
}
func resetSuppressedNotificationFeedbackHandlerForTesting() {
suppressedNotificationFeedbackHandler = { _, _ in }
suppressedNotificationFeedbackHandler = { store, notification in
store.playSuppressedNotificationFeedback(for: notification)
}
}
func promptToEnableNotificationsForTesting() {