From 2643ea90660bfea4caef18d9b62f72181e485119 Mon Sep 17 00:00:00 2001 From: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com> Date: Thu, 16 Mar 2023 00:09:33 +0300 Subject: [PATCH] ios: reverted some changes related to lockScreen (#2011) * Revert "ios: CallKit enhancements (#2010)" This reverts commit 840df89ca631eddb8c954fb89d7c54671747f3ef. * Revert "ios: CallKit integrated with app lock and screen protect (#2007)" This reverts commit 0404b020e6fb36e114c0e86b17a3d09d0e37e5bc. * ios: reverted some changes related to lockScreen * undo delay * better support of appLock + call * refactor * refactor 2 * refactor 3 * refactor 4 --------- Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> --- apps/ios/Shared/AppDelegate.swift | 10 -- apps/ios/Shared/ContentView.swift | 125 +++++++++++------- apps/ios/Shared/Model/ChatModel.swift | 3 - apps/ios/Shared/SimpleXApp.swift | 4 +- .../Shared/Views/Call/ActiveCallView.swift | 24 +--- .../Shared/Views/Call/CallController.swift | 8 +- 6 files changed, 88 insertions(+), 86 deletions(-) diff --git a/apps/ios/Shared/AppDelegate.swift b/apps/ios/Shared/AppDelegate.swift index 457aaa2824..f20882383a 100644 --- a/apps/ios/Shared/AppDelegate.swift +++ b/apps/ios/Shared/AppDelegate.swift @@ -94,16 +94,6 @@ 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") diff --git a/apps/ios/Shared/ContentView.swift b/apps/ios/Shared/ContentView.swift index 2b56580136..2bfec8368d 100644 --- a/apps/ios/Shared/ContentView.swift +++ b/apps/ios/Shared/ContentView.swift @@ -27,48 +27,64 @@ struct ContentView: View { var body: some View { ZStack { + contentView() if chatModel.showCallView, let call = chatModel.activeCall { - ActiveCallView(call: call, canConnectCall: $canConnectCall) - } - if prefPerformLA && userAuthorized != true { - Rectangle().fill(colorScheme == .dark ? .black : .white) - .frame(maxWidth: .infinity, maxHeight: .infinity) - .onTapGesture(perform: {}) - Button(action: runAuthenticate) { Label("Unlock", systemImage: "lock") } - } else if let status = chatModel.chatDbStatus, status != .ok { - DatabaseErrorView(status: status) - } else if !chatModel.v3DBMigration.startChat { - MigrateToAppGroupView() - } else if let step = chatModel.onboardingStage, (!chatModel.showCallView || chatModel.activeCall == nil) { - if case .onboardingComplete = step, - chatModel.currentUser != nil { - mainView() - } else { - OnboardingView(onboarding: step) - } + callView(call) } } .onAppear { - logger.debug("ContentView: canConnectCall \(canConnectCall), doAuthenticate \(doAuthenticate)") - if doAuthenticate { runAuthenticate() } + if prefPerformLA { requestNtfAuthorization() } + initAuthenticate() + } + .onChange(of: doAuthenticate) { _ in + initAuthenticate() } - .onChange(of: doAuthenticate) { _ in if doAuthenticate { runAuthenticate() } } .alert(isPresented: $alertManager.presentAlert) { alertManager.alertView! } } + @ViewBuilder private func contentView() -> some View { + if prefPerformLA && userAuthorized != true { + lockButton() + } else if let status = chatModel.chatDbStatus, status != .ok { + DatabaseErrorView(status: status) + } else if !chatModel.v3DBMigration.startChat { + MigrateToAppGroupView() + } else if let step = chatModel.onboardingStage { + if case .onboardingComplete = step, + chatModel.currentUser != nil { + mainView() + } else { + OnboardingView(onboarding: step) + } + } + } + + @ViewBuilder private func callView(_ call: Call) -> some View { + if CallController.useCallKit() { + ActiveCallView(call: call, canConnectCall: Binding.constant(true)) + .onDisappear { + if userAuthorized == false && doAuthenticate { runAuthenticate() } + } + } else { + ActiveCallView(call: call, canConnectCall: $canConnectCall) + if prefPerformLA && userAuthorized != true { + Rectangle() + .fill(colorScheme == .dark ? .black : .white) + .frame(maxWidth: .infinity, maxHeight: .infinity) + lockButton() + } + } + } + + private func lockButton() -> some View { + Button(action: runAuthenticate) { Label("Unlock", systemImage: "lock") } + } + private func mainView() -> some View { ZStack(alignment: .top) { ChatListView().privacySensitive(protectScreen) .onAppear { - NtfManager.shared.requestAuthorization( - onDeny: { - if (!notificationAlertShown) { - notificationAlertShown = true - alertManager.showAlert(notificationAlert()) - } - }, - onAuthorized: { notificationAlertShown = false } - ) + if !prefPerformLA { requestNtfAuthorization() } // Local Authentication notice is to be shown on next start after onboarding is complete if (!prefLANoticeShown && prefShowLANotice && !chatModel.chats.isEmpty) { prefLANoticeShown = true @@ -93,24 +109,29 @@ struct ContentView: View { } // private func processUserActivity(_ activity: NSUserActivity) { -// let intent = activity.interaction?.intent -// if let contacts = (intent as? INStartCallIntent)?.contacts { -// callToContact(contacts, .audio) -// } else if let contacts = (intent as? INStartAudioCallIntent)?.contacts { -// callToContact(contacts, .audio) -// } else if let contacts = (intent as? INStartVideoCallIntent)?.contacts { -// callToContact(contacts, .video) -// } -// } -// -// private func callToContact(_ contacts: [INPerson], _ mediaType: CallMediaType) { -// if let contactId = contacts.first?.personHandle?.value, -// let chatInfo = chatModel.chats.first(where: { $0.id == contactId })?.chatInfo, -// case let .direct(contact) = chatInfo { -// CallController.shared.startCall(contact, mediaType) +// let callToContact = { (contactId: ChatId?, mediaType: CallMediaType) in +// if let chatInfo = chatModel.chats.first(where: { $0.id == contactId })?.chatInfo, +// case let .direct(contact) = chatInfo { +// CallController.shared.startCall(contact, mediaType) +// } +// } +// if let intent = activity.interaction?.intent as? INStartCallIntent { +// callToContact(intent.contacts?.first?.personHandle?.value, .audio) +// } else if let intent = activity.interaction?.intent as? INStartAudioCallIntent { +// callToContact(intent.contacts?.first?.personHandle?.value, .audio) +// } else if let intent = activity.interaction?.intent as? INStartVideoCallIntent { +// callToContact(intent.contacts?.first?.personHandle?.value, .video) // } // } + private func initAuthenticate() { + if CallController.useCallKit() && chatModel.showCallView && chatModel.activeCall != nil { + userAuthorized = false + } else if doAuthenticate { + runAuthenticate() + } + } + private func runAuthenticate() { if !prefPerformLA { userAuthorized = true @@ -134,13 +155,25 @@ struct ContentView: View { break case .unavailable: userAuthorized = true - canConnectCall = true prefPerformLA = false + canConnectCall = true AlertManager.shared.showAlert(laUnavailableTurningOffAlert()) } } } + func requestNtfAuthorization() { + NtfManager.shared.requestAuthorization( + onDeny: { + if (!notificationAlertShown) { + notificationAlertShown = true + alertManager.showAlert(notificationAlert()) + } + }, + onAuthorized: { notificationAlertShown = false } + ) + } + func laNoticeAlert() -> Alert { Alert( title: Text("SimpleX Lock"), diff --git a/apps/ios/Shared/Model/ChatModel.swift b/apps/ios/Shared/Model/ChatModel.swift index 11d7bce826..9100f7bcb9 100644 --- a/apps/ios/Shared/Model/ChatModel.swift +++ b/apps/ios/Shared/Model/ChatModel.swift @@ -59,9 +59,6 @@ final class ChatModel: ObservableObject { @Published var draft: ComposeState? @Published var draftChatId: String? - var sceneWasActiveAtLeastOnce = false - var onLockScreenCurrently = false - var messageDelivery: Dictionary Void> = [:] var filesToDelete: [String] = [] diff --git a/apps/ios/Shared/SimpleXApp.swift b/apps/ios/Shared/SimpleXApp.swift index 1e25e15426..08fca3af05 100644 --- a/apps/ios/Shared/SimpleXApp.swift +++ b/apps/ios/Shared/SimpleXApp.swift @@ -20,8 +20,8 @@ struct SimpleXApp: App { @AppStorage(DEFAULT_PERFORM_LA) private var prefPerformLA = false @State private var userAuthorized: Bool? @State private var doAuthenticate = false - @State private var canConnectCall = false @State private var enteredBackground: TimeInterval? = nil + @State private var canConnectCall = false @State private var lastSuccessfulUnlock: TimeInterval? = nil init() { @@ -66,7 +66,6 @@ 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 { @@ -116,7 +115,6 @@ struct SimpleXApp: App { } } - private func unlockedRecently() -> Bool { if let lastSuccessfulUnlock = lastSuccessfulUnlock { return ProcessInfo.processInfo.systemUptime - lastSuccessfulUnlock < 2 diff --git a/apps/ios/Shared/Views/Call/ActiveCallView.swift b/apps/ios/Shared/Views/Call/ActiveCallView.swift index 98a006ae92..e4a9385706 100644 --- a/apps/ios/Shared/Views/Call/ActiveCallView.swift +++ b/apps/ios/Shared/Views/Call/ActiveCallView.swift @@ -12,12 +12,12 @@ import SimpleXChat struct ActiveCallView: View { @EnvironmentObject var m: ChatModel - @Environment(\.scenePhase) var scenePhase @ObservedObject var call: Call - @Binding var canConnectCall: Bool + @Environment(\.scenePhase) var scenePhase @State private var client: WebRTCClient? = nil @State private var activeCall: WebRTCClient.Call? = nil @State private var localRendererAspectRatio: CGFloat? = nil + @Binding var canConnectCall: Bool var body: some View { ZStack(alignment: .bottom) { @@ -38,7 +38,7 @@ struct ActiveCallView: View { } } .onAppear { - logger.debug("ActiveCallView: appear client is nil \(client == nil), canConnectCall \(canConnectCall, privacy: .public), scenePhase \(String(describing: scenePhase), privacy: .public)") + logger.debug("ActiveCallView: appear client is nil \(client == nil), scenePhase \(String(describing: scenePhase), privacy: .public), canConnectCall \(canConnectCall)") createWebRTCClient() } .onChange(of: canConnectCall) { _ in @@ -55,22 +55,8 @@ struct ActiveCallView: View { } private func createWebRTCClient() { - 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) + if client == nil && canConnectCall { + client = WebRTCClient($activeCall, { msg in await MainActor.run { processRtcMessage(msg: msg) } }, $localRendererAspectRatio) sendCommandToClient() } } diff --git a/apps/ios/Shared/Views/Call/CallController.swift b/apps/ios/Shared/Views/Call/CallController.swift index a2fbe90c4c..7ad756b1c0 100644 --- a/apps/ios/Shared/Views/Call/CallController.swift +++ b/apps/ios/Shared/Views/Call/CallController.swift @@ -97,7 +97,6 @@ class CallController: NSObject, CXProviderDelegate, PKPushRegistryDelegate, Obse } func provider(_ provider: CXProvider, didActivate audioSession: AVAudioSession) { - print("received", #function) logger.debug("CallController: activating audioSession and audio in WebRTCClient") RTCAudioSession.sharedInstance().audioSessionDidActivate(audioSession) RTCAudioSession.sharedInstance().isAudioEnabled = true @@ -113,7 +112,6 @@ class CallController: NSObject, CXProviderDelegate, PKPushRegistryDelegate, Obse } func provider(_ provider: CXProvider, didDeactivate audioSession: AVAudioSession) { - print("received", #function) logger.debug("CallController: deactivating audioSession and audio in WebRTCClient") RTCAudioSession.sharedInstance().audioSessionDidDeactivate(audioSession) RTCAudioSession.sharedInstance().isAudioEnabled = false @@ -265,7 +263,7 @@ class CallController: NSObject, CXProviderDelegate, PKPushRegistryDelegate, Obse } func endCall(callUUID: UUID) { - logger.debug("CallController: ending the call") + logger.debug("CallController: ending the call with UUID \(callUUID.uuidString)") if CallController.useCallKit() { requestTransaction(with: CXEndCallAction(call: callUUID)) } else { @@ -280,7 +278,7 @@ class CallController: NSObject, CXProviderDelegate, PKPushRegistryDelegate, Obse } func endCall(invitation: RcvCallInvitation) { - logger.debug("CallController: ending the call") + logger.debug("CallController: ending the call with invitation") callManager.endCall(invitation: invitation) { if invitation.contact.id == self.activeCallInvitation?.contact.id { DispatchQueue.main.async { @@ -291,7 +289,7 @@ class CallController: NSObject, CXProviderDelegate, PKPushRegistryDelegate, Obse } func endCall(call: Call, completed: @escaping () -> Void) { - logger.debug("CallController: ending the call") + logger.debug("CallController: ending the call with call instance") callManager.endCall(call: call, completed: completed) }