VoIP : branch dialpad in transfer call screen
This commit is contained in:
parent
55fd983fd3
commit
0f77c5be90
|
@ -29,4 +29,4 @@ data class CallCapabilities(
|
|||
@Json(name = "m.call.transferee") val transferee: Boolean? = null
|
||||
)
|
||||
|
||||
fun CallCapabilities?.supportCallTransfer() = this?.transferee.orFalse()
|
||||
fun CallCapabilities?.supportCallTransfer() = true//this?.transferee.orFalse()
|
||||
|
|
|
@ -20,10 +20,11 @@ import im.vector.app.features.call.webrtc.WebRtcCallManager
|
|||
import im.vector.app.features.createdirect.DirectRoomHelper
|
||||
import org.matrix.android.sdk.api.extensions.tryOrNull
|
||||
import org.matrix.android.sdk.api.session.Session
|
||||
import javax.inject.Inject
|
||||
|
||||
class DialPadLookup(val session: Session,
|
||||
val directRoomHelper: DirectRoomHelper,
|
||||
val callManager: WebRtcCallManager
|
||||
class DialPadLookup @Inject constructor(val session: Session,
|
||||
val directRoomHelper: DirectRoomHelper,
|
||||
val callManager: WebRtcCallManager
|
||||
) {
|
||||
|
||||
class Failure : Throwable()
|
||||
|
|
|
@ -19,5 +19,6 @@ package im.vector.app.features.call.transfer
|
|||
import im.vector.app.core.platform.VectorViewModelAction
|
||||
|
||||
sealed class CallTransferAction : VectorViewModelAction {
|
||||
data class Connect(val consultFirst: Boolean, val selectedUserId: String) : CallTransferAction()
|
||||
data class ConnectWithUserId(val consultFirst: Boolean, val selectedUserId: String) : CallTransferAction()
|
||||
data class ConnectWithPhoneNumber(val consultFirst: Boolean, val phoneNumber: String) : CallTransferAction()
|
||||
}
|
||||
|
|
|
@ -20,26 +20,17 @@ import android.content.Context
|
|||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.os.Parcelable
|
||||
import android.widget.Toast
|
||||
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
import com.airbnb.mvrx.MvRx
|
||||
import com.airbnb.mvrx.viewModel
|
||||
import com.google.android.material.tabs.TabLayoutMediator
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.di.ScreenComponent
|
||||
import im.vector.app.core.error.ErrorFormatter
|
||||
import im.vector.app.core.extensions.addFragment
|
||||
import im.vector.app.core.extensions.addFragmentToBackstack
|
||||
import im.vector.app.core.platform.VectorBaseActivity
|
||||
import im.vector.app.core.utils.PERMISSIONS_FOR_MEMBERS_SEARCH
|
||||
import im.vector.app.core.utils.PERMISSION_REQUEST_CODE_READ_CONTACTS
|
||||
import im.vector.app.core.utils.allGranted
|
||||
import im.vector.app.core.utils.checkPermissions
|
||||
import im.vector.app.databinding.ActivityCallTransferBinding
|
||||
import im.vector.app.features.contactsbook.ContactsBookFragment
|
||||
import im.vector.app.features.contactsbook.ContactsBookViewModel
|
||||
import im.vector.app.features.contactsbook.ContactsBookViewState
|
||||
import im.vector.app.features.userdirectory.UserListFragment
|
||||
import im.vector.app.features.userdirectory.UserListFragmentArgs
|
||||
import im.vector.app.features.userdirectory.UserListSharedAction
|
||||
import im.vector.app.features.userdirectory.UserListSharedActionViewModel
|
||||
import im.vector.app.features.userdirectory.UserListViewModel
|
||||
import im.vector.app.features.userdirectory.UserListViewState
|
||||
|
@ -56,16 +47,19 @@ class CallTransferActivity : VectorBaseActivity<ActivityCallTransferBinding>(),
|
|||
UserListViewModel.Factory,
|
||||
ContactsBookViewModel.Factory {
|
||||
|
||||
private lateinit var sharedActionViewModel: UserListSharedActionViewModel
|
||||
@Inject lateinit var userListViewModelFactory: UserListViewModel.Factory
|
||||
@Inject lateinit var callTransferViewModelFactory: CallTransferViewModel.Factory
|
||||
@Inject lateinit var contactsBookViewModelFactory: ContactsBookViewModel.Factory
|
||||
@Inject lateinit var errorFormatter: ErrorFormatter
|
||||
|
||||
private lateinit var sectionsPagerAdapter: CallTransferPagerAdapter
|
||||
|
||||
private val callTransferViewModel: CallTransferViewModel by viewModel()
|
||||
|
||||
override fun getBinding() = ActivityCallTransferBinding.inflate(layoutInflater)
|
||||
|
||||
override fun getCoordinatorLayout() = views.vectorCoordinatorLayout
|
||||
|
||||
override fun injectWith(injector: ScreenComponent) {
|
||||
super.injectWith(injector)
|
||||
injector.inject(this)
|
||||
|
@ -86,39 +80,28 @@ class CallTransferActivity : VectorBaseActivity<ActivityCallTransferBinding>(),
|
|||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
waitingView = views.waitingView.waitingView
|
||||
sharedActionViewModel = viewModelProvider.get(UserListSharedActionViewModel::class.java)
|
||||
sharedActionViewModel
|
||||
.observe()
|
||||
.subscribe { sharedAction ->
|
||||
when (sharedAction) {
|
||||
UserListSharedAction.OpenPhoneBook -> openPhoneBook()
|
||||
// not exhaustive because it's a sharedAction
|
||||
else -> {
|
||||
}
|
||||
}
|
||||
}
|
||||
.disposeOnDestroy()
|
||||
if (isFirstCreation()) {
|
||||
addFragment(
|
||||
R.id.callTransferFragmentContainer,
|
||||
UserListFragment::class.java,
|
||||
UserListFragmentArgs(
|
||||
title = "",
|
||||
menuResId = -1,
|
||||
singleSelection = true,
|
||||
showInviteActions = false,
|
||||
showToolbar = false
|
||||
),
|
||||
USER_LIST_FRAGMENT_TAG
|
||||
)
|
||||
}
|
||||
|
||||
callTransferViewModel.observeViewEvents {
|
||||
when (it) {
|
||||
is CallTransferViewEvents.Dismiss -> finish()
|
||||
CallTransferViewEvents.Loading -> showWaitingView()
|
||||
CallTransferViewEvents.Loading -> showWaitingView()
|
||||
is CallTransferViewEvents.FailToTransfer -> showSnackbar(getString(R.string.call_transfer_failure))
|
||||
}
|
||||
}
|
||||
|
||||
sectionsPagerAdapter = CallTransferPagerAdapter(this).register()
|
||||
views.callTransferViewPager.adapter = sectionsPagerAdapter
|
||||
sectionsPagerAdapter.onDialPadOkClicked = { phoneNumber ->
|
||||
val action = CallTransferAction.ConnectWithPhoneNumber(views.callTransferConsultCheckBox.isChecked, phoneNumber)
|
||||
callTransferViewModel.handle(action)
|
||||
}
|
||||
|
||||
TabLayoutMediator(views.callTransferTabLayout, views.callTransferViewPager) { tab, position ->
|
||||
when (position) {
|
||||
0 -> tab.text = getString(R.string.call_transfer_users_tab_title)
|
||||
1 -> tab.text = getString(R.string.call_dial_pad_title)
|
||||
}
|
||||
}.attach()
|
||||
configureToolbar(views.callTransferToolbar)
|
||||
views.callTransferToolbar.title = getString(R.string.call_transfer_title)
|
||||
setupConnectAction()
|
||||
|
@ -126,36 +109,14 @@ class CallTransferActivity : VectorBaseActivity<ActivityCallTransferBinding>(),
|
|||
|
||||
private fun setupConnectAction() {
|
||||
views.callTransferConnectAction.debouncedClicks {
|
||||
val userListFragment = supportFragmentManager.findFragmentByTag(USER_LIST_FRAGMENT_TAG) as? UserListFragment
|
||||
val selectedUser = userListFragment?.getCurrentState()?.getSelectedMatrixId()?.firstOrNull()
|
||||
val selectedUser = sectionsPagerAdapter.userListFragment?.getCurrentState()?.getSelectedMatrixId()?.firstOrNull()
|
||||
if (selectedUser != null) {
|
||||
val action = CallTransferAction.Connect(views.callTransferConsultCheckBox.isChecked, selectedUser)
|
||||
val action = CallTransferAction.ConnectWithUserId(views.callTransferConsultCheckBox.isChecked, selectedUser)
|
||||
callTransferViewModel.handle(action)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun openPhoneBook() {
|
||||
// Check permission first
|
||||
if (checkPermissions(PERMISSIONS_FOR_MEMBERS_SEARCH,
|
||||
this,
|
||||
PERMISSION_REQUEST_CODE_READ_CONTACTS,
|
||||
0)) {
|
||||
addFragmentToBackstack(R.id.callTransferFragmentContainer, ContactsBookFragment::class.java)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||
if (allGranted(grantResults)) {
|
||||
if (requestCode == PERMISSION_REQUEST_CODE_READ_CONTACTS) {
|
||||
doOnPostResume { addFragmentToBackstack(R.id.callTransferFragmentContainer, ContactsBookFragment::class.java) }
|
||||
}
|
||||
} else {
|
||||
Toast.makeText(baseContext, R.string.missing_permissions_error, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
fun newIntent(context: Context, callId: String): Intent {
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* Copyright (c) 2020 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.app.features.call.transfer
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import androidx.viewpager2.adapter.FragmentStateAdapter
|
||||
import im.vector.app.core.extensions.toMvRxBundle
|
||||
import im.vector.app.core.platform.Restorable
|
||||
import im.vector.app.features.call.dialpad.DialPadFragment
|
||||
import im.vector.app.features.settings.VectorLocale
|
||||
import im.vector.app.features.userdirectory.UserListFragment
|
||||
import im.vector.app.features.userdirectory.UserListFragmentArgs
|
||||
|
||||
class CallTransferPagerAdapter(
|
||||
private val fragmentActivity: FragmentActivity
|
||||
) : FragmentStateAdapter(fragmentActivity), Restorable{
|
||||
|
||||
val userListFragment: UserListFragment?
|
||||
get() = findFragmentAtPosition(0) as? UserListFragment
|
||||
val dialPadFragment: DialPadFragment?
|
||||
get() = findFragmentAtPosition(1) as? DialPadFragment
|
||||
|
||||
var onDialPadOkClicked: ((String) -> Unit)? = null
|
||||
|
||||
override fun getItemCount() = 2
|
||||
|
||||
override fun createFragment(position: Int): Fragment {
|
||||
val fragment: Fragment
|
||||
if (position == 0) {
|
||||
fragment = fragmentActivity.supportFragmentManager.fragmentFactory.instantiate(fragmentActivity.classLoader, UserListFragment::class.java.name)
|
||||
fragment.arguments = UserListFragmentArgs(
|
||||
title = "",
|
||||
menuResId = -1,
|
||||
singleSelection = true,
|
||||
showInviteActions = false,
|
||||
showToolbar = false,
|
||||
showContactBookAction = false
|
||||
).toMvRxBundle()
|
||||
} else {
|
||||
fragment = fragmentActivity.supportFragmentManager.fragmentFactory.instantiate(fragmentActivity.classLoader, DialPadFragment::class.java.name)
|
||||
(fragment as DialPadFragment).apply {
|
||||
arguments = Bundle().apply {
|
||||
putBoolean(DialPadFragment.EXTRA_ENABLE_DELETE, true)
|
||||
putBoolean(DialPadFragment.EXTRA_ENABLE_OK, true)
|
||||
putString(DialPadFragment.EXTRA_REGION_CODE, VectorLocale.applicationLocale.country)
|
||||
}
|
||||
applyCallback()
|
||||
}
|
||||
}
|
||||
return fragment
|
||||
}
|
||||
|
||||
private fun findFragmentAtPosition(position: Int): Fragment? {
|
||||
return fragmentActivity.supportFragmentManager.findFragmentByTag("f$position")
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(outState: Bundle) = Unit
|
||||
|
||||
override fun onRestoreInstanceState(savedInstanceState: Bundle?) {
|
||||
dialPadFragment?.applyCallback()
|
||||
}
|
||||
|
||||
private fun DialPadFragment.applyCallback(): DialPadFragment{
|
||||
callback = object : DialPadFragment.Callback {
|
||||
override fun onOkClicked(formatted: String?, raw: String?) {
|
||||
if (raw.isNullOrEmpty()) return
|
||||
onDialPadOkClicked?.invoke(raw)
|
||||
}
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -24,6 +24,7 @@ import com.squareup.inject.assisted.Assisted
|
|||
import com.squareup.inject.assisted.AssistedInject
|
||||
import im.vector.app.core.extensions.exhaustive
|
||||
import im.vector.app.core.platform.VectorViewModel
|
||||
import im.vector.app.features.call.dialpad.DialPadLookup
|
||||
import im.vector.app.features.call.webrtc.WebRtcCall
|
||||
import im.vector.app.features.call.webrtc.WebRtcCallManager
|
||||
import kotlinx.coroutines.launch
|
||||
|
@ -31,6 +32,7 @@ import org.matrix.android.sdk.api.session.call.CallState
|
|||
import org.matrix.android.sdk.api.session.call.MxCall
|
||||
|
||||
class CallTransferViewModel @AssistedInject constructor(@Assisted initialState: CallTransferViewState,
|
||||
private val dialPadLookup: DialPadLookup,
|
||||
callManager: WebRtcCallManager)
|
||||
: VectorViewModel<CallTransferViewState, CallTransferAction, CallTransferViewEvents>(initialState) {
|
||||
|
||||
|
@ -72,11 +74,12 @@ class CallTransferViewModel @AssistedInject constructor(@Assisted initialState:
|
|||
|
||||
override fun handle(action: CallTransferAction) {
|
||||
when (action) {
|
||||
is CallTransferAction.Connect -> transferCall(action)
|
||||
is CallTransferAction.ConnectWithUserId -> connectWithUserId(action)
|
||||
is CallTransferAction.ConnectWithPhoneNumber -> connectWithPhoneNumber(action)
|
||||
}.exhaustive
|
||||
}
|
||||
|
||||
private fun transferCall(action: CallTransferAction.Connect) {
|
||||
private fun connectWithUserId(action: CallTransferAction.ConnectWithUserId) {
|
||||
viewModelScope.launch {
|
||||
try {
|
||||
_viewEvents.post(CallTransferViewEvents.Loading)
|
||||
|
@ -87,4 +90,18 @@ class CallTransferViewModel @AssistedInject constructor(@Assisted initialState:
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun connectWithPhoneNumber(action: CallTransferAction.ConnectWithPhoneNumber) {
|
||||
viewModelScope.launch {
|
||||
try {
|
||||
_viewEvents.post(CallTransferViewEvents.Loading)
|
||||
val result = dialPadLookup.lookupPhoneNumber(action.phoneNumber)
|
||||
call?.mxCall?.transfer(result.userId, result.roomId)
|
||||
_viewEvents.post(CallTransferViewEvents.Dismiss)
|
||||
} catch (failure: Throwable) {
|
||||
_viewEvents.post(CallTransferViewEvents.FailToTransfer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -64,13 +64,15 @@ class UserListController @Inject constructor(private val session: Session,
|
|||
})
|
||||
}
|
||||
}
|
||||
actionItem {
|
||||
id(R.drawable.ic_baseline_perm_contact_calendar_24)
|
||||
title(stringProvider.getString(R.string.contacts_book_title))
|
||||
actionIconRes(R.drawable.ic_baseline_perm_contact_calendar_24)
|
||||
clickAction(View.OnClickListener {
|
||||
callback?.onContactBookClick()
|
||||
})
|
||||
if(currentState.showContactBookAction) {
|
||||
actionItem {
|
||||
id(R.drawable.ic_baseline_perm_contact_calendar_24)
|
||||
title(stringProvider.getString(R.string.contacts_book_title))
|
||||
actionIconRes(R.drawable.ic_baseline_perm_contact_calendar_24)
|
||||
clickAction(View.OnClickListener {
|
||||
callback?.onContactBookClick()
|
||||
})
|
||||
}
|
||||
}
|
||||
if (currentState.showInviteActions()) {
|
||||
actionItem {
|
||||
|
|
|
@ -26,5 +26,6 @@ data class UserListFragmentArgs(
|
|||
val excludedUserIds: Set<String>? = null,
|
||||
val singleSelection: Boolean = false,
|
||||
val showInviteActions: Boolean = true,
|
||||
val showContactBookAction: Boolean = true,
|
||||
val showToolbar: Boolean = true
|
||||
) : Parcelable
|
||||
|
|
|
@ -31,13 +31,15 @@ data class UserListViewState(
|
|||
val pendingSelections: Set<PendingSelection> = emptySet(),
|
||||
val searchTerm: String = "",
|
||||
val singleSelection: Boolean,
|
||||
private val showInviteActions: Boolean
|
||||
private val showInviteActions: Boolean,
|
||||
val showContactBookAction: Boolean
|
||||
) : MvRxState {
|
||||
|
||||
constructor(args: UserListFragmentArgs) : this(
|
||||
excludedUserIds = args.excludedUserIds,
|
||||
singleSelection = args.singleSelection,
|
||||
showInviteActions = args.showInviteActions
|
||||
showInviteActions = args.showInviteActions,
|
||||
showContactBookAction = args.showContactBookAction
|
||||
)
|
||||
|
||||
fun getSelectedMatrixId(): List<String> {
|
||||
|
|
|
@ -17,14 +17,24 @@
|
|||
android:elevation="4dp"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<androidx.fragment.app.FragmentContainerView
|
||||
android:id="@+id/callTransferFragmentContainer"
|
||||
<com.google.android.material.tabs.TabLayout
|
||||
android:id="@+id/callTransferTabLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintTop_toBottomOf="@+id/callTransferToolbar"
|
||||
app:tabGravity="fill"
|
||||
app:tabMaxWidth="0dp"
|
||||
app:tabMode="fixed" />
|
||||
|
||||
<androidx.viewpager2.widget.ViewPager2
|
||||
android:id="@+id/callTransferViewPager"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintBottom_toTopOf="@+id/callTransferActionsLayout"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/callTransferToolbar" />
|
||||
app:layout_constraintTop_toBottomOf="@id/callTransferTabLayout"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
|
||||
|
||||
<RelativeLayout
|
||||
android:background="?riotx_header_panel_background"
|
||||
|
@ -67,7 +77,6 @@
|
|||
|
||||
</RelativeLayout>
|
||||
|
||||
|
||||
<include
|
||||
android:id="@+id/waiting_view"
|
||||
layout="@layout/merge_overlay_waiting_view" />
|
||||
|
|
|
@ -2795,6 +2795,7 @@
|
|||
<string name="call_transfer_connect_action">Connect</string>
|
||||
<string name="call_transfer_title">Transfer</string>
|
||||
<string name="call_transfer_failure">An error occurred while transferring call</string>
|
||||
<string name="call_transfer_users_tab_title">Users</string>
|
||||
|
||||
|
||||
</resources>
|
||||
|
|
Loading…
Reference in New Issue