From ed619e58e11c1055e13c4302abe665af74fde575 Mon Sep 17 00:00:00 2001 From: Benoit Martins Date: Wed, 23 Oct 2024 16:55:30 +0200 Subject: [PATCH] Fix group call creation --- Linphone/Localizable.xcstrings | 34 +++++++ Linphone/UI/Call/CallView.swift | 14 ++- .../UI/Call/ViewModel/CallViewModel.swift | 11 ++- Linphone/UI/Main/ContentView.swift | 31 ++++++- .../Fragments/ConversationFragment.swift | 7 +- .../Model/ConversationModel.swift | 92 ++++++++++--------- .../ViewModel/StartCallViewModel.swift | 12 ++- 7 files changed, 145 insertions(+), 56 deletions(-) diff --git a/Linphone/Localizable.xcstrings b/Linphone/Localizable.xcstrings index d1c538639..97bfe9292 100644 --- a/Linphone/Localizable.xcstrings +++ b/Linphone/Localizable.xcstrings @@ -1252,6 +1252,40 @@ } } }, + "conversation_info_confirm_start_group_call_dialog_message" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "All participants will receive a call." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tous les participants de la conversation recevront un appel." + } + } + } + }, + "conversation_info_confirm_start_group_call_dialog_title" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Start a group call?" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Démarrer un appel de groupe ?" + } + } + } + }, "conversation_invalid_participant_due_to_security_mode_toast" : { "extractionState" : "manual", "localizations" : { diff --git a/Linphone/UI/Call/CallView.swift b/Linphone/UI/Call/CallView.swift index 7ef1d8a93..786b561d7 100644 --- a/Linphone/UI/Call/CallView.swift +++ b/Linphone/UI/Call/CallView.swift @@ -65,6 +65,7 @@ struct CallView: View { @State var isShowParticipantsListFragment: Bool = false @Binding var isShowStartCallFragment: Bool @Binding var isShowConversationFragment: Bool + @Binding var isShowStartCallGroupPopup: Bool @State var buttonSize = 60.0 @@ -197,7 +198,8 @@ struct CallView: View { conversationViewModel: conversationViewModel, conversationsListViewModel: conversationsListViewModel, conversationForwardMessageViewModel: conversationForwardMessageViewModel, - isShowConversationFragment: $isShowConversationFragment + isShowConversationFragment: $isShowConversationFragment, + isShowStartCallGroupPopup: $isShowStartCallGroupPopup ) .frame(maxWidth: .infinity) .background(Color.gray100) @@ -675,6 +677,13 @@ struct CallView: View { maxWidth: fullscreenVideo && !telecomManager.isPausedByRemote ? geometry.size.width : geometry.size.width - 8, maxHeight: fullscreenVideo && !telecomManager.isPausedByRemote ? geometry.size.height + geometry.safeAreaInsets.top + geometry.safeAreaInsets.bottom : geometry.size.height - (minBottomSheetHeight * geometry.size.height > 80 ? minBottomSheetHeight * geometry.size.height : 78) - 40 - 20 + geometry.safeAreaInsets.bottom ) + } else if telecomManager.outgoingCallStarted { + ProgressView() + .progressViewStyle(CircularProgressViewStyle(tint: .white)) + .frame(width: 60, height: 60, alignment: .center) + .onDisappear { + callViewModel.resetCallView() + } } if callViewModel.isRecording { @@ -2781,7 +2790,8 @@ struct PressedButtonStyle: ButtonStyle { conversationForwardMessageViewModel: ConversationForwardMessageViewModel(), fullscreenVideo: .constant(false), isShowStartCallFragment: .constant(false), - isShowConversationFragment: .constant(false) + isShowConversationFragment: .constant(false), + isShowStartCallGroupPopup: .constant(false) ) } // swiftlint:enable type_body_length diff --git a/Linphone/UI/Call/ViewModel/CallViewModel.swift b/Linphone/UI/Call/ViewModel/CallViewModel.swift index 6ce03614d..a3ce8d591 100644 --- a/Linphone/UI/Call/ViewModel/CallViewModel.swift +++ b/Linphone/UI/Call/ViewModel/CallViewModel.swift @@ -98,6 +98,10 @@ class CallViewModel: ObservableObject { } func resetCallView() { + DispatchQueue.main.async { + self.displayName = "" + } + coreContext.doOnCoreQueue { core in if core.currentCall != nil && core.currentCall!.remoteAddress != nil { if self.callDelegate != nil { @@ -123,12 +127,16 @@ class CallViewModel: ObservableObject { } + var displayNameTmp = "" + var isOneOneCallTmp = false if self.currentCall?.remoteAddress != nil { let conf = self.currentCall!.conference let confInfo = core.findConferenceInformationFromUri(uri: self.currentCall!.remoteAddress!) if conf == nil && confInfo == nil { isOneOneCallTmp = true + } else { + displayNameTmp = confInfo?.subject ?? "Conference-focus" } } @@ -151,7 +159,6 @@ class CallViewModel: ObservableObject { let remoteAddressStringTmp = remoteAddressTmp != nil ? String(remoteAddressTmp!.asStringUriOnly().dropFirst(4)) : "" - var displayNameTmp = "" if self.currentCall?.conference != nil { displayNameTmp = self.currentCall?.conference?.subject ?? "" } else if self.currentCall?.remoteAddress != nil { @@ -161,7 +168,7 @@ class CallViewModel: ObservableObject { } else { if self.currentCall!.remoteAddress!.displayName != nil { displayNameTmp = self.currentCall!.remoteAddress!.displayName! - } else if self.currentCall!.remoteAddress!.username != nil { + } else if self.currentCall!.remoteAddress!.username != nil && displayNameTmp.isEmpty { displayNameTmp = self.currentCall!.remoteAddress!.username! } } diff --git a/Linphone/UI/Main/ContentView.swift b/Linphone/UI/Main/ContentView.swift index 599143a0d..64c4dd3b7 100644 --- a/Linphone/UI/Main/ContentView.swift +++ b/Linphone/UI/Main/ContentView.swift @@ -66,6 +66,7 @@ struct ContentView: View { @State var isShowStartConversationFragment = false @State var isShowDismissPopup = false @State var isShowSendCancelMeetingNotificationPopup = false + @State var isShowStartCallGroupPopup = false @State var isShowSipAddressesPopup = false @State var isShowSipAddressesPopupType = 0 // 0 to call, 1 to message, 2 to video call @State var isShowConversationFragment = false @@ -861,7 +862,8 @@ struct ContentView: View { conversationViewModel: conversationViewModel, conversationsListViewModel: conversationsListViewModel, conversationForwardMessageViewModel: conversationForwardMessageViewModel, - isShowConversationFragment: $isShowConversationFragment + isShowConversationFragment: $isShowConversationFragment, + isShowStartCallGroupPopup: $isShowStartCallGroupPopup ) .frame(maxWidth: .infinity) .background(Color.gray100) @@ -1159,6 +1161,30 @@ struct ContentView: View { } } + if isShowStartCallGroupPopup { + PopupView( + isShowPopup: $isShowStartCallGroupPopup, + title: Text("conversation_info_confirm_start_group_call_dialog_title"), + content: Text("conversation_info_confirm_start_group_call_dialog_message"), + titleFirstButton: Text("Cancel"), + actionFirstButton: { + self.isShowStartCallGroupPopup.toggle() + }, + titleSecondButton: Text("Confirm"), + actionSecondButton: { + if conversationViewModel.displayedConversation != nil { + conversationViewModel.displayedConversation!.createGroupCall() + } + self.isShowStartCallGroupPopup.toggle() + } + ) + .background(.black.opacity(0.65)) + .zIndex(3) + .onTapGesture { + self.isShowStartCallGroupPopup.toggle() + } + } + if telecomManager.meetingWaitingRoomDisplayed { MeetingWaitingRoomFragment(meetingWaitingRoomViewModel: meetingWaitingRoomViewModel) .zIndex(3) @@ -1176,7 +1202,8 @@ struct ContentView: View { conversationForwardMessageViewModel: conversationForwardMessageViewModel, fullscreenVideo: $fullscreenVideo, isShowStartCallFragment: $isShowStartCallFragment, - isShowConversationFragment: $isShowConversationFragment + isShowConversationFragment: $isShowConversationFragment, + isShowStartCallGroupPopup: $isShowStartCallGroupPopup ) .zIndex(5) .transition(.scale.combined(with: .move(edge: .top))) diff --git a/Linphone/UI/Main/Conversations/Fragments/ConversationFragment.swift b/Linphone/UI/Main/Conversations/Fragments/ConversationFragment.swift index 8aa44389e..a29489ba4 100644 --- a/Linphone/UI/Main/Conversations/Fragments/ConversationFragment.swift +++ b/Linphone/UI/Main/Conversations/Fragments/ConversationFragment.swift @@ -56,6 +56,7 @@ struct ConversationFragment: View { @State private var isShowConversationForwardMessageFragment = false @Binding var isShowConversationFragment: Bool + @Binding var isShowStartCallGroupPopup: Bool @State private var selectedCategoryIndex = 0 @@ -202,7 +203,11 @@ struct ConversationFragment: View { Spacer() Button { - conversationViewModel.displayedConversation!.call() + if conversationViewModel.displayedConversation!.isGroup { + isShowStartCallGroupPopup.toggle() + } else { + 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 0e84f8a20..b5d8dca7e 100644 --- a/Linphone/UI/Main/Conversations/Model/ConversationModel.swift +++ b/Linphone/UI/Main/Conversations/Model/ConversationModel.swift @@ -50,6 +50,7 @@ class ConversationModel: ObservableObject { @Published var unreadMessagesCount: Int @Published var avatarModel: ContactAvatarModel + private var conferenceScheduler: ConferenceScheduler? private var conferenceSchedulerDelegate: ConferenceSchedulerDelegate? init(chatRoom: ChatRoom) { @@ -114,54 +115,57 @@ class ConversationModel: ObservableObject { TelecomManager.shared.doCallOrJoinConf(address: self.chatRoom.participants.first!.address!) } } else { - //self.createGroupCall(core: core) + self.createGroupCall() } } } - 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)" - ) - } + func createGroupCall() { + coreContext.doOnCoreQueue { core in + let account = core.defaultAccount + if account == nil { + Log.error( + "\(ConversationModel.TAG) No default account found, can't create group call!" + ) + return } - 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)" - ) + 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)" + ) + + self.conferenceScheduler = try core.createConferenceScheduler(account: account) + if self.conferenceScheduler != nil { + self.conferenceAddDelegate(core: core, conferenceScheduler: self.conferenceScheduler!) + // Will trigger the conference creation/update automatically + self.conferenceScheduler!.info = conferenceInfo + } + } catch let error { + Log.error( + "\(ConversationModel.TAG) createGroupCall: \(error)" + ) + } } } @@ -175,10 +179,10 @@ class ConversationModel: ObservableObject { let conferenceAddress = conferenceScheduler.info?.uri if conferenceAddress != nil { Log.info( - "\(ConversationModel.TAG) Conference info created, address is \(conferenceAddress?.asStringUriOnly() ?? "Error conference address")" + "\(ConversationModel.TAG) Conference info created, address is \(conferenceAddress!.asStringUriOnly())" ) - TelecomManager.shared.doCallOrJoinConf(address: conferenceAddress!) + TelecomManager.shared.doCallWithCore(addr: conferenceAddress!, isVideo: true, isConference: true) } else { Log.error("\(ConversationModel.TAG) Conference info URI is null!") diff --git a/Linphone/UI/Main/History/ViewModel/StartCallViewModel.swift b/Linphone/UI/Main/History/ViewModel/StartCallViewModel.swift index 4270d7fc5..20bd0d262 100644 --- a/Linphone/UI/Main/History/ViewModel/StartCallViewModel.swift +++ b/Linphone/UI/Main/History/ViewModel/StartCallViewModel.swift @@ -37,6 +37,7 @@ class StartCallViewModel: ObservableObject { @Published var operationInProgress: Bool = false + private var conferenceScheduler: ConferenceScheduler? private var conferenceSchedulerDelegate: ConferenceSchedulerDelegate? init() { @@ -104,11 +105,12 @@ class StartCallViewModel: ObservableObject { "\(StartCallViewModel.TAG) Creating group call with subject \(self.messageText) and \(participantsList.count) participant(s)" ) - let conferenceScheduler = try core.createConferenceScheduler(account: account) - self.conferenceAddDelegate(core: core, conferenceScheduler: conferenceScheduler) - conferenceScheduler.account = account - // Will trigger the conference creation/update automatically - conferenceScheduler.info = conferenceInfo + self.conferenceScheduler = try core.createConferenceScheduler(account: account) + if self.conferenceScheduler != nil { + self.conferenceAddDelegate(core: core, conferenceScheduler: self.conferenceScheduler!) + // Will trigger the conference creation/update automatically + self.conferenceScheduler!.info = conferenceInfo + } } catch let error { Log.error( "\(StartCallViewModel.TAG) createGroupCall: \(error)"