Add transfer call and attended transfer

This commit is contained in:
benoit.martins 2024-01-25 15:49:28 +01:00
parent 4048fa3075
commit 433e28e945
6 changed files with 198 additions and 49 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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