From e6d9043c374304c3b2af4efa5cded13c0d952633 Mon Sep 17 00:00:00 2001 From: Hariharan Mudaliar Date: Mon, 8 Dec 2025 15:50:51 +0530 Subject: [PATCH] Working Low Battery Indicator --- .../components/Settings/SettingsView.swift | 3 +++ .../models/BatteryStatusViewModel.swift | 23 +++++++++++++++++++ DynamicIsland/models/Constants.swift | 1 + 3 files changed, 27 insertions(+) diff --git a/DynamicIsland/components/Settings/SettingsView.swift b/DynamicIsland/components/Settings/SettingsView.swift index 7dc8724..8d2a3b0 100644 --- a/DynamicIsland/components/Settings/SettingsView.swift +++ b/DynamicIsland/components/Settings/SettingsView.swift @@ -586,6 +586,7 @@ struct SettingsView: View { SettingsSearchEntry(tab: .battery, title: "Show battery percentage", keywords: ["battery percent"], highlightID: SettingsTab.battery.highlightID(for: "Show battery percentage")), SettingsSearchEntry(tab: .battery, title: "Show power status notifications", keywords: ["notifications", "power"], highlightID: SettingsTab.battery.highlightID(for: "Show power status notifications")), SettingsSearchEntry(tab: .battery, title: "Show power status icons", keywords: ["power icons", "charging icon"], highlightID: SettingsTab.battery.highlightID(for: "Show power status icons")), + SettingsSearchEntry(tab: .battery, title: "Play low battery alert sound", keywords: ["low battery", "alert", "sound"], highlightID: SettingsTab.battery.highlightID(for: "Play low battery alert sound")), // HUDs SettingsSearchEntry(tab: .hud, title: "Show Bluetooth device connections", keywords: ["bluetooth", "hud"], highlightID: SettingsTab.hud.highlightID(for: "Show Bluetooth device connections")), @@ -1050,6 +1051,8 @@ struct Charge: View { .settingsHighlight(id: highlightID("Show battery indicator")) Defaults.Toggle("Show power status notifications", key: .showPowerStatusNotifications) .settingsHighlight(id: highlightID("Show power status notifications")) + Defaults.Toggle("Play low battery alert sound", key: .playLowBatteryAlertSound) + .settingsHighlight(id: highlightID("Play low battery alert sound")) } header: { Text("General") } diff --git a/DynamicIsland/models/BatteryStatusViewModel.swift b/DynamicIsland/models/BatteryStatusViewModel.swift index f8e9872..59cf53d 100644 --- a/DynamicIsland/models/BatteryStatusViewModel.swift +++ b/DynamicIsland/models/BatteryStatusViewModel.swift @@ -11,6 +11,8 @@ class BatteryStatusViewModel: ObservableObject { private var powerSourceChangedCallback: IOPowerSourceCallbackType? private var runLoopSource: Unmanaged? var animations: DynamicIslandAnimations = DynamicIslandAnimations() + private let lowBatteryAlertSoundPlayer = AudioPlayer() + private let lowBatteryAlertThresholds: [Float] = [20, 15, 10, 5] @ObservedObject var coordinator = DynamicIslandViewCoordinator.shared @@ -63,6 +65,8 @@ class BatteryStatusViewModel: ObservableObject { case .batteryLevelChanged(let level): print("🔋 Battery level: \(Int(level))%") + let previousLevel = self.levelBattery + self.handleLowBatteryAlertIfNeeded(previousLevel: previousLevel, newLevel: level) withAnimation { self.levelBattery = level } @@ -128,6 +132,25 @@ class BatteryStatusViewModel: ObservableObject { } } + private func handleLowBatteryAlertIfNeeded(previousLevel: Float, newLevel: Float) { + guard Defaults[.playLowBatteryAlertSound] else { return } + guard !isPluggedIn, !isCharging else { return } + guard newLevel < previousLevel else { return } + + for threshold in lowBatteryAlertThresholds { + if previousLevel >= threshold && newLevel < threshold { + self.statusText = "Low battery" + notifyImportanChangeStatus() + playLowBatteryAlertSound() + break + } + } + } + + private func playLowBatteryAlertSound() { + lowBatteryAlertSoundPlayer.play(fileName: "lowbattery", fileExtension: "mp3") + } + deinit { print("🔌 Cleaning up battery monitoring...") if let managerBatteryId: Int = managerBatteryId { diff --git a/DynamicIsland/models/Constants.swift b/DynamicIsland/models/Constants.swift index 7ff6b6e..8af0b38 100644 --- a/DynamicIsland/models/Constants.swift +++ b/DynamicIsland/models/Constants.swift @@ -482,6 +482,7 @@ extension Defaults.Keys { static let showBatteryIndicator = Key("showBatteryIndicator", default: true) static let showBatteryPercentage = Key("showBatteryPercentage", default: true) static let showPowerStatusIcons = Key("showPowerStatusIcons", default: true) + static let playLowBatteryAlertSound = Key("playLowBatteryAlertSound", default: true) // MARK: Downloads static let enableDownloadListener = Key("enableDownloadListener", default: true)