diff --git a/Linphone/UI/Main/Conversations/Fragments/ConversationFragment.swift b/Linphone/UI/Main/Conversations/Fragments/ConversationFragment.swift index 4a60f942e..1bd1637d7 100644 --- a/Linphone/UI/Main/Conversations/Fragments/ConversationFragment.swift +++ b/Linphone/UI/Main/Conversations/Fragments/ConversationFragment.swift @@ -190,6 +190,7 @@ struct ConversationFragment: View { Spacer() Button { + conversationViewModel.displayedConversation!.call() } label: { Image("phone") .renderingMode(.template) diff --git a/Linphone/UI/Main/Conversations/Model/ConversationModel.swift b/Linphone/UI/Main/Conversations/Model/ConversationModel.swift index 2992f66d6..0e84f8a20 100644 --- a/Linphone/UI/Main/Conversations/Model/ConversationModel.swift +++ b/Linphone/UI/Main/Conversations/Model/ConversationModel.swift @@ -50,6 +50,8 @@ class ConversationModel: ObservableObject { @Published var unreadMessagesCount: Int @Published var avatarModel: ContactAvatarModel + private var conferenceSchedulerDelegate: ConferenceSchedulerDelegate? + init(chatRoom: ChatRoom) { self.chatRoom = chatRoom @@ -104,13 +106,97 @@ class ConversationModel: ObservableObject { } func call() { - coreContext.doOnCoreQueue { _ in - if self.chatRoom.peerAddress != nil { + coreContext.doOnCoreQueue { core in + if self.chatRoom.hasCapability(mask: ChatRoom.Capabilities.OneToOne.rawValue) && !self.chatRoom.hasCapability(mask: ChatRoom.Capabilities.Conference.rawValue) { TelecomManager.shared.doCallOrJoinConf(address: self.chatRoom.peerAddress!) + } else if self.chatRoom.hasCapability(mask: ChatRoom.Capabilities.OneToOne.rawValue) && self.chatRoom.hasCapability(mask: ChatRoom.Capabilities.Conference.rawValue) { + if self.chatRoom.participants.first != nil && self.chatRoom.participants.first!.address != nil { + TelecomManager.shared.doCallOrJoinConf(address: self.chatRoom.participants.first!.address!) + } + } else { + //self.createGroupCall(core: core) } } } + func createGroupCall(core: Core) { + let account = core.defaultAccount + if account == nil { + Log.error( + "\(ConversationModel.TAG) No default account found, can't create group call!" + ) + return + } + + do { + let conferenceInfo = try Factory.Instance.createConferenceInfo() + conferenceInfo.organizer = account!.params?.identityAddress + conferenceInfo.subject = self.chatRoom.subject ?? "Conference" + + var participantsList: [ParticipantInfo] = [] + self.chatRoom.participants.forEach { participant in + do { + let info = try Factory.Instance.createParticipantInfo(address: participant.address!) + // For meetings, all participants must have Speaker role + info.role = Participant.Role.Speaker + participantsList.append(info) + } catch let error { + Log.error( + "\(ConversationModel.TAG) Can't create ParticipantInfo: \(error)" + ) + } + } + + conferenceInfo.addParticipantInfos(participantInfos: participantsList) + + Log.info( + "\(ConversationModel.TAG) Creating group call with subject \(self.chatRoom.subject ?? "Conference") and \(participantsList.count) participant(s)" + ) + + let conferenceScheduler = try core.createConferenceScheduler() + self.conferenceAddDelegate(core: core, conferenceScheduler: conferenceScheduler) + conferenceScheduler.account = account + // Will trigger the conference creation/update automatically + conferenceScheduler.info = conferenceInfo + } catch let error { + Log.error( + "\(ConversationModel.TAG) createGroupCall: \(error)" + ) + } + } + + func conferenceAddDelegate(core: Core, conferenceScheduler: ConferenceScheduler) { + self.conferenceSchedulerDelegate = ConferenceSchedulerDelegateStub(onStateChanged: { (conferenceScheduler: ConferenceScheduler, state: ConferenceScheduler.State) in + Log.info("\(ConversationModel.TAG) Conference scheduler state is \(state)") + if state == ConferenceScheduler.State.Ready { + conferenceScheduler.removeDelegate(delegate: self.conferenceSchedulerDelegate!) + self.conferenceSchedulerDelegate = nil + + let conferenceAddress = conferenceScheduler.info?.uri + if conferenceAddress != nil { + Log.info( + "\(ConversationModel.TAG) Conference info created, address is \(conferenceAddress?.asStringUriOnly() ?? "Error conference address")" + ) + + TelecomManager.shared.doCallOrJoinConf(address: conferenceAddress!) + } else { + Log.error("\(ConversationModel.TAG) Conference info URI is null!") + + ToastViewModel.shared.toastMessage = "Failed_to_create_group_call_error" + ToastViewModel.shared.displayToast = true + } + } else if state == ConferenceScheduler.State.Error { + conferenceScheduler.removeDelegate(delegate: self.conferenceSchedulerDelegate!) + self.conferenceSchedulerDelegate = nil + Log.error("\(ConversationModel.TAG) Failed to create group call!") + + ToastViewModel.shared.toastMessage = "Failed_to_create_group_call_error" + ToastViewModel.shared.displayToast = true + } + }) + conferenceScheduler.addDelegate(delegate: self.conferenceSchedulerDelegate!) + } + func getContentTextMessage() { coreContext.doOnCoreQueue { _ in let lastMessage = self.chatRoom.lastMessageInHistory diff --git a/Linphone/UI/Main/History/ViewModel/StartCallViewModel.swift b/Linphone/UI/Main/History/ViewModel/StartCallViewModel.swift index 03fcb657e..4270d7fc5 100644 --- a/Linphone/UI/Main/History/ViewModel/StartCallViewModel.swift +++ b/Linphone/UI/Main/History/ViewModel/StartCallViewModel.swift @@ -94,7 +94,9 @@ class StartCallViewModel: ObservableObject { } } - self.participants.removeAll() + DispatchQueue.main.async { + self.participants.removeAll() + } conferenceInfo.addParticipantInfos(participantInfos: participantsList) @@ -102,7 +104,7 @@ class StartCallViewModel: ObservableObject { "\(StartCallViewModel.TAG) Creating group call with subject \(self.messageText) and \(participantsList.count) participant(s)" ) - let conferenceScheduler = try core.createConferenceScheduler() + let conferenceScheduler = try core.createConferenceScheduler(account: account) self.conferenceAddDelegate(core: core, conferenceScheduler: conferenceScheduler) conferenceScheduler.account = account // Will trigger the conference creation/update automatically