Working stuff

This commit is contained in:
Hariharan Mudaliar 2026-01-14 15:11:57 +05:30
commit 94a612f327
No known key found for this signature in database
GPG key ID: 025583EB0BE5640E
13 changed files with 913 additions and 150 deletions

View file

@ -11,24 +11,54 @@ final class ExtensionLockScreenWidgetManager: ObservableObject {
private let authorizationManager = ExtensionAuthorizationManager.shared
private let maxCapacityKey = Defaults.Keys.extensionLockScreenWidgetCapacity
private var presentationController: ExtensionLockScreenWidgetPresentationController!
private let eventBridge = ExtensionEventBridge.shared
private var widgetObserver: NSObjectProtocol?
private var suppressBroadcast = false
private let currentProcessID = ProcessInfo.processInfo.processIdentifier
private init() {
activeWidgets = eventBridge.loadPersistedLockScreenWidgets()
sortWidgets()
presentationController = ExtensionLockScreenWidgetPresentationController(manager: self)
presentationController.activate()
widgetObserver = eventBridge.observeLockScreenWidgetSnapshots { [weak self] payloads, sourcePID in
self?.applySnapshot(payloads, sourcePID: sourcePID)
}
}
deinit {
if let token = widgetObserver {
eventBridge.removeObserver(token)
}
}
func present(descriptor: AtollLockScreenWidgetDescriptor, bundleIdentifier: String) throws {
guard authorizationManager.canProcessLockScreenRequest(from: bundleIdentifier) else {
logDiagnostics("Rejected lock screen widget \(descriptor.id) from \(bundleIdentifier): scope disabled or bundle unauthorized")
throw ExtensionValidationError.unauthorized
}
guard descriptor.isValid else {
logDiagnostics("Rejected lock screen widget \(descriptor.id) from \(bundleIdentifier): descriptor validation failed")
throw ExtensionValidationError.invalidDescriptor("Structure validation failed")
}
guard activeWidgets.count < Defaults[maxCapacityKey] else {
throw ExtensionValidationError.exceedsCapacity
if let index = activeWidgets.firstIndex(where: { $0.descriptor.id == descriptor.id && $0.bundleIdentifier == bundleIdentifier }) {
let payload = ExtensionLockScreenWidgetPayload(
bundleIdentifier: bundleIdentifier,
descriptor: descriptor,
receivedAt: activeWidgets[index].receivedAt
)
activeWidgets[index] = payload
sortWidgets()
authorizationManager.recordActivity(for: bundleIdentifier, scope: .lockScreenWidgets)
Logger.log("Replaced extension widget \(descriptor.id) for \(bundleIdentifier)", category: .extensions)
broadcastSnapshot()
return
}
guard activeWidgets.contains(where: { $0.descriptor.id == descriptor.id }) == false else {
throw ExtensionValidationError.duplicateIdentifier
guard activeWidgets.count < Defaults[maxCapacityKey] else {
logDiagnostics("Rejected lock screen widget \(descriptor.id) from \(bundleIdentifier): capacity limit \(Defaults[maxCapacityKey]) reached")
throw ExtensionValidationError.exceedsCapacity
}
let payload = ExtensionLockScreenWidgetPayload(
@ -39,10 +69,13 @@ final class ExtensionLockScreenWidgetManager: ObservableObject {
activeWidgets.append(payload)
sortWidgets()
authorizationManager.recordActivity(for: bundleIdentifier, scope: .lockScreenWidgets)
logDiagnostics("Queued lock screen widget \(descriptor.id) for \(bundleIdentifier); total widgets: \(activeWidgets.count)")
broadcastSnapshot()
}
func update(descriptor: AtollLockScreenWidgetDescriptor, bundleIdentifier: String) throws {
guard descriptor.isValid else {
logDiagnostics("Rejected lock screen widget update \(descriptor.id) from \(bundleIdentifier): descriptor validation failed")
throw ExtensionValidationError.invalidDescriptor("Structure validation failed")
}
guard let index = activeWidgets.firstIndex(where: { $0.descriptor.id == descriptor.id && $0.bundleIdentifier == bundleIdentifier }) else {
@ -57,6 +90,8 @@ final class ExtensionLockScreenWidgetManager: ObservableObject {
activeWidgets[index] = payload
sortWidgets()
authorizationManager.recordActivity(for: bundleIdentifier, scope: .lockScreenWidgets)
logDiagnostics("Updated lock screen widget \(descriptor.id) for \(bundleIdentifier)")
broadcastSnapshot()
}
func dismiss(widgetID: String, bundleIdentifier: String) {
@ -65,6 +100,8 @@ final class ExtensionLockScreenWidgetManager: ObservableObject {
if previousCount != activeWidgets.count {
Logger.log("Dismissed extension widget \(widgetID) from \(bundleIdentifier)", category: .extensions)
ExtensionXPCServiceHost.shared.notifyWidgetDismiss(bundleIdentifier: bundleIdentifier, widgetID: widgetID)
logDiagnostics("Removed lock screen widget \(widgetID) for \(bundleIdentifier); remaining: \(activeWidgets.count)")
broadcastSnapshot()
}
}
@ -74,6 +111,10 @@ final class ExtensionLockScreenWidgetManager: ObservableObject {
.map { $0.descriptor.id }
activeWidgets.removeAll { $0.bundleIdentifier == bundleIdentifier }
ids.forEach { ExtensionXPCServiceHost.shared.notifyWidgetDismiss(bundleIdentifier: bundleIdentifier, widgetID: $0) }
if !ids.isEmpty {
logDiagnostics("Removed all lock screen widgets for \(bundleIdentifier); ids: \(ids.joined(separator: ", "))")
broadcastSnapshot()
}
}
private func sortWidgets() {
@ -84,4 +125,28 @@ final class ExtensionLockScreenWidgetManager: ObservableObject {
return lhs.priority > rhs.priority
}
}
private func broadcastSnapshot() {
guard !suppressBroadcast else { return }
eventBridge.broadcastLockScreenWidgetSnapshot(activeWidgets)
logDiagnostics("Broadcasted lock screen widget snapshot (count: \(activeWidgets.count))")
}
private func applySnapshot(_ payloads: [ExtensionLockScreenWidgetPayload], sourcePID: Int32) {
guard sourcePID != currentProcessID else { return }
suppressBroadcast = true
activeWidgets = payloads.sorted { lhs, rhs in
if lhs.priority == rhs.priority {
return lhs.receivedAt < rhs.receivedAt
}
return lhs.priority > rhs.priority
}
suppressBroadcast = false
logDiagnostics("Applied external lock screen widget snapshot from PID \(sourcePID) (count: \(payloads.count))")
}
private func logDiagnostics(_ message: String) {
guard Defaults[.extensionDiagnosticsLoggingEnabled] else { return }
Logger.log(message, category: .extensions)
}
}