From 05d41f6bb75b5eb524bd6af83564e68adb6770c2 Mon Sep 17 00:00:00 2001 From: Hariharan Mudaliar Date: Fri, 17 Oct 2025 18:48:22 +0530 Subject: [PATCH] Working lock liveactivity --- DynamicIsland/DynamicIslandApp.swift | 40 +++++++++++++++++-- .../LockScreenLiveActivityOverlay.swift | 15 +++++-- .../LockScreenLiveActivityWindowManager.swift | 16 +++++++- 3 files changed, 63 insertions(+), 8 deletions(-) diff --git a/DynamicIsland/DynamicIslandApp.swift b/DynamicIsland/DynamicIslandApp.swift index ec917b0..4c490fd 100644 --- a/DynamicIsland/DynamicIslandApp.swift +++ b/DynamicIsland/DynamicIslandApp.swift @@ -91,6 +91,7 @@ class AppDelegate: NSObject, NSApplicationDelegate { private var previousScreens: [NSScreen]? private var onboardingWindowController: NSWindowController? private var cancellables = Set() + private var windowsHiddenForLock = false // Media key monitoring private var globalEventMonitor: Any? @@ -209,14 +210,45 @@ class AppDelegate: NSObject, NSApplicationDelegate { @objc func onScreenLocked(_: Notification) { print("Screen locked") - cleanupWindows() + hideWindowsForLock() } - + @objc func onScreenUnlocked(_: Notification) { print("Screen unlocked") DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { [weak self] in - self?.cleanupWindows() - self?.adjustWindowPosition(changeAlpha: true) + guard let self = self else { return } + self.restoreWindowsAfterLock() + self.adjustWindowPosition(changeAlpha: true) + } + } + + private func hideWindowsForLock() { + guard !windowsHiddenForLock else { return } + windowsHiddenForLock = true + + if Defaults[.showOnAllDisplays] { + for window in windows.values { + window.alphaValue = 0 + window.orderOut(nil) + } + } else if let window = window { + window.alphaValue = 0 + window.orderOut(nil) + } + } + + private func restoreWindowsAfterLock() { + guard windowsHiddenForLock else { return } + windowsHiddenForLock = false + + if Defaults[.showOnAllDisplays] { + for window in windows.values { + window.orderFrontRegardless() + window.alphaValue = 1 + } + } else if let window = window { + window.orderFrontRegardless() + window.alphaValue = 1 } } diff --git a/DynamicIsland/components/LockScreen/LockScreenLiveActivityOverlay.swift b/DynamicIsland/components/LockScreen/LockScreenLiveActivityOverlay.swift index d28fe33..9a3699e 100644 --- a/DynamicIsland/components/LockScreen/LockScreenLiveActivityOverlay.swift +++ b/DynamicIsland/components/LockScreen/LockScreenLiveActivityOverlay.swift @@ -12,9 +12,14 @@ enum LockLiveActivityState: Equatable { case unlocking } +final class LockScreenLiveActivityOverlayViewModel: ObservableObject { + @Published var expansion: CGFloat = 1 +} + struct LockScreenLiveActivityOverlay: View { let state: LockLiveActivityState let notchSize: CGSize + @ObservedObject var viewModel: LockScreenLiveActivityOverlayViewModel private var indicatorSize: CGFloat { max(0, notchSize.height - 12) @@ -65,15 +70,19 @@ struct LockScreenLiveActivityOverlay: View { ) ) .frame(width: totalWidth, height: notchSize.height) + .scaleEffect(x: max(0.05, viewModel.expansion), y: 1, anchor: .center) + .opacity(min(1, max(0.2, viewModel.expansion * 5))) .animation(.spring(response: 0.45, dampingFraction: 0.85), value: state) + .animation(.spring(response: 0.5, dampingFraction: 0.85), value: viewModel.expansion) .drawingGroup() } } #Preview { - VStack(spacing: 24) { - LockScreenLiveActivityOverlay(state: .locked, notchSize: CGSize(width: 220, height: 32)) - LockScreenLiveActivityOverlay(state: .unlocking, notchSize: CGSize(width: 220, height: 32)) + let model = LockScreenLiveActivityOverlayViewModel() + return VStack(spacing: 24) { + LockScreenLiveActivityOverlay(state: .locked, notchSize: CGSize(width: 220, height: 32), viewModel: model) + LockScreenLiveActivityOverlay(state: .unlocking, notchSize: CGSize(width: 220, height: 32), viewModel: model) } .padding() .background(Color.gray.opacity(0.2)) diff --git a/DynamicIsland/managers/LockScreenLiveActivityWindowManager.swift b/DynamicIsland/managers/LockScreenLiveActivityWindowManager.swift index 6c14f76..7ddd400 100644 --- a/DynamicIsland/managers/LockScreenLiveActivityWindowManager.swift +++ b/DynamicIsland/managers/LockScreenLiveActivityWindowManager.swift @@ -18,6 +18,7 @@ class LockScreenLiveActivityWindowManager { private var hasDelegated = false private var hideTask: Task? private var hostingView: NSHostingView? + private let overlayModel = LockScreenLiveActivityOverlayViewModel() private init() {} @@ -82,7 +83,7 @@ class LockScreenLiveActivityWindowManager { let targetFrame = frame(for: notchSize, on: screen) window.setFrame(targetFrame, display: true) - let overlay = LockScreenLiveActivityOverlay(state: state, notchSize: notchSize) + let overlay = LockScreenLiveActivityOverlay(state: state, notchSize: notchSize, viewModel: overlayModel) if let hostingView { hostingView.rootView = overlay @@ -107,6 +108,15 @@ class LockScreenLiveActivityWindowManager { window.orderFrontRegardless() + if state == .locked { + overlayModel.expansion = 0.2 + withAnimation(.spring(response: 0.55, dampingFraction: 0.82)) { + overlayModel.expansion = 1 + } + } else { + overlayModel.expansion = 1 + } + if window.alphaValue < 1 { NSAnimationContext.runAnimationGroup { context in context.duration = 0.12 @@ -141,6 +151,10 @@ class LockScreenLiveActivityWindowManager { guard let window else { return } + withAnimation(.easeOut(duration: 0.1)) { + overlayModel.expansion = 0.2 + } + NSAnimationContext.runAnimationGroup { context in context.duration = 0.1 window.animator().alphaValue = 0