Cover screen on .inactive (#282)
* Make unlock block actor-safe * Cover views on .inactive, lock on .background
This commit is contained in:
parent
0591363b15
commit
e3cfdadf97
|
@ -9,7 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Option to lock app when entering background (iOS). [#270](https://github.com/passepartoutvpn/passepartout-apple/pull/270), [#271](https://github.com/passepartoutvpn/passepartout-apple/pull/271), [#273](https://github.com/passepartoutvpn/passepartout-apple/pull/273), [#275](https://github.com/passepartoutvpn/passepartout-apple/pull/275)
|
- Option to lock app when entering background (iOS). [#270](https://github.com/passepartoutvpn/passepartout-apple/pull/270), [#271](https://github.com/passepartoutvpn/passepartout-apple/pull/271), [#273](https://github.com/passepartoutvpn/passepartout-apple/pull/273), [#275](https://github.com/passepartoutvpn/passepartout-apple/pull/275), [#282](https://github.com/passepartoutvpn/passepartout-apple/pull/282)
|
||||||
- 3D Touch items (iOS). [#267](https://github.com/passepartoutvpn/passepartout-apple/pull/267)
|
- 3D Touch items (iOS). [#267](https://github.com/passepartoutvpn/passepartout-apple/pull/267)
|
||||||
- Ukranian translations (Dmitry Chirkin). [#243](https://github.com/passepartoutvpn/passepartout-apple/pull/243)
|
- Ukranian translations (Dmitry Chirkin). [#243](https://github.com/passepartoutvpn/passepartout-apple/pull/243)
|
||||||
- Restore DNS "Domain" setting. [#260](https://github.com/passepartoutvpn/passepartout-apple/pull/260)
|
- Restore DNS "Domain" setting. [#260](https://github.com/passepartoutvpn/passepartout-apple/pull/260)
|
||||||
|
|
|
@ -498,23 +498,21 @@ extension View {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private static func themeUnlockScreenBlock(isLocked: Binding<Bool>) {
|
private static func themeUnlockScreenBlock() async -> Bool {
|
||||||
let context = LAContext()
|
let context = LAContext()
|
||||||
let policy: LAPolicy = .deviceOwnerAuthentication
|
let policy: LAPolicy = .deviceOwnerAuthentication
|
||||||
var error: NSError?
|
var error: NSError?
|
||||||
guard context.canEvaluatePolicy(policy, error: &error) else {
|
guard context.canEvaluatePolicy(policy, error: &error) else {
|
||||||
isLocked.wrappedValue = false
|
return true
|
||||||
return
|
|
||||||
}
|
}
|
||||||
Task { @MainActor in
|
|
||||||
do {
|
do {
|
||||||
let isAuthorized = try await context.evaluatePolicy(
|
let isAuthorized = try await context.evaluatePolicy(
|
||||||
policy,
|
policy,
|
||||||
localizedReason: L10n.Global.Messages.unlockApp
|
localizedReason: L10n.Global.Messages.unlockApp
|
||||||
)
|
)
|
||||||
isLocked.wrappedValue = !isAuthorized
|
return isAuthorized
|
||||||
} catch {
|
} catch {
|
||||||
}
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,24 +32,36 @@ struct LockableView<Content: View, LockedContent: View>: View {
|
||||||
|
|
||||||
let lockedContent: () -> LockedContent
|
let lockedContent: () -> LockedContent
|
||||||
|
|
||||||
let unlockBlock: (Binding<Bool>) -> Void
|
let unlockBlock: () async -> Bool
|
||||||
|
|
||||||
@Environment(\.scenePhase) private var scenePhase
|
@Environment(\.scenePhase) private var scenePhase
|
||||||
|
|
||||||
@ObservedObject private var lock: Lock = .shared
|
@ObservedObject private var lock: Lock = .shared
|
||||||
|
|
||||||
private var isLocked: Binding<Bool> {
|
@Binding private var state: Lock.State
|
||||||
.init {
|
|
||||||
Lock.shared.isActive
|
init(
|
||||||
|
locksInBackground: Binding<Bool>,
|
||||||
|
content: @escaping () -> Content,
|
||||||
|
lockedContent: @escaping () -> LockedContent,
|
||||||
|
unlockBlock: @escaping () async -> Bool
|
||||||
|
) {
|
||||||
|
_locksInBackground = locksInBackground
|
||||||
|
self.content = content
|
||||||
|
self.lockedContent = lockedContent
|
||||||
|
self.unlockBlock = unlockBlock
|
||||||
|
|
||||||
|
_state = .init {
|
||||||
|
Lock.shared.state
|
||||||
} set: {
|
} set: {
|
||||||
Lock.shared.isActive = $0
|
Lock.shared.state = $0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ZStack {
|
ZStack {
|
||||||
content()
|
content()
|
||||||
if isLocked.wrappedValue {
|
if locksInBackground && state != .none {
|
||||||
lockedContent()
|
lockedContent()
|
||||||
}
|
}
|
||||||
}.onChange(of: scenePhase, perform: onScenePhase)
|
}.onChange(of: scenePhase, perform: onScenePhase)
|
||||||
|
@ -60,6 +72,11 @@ struct LockableView<Content: View, LockedContent: View>: View {
|
||||||
case .active:
|
case .active:
|
||||||
unlockIfNeeded()
|
unlockIfNeeded()
|
||||||
|
|
||||||
|
case .inactive:
|
||||||
|
if state == .none {
|
||||||
|
state = .covered
|
||||||
|
}
|
||||||
|
|
||||||
case .background:
|
case .background:
|
||||||
lockIfNeeded()
|
lockIfNeeded()
|
||||||
|
|
||||||
|
@ -72,25 +89,44 @@ struct LockableView<Content: View, LockedContent: View>: View {
|
||||||
guard locksInBackground else {
|
guard locksInBackground else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
isLocked.wrappedValue = true
|
state = .locked
|
||||||
}
|
}
|
||||||
|
|
||||||
func unlockIfNeeded() {
|
func unlockIfNeeded() {
|
||||||
guard locksInBackground else {
|
guard locksInBackground else {
|
||||||
isLocked.wrappedValue = false
|
state = .none
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
guard isLocked.wrappedValue else {
|
switch state {
|
||||||
|
case .none:
|
||||||
|
break
|
||||||
|
|
||||||
|
case .covered:
|
||||||
|
state = .none
|
||||||
|
|
||||||
|
case .locked:
|
||||||
|
Task { @MainActor in
|
||||||
|
guard await unlockBlock() else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
unlockBlock(isLocked)
|
state = .none
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class Lock: ObservableObject {
|
private class Lock: ObservableObject {
|
||||||
|
enum State {
|
||||||
|
case none
|
||||||
|
|
||||||
|
case covered
|
||||||
|
|
||||||
|
case locked
|
||||||
|
}
|
||||||
|
|
||||||
static let shared = Lock()
|
static let shared = Lock()
|
||||||
|
|
||||||
@Published var isActive = true
|
@Published var state: State = .locked
|
||||||
|
|
||||||
private init() {
|
private init() {
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue