Merge pull request #85 from Ebullioscopic/feature/lock-screen

Fix Unlock delay
This commit is contained in:
Hariharan Mudaliar 2025-11-07 01:51:37 +05:30 • committed by GitHub
commit 207505c2fd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 41 additions and 17 deletions

View file

@ -16,6 +16,14 @@ struct LockScreenLiveActivity: View {
@State private var gestureProgress: CGFloat = 0 @State private var gestureProgress: CGFloat = 0
@State private var isExpanded: Bool = false @State private var isExpanded: Bool = false
private var expandAnimation: Animation {
.smooth(duration: LockScreenAnimationTimings.lockExpand)
}
private var collapseAnimation: Animation {
.smooth(duration: LockScreenAnimationTimings.unlockCollapse)
}
private var iconColor: Color { private var iconColor: Color {
.white .white
} }
@ -48,9 +56,9 @@ struct LockScreenLiveActivity: View {
.frame(height: vm.effectiveClosedNotchHeight + (isHovering ? 8 : 0)) .frame(height: vm.effectiveClosedNotchHeight + (isHovering ? 8 : 0))
.onAppear { .onAppear {
iconAnimator.update(isLocked: lockScreenManager.isLocked, animated: false) iconAnimator.update(isLocked: lockScreenManager.isLocked, animated: false)
// Expand immediately without animation to avoid conflicts let shouldStartExpanded = lockScreenManager.isLocked || !lockScreenManager.isLockIdle
withAnimation(.smooth(duration: 0.4)) { withAnimation(expandAnimation) {
isExpanded = true isExpanded = shouldStartExpanded
} }
} }
.onDisappear { .onDisappear {
@ -59,17 +67,26 @@ struct LockScreenLiveActivity: View {
} }
.onChange(of: lockScreenManager.isLockIdle) { _, newValue in .onChange(of: lockScreenManager.isLockIdle) { _, newValue in
if newValue { if newValue {
withAnimation(.smooth(duration: 0.4)) { withAnimation(collapseAnimation) {
isExpanded = false isExpanded = false
} }
} else { } else if lockScreenManager.isLocked {
withAnimation(.smooth(duration: 0.4)) { withAnimation(expandAnimation) {
isExpanded = true isExpanded = true
} }
} }
} }
.onChange(of: lockScreenManager.isLocked) { _, newValue in .onChange(of: lockScreenManager.isLocked) { _, newValue in
iconAnimator.update(isLocked: newValue) iconAnimator.update(isLocked: newValue)
if newValue {
withAnimation(expandAnimation) {
isExpanded = true
}
} else {
withAnimation(collapseAnimation) {
isExpanded = false
}
}
} }
.animation(.spring(response: 0.5, dampingFraction: 0.85), value: lockScreenManager.isLocked) .animation(.spring(response: 0.5, dampingFraction: 0.85), value: lockScreenManager.isLocked)
.animation(.easeOut(duration: 0.25), value: isExpanded) .animation(.easeOut(duration: 0.25), value: isExpanded)

View file

@ -9,6 +9,7 @@ import AppKit
import Defaults import Defaults
import SkyLightWindow import SkyLightWindow
import SwiftUI import SwiftUI
import QuartzCore
@MainActor @MainActor
class LockScreenLiveActivityWindowManager { class LockScreenLiveActivityWindowManager {
@ -165,9 +166,7 @@ class LockScreenLiveActivityWindowManager {
overlayAnimator.update(isLocked: false) overlayAnimator.update(isLocked: false)
hideTask = Task { [weak self] in hideTask = Task { [weak self] in
//try? await Task.sleep(for: .milliseconds(450)) try? await Task.sleep(for: .seconds(LockScreenAnimationTimings.unlockCollapse))
try? await Task.sleep(for: .seconds(max(Defaults[.waitInterval], 0.7)))
//try? await Task.sleep(for: .seconds(1.0))
guard let self, !Task.isCancelled else { return } guard let self, !Task.isCancelled else { return }
await MainActor.run { await MainActor.run {
self.hideWithAnimation() self.hideWithAnimation()
@ -185,17 +184,18 @@ class LockScreenLiveActivityWindowManager {
private func hideWithAnimation() { private func hideWithAnimation() {
guard let window else { return } guard let window else { return }
withAnimation(.easeInOut(duration: 0.18)) { withAnimation(.smooth(duration: LockScreenAnimationTimings.unlockCollapse)) {
overlayModel.opacity = 0 overlayModel.opacity = 0
overlayModel.scale = 0.7 overlayModel.scale = 0.7
} }
NSAnimationContext.runAnimationGroup { context in NSAnimationContext.runAnimationGroup { context in
context.duration = 0.2 context.duration = LockScreenAnimationTimings.unlockCollapse
context.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
window.animator().alphaValue = 0 window.animator().alphaValue = 0
} }
DispatchQueue.main.asyncAfter(deadline: .now() + 0.22) { DispatchQueue.main.asyncAfter(deadline: .now() + LockScreenAnimationTimings.unlockCollapse + 0.02) {
window.orderOut(nil) window.orderOut(nil)
} }

View file

@ -12,6 +12,11 @@ import AppKit
import Defaults import Defaults
import SwiftUI import SwiftUI
enum LockScreenAnimationTimings {
static let lockExpand: TimeInterval = 0.45
static let unlockCollapse: TimeInterval = 0.82
}
@MainActor @MainActor
class LockScreenManager: ObservableObject { class LockScreenManager: ObservableObject {
static let shared = LockScreenManager() static let shared = LockScreenManager()
@ -125,7 +130,7 @@ class LockScreenManager: ObservableObject {
if Defaults[.enableLockScreenLiveActivity] { if Defaults[.enableLockScreenLiveActivity] {
collapseTask?.cancel() collapseTask?.cancel()
collapseTask = Task { [weak self] in collapseTask = Task { [weak self] in
try? await Task.sleep(for: .milliseconds(380)) try? await Task.sleep(for: .seconds(LockScreenAnimationTimings.unlockCollapse))
guard let self = self, !Task.isCancelled else { return } guard let self = self, !Task.isCancelled else { return }
await MainActor.run { await MainActor.run {
self.coordinator.toggleExpandingView(status: false, type: .lockScreen) self.coordinator.toggleExpandingView(status: false, type: .lockScreen)
@ -134,7 +139,7 @@ class LockScreenManager: ObservableObject {
} }
self.lastUpdated = Date() self.lastUpdated = Date()
self.updateIdleState(locked: false) self.updateIdleState(locked: false)
self.isLocked = false self.isLocked = false
print("[\(self.timestamp())] LockScreenManager: ✅ Lock screen deactivated") print("[\(self.timestamp())] LockScreenManager: ✅ Lock screen deactivated")
@ -150,11 +155,13 @@ class LockScreenManager: ObservableObject {
} else { } else {
debounceIdleTask?.cancel() debounceIdleTask?.cancel()
debounceIdleTask = Task { [weak self] in debounceIdleTask = Task { [weak self] in
try? await Task.sleep(for: .seconds(Defaults[.waitInterval])) let configuredInterval = max(Defaults[.waitInterval], 0)
let idleDelay = min(max(configuredInterval, 0.2), LockScreenAnimationTimings.unlockCollapse)
try? await Task.sleep(for: .seconds(idleDelay))
guard let self = self, !Task.isCancelled else { return } guard let self = self, !Task.isCancelled else { return }
await MainActor.run { await MainActor.run {
if self.lastUpdated.timeIntervalSinceNow < -Defaults[.waitInterval] { if self.lastUpdated.timeIntervalSinceNow < -idleDelay {
withAnimation { withAnimation(.smooth(duration: 0.3)) {
self.isLockIdle = !self.isLocked self.isLockIdle = !self.isLocked
} }
} }