Atoll/DynamicIsland/managers/SystemChangesObserver.swift
Hariharan Mudaliar 278b1aeaad Fix:Frequent Calls
2025-09-06 22:13:57 +05:30

193 lines
6.1 KiB
Swift

//
// SystemChangesObserver.swift
// DynamicIsland
//
// Adapted from TheBoringWorker-HUD ChangesObserver.swift
// Created by GitHub Copilot on 06/09/25.
//
import Cocoa
import Foundation
import Defaults
class SystemChangesObserver {
private var oldVolume: Float = 0
private var oldMuted: Bool = false
private var oldBrightness: Float = 0
private weak var coordinator: DynamicIslandViewCoordinator?
// Backup timer for edge cases only
private var backupTimer: Timer?
init(coordinator: DynamicIslandViewCoordinator) {
self.coordinator = coordinator
// Initialize baseline values only once
oldVolume = SystemVolumeManager.getOutputVolume()
oldMuted = SystemVolumeManager.isMuted()
do {
oldBrightness = try SystemDisplayManager.getDisplayBrightness()
} catch {
NSLog("Failed to retrieve initial display brightness: \(error)")
}
}
func startObserving() {
guard Defaults[.enableSystemHUD] else { return }
startMinimalBackupTimer()
}
private func startMinimalBackupTimer() {
// More frequent backup check (every 300ms) for better responsiveness
// This is a reasonable compromise between the original 200ms and the previous 5s
backupTimer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { [weak self] _ in
guard Defaults[.enableSystemHUD] else { return }
self?.performBackupCheck()
}
}
private func performBackupCheck() {
// Only check if we haven't had recent activity
checkVolumeChanges()
checkBrightnessChanges()
}
// MARK: - Public Media Key Event Handlers (called from MediaKeyApplication)
func handleVolumeKeyEvent() {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.05) {
self.handleVolumeKeyPress()
}
}
func handleBrightnessKeyEvent() {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.05) {
self.handleBrightnessKeyPress()
}
}
// MARK: - Key Press Event Handlers
private func handleVolumeKeyPress() {
guard Defaults[.enableVolumeHUD] else { return }
let newVolume = SystemVolumeManager.getOutputVolume()
let newMuted = SystemVolumeManager.isMuted()
// Always show HUD for key press feedback, even if value doesn't change
print("🔊 Volume key pressed - showing HUD: volume=\(newVolume), muted=\(newMuted)")
if newMuted {
sendVolumeNotification(value: 0.0)
} else {
sendVolumeNotification(value: newVolume)
}
// Update stored values
oldVolume = newVolume
oldMuted = newMuted
}
private func handleBrightnessKeyPress() {
guard Defaults[.enableBrightnessHUD] else { return }
guard NSScreen.screens.count > 0 else { return }
do {
let newBrightness = try SystemDisplayManager.getDisplayBrightness()
// Always show HUD for key press feedback, even if value doesn't change
print("☀️ Brightness key pressed - showing HUD: brightness=\(newBrightness)")
sendBrightnessNotification(value: newBrightness)
// Update stored value
oldBrightness = newBrightness
} catch {
// Silently ignore brightness errors to reduce log spam
}
}
private func checkVolumeChanges() {
guard Defaults[.enableVolumeHUD] else { return }
let newVolume = SystemVolumeManager.getOutputVolume()
let newMuted = SystemVolumeManager.isMuted()
let volumeChanged = !isAlmost(firstNumber: oldVolume, secondNumber: newVolume)
let muteChanged = newMuted != oldMuted
if volumeChanged || muteChanged {
print("🔊 Volume change detected: \(oldVolume) → \(newVolume), muted: \(oldMuted) → \(newMuted)")
if newMuted {
sendVolumeNotification(value: 0.0)
} else {
sendVolumeNotification(value: newVolume)
}
oldVolume = newVolume
oldMuted = newMuted
}
}
private func checkBrightnessChanges() {
guard Defaults[.enableBrightnessHUD] else { return }
guard NSScreen.screens.count > 0 else { return }
do {
let newBrightness = try SystemDisplayManager.getDisplayBrightness()
let brightnessChanged = !isAlmost(firstNumber: oldBrightness, secondNumber: newBrightness)
if brightnessChanged {
print("☀️ Brightness change detected: \(oldBrightness) → \(newBrightness)")
sendBrightnessNotification(value: newBrightness)
oldBrightness = newBrightness
}
} catch {
// Silently ignore brightness errors to reduce log spam
}
}
private func isAlmost(firstNumber: Float, secondNumber: Float) -> Bool {
// Convert sensitivity setting to a more responsive threshold
// Sensitivity 1-10 scale maps to 0.01-0.10 threshold range
let marginValue = Float(Defaults[.systemHUDSensitivity]) / 100.0
let threshold = max(0.01, marginValue) // Minimum threshold for responsiveness
return abs(firstNumber - secondNumber) <= threshold
}
// MARK: - Internal Notification Methods
private func sendVolumeNotification(value: Float) {
coordinator?.toggleSneakPeek(
status: true,
type: .volume,
value: CGFloat(value),
icon: ""
)
}
private func sendBrightnessNotification(value: Float) {
coordinator?.toggleSneakPeek(
status: true,
type: .brightness,
value: CGFloat(value),
icon: ""
)
}
deinit {
stopObserving()
}
func stopObserving() {
// Clean up backup timer
backupTimer?.invalidate()
backupTimer = nil
print("🎹 Media key detection stopped")
}
}