Merge branch 'ios-notifications' into ep/ios-file-provider
This commit is contained in:
commit
e15d4ac6b6
@ -11,7 +11,7 @@ android {
|
|||||||
applicationId "chat.simplex.app"
|
applicationId "chat.simplex.app"
|
||||||
minSdk 29
|
minSdk 29
|
||||||
targetSdk 32
|
targetSdk 32
|
||||||
versionCode 35
|
versionCode 36
|
||||||
versionName "2.2"
|
versionName "2.2"
|
||||||
|
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
@ -100,6 +100,7 @@ class MainActivity: FragmentActivity(), LifecycleEventObserver {
|
|||||||
userAuthorized.value = true
|
userAuthorized.value = true
|
||||||
} else {
|
} else {
|
||||||
userAuthorized.value = false
|
userAuthorized.value = false
|
||||||
|
ModalManager.shared.closeModals()
|
||||||
authenticate(
|
authenticate(
|
||||||
generalGetString(R.string.auth_unlock),
|
generalGetString(R.string.auth_unlock),
|
||||||
generalGetString(R.string.auth_log_in_using_credential),
|
generalGetString(R.string.auth_log_in_using_credential),
|
||||||
@ -241,7 +242,9 @@ fun MainPage(
|
|||||||
// this with LaunchedEffect(userAuthorized.value) fixes bottom sheet visibly collapsing after authentication
|
// this with LaunchedEffect(userAuthorized.value) fixes bottom sheet visibly collapsing after authentication
|
||||||
var chatsAccessAuthorized by remember { mutableStateOf(false) }
|
var chatsAccessAuthorized by remember { mutableStateOf(false) }
|
||||||
LaunchedEffect(userAuthorized.value) {
|
LaunchedEffect(userAuthorized.value) {
|
||||||
delay(500L)
|
if (chatModel.controller.appPrefs.performLA.get()) {
|
||||||
|
delay(500L)
|
||||||
|
}
|
||||||
chatsAccessAuthorized = userAuthorized.value == true
|
chatsAccessAuthorized = userAuthorized.value == true
|
||||||
}
|
}
|
||||||
var showAdvertiseLAAlert by remember { mutableStateOf(false) }
|
var showAdvertiseLAAlert by remember { mutableStateOf(false) }
|
||||||
|
@ -70,18 +70,21 @@ struct ContentView: View {
|
|||||||
if !prefPerformLA {
|
if !prefPerformLA {
|
||||||
userAuthorized = true
|
userAuthorized = true
|
||||||
} else {
|
} else {
|
||||||
userAuthorized = false
|
chatModel.showChatInfo = false
|
||||||
authenticate(reason: NSLocalizedString("Unlock", comment: "authentication reason")) { laResult in
|
DispatchQueue.main.async() {
|
||||||
switch (laResult) {
|
userAuthorized = false
|
||||||
case .success:
|
authenticate(reason: NSLocalizedString("Unlock", comment: "authentication reason")) { laResult in
|
||||||
userAuthorized = true
|
switch (laResult) {
|
||||||
case .failed:
|
case .success:
|
||||||
laFailed = true
|
userAuthorized = true
|
||||||
AlertManager.shared.showAlert(laFailedAlert())
|
case .failed:
|
||||||
case .unavailable:
|
laFailed = true
|
||||||
userAuthorized = true
|
AlertManager.shared.showAlert(laFailedAlert())
|
||||||
prefPerformLA = false
|
case .unavailable:
|
||||||
AlertManager.shared.showAlert(laUnavailableTurningOffAlert())
|
userAuthorized = true
|
||||||
|
prefPerformLA = false
|
||||||
|
AlertManager.shared.showAlert(laUnavailableTurningOffAlert())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ import SimpleXChat
|
|||||||
final class ChatModel: ObservableObject {
|
final class ChatModel: ObservableObject {
|
||||||
@Published var onboardingStage: OnboardingStage?
|
@Published var onboardingStage: OnboardingStage?
|
||||||
@Published var currentUser: User?
|
@Published var currentUser: User?
|
||||||
|
@Published var showChatInfo: Bool = false // TODO comprehensively close modal views on authentication
|
||||||
// list of chat "previews"
|
// list of chat "previews"
|
||||||
@Published var chats: [Chat] = []
|
@Published var chats: [Chat] = []
|
||||||
// current chat
|
// current chat
|
||||||
|
@ -11,7 +11,6 @@ import UIKit
|
|||||||
import Dispatch
|
import Dispatch
|
||||||
import BackgroundTasks
|
import BackgroundTasks
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
import CallKit
|
|
||||||
import SimpleXChat
|
import SimpleXChat
|
||||||
|
|
||||||
private var chatController: chat_ctrl?
|
private var chatController: chat_ctrl?
|
||||||
@ -681,7 +680,7 @@ func processReceivedMsg(_ res: ChatResponse) {
|
|||||||
}
|
}
|
||||||
withCall(contact) { call in
|
withCall(contact) { call in
|
||||||
m.callCommand = .end
|
m.callCommand = .end
|
||||||
CallController.shared.reportCallRemoteEnded(call: call)
|
// CallController.shared.reportCallRemoteEnded(call: call)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
logger.debug("unsupported event: \(res.responseType)")
|
logger.debug("unsupported event: \(res.responseType)")
|
||||||
|
@ -94,9 +94,9 @@ struct ActiveCallView: View {
|
|||||||
case let .connection(state):
|
case let .connection(state):
|
||||||
if let callStatus = WebRTCCallStatus.init(rawValue: state.connectionState),
|
if let callStatus = WebRTCCallStatus.init(rawValue: state.connectionState),
|
||||||
case .connected = callStatus {
|
case .connected = callStatus {
|
||||||
if case .outgoing = call.direction {
|
// if case .outgoing = call.direction {
|
||||||
CallController.shared.reportOutgoingCall(call: call, connectedAt: nil)
|
// CallController.shared.reportOutgoingCall(call: call, connectedAt: nil)
|
||||||
}
|
// }
|
||||||
call.callState = .connected
|
call.callState = .connected
|
||||||
// CallKit doesn't work well with WKWebView
|
// CallKit doesn't work well with WKWebView
|
||||||
// This is a hack to enable microphone in WKWebView after CallKit takes over it
|
// This is a hack to enable microphone in WKWebView after CallKit takes over it
|
||||||
|
@ -7,91 +7,92 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
import CallKit
|
//import CallKit
|
||||||
import AVFoundation
|
import AVFoundation
|
||||||
import SimpleXChat
|
import SimpleXChat
|
||||||
|
|
||||||
class CallController: NSObject, CXProviderDelegate, ObservableObject {
|
//class CallController: NSObject, CXProviderDelegate, ObservableObject {
|
||||||
|
class CallController: NSObject, ObservableObject {
|
||||||
static let useCallKit = false
|
static let useCallKit = false
|
||||||
static let shared = CallController()
|
static let shared = CallController()
|
||||||
private let provider = CXProvider(configuration: CallController.configuration)
|
// private let provider = CXProvider(configuration: CallController.configuration)
|
||||||
private let controller = CXCallController()
|
// private let controller = CXCallController()
|
||||||
private let callManager = CallManager()
|
private let callManager = CallManager()
|
||||||
@Published var activeCallInvitation: CallInvitation?
|
@Published var activeCallInvitation: CallInvitation?
|
||||||
|
|
||||||
// PKPushRegistry will be used from notification service extension
|
// PKPushRegistry will be used from notification service extension
|
||||||
// let registry = PKPushRegistry(queue: nil)
|
// let registry = PKPushRegistry(queue: nil)
|
||||||
|
|
||||||
static let configuration: CXProviderConfiguration = {
|
// static let configuration: CXProviderConfiguration = {
|
||||||
let configuration = CXProviderConfiguration()
|
// let configuration = CXProviderConfiguration()
|
||||||
configuration.supportsVideo = true
|
// configuration.supportsVideo = true
|
||||||
configuration.supportedHandleTypes = [.generic]
|
// configuration.supportedHandleTypes = [.generic]
|
||||||
configuration.includesCallsInRecents = true // TODO disable or add option
|
// configuration.includesCallsInRecents = true // TODO disable or add option
|
||||||
configuration.maximumCallsPerCallGroup = 1
|
// configuration.maximumCallsPerCallGroup = 1
|
||||||
return configuration
|
// return configuration
|
||||||
}()
|
// }()
|
||||||
|
|
||||||
override init() {
|
override init() {
|
||||||
super.init()
|
super.init()
|
||||||
self.provider.setDelegate(self, queue: nil)
|
// self.provider.setDelegate(self, queue: nil)
|
||||||
// self.registry.delegate = self
|
// self.registry.delegate = self
|
||||||
// self.registry.desiredPushTypes = [.voIP]
|
// self.registry.desiredPushTypes = [.voIP]
|
||||||
}
|
}
|
||||||
|
|
||||||
func providerDidReset(_ provider: CXProvider) {
|
// func providerDidReset(_ provider: CXProvider) {
|
||||||
}
|
// }
|
||||||
|
|
||||||
func provider(_ provider: CXProvider, perform action: CXStartCallAction) {
|
// func provider(_ provider: CXProvider, perform action: CXStartCallAction) {
|
||||||
logger.debug("CallController.provider CXStartCallAction")
|
// logger.debug("CallController.provider CXStartCallAction")
|
||||||
if callManager.startOutgoingCall(callUUID: action.callUUID) {
|
// if callManager.startOutgoingCall(callUUID: action.callUUID) {
|
||||||
action.fulfill()
|
// action.fulfill()
|
||||||
provider.reportOutgoingCall(with: action.callUUID, startedConnectingAt: nil)
|
// provider.reportOutgoingCall(with: action.callUUID, startedConnectingAt: nil)
|
||||||
} else {
|
// } else {
|
||||||
action.fail()
|
// action.fail()
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) {
|
|
||||||
logger.debug("CallController.provider CXAnswerCallAction")
|
|
||||||
if callManager.answerIncomingCall(callUUID: action.callUUID) {
|
|
||||||
action.fulfill()
|
|
||||||
} else {
|
|
||||||
action.fail()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func provider(_ provider: CXProvider, perform action: CXEndCallAction) {
|
|
||||||
logger.debug("CallController.provider CXEndCallAction")
|
|
||||||
callManager.endCall(callUUID: action.callUUID) { ok in
|
|
||||||
if ok {
|
|
||||||
action.fulfill()
|
|
||||||
} else {
|
|
||||||
action.fail()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func provider(_ provider: CXProvider, timedOutPerforming action: CXAction) {
|
|
||||||
print("timed out", #function)
|
|
||||||
action.fulfill()
|
|
||||||
}
|
|
||||||
|
|
||||||
func provider(_ provider: CXProvider, didActivate audioSession: AVAudioSession) {
|
|
||||||
print("received", #function)
|
|
||||||
// do {
|
|
||||||
// try audioSession.setCategory(.playAndRecord, mode: .voiceChat, options: .mixWithOthers)
|
|
||||||
// logger.debug("audioSession category set")
|
|
||||||
// try audioSession.setActive(true)
|
|
||||||
// logger.debug("audioSession activated")
|
|
||||||
// } catch {
|
|
||||||
// print(error)
|
|
||||||
// logger.error("failed activating audio session")
|
|
||||||
// }
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
func provider(_ provider: CXProvider, didDeactivate audioSession: AVAudioSession) {
|
// func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) {
|
||||||
print("received", #function)
|
// logger.debug("CallController.provider CXAnswerCallAction")
|
||||||
}
|
// if callManager.answerIncomingCall(callUUID: action.callUUID) {
|
||||||
|
// action.fulfill()
|
||||||
|
// } else {
|
||||||
|
// action.fail()
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func provider(_ provider: CXProvider, perform action: CXEndCallAction) {
|
||||||
|
// logger.debug("CallController.provider CXEndCallAction")
|
||||||
|
// callManager.endCall(callUUID: action.callUUID) { ok in
|
||||||
|
// if ok {
|
||||||
|
// action.fulfill()
|
||||||
|
// } else {
|
||||||
|
// action.fail()
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func provider(_ provider: CXProvider, timedOutPerforming action: CXAction) {
|
||||||
|
// print("timed out", #function)
|
||||||
|
// action.fulfill()
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func provider(_ provider: CXProvider, didActivate audioSession: AVAudioSession) {
|
||||||
|
// print("received", #function)
|
||||||
|
//// do {
|
||||||
|
//// try audioSession.setCategory(.playAndRecord, mode: .voiceChat, options: .mixWithOthers)
|
||||||
|
//// logger.debug("audioSession category set")
|
||||||
|
//// try audioSession.setActive(true)
|
||||||
|
//// logger.debug("audioSession activated")
|
||||||
|
//// } catch {
|
||||||
|
//// print(error)
|
||||||
|
//// logger.error("failed activating audio session")
|
||||||
|
//// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func provider(_ provider: CXProvider, didDeactivate audioSession: AVAudioSession) {
|
||||||
|
// print("received", #function)
|
||||||
|
// }
|
||||||
|
|
||||||
// func pushRegistry(_ registry: PKPushRegistry, didUpdate pushCredentials: PKPushCredentials, for type: PKPushType) {
|
// func pushRegistry(_ registry: PKPushRegistry, didUpdate pushCredentials: PKPushCredentials, for type: PKPushType) {
|
||||||
//
|
//
|
||||||
@ -122,48 +123,49 @@ class CallController: NSObject, CXProviderDelegate, ObservableObject {
|
|||||||
func reportNewIncomingCall(invitation: CallInvitation, completion: @escaping (Error?) -> Void) {
|
func reportNewIncomingCall(invitation: CallInvitation, completion: @escaping (Error?) -> Void) {
|
||||||
logger.debug("CallController.reportNewIncomingCall")
|
logger.debug("CallController.reportNewIncomingCall")
|
||||||
if !UserDefaults.standard.bool(forKey: DEFAULT_EXPERIMENTAL_CALLS) { return }
|
if !UserDefaults.standard.bool(forKey: DEFAULT_EXPERIMENTAL_CALLS) { return }
|
||||||
if CallController.useCallKit, let uuid = invitation.callkitUUID {
|
// if CallController.useCallKit, let uuid = invitation.callkitUUID {
|
||||||
let update = CXCallUpdate()
|
// let update = CXCallUpdate()
|
||||||
update.remoteHandle = CXHandle(type: .generic, value: invitation.contact.displayName)
|
// update.remoteHandle = CXHandle(type: .generic, value: invitation.contact.displayName)
|
||||||
update.hasVideo = invitation.peerMedia == .video
|
// update.hasVideo = invitation.peerMedia == .video
|
||||||
provider.reportNewIncomingCall(with: uuid, update: update, completion: completion)
|
// provider.reportNewIncomingCall(with: uuid, update: update, completion: completion)
|
||||||
} else {
|
// } else {
|
||||||
NtfManager.shared.notifyCallInvitation(invitation)
|
NtfManager.shared.notifyCallInvitation(invitation)
|
||||||
if invitation.callTs.timeIntervalSinceNow >= -180 {
|
if invitation.callTs.timeIntervalSinceNow >= -180 {
|
||||||
activeCallInvitation = invitation
|
activeCallInvitation = invitation
|
||||||
}
|
}
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
func reportOutgoingCall(call: Call, connectedAt dateConnected: Date?) {
|
// func reportOutgoingCall(call: Call, connectedAt dateConnected: Date?) {
|
||||||
if CallController.useCallKit, let uuid = call.callkitUUID {
|
// if CallController.useCallKit, let uuid = call.callkitUUID {
|
||||||
provider.reportOutgoingCall(with: uuid, connectedAt: dateConnected)
|
// provider.reportOutgoingCall(with: uuid, connectedAt: dateConnected)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
func reportCallRemoteEnded(invitation: CallInvitation) {
|
func reportCallRemoteEnded(invitation: CallInvitation) {
|
||||||
if CallController.useCallKit, let uuid = invitation.callkitUUID {
|
// if CallController.useCallKit, let uuid = invitation.callkitUUID {
|
||||||
provider.reportCall(with: uuid, endedAt: nil, reason: .remoteEnded)
|
// provider.reportCall(with: uuid, endedAt: nil, reason: .remoteEnded)
|
||||||
} else if invitation.contact.id == activeCallInvitation?.contact.id {
|
// } else if invitation.contact.id == activeCallInvitation?.contact.id {
|
||||||
activeCallInvitation = nil
|
activeCallInvitation = nil
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
func reportCallRemoteEnded(call: Call) {
|
// func reportCallRemoteEnded(call: Call) {
|
||||||
if CallController.useCallKit, let uuid = call.callkitUUID {
|
// if CallController.useCallKit, let uuid = call.callkitUUID {
|
||||||
provider.reportCall(with: uuid, endedAt: nil, reason: .remoteEnded)
|
// provider.reportCall(with: uuid, endedAt: nil, reason: .remoteEnded)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
func startCall(_ contact: Contact, _ media: CallMediaType) {
|
func startCall(_ contact: Contact, _ media: CallMediaType) {
|
||||||
logger.debug("CallController.startCall")
|
logger.debug("CallController.startCall")
|
||||||
let uuid = callManager.newOutgoingCall(contact, media)
|
let uuid = callManager.newOutgoingCall(contact, media)
|
||||||
if CallController.useCallKit {
|
// if CallController.useCallKit {
|
||||||
let handle = CXHandle(type: .generic, value: contact.displayName)
|
// let handle = CXHandle(type: .generic, value: contact.displayName)
|
||||||
let action = CXStartCallAction(call: uuid, handle: handle)
|
// let action = CXStartCallAction(call: uuid, handle: handle)
|
||||||
action.isVideo = media == .video
|
// action.isVideo = media == .video
|
||||||
requestTransaction(with: action)
|
// requestTransaction(with: action)
|
||||||
} else if callManager.startOutgoingCall(callUUID: uuid) {
|
// } else if callManager.startOutgoingCall(callUUID: uuid) {
|
||||||
|
if callManager.startOutgoingCall(callUUID: uuid) {
|
||||||
logger.debug("CallController.startCall: call started")
|
logger.debug("CallController.startCall: call started")
|
||||||
} else {
|
} else {
|
||||||
logger.error("CallController.startCall: no active call")
|
logger.error("CallController.startCall: no active call")
|
||||||
@ -178,9 +180,9 @@ class CallController: NSObject, CXProviderDelegate, ObservableObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func endCall(callUUID: UUID) {
|
func endCall(callUUID: UUID) {
|
||||||
if CallController.useCallKit {
|
// if CallController.useCallKit {
|
||||||
requestTransaction(with: CXEndCallAction(call: callUUID))
|
// requestTransaction(with: CXEndCallAction(call: callUUID))
|
||||||
} else {
|
// } else {
|
||||||
callManager.endCall(callUUID: callUUID) { ok in
|
callManager.endCall(callUUID: callUUID) { ok in
|
||||||
if ok {
|
if ok {
|
||||||
logger.debug("CallController.endCall: call ended")
|
logger.debug("CallController.endCall: call ended")
|
||||||
@ -188,7 +190,7 @@ class CallController: NSObject, CXProviderDelegate, ObservableObject {
|
|||||||
logger.error("CallController.endCall: no actove call pr call invitation to end")
|
logger.error("CallController.endCall: no actove call pr call invitation to end")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
func endCall(invitation: CallInvitation) {
|
func endCall(invitation: CallInvitation) {
|
||||||
@ -205,15 +207,15 @@ class CallController: NSObject, CXProviderDelegate, ObservableObject {
|
|||||||
callManager.endCall(call: call, completed: completed)
|
callManager.endCall(call: call, completed: completed)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func requestTransaction(with action: CXAction) {
|
// private func requestTransaction(with action: CXAction) {
|
||||||
let t = CXTransaction()
|
// let t = CXTransaction()
|
||||||
t.addAction(action)
|
// t.addAction(action)
|
||||||
controller.request(t) { error in
|
// controller.request(t) { error in
|
||||||
if let error = error {
|
// if let error = error {
|
||||||
logger.error("CallController.requestTransaction error requesting transaction: \(error.localizedDescription)")
|
// logger.error("CallController.requestTransaction error requesting transaction: \(error.localizedDescription)")
|
||||||
} else {
|
// } else {
|
||||||
logger.debug("CallController.requestTransaction requested transaction successfully")
|
// logger.debug("CallController.requestTransaction requested transaction successfully")
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,6 @@ struct ChatInfoView: View {
|
|||||||
@EnvironmentObject var chatModel: ChatModel
|
@EnvironmentObject var chatModel: ChatModel
|
||||||
@ObservedObject var alertManager = AlertManager.shared
|
@ObservedObject var alertManager = AlertManager.shared
|
||||||
@ObservedObject var chat: Chat
|
@ObservedObject var chat: Chat
|
||||||
@Binding var showChatInfo: Bool
|
|
||||||
@State var alert: ChatInfoViewAlert? = nil
|
@State var alert: ChatInfoViewAlert? = nil
|
||||||
@State var deletingContact: Contact?
|
@State var deletingContact: Contact?
|
||||||
|
|
||||||
@ -100,7 +99,7 @@ struct ChatInfoView: View {
|
|||||||
try await apiDeleteChat(type: .direct, id: contact.apiId)
|
try await apiDeleteChat(type: .direct, id: contact.apiId)
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
chatModel.removeChat(contact.id)
|
chatModel.removeChat(contact.id)
|
||||||
showChatInfo = false
|
chatModel.showChatInfo = false
|
||||||
}
|
}
|
||||||
} catch let error {
|
} catch let error {
|
||||||
logger.error("ChatInfoView.deleteContactAlert apiDeleteChat error: \(error.localizedDescription)")
|
logger.error("ChatInfoView.deleteContactAlert apiDeleteChat error: \(error.localizedDescription)")
|
||||||
@ -119,7 +118,7 @@ struct ChatInfoView: View {
|
|||||||
Task {
|
Task {
|
||||||
await clearChat(chat)
|
await clearChat(chat)
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
showChatInfo = false
|
chatModel.showChatInfo = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -131,6 +130,6 @@ struct ChatInfoView: View {
|
|||||||
struct ChatInfoView_Previews: PreviewProvider {
|
struct ChatInfoView_Previews: PreviewProvider {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
@State var showChatInfo = true
|
@State var showChatInfo = true
|
||||||
return ChatInfoView(chat: Chat(chatInfo: ChatInfo.sampleData.direct, chatItems: []), showChatInfo: $showChatInfo)
|
return ChatInfoView(chat: Chat(chatInfo: ChatInfo.sampleData.direct, chatItems: []))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,6 @@ struct ChatView: View {
|
|||||||
@State private var composeState = ComposeState()
|
@State private var composeState = ComposeState()
|
||||||
@State private var deletingItem: ChatItem? = nil
|
@State private var deletingItem: ChatItem? = nil
|
||||||
@FocusState private var keyboardVisible: Bool
|
@FocusState private var keyboardVisible: Bool
|
||||||
@State private var showChatInfo = false
|
|
||||||
@State private var showDeleteMessage = false
|
@State private var showDeleteMessage = false
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
@ -99,12 +98,12 @@ struct ChatView: View {
|
|||||||
}
|
}
|
||||||
ToolbarItem(placement: .principal) {
|
ToolbarItem(placement: .principal) {
|
||||||
Button {
|
Button {
|
||||||
showChatInfo = true
|
chatModel.showChatInfo = true
|
||||||
} label: {
|
} label: {
|
||||||
ChatInfoToolbar(chat: chat)
|
ChatInfoToolbar(chat: chat)
|
||||||
}
|
}
|
||||||
.sheet(isPresented: $showChatInfo) {
|
.sheet(isPresented: $chatModel.showChatInfo) {
|
||||||
ChatInfoView(chat: chat, showChatInfo: $showChatInfo)
|
ChatInfoView(chat: chat)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ToolbarItem(placement: .navigationBarTrailing) {
|
ToolbarItem(placement: .navigationBarTrailing) {
|
||||||
|
@ -1505,7 +1505,7 @@
|
|||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements";
|
CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 49;
|
CURRENT_PROJECT_VERSION = 51;
|
||||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
@ -1548,7 +1548,7 @@
|
|||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements";
|
CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 49;
|
CURRENT_PROJECT_VERSION = 51;
|
||||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
@ -1629,7 +1629,7 @@
|
|||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements";
|
CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 49;
|
CURRENT_PROJECT_VERSION = 51;
|
||||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
@ -1668,7 +1668,7 @@
|
|||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements";
|
CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 49;
|
CURRENT_PROJECT_VERSION = 51;
|
||||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
name: simplex-chat
|
name: simplex-chat
|
||||||
version: 2.1.0
|
version: 2.2.0
|
||||||
#synopsis:
|
#synopsis:
|
||||||
#description:
|
#description:
|
||||||
homepage: https://github.com/simplex-chat/simplex-chat#readme
|
homepage: https://github.com/simplex-chat/simplex-chat#readme
|
||||||
|
@ -5,7 +5,7 @@ cabal-version: 1.12
|
|||||||
-- see: https://github.com/sol/hpack
|
-- see: https://github.com/sol/hpack
|
||||||
|
|
||||||
name: simplex-chat
|
name: simplex-chat
|
||||||
version: 2.1.0
|
version: 2.2.0
|
||||||
category: Web, System, Services, Cryptography
|
category: Web, System, Services, Cryptography
|
||||||
homepage: https://github.com/simplex-chat/simplex-chat#readme
|
homepage: https://github.com/simplex-chat/simplex-chat#readme
|
||||||
author: simplex.chat
|
author: simplex.chat
|
||||||
|
Loading…
Reference in New Issue
Block a user