mirror of
https://gitlab.linphone.org/BC/public/linphone-iphone.git
synced 2026-01-24 14:48:07 +00:00
Add transfer call and attended transfer
This commit is contained in:
parent
4048fa3075
commit
433e28e945
6 changed files with 198 additions and 49 deletions
|
|
@ -237,6 +237,22 @@ final class CoreContext: ObservableObject {
|
|||
}
|
||||
})
|
||||
|
||||
self.mCoreSuscriptions.insert(self.mCore.publisher?.onTransferStateChanged?.postOnMainQueue { (cbValue: (_: Core, transfered: Call, callState: Call.State)) in
|
||||
Log.info(
|
||||
"[CoreContext] Transferred call \(cbValue.transfered.remoteAddress!.asStringUriOnly()) state changed \(cbValue.callState)"
|
||||
)
|
||||
if cbValue.callState == Call.State.Connected {
|
||||
ToastViewModel.shared.toastMessage = "Success_toast_call_transfer_successful"
|
||||
ToastViewModel.shared.displayToast = true
|
||||
} else if cbValue.callState == Call.State.OutgoingProgress {
|
||||
ToastViewModel.shared.toastMessage = "Success_toast_call_transfer_in_progress"
|
||||
ToastViewModel.shared.displayToast = true
|
||||
} else if cbValue.callState == Call.State.End || cbValue.callState == Call.State.Error {
|
||||
ToastViewModel.shared.toastMessage = "Failed_toast_call_transfer_failed"
|
||||
ToastViewModel.shared.displayToast = true
|
||||
}
|
||||
})
|
||||
|
||||
self.mIterateSuscription = Timer.publish(every: 0.02, on: .main, in: .common)
|
||||
.autoconnect()
|
||||
.receive(on: coreQueue)
|
||||
|
|
|
|||
|
|
@ -199,12 +199,21 @@
|
|||
},
|
||||
"Bluetooth" : {
|
||||
|
||||
},
|
||||
"Call has been successfully transferred" : {
|
||||
|
||||
},
|
||||
"Call history" : {
|
||||
|
||||
},
|
||||
"Call is being transferred" : {
|
||||
|
||||
},
|
||||
"Call list" : {
|
||||
|
||||
},
|
||||
"Call transfer failed!" : {
|
||||
|
||||
},
|
||||
"Calls" : {
|
||||
|
||||
|
|
@ -232,9 +241,6 @@
|
|||
},
|
||||
"Contacts" : {
|
||||
|
||||
},
|
||||
"Content" : {
|
||||
|
||||
},
|
||||
"Continue" : {
|
||||
|
||||
|
|
@ -558,9 +564,6 @@
|
|||
},
|
||||
"This contact will be deleted definitively." : {
|
||||
|
||||
},
|
||||
"Title" : {
|
||||
|
||||
},
|
||||
"TLS" : {
|
||||
|
||||
|
|
|
|||
|
|
@ -741,10 +741,14 @@ struct CallView: View {
|
|||
HStack(spacing: 0) {
|
||||
VStack {
|
||||
Button {
|
||||
withAnimation {
|
||||
callViewModel.isTransferInsteadCall = true
|
||||
MagicSearchSingleton.shared.searchForSuggestions()
|
||||
isShowStartCallFragment.toggle()
|
||||
if callViewModel.calls.count < 2 {
|
||||
withAnimation {
|
||||
callViewModel.isTransferInsteadCall = true
|
||||
MagicSearchSingleton.shared.searchForSuggestions()
|
||||
isShowStartCallFragment.toggle()
|
||||
}
|
||||
} else {
|
||||
callViewModel.transferClicked()
|
||||
}
|
||||
} label: {
|
||||
Image("phone-transfer")
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ class CallViewModel: ObservableObject {
|
|||
@Published var isMediaEncrypted: Bool = false
|
||||
@Published var isZrtpPq: Bool = false
|
||||
@Published var isRemoteDeviceTrusted: Bool = false
|
||||
@Published var selectedCall: Call? = nil
|
||||
@Published var selectedCall: Call?
|
||||
@Published var isTransferInsteadCall: Bool = false
|
||||
|
||||
var calls: [Call] = []
|
||||
|
|
@ -408,4 +408,53 @@ class CallViewModel: ObservableObject {
|
|||
self.zrtpPopupDisplayed = true
|
||||
}
|
||||
}
|
||||
|
||||
func transferClicked() {
|
||||
coreContext.doOnCoreQueue { core in
|
||||
var callToTransferTo = core.calls.last { call in
|
||||
call.state == Call.State.Paused && call.callLog?.callId != self.currentCall?.callLog?.callId
|
||||
}
|
||||
|
||||
if (callToTransferTo == nil) {
|
||||
Log.error(
|
||||
"[CallViewModel] Couldn't find a call in Paused state to transfer current call to"
|
||||
)
|
||||
} else {
|
||||
if self.currentCall != nil && self.currentCall!.remoteAddress != nil && callToTransferTo!.remoteAddress != nil {
|
||||
Log.info(
|
||||
"[CallViewModel] Doing an attended transfer between currently displayed call \(self.currentCall!.remoteAddress!.asStringUriOnly()) "
|
||||
+ "and paused call \(callToTransferTo!.remoteAddress!.asStringUriOnly())"
|
||||
)
|
||||
|
||||
do {
|
||||
try callToTransferTo!.transferToAnother(dest: self.currentCall!)
|
||||
Log.info("[CallViewModel] Attended transfer is successful")
|
||||
} catch _ {
|
||||
ToastViewModel.shared.toastMessage = "Failed_toast_call_transfer_failed"
|
||||
ToastViewModel.shared.displayToast = true
|
||||
|
||||
Log.error("[CallViewModel] Failed to make attended transfer!")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func blindTransferCallTo(toAddress: Address) {
|
||||
if self.currentCall != nil && self.currentCall!.remoteAddress != nil {
|
||||
Log.info(
|
||||
"[CallViewModel] Call \(self.currentCall!.remoteAddress!.asStringUriOnly()) is being blindly transferred to \(toAddress.asStringUriOnly())"
|
||||
)
|
||||
|
||||
do {
|
||||
try self.currentCall!.transferTo(referTo: toAddress)
|
||||
Log.info("[CallViewModel] Blind call transfer is successful")
|
||||
} catch _ {
|
||||
ToastViewModel.shared.toastMessage = "Failed_toast_call_transfer_failed"
|
||||
ToastViewModel.shared.displayToast = true
|
||||
|
||||
Log.error("[CallViewModel] Failed to make blind call transfer!")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,13 @@ struct ToastView: View {
|
|||
VStack {
|
||||
if toastViewModel.displayToast {
|
||||
HStack {
|
||||
if toastViewModel.toastMessage.contains("Info_") {
|
||||
if toastViewModel.toastMessage.contains("toast_call_transfer") {
|
||||
Image("phone-transfer")
|
||||
.resizable()
|
||||
.renderingMode(.template)
|
||||
.frame(width: 25, height: 25, alignment: .leading)
|
||||
.foregroundStyle(toastViewModel.toastMessage.contains("Success") ? Color.greenSuccess500 : Color.redDanger500)
|
||||
} else if toastViewModel.toastMessage.contains("Info_") {
|
||||
Image("trusted")
|
||||
.resizable()
|
||||
.frame(width: 25, height: 25, alignment: .leading)
|
||||
|
|
@ -110,6 +116,27 @@ struct ToastView: View {
|
|||
.default_text_style(styleSize: 15)
|
||||
.padding(8)
|
||||
|
||||
case "Success_toast_call_transfer_successful":
|
||||
Text("Call has been successfully transferred")
|
||||
.multilineTextAlignment(.center)
|
||||
.foregroundStyle(Color.greenSuccess500)
|
||||
.default_text_style(styleSize: 15)
|
||||
.padding(8)
|
||||
|
||||
case "Success_toast_call_transfer_in_progress":
|
||||
Text("Call is being transferred")
|
||||
.multilineTextAlignment(.center)
|
||||
.foregroundStyle(Color.greenSuccess500)
|
||||
.default_text_style(styleSize: 15)
|
||||
.padding(8)
|
||||
|
||||
case "Failed_toast_call_transfer_failed":
|
||||
Text("Call transfer failed!")
|
||||
.multilineTextAlignment(.center)
|
||||
.foregroundStyle(Color.redDanger500)
|
||||
.default_text_style(styleSize: 15)
|
||||
.padding(8)
|
||||
|
||||
default:
|
||||
Text("Error")
|
||||
.multilineTextAlignment(.center)
|
||||
|
|
|
|||
|
|
@ -177,26 +177,50 @@ struct StartCallFragment: View {
|
|||
}
|
||||
|
||||
ContactsListFragment(contactViewModel: ContactViewModel(), contactsListViewModel: ContactsListViewModel(), showingSheet: .constant(false), startCallFunc: { addr in
|
||||
showingDialer = false
|
||||
|
||||
DispatchQueue.global().asyncAfter(deadline: .now() + 0.2) {
|
||||
magicSearch.searchForContacts(
|
||||
sourceFlags: MagicSearch.Source.Friends.rawValue | MagicSearch.Source.LdapServers.rawValue)
|
||||
if callViewModel.isTransferInsteadCall {
|
||||
showingDialer = false
|
||||
|
||||
if callViewModel.isTransferInsteadCall == true {
|
||||
callViewModel.isTransferInsteadCall = false
|
||||
DispatchQueue.global().asyncAfter(deadline: .now() + 0.2) {
|
||||
magicSearch.searchForContacts(
|
||||
sourceFlags: MagicSearch.Source.Friends.rawValue | MagicSearch.Source.LdapServers.rawValue)
|
||||
|
||||
if callViewModel.isTransferInsteadCall == true {
|
||||
callViewModel.isTransferInsteadCall = false
|
||||
}
|
||||
|
||||
resetCallView()
|
||||
}
|
||||
|
||||
resetCallView()
|
||||
}
|
||||
|
||||
startCallViewModel.searchField = ""
|
||||
magicSearch.currentFilterSuggestions = ""
|
||||
delayColorDismiss()
|
||||
|
||||
withAnimation {
|
||||
isShowStartCallFragment.toggle()
|
||||
telecomManager.doCallWithCore(addr: addr, isVideo: false)
|
||||
startCallViewModel.searchField = ""
|
||||
magicSearch.currentFilterSuggestions = ""
|
||||
delayColorDismiss()
|
||||
|
||||
withAnimation {
|
||||
isShowStartCallFragment.toggle()
|
||||
callViewModel.blindTransferCallTo(toAddress: addr)
|
||||
}
|
||||
} else {
|
||||
showingDialer = false
|
||||
|
||||
DispatchQueue.global().asyncAfter(deadline: .now() + 0.2) {
|
||||
magicSearch.searchForContacts(
|
||||
sourceFlags: MagicSearch.Source.Friends.rawValue | MagicSearch.Source.LdapServers.rawValue)
|
||||
|
||||
if callViewModel.isTransferInsteadCall == true {
|
||||
callViewModel.isTransferInsteadCall = false
|
||||
}
|
||||
|
||||
resetCallView()
|
||||
}
|
||||
|
||||
startCallViewModel.searchField = ""
|
||||
magicSearch.currentFilterSuggestions = ""
|
||||
delayColorDismiss()
|
||||
|
||||
withAnimation {
|
||||
isShowStartCallFragment.toggle()
|
||||
telecomManager.doCallWithCore(addr: addr, isVideo: false)
|
||||
}
|
||||
}
|
||||
})
|
||||
.padding(.horizontal, 16)
|
||||
|
|
@ -235,29 +259,55 @@ struct StartCallFragment: View {
|
|||
var suggestionsList: some View {
|
||||
ForEach(0..<contactsManager.lastSearchSuggestions.count, id: \.self) { index in
|
||||
Button {
|
||||
showingDialer = false
|
||||
|
||||
DispatchQueue.global().asyncAfter(deadline: .now() + 0.2) {
|
||||
magicSearch.searchForContacts(
|
||||
sourceFlags: MagicSearch.Source.Friends.rawValue | MagicSearch.Source.LdapServers.rawValue)
|
||||
if callViewModel.isTransferInsteadCall {
|
||||
showingDialer = false
|
||||
|
||||
if callViewModel.isTransferInsteadCall == true {
|
||||
callViewModel.isTransferInsteadCall = false
|
||||
DispatchQueue.global().asyncAfter(deadline: .now() + 0.2) {
|
||||
magicSearch.searchForContacts(
|
||||
sourceFlags: MagicSearch.Source.Friends.rawValue | MagicSearch.Source.LdapServers.rawValue)
|
||||
|
||||
if callViewModel.isTransferInsteadCall == true {
|
||||
callViewModel.isTransferInsteadCall = false
|
||||
}
|
||||
|
||||
resetCallView()
|
||||
}
|
||||
|
||||
resetCallView()
|
||||
}
|
||||
|
||||
startCallViewModel.searchField = ""
|
||||
magicSearch.currentFilterSuggestions = ""
|
||||
delayColorDismiss()
|
||||
|
||||
withAnimation {
|
||||
isShowStartCallFragment.toggle()
|
||||
if contactsManager.lastSearchSuggestions[index].address != nil {
|
||||
telecomManager.doCallWithCore(
|
||||
addr: contactsManager.lastSearchSuggestions[index].address!, isVideo: false
|
||||
)
|
||||
startCallViewModel.searchField = ""
|
||||
magicSearch.currentFilterSuggestions = ""
|
||||
delayColorDismiss()
|
||||
|
||||
withAnimation {
|
||||
isShowStartCallFragment.toggle()
|
||||
if contactsManager.lastSearchSuggestions[index].address != nil {
|
||||
callViewModel.blindTransferCallTo(toAddress: contactsManager.lastSearchSuggestions[index].address!)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
showingDialer = false
|
||||
|
||||
DispatchQueue.global().asyncAfter(deadline: .now() + 0.2) {
|
||||
magicSearch.searchForContacts(
|
||||
sourceFlags: MagicSearch.Source.Friends.rawValue | MagicSearch.Source.LdapServers.rawValue)
|
||||
|
||||
if callViewModel.isTransferInsteadCall == true {
|
||||
callViewModel.isTransferInsteadCall = false
|
||||
}
|
||||
|
||||
resetCallView()
|
||||
}
|
||||
|
||||
startCallViewModel.searchField = ""
|
||||
magicSearch.currentFilterSuggestions = ""
|
||||
delayColorDismiss()
|
||||
|
||||
withAnimation {
|
||||
isShowStartCallFragment.toggle()
|
||||
if contactsManager.lastSearchSuggestions[index].address != nil {
|
||||
telecomManager.doCallWithCore(
|
||||
addr: contactsManager.lastSearchSuggestions[index].address!, isVideo: false
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
} label: {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue