ios: CallKit enhancements (#2010)

* ios: CallKit enhancements

* better checks
This commit is contained in:
Stanislav Dmitrenko
2023-03-15 18:32:27 +03:00
committed by GitHub
parent 0404b020e6
commit 840df89ca6
5 changed files with 46 additions and 13 deletions

View File

@@ -94,6 +94,16 @@ class AppDelegate: NSObject, UIApplicationDelegate {
return configuration
}
func applicationProtectedDataWillBecomeUnavailable(_ application: UIApplication) {
logger.debug("AppDelegate: will lock screen")
ChatModel.shared.onLockScreenCurrently = true
}
func applicationProtectedDataDidBecomeAvailable(_ application: UIApplication) {
logger.debug("AppDelegate: did unlock screen")
ChatModel.shared.onLockScreenCurrently = false
}
private func receiveMessages(_ completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
let complete = BGManager.shared.completionHandler {
logger.debug("AppDelegate: completed BGManager.receiveMessages")

View File

@@ -17,6 +17,7 @@ struct ContentView: View {
@Binding var doAuthenticate: Bool
@Binding var userAuthorized: Bool?
@Binding var canConnectCall: Bool
@Binding var lastSuccessfulUnlock: TimeInterval?
@AppStorage(DEFAULT_SHOW_LA_NOTICE) private var prefShowLANotice = false
@AppStorage(DEFAULT_LA_NOTICE_SHOWN) private var prefLANoticeShown = false
@AppStorage(DEFAULT_PERFORM_LA) private var prefPerformLA = false
@@ -27,7 +28,7 @@ struct ContentView: View {
var body: some View {
ZStack {
if chatModel.showCallView, let call = chatModel.activeCall {
ActiveCallView(call: call, userAuthorized: $userAuthorized, canConnectCall: $canConnectCall)
ActiveCallView(call: call, canConnectCall: $canConnectCall)
}
if prefPerformLA && userAuthorized != true {
Rectangle().fill(colorScheme == .dark ? .black : .white)
@@ -128,6 +129,7 @@ struct ContentView: View {
case .success:
userAuthorized = true
canConnectCall = true
lastSuccessfulUnlock = ProcessInfo.processInfo.systemUptime
case .failed:
break
case .unavailable:

View File

@@ -9,7 +9,6 @@
import Foundation
import Combine
import SwiftUI
import WebKit
import SimpleXChat
final class ChatModel: ObservableObject {
@@ -59,7 +58,9 @@ final class ChatModel: ObservableObject {
@Published var stopPreviousRecPlay: Bool = false // value is not taken into account, only the fact it switches
@Published var draft: ComposeState?
@Published var draftChatId: String?
var callWebView: WKWebView?
var sceneWasActiveAtLeastOnce = false
var onLockScreenCurrently = false
var messageDelivery: Dictionary<Int64, () -> Void> = [:]

View File

@@ -22,6 +22,7 @@ struct SimpleXApp: App {
@State private var doAuthenticate = false
@State private var canConnectCall = false
@State private var enteredBackground: TimeInterval? = nil
@State private var lastSuccessfulUnlock: TimeInterval? = nil
init() {
hs_init(0, nil)
@@ -35,7 +36,7 @@ struct SimpleXApp: App {
var body: some Scene {
return WindowGroup {
ContentView(doAuthenticate: $doAuthenticate, userAuthorized: $userAuthorized, canConnectCall: $canConnectCall)
ContentView(doAuthenticate: $doAuthenticate, userAuthorized: $userAuthorized, canConnectCall: $canConnectCall, lastSuccessfulUnlock: $lastSuccessfulUnlock)
.environmentObject(chatModel)
.onOpenURL { url in
logger.debug("ContentView.onOpenURL: \(url)")
@@ -65,6 +66,7 @@ struct SimpleXApp: App {
NtfManager.shared.setNtfBadgeCount(chatModel.totalUnreadCountForAllUsers())
case .active:
CallController.shared.onEndCall = nil
chatModel.sceneWasActiveAtLeastOnce = true
let appState = appStateGroupDefault.get()
startChatAndActivate()
if appState.inactive && chatModel.chatRunning == true {
@@ -74,7 +76,7 @@ struct SimpleXApp: App {
}
}
doAuthenticate = authenticationExpired()
canConnectCall = !(doAuthenticate && prefPerformLA)
canConnectCall = !(doAuthenticate && prefPerformLA) || unlockedRecently()
default:
break
}
@@ -114,6 +116,15 @@ struct SimpleXApp: App {
}
}
private func unlockedRecently() -> Bool {
if let lastSuccessfulUnlock = lastSuccessfulUnlock {
return ProcessInfo.processInfo.systemUptime - lastSuccessfulUnlock < 2
} else {
return false
}
}
private func updateChats() {
do {
let chats = try apiGetChats()

View File

@@ -14,7 +14,6 @@ struct ActiveCallView: View {
@EnvironmentObject var m: ChatModel
@Environment(\.scenePhase) var scenePhase
@ObservedObject var call: Call
@Binding var userAuthorized: Bool?
@Binding var canConnectCall: Bool
@State private var client: WebRTCClient? = nil
@State private var activeCall: WebRTCClient.Call? = nil
@@ -39,11 +38,7 @@ struct ActiveCallView: View {
}
}
.onAppear {
logger.debug("ActiveCallView: appear client is nil \(client == nil), userAuthorized \(userAuthorized.debugDescription, privacy: .public), scenePhase \(String(describing: scenePhase), privacy: .public)")
createWebRTCClient()
}
.onChange(of: userAuthorized) { _ in
logger.debug("ActiveCallView: userAuthorized changed to \(userAuthorized.debugDescription, privacy: .public)")
logger.debug("ActiveCallView: appear client is nil \(client == nil), canConnectCall \(canConnectCall, privacy: .public), scenePhase \(String(describing: scenePhase), privacy: .public)")
createWebRTCClient()
}
.onChange(of: canConnectCall) { _ in
@@ -60,8 +55,22 @@ struct ActiveCallView: View {
}
private func createWebRTCClient() {
if client == nil && ((userAuthorized == true && canConnectCall) || scenePhase == .background) {
client = WebRTCClient($activeCall, { msg in await MainActor.run { processRtcMessage(msg: msg) } }, $localRendererAspectRatio)
if client == nil && (canConnectCall || m.onLockScreenCurrently) {
createWebRTCClientWithoutWait()
} else if (!m.sceneWasActiveAtLeastOnce) {
// This code waits a second until it recheck `sceneWasActiveAtLeastOnce`.
// It helps to know whether a call from lockscreen or not.
// After the second `sceneWasActiveAtLeastOnce` will still be false when the call from lockscreen
Task {
try? await Task.sleep(nanoseconds: 1_000_000_000)
createWebRTCClientWithoutWait()
}
}
}
private func createWebRTCClientWithoutWait() {
if client == nil && (canConnectCall || !m.sceneWasActiveAtLeastOnce || m.onLockScreenCurrently) {
client = WebRTCClient($activeCall, { msg in await MainActor.run {processRtcMessage(msg: msg)} }, $localRendererAspectRatio)
sendCommandToClient()
}
}