Add mosaic mode to conference call view

This commit is contained in:
Benoit Martins 2024-04-29 16:03:40 +02:00
parent b16372c420
commit 1f0c3fa5f7
13 changed files with 1165 additions and 370 deletions

View file

@ -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
}
}

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="#000000" viewBox="0 0 256 256"><path d="M216,48H40A16,16,0,0,0,24,64V192a16,16,0,0,0,16,16H216a16,16,0,0,0,16-16V64A16,16,0,0,0,216,48ZM40,64H216v56H136a8,8,0,0,0-8,8v64H40ZM216,192H144V136h72v56Z"></path></svg>

After

Width:  |  Height:  |  Size: 280 B

View file

@ -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
}
}

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="#000000" viewBox="0 0 256 256"><path d="M224,128a8,8,0,0,1-8,8H136v80a8,8,0,0,1-16,0V136H40a8,8,0,0,1,0-16h80V40a8,8,0,0,1,16,0v80h80A8,8,0,0,1,224,128Z"></path></svg>

After

Width:  |  Height:  |  Size: 236 B

View file

@ -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
}
}

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="#000000" viewBox="0 0 256 256"><path d="M104,40H56A16,16,0,0,0,40,56v48a16,16,0,0,0,16,16h48a16,16,0,0,0,16-16V56A16,16,0,0,0,104,40Zm0,64H56V56h48v48Zm96-64H152a16,16,0,0,0-16,16v48a16,16,0,0,0,16,16h48a16,16,0,0,0,16-16V56A16,16,0,0,0,200,40Zm0,64H152V56h48v48Zm-96,32H56a16,16,0,0,0-16,16v48a16,16,0,0,0,16,16h48a16,16,0,0,0,16-16V152A16,16,0,0,0,104,136Zm0,64H56V152h48v48Zm96-64H152a16,16,0,0,0-16,16v48a16,16,0,0,0,16,16h48a16,16,0,0,0,16-16V152A16,16,0,0,0,200,136Zm0,64H152V152h48v48Z"></path></svg>

After

Width:  |  Height:  |  Size: 576 B

View file

@ -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
}
}

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="#000000" viewBox="0 0 256 256"><path d="M56,96v64a8,8,0,0,1-16,0V96a8,8,0,0,1,16,0ZM88,24a8,8,0,0,0-8,8V224a8,8,0,0,0,16,0V32A8,8,0,0,0,88,24Zm40,32a8,8,0,0,0-8,8V192a8,8,0,0,0,16,0V64A8,8,0,0,0,128,56Zm40,32a8,8,0,0,0-8,8v64a8,8,0,0,0,16,0V96A8,8,0,0,0,168,88Zm40-16a8,8,0,0,0-8,8v96a8,8,0,0,0,16,0V80A8,8,0,0,0,208,72Z"></path></svg>

After

Width:  |  Height:  |  Size: 404 B

View file

@ -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" : {

File diff suppressed because it is too large Load diff

View file

@ -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)

View file

@ -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
}
}

View file

@ -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
}
}
})
}
)
}