Files
clawdbot/apps/macos/Sources/Clawdis/VoiceWakeChime.swift
2025-12-08 22:04:02 +01:00

78 lines
1.9 KiB
Swift

import AppKit
import Foundation
enum VoiceWakeChime: Codable, Equatable, Sendable {
case none
case system(name: String)
case custom(displayName: String, bookmark: Data)
var systemName: String? {
if case let .system(name) = self {
return name
}
return nil
}
var displayLabel: String {
switch self {
case .none:
return "No Sound"
case let .system(name):
return VoiceWakeChimeCatalog.displayName(for: name)
case let .custom(displayName, _):
return displayName
}
}
}
struct VoiceWakeChimeCatalog {
/// Options shown in the picker.
static let systemOptions: [String] = [
"Glass", // default
"Ping",
"Pop",
"Frog",
"Submarine",
"Funk",
"Tink",
]
static func displayName(for raw: String) -> String {
return raw
}
}
@MainActor
enum VoiceWakeChimePlayer {
private static var lastSound: NSSound?
@MainActor
static func play(_ chime: VoiceWakeChime) {
guard let sound = self.sound(for: chime) else { return }
self.lastSound = sound
sound.stop()
sound.play()
}
private static func sound(for chime: VoiceWakeChime) -> NSSound? {
switch chime {
case .none:
return nil
case let .system(name):
return NSSound(named: NSSound.Name(name))
case let .custom(_, bookmark):
var stale = false
guard let url = try? URL(
resolvingBookmarkData: bookmark,
options: [.withoutUI, .withSecurityScope],
bookmarkDataIsStale: &stale)
else { return nil }
let scoped = url.startAccessingSecurityScopedResource()
defer { if scoped { url.stopAccessingSecurityScopedResource() } }
return NSSound(contentsOf: url, byReference: false)
}
}
}