Added attented transfer + setting to skip dialer when adding new call or transfering a call + fixed toast instead of snack for dialer transfer message
This commit is contained in:
parent
74fd59a541
commit
09bde054d0
12 changed files with 109 additions and 26 deletions
|
@ -15,6 +15,7 @@ Group changes to describe their impact on the project, as follows:
|
|||
### Added
|
||||
- Showing short term presence for contacts whom publish it + added setting to disable it (enabled by default for sip.linphone.org accounts)
|
||||
- Confirmation dialog before removing account
|
||||
- Attended transfer instead of blind transfer if there is more than 1 call
|
||||
|
||||
### Changed
|
||||
- Account EXPIRES is now set to 1 month instead of 1 year for sip.linphone.org accounts
|
||||
|
|
|
@ -66,7 +66,7 @@ fun popupTo(
|
|||
|
||||
/* Main activity related */
|
||||
|
||||
internal fun MainActivity.navigateToDialer(args: Bundle?) {
|
||||
internal fun MainActivity.navigateToDialer(args: Bundle? = null) {
|
||||
findNavController(R.id.nav_host_fragment).navigate(
|
||||
R.id.action_global_dialerFragment,
|
||||
args,
|
||||
|
@ -90,6 +90,14 @@ internal fun MainActivity.navigateToChatRoom(localAddress: String?, peerAddress:
|
|||
)
|
||||
}
|
||||
|
||||
internal fun MainActivity.navigateToContacts() {
|
||||
findNavController(R.id.nav_host_fragment).navigate(
|
||||
R.id.action_global_masterContactsFragment,
|
||||
null,
|
||||
popupTo(R.id.masterContactsFragment, true)
|
||||
)
|
||||
}
|
||||
|
||||
internal fun MainActivity.navigateToContact(contactId: String?) {
|
||||
val deepLink = "linphone-android://contact/view/$contactId"
|
||||
findNavController(R.id.nav_host_fragment).navigate(
|
||||
|
|
|
@ -339,9 +339,15 @@ class MainActivity : GenericActivity(), SnackBarActivity, NavController.OnDestin
|
|||
}
|
||||
intent.hasExtra("Dialer") -> {
|
||||
Log.i("[Main Activity] Found dialer intent extra, go to dialer")
|
||||
val args = Bundle()
|
||||
args.putBoolean("Transfer", intent.getBooleanExtra("Transfer", false))
|
||||
navigateToDialer(args)
|
||||
val isTransfer = intent.getBooleanExtra("Transfer", false)
|
||||
sharedViewModel.pendingCallTransfer = isTransfer
|
||||
navigateToDialer()
|
||||
}
|
||||
intent.hasExtra("Contacts") -> {
|
||||
Log.i("[Main Activity] Found contacts intent extra, go to contacts list")
|
||||
val isTransfer = intent.getBooleanExtra("Transfer", false)
|
||||
sharedViewModel.pendingCallTransfer = isTransfer
|
||||
navigateToContacts()
|
||||
}
|
||||
else -> {
|
||||
val core = coreContext.core
|
||||
|
|
|
@ -31,7 +31,6 @@ import android.content.res.Configuration
|
|||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.widget.Toast
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.google.android.material.transition.MaterialSharedAxis
|
||||
|
@ -152,8 +151,8 @@ class DialerFragment : SecureFragment<DialerFragmentBinding>() {
|
|||
viewModel.onMessageToNotifyEvent.observe(
|
||||
viewLifecycleOwner
|
||||
) {
|
||||
it.consume { id ->
|
||||
Toast.makeText(requireContext(), id, Toast.LENGTH_SHORT).show()
|
||||
it.consume { resourceId ->
|
||||
(requireActivity() as MainActivity).showSnackBar(resourceId)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -162,18 +161,21 @@ class DialerFragment : SecureFragment<DialerFragmentBinding>() {
|
|||
return
|
||||
}
|
||||
|
||||
if (arguments?.containsKey("Transfer") == true) {
|
||||
sharedViewModel.pendingCallTransfer = arguments?.getBoolean("Transfer") ?: false
|
||||
Log.i("[Dialer] Is pending call transfer: ${sharedViewModel.pendingCallTransfer}")
|
||||
}
|
||||
|
||||
if (arguments?.containsKey("URI") == true) {
|
||||
val address = arguments?.getString("URI") ?: ""
|
||||
Log.i("[Dialer] Found URI to call: $address")
|
||||
val skipAutoCall = arguments?.getBoolean("SkipAutoCallStart") ?: false
|
||||
|
||||
if (corePreferences.callRightAway && !skipAutoCall) {
|
||||
Log.i("[Dialer] Call right away setting is enabled, start the call to $address")
|
||||
if (corePreferences.skipDialerForNewCallAndTransfer) {
|
||||
if (sharedViewModel.pendingCallTransfer) {
|
||||
Log.i("[Dialer] We were asked to skip dialer so starting new call to [$address] now")
|
||||
viewModel.transferCallTo(address)
|
||||
} else {
|
||||
Log.i("[Dialer] We were asked to skip dialer so starting transfer to [$address] now")
|
||||
viewModel.directCall(address)
|
||||
}
|
||||
} else if (corePreferences.callRightAway && !skipAutoCall) {
|
||||
Log.i("[Dialer] Call right away setting is enabled, start the call to [$address]")
|
||||
viewModel.directCall(address)
|
||||
} else {
|
||||
sharedViewModel.dialerUri = address
|
||||
|
@ -184,6 +186,8 @@ class DialerFragment : SecureFragment<DialerFragmentBinding>() {
|
|||
Log.i("[Dialer] Pending call transfer mode = ${sharedViewModel.pendingCallTransfer}")
|
||||
viewModel.transferVisibility.value = sharedViewModel.pendingCallTransfer
|
||||
|
||||
viewModel.autoInitiateVideoCalls.value = coreContext.core.videoActivationPolicy.automaticallyInitiate
|
||||
|
||||
checkForUpdate()
|
||||
|
||||
checkPermissions()
|
||||
|
|
|
@ -98,6 +98,13 @@ class DialerViewModel : LogsUploadViewModel() {
|
|||
atLeastOneCall.value = core.callsNb > 0
|
||||
}
|
||||
|
||||
override fun onTransferStateChanged(core: Core, transfered: Call, callState: Call.State) {
|
||||
if (callState == Call.State.OutgoingProgress) {
|
||||
// Will work for both blind & attended transfer
|
||||
onMessageToNotifyEvent.value = Event(org.linphone.R.string.dialer_transfer_succeded)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onNetworkReachable(core: Core, reachable: Boolean) {
|
||||
val address = addressWaitingNetworkToBeCalled.orEmpty()
|
||||
if (reachable && address.isNotEmpty()) {
|
||||
|
@ -207,13 +214,7 @@ class DialerViewModel : LogsUploadViewModel() {
|
|||
fun transferCall(): Boolean {
|
||||
val addressToCall = enteredUri.value.orEmpty()
|
||||
return if (addressToCall.isNotEmpty()) {
|
||||
onMessageToNotifyEvent.value = Event(
|
||||
if (coreContext.transferCallTo(addressToCall)) {
|
||||
org.linphone.R.string.dialer_transfer_succeded
|
||||
} else {
|
||||
org.linphone.R.string.dialer_transfer_failed
|
||||
}
|
||||
)
|
||||
transferCallTo(addressToCall)
|
||||
eraseAll()
|
||||
true
|
||||
} else {
|
||||
|
@ -222,6 +223,12 @@ class DialerViewModel : LogsUploadViewModel() {
|
|||
}
|
||||
}
|
||||
|
||||
fun transferCallTo(addressToCall: String) {
|
||||
if (!coreContext.transferCallTo(addressToCall)) {
|
||||
onMessageToNotifyEvent.value = Event(org.linphone.R.string.dialer_transfer_failed)
|
||||
}
|
||||
}
|
||||
|
||||
fun switchCamera() {
|
||||
coreContext.switchCamera()
|
||||
}
|
||||
|
|
|
@ -249,7 +249,11 @@ class ConferenceCallFragment : GenericFragment<VoipConferenceCallFragmentBinding
|
|||
it.consume { isCallTransfer ->
|
||||
val intent = Intent()
|
||||
intent.setClass(requireContext(), MainActivity::class.java)
|
||||
intent.putExtra("Dialer", true)
|
||||
if (corePreferences.skipDialerForNewCallAndTransfer) {
|
||||
intent.putExtra("Contacts", true)
|
||||
} else {
|
||||
intent.putExtra("Dialer", true)
|
||||
}
|
||||
intent.putExtra("Transfer", isCallTransfer)
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
startActivity(intent)
|
||||
|
|
|
@ -161,7 +161,11 @@ class SingleCallFragment : GenericVideoPreviewFragment<VoipSingleCallFragmentBin
|
|||
it.consume { isCallTransfer ->
|
||||
val intent = Intent()
|
||||
intent.setClass(requireContext(), MainActivity::class.java)
|
||||
intent.putExtra("Dialer", true)
|
||||
if (corePreferences.skipDialerForNewCallAndTransfer) {
|
||||
intent.putExtra("Contacts", true)
|
||||
} else {
|
||||
intent.putExtra("Dialer", true)
|
||||
}
|
||||
intent.putExtra("Transfer", isCallTransfer)
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
startActivity(intent)
|
||||
|
|
|
@ -79,6 +79,8 @@ class ControlsViewModel : ViewModel() {
|
|||
|
||||
val showTakeSnapshotButton = MutableLiveData<Boolean>()
|
||||
|
||||
val attendedTransfer = MutableLiveData<Boolean>()
|
||||
|
||||
val goToConferenceParticipantsListEvent: MutableLiveData<Event<Boolean>> by lazy {
|
||||
MutableLiveData<Event<Boolean>>()
|
||||
}
|
||||
|
@ -117,6 +119,7 @@ class ControlsViewModel : ViewModel() {
|
|||
Log.i("[Call Controls] State changed: $state")
|
||||
isOutgoingEarlyMedia.value = state == Call.State.OutgoingEarlyMedia
|
||||
isIncomingEarlyMediaVideo.value = state == Call.State.IncomingEarlyMedia && call.remoteParams?.isVideoEnabled == true
|
||||
attendedTransfer.value = core.callsNb > 1
|
||||
|
||||
if (state == Call.State.StreamsRunning) {
|
||||
if (!call.currentParams.isVideoEnabled && fullScreenMode.value == true) {
|
||||
|
@ -412,7 +415,44 @@ class ControlsViewModel : ViewModel() {
|
|||
goToConferenceLayoutSettingsEvent.value = Event(true)
|
||||
}
|
||||
|
||||
fun goToDialerForCallTransfer() {
|
||||
fun transferCall() {
|
||||
// In case there is more than 1 call, transfer will be attended instead of blind
|
||||
if (coreContext.core.callsNb > 1) {
|
||||
attendedTransfer()
|
||||
} else {
|
||||
goToDialerForCallTransfer()
|
||||
}
|
||||
}
|
||||
|
||||
private fun attendedTransfer() {
|
||||
val core = coreContext.core
|
||||
val currentCall = core.currentCall
|
||||
|
||||
if (currentCall == null) {
|
||||
Log.e("[Call Controls] Can't do an attended transfer without a current call")
|
||||
return
|
||||
}
|
||||
if (core.callsNb <= 1) {
|
||||
Log.e("[Call Controls] Need at least two calls to do an attended transfer")
|
||||
return
|
||||
}
|
||||
|
||||
val callToTransferTo = core.calls.findLast {
|
||||
it.state == Call.State.Paused
|
||||
}
|
||||
if (callToTransferTo == null) {
|
||||
Log.e("[Call Controls] Couldn't find a call in Paused state to transfer current call to")
|
||||
return
|
||||
}
|
||||
|
||||
Log.i("[Call Controls] Doing an attended transfer between active call [${currentCall.remoteAddress.asStringUriOnly()}] and paused call [${callToTransferTo.remoteAddress.asStringUriOnly()}]")
|
||||
val result = callToTransferTo.transferToAnother(currentCall)
|
||||
if (result != 0) {
|
||||
Log.e("[Call Controls] Attended transfer failed!")
|
||||
}
|
||||
}
|
||||
|
||||
private fun goToDialerForCallTransfer() {
|
||||
goToDialerEvent.value = Event(true)
|
||||
}
|
||||
|
||||
|
|
|
@ -317,6 +317,13 @@ class CorePreferences constructor(private val context: Context) {
|
|||
config.setBool("app", "call_right_away", value)
|
||||
}
|
||||
|
||||
// Will send user to contacts list directly
|
||||
var skipDialerForNewCallAndTransfer: Boolean
|
||||
get() = config.getBool("app", "skip_dialer_for_new_call_and_transfer", false)
|
||||
set(value) {
|
||||
config.setBool("app", "skip_dialer_for_new_call_and_transfer", value)
|
||||
}
|
||||
|
||||
var automaticallyStartCallRecording: Boolean
|
||||
get() = config.getBool("app", "auto_start_call_record", false)
|
||||
set(value) {
|
||||
|
|
|
@ -108,8 +108,8 @@
|
|||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:onClick="@{() -> controlsViewModel.goToDialerForCallTransfer()}"
|
||||
android:text="@string/call_action_transfer_call"
|
||||
android:onClick="@{() -> controlsViewModel.transferCall()}"
|
||||
android:text="@{controlsViewModel.attendedTransfer ? @string/call_action_attended_transfer_call : @string/call_action_transfer_call, default=@string/call_action_transfer_call}"
|
||||
android:visibility="@{conferenceViewModel.conferenceExists ? View.GONE : View.VISIBLE, default=gone}"
|
||||
app:drawableTopCompat="@drawable/icon_call_forward"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
|
|
|
@ -768,4 +768,5 @@
|
|||
<string name="account_setting_delete_dialog_title">Voulez-vous supprimer votre compte ?</string>
|
||||
<string name="account_setting_delete_generic_confirmation_dialog">Votre compte sera supprimé localement.\nPour le supprimer de manière définitive, rendez-vous sur le site internet de votre fournisseur SIP.</string>
|
||||
<string name="account_setting_delete_sip_linphone_org_confirmation_dialog">Votre compte sera supprimé localement.\nPour le supprimer de manière définitive, rendez-vous sur notre plateforme de gestion des comptes :</string>
|
||||
<string name="call_action_attended_transfer_call">Transfert supervisé</string>
|
||||
</resources>
|
|
@ -348,6 +348,7 @@
|
|||
<string name="call_action_statistics">Call statistics</string>
|
||||
<string name="call_action_add_call">Start new call</string>
|
||||
<string name="call_action_transfer_call">Transfer call</string>
|
||||
<string name="call_action_attended_transfer_call">Attended transfer</string>
|
||||
<string name="call_context_action_resume">Resume call</string>
|
||||
<string name="call_context_action_pause">Pause call</string>
|
||||
<string name="call_context_action_transfer">Transfer call</string>
|
||||
|
|
Loading…
Reference in a new issue