2022-01-21 11:09:33 +00:00
|
|
|
//
|
|
|
|
// ContentView.swift
|
|
|
|
// Shared
|
|
|
|
//
|
|
|
|
// Created by Evgeny Poberezkin on 17/01/2022.
|
|
|
|
//
|
|
|
|
|
|
|
|
import SwiftUI
|
2023-03-14 11:12:40 +03:00
|
|
|
import Intents
|
2022-09-07 12:49:41 +01:00
|
|
|
import SimpleXChat
|
2022-01-21 11:09:33 +00:00
|
|
|
|
|
|
|
struct ContentView: View {
|
2022-01-29 11:10:04 +00:00
|
|
|
@EnvironmentObject var chatModel: ChatModel
|
2022-02-12 15:59:43 +00:00
|
|
|
@ObservedObject var alertManager = AlertManager.shared
|
2022-05-24 19:34:27 +01:00
|
|
|
@ObservedObject var callController = CallController.shared
|
2022-05-28 22:09:46 +04:00
|
|
|
@Binding var doAuthenticate: Bool
|
2022-06-03 12:24:50 +01:00
|
|
|
@Binding var userAuthorized: Bool?
|
2022-05-28 22:09:46 +04:00
|
|
|
@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
|
2023-01-11 17:09:17 +00:00
|
|
|
@AppStorage(DEFAULT_PRIVACY_PROTECT_SCREEN) private var protectScreen = false
|
2022-11-25 21:43:10 +00:00
|
|
|
@AppStorage(DEFAULT_NOTIFICATION_ALERT_SHOWN) private var notificationAlertShown = false
|
2022-12-26 14:08:01 +00:00
|
|
|
@State private var showWhatsNew = false
|
2022-02-03 07:16:29 +00:00
|
|
|
|
2022-01-21 11:09:33 +00:00
|
|
|
var body: some View {
|
2022-05-09 09:52:09 +01:00
|
|
|
ZStack {
|
2022-06-03 09:16:07 +01:00
|
|
|
if prefPerformLA && userAuthorized != true {
|
|
|
|
Button(action: runAuthenticate) { Label("Unlock", systemImage: "lock") }
|
2022-09-07 12:49:41 +01:00
|
|
|
} else if let status = chatModel.chatDbStatus, status != .ok {
|
|
|
|
DatabaseErrorView(status: status)
|
2022-07-01 22:45:58 +01:00
|
|
|
} else if !chatModel.v3DBMigration.startChat {
|
|
|
|
MigrateToAppGroupView()
|
|
|
|
} else if let step = chatModel.onboardingStage {
|
|
|
|
if case .onboardingComplete = step,
|
|
|
|
chatModel.currentUser != nil {
|
2022-11-25 14:31:37 +00:00
|
|
|
mainView().privacySensitive(protectScreen)
|
2022-07-01 22:45:58 +01:00
|
|
|
} else {
|
|
|
|
OnboardingView(onboarding: step)
|
2022-02-26 20:21:32 +00:00
|
|
|
}
|
2022-05-09 09:52:09 +01:00
|
|
|
}
|
2022-01-22 17:54:22 +00:00
|
|
|
}
|
2022-06-24 13:52:20 +01:00
|
|
|
.onAppear {
|
|
|
|
if doAuthenticate { runAuthenticate() }
|
|
|
|
}
|
2022-06-03 09:16:07 +01:00
|
|
|
.onChange(of: doAuthenticate) { _ in if doAuthenticate { runAuthenticate() } }
|
2022-05-09 09:52:09 +01:00
|
|
|
.alert(isPresented: $alertManager.presentAlert) { alertManager.alertView! }
|
2022-02-09 22:53:06 +00:00
|
|
|
}
|
2022-02-12 15:59:43 +00:00
|
|
|
|
2022-06-24 13:52:20 +01:00
|
|
|
private func mainView() -> some View {
|
|
|
|
ZStack(alignment: .top) {
|
2022-07-26 10:55:58 +04:00
|
|
|
ChatListView()
|
2022-06-24 13:52:20 +01:00
|
|
|
.onAppear {
|
2022-11-25 21:43:10 +00:00
|
|
|
NtfManager.shared.requestAuthorization(
|
|
|
|
onDeny: {
|
|
|
|
if (!notificationAlertShown) {
|
|
|
|
notificationAlertShown = true
|
|
|
|
alertManager.showAlert(notificationAlert())
|
|
|
|
}
|
|
|
|
},
|
|
|
|
onAuthorized: { notificationAlertShown = false }
|
|
|
|
)
|
2022-06-24 13:52:20 +01:00
|
|
|
// Local Authentication notice is to be shown on next start after onboarding is complete
|
2022-12-30 20:17:56 +04:00
|
|
|
if (!prefLANoticeShown && prefShowLANotice && !chatModel.chats.isEmpty) {
|
2022-06-24 13:52:20 +01:00
|
|
|
prefLANoticeShown = true
|
|
|
|
alertManager.showAlert(laNoticeAlert())
|
2022-12-26 14:08:01 +00:00
|
|
|
} else if !chatModel.showCallView && CallController.shared.activeCallInvitation == nil {
|
|
|
|
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
|
2023-02-02 10:11:11 +00:00
|
|
|
if !showWhatsNew {
|
|
|
|
showWhatsNew = shouldShowWhatsNew()
|
|
|
|
}
|
2022-12-26 14:08:01 +00:00
|
|
|
}
|
2022-06-24 13:52:20 +01:00
|
|
|
}
|
|
|
|
prefShowLANotice = true
|
|
|
|
}
|
2022-12-26 14:08:01 +00:00
|
|
|
.sheet(isPresented: $showWhatsNew) {
|
|
|
|
WhatsNewView()
|
|
|
|
}
|
2022-06-24 13:52:20 +01:00
|
|
|
if chatModel.showCallView, let call = chatModel.activeCall {
|
|
|
|
ActiveCallView(call: call)
|
|
|
|
}
|
|
|
|
IncomingCallView()
|
|
|
|
}
|
2023-03-14 11:12:40 +03:00
|
|
|
.onContinueUserActivity("INStartCallIntent", perform: processUserActivity)
|
|
|
|
.onContinueUserActivity("INStartAudioCallIntent", perform: processUserActivity)
|
|
|
|
.onContinueUserActivity("INStartVideoCallIntent", perform: processUserActivity)
|
|
|
|
}
|
|
|
|
|
|
|
|
private func processUserActivity(_ activity: NSUserActivity) {
|
|
|
|
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)
|
|
|
|
}
|
2022-06-24 13:52:20 +01:00
|
|
|
}
|
|
|
|
|
2022-05-28 22:09:46 +04:00
|
|
|
private func runAuthenticate() {
|
|
|
|
if !prefPerformLA {
|
|
|
|
userAuthorized = true
|
2022-06-03 12:24:50 +01:00
|
|
|
} else {
|
2022-08-04 12:41:05 +01:00
|
|
|
dismissAllSheets(animated: false) {
|
2022-12-03 21:42:12 +00:00
|
|
|
chatModel.chatId = nil
|
2022-08-04 12:41:05 +01:00
|
|
|
justAuthenticate()
|
|
|
|
}
|
2022-06-03 12:24:50 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private func justAuthenticate() {
|
2022-06-03 13:05:34 +01:00
|
|
|
userAuthorized = false
|
2022-06-03 12:24:50 +01:00
|
|
|
authenticate(reason: NSLocalizedString("Unlock", comment: "authentication reason")) { laResult in
|
|
|
|
switch (laResult) {
|
|
|
|
case .success:
|
|
|
|
userAuthorized = true
|
|
|
|
case .failed:
|
2022-07-11 16:38:21 +04:00
|
|
|
break
|
2022-06-03 12:24:50 +01:00
|
|
|
case .unavailable:
|
|
|
|
userAuthorized = true
|
|
|
|
prefPerformLA = false
|
|
|
|
AlertManager.shared.showAlert(laUnavailableTurningOffAlert())
|
2022-05-28 22:09:46 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func laNoticeAlert() -> Alert {
|
|
|
|
Alert(
|
|
|
|
title: Text("SimpleX Lock"),
|
|
|
|
message: Text("To protect your information, turn on SimpleX Lock.\nYou will be prompted to complete authentication before this feature is enabled."),
|
|
|
|
primaryButton: .default(Text("Turn on")) {
|
2022-05-29 08:06:56 +01:00
|
|
|
authenticate(reason: NSLocalizedString("Enable SimpleX Lock", comment: "authentication reason")) { laResult in
|
2022-05-28 22:09:46 +04:00
|
|
|
switch laResult {
|
|
|
|
case .success:
|
|
|
|
prefPerformLA = true
|
|
|
|
alertManager.showAlert(laTurnedOnAlert())
|
|
|
|
case .failed:
|
|
|
|
prefPerformLA = false
|
|
|
|
alertManager.showAlert(laFailedAlert())
|
|
|
|
case .unavailable:
|
|
|
|
prefPerformLA = false
|
|
|
|
alertManager.showAlert(laUnavailableInstructionAlert())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
secondaryButton: .cancel()
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2022-02-12 15:59:43 +00:00
|
|
|
func notificationAlert() -> Alert {
|
|
|
|
Alert(
|
2022-04-16 09:37:01 +01:00
|
|
|
title: Text("Notifications are disabled!"),
|
2022-11-29 12:41:48 +04:00
|
|
|
message: Text("The app can notify you when you receive messages or contact requests - please open settings to enable."),
|
|
|
|
primaryButton: .default(Text("Open Settings")) {
|
|
|
|
DispatchQueue.main.async {
|
|
|
|
UIApplication.shared.open(URL(string: UIApplication.openSettingsURLString)!, options: [:], completionHandler: nil)
|
|
|
|
}
|
|
|
|
},
|
|
|
|
secondaryButton: .cancel()
|
|
|
|
)
|
2022-02-12 15:59:43 +00:00
|
|
|
}
|
2022-01-21 11:09:33 +00:00
|
|
|
}
|
|
|
|
|
2022-05-09 09:52:09 +01:00
|
|
|
func connectViaUrl() {
|
|
|
|
let m = ChatModel.shared
|
|
|
|
if let url = m.appOpenUrl {
|
|
|
|
m.appOpenUrl = nil
|
|
|
|
AlertManager.shared.showAlert(connectViaUrlAlert(url))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func connectViaUrlAlert(_ url: URL) -> Alert {
|
|
|
|
var path = url.path
|
|
|
|
logger.debug("ChatListView.connectViaUrlAlert path: \(path)")
|
|
|
|
if (path == "/contact" || path == "/invitation") {
|
|
|
|
path.removeFirst()
|
|
|
|
let action: ConnReqType = path == "contact" ? .contact : .invitation
|
|
|
|
let link = url.absoluteString.replacingOccurrences(of: "///\(path)", with: "/\(path)")
|
|
|
|
let title: LocalizedStringKey
|
|
|
|
if case .contact = action { title = "Connect via contact link?" }
|
|
|
|
else { title = "Connect via one-time link?" }
|
|
|
|
return Alert(
|
|
|
|
title: Text(title),
|
|
|
|
message: Text("Your profile will be sent to the contact that you received this link from"),
|
|
|
|
primaryButton: .default(Text("Connect")) {
|
|
|
|
connectViaLink(link)
|
|
|
|
},
|
|
|
|
secondaryButton: .cancel()
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
return Alert(title: Text("Error: URL is invalid"))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-12 15:59:43 +00:00
|
|
|
final class AlertManager: ObservableObject {
|
|
|
|
static let shared = AlertManager()
|
|
|
|
@Published var presentAlert = false
|
|
|
|
@Published var alertView: Alert?
|
|
|
|
|
|
|
|
func showAlert(_ alert: Alert) {
|
2022-02-14 11:53:44 +00:00
|
|
|
logger.debug("AlertManager.showAlert")
|
2022-04-02 14:35:35 +01:00
|
|
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
|
2022-02-12 15:59:43 +00:00
|
|
|
self.alertView = alert
|
|
|
|
self.presentAlert = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-16 09:37:01 +01:00
|
|
|
func showAlertMsg(title: LocalizedStringKey, message: LocalizedStringKey? = nil) {
|
2022-05-28 14:58:52 +04:00
|
|
|
showAlert(mkAlert(title: title, message: message))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func mkAlert(title: LocalizedStringKey, message: LocalizedStringKey? = nil) -> Alert {
|
|
|
|
if let message = message {
|
|
|
|
return Alert(title: Text(title), message: Text(message))
|
|
|
|
} else {
|
|
|
|
return Alert(title: Text(title))
|
2022-02-12 15:59:43 +00:00
|
|
|
}
|
|
|
|
}
|
2022-01-22 17:54:22 +00:00
|
|
|
|
|
|
|
//struct ContentView_Previews: PreviewProvider {
|
|
|
|
// static var previews: some View {
|
|
|
|
// ContentView(text: "Hello!")
|
|
|
|
// }
|
|
|
|
//}
|