Fix lock view flickering on first appearance

Fixes #781
This commit is contained in:
Davide 2024-10-30 12:25:33 +01:00
parent aadc46e98f
commit c677a1e655
2 changed files with 47 additions and 30 deletions

View File

@ -327,7 +327,7 @@ struct ThemeLockScreenModifier: ViewModifier {
func body(content: Content) -> some View { func body(content: Content) -> some View {
LockableView( LockableView(
locksInBackground: $locksInBackground, locksInBackground: locksInBackground,
content: { content: {
content content
}, },

View File

@ -32,8 +32,10 @@ public struct LockableView<Content: View, LockedContent: View>: View {
@Environment(\.scenePhase) @Environment(\.scenePhase)
private var scenePhase private var scenePhase
@Binding // unobserved here, observed in LockedContentWrapper
private var locksInBackground: Bool private let lock: Lock
private let locksInBackground: Bool
private let content: () -> Content private let content: () -> Content
@ -41,42 +43,38 @@ public struct LockableView<Content: View, LockedContent: View>: View {
private let unlockBlock: () async -> Bool private let unlockBlock: () async -> Bool
@ObservedObject @MainActor
private var lock: Lock = .shared
@Binding
private var state: Lock.State
public init( public init(
locksInBackground: Binding<Bool>, locksInBackground: Bool,
content: @escaping () -> Content, content: @escaping () -> Content,
lockedContent: @escaping () -> LockedContent, lockedContent: @escaping () -> LockedContent,
unlockBlock: @escaping () async -> Bool unlockBlock: @escaping () async -> Bool
) { ) {
_locksInBackground = locksInBackground lock = .shared
self.locksInBackground = locksInBackground
self.content = content self.content = content
self.lockedContent = lockedContent self.lockedContent = lockedContent
self.unlockBlock = unlockBlock self.unlockBlock = unlockBlock
_state = .init {
Lock.shared.state
} set: {
Lock.shared.state = $0
}
} }
public var body: some View { public var body: some View {
ZStack { debugChanges()
return ZStack {
content() content()
if locksInBackground && state != .none { if locksInBackground {
lockedContent() LockedContentWrapperView(
lock: lock,
content: lockedContent
)
} }
}.onChange(of: scenePhase, perform: onScenePhase) }
.onChange(of: scenePhase, perform: onScenePhase)
} }
} }
// MARK: - // MARK: -
@MainActor
private final class Lock: ObservableObject { private final class Lock: ObservableObject {
enum State { enum State {
case none case none
@ -88,7 +86,8 @@ private final class Lock: ObservableObject {
static let shared = Lock() static let shared = Lock()
@Published var state: State = .locked @Published
var state: State = .locked
private init() { private init() {
} }
@ -96,6 +95,7 @@ private final class Lock: ObservableObject {
// MARK: - // MARK: -
@MainActor
private extension LockableView { private extension LockableView {
func onScenePhase(_ scenePhase: ScenePhase) { func onScenePhase(_ scenePhase: ScenePhase) {
switch scenePhase { switch scenePhase {
@ -103,8 +103,8 @@ private extension LockableView {
unlockIfNeeded() unlockIfNeeded()
case .inactive: case .inactive:
if state == .none { if lock.state == .none {
state = .covered lock.state = .covered
} }
case .background: case .background:
@ -119,30 +119,47 @@ private extension LockableView {
guard locksInBackground else { guard locksInBackground else {
return return
} }
state = .locked lock.state = .locked
} }
func unlockIfNeeded() { func unlockIfNeeded() {
guard locksInBackground else { guard locksInBackground else {
state = .none lock.state = .none
return return
} }
switch state { switch lock.state {
case .none: case .none:
break break
case .covered: case .covered:
state = .none lock.state = .none
case .locked: case .locked:
Task { @MainActor in Task {
guard await unlockBlock() else { guard await unlockBlock() else {
return return
} }
state = .none lock.state = .none
} }
} }
} }
} }
// MARK: -
private struct LockedContentWrapperView<Content>: View where Content: View {
@ObservedObject
var lock: Lock
@ViewBuilder
let content: Content
var body: some View {
if lock.state != .none {
content
}
}
}
#endif #endif