diff --git a/Linphone/Assets.xcassets/picture-in-picture.imageset/Contents.json b/Linphone/Assets.xcassets/picture-in-picture.imageset/Contents.json
new file mode 100644
index 000000000..44e023b13
--- /dev/null
+++ b/Linphone/Assets.xcassets/picture-in-picture.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "filename" : "picture-in-picture.svg",
+ "idiom" : "universal",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/Linphone/Assets.xcassets/picture-in-picture.imageset/picture-in-picture.svg b/Linphone/Assets.xcassets/picture-in-picture.imageset/picture-in-picture.svg
new file mode 100644
index 000000000..4a7ab8304
--- /dev/null
+++ b/Linphone/Assets.xcassets/picture-in-picture.imageset/picture-in-picture.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/Linphone/Assets.xcassets/plus.imageset/Contents.json b/Linphone/Assets.xcassets/plus.imageset/Contents.json
new file mode 100644
index 000000000..16eddb498
--- /dev/null
+++ b/Linphone/Assets.xcassets/plus.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "filename" : "plus.svg",
+ "idiom" : "universal",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/Linphone/Assets.xcassets/plus.imageset/plus.svg b/Linphone/Assets.xcassets/plus.imageset/plus.svg
new file mode 100644
index 000000000..79c378c6b
--- /dev/null
+++ b/Linphone/Assets.xcassets/plus.imageset/plus.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/Linphone/Assets.xcassets/squares-four.imageset/Contents.json b/Linphone/Assets.xcassets/squares-four.imageset/Contents.json
new file mode 100644
index 000000000..9fa7f7893
--- /dev/null
+++ b/Linphone/Assets.xcassets/squares-four.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "filename" : "squares-four.svg",
+ "idiom" : "universal",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/Linphone/Assets.xcassets/squares-four.imageset/squares-four.svg b/Linphone/Assets.xcassets/squares-four.imageset/squares-four.svg
new file mode 100644
index 000000000..85f5689ef
--- /dev/null
+++ b/Linphone/Assets.xcassets/squares-four.imageset/squares-four.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/Linphone/Assets.xcassets/waveform.imageset/Contents.json b/Linphone/Assets.xcassets/waveform.imageset/Contents.json
new file mode 100644
index 000000000..c9be92b8a
--- /dev/null
+++ b/Linphone/Assets.xcassets/waveform.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "filename" : "waveform.svg",
+ "idiom" : "universal",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/Linphone/Assets.xcassets/waveform.imageset/waveform.svg b/Linphone/Assets.xcassets/waveform.imageset/waveform.svg
new file mode 100644
index 000000000..ab8d0faff
--- /dev/null
+++ b/Linphone/Assets.xcassets/waveform.imageset/waveform.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/Linphone/Localizable.xcstrings b/Linphone/Localizable.xcstrings
index d26d8e3f5..2652bf8e4 100644
--- a/Linphone/Localizable.xcstrings
+++ b/Linphone/Localizable.xcstrings
@@ -218,6 +218,9 @@
},
"Attended transfer" : {
+ },
+ "Audio seulement" : {
+
},
"Block the address" : {
@@ -501,6 +504,9 @@
},
"Missed call" : {
+ },
+ "Mosaïque" : {
+
},
"New call" : {
@@ -555,6 +561,9 @@
},
"Partager le lien" : {
+ },
+ "Participant actif" : {
+
},
"Participants" : {
diff --git a/Linphone/UI/Call/CallView.swift b/Linphone/UI/Call/CallView.swift
index 1574c9dbe..2e52f23f4 100644
--- a/Linphone/UI/Call/CallView.swift
+++ b/Linphone/UI/Call/CallView.swift
@@ -25,6 +25,7 @@ import UniformTypeIdentifiers
// swiftlint:disable type_body_length
// swiftlint:disable line_length
+// swiftlint:disable file_length
struct CallView: View {
@ObservedObject private var coreContext = CoreContext.shared
@@ -39,7 +40,9 @@ struct CallView: View {
let pub = NotificationCenter.default.publisher(for: AVAudioSession.routeChangeNotification)
@State var audioRouteSheet: Bool = false
- @State var options: Int = 1
+ @State var changeLayoutSheet: Bool = false
+ @State var optionsAudioRoute: Int = 1
+ @State var optionsChangeLayout: Int = 2
@State var imageAudioRoute: String = ""
@State var angleDegree = 0.0
@State var showingDialer = false
@@ -64,7 +67,13 @@ struct CallView: View {
.sheet(isPresented: $audioRouteSheet, onDismiss: {
audioRouteSheet = false
}) {
- innerBottomSheet()
+ audioRouteBottomSheet()
+ .presentationDetents([.fraction(0.3)])
+ }
+ .sheet(isPresented: $changeLayoutSheet, onDismiss: {
+ changeLayoutSheet = false
+ }) {
+ changeLayoutBottomSheet()
.presentationDetents([.fraction(0.3)])
}
.sheet(isPresented: $showingDialer) {
@@ -81,7 +90,13 @@ struct CallView: View {
.sheet(isPresented: $audioRouteSheet, onDismiss: {
audioRouteSheet = false
}) {
- innerBottomSheet()
+ audioRouteBottomSheet()
+ .presentationDetents([.fraction(0.3)])
+ }
+ .sheet(isPresented: $changeLayoutSheet, onDismiss: {
+ changeLayoutSheet = false
+ }) {
+ changeLayoutBottomSheet()
.presentationDetents([.fraction(0.3)])
}
.sheet(isPresented: $showingDialer) {
@@ -95,10 +110,15 @@ struct CallView: View {
} else {
innerView(geometry: geo)
.halfSheet(showSheet: $audioRouteSheet) {
- innerBottomSheet()
+ audioRouteBottomSheet()
} onDismiss: {
audioRouteSheet = false
}
+ .halfSheet(showSheet: $changeLayoutSheet) {
+ changeLayoutBottomSheet()
+ } onDismiss: {
+ changeLayoutSheet = false
+ }
.halfSheet(showSheet: $showingDialer) {
DialerBottomSheet(
startCallViewModel: StartCallViewModel(),
@@ -149,10 +169,10 @@ struct CallView: View {
}
@ViewBuilder
- func innerBottomSheet() -> some View {
+ func audioRouteBottomSheet() -> some View {
VStack(spacing: 0) {
Button(action: {
- options = 1
+ optionsAudioRoute = 1
do {
try AVAudioSession.sharedInstance().overrideOutputAudioPort(.none)
@@ -166,7 +186,7 @@ struct CallView: View {
}
}, label: {
HStack {
- Image(options == 1 ? "radio-button-fill" : "radio-button")
+ Image(optionsAudioRoute == 1 ? "radio-button-fill" : "radio-button")
.renderingMode(.template)
.resizable()
.foregroundStyle(.white)
@@ -189,7 +209,7 @@ struct CallView: View {
.frame(maxHeight: .infinity)
Button(action: {
- options = 2
+ optionsAudioRoute = 2
do {
try AVAudioSession.sharedInstance().overrideOutputAudioPort(.speaker)
@@ -198,7 +218,7 @@ struct CallView: View {
}
}, label: {
HStack {
- Image(options == 2 ? "radio-button-fill" : "radio-button")
+ Image(optionsAudioRoute == 2 ? "radio-button-fill" : "radio-button")
.renderingMode(.template)
.resizable()
.foregroundStyle(.white)
@@ -221,7 +241,7 @@ struct CallView: View {
.frame(maxHeight: .infinity)
Button(action: {
- options = 3
+ optionsAudioRoute = 3
do {
try AVAudioSession.sharedInstance().overrideOutputAudioPort(.none)
@@ -231,7 +251,7 @@ struct CallView: View {
}
}, label: {
HStack {
- Image(options == 3 ? "radio-button-fill" : "radio-button")
+ Image(optionsAudioRoute == 3 ? "radio-button-fill" : "radio-button")
.renderingMode(.template)
.resizable()
.foregroundStyle(.white)
@@ -258,6 +278,97 @@ struct CallView: View {
.frame(maxHeight: .infinity)
}
+ @ViewBuilder
+ func changeLayoutBottomSheet() -> some View {
+ VStack(spacing: 0) {
+ Button(action: {
+ optionsChangeLayout = 1
+ changeLayoutSheet = false
+ }, label: {
+ HStack {
+ Image(optionsChangeLayout == 1 ? "radio-button-fill" : "radio-button")
+ .renderingMode(.template)
+ .resizable()
+ .foregroundStyle(callViewModel.participantList.count > 5 ? Color.gray500 : .white)
+ .frame(width: 25, height: 25, alignment: .leading)
+ .padding(.all, 10)
+
+ Text("Mosaïque")
+ .foregroundStyle(callViewModel.participantList.count > 5 ? Color.gray500 : .white)
+ .default_text_style_white(styleSize: 15)
+
+ Spacer()
+
+ Image("squares-four")
+ .renderingMode(.template)
+ .resizable()
+ .foregroundStyle(callViewModel.participantList.count > 5 ? Color.gray500 : .white)
+ .frame(width: 25, height: 25, alignment: .leading)
+ .padding(.all, 10)
+ }
+ })
+ .disabled(callViewModel.participantList.count > 5)
+ .frame(maxHeight: .infinity)
+
+ Button(action: {
+ optionsChangeLayout = 2
+ changeLayoutSheet = false
+ }, label: {
+ HStack {
+ Image(optionsChangeLayout == 2 ? "radio-button-fill" : "radio-button")
+ .renderingMode(.template)
+ .resizable()
+ .foregroundStyle(.white)
+ .frame(width: 25, height: 25, alignment: .leading)
+ .padding(.all, 10)
+
+ Text("Participant actif")
+ .default_text_style_white(styleSize: 15)
+
+ Spacer()
+
+ Image("picture-in-picture")
+ .renderingMode(.template)
+ .resizable()
+ .foregroundStyle(.white)
+ .frame(width: 25, height: 25, alignment: .leading)
+ .padding(.all, 10)
+ }
+ })
+ .frame(maxHeight: .infinity)
+
+ Button(action: {
+ optionsChangeLayout = 3
+ changeLayoutSheet = false
+ }, label: {
+ HStack {
+ Image(optionsChangeLayout == 3 ? "radio-button-fill" : "radio-button")
+ .renderingMode(.template)
+ .resizable()
+ .foregroundStyle(.white)
+ .frame(width: 25, height: 25, alignment: .leading)
+ .padding(.all, 10)
+
+ Text("Audio seulement")
+ .default_text_style_white(styleSize: 15)
+
+ Spacer()
+
+ Image("waveform")
+ .renderingMode(.template)
+ .resizable()
+ .foregroundStyle(.white)
+ .frame(width: 25, height: 25, alignment: .leading)
+ .padding(.all, 10)
+ }
+ })
+ .frame(maxHeight: .infinity)
+ }
+ .padding(.horizontal, 20)
+ .background(Color.gray600)
+ .frame(maxHeight: .infinity)
+ }
+
@ViewBuilder
// swiftlint:disable:next cyclomatic_complexity
func innerView(geometry: GeometryProxy) -> some View {
@@ -563,336 +674,10 @@ struct CallView: View {
)
}
} else if callViewModel.isConference && !telecomManager.outgoingCallStarted && callViewModel.activeSpeakerParticipant != nil {
- if callViewModel.activeSpeakerParticipant!.onPause {
- VStack {
- VStack {
- Spacer()
-
- Image("pause")
- .renderingMode(.template)
- .resizable()
- .foregroundStyle(.white)
- .frame(width: 40, height: 40)
-
- Text("En pause")
- .frame(maxWidth: .infinity, alignment: .center)
- .foregroundStyle(Color.white)
- .default_text_style_500(styleSize: 14)
- .lineLimit(1)
- .padding(.horizontal, 10)
-
- Spacer()
- }
- .frame(
- width: fullscreenVideo && !telecomManager.isPausedByRemote ? geometry.size.width : geometry.size.width - 8,
- height: 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 - 160 + geometry.safeAreaInsets.bottom
- )
-
- Spacer()
- }
- .frame(
- 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
- )
+ if optionsChangeLayout == 1 && callViewModel.participantList.count <= 5 {
+ mosaicMode(geometry: geometry, height: (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 {
- VStack {
- VStack {
- Spacer()
- ZStack {
- if callViewModel.activeSpeakerParticipant?.address != nil {
- let addressFriend = contactsManager.getFriendWithAddress(address: callViewModel.activeSpeakerParticipant!.address)
-
- let contactAvatarModel = addressFriend != nil
- ? ContactsManager.shared.avatarListModel.first(where: {
- ($0.friend!.consolidatedPresence == .Online || $0.friend!.consolidatedPresence == .Busy)
- && $0.friend!.name == addressFriend!.name
- && $0.friend!.address!.asStringUriOnly() == addressFriend!.address!.asStringUriOnly()
- })
- : ContactAvatarModel(friend: nil, name: "", withPresence: false)
-
- if addressFriend != nil && addressFriend!.photo != nil && !addressFriend!.photo!.isEmpty {
- if contactAvatarModel != nil {
- Avatar(contactAvatarModel: contactAvatarModel!, avatarSize: 200, hidePresence: true)
- .onAppear {
- DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
- displayVideo = true
- }
- }
- }
- } else {
- if callViewModel.activeSpeakerParticipant!.address.displayName != nil {
- Image(uiImage: contactsManager.textToImage(
- firstName: callViewModel.activeSpeakerParticipant!.address.displayName!,
- lastName: callViewModel.activeSpeakerParticipant!.address.displayName!.components(separatedBy: " ").count > 1
- ? callViewModel.activeSpeakerParticipant!.address.displayName!.components(separatedBy: " ")[1]
- : ""))
- .resizable()
- .frame(width: 200, height: 200)
- .clipShape(Circle())
- .onAppear {
- DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
- displayVideo = true
- }
- }
-
- } else {
- Image(uiImage: contactsManager.textToImage(
- firstName: callViewModel.activeSpeakerParticipant!.address.username ?? "Username Error",
- lastName: callViewModel.activeSpeakerParticipant!.address.username!.components(separatedBy: " ").count > 1
- ? callViewModel.activeSpeakerParticipant!.address.username!.components(separatedBy: " ")[1]
- : ""))
- .resizable()
- .frame(width: 200, height: 200)
- .clipShape(Circle())
- .onAppear {
- DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
- displayVideo = true
- }
- }
- }
-
- }
- } else {
- Image("profil-picture-default")
- .resizable()
- .frame(width: 200, height: 200)
- .clipShape(Circle())
- }
- }
-
- Spacer()
- }
- .frame(
- width: fullscreenVideo && !telecomManager.isPausedByRemote ? geometry.size.width : geometry.size.width - 8,
- height: 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 - 160 + geometry.safeAreaInsets.bottom
- )
-
- Spacer()
- }
- .frame(
- 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
- )
-
- if telecomManager.remoteConfVideo && !telecomManager.outgoingCallStarted && callViewModel.activeSpeakerParticipant != nil && displayVideo {
- VStack {
- VStack {
- LinphoneVideoViewHolder { view in
- coreContext.doOnCoreQueue { core in
- core.nativeVideoWindow = view
- }
- }
- .onTapGesture {
- if callViewModel.videoDisplayed {
- fullscreenVideo.toggle()
- }
- }
- }
- .frame(
- width: fullscreenVideo && !telecomManager.isPausedByRemote ? geometry.size.width : geometry.size.width - 8,
- height: 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 - 160 + geometry.safeAreaInsets.bottom
- )
- .cornerRadius(20)
-
- Spacer()
- }
- .frame(
- width: fullscreenVideo && !telecomManager.isPausedByRemote ? geometry.size.width : geometry.size.width - 8,
- height: 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
- )
- }
- }
-
- if callViewModel.isConference && !telecomManager.outgoingCallStarted && callViewModel.activeSpeakerParticipant != nil && callViewModel.activeSpeakerParticipant!.isMuted {
- VStack {
- HStack {
- Spacer()
-
- HStack(alignment: .center) {
- Image("microphone-slash")
- .renderingMode(.template)
- .resizable()
- .foregroundStyle(Color.grayMain2c800)
- .frame(width: 20, height: 20)
- }
- .padding(5)
- .background(.white)
- .cornerRadius(40)
- }
- Spacer()
- }
- .frame(maxWidth: .infinity)
- .padding(.all, 20)
- }
-
- if callViewModel.isConference {
- HStack {
- Spacer()
- VStack {
- Spacer()
-
- Text(callViewModel.activeSpeakerName)
- .frame(maxWidth: .infinity, alignment: .leading)
- .foregroundStyle(Color.white)
- .default_text_style_500(styleSize: 20)
- .lineLimit(1)
- .padding(.horizontal, 10)
- .padding(.bottom, 6)
-
- ScrollView(.horizontal) {
- HStack {
- ZStack {
- VStack {
- Spacer()
-
- if callViewModel.myParticipantModel != nil {
- Avatar(contactAvatarModel: callViewModel.myParticipantModel!.avatarModel, avatarSize: 50, hidePresence: true)
- }
-
- Spacer()
- }
- .frame(width: 140, height: 140)
-
- if callViewModel.videoDisplayed {
- LinphoneVideoViewHolder { view in
- coreContext.doOnCoreQueue { core in
- core.nativePreviewWindow = view
- }
- }
- .frame(width: angleDegree == 0 ? 120*1.2 : 160*1.2, height: angleDegree == 0 ? 160*1.2 : 120*1.2)
- .scaledToFill()
- .clipped()
- }
-
- VStack(alignment: .leading) {
- Spacer()
-
- if callViewModel.myParticipantModel != nil {
- Text(callViewModel.myParticipantModel!.name)
- .frame(maxWidth: .infinity, alignment: .leading)
- .foregroundStyle(Color.white)
- .default_text_style_500(styleSize: 14)
- .lineLimit(1)
- .padding(.horizontal, 10)
- .padding(.bottom, 6)
- }
- }
- .frame(width: 140, height: 140)
- }
- .frame(width: 140, height: 140)
- .background(Color.gray600)
- .cornerRadius(20)
-
- ForEach(0.. 80 ? minBottomSheetHeight * geometry.size.height : 78) - 40 - 20 + geometry.safeAreaInsets.bottom
- )
- .padding(.bottom, 10)
- .padding(.leading, -10)
+ activeSpeakerMode(geometry: geometry)
}
} else if callViewModel.isConference && !telecomManager.outgoingCallStarted && callViewModel.participantList.isEmpty {
VStack {
@@ -1034,6 +819,832 @@ struct CallView: View {
}
// swiftlint:enable function_body_length
+ func activeSpeakerMode(geometry: GeometryProxy) -> some View {
+ ZStack {
+ if callViewModel.activeSpeakerParticipant!.onPause {
+ VStack {
+ VStack {
+ Spacer()
+
+ Image("pause")
+ .renderingMode(.template)
+ .resizable()
+ .foregroundStyle(.white)
+ .frame(width: 40, height: 40)
+
+ Text("En pause")
+ .frame(maxWidth: .infinity, alignment: .center)
+ .foregroundStyle(Color.white)
+ .default_text_style_500(styleSize: 14)
+ .lineLimit(1)
+ .padding(.horizontal, 10)
+
+ Spacer()
+ }
+ .frame(
+ width: fullscreenVideo && !telecomManager.isPausedByRemote ? geometry.size.width : geometry.size.width - 8,
+ height: 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 - 160 + geometry.safeAreaInsets.bottom
+ )
+
+ Spacer()
+ }
+ .frame(
+ 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 {
+ VStack {
+ VStack {
+ Spacer()
+ ZStack {
+ if callViewModel.activeSpeakerParticipant?.address != nil {
+ let addressFriend = contactsManager.getFriendWithAddress(address: callViewModel.activeSpeakerParticipant!.address)
+
+ let contactAvatarModel = addressFriend != nil
+ ? ContactsManager.shared.avatarListModel.first(where: {
+ ($0.friend!.consolidatedPresence == .Online || $0.friend!.consolidatedPresence == .Busy)
+ && $0.friend!.name == addressFriend!.name
+ && $0.friend!.address!.asStringUriOnly() == addressFriend!.address!.asStringUriOnly()
+ })
+ : ContactAvatarModel(friend: nil, name: "", withPresence: false)
+
+ if addressFriend != nil && addressFriend!.photo != nil && !addressFriend!.photo!.isEmpty {
+ if contactAvatarModel != nil {
+ Avatar(contactAvatarModel: contactAvatarModel!, avatarSize: 200, hidePresence: true)
+ .onAppear {
+ DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
+ displayVideo = true
+ }
+ }
+ }
+ } else {
+ if callViewModel.activeSpeakerParticipant!.address.displayName != nil {
+ Image(uiImage: contactsManager.textToImage(
+ firstName: callViewModel.activeSpeakerParticipant!.address.displayName!,
+ lastName: callViewModel.activeSpeakerParticipant!.address.displayName!.components(separatedBy: " ").count > 1
+ ? callViewModel.activeSpeakerParticipant!.address.displayName!.components(separatedBy: " ")[1]
+ : ""))
+ .resizable()
+ .frame(width: 200, height: 200)
+ .clipShape(Circle())
+ .onAppear {
+ DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
+ displayVideo = true
+ }
+ }
+
+ } else {
+ Image(uiImage: contactsManager.textToImage(
+ firstName: callViewModel.activeSpeakerParticipant!.address.username ?? "Username Error",
+ lastName: callViewModel.activeSpeakerParticipant!.address.username!.components(separatedBy: " ").count > 1
+ ? callViewModel.activeSpeakerParticipant!.address.username!.components(separatedBy: " ")[1]
+ : ""))
+ .resizable()
+ .frame(width: 200, height: 200)
+ .clipShape(Circle())
+ .onAppear {
+ DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
+ displayVideo = true
+ }
+ }
+ }
+
+ }
+ } else {
+ Image("profil-picture-default")
+ .resizable()
+ .frame(width: 200, height: 200)
+ .clipShape(Circle())
+ }
+ }
+
+ Spacer()
+ }
+ .frame(
+ width: fullscreenVideo && !telecomManager.isPausedByRemote ? geometry.size.width : geometry.size.width - 8,
+ height: 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 - 160 + geometry.safeAreaInsets.bottom
+ )
+
+ Spacer()
+ }
+ .frame(
+ 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
+ )
+
+ if telecomManager.remoteConfVideo && !telecomManager.outgoingCallStarted && callViewModel.activeSpeakerParticipant != nil && displayVideo {
+ VStack {
+ VStack {
+ LinphoneVideoViewHolder { view in
+ coreContext.doOnCoreQueue { core in
+ core.nativeVideoWindow = view
+ }
+ }
+ .onTapGesture {
+ if callViewModel.videoDisplayed {
+ fullscreenVideo.toggle()
+ }
+ }
+ }
+ .frame(
+ width: fullscreenVideo && !telecomManager.isPausedByRemote ? geometry.size.width : geometry.size.width - 8,
+ height: 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 - 160 + geometry.safeAreaInsets.bottom
+ )
+ .cornerRadius(20)
+
+ Spacer()
+ }
+ .frame(
+ width: fullscreenVideo && !telecomManager.isPausedByRemote ? geometry.size.width : geometry.size.width - 8,
+ height: 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
+ )
+ }
+ }
+
+ if callViewModel.isConference && !telecomManager.outgoingCallStarted && callViewModel.activeSpeakerParticipant != nil && callViewModel.activeSpeakerParticipant!.isMuted {
+ VStack {
+ HStack {
+ Spacer()
+
+ HStack(alignment: .center) {
+ Image("microphone-slash")
+ .renderingMode(.template)
+ .resizable()
+ .foregroundStyle(Color.grayMain2c800)
+ .frame(width: 20, height: 20)
+ }
+ .padding(5)
+ .background(.white)
+ .cornerRadius(40)
+ }
+ Spacer()
+ }
+ .frame(maxWidth: .infinity)
+ .padding(.all, 20)
+ }
+
+ if callViewModel.isConference {
+ HStack {
+ Spacer()
+ VStack {
+ Spacer()
+
+ Text(callViewModel.activeSpeakerName)
+ .frame(maxWidth: .infinity, alignment: .leading)
+ .foregroundStyle(Color.white)
+ .default_text_style_500(styleSize: 20)
+ .lineLimit(1)
+ .padding(.horizontal, 10)
+ .padding(.bottom, 6)
+
+ ScrollView(.horizontal) {
+ HStack {
+ ZStack {
+ VStack {
+ Spacer()
+
+ if callViewModel.myParticipantModel != nil {
+ Avatar(contactAvatarModel: callViewModel.myParticipantModel!.avatarModel, avatarSize: 50, hidePresence: true)
+ }
+
+ Spacer()
+ }
+ .frame(width: 140, height: 140)
+
+ if callViewModel.videoDisplayed {
+ LinphoneVideoViewHolder { view in
+ coreContext.doOnCoreQueue { core in
+ core.nativePreviewWindow = view
+ }
+ }
+ .frame(width: angleDegree == 0 ? 120*1.2 : 160*1.2, height: angleDegree == 0 ? 160*1.2 : 120*1.2)
+ .scaledToFill()
+ .clipped()
+ }
+
+ VStack(alignment: .leading) {
+ Spacer()
+
+ if callViewModel.myParticipantModel != nil {
+ Text(callViewModel.myParticipantModel!.name)
+ .frame(maxWidth: .infinity, alignment: .leading)
+ .foregroundStyle(Color.white)
+ .default_text_style_500(styleSize: 14)
+ .lineLimit(1)
+ .padding(.horizontal, 10)
+ .padding(.bottom, 6)
+ }
+ }
+ .frame(width: 140, height: 140)
+ }
+ .frame(width: 140, height: 140)
+ .background(Color.gray600)
+ .overlay(
+ RoundedRectangle(cornerRadius: 20)
+ .stroke(callViewModel.myParticipantModel != nil && callViewModel.myParticipantModel!.isSpeaking ? .white : Color.gray600, lineWidth: 4)
+ )
+ .cornerRadius(20)
+
+ ForEach(0.. 80 ? minBottomSheetHeight * geometry.size.height : 78) - 40 - 20 + geometry.safeAreaInsets.bottom
+ )
+ .padding(.bottom, 10)
+ .padding(.leading, -10)
+ }
+ }
+ .onAppear {
+ optionsChangeLayout = 2
+ }
+ }
+
+ // swiftlint:disable:next cyclomatic_complexity
+ func mosaicMode(geometry: GeometryProxy, height: Double) -> some View {
+ VStack {
+ if geometry.size.width < geometry.size.height {
+ let maxValue = max(
+ ((geometry.size.width/2) - 10.0) * ceil(Double(callViewModel.participantList.count + 1) / 2.0) > height ? ((height / 3) - 10.0) : ((geometry.size.width/2) - 10.0),
+ ((height / Double(callViewModel.participantList.count + 1)) - 10.0)
+ )
+
+ LazyVGrid(columns: [
+ GridItem(.adaptive(
+ minimum: maxValue
+ ))
+ ], spacing: 10) {
+ if callViewModel.myParticipantModel != nil {
+ ZStack {
+ if callViewModel.myParticipantModel!.isJoining {
+ VStack {
+ Spacer()
+
+ ActivityIndicator(color: .white)
+ .frame(width: maxValue/4, height: maxValue/4)
+ .padding(.bottom, 5)
+
+ Text("Joining...")
+ .frame(maxWidth: .infinity, alignment: .center)
+ .foregroundStyle(Color.white)
+ .default_text_style_500(styleSize: 14)
+ .lineLimit(1)
+ .padding(.horizontal, 10)
+
+ Spacer()
+ }
+ } else if callViewModel.myParticipantModel!.onPause {
+ VStack {
+ Spacer()
+
+ Image("pause")
+ .renderingMode(.template)
+ .resizable()
+ .foregroundStyle(.white)
+ .frame(width: maxValue/4, height: maxValue/4)
+
+ Text("En pause")
+ .frame(maxWidth: .infinity, alignment: .center)
+ .foregroundStyle(Color.white)
+ .default_text_style_500(styleSize: 14)
+ .lineLimit(1)
+ .padding(.horizontal, 10)
+
+ Spacer()
+ }
+ } else {
+ VStack {
+ Spacer()
+
+ if callViewModel.myParticipantModel != nil {
+ Avatar(contactAvatarModel: callViewModel.myParticipantModel!.avatarModel, avatarSize: maxValue/2, hidePresence: true)
+ }
+
+ Spacer()
+ }
+ .frame(width: maxValue, height: maxValue)
+
+ if callViewModel.videoDisplayed {
+ LinphoneVideoViewHolder { view in
+ coreContext.doOnCoreQueue { core in
+ core.nativePreviewWindow = view
+ }
+ }
+ .frame(
+ width: 120 * ceil(maxValue / 120),
+ height: 160 * ceil(maxValue / 120)
+ )
+ .scaledToFill()
+ .clipped()
+ }
+
+ if callViewModel.myParticipantModel!.isMuted {
+ VStack {
+ HStack {
+ Spacer()
+
+ HStack(alignment: .center) {
+ Image("microphone-slash")
+ .renderingMode(.template)
+ .resizable()
+ .foregroundStyle(Color.grayMain2c800)
+ .frame(width: 12, height: 12)
+ }
+ .padding(2)
+ .background(.white)
+ .cornerRadius(40)
+ }
+ Spacer()
+ }
+ .frame(maxWidth: .infinity)
+ .padding(.all, 10)
+ }
+ }
+
+ VStack(alignment: .leading) {
+ Spacer()
+
+ if callViewModel.myParticipantModel != nil {
+ Text(callViewModel.myParticipantModel!.name)
+ .frame(maxWidth: .infinity, alignment: .leading)
+ .foregroundStyle(Color.white)
+ .default_text_style_500(styleSize: 14)
+ .lineLimit(1)
+ .padding(.horizontal, 10)
+ .padding(.bottom, 6)
+ }
+ }
+ .frame(width: maxValue, height: maxValue)
+ }
+ .frame(
+ width: maxValue,
+ height: maxValue,
+ alignment: .center
+ )
+ .background(Color.gray600)
+ .overlay(
+ RoundedRectangle(cornerRadius: 20)
+ .stroke(callViewModel.myParticipantModel!.isSpeaking ? .white : Color.gray600, lineWidth: 4)
+ )
+ .cornerRadius(20)
+ }
+
+ ForEach(0.. height ? ((height / 2) - 10.0) : ((geometry.size.width/3) - 10.0),
+ ((geometry.size.width/Double(callViewModel.participantList.count + 1)) - 10.0) > height ? height - 20 : ((geometry.size.width/Double(callViewModel.participantList.count + 1)) - 10.0)
+ )
+
+ LazyHGrid(rows: [
+ GridItem(.adaptive(
+ minimum: maxValue
+ ))
+ ], spacing: 10) {
+ if callViewModel.myParticipantModel != nil {
+ ZStack {
+ if callViewModel.myParticipantModel!.isJoining {
+ VStack {
+ Spacer()
+
+ ActivityIndicator(color: .white)
+ .frame(width: maxValue/4, height: maxValue/4)
+ .padding(.bottom, 5)
+
+ Text("Joining...")
+ .frame(maxWidth: .infinity, alignment: .center)
+ .foregroundStyle(Color.white)
+ .default_text_style_500(styleSize: 14)
+ .lineLimit(1)
+ .padding(.horizontal, 10)
+
+ Spacer()
+ }
+ } else if callViewModel.myParticipantModel!.onPause {
+ VStack {
+ Spacer()
+
+ Image("pause")
+ .renderingMode(.template)
+ .resizable()
+ .foregroundStyle(.white)
+ .frame(width: maxValue/4, height: maxValue/4)
+
+ Text("En pause")
+ .frame(maxWidth: .infinity, alignment: .center)
+ .foregroundStyle(Color.white)
+ .default_text_style_500(styleSize: 14)
+ .lineLimit(1)
+ .padding(.horizontal, 10)
+
+ Spacer()
+ }
+ } else {
+ VStack {
+ Spacer()
+
+ if callViewModel.myParticipantModel != nil {
+ Avatar(contactAvatarModel: callViewModel.myParticipantModel!.avatarModel, avatarSize: maxValue/2, hidePresence: true)
+ }
+
+ Spacer()
+ }
+ .frame(width: maxValue, height: maxValue)
+
+ if callViewModel.videoDisplayed {
+ LinphoneVideoViewHolder { view in
+ coreContext.doOnCoreQueue { core in
+ core.nativePreviewWindow = view
+ }
+ }
+ .frame(
+ width: 160 * ceil(maxValue / 120),
+ height: 120 * ceil(maxValue / 120)
+ )
+ .scaledToFill()
+ .clipped()
+ }
+
+ if callViewModel.myParticipantModel!.isMuted {
+ VStack {
+ HStack {
+ Spacer()
+
+ HStack(alignment: .center) {
+ Image("microphone-slash")
+ .renderingMode(.template)
+ .resizable()
+ .foregroundStyle(Color.grayMain2c800)
+ .frame(width: 12, height: 12)
+ }
+ .padding(2)
+ .background(.white)
+ .cornerRadius(40)
+ }
+ Spacer()
+ }
+ .frame(maxWidth: .infinity)
+ .padding(.all, 10)
+ }
+ }
+
+ VStack(alignment: .leading) {
+ Spacer()
+
+ if callViewModel.myParticipantModel != nil {
+ Text(callViewModel.myParticipantModel!.name)
+ .frame(maxWidth: .infinity, alignment: .leading)
+ .foregroundStyle(Color.white)
+ .default_text_style_500(styleSize: 14)
+ .lineLimit(1)
+ .padding(.horizontal, 10)
+ .padding(.bottom, 6)
+ }
+ }
+ .frame(width: maxValue, height: maxValue)
+ }
+ .frame(
+ width: maxValue,
+ height: maxValue,
+ alignment: .center
+ )
+ .background(Color.gray600)
+ .overlay(
+ RoundedRectangle(cornerRadius: 20)
+ .stroke(callViewModel.myParticipantModel!.isSpeaking ? .white : Color.gray600, lineWidth: 4)
+ )
+ .cornerRadius(20)
+ }
+
+ ForEach(0.. some View {
GeometryReader { _ in
@@ -1326,6 +1937,7 @@ struct CallView: View {
} else {
VStack {
Button {
+ changeLayoutSheet = true
} label: {
HStack {
Image("notebook")
@@ -1651,6 +2263,7 @@ struct CallView: View {
} else {
VStack {
Button {
+ changeLayoutSheet = true
} label: {
HStack {
Image("notebook")
@@ -1894,3 +2507,4 @@ struct PressedButtonStyle: ButtonStyle {
}
// swiftlint:enable type_body_length
// swiftlint:enable line_length
+// swiftlint:enable file_length
diff --git a/Linphone/UI/Call/Fragments/ParticipantsListFragment.swift b/Linphone/UI/Call/Fragments/ParticipantsListFragment.swift
index 301d1de99..31152edb7 100644
--- a/Linphone/UI/Call/Fragments/ParticipantsListFragment.swift
+++ b/Linphone/UI/Call/Fragments/ParticipantsListFragment.swift
@@ -74,6 +74,27 @@ struct ParticipantsListFragment: View {
.background(.white)
participantsList
+
+ HStack {
+ Spacer()
+
+ NavigationLink(destination: {
+ //AddParticipantsFragment()
+ }, label: {
+ Image("plus")
+ .resizable()
+ .renderingMode(.template)
+ .frame(width: 25, height: 25)
+ .foregroundStyle(.white)
+ .padding()
+ .background(Color.orangeMain500)
+ .clipShape(Circle())
+ .shadow(color: .black.opacity(0.2), radius: 4)
+
+ })
+ .padding()
+ }
+ .padding(.trailing, 10)
}
.background(.white)
diff --git a/Linphone/UI/Call/Model/ParticipantModel.swift b/Linphone/UI/Call/Model/ParticipantModel.swift
index e68da99cf..0a1ec61d4 100644
--- a/Linphone/UI/Call/Model/ParticipantModel.swift
+++ b/Linphone/UI/Call/Model/ParticipantModel.swift
@@ -32,8 +32,9 @@ class ParticipantModel: ObservableObject {
@Published var onPause: Bool
@Published var isMuted: Bool
@Published var isAdmin: Bool
+ @Published var isSpeaking: Bool
- init(address: Address, isJoining: Bool = false, onPause: Bool = false, isMuted: Bool = false, isAdmin: Bool = false) {
+ init(address: Address, isJoining: Bool = false, onPause: Bool = false, isMuted: Bool = false, isAdmin: Bool = false, isSpeaking: Bool = false) {
self.address = address
self.sipUri = address.asStringUriOnly()
@@ -50,5 +51,6 @@ class ParticipantModel: ObservableObject {
self.onPause = onPause
self.isMuted = isMuted
self.isAdmin = isAdmin
+ self.isSpeaking = isSpeaking
}
}
diff --git a/Linphone/UI/Call/ViewModel/CallViewModel.swift b/Linphone/UI/Call/ViewModel/CallViewModel.swift
index 24299823f..72a08548a 100644
--- a/Linphone/UI/Call/ViewModel/CallViewModel.swift
+++ b/Linphone/UI/Call/ViewModel/CallViewModel.swift
@@ -305,6 +305,7 @@ class CallViewModel: ObservableObject {
)
}
+ // swiftlint:disable:next cyclomatic_complexity
func addConferenceCallBacks() {
coreContext.doOnCoreQueue { core in
self.mConferenceSuscriptions.insert(
@@ -386,7 +387,52 @@ class CallViewModel: ObservableObject {
}
})
+ var activeSpeakerParticipantTmp: ParticipantModel? = nil
+ var activeSpeakerNameTmp = ""
+
+ if self.activeSpeakerParticipant == nil {
+ if cbValue.conference.activeSpeakerParticipantDevice?.address != nil {
+ activeSpeakerParticipantTmp = ParticipantModel(
+ address: cbValue.conference.activeSpeakerParticipantDevice!.address!,
+ isJoining: false,
+ onPause: cbValue.conference.activeSpeakerParticipantDevice!.state == .OnHold,
+ isMuted: cbValue.conference.activeSpeakerParticipantDevice!.isMuted
+ )
+ } else if cbValue.conference.participantList.first?.address != nil && cbValue.conference.participantList.first!.address!.clone()!.equal(address2: (cbValue.conference.me?.address)!) {
+ activeSpeakerParticipantTmp = ParticipantModel(
+ address: cbValue.conference.participantDeviceList.first!.address!,
+ isJoining: false,
+ onPause: cbValue.conference.participantDeviceList.first!.state == .OnHold,
+ isMuted: cbValue.conference.participantDeviceList.first!.isMuted
+ )
+ } else if cbValue.conference.participantList.last?.address != nil {
+ activeSpeakerParticipantTmp = ParticipantModel(
+ address: cbValue.conference.participantDeviceList.last!.address!,
+ isJoining: false,
+ onPause: cbValue.conference.participantDeviceList.last!.state == .OnHold,
+ isMuted: cbValue.conference.participantDeviceList.last!.isMuted
+ )
+ }
+
+ if activeSpeakerParticipantTmp != nil {
+ let friend = ContactsManager.shared.getFriendWithAddress(address: activeSpeakerParticipantTmp!.address)
+ if friend != nil && friend!.address != nil && friend!.address!.displayName != nil {
+ activeSpeakerNameTmp = friend!.address!.displayName!
+ } else {
+ if activeSpeakerParticipantTmp!.address.displayName != nil {
+ activeSpeakerNameTmp = activeSpeakerParticipantTmp!.address.displayName!
+ } else if activeSpeakerParticipantTmp!.address.username != nil {
+ activeSpeakerNameTmp = activeSpeakerParticipantTmp!.address.username!
+ }
+ }
+ }
+ }
+
DispatchQueue.main.async {
+ if self.activeSpeakerParticipant == nil {
+ self.activeSpeakerParticipant = activeSpeakerParticipantTmp
+ self.activeSpeakerName = activeSpeakerNameTmp
+ }
self.participantList = participantListTmp
}
}
@@ -435,17 +481,16 @@ class CallViewModel: ObservableObject {
DispatchQueue.main.async {
self.activeSpeakerParticipant!.isMuted = isMutedTmp
}
- } else {
- self.participantList.forEach({ participantDevice in
- if participantDevice.address.equal(address2: cbValue.participantDevice.address!) {
- let isMutedTmp = cbValue.isMuted
-
- DispatchQueue.main.async {
- participantDevice.isMuted = isMutedTmp
- }
- }
- })
}
+ self.participantList.forEach({ participantDevice in
+ if participantDevice.address.equal(address2: cbValue.participantDevice.address!) {
+ let isMutedTmp = cbValue.isMuted
+
+ DispatchQueue.main.async {
+ participantDevice.isMuted = isMutedTmp
+ }
+ }
+ })
}
)
@@ -461,18 +506,17 @@ class CallViewModel: ObservableObject {
self.activeSpeakerParticipant!.onPause = activeSpeakerParticipantOnPauseTmp
self.activeSpeakerParticipant!.isJoining = activeSpeakerParticipantIsJoiningTmp
}
- } else {
- self.participantList.forEach({ participantDevice in
- if participantDevice.address.equal(address2: cbValue.device.address!) {
- let participantDeviceOnPauseTmp = cbValue.state == .OnHold
- let participantDeviceIsJoiningTmp = cbValue.state == .Joining || cbValue.state == .Alerting
- DispatchQueue.main.async {
- participantDevice.onPause = participantDeviceOnPauseTmp
- participantDevice.isJoining = participantDeviceIsJoiningTmp
- }
- }
- })
}
+ self.participantList.forEach({ participantDevice in
+ if participantDevice.address.equal(address2: cbValue.device.address!) {
+ let participantDeviceOnPauseTmp = cbValue.state == .OnHold
+ let participantDeviceIsJoiningTmp = cbValue.state == .Joining || cbValue.state == .Alerting
+ DispatchQueue.main.async {
+ participantDevice.onPause = participantDeviceOnPauseTmp
+ participantDevice.isJoining = participantDeviceIsJoiningTmp
+ }
+ }
+ })
}
)
@@ -483,15 +527,32 @@ class CallViewModel: ObservableObject {
DispatchQueue.main.async {
self.myParticipantModel!.isAdmin = isAdmin
}
- } else {
- self.participantList.forEach({ participantDevice in
- if participantDevice.address.clone()!.equal(address2: cbValue.participant.address!) {
- DispatchQueue.main.async {
- participantDevice.isAdmin = isAdmin
- }
- }
- })
}
+ self.participantList.forEach({ participantDevice in
+ if participantDevice.address.clone()!.equal(address2: cbValue.participant.address!) {
+ DispatchQueue.main.async {
+ participantDevice.isAdmin = isAdmin
+ }
+ }
+ })
+ }
+ )
+
+ self.mConferenceSuscriptions.insert(
+ self.currentCall?.conference?.publisher?.onParticipantDeviceIsSpeakingChanged?.postOnMainQueue {(cbValue: (conference: Conference, participantDevice: ParticipantDevice, isSpeaking: Bool)) in
+ let isSpeaking = cbValue.participantDevice.isSpeaking
+ if self.myParticipantModel != nil && self.myParticipantModel!.address.clone()!.equal(address2: cbValue.participantDevice.address!) {
+ DispatchQueue.main.async {
+ self.myParticipantModel!.isSpeaking = isSpeaking
+ }
+ }
+ self.participantList.forEach({ participantDeviceList in
+ if participantDeviceList.address.clone()!.equal(address2: cbValue.participantDevice.address!) {
+ DispatchQueue.main.async {
+ participantDeviceList.isSpeaking = isSpeaking
+ }
+ }
+ })
}
)
}