Add SipAddressesPopup to StartCallFragment, StartConversationFragment, and AddParticipantsFragment

This commit is contained in:
Benoit Martins 2026-03-19 17:13:22 +01:00
parent 54b8ae4b02
commit b84bd1faf3
8 changed files with 511 additions and 42 deletions

View file

@ -1,7 +1,7 @@
import Foundation
public enum AppGitInfo {
public static let branch = "master"
public static let commit = "b82156d2f"
public static let branch = "feature/address_selector"
public static let commit = "dcfa42329"
public static let tag = "6.1.0-alpha"
}

View file

@ -150,14 +150,14 @@ struct ContactInnerFragment: View {
Button(action: {
CoreContext.shared.doOnCoreQueue { core in
if contactAvatarModel.addresses.count == 1 {
if contactAvatarModel.addresses.count == 1 && contactAvatarModel.phoneNumbersWithLabel.isEmpty {
do {
let address = try Factory.Instance.createAddress(addr: contactAvatarModel.address)
telecomManager.doCallOrJoinConf(address: address, isVideo: false)
} catch {
Log.error("[ContactInnerFragment] unable to create address for a new outgoing call : \(contactAvatarModel.address) \(error) ")
}
} else if contactAvatarModel.addresses.count < 1 && contactAvatarModel.phoneNumbersWithLabel.count == 1 {
} else if contactAvatarModel.addresses.isEmpty && contactAvatarModel.phoneNumbersWithLabel.count == 1 {
if let firstPhoneNumbersWithLabel = contactAvatarModel.phoneNumbersWithLabel.first, let address = core.interpretUrl(url: firstPhoneNumbersWithLabel.phoneNumber, applyInternationalPrefix: LinphoneUtils.applyInternationalPrefix(core: core)) {
telecomManager.doCallOrJoinConf(address: address, isVideo: false)
}
@ -191,14 +191,14 @@ struct ContactInnerFragment: View {
Button(action: {
CoreContext.shared.doOnCoreQueue { core in
if contactAvatarModel.addresses.count == 1 {
if contactAvatarModel.addresses.count == 1 && contactAvatarModel.phoneNumbersWithLabel.isEmpty {
do {
let address = try Factory.Instance.createAddress(addr: contactAvatarModel.address)
contactsListViewModel.createOneToOneChatRoomWith(remote: address)
} catch {
Log.error("[ContactInnerFragment] unable to create address for a new outgoing call : \(contactAvatarModel.address) \(error) ")
}
} else if contactAvatarModel.addresses.count < 1 && contactAvatarModel.phoneNumbersWithLabel.count == 1 {
} else if contactAvatarModel.addresses.isEmpty && contactAvatarModel.phoneNumbersWithLabel.count == 1 {
if let firstPhoneNumbersWithLabel = contactAvatarModel.phoneNumbersWithLabel.first, let address = core.interpretUrl(url: firstPhoneNumbersWithLabel.phoneNumber, applyInternationalPrefix: LinphoneUtils.applyInternationalPrefix(core: core)) {
contactsListViewModel.createOneToOneChatRoomWith(remote: address)
}
@ -233,14 +233,14 @@ struct ContactInnerFragment: View {
if !SharedMainViewModel.shared.disableVideoCall {
Button(action: {
CoreContext.shared.doOnCoreQueue { core in
if contactAvatarModel.addresses.count == 1 {
if contactAvatarModel.addresses.count == 1 && contactAvatarModel.phoneNumbersWithLabel.isEmpty {
do {
let address = try Factory.Instance.createAddress(addr: contactAvatarModel.address)
telecomManager.doCallOrJoinConf(address: address, isVideo: true)
} catch {
Log.error("[ContactInnerFragment] unable to create address for a new outgoing call : \(contactAvatarModel.address) \(error) ")
}
} else if contactAvatarModel.addresses.count < 1 && contactAvatarModel.phoneNumbersWithLabel.count == 1 {
} else if contactAvatarModel.addresses.isEmpty && contactAvatarModel.phoneNumbersWithLabel.count == 1 {
if let firstPhoneNumbersWithLabel = contactAvatarModel.phoneNumbersWithLabel.first, let address = core.interpretUrl(url: firstPhoneNumbersWithLabel.phoneNumber, applyInternationalPrefix: LinphoneUtils.applyInternationalPrefix(core: core)) {
telecomManager.doCallOrJoinConf(address: address, isVideo: true)
}

View file

@ -85,7 +85,51 @@ struct SipAddressesPopup: View {
}
}
} catch {
Log.error("[ContactInnerActionsFragment] unable to create address for a new outgoing call : \(contactAvatarModel.addresses[index]) \(error) ")
Log.error("[SipAddressesPopup] unable to create address for a new outgoing call : \(contactAvatarModel.addresses[index]) \(error) ")
}
}
}
ForEach(0..<contactAvatarModel.phoneNumbersWithLabel.count, id: \.self) { index in
HStack {
HStack {
VStack {
Text(String(localized: "phone_number") + ":")
.default_text_style_700(styleSize: 14)
.frame(maxWidth: .infinity, alignment: .leading)
Text(contactAvatarModel.phoneNumbersWithLabel[index].phoneNumber)
.default_text_style(styleSize: 14)
.frame(maxWidth: .infinity, alignment: .leading)
.lineLimit(1)
.fixedSize(horizontal: false, vertical: true)
}
Spacer()
}
.padding(.vertical, 15)
.padding(.horizontal, 10)
}
.background(.white)
.onTapGesture {
CoreContext.shared.doOnCoreQueue { core in
if let address = core.interpretUrl(url: contactAvatarModel.phoneNumbersWithLabel[index].phoneNumber, applyInternationalPrefix: LinphoneUtils.applyInternationalPrefix(core: core)) {
DispatchQueue.main.async {
if isShowSipAddressesPopupType != 1 {
withAnimation {
isShowSipAddressesPopup = false
telecomManager.doCallOrJoinConf(address: address, isVideo: isShowSipAddressesPopupType == 2)
isShowSipAddressesPopupType = 0
}
} else {
withAnimation {
isShowSipAddressesPopup = false
contactsListViewModel.createOneToOneChatRoomWith(remote: address)
isShowSipAddressesPopupType = 0
}
}
}
} else {
Log.error("[SipAddressesPopup] unable to create address (interpret Url for phone number) for a new outgoing call : \(contactAvatarModel.addresses[index])")
}
}
}
}
@ -97,6 +141,7 @@ struct SipAddressesPopup: View {
.frame(maxHeight: .infinity)
.shadow(color: Color.orangeMain500, radius: 0, x: 0, y: 2)
.frame(maxWidth: SharedMainViewModel.shared.maxWidth)
.padding(.horizontal, 20)
.position(x: geometry.size.width / 2, y: geometry.size.height / 2)
}
}

View file

@ -1276,8 +1276,8 @@ struct ContentView: View {
if isShowStartCallFragment {
StartCallFragment(
isShowStartCallFragment: $isShowStartCallFragment,
showingDialer: $showingDialer,
isShowStartCallFragment: $isShowStartCallFragment,
resetCallView: {callViewModel.resetCallView()}
)
.environmentObject(callViewModel)

View file

@ -32,6 +32,9 @@ struct StartConversationFragment: View {
@Binding var isShowStartConversationFragment: Bool
@State private var contactAvatarModel: ContactAvatarModel? = nil
@State private var isShowSipAddressesPopup: Bool = false
@FocusState var isSearchFieldFocused: Bool
@State private var delayedColor = Color.white
@ -184,7 +187,24 @@ struct StartConversationFragment: View {
}
ContactsListFragment(showingSheet: .constant(false), startCallFunc: { addr in
startConversationViewModel.createOneToOneChatRoomWith(remote: addr)
CoreContext.shared.doOnCoreQueue { core in
ContactAvatarModel.getAvatarModelFromAddress(address: addr) { contactAvatarModel in
self.contactAvatarModel = contactAvatarModel
DispatchQueue.main.async {
if contactAvatarModel.addresses.count == 1 && contactAvatarModel.phoneNumbersWithLabel.isEmpty {
startConversationViewModel.createOneToOneChatRoomWith(remote: addr)
} else if contactAvatarModel.addresses.isEmpty && contactAvatarModel.phoneNumbersWithLabel.count == 1 {
if let firstPhoneNumbersWithLabel = contactAvatarModel.phoneNumbersWithLabel.first, let phoneAddr = core.interpretUrl(url: firstPhoneNumbersWithLabel.phoneNumber, applyInternationalPrefix: LinphoneUtils.applyInternationalPrefix(core: core)) {
startConversationViewModel.createOneToOneChatRoomWith(remote: phoneAddr)
}
} else {
DispatchQueue.main.async {
isShowSipAddressesPopup = true
}
}
}
}
}
})
.padding(.horizontal, 16)
@ -213,6 +233,100 @@ struct StartConversationFragment: View {
}
.background(.white)
if isShowSipAddressesPopup && contactAvatarModel != nil {
VStack(alignment: .leading) {
HStack {
Text("contact_dialog_pick_phone_number_or_sip_address_title")
.default_text_style_800(styleSize: 16)
.padding(.bottom, 2)
Spacer()
Image("x")
.renderingMode(.template)
.resizable()
.foregroundStyle(Color.grayMain2c600)
.frame(width: 25, height: 25)
.padding(.all, 10)
}
.frame(maxWidth: .infinity)
ForEach(0..<contactAvatarModel!.addresses.count, id: \.self) { index in
HStack {
HStack {
VStack {
Text(String(localized: "sip_address") + ":")
.default_text_style_700(styleSize: 14)
.frame(maxWidth: .infinity, alignment: .leading)
Text(contactAvatarModel!.addresses[index].dropFirst(4))
.default_text_style(styleSize: 14)
.frame(maxWidth: .infinity, alignment: .leading)
.lineLimit(1)
.fixedSize(horizontal: false, vertical: true)
}
Spacer()
}
.padding(.vertical, 15)
.padding(.horizontal, 10)
}
.background(.white)
.onTapGesture {
do {
let addr = try Factory.Instance.createAddress(addr: contactAvatarModel!.addresses[index])
startConversationViewModel.createOneToOneChatRoomWith(remote: addr)
} catch {
Log.error("[StartConversationFragment] unable to create address for a new outgoing call : \(contactAvatarModel!.addresses[index]) \(error) ")
}
}
}
ForEach(0..<contactAvatarModel!.phoneNumbersWithLabel.count, id: \.self) { index in
HStack {
HStack {
VStack {
Text(String(localized: "phone_number") + ":")
.default_text_style_700(styleSize: 14)
.frame(maxWidth: .infinity, alignment: .leading)
Text(contactAvatarModel!.phoneNumbersWithLabel[index].phoneNumber)
.default_text_style(styleSize: 14)
.frame(maxWidth: .infinity, alignment: .leading)
.lineLimit(1)
.fixedSize(horizontal: false, vertical: true)
}
Spacer()
}
.padding(.vertical, 15)
.padding(.horizontal, 10)
}
.background(.white)
.onTapGesture {
CoreContext.shared.doOnCoreQueue { core in
if let phoneAddr = core.interpretUrl(url: contactAvatarModel!.phoneNumbersWithLabel[index].phoneNumber, applyInternationalPrefix: LinphoneUtils.applyInternationalPrefix(core: core)) {
DispatchQueue.main.async {
startConversationViewModel.createOneToOneChatRoomWith(remote: phoneAddr)
}
} else {
Log.error("[StartConversationFragment] unable to create address (interpret Url for phone number) for a new outgoing call : \(contactAvatarModel!.addresses[index])")
}
}
}
}
}
.padding(.horizontal, 20)
.padding(.vertical, 20)
.background(.white)
.cornerRadius(20)
.frame(maxHeight: .infinity)
.shadow(color: Color.orangeMain500, radius: 0, x: 0, y: 2)
.frame(maxWidth: SharedMainViewModel.shared.maxWidth)
.padding(.horizontal, 20)
.background(.black.opacity(0.65))
.zIndex(3)
.onTapGesture {
isShowSipAddressesPopup.toggle()
}
}
if startConversationViewModel.operationOneToOneInProgress {
PopupLoadingView()
.background(.black.opacity(0.65))

View file

@ -232,6 +232,7 @@ struct HistoryContactFragment: View {
.frame(maxWidth: .infinity)
.padding(.top, 10)
.padding(.bottom, 2)
.padding(.horizontal, 10)
.background(Color.gray100)
HStack {

View file

@ -29,14 +29,18 @@ struct StartCallFragment: View {
@ObservedObject private var telecomManager = TelecomManager.shared
@EnvironmentObject var callViewModel: CallViewModel
@EnvironmentObject var conversationsListViewModel: ConversationsListViewModel
@StateObject private var startCallViewModel = StartCallViewModel()
@State private var contactAvatarModel: ContactAvatarModel? = nil
@State private var transferAddress: Address? = nil
@State private var isShowTransferPopup: Bool = false
@State private var isShowSipAddressesPopup: Bool = false
@Binding var isShowStartCallFragment: Bool
@Binding var showingDialer: Bool
@Binding var isShowStartCallFragment: Bool
@FocusState var isSearchFieldFocused: Bool
@State private var delayedColor = Color.white
@ -290,28 +294,68 @@ struct StartCallFragment: View {
ContactsListFragment(showingSheet: .constant(false)
, startCallFunc: { addr in
if callViewModel.isTransferInsteadCall {
self.transferAddress = addr
self.isShowTransferPopup = true
} else {
showingDialer = false
startCallViewModel.searchField = ""
magicSearch.currentFilter = ""
magicSearch.searchForContacts()
if callViewModel.isTransferInsteadCall == true {
callViewModel.isTransferInsteadCall = false
}
resetCallView()
delayColorDismiss()
withAnimation {
isShowStartCallFragment.toggle()
telecomManager.doCallOrJoinConf(address: addr)
CoreContext.shared.doOnCoreQueue { core in
ContactAvatarModel.getAvatarModelFromAddress(address: addr) { contactAvatarModel in
self.contactAvatarModel = contactAvatarModel
DispatchQueue.main.async {
if contactAvatarModel.addresses.count == 1 && contactAvatarModel.phoneNumbersWithLabel.isEmpty {
if callViewModel.isTransferInsteadCall {
self.transferAddress = addr
self.isShowTransferPopup = true
} else {
showingDialer = false
startCallViewModel.searchField = ""
magicSearch.currentFilter = ""
magicSearch.searchForContacts()
if callViewModel.isTransferInsteadCall == true {
callViewModel.isTransferInsteadCall = false
}
resetCallView()
delayColorDismiss()
withAnimation {
isShowStartCallFragment.toggle()
telecomManager.doCallOrJoinConf(address: addr)
}
}
} else if contactAvatarModel.addresses.isEmpty && contactAvatarModel.phoneNumbersWithLabel.count == 1 {
if let firstPhoneNumbersWithLabel = contactAvatarModel.phoneNumbersWithLabel.first, let addr = core.interpretUrl(url: firstPhoneNumbersWithLabel.phoneNumber, applyInternationalPrefix: LinphoneUtils.applyInternationalPrefix(core: core)) {
if callViewModel.isTransferInsteadCall {
self.transferAddress = addr
self.isShowTransferPopup = true
} else {
showingDialer = false
startCallViewModel.searchField = ""
magicSearch.currentFilter = ""
magicSearch.searchForContacts()
if callViewModel.isTransferInsteadCall == true {
callViewModel.isTransferInsteadCall = false
}
resetCallView()
delayColorDismiss()
withAnimation {
isShowStartCallFragment.toggle()
telecomManager.doCallOrJoinConf(address: addr)
}
}
}
} else {
DispatchQueue.main.async {
isShowSipAddressesPopup = true
}
}
}
}
}
})
@ -342,6 +386,151 @@ struct StartCallFragment: View {
}
.background(.white)
if isShowSipAddressesPopup && contactAvatarModel != nil {
VStack(alignment: .leading) {
HStack {
Text("contact_dialog_pick_phone_number_or_sip_address_title")
.default_text_style_800(styleSize: 16)
.padding(.bottom, 2)
Spacer()
Image("x")
.renderingMode(.template)
.resizable()
.foregroundStyle(Color.grayMain2c600)
.frame(width: 25, height: 25)
.padding(.all, 10)
}
.frame(maxWidth: .infinity)
ForEach(0..<contactAvatarModel!.addresses.count, id: \.self) { index in
HStack {
HStack {
VStack {
Text(String(localized: "sip_address") + ":")
.default_text_style_700(styleSize: 14)
.frame(maxWidth: .infinity, alignment: .leading)
Text(contactAvatarModel!.addresses[index].dropFirst(4))
.default_text_style(styleSize: 14)
.frame(maxWidth: .infinity, alignment: .leading)
.lineLimit(1)
.fixedSize(horizontal: false, vertical: true)
}
Spacer()
}
.padding(.vertical, 15)
.padding(.horizontal, 10)
}
.background(.white)
.onTapGesture {
do {
let addr = try Factory.Instance.createAddress(addr: contactAvatarModel!.addresses[index])
if callViewModel.isTransferInsteadCall {
self.isShowSipAddressesPopup = false
self.transferAddress = addr
self.isShowTransferPopup = true
} else {
showingDialer = false
startCallViewModel.searchField = ""
magicSearch.currentFilter = ""
magicSearch.searchForContacts()
if callViewModel.isTransferInsteadCall == true {
callViewModel.isTransferInsteadCall = false
}
resetCallView()
delayColorDismiss()
withAnimation {
isShowSipAddressesPopup = false
isShowStartCallFragment.toggle()
telecomManager.doCallOrJoinConf(address: addr)
}
}
} catch {
Log.error("[StartCallFragment] unable to create address for a new outgoing call : \(contactAvatarModel!.addresses[index]) \(error) ")
}
}
}
ForEach(0..<contactAvatarModel!.phoneNumbersWithLabel.count, id: \.self) { index in
HStack {
HStack {
VStack {
Text(String(localized: "phone_number") + ":")
.default_text_style_700(styleSize: 14)
.frame(maxWidth: .infinity, alignment: .leading)
Text(contactAvatarModel!.phoneNumbersWithLabel[index].phoneNumber)
.default_text_style(styleSize: 14)
.frame(maxWidth: .infinity, alignment: .leading)
.lineLimit(1)
.fixedSize(horizontal: false, vertical: true)
}
Spacer()
}
.padding(.vertical, 15)
.padding(.horizontal, 10)
}
.background(.white)
.onTapGesture {
CoreContext.shared.doOnCoreQueue { core in
if let addr = core.interpretUrl(url: contactAvatarModel!.phoneNumbersWithLabel[index].phoneNumber, applyInternationalPrefix: LinphoneUtils.applyInternationalPrefix(core: core)) {
DispatchQueue.main.async {
if callViewModel.isTransferInsteadCall {
self.isShowSipAddressesPopup = false
self.transferAddress = addr
self.isShowTransferPopup = true
} else {
showingDialer = false
startCallViewModel.searchField = ""
magicSearch.currentFilter = ""
magicSearch.searchForContacts()
if callViewModel.isTransferInsteadCall == true {
callViewModel.isTransferInsteadCall = false
}
resetCallView()
delayColorDismiss()
withAnimation {
isShowSipAddressesPopup = false
isShowStartCallFragment.toggle()
telecomManager.doCallOrJoinConf(address: addr)
}
}
}
} else {
Log.error("[StartCallFragment] unable to create address (interpret Url for phone number) for a new outgoing call : \(contactAvatarModel!.addresses[index])")
}
}
}
}
}
.padding(.horizontal, 20)
.padding(.vertical, 20)
.background(.white)
.cornerRadius(20)
.frame(maxHeight: .infinity)
.shadow(color: Color.orangeMain500, radius: 0, x: 0, y: 2)
.frame(maxWidth: SharedMainViewModel.shared.maxWidth)
.padding(.horizontal, 20)
.background(.black.opacity(0.65))
.zIndex(3)
.onTapGesture {
isShowSipAddressesPopup.toggle()
}
}
if isShowTransferPopup {
PopupView(
isShowPopup: $isShowTransferPopup,
@ -559,8 +748,8 @@ struct StartCallFragment: View {
#Preview {
StartCallFragment(
isShowStartCallFragment: .constant(true),
showingDialer: .constant(false),
isShowStartCallFragment: .constant(true),
resetCallView: {}
)
}

View file

@ -35,6 +35,9 @@ struct AddParticipantsFragment: View {
@FocusState var isSearchFieldFocused: Bool
@State private var isShowSipAddressesPopup: Bool = false
@State private var contactAvatarModel: ContactAvatarModel? = nil
var dismissOnCheckClick: Bool
var body: some View {
@ -208,6 +211,11 @@ struct AddParticipantsFragment: View {
if addParticipantsViewModel.participantsToAdd.contains(where: {
$0.address.asStringUriOnly() == contactsManager.avatarListModel[index].address
|| $0.avatarModel.address == contactsManager.avatarListModel[index].address
|| phoneListsEqual(
$0.avatarModel.phoneNumbersWithLabel,
contactsManager.avatarListModel[index].phoneNumbersWithLabel
)
}) {
Image("check")
.renderingMode(.template)
@ -221,13 +229,20 @@ struct AddParticipantsFragment: View {
.background(.white)
.onTapGesture {
CoreContext.shared.doOnCoreQueue { core in
if !contactsManager.avatarListModel[index].address.isEmpty {
if let addr = try? Factory.Instance.createAddress(addr: contactsManager.avatarListModel[index].address) {
addParticipantsViewModel.selectParticipant(addr: addr)
}
} else if !contactsManager.avatarListModel[index].phoneNumbersWithLabel.isEmpty {
if let address = core.interpretUrl(url: contactsManager.avatarListModel[index].phoneNumbersWithLabel.first?.phoneNumber ?? "", applyInternationalPrefix: LinphoneUtils.applyInternationalPrefix(core: core)) {
addParticipantsViewModel.selectParticipant(addr: address)
self.contactAvatarModel = contactsManager.avatarListModel[index]
if let contactAvatarModelTmp = self.contactAvatarModel {
if contactAvatarModelTmp.addresses.count == 1 && contactAvatarModelTmp.phoneNumbersWithLabel.isEmpty {
if let firstAddress = contactAvatarModelTmp.addresses.first, let addr = try? Factory.Instance.createAddress(addr: firstAddress) {
addParticipantsViewModel.selectParticipant(addr: addr)
}
} else if contactAvatarModelTmp.addresses.isEmpty && contactAvatarModelTmp.phoneNumbersWithLabel.count == 1 {
if let address = core.interpretUrl(url: contactAvatarModelTmp.phoneNumbersWithLabel.first?.phoneNumber ?? "", applyInternationalPrefix: LinphoneUtils.applyInternationalPrefix(core: core)) {
addParticipantsViewModel.selectParticipant(addr: address)
}
} else {
DispatchQueue.main.async {
isShowSipAddressesPopup = true
}
}
}
}
@ -255,6 +270,7 @@ struct AddParticipantsFragment: View {
}
}
}
Button {
withAnimation {
confirmAddParticipantsFunc(addParticipantsViewModel.participantsToAdd)
@ -277,6 +293,100 @@ struct AddParticipantsFragment: View {
}
.padding()
if isShowSipAddressesPopup && contactAvatarModel != nil {
VStack(alignment: .leading) {
HStack {
Text("contact_dialog_pick_phone_number_or_sip_address_title")
.default_text_style_800(styleSize: 16)
.padding(.bottom, 2)
Spacer()
Image("x")
.renderingMode(.template)
.resizable()
.foregroundStyle(Color.grayMain2c600)
.frame(width: 25, height: 25)
.padding(.all, 10)
}
.frame(maxWidth: .infinity)
ForEach(0..<contactAvatarModel!.addresses.count, id: \.self) { index in
HStack {
HStack {
VStack {
Text(String(localized: "sip_address") + ":")
.default_text_style_700(styleSize: 14)
.frame(maxWidth: .infinity, alignment: .leading)
Text(contactAvatarModel!.addresses[index].dropFirst(4))
.default_text_style(styleSize: 14)
.frame(maxWidth: .infinity, alignment: .leading)
.lineLimit(1)
.fixedSize(horizontal: false, vertical: true)
}
Spacer()
}
.padding(.vertical, 15)
.padding(.horizontal, 10)
}
.background(.white)
.onTapGesture {
do {
let addr = try Factory.Instance.createAddress(addr: contactAvatarModel!.addresses[index])
addParticipantsViewModel.selectParticipant(addr: addr)
self.isShowSipAddressesPopup = false
} catch {
Log.error("[AddParticipantsFragment] unable to create address for a new outgoing call : \(contactAvatarModel!.addresses[index]) \(error) ")
}
}
}
ForEach(0..<contactAvatarModel!.phoneNumbersWithLabel.count, id: \.self) { index in
HStack {
HStack {
VStack {
Text(String(localized: "phone_number") + ":")
.default_text_style_700(styleSize: 14)
.frame(maxWidth: .infinity, alignment: .leading)
Text(contactAvatarModel!.phoneNumbersWithLabel[index].phoneNumber)
.default_text_style(styleSize: 14)
.frame(maxWidth: .infinity, alignment: .leading)
.lineLimit(1)
.fixedSize(horizontal: false, vertical: true)
}
Spacer()
}
.padding(.vertical, 15)
.padding(.horizontal, 10)
}
.background(.white)
.onTapGesture {
CoreContext.shared.doOnCoreQueue { core in
if let phoneAddr = core.interpretUrl(url: contactAvatarModel!.phoneNumbersWithLabel[index].phoneNumber, applyInternationalPrefix: LinphoneUtils.applyInternationalPrefix(core: core)) {
addParticipantsViewModel.selectParticipant(addr: phoneAddr)
self.isShowSipAddressesPopup = false
} else {
Log.error("[AddParticipantsFragment] unable to create address (interpret Url for phone number) for a new outgoing call : \(contactAvatarModel!.addresses[index])")
}
}
}
}
}
.padding(.horizontal, 20)
.padding(.vertical, 20)
.background(.white)
.cornerRadius(20)
.frame(maxHeight: .infinity)
.shadow(color: Color.orangeMain500, radius: 0, x: 0, y: 2)
.frame(maxWidth: SharedMainViewModel.shared.maxWidth)
.padding(.horizontal, 20)
.background(.black.opacity(0.65))
.zIndex(3)
.onTapGesture {
isShowSipAddressesPopup.toggle()
}
}
}
.navigationTitle("")
.navigationBarHidden(true)
@ -362,4 +472,14 @@ struct AddParticipantsFragment: View {
.listRowSeparator(.hidden)
}
}
func phoneListsEqual(
_ lhs: [(label: String, phoneNumber: String)],
_ rhs: [(label: String, phoneNumber: String)]
) -> Bool {
lhs.count == rhs.count &&
zip(lhs, rhs).allSatisfy { l, r in
l.label == r.label && l.phoneNumber == r.phoneNumber
}
}
}