mirror of
https://github.com/FBukovina/Atoll.git
synced 2026-10-27 15:14:33 +00:00
Add Lock/Unlock sounds
This commit is contained in:
parent
3bba53c583
commit
149a022765
5 changed files with 68 additions and 0 deletions
|
|
@ -356,6 +356,7 @@ struct GeneralSettings: View {
|
|||
|
||||
Section {
|
||||
Defaults.Toggle("Enable Lock Screen Live Activity", key: .enableLockScreenLiveActivity)
|
||||
Defaults.Toggle("Play lock/unlock sounds", key: .enableLockSounds)
|
||||
if #available(macOS 26.0, *) {
|
||||
Picker("Lock screen material", selection: $lockScreenGlassStyle) {
|
||||
ForEach(LockScreenGlassStyle.allCases) { style in
|
||||
|
|
|
|||
BIN
DynamicIsland/lock.mp3
Normal file
BIN
DynamicIsland/lock.mp3
Normal file
Binary file not shown.
|
|
@ -11,6 +11,7 @@ import Combine
|
|||
import AppKit
|
||||
import Defaults
|
||||
import SwiftUI
|
||||
import AVFoundation
|
||||
|
||||
enum LockScreenAnimationTimings {
|
||||
static let lockExpand: TimeInterval = 0.45
|
||||
|
|
@ -80,6 +81,7 @@ class LockScreenManager: ObservableObject {
|
|||
|
||||
@objc private func screenLocked() {
|
||||
print("[\(timestamp())] LockScreenManager: 🔒 Screen LOCKED event received")
|
||||
LockSoundPlayer.shared.playLockChime()
|
||||
|
||||
// Update state SYNCHRONOUSLY without Task/await to avoid any delay
|
||||
lastUpdated = Date()
|
||||
|
|
@ -120,6 +122,7 @@ class LockScreenManager: ObservableObject {
|
|||
|
||||
@objc private func screenUnlocked() {
|
||||
print("[\(timestamp())] LockScreenManager: 🔓 Screen UNLOCKED event received")
|
||||
LockSoundPlayer.shared.playUnlockChime()
|
||||
|
||||
// Hide panel window immediately and synchronously
|
||||
print("[\(timestamp())] LockScreenManager: 🚪 Hiding panel window")
|
||||
|
|
@ -190,3 +193,66 @@ extension LockScreenManager {
|
|||
return true // Always available on macOS
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Lock Sound Playback
|
||||
|
||||
@MainActor
|
||||
final class LockSoundPlayer {
|
||||
static let shared = LockSoundPlayer()
|
||||
private let throttleInterval: TimeInterval = 0.25
|
||||
private var players: [SoundType: AVAudioPlayer] = [:]
|
||||
private var lastPlaybackDates: [SoundType: Date] = [:]
|
||||
|
||||
private init() {}
|
||||
|
||||
func playLockChime() {
|
||||
play(.lock)
|
||||
}
|
||||
|
||||
func playUnlockChime() {
|
||||
play(.unlock)
|
||||
}
|
||||
|
||||
private func play(_ type: SoundType) {
|
||||
guard Defaults[.enableLockSounds] else { return }
|
||||
guard shouldPlay(type) else { return }
|
||||
guard let player = resolvePlayer(for: type) else { return }
|
||||
|
||||
player.currentTime = 0
|
||||
player.play()
|
||||
lastPlaybackDates[type] = Date()
|
||||
}
|
||||
|
||||
private func shouldPlay(_ type: SoundType) -> Bool {
|
||||
guard let last = lastPlaybackDates[type] else { return true }
|
||||
return Date().timeIntervalSince(last) >= throttleInterval
|
||||
}
|
||||
|
||||
private func resolvePlayer(for type: SoundType) -> AVAudioPlayer? {
|
||||
if let cached = players[type] {
|
||||
return cached
|
||||
}
|
||||
|
||||
guard let url = Bundle.main.url(forResource: type.resourceName, withExtension: "mp3") else {
|
||||
Logger.log("Missing \(type.resourceName).mp3 in bundle", category: .warning)
|
||||
return nil
|
||||
}
|
||||
|
||||
do {
|
||||
let player = try AVAudioPlayer(contentsOf: url)
|
||||
player.prepareToPlay()
|
||||
players[type] = player
|
||||
return player
|
||||
} catch {
|
||||
Logger.log("Failed to initialize lock sound player for \(type.resourceName): \(error.localizedDescription)", category: .error)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
private enum SoundType: String {
|
||||
case lock
|
||||
case unlock
|
||||
|
||||
var resourceName: String { rawValue }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -601,6 +601,7 @@ extension Defaults.Keys {
|
|||
|
||||
// MARK: Lock Screen Features
|
||||
static let enableLockScreenLiveActivity = Key<Bool>("enableLockScreenLiveActivity", default: true)
|
||||
static let enableLockSounds = Key<Bool>("enableLockSounds", default: true)
|
||||
|
||||
// MARK: ImageService
|
||||
static let didClearLegacyURLCacheV1 = Key<Bool>("didClearLegacyURLCacheV1", default: false)
|
||||
|
|
|
|||
BIN
DynamicIsland/unlock.mp3
Normal file
BIN
DynamicIsland/unlock.mp3
Normal file
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue