mirror of
https://github.com/FBukovina/Atoll.git
synced 2026-10-27 15:14:33 +00:00
Merge pull request #260 from Ebullioscopic/ui/fixes
Update Feedback for Volume Change
This commit is contained in:
commit
63c95386a5
5 changed files with 76 additions and 0 deletions
|
|
@ -3382,6 +3382,10 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"Audio feedback" : {
|
||||
"comment" : "A section header that lists audio feedback settings.",
|
||||
"isCommentAutoGenerated" : true
|
||||
},
|
||||
"Authorize" : {
|
||||
"comment" : "A button that authorizes an app extension.",
|
||||
"isCommentAutoGenerated" : true
|
||||
|
|
@ -15194,6 +15198,10 @@
|
|||
},
|
||||
"Pinned Items" : {
|
||||
|
||||
},
|
||||
"Plays the supplied feedback clip whenever you press the hardware volume keys." : {
|
||||
"comment" : "A help text describing the audio feedback feature.",
|
||||
"isCommentAutoGenerated" : true
|
||||
},
|
||||
"Please configure your API key for the selected AI provider in model settings." : {
|
||||
|
||||
|
|
@ -16032,6 +16040,9 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Requires Accessibility permission so Dynamic Island can intercept the hardware volume keys." : {
|
||||
|
||||
},
|
||||
"Reset" : {
|
||||
"localizations" : {
|
||||
|
|
|
|||
BIN
DynamicIsland/audio-feedback.m4a
Normal file
BIN
DynamicIsland/audio-feedback.m4a
Normal file
Binary file not shown.
|
|
@ -1859,6 +1859,18 @@ struct HUD: View {
|
|||
}
|
||||
}
|
||||
|
||||
Section {
|
||||
Defaults.Toggle("Play feedback when volume is changed", key: .playVolumeChangeFeedback)
|
||||
.settingsHighlight(id: highlightID("Play feedback when volume is changed"))
|
||||
.help("Plays the supplied feedback clip whenever you press the hardware volume keys.")
|
||||
} header: {
|
||||
Text("Audio feedback")
|
||||
} footer: {
|
||||
Text("Requires Accessibility permission so Dynamic Island can intercept the hardware volume keys.")
|
||||
.foregroundStyle(.secondary)
|
||||
.font(.caption)
|
||||
}
|
||||
|
||||
Section {
|
||||
Defaults.Toggle("Color-coded volume display", key: .useColorCodedVolumeDisplay)
|
||||
.disabled(colorCodingDisabled)
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import Foundation
|
|||
import CoreGraphics
|
||||
import Defaults
|
||||
import AppKit
|
||||
import AVFoundation
|
||||
|
||||
final class SystemChangesObserver: MediaKeyInterceptorDelegate {
|
||||
private weak var coordinator: DynamicIslandViewCoordinator?
|
||||
|
|
@ -9,6 +10,7 @@ final class SystemChangesObserver: MediaKeyInterceptorDelegate {
|
|||
private let brightnessController = SystemBrightnessController.shared
|
||||
private let keyboardBacklightController = SystemKeyboardBacklightController.shared
|
||||
private let mediaKeyInterceptor = MediaKeyInterceptor.shared
|
||||
private let volumeFeedbackPlayer = VolumeFeedbackPlayer.shared
|
||||
|
||||
private static let headsetIconSymbols: Set<String> = [
|
||||
"airpods",
|
||||
|
|
@ -140,6 +142,7 @@ final class SystemChangesObserver: MediaKeyInterceptorDelegate {
|
|||
let baseStep = stepSize(for: step, base: standardVolumeStep)
|
||||
let delta = direction == .up ? baseStep : -baseStep
|
||||
volumeController.adjust(by: delta)
|
||||
volumeFeedbackPlayer.playIfNeeded()
|
||||
}
|
||||
|
||||
func mediaKeyInterceptorDidToggleMute(_ interceptor: MediaKeyInterceptor) {
|
||||
|
|
@ -325,4 +328,53 @@ private extension SystemChangesObserver {
|
|||
}
|
||||
}
|
||||
|
||||
private final class VolumeFeedbackPlayer {
|
||||
static let shared = VolumeFeedbackPlayer()
|
||||
|
||||
private let queue = DispatchQueue(label: "com.dynamicisland.volume-feedback-player")
|
||||
private var player: AVAudioPlayer?
|
||||
private var lastPlayDate: Date = .distantPast
|
||||
private let minimumInterval: TimeInterval = 0.08
|
||||
private var didLogMissingAsset = false
|
||||
|
||||
private init() {}
|
||||
|
||||
func playIfNeeded() {
|
||||
guard Defaults[.playVolumeChangeFeedback] else { return }
|
||||
queue.async { [weak self] in
|
||||
guard let self else { return }
|
||||
let now = Date()
|
||||
guard now.timeIntervalSince(self.lastPlayDate) >= self.minimumInterval else { return }
|
||||
self.lastPlayDate = now
|
||||
self.preparePlayerIfNeeded()
|
||||
guard let player = self.player else { return }
|
||||
player.currentTime = 0
|
||||
player.play()
|
||||
}
|
||||
}
|
||||
|
||||
private func preparePlayerIfNeeded() {
|
||||
if player != nil { return }
|
||||
guard let url = Bundle.main.url(forResource: "audio-feedback", withExtension: "m4a") else {
|
||||
if !didLogMissingAsset {
|
||||
NSLog("⚠️ audio-feedback.m4a is missing from the app bundle; volume feedback disabled.")
|
||||
didLogMissingAsset = true
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
do {
|
||||
let audioPlayer = try AVAudioPlayer(contentsOf: url)
|
||||
audioPlayer.volume = 1
|
||||
audioPlayer.prepareToPlay()
|
||||
player = audioPlayer
|
||||
} catch {
|
||||
if !didLogMissingAsset {
|
||||
NSLog("⚠️ Failed to initialize volume feedback player: \(error.localizedDescription)")
|
||||
didLogMissingAsset = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -871,6 +871,7 @@ extension Defaults.Keys {
|
|||
static let enableBrightnessHUD = Key<Bool>("enableBrightnessHUD", default: true)
|
||||
static let enableKeyboardBacklightHUD = Key<Bool>("enableKeyboardBacklightHUD", default: true)
|
||||
static let systemHUDSensitivity = Key<Int>("systemHUDSensitivity", default: 5)
|
||||
static let playVolumeChangeFeedback = Key<Bool>("playVolumeChangeFeedback", default: false)
|
||||
|
||||
// MARK: Custom OSD Window Feature
|
||||
static let enableCustomOSD = Key<Bool>("enableCustomOSD", default: false)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue