mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2025-02-03 12:37:31 +01:00
DialPad: show dialerchoice dialog when supported
This commit is contained in:
parent
14502573bf
commit
1f96367286
@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2021 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
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
|
||||||
|
import im.vector.app.databinding.BottomSheetCallDialerChoiceBinding
|
||||||
|
|
||||||
|
class DialerChoiceBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetCallDialerChoiceBinding>() {
|
||||||
|
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetCallDialerChoiceBinding {
|
||||||
|
return BottomSheetCallDialerChoiceBinding.inflate(inflater, container, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
var onDialPadClicked: (() ->Unit)? = null
|
||||||
|
var onVoiceCallClicked: (() ->Unit)? = null
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
views.dialerChoiceDialPad.views.itemVerificationClickableZone.debouncedClicks {
|
||||||
|
onDialPadClicked?.invoke()
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
views.dialerChoiceVoiceCall.views.itemVerificationClickableZone.debouncedClicks {
|
||||||
|
onVoiceCallClicked?.invoke()
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Callback {
|
||||||
|
fun onDialPadClicked()
|
||||||
|
fun onVoiceCallClicked()
|
||||||
|
}
|
||||||
|
}
|
@ -29,8 +29,8 @@ class DialPadLookup(val session: Session,
|
|||||||
class Failure : Throwable()
|
class Failure : Throwable()
|
||||||
data class Result(val userId: String, val roomId: String)
|
data class Result(val userId: String, val roomId: String)
|
||||||
|
|
||||||
suspend fun lookupPhoneNumber(phoneNumber: String): Result? {
|
suspend fun lookupPhoneNumber(phoneNumber: String): Result {
|
||||||
val supportedProtocolKey = callManager.supportedPSTNProtocol ?: return null
|
val supportedProtocolKey = callManager.supportedPSTNProtocol ?: throw Failure()
|
||||||
val thirdPartyUser = tryOrNull {
|
val thirdPartyUser = tryOrNull {
|
||||||
session.getThirdPartyUser(supportedProtocolKey, fields = mapOf(
|
session.getThirdPartyUser(supportedProtocolKey, fields = mapOf(
|
||||||
"m.id.phone" to phoneNumber
|
"m.id.phone" to phoneNumber
|
||||||
|
@ -265,6 +265,19 @@ class RoomDetailFragment @Inject constructor(
|
|||||||
pillsPostProcessorFactory.create(roomDetailArgs.roomId)
|
pillsPostProcessorFactory.create(roomDetailArgs.roomId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val callActionsHandler by lazy {
|
||||||
|
StartCallActionsHandler(
|
||||||
|
roomId = roomDetailArgs.roomId,
|
||||||
|
fragment = this,
|
||||||
|
vectorPreferences = vectorPreferences,
|
||||||
|
roomDetailViewModel = roomDetailViewModel,
|
||||||
|
sharedActiveCallViewModel = sharedCallActionViewModel,
|
||||||
|
startCallActivityResultLauncher = startCallActivityResultLauncher,
|
||||||
|
showDialogWithMessage = ::showDialogWithMessage,
|
||||||
|
onTapToReturnToCall = ::onTapToReturnToCall
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private val autoCompleter: AutoCompleter by lazy {
|
private val autoCompleter: AutoCompleter by lazy {
|
||||||
autoCompleterFactory.create(roomDetailArgs.roomId)
|
autoCompleterFactory.create(roomDetailArgs.roomId)
|
||||||
}
|
}
|
||||||
@ -759,9 +772,12 @@ class RoomDetailFragment @Inject constructor(
|
|||||||
roomDetailViewModel.handle(RoomDetailAction.ManageIntegrations)
|
roomDetailViewModel.handle(RoomDetailAction.ManageIntegrations)
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
R.id.voice_call,
|
R.id.voice_call -> {
|
||||||
|
callActionsHandler.onVoiceCallClicked()
|
||||||
|
true
|
||||||
|
}
|
||||||
R.id.video_call -> {
|
R.id.video_call -> {
|
||||||
handleCallRequest(item)
|
callActionsHandler.onVideoCallClicked()
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
R.id.hangup_call -> {
|
R.id.hangup_call -> {
|
||||||
@ -784,76 +800,6 @@ class RoomDetailFragment @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleCallRequest(item: MenuItem) = withState(roomDetailViewModel) { state ->
|
|
||||||
val roomSummary = state.asyncRoomSummary.invoke() ?: return@withState
|
|
||||||
val isVideoCall = item.itemId == R.id.video_call
|
|
||||||
when (roomSummary.joinedMembersCount) {
|
|
||||||
1 -> {
|
|
||||||
val pendingInvite = roomSummary.invitedMembersCount ?: 0 > 0
|
|
||||||
if (pendingInvite) {
|
|
||||||
// wait for other to join
|
|
||||||
showDialogWithMessage(getString(R.string.cannot_call_yourself_with_invite))
|
|
||||||
} else {
|
|
||||||
// You cannot place a call with yourself.
|
|
||||||
showDialogWithMessage(getString(R.string.cannot_call_yourself))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
2 -> {
|
|
||||||
val activeCall = sharedCallActionViewModel.activeCall.value
|
|
||||||
if (activeCall != null) {
|
|
||||||
// resume existing if same room, if not prompt to kill and then restart new call?
|
|
||||||
if (activeCall.roomId == roomDetailArgs.roomId) {
|
|
||||||
onTapToReturnToCall()
|
|
||||||
}
|
|
||||||
// else {
|
|
||||||
// TODO might not work well, and should prompt
|
|
||||||
// webRtcPeerConnectionManager.endCall()
|
|
||||||
// safeStartCall(it, isVideoCall)
|
|
||||||
// }
|
|
||||||
} else if (!state.isAllowedToStartWebRTCCall) {
|
|
||||||
showDialogWithMessage(getString(
|
|
||||||
if (state.isDm()) {
|
|
||||||
R.string.no_permissions_to_start_webrtc_call_in_direct_room
|
|
||||||
} else {
|
|
||||||
R.string.no_permissions_to_start_webrtc_call
|
|
||||||
})
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
safeStartCall(isVideoCall)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
// it's jitsi call
|
|
||||||
// can you add widgets??
|
|
||||||
if (!state.isAllowedToManageWidgets) {
|
|
||||||
// You do not have permission to start a conference call in this room
|
|
||||||
showDialogWithMessage(getString(
|
|
||||||
if (state.isDm()) {
|
|
||||||
R.string.no_permissions_to_start_conf_call_in_direct_room
|
|
||||||
} else {
|
|
||||||
R.string.no_permissions_to_start_conf_call
|
|
||||||
}
|
|
||||||
))
|
|
||||||
} else {
|
|
||||||
if (state.activeRoomWidgets()?.filter { it.type == WidgetType.Jitsi }?.any() == true) {
|
|
||||||
// A conference is already in progress!
|
|
||||||
showDialogWithMessage(getString(R.string.conference_call_in_progress))
|
|
||||||
} else {
|
|
||||||
AlertDialog.Builder(requireContext())
|
|
||||||
.setTitle(if (isVideoCall) R.string.video_meeting else R.string.audio_meeting)
|
|
||||||
.setMessage(R.string.audio_video_meeting_description)
|
|
||||||
.setPositiveButton(getString(R.string.create)) { _, _ ->
|
|
||||||
// create the widget, then navigate to it..
|
|
||||||
roomDetailViewModel.handle(RoomDetailAction.AddJitsiWidget(isVideoCall))
|
|
||||||
}
|
|
||||||
.setNegativeButton(getString(R.string.cancel), null)
|
|
||||||
.show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun displayDisabledIntegrationDialog() {
|
private fun displayDisabledIntegrationDialog() {
|
||||||
AlertDialog.Builder(requireActivity())
|
AlertDialog.Builder(requireActivity())
|
||||||
.setTitle(R.string.disabled_integration_dialog_title)
|
.setTitle(R.string.disabled_integration_dialog_title)
|
||||||
@ -865,54 +811,6 @@ class RoomDetailFragment @Inject constructor(
|
|||||||
.show()
|
.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun safeStartCall(isVideoCall: Boolean) {
|
|
||||||
if (vectorPreferences.preventAccidentalCall()) {
|
|
||||||
AlertDialog.Builder(requireActivity())
|
|
||||||
.setMessage(if (isVideoCall) R.string.start_video_call_prompt_msg else R.string.start_voice_call_prompt_msg)
|
|
||||||
.setPositiveButton(if (isVideoCall) R.string.start_video_call else R.string.start_voice_call) { _, _ ->
|
|
||||||
safeStartCall2(isVideoCall)
|
|
||||||
}
|
|
||||||
.setNegativeButton(R.string.cancel, null)
|
|
||||||
.show()
|
|
||||||
} else {
|
|
||||||
safeStartCall2(isVideoCall)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private val startCallActivityResultLauncher = registerForPermissionsResult { allGranted ->
|
|
||||||
if (allGranted) {
|
|
||||||
(roomDetailViewModel.pendingAction as? RoomDetailAction.StartCall)?.let {
|
|
||||||
roomDetailViewModel.pendingAction = null
|
|
||||||
roomDetailViewModel.handle(it)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
context?.toast(R.string.permissions_action_not_performed_missing_permissions)
|
|
||||||
cleanUpAfterPermissionNotGranted()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun safeStartCall2(isVideoCall: Boolean) {
|
|
||||||
val startCallAction = RoomDetailAction.StartCall(isVideoCall)
|
|
||||||
roomDetailViewModel.pendingAction = startCallAction
|
|
||||||
if (isVideoCall) {
|
|
||||||
if (checkPermissions(PERMISSIONS_FOR_VIDEO_IP_CALL,
|
|
||||||
requireActivity(),
|
|
||||||
startCallActivityResultLauncher,
|
|
||||||
R.string.permissions_rationale_msg_camera_and_audio)) {
|
|
||||||
roomDetailViewModel.pendingAction = null
|
|
||||||
roomDetailViewModel.handle(startCallAction)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (checkPermissions(PERMISSIONS_FOR_AUDIO_IP_CALL,
|
|
||||||
requireActivity(),
|
|
||||||
startCallActivityResultLauncher,
|
|
||||||
R.string.permissions_rationale_msg_record_audio)) {
|
|
||||||
roomDetailViewModel.pendingAction = null
|
|
||||||
roomDetailViewModel.handle(startCallAction)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun renderRegularMode(text: String) {
|
private fun renderRegularMode(text: String) {
|
||||||
autoCompleter.exitSpecialMode()
|
autoCompleter.exitSpecialMode()
|
||||||
views.composerLayout.collapse()
|
views.composerLayout.collapse()
|
||||||
@ -1052,6 +950,18 @@ class RoomDetailFragment @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val startCallActivityResultLauncher = registerForPermissionsResult { allGranted ->
|
||||||
|
if (allGranted) {
|
||||||
|
(roomDetailViewModel.pendingAction as? RoomDetailAction.StartCall)?.let {
|
||||||
|
roomDetailViewModel.pendingAction = null
|
||||||
|
roomDetailViewModel.handle(it)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
context?.toast(R.string.permissions_action_not_performed_missing_permissions)
|
||||||
|
cleanUpAfterPermissionNotGranted()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// PRIVATE METHODS *****************************************************************************
|
// PRIVATE METHODS *****************************************************************************
|
||||||
|
|
||||||
private fun setupRecyclerView() {
|
private fun setupRecyclerView() {
|
||||||
|
@ -119,7 +119,8 @@ class RoomDetailViewModel @AssistedInject constructor(
|
|||||||
private val chatEffectManager: ChatEffectManager,
|
private val chatEffectManager: ChatEffectManager,
|
||||||
private val directRoomHelper: DirectRoomHelper,
|
private val directRoomHelper: DirectRoomHelper,
|
||||||
timelineSettingsFactory: TimelineSettingsFactory
|
timelineSettingsFactory: TimelineSettingsFactory
|
||||||
) : VectorViewModel<RoomDetailViewState, RoomDetailAction, RoomDetailViewEvents>(initialState), Timeline.Listener, ChatEffectManager.Delegate {
|
) : VectorViewModel<RoomDetailViewState, RoomDetailAction, RoomDetailViewEvents>(initialState),
|
||||||
|
Timeline.Listener, ChatEffectManager.Delegate, WebRtcCallManager.PSTNSupportListener {
|
||||||
|
|
||||||
private val room = session.getRoom(initialState.roomId)!!
|
private val room = session.getRoom(initialState.roomId)!!
|
||||||
private val eventId = initialState.eventId
|
private val eventId = initialState.eventId
|
||||||
@ -169,11 +170,13 @@ class RoomDetailViewModel @AssistedInject constructor(
|
|||||||
observeMyRoomMember()
|
observeMyRoomMember()
|
||||||
observeActiveRoomWidgets()
|
observeActiveRoomWidgets()
|
||||||
observePowerLevel()
|
observePowerLevel()
|
||||||
|
updateShowDialerOptionState()
|
||||||
room.getRoomSummaryLive()
|
room.getRoomSummaryLive()
|
||||||
room.markAsRead(ReadService.MarkAsReadParams.READ_RECEIPT, NoOpMatrixCallback())
|
room.markAsRead(ReadService.MarkAsReadParams.READ_RECEIPT, NoOpMatrixCallback())
|
||||||
room.rx().loadRoomMembersIfNeeded().subscribeLogError().disposeOnClear()
|
room.rx().loadRoomMembersIfNeeded().subscribeLogError().disposeOnClear()
|
||||||
// Inform the SDK that the room is displayed
|
// Inform the SDK that the room is displayed
|
||||||
session.onRoomDisplayed(initialState.roomId)
|
session.onRoomDisplayed(initialState.roomId)
|
||||||
|
callManager.addPstnSupportListener(this)
|
||||||
chatEffectManager.delegate = this
|
chatEffectManager.delegate = this
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -294,7 +297,7 @@ class RoomDetailViewModel @AssistedInject constructor(
|
|||||||
private fun handleStartCallWithPhoneNumber(action: RoomDetailAction.StartCallWithPhoneNumber) {
|
private fun handleStartCallWithPhoneNumber(action: RoomDetailAction.StartCallWithPhoneNumber) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
try {
|
try {
|
||||||
val result = DialPadLookup(session, directRoomHelper, callManager).lookupPhoneNumber(action.phoneNumber) ?: return@launch
|
val result = DialPadLookup(session, directRoomHelper, callManager).lookupPhoneNumber(action.phoneNumber)
|
||||||
callManager.startOutgoingCall(result.roomId, result.userId, action.videoCall)
|
callManager.startOutgoingCall(result.roomId, result.userId, action.videoCall)
|
||||||
} catch (failure: Throwable) {
|
} catch (failure: Throwable) {
|
||||||
_viewEvents.post(RoomDetailViewEvents.ActionFailure(action, failure))
|
_viewEvents.post(RoomDetailViewEvents.ActionFailure(action, failure))
|
||||||
@ -1431,6 +1434,16 @@ class RoomDetailViewModel @AssistedInject constructor(
|
|||||||
_viewEvents.post(RoomDetailViewEvents.OnNewTimelineEvents(eventIds))
|
_viewEvents.post(RoomDetailViewEvents.OnNewTimelineEvents(eventIds))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onPSTNSupportUpdated() {
|
||||||
|
updateShowDialerOptionState()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateShowDialerOptionState(){
|
||||||
|
setState {
|
||||||
|
copy(showDialerOption = callManager.supportsPSTNProtocol)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCleared() {
|
override fun onCleared() {
|
||||||
roomSummaryHolder.clear()
|
roomSummaryHolder.clear()
|
||||||
timeline.dispose()
|
timeline.dispose()
|
||||||
@ -1440,6 +1453,7 @@ class RoomDetailViewModel @AssistedInject constructor(
|
|||||||
}
|
}
|
||||||
chatEffectManager.delegate = null
|
chatEffectManager.delegate = null
|
||||||
chatEffectManager.dispose()
|
chatEffectManager.dispose()
|
||||||
|
callManager.removePstnSupportListener(this)
|
||||||
super.onCleared()
|
super.onCleared()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -74,7 +74,8 @@ data class RoomDetailViewState(
|
|||||||
val canSendMessage: Boolean = true,
|
val canSendMessage: Boolean = true,
|
||||||
val canInvite: Boolean = true,
|
val canInvite: Boolean = true,
|
||||||
val isAllowedToManageWidgets: Boolean = false,
|
val isAllowedToManageWidgets: Boolean = false,
|
||||||
val isAllowedToStartWebRTCCall: Boolean = true
|
val isAllowedToStartWebRTCCall: Boolean = true,
|
||||||
|
val showDialerOption: Boolean = false
|
||||||
) : MvRxState {
|
) : MvRxState {
|
||||||
|
|
||||||
constructor(args: RoomDetailArgs) : this(
|
constructor(args: RoomDetailArgs) : this(
|
||||||
|
@ -0,0 +1,181 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2021 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.home.room.detail
|
||||||
|
|
||||||
|
import androidx.activity.result.ActivityResult
|
||||||
|
import androidx.activity.result.ActivityResultLauncher
|
||||||
|
import androidx.appcompat.app.AlertDialog
|
||||||
|
import com.airbnb.mvrx.withState
|
||||||
|
import im.vector.app.R
|
||||||
|
import im.vector.app.core.utils.PERMISSIONS_FOR_AUDIO_IP_CALL
|
||||||
|
import im.vector.app.core.utils.PERMISSIONS_FOR_VIDEO_IP_CALL
|
||||||
|
import im.vector.app.core.utils.checkPermissions
|
||||||
|
import im.vector.app.core.utils.registerForPermissionsResult
|
||||||
|
import im.vector.app.core.utils.toast
|
||||||
|
import im.vector.app.features.call.DialerChoiceBottomSheet
|
||||||
|
import im.vector.app.features.call.SharedActiveCallViewModel
|
||||||
|
import im.vector.app.features.call.dialpad.CallDialPadBottomSheet
|
||||||
|
import im.vector.app.features.call.dialpad.DialPadFragment
|
||||||
|
import im.vector.app.features.settings.VectorPreferences
|
||||||
|
import org.matrix.android.sdk.api.session.widgets.model.WidgetType
|
||||||
|
|
||||||
|
class StartCallActionsHandler(
|
||||||
|
private val roomId: String,
|
||||||
|
private val fragment: RoomDetailFragment,
|
||||||
|
private val vectorPreferences: VectorPreferences,
|
||||||
|
private val roomDetailViewModel: RoomDetailViewModel,
|
||||||
|
private val sharedActiveCallViewModel: SharedActiveCallViewModel,
|
||||||
|
private val startCallActivityResultLauncher: ActivityResultLauncher<Array<String>>,
|
||||||
|
private val showDialogWithMessage: (String) -> Unit,
|
||||||
|
private val onTapToReturnToCall: () -> Unit) {
|
||||||
|
|
||||||
|
fun onVideoCallClicked() {
|
||||||
|
handleCallRequest(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onVoiceCallClicked() = withState(roomDetailViewModel) {
|
||||||
|
if (it.showDialerOption) {
|
||||||
|
displayDialerChoiceBottomSheet()
|
||||||
|
} else {
|
||||||
|
handleCallRequest(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun displayDialerChoiceBottomSheet() {
|
||||||
|
DialerChoiceBottomSheet().apply {
|
||||||
|
onDialPadClicked = ::displayDialPadBottomSheet
|
||||||
|
onVoiceCallClicked = { handleCallRequest(false) }
|
||||||
|
}.show(fragment.parentFragmentManager, "DIALER_OPTION")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun displayDialPadBottomSheet() {
|
||||||
|
CallDialPadBottomSheet.newInstance(true).apply {
|
||||||
|
callback = object : DialPadFragment.Callback {
|
||||||
|
override fun onOkClicked(formatted: String?, raw: String?) {
|
||||||
|
if (raw.isNullOrEmpty()) return
|
||||||
|
roomDetailViewModel.handle(RoomDetailAction.StartCallWithPhoneNumber(raw, false))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.show(fragment.parentFragmentManager, "DIAL_PAD")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleCallRequest(isVideoCall: Boolean) = withState(roomDetailViewModel) { state ->
|
||||||
|
val roomSummary = state.asyncRoomSummary.invoke() ?: return@withState
|
||||||
|
when (roomSummary.joinedMembersCount) {
|
||||||
|
1 -> {
|
||||||
|
val pendingInvite = roomSummary.invitedMembersCount ?: 0 > 0
|
||||||
|
if (pendingInvite) {
|
||||||
|
// wait for other to join
|
||||||
|
showDialogWithMessage(fragment.getString(R.string.cannot_call_yourself_with_invite))
|
||||||
|
} else {
|
||||||
|
// You cannot place a call with yourself.
|
||||||
|
showDialogWithMessage(fragment.getString(R.string.cannot_call_yourself))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
2 -> {
|
||||||
|
val activeCall = sharedActiveCallViewModel.activeCall.value
|
||||||
|
if (activeCall != null) {
|
||||||
|
// resume existing if same room, if not prompt to kill and then restart new call?
|
||||||
|
if (activeCall.roomId == roomId) {
|
||||||
|
onTapToReturnToCall()
|
||||||
|
}
|
||||||
|
// else {
|
||||||
|
// TODO might not work well, and should prompt
|
||||||
|
// webRtcPeerConnectionManager.endCall()
|
||||||
|
// safeStartCall(it, isVideoCall)
|
||||||
|
// }
|
||||||
|
} else if (!state.isAllowedToStartWebRTCCall) {
|
||||||
|
showDialogWithMessage(fragment.getString(
|
||||||
|
if (state.isDm()) {
|
||||||
|
R.string.no_permissions_to_start_webrtc_call_in_direct_room
|
||||||
|
} else {
|
||||||
|
R.string.no_permissions_to_start_webrtc_call
|
||||||
|
})
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
safeStartCall(isVideoCall)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
// it's jitsi call
|
||||||
|
// can you add widgets??
|
||||||
|
if (!state.isAllowedToManageWidgets) {
|
||||||
|
// You do not have permission to start a conference call in this room
|
||||||
|
showDialogWithMessage(fragment.getString(
|
||||||
|
if (state.isDm()) {
|
||||||
|
R.string.no_permissions_to_start_conf_call_in_direct_room
|
||||||
|
} else {
|
||||||
|
R.string.no_permissions_to_start_conf_call
|
||||||
|
}
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
if (state.activeRoomWidgets()?.filter { it.type == WidgetType.Jitsi }?.any() == true) {
|
||||||
|
// A conference is already in progress!
|
||||||
|
showDialogWithMessage(fragment.getString(R.string.conference_call_in_progress))
|
||||||
|
} else {
|
||||||
|
AlertDialog.Builder(fragment.requireContext())
|
||||||
|
.setTitle(if (isVideoCall) R.string.video_meeting else R.string.audio_meeting)
|
||||||
|
.setMessage(R.string.audio_video_meeting_description)
|
||||||
|
.setPositiveButton(fragment.getString(R.string.create)) { _, _ ->
|
||||||
|
// create the widget, then navigate to it..
|
||||||
|
roomDetailViewModel.handle(RoomDetailAction.AddJitsiWidget(isVideoCall))
|
||||||
|
}
|
||||||
|
.setNegativeButton(fragment.getString(R.string.cancel), null)
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun safeStartCall(isVideoCall: Boolean) {
|
||||||
|
if (vectorPreferences.preventAccidentalCall()) {
|
||||||
|
AlertDialog.Builder(fragment.requireActivity())
|
||||||
|
.setMessage(if (isVideoCall) R.string.start_video_call_prompt_msg else R.string.start_voice_call_prompt_msg)
|
||||||
|
.setPositiveButton(if (isVideoCall) R.string.start_video_call else R.string.start_voice_call) { _, _ ->
|
||||||
|
safeStartCall2(isVideoCall)
|
||||||
|
}
|
||||||
|
.setNegativeButton(R.string.cancel, null)
|
||||||
|
.show()
|
||||||
|
} else {
|
||||||
|
safeStartCall2(isVideoCall)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun safeStartCall2(isVideoCall: Boolean) {
|
||||||
|
val startCallAction = RoomDetailAction.StartCall(isVideoCall)
|
||||||
|
roomDetailViewModel.pendingAction = startCallAction
|
||||||
|
if (isVideoCall) {
|
||||||
|
if (checkPermissions(PERMISSIONS_FOR_VIDEO_IP_CALL,
|
||||||
|
fragment.requireActivity(),
|
||||||
|
startCallActivityResultLauncher,
|
||||||
|
R.string.permissions_rationale_msg_camera_and_audio)) {
|
||||||
|
roomDetailViewModel.pendingAction = null
|
||||||
|
roomDetailViewModel.handle(startCallAction)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (checkPermissions(PERMISSIONS_FOR_AUDIO_IP_CALL,
|
||||||
|
fragment.requireActivity(),
|
||||||
|
startCallActivityResultLauncher,
|
||||||
|
R.string.permissions_rationale_msg_record_audio)) {
|
||||||
|
roomDetailViewModel.pendingAction = null
|
||||||
|
roomDetailViewModel.handle(startCallAction)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -15,6 +15,7 @@
|
|||||||
app:actionTitle="@string/call_select_sound_device"
|
app:actionTitle="@string/call_select_sound_device"
|
||||||
app:leftIcon="@drawable/ic_call_speaker_default"
|
app:leftIcon="@drawable/ic_call_speaker_default"
|
||||||
app:tint="?attr/riotx_text_primary"
|
app:tint="?attr/riotx_text_primary"
|
||||||
|
app:titleTextColor="?attr/riotx_text_primary"
|
||||||
tools:actionDescription="Speaker" />
|
tools:actionDescription="Speaker" />
|
||||||
|
|
||||||
<im.vector.app.core.ui.views.BottomSheetActionButton
|
<im.vector.app.core.ui.views.BottomSheetActionButton
|
||||||
@ -24,6 +25,7 @@
|
|||||||
app:actionTitle="@string/call_switch_camera"
|
app:actionTitle="@string/call_switch_camera"
|
||||||
app:leftIcon="@drawable/ic_video_flip"
|
app:leftIcon="@drawable/ic_video_flip"
|
||||||
app:tint="?attr/riotx_text_primary"
|
app:tint="?attr/riotx_text_primary"
|
||||||
|
app:titleTextColor="?attr/riotx_text_primary"
|
||||||
tools:actionDescription="Front" />
|
tools:actionDescription="Front" />
|
||||||
|
|
||||||
<im.vector.app.core.ui.views.BottomSheetActionButton
|
<im.vector.app.core.ui.views.BottomSheetActionButton
|
||||||
@ -33,6 +35,7 @@
|
|||||||
app:actionTitle="@string/call_dial_pad_title"
|
app:actionTitle="@string/call_dial_pad_title"
|
||||||
app:leftIcon="@drawable/ic_call_dial_pad"
|
app:leftIcon="@drawable/ic_call_dial_pad"
|
||||||
app:tint="?attr/riotx_text_primary"
|
app:tint="?attr/riotx_text_primary"
|
||||||
|
app:titleTextColor="?attr/riotx_text_primary"
|
||||||
tools:actionDescription="" />
|
tools:actionDescription="" />
|
||||||
|
|
||||||
<im.vector.app.core.ui.views.BottomSheetActionButton
|
<im.vector.app.core.ui.views.BottomSheetActionButton
|
||||||
@ -42,6 +45,7 @@
|
|||||||
app:actionTitle="@string/call_format_turn_hd_on"
|
app:actionTitle="@string/call_format_turn_hd_on"
|
||||||
app:leftIcon="@drawable/ic_hd"
|
app:leftIcon="@drawable/ic_hd"
|
||||||
app:tint="?attr/riotx_text_primary"
|
app:tint="?attr/riotx_text_primary"
|
||||||
|
app:titleTextColor="?attr/riotx_text_primary"
|
||||||
tools:actionDescription="Front" />
|
tools:actionDescription="Front" />
|
||||||
|
|
||||||
<im.vector.app.core.ui.views.BottomSheetActionButton
|
<im.vector.app.core.ui.views.BottomSheetActionButton
|
||||||
@ -51,6 +55,7 @@
|
|||||||
app:actionTitle="Hold/resume"
|
app:actionTitle="Hold/resume"
|
||||||
app:leftIcon="@drawable/ic_call_hold_action"
|
app:leftIcon="@drawable/ic_call_hold_action"
|
||||||
app:tint="?attr/riotx_text_primary"
|
app:tint="?attr/riotx_text_primary"
|
||||||
|
app:titleTextColor="?attr/riotx_text_primary"
|
||||||
tools:actionDescription="" />
|
tools:actionDescription="" />
|
||||||
|
|
||||||
|
|
||||||
|
@ -0,0 +1,30 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/callControlsWrapper"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="?riotx_bottom_sheet_background"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<im.vector.app.core.ui.views.BottomSheetActionButton
|
||||||
|
android:id="@+id/dialerChoiceDialPad"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:actionTitle="@string/call_dial_pad_title"
|
||||||
|
app:leftIcon="@drawable/ic_call_dial_pad"
|
||||||
|
app:tint="?attr/riotx_text_primary"
|
||||||
|
app:titleTextColor="?attr/riotx_text_primary" />
|
||||||
|
|
||||||
|
<im.vector.app.core.ui.views.BottomSheetActionButton
|
||||||
|
android:id="@+id/dialerChoiceVoiceCall"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:actionTitle="@string/action_voice_call"
|
||||||
|
app:leftIcon="@drawable/ic_call_answer"
|
||||||
|
app:tint="?attr/riotx_text_primary"
|
||||||
|
app:titleTextColor="?attr/riotx_text_primary" />
|
||||||
|
|
||||||
|
|
||||||
|
</LinearLayout>
|
Loading…
x
Reference in New Issue
Block a user