Fix: Migrations

This commit is contained in:
Hariharan Mudaliar 2025-08-03 21:26:50 +05:30
commit be152c1531
41 changed files with 2373 additions and 1321 deletions

View file

@ -1,12 +1,12 @@
import Foundation
import Cocoa
import SwiftUI
import IOKit.ps
import Defaults
import Foundation
import IOKit.ps
import SwiftUI
/// A view model that manages and monitors the battery status of the device
class BatteryStatusViewModel: ObservableObject {
private var wasCharging: Bool = false
private var powerSourceChangedCallback: IOPowerSourceCallbackType?
private var runLoopSource: Unmanaged<CFRunLoopSource>?
@ -22,14 +22,14 @@ class BatteryStatusViewModel: ObservableObject {
@Published private(set) var isInitial: Bool = false
@Published private(set) var timeToFullCharge: Int = 0
@Published private(set) var statusText: String = ""
private let managerBattery = BatteryActivityManager.shared
private var managerBatteryId: Int?
static let shared = BatteryStatusViewModel()
/// Initializes the view model with a given DynamicIslandViewModel instance
/// - Parameter vm: The DynamicIslandViewModel instance
/// Initializes the view model with a given BoringViewModel instance
/// - Parameter vm: The BoringViewModel instance
private init() {
setupPowerStatus()
setupMonitor()
@ -48,58 +48,61 @@ class BatteryStatusViewModel: ObservableObject {
self.handleBatteryEvent(event)
}
}
/// Handles battery events and updates the corresponding properties
/// - Parameter event: The battery event to handle
private func handleBatteryEvent(_ event: BatteryActivityManager.BatteryEvent) {
private func handleBatteryEvent(_ event: BatteryActivityManager.BatteryEvent) {
switch event {
case .powerSourceChanged(let isPluggedIn):
print("🔌 Power source: \(isPluggedIn ? "Connected" : "Disconnected")")
withAnimation {
self.isPluggedIn = isPluggedIn
self.statusText = isPluggedIn ? "Plugged In" : "Unplugged"
self.notifyImportanChangeStatus()
}
case .batteryLevelChanged(let level):
print("🔋 Battery level: \(Int(level))%")
withAnimation {
self.levelBattery = level
}
case .lowPowerModeChanged(let isEnabled):
print("⚡ Low power mode: \(isEnabled ? "Enabled" : "Disabled")")
self.notifyImportanChangeStatus()
withAnimation {
self.isInLowPowerMode = isEnabled
self.statusText = "Low Power: \(self.isInLowPowerMode ? "On" : "Off")"
}
case .isChargingChanged(let isCharging):
print("🔌 Charging: \(isCharging ? "Yes" : "No")")
print("maxCapacity: \(self.maxCapacity)")
print("levelBattery: \(self.levelBattery)")
self.notifyImportanChangeStatus()
withAnimation {
self.isCharging = isCharging
self.statusText = isCharging ? "Charging battery" : (self.levelBattery < self.maxCapacity ? "Not charging" : "Full charge")
}
case .timeToFullChargeChanged(let time):
print("🕒 Time to full charge: \(time) minutes")
withAnimation {
self.timeToFullCharge = time
}
case .maxCapacityChanged(let capacity):
print("🔋 Max capacity: \(capacity)")
withAnimation {
self.maxCapacity = capacity
}
case .error(let description):
print("⚠️ Error: \(description)")
case .powerSourceChanged(let isPluggedIn):
print("🔌 Power source: \(isPluggedIn ? "Connected" : "Disconnected")")
withAnimation {
self.isPluggedIn = isPluggedIn
self.statusText = isPluggedIn ? "Plugged In" : "Unplugged"
self.notifyImportanChangeStatus()
}
case .batteryLevelChanged(let level):
print("🔋 Battery level: \(Int(level))%")
withAnimation {
self.levelBattery = level
}
case .lowPowerModeChanged(let isEnabled):
print("⚡ Low power mode: \(isEnabled ? "Enabled" : "Disabled")")
self.notifyImportanChangeStatus()
withAnimation {
self.isInLowPowerMode = isEnabled
self.statusText = "Low Power: \(self.isInLowPowerMode ? "On" : "Off")"
}
case .isChargingChanged(let isCharging):
print("🔌 Charging: \(isCharging ? "Yes" : "No")")
print("maxCapacity: \(self.maxCapacity)")
print("levelBattery: \(self.levelBattery)")
self.notifyImportanChangeStatus()
withAnimation {
self.isCharging = isCharging
self.statusText =
isCharging
? "Charging battery"
: (self.levelBattery < self.maxCapacity ? "Not charging" : "Full charge")
}
case .timeToFullChargeChanged(let time):
print("🕒 Time to full charge: \(time) minutes")
withAnimation {
self.timeToFullCharge = time
}
case .maxCapacityChanged(let capacity):
print("🔋 Max capacity: \(capacity)")
withAnimation {
self.maxCapacity = capacity
}
case .error(let description):
print("⚠️ Error: \(description)")
}
}
/// Updates the battery information with the given BatteryInfo instance
@ -114,25 +117,13 @@ class BatteryStatusViewModel: ObservableObject {
self.maxCapacity = batteryInfo.maxCapacity
self.statusText = batteryInfo.isPluggedIn ? "Plugged In" : "Unplugged"
}
notifyImportanChangeStatus(delay: coordinator.firstLaunch ? 6 : 0.0)
withAnimation {
if self.isCharging {
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
self.statusText = "Charging: Yes"
}
}
if self.isInLowPowerMode {
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
self.statusText = "Low Power: On"
}
}
}
}
/// Notifies important changes in the battery status with an optional delay
/// - Parameter delay: The delay before notifying the change, default is 0.0
private func notifyImportanChangeStatus(delay: Double = 0.0) {
DispatchQueue.main.asyncAfter(deadline: .now() + delay) {
Task {
try? await Task.sleep(for: .seconds(delay))
self.coordinator.toggleExpandingView(status: true, type: .battery)
}
}
@ -143,5 +134,5 @@ class BatteryStatusViewModel: ObservableObject {
managerBattery.removeObserver(byId: managerBatteryId)
}
}
}

View file

@ -117,6 +117,7 @@ extension Defaults.Keys {
static let sneakPeekStyles = Key<SneakPeekStyle>("sneakPeekStyles", default: .standard)
static let enableFullscreenMediaDetection = Key<Bool>("enableFullscreenMediaDetection", default: true)
static let waitInterval = Key<Double>("waitInterval", default: 3)
static let showShuffleAndRepeat = Key<Bool>("showShuffleAndRepeat", default: false)
// MARK: Battery
static let showPowerStatusNotifications = Key<Bool>("showPowerStatusNotifications", default: true)

View file

@ -30,6 +30,10 @@ class DynamicIslandViewModel: NSObject, ObservableObject {
@Published var isHoveringCalendar: Bool = false
@Published var isBatteryPopoverActive: Bool = false
@Published var isClipboardPopoverActive: Bool = false
let webcamManager = WebcamManager.shared
@Published var isCameraExpanded: Bool = false
@Published var isRequestingAuthorization: Bool = false
@Published var screen: String?
@ -172,4 +176,46 @@ class DynamicIslandViewModel: NSObject, ObservableObject {
}
}
}
func toggleCameraPreview() {
if isRequestingAuthorization {
return
}
switch webcamManager.authorizationStatus {
case .authorized:
if webcamManager.isSessionRunning {
webcamManager.stopSession()
isCameraExpanded = false
} else if webcamManager.cameraAvailable {
webcamManager.startSession()
isCameraExpanded = true
}
case .denied, .restricted:
DispatchQueue.main.async {
NSApp.setActivationPolicy(.regular)
NSApp.activate(ignoringOtherApps: true)
let alert = NSAlert()
alert.messageText = "Camera Access Required"
alert.informativeText = "Please allow camera access in System Settings."
alert.addButton(withTitle: "OK")
alert.runModal()
NSApp.setActivationPolicy(.accessory)
NSApp.deactivate()
}
case .notDetermined:
isRequestingAuthorization = true
webcamManager.checkAndRequestVideoAuthorization()
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
self.isRequestingAuthorization = false
}
default:
break
}
}
}

View file

@ -7,6 +7,12 @@
import Foundation
enum RepeatMode: Int, Codable {
case off = 1
case one = 2
case all = 3
}
struct PlaybackState {
var bundleIdentifier: String
var isPlaying: Bool = false
@ -16,8 +22,8 @@ struct PlaybackState {
var currentTime: Double = 0
var duration: Double = 0
var playbackRate: Double = 1
var isShuffled: Bool? = nil
var isRepeating: Bool? = nil
var isShuffled: Bool = false
var repeatMode: RepeatMode = .off
var lastUpdated: Date = Date.distantPast
var artwork: Data?
}