forked from mirrors/linphone-iphone
Add mosaic mode to conference call view
This commit is contained in:
parent
b16372c420
commit
1f0c3fa5f7
13 changed files with 1165 additions and 370 deletions
21
Linphone/Assets.xcassets/picture-in-picture.imageset/Contents.json
vendored
Normal file
21
Linphone/Assets.xcassets/picture-in-picture.imageset/Contents.json
vendored
Normal 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
|
||||
}
|
||||
}
|
||||
1
Linphone/Assets.xcassets/picture-in-picture.imageset/picture-in-picture.svg
vendored
Normal file
1
Linphone/Assets.xcassets/picture-in-picture.imageset/picture-in-picture.svg
vendored
Normal 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 |
21
Linphone/Assets.xcassets/plus.imageset/Contents.json
vendored
Normal file
21
Linphone/Assets.xcassets/plus.imageset/Contents.json
vendored
Normal 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
|
||||
}
|
||||
}
|
||||
1
Linphone/Assets.xcassets/plus.imageset/plus.svg
vendored
Normal file
1
Linphone/Assets.xcassets/plus.imageset/plus.svg
vendored
Normal 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 |
21
Linphone/Assets.xcassets/squares-four.imageset/Contents.json
vendored
Normal file
21
Linphone/Assets.xcassets/squares-four.imageset/Contents.json
vendored
Normal 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
|
||||
}
|
||||
}
|
||||
1
Linphone/Assets.xcassets/squares-four.imageset/squares-four.svg
vendored
Normal file
1
Linphone/Assets.xcassets/squares-four.imageset/squares-four.svg
vendored
Normal 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 |
21
Linphone/Assets.xcassets/waveform.imageset/Contents.json
vendored
Normal file
21
Linphone/Assets.xcassets/waveform.imageset/Contents.json
vendored
Normal 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
|
||||
}
|
||||
}
|
||||
1
Linphone/Assets.xcassets/waveform.imageset/waveform.svg
vendored
Normal file
1
Linphone/Assets.xcassets/waveform.imageset/waveform.svg
vendored
Normal 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 |
|
|
@ -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
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue