DialPad: integrate getThirdPartyUser with protocol and add helper for create DM

This commit is contained in:
ganfra 2021-01-12 20:10:52 +01:00
parent 268d740059
commit 14502573bf
16 changed files with 298 additions and 82 deletions

View File

@ -18,6 +18,7 @@ package org.matrix.android.sdk.api.session.thirdparty
import org.matrix.android.sdk.api.MatrixCallback import org.matrix.android.sdk.api.MatrixCallback
import org.matrix.android.sdk.api.session.room.model.thirdparty.ThirdPartyProtocol import org.matrix.android.sdk.api.session.room.model.thirdparty.ThirdPartyProtocol
import org.matrix.android.sdk.api.session.thirdparty.model.ThirdPartyUser
import org.matrix.android.sdk.api.util.Cancelable import org.matrix.android.sdk.api.util.Cancelable
interface ThirdPartyService { interface ThirdPartyService {
@ -28,4 +29,11 @@ interface ThirdPartyService {
*/ */
suspend fun getThirdPartyProtocols(): Map<String, ThirdPartyProtocol> suspend fun getThirdPartyProtocols(): Map<String, ThirdPartyProtocol>
/**
* Retrieve a Matrix User ID linked to a user on the third party service, given a set of user parameters.
* @param protocol Required. The name of the protocol.
* @param fields One or more custom fields that are passed to the AS to help identify the user.
*/
suspend fun getThirdPartyUser(protocol: String, fields: Map<String, String> = emptyMap()): List<ThirdPartyUser>
} }

View File

@ -0,0 +1,37 @@
/*
* 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 org.matrix.android.sdk.api.session.thirdparty.model
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import org.matrix.android.sdk.api.util.JsonDict
@JsonClass(generateAdapter = true)
data class ThirdPartyUser(
/*
Required. A Matrix User ID represting a third party user.
*/
@Json(name = "userid") val userId: String,
/*
Required. The protocol ID that the third party location is a part of.
*/
@Json(name = "protocol") val protocol: String,
/*
Required. Information used to identify this third party location.
*/
@Json(name = "fields") val fields: JsonDict
)

View File

@ -18,13 +18,22 @@ package org.matrix.android.sdk.internal.session.thirdparty
import org.matrix.android.sdk.api.session.room.model.thirdparty.ThirdPartyProtocol import org.matrix.android.sdk.api.session.room.model.thirdparty.ThirdPartyProtocol
import org.matrix.android.sdk.api.session.thirdparty.ThirdPartyService import org.matrix.android.sdk.api.session.thirdparty.ThirdPartyService
import org.matrix.android.sdk.api.session.thirdparty.model.ThirdPartyUser
import javax.inject.Inject import javax.inject.Inject
internal class DefaultThirdPartyService @Inject constructor(private val getThirdPartyProtocolTask: GetThirdPartyProtocolsTask) internal class DefaultThirdPartyService @Inject constructor(private val getThirdPartyProtocolTask: GetThirdPartyProtocolsTask,
private val getThirdPartyUserTask: GetThirdPartyUserTask)
: ThirdPartyService { : ThirdPartyService {
override suspend fun getThirdPartyProtocols(): Map<String, ThirdPartyProtocol> { override suspend fun getThirdPartyProtocols(): Map<String, ThirdPartyProtocol> {
return getThirdPartyProtocolTask.execute(Unit) return getThirdPartyProtocolTask.execute(Unit)
} }
override suspend fun getThirdPartyUser(protocol: String, fields: Map<String, String>): List<ThirdPartyUser> {
val taskParams = GetThirdPartyUserTask.Params(
protocol = protocol,
fields = fields
)
return getThirdPartyUserTask.execute(taskParams)
}
} }

View File

@ -0,0 +1,43 @@
/*
* Copyright 2020 The Matrix.org Foundation C.I.C.
*
* 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 org.matrix.android.sdk.internal.session.thirdparty
import org.greenrobot.eventbus.EventBus
import org.matrix.android.sdk.api.session.thirdparty.model.ThirdPartyUser
import org.matrix.android.sdk.internal.network.executeRequest
import org.matrix.android.sdk.internal.task.Task
import javax.inject.Inject
internal interface GetThirdPartyUserTask : Task<GetThirdPartyUserTask.Params, List<ThirdPartyUser>> {
data class Params(
val protocol: String,
val fields: Map<String, String> = emptyMap()
)
}
internal class DefaultGetThirdPartyUserTask @Inject constructor(
private val thirdPartyAPI: ThirdPartyAPI,
private val eventBus: EventBus
) : GetThirdPartyUserTask {
override suspend fun execute(params: GetThirdPartyUserTask.Params): List<ThirdPartyUser> {
return executeRequest(eventBus) {
apiCall = thirdPartyAPI.getThirdPartyUser(params.protocol, params.fields)
}
}
}

View File

@ -21,6 +21,7 @@ import org.matrix.android.sdk.api.session.events.model.Event
import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoomsParams import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoomsParams
import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoomsResponse import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoomsResponse
import org.matrix.android.sdk.api.session.room.model.thirdparty.ThirdPartyProtocol import org.matrix.android.sdk.api.session.room.model.thirdparty.ThirdPartyProtocol
import org.matrix.android.sdk.api.session.thirdparty.model.ThirdPartyUser
import org.matrix.android.sdk.api.util.JsonDict import org.matrix.android.sdk.api.util.JsonDict
import org.matrix.android.sdk.internal.network.NetworkConstants import org.matrix.android.sdk.internal.network.NetworkConstants
import org.matrix.android.sdk.internal.session.room.alias.GetAliasesResponse import org.matrix.android.sdk.internal.session.room.alias.GetAliasesResponse
@ -47,15 +48,28 @@ import retrofit2.http.POST
import retrofit2.http.PUT import retrofit2.http.PUT
import retrofit2.http.Path import retrofit2.http.Path
import retrofit2.http.Query import retrofit2.http.Query
import retrofit2.http.QueryMap
internal interface ThirdPartyAPI { internal interface ThirdPartyAPI {
/** /**
* Get the third party server protocols. * Get the third party server protocols.
* *
* Ref: https://matrix.org/docs/spec/client_server/r0.4.0.html#get-matrix-client-r0-thirdparty-protocols * Ref: https://matrix.org/docs/spec/client_server/r0.6.1.html#get-matrix-client-r0-thirdparty-protocols
*/ */
@GET(NetworkConstants.URI_API_PREFIX_PATH_R0 + "thirdparty/protocols") @GET(NetworkConstants.URI_API_PREFIX_PATH_R0 + "thirdparty/protocols")
fun thirdPartyProtocols(): Call<Map<String, ThirdPartyProtocol>> fun thirdPartyProtocols(): Call<Map<String, ThirdPartyProtocol>>
/**
* Retrieve a Matrix User ID linked to a user on the third party service, given a set of user parameters.
*
* Ref: https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-client-r0-thirdparty-user-protocol
*/
@GET(NetworkConstants.URI_API_PREFIX_PATH_R0 + "thirdparty/protocols/user/{protocol}")
fun getThirdPartyUser(@Path("protocol") protocol: String, @QueryMap params: Map<String, String>?): Call<List<ThirdPartyUser>>
} }

View File

@ -42,4 +42,7 @@ internal abstract class ThirdPartyModule {
@Binds @Binds
abstract fun bindGetThirdPartyProtocolsTask(task: DefaultGetThirdPartyProtocolsTask): GetThirdPartyProtocolsTask abstract fun bindGetThirdPartyProtocolsTask(task: DefaultGetThirdPartyProtocolsTask): GetThirdPartyProtocolsTask
@Binds
abstract fun bindGetThirdPartyUserTask(task: DefaultGetThirdPartyUserTask): GetThirdPartyUserTask
} }

View File

@ -18,6 +18,7 @@ package im.vector.app.core.error
import im.vector.app.R import im.vector.app.R
import im.vector.app.core.resources.StringProvider import im.vector.app.core.resources.StringProvider
import im.vector.app.features.call.dialpad.DialPadLookup
import org.matrix.android.sdk.api.failure.Failure import org.matrix.android.sdk.api.failure.Failure
import org.matrix.android.sdk.api.failure.MatrixError import org.matrix.android.sdk.api.failure.MatrixError
import org.matrix.android.sdk.api.failure.isInvalidPassword import org.matrix.android.sdk.api.failure.isInvalidPassword
@ -109,8 +110,9 @@ class DefaultErrorFormatter @Inject constructor(
throwable.localizedMessage throwable.localizedMessage
} }
} }
is SsoFlowNotSupportedYet -> stringProvider.getString(R.string.error_sso_flow_not_supported_yet) is SsoFlowNotSupportedYet -> stringProvider.getString(R.string.error_sso_flow_not_supported_yet)
else -> throwable.localizedMessage is DialPadLookup.Failure -> stringProvider.getString(R.string.call_dial_pad_lookup_error)
else -> throwable.localizedMessage
} }
?: stringProvider.getString(R.string.unknown_error) ?: stringProvider.getString(R.string.unknown_error)
} }

View File

@ -63,7 +63,7 @@ class CallDialPadBottomSheet private constructor() : VectorBaseBottomSheetDialog
putBoolean(DialPadFragment.EXTRA_ENABLE_OK, showActions) putBoolean(DialPadFragment.EXTRA_ENABLE_OK, showActions)
putString(DialPadFragment.EXTRA_REGION_CODE, VectorLocale.applicationLocale.country) putString(DialPadFragment.EXTRA_REGION_CODE, VectorLocale.applicationLocale.country)
} }
callback = this@CallDialPadBottomSheet.callback callback = DialPadFragmentCallbackWrapper(this@CallDialPadBottomSheet.callback)
}.also { }.also {
addChildFragment(R.id.callDialPadFragmentContainer, it) addChildFragment(R.id.callDialPadFragmentContainer, it)
} }
@ -83,6 +83,24 @@ class CallDialPadBottomSheet private constructor() : VectorBaseBottomSheetDialog
private fun setCallbackToFragment(callback: DialPadFragment.Callback?) { private fun setCallbackToFragment(callback: DialPadFragment.Callback?) {
if (!isAdded) return if (!isAdded) return
val dialPadFragment = childFragmentManager.findFragmentById(R.id.callDialPadFragmentContainer) as? DialPadFragment val dialPadFragment = childFragmentManager.findFragmentById(R.id.callDialPadFragmentContainer) as? DialPadFragment
dialPadFragment?.callback = callback dialPadFragment?.callback = DialPadFragmentCallbackWrapper(callback)
} }
private inner class DialPadFragmentCallbackWrapper(val callback: DialPadFragment.Callback?): DialPadFragment.Callback{
override fun onDigitAppended(digit: String) {
callback?.onDigitAppended(digit)
}
override fun onOkClicked(formatted: String?, raw: String?) {
callback?.onOkClicked(formatted, raw)
dismiss()
}
}
} }

View File

@ -0,0 +1,43 @@
/*
* 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.dialpad
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
class DialPadLookup(val session: Session,
val directRoomHelper: DirectRoomHelper,
val callManager: WebRtcCallManager
) {
class Failure : Throwable()
data class Result(val userId: String, val roomId: String)
suspend fun lookupPhoneNumber(phoneNumber: String): Result? {
val supportedProtocolKey = callManager.supportedPSTNProtocol ?: return null
val thirdPartyUser = tryOrNull {
session.getThirdPartyUser(supportedProtocolKey, fields = mapOf(
"m.id.phone" to phoneNumber
)).firstOrNull()
} ?: throw Failure()
val roomId = directRoomHelper.ensureDMExists(thirdPartyUser.userId)
return Result(userId = thirdPartyUser.userId, roomId = roomId)
}
}

View File

@ -100,17 +100,20 @@ class WebRtcCallManager @Inject constructor(
private var peerConnectionFactory: PeerConnectionFactory? = null private var peerConnectionFactory: PeerConnectionFactory? = null
private val executor = Executors.newSingleThreadExecutor() private val executor = Executors.newSingleThreadExecutor()
private val dispatcher = executor.asCoroutineDispatcher() private val dispatcher = executor.asCoroutineDispatcher()
var supportsPSTNProtocol: Boolean = false var supportedPSTNProtocol: String? = null
private set private set
val supportsPSTNProtocol: Boolean
get() = supportedPSTNProtocol != null
private val rootEglBase by lazy { EglUtils.rootEglBase } private val rootEglBase by lazy { EglUtils.rootEglBase }
private var isInBackground: Boolean = true private var isInBackground: Boolean = true
init { init {
GlobalScope.launch { GlobalScope.launch {
supportsPSTNProtocol = currentSession?.getSupportedPSTN(3) != null supportedPSTNProtocol = currentSession?.getSupportedPSTN(3)
if (supportsPSTNProtocol) { if (supportedPSTNProtocol != null) {
pstnSupportListeners.forEach { it.onPSTNSupportUpdated() } pstnSupportListeners.forEach { it.onPSTNSupportUpdated() }
} }
} }

View File

@ -0,0 +1,56 @@
/*
* 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.createdirect
import im.vector.app.features.raw.wellknown.getElementWellknown
import im.vector.app.features.raw.wellknown.isE2EByDefault
import org.matrix.android.sdk.api.extensions.tryOrNull
import org.matrix.android.sdk.api.raw.RawService
import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams
import org.matrix.android.sdk.internal.util.awaitCallback
import java.lang.IllegalStateException
import javax.inject.Inject
class DirectRoomHelper @Inject constructor(
private val rawService: RawService,
private val session: Session
) {
suspend fun ensureDMExists(userId: String): String {
val existingRoomId = tryOrNull { session.getExistingDirectRoomWithUser(userId) }
val roomId: String
if (existingRoomId != null) {
roomId = existingRoomId
} else {
val adminE2EByDefault = rawService.getElementWellknown(session.myUserId)
?.isE2EByDefault()
?: true
val roomParams = CreateRoomParams().apply {
invitedUserIds.add(userId)
setDirectMessage()
enableEncryptionIfInvitedUsersSupportIt = adminE2EByDefault
}
roomId = awaitCallback {
session.createRoom(roomParams, it)
}
}
return roomId
}
}

View File

@ -72,6 +72,8 @@ sealed class RoomDetailAction : VectorViewModelAction {
data class IgnoreUser(val userId: String?) : RoomDetailAction() data class IgnoreUser(val userId: String?) : RoomDetailAction()
object ResendAll : RoomDetailAction() object ResendAll : RoomDetailAction()
data class StartCallWithPhoneNumber(val phoneNumber: String, val videoCall: Boolean): RoomDetailAction()
data class StartCall(val isVideo: Boolean) : RoomDetailAction() data class StartCall(val isVideo: Boolean) : RoomDetailAction()
data class AcceptCall(val callId: String): RoomDetailAction() data class AcceptCall(val callId: String): RoomDetailAction()
object EndCall : RoomDetailAction() object EndCall : RoomDetailAction()

View File

@ -32,9 +32,11 @@ import im.vector.app.core.extensions.exhaustive
import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.platform.VectorViewModel
import im.vector.app.core.resources.StringProvider import im.vector.app.core.resources.StringProvider
import im.vector.app.core.utils.subscribeLogError import im.vector.app.core.utils.subscribeLogError
import im.vector.app.features.call.dialpad.DialPadLookup
import im.vector.app.features.call.webrtc.WebRtcCallManager import im.vector.app.features.call.webrtc.WebRtcCallManager
import im.vector.app.features.command.CommandParser import im.vector.app.features.command.CommandParser
import im.vector.app.features.command.ParsedCommand import im.vector.app.features.command.ParsedCommand
import im.vector.app.features.createdirect.DirectRoomHelper
import im.vector.app.features.crypto.verification.SupportedVerificationMethodsProvider import im.vector.app.features.crypto.verification.SupportedVerificationMethodsProvider
import im.vector.app.features.home.room.detail.composer.rainbow.RainbowGenerator import im.vector.app.features.home.room.detail.composer.rainbow.RainbowGenerator
import im.vector.app.features.home.room.detail.sticker.StickerPickerActionHandler import im.vector.app.features.home.room.detail.sticker.StickerPickerActionHandler
@ -115,6 +117,7 @@ class RoomDetailViewModel @AssistedInject constructor(
private val typingHelper: TypingHelper, private val typingHelper: TypingHelper,
private val callManager: WebRtcCallManager, private val callManager: WebRtcCallManager,
private val chatEffectManager: ChatEffectManager, private val chatEffectManager: ChatEffectManager,
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 {
@ -264,6 +267,7 @@ class RoomDetailViewModel @AssistedInject constructor(
is RoomDetailAction.TapOnFailedToDecrypt -> handleTapOnFailedToDecrypt(action) is RoomDetailAction.TapOnFailedToDecrypt -> handleTapOnFailedToDecrypt(action)
is RoomDetailAction.SelectStickerAttachment -> handleSelectStickerAttachment() is RoomDetailAction.SelectStickerAttachment -> handleSelectStickerAttachment()
is RoomDetailAction.OpenIntegrationManager -> handleOpenIntegrationManager() is RoomDetailAction.OpenIntegrationManager -> handleOpenIntegrationManager()
is RoomDetailAction.StartCallWithPhoneNumber -> handleStartCallWithPhoneNumber(action)
is RoomDetailAction.StartCall -> handleStartCall(action) is RoomDetailAction.StartCall -> handleStartCall(action)
is RoomDetailAction.AcceptCall -> handleAcceptCall(action) is RoomDetailAction.AcceptCall -> handleAcceptCall(action)
is RoomDetailAction.EndCall -> handleEndCall() is RoomDetailAction.EndCall -> handleEndCall()
@ -287,6 +291,17 @@ class RoomDetailViewModel @AssistedInject constructor(
}.exhaustive }.exhaustive
} }
private fun handleStartCallWithPhoneNumber(action: RoomDetailAction.StartCallWithPhoneNumber) {
viewModelScope.launch {
try {
val result = DialPadLookup(session, directRoomHelper, callManager).lookupPhoneNumber(action.phoneNumber) ?: return@launch
callManager.startOutgoingCall(result.roomId, result.userId, action.videoCall)
} catch (failure: Throwable) {
_viewEvents.post(RoomDetailViewEvents.ActionFailure(action, failure))
}
}
}
private fun handleAcceptCall(action: RoomDetailAction.AcceptCall) { private fun handleAcceptCall(action: RoomDetailAction.AcceptCall) {
callManager.getCallById(action.callId)?.also { callManager.getCallById(action.callId)?.also {
_viewEvents.post(RoomDetailViewEvents.DisplayAndAcceptCall(it)) _viewEvents.post(RoomDetailViewEvents.DisplayAndAcceptCall(it))
@ -317,18 +332,15 @@ class RoomDetailViewModel @AssistedInject constructor(
} }
private fun handleOpenOrCreateDm(action: RoomDetailAction.OpenOrCreateDm) { private fun handleOpenOrCreateDm(action: RoomDetailAction.OpenOrCreateDm) {
val existingDmRoomId = session.getExistingDirectRoomWithUser(action.userId) viewModelScope.launch {
if (existingDmRoomId == null) { val roomId = try {
// First create a direct room directRoomHelper.ensureDMExists(action.userId)
viewModelScope.launch(Dispatchers.IO) { } catch (failure: Throwable) {
val roomId = awaitCallback<String> { _viewEvents.post(RoomDetailViewEvents.ActionFailure(action, failure))
session.createDirectRoom(action.userId, it) return@launch
}
_viewEvents.post(RoomDetailViewEvents.OpenRoom(roomId))
} }
} else { if (roomId != initialState.roomId) {
if (existingDmRoomId != initialState.roomId) { _viewEvents.post(RoomDetailViewEvents.OpenRoom(roomId = roomId))
_viewEvents.post(RoomDetailViewEvents.OpenRoom(existingDmRoomId))
} }
} }
} }

View File

@ -30,6 +30,7 @@ import im.vector.app.R
import im.vector.app.core.extensions.exhaustive import im.vector.app.core.extensions.exhaustive
import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.platform.VectorViewModel
import im.vector.app.core.resources.StringProvider import im.vector.app.core.resources.StringProvider
import im.vector.app.features.createdirect.DirectRoomHelper
import im.vector.app.features.raw.wellknown.getElementWellknown import im.vector.app.features.raw.wellknown.getElementWellknown
import im.vector.app.features.raw.wellknown.isE2EByDefault import im.vector.app.features.raw.wellknown.isE2EByDefault
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@ -48,6 +49,7 @@ class MatrixToBottomSheetViewModel @AssistedInject constructor(
@Assisted initialState: MatrixToBottomSheetState, @Assisted initialState: MatrixToBottomSheetState,
private val session: Session, private val session: Session,
private val stringProvider: StringProvider, private val stringProvider: StringProvider,
private val directRoomHelper: DirectRoomHelper,
private val rawService: RawService) : VectorViewModel<MatrixToBottomSheetState, MatrixToAction, MatrixToViewEvents>(initialState) { private val rawService: RawService) : VectorViewModel<MatrixToBottomSheetState, MatrixToAction, MatrixToViewEvents>(initialState) {
@AssistedInject.Factory @AssistedInject.Factory
@ -125,42 +127,23 @@ class MatrixToBottomSheetViewModel @AssistedInject constructor(
} }
private fun handleStartChatting(action: MatrixToAction.StartChattingWithUser) { private fun handleStartChatting(action: MatrixToAction.StartChattingWithUser) {
val mxId = action.matrixItem.id viewModelScope.launch {
val existing = session.getExistingDirectRoomWithUser(mxId)
if (existing != null) {
// navigate to this room
_viewEvents.post(MatrixToViewEvents.NavigateToRoom(existing))
} else {
setState { setState {
copy(startChattingState = Loading()) copy(startChattingState = Loading())
} }
// we should create the room then navigate val roomId = try {
viewModelScope.launch(Dispatchers.IO) { directRoomHelper.ensureDMExists(action.matrixItem.id)
val adminE2EByDefault = rawService.getElementWellknown(session.myUserId) } catch (failure: Throwable) {
?.isE2EByDefault()
?: true
val roomParams = CreateRoomParams()
.apply {
invitedUserIds.add(mxId)
setDirectMessage()
enableEncryptionIfInvitedUsersSupportIt = adminE2EByDefault
}
val roomId = try {
awaitCallback<String> { session.createRoom(roomParams, it) }
} catch (failure: Throwable) {
setState {
copy(startChattingState = Fail(Exception(stringProvider.getString(R.string.invite_users_to_room_failure))))
}
return@launch
}
setState { setState {
// we can hide this button has we will navigate out copy(startChattingState = Fail(Exception(stringProvider.getString(R.string.invite_users_to_room_failure))))
copy(startChattingState = Uninitialized)
} }
_viewEvents.post(MatrixToViewEvents.NavigateToRoom(roomId)) return@launch
} }
setState {
// we can hide this button has we will navigate out
copy(startChattingState = Uninitialized)
}
_viewEvents.post(MatrixToViewEvents.NavigateToRoom(roomId))
} }
} }
} }

View File

@ -26,8 +26,7 @@ import com.squareup.inject.assisted.AssistedInject
import im.vector.app.R import im.vector.app.R
import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.platform.VectorViewModel
import im.vector.app.core.resources.StringProvider import im.vector.app.core.resources.StringProvider
import im.vector.app.features.raw.wellknown.getElementWellknown import im.vector.app.features.createdirect.DirectRoomHelper
import im.vector.app.features.raw.wellknown.isE2EByDefault
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.api.extensions.tryOrNull
@ -35,7 +34,6 @@ import org.matrix.android.sdk.api.raw.RawService
import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.permalinks.PermalinkData import org.matrix.android.sdk.api.session.permalinks.PermalinkData
import org.matrix.android.sdk.api.session.permalinks.PermalinkParser import org.matrix.android.sdk.api.session.permalinks.PermalinkParser
import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams
import org.matrix.android.sdk.api.session.user.model.User import org.matrix.android.sdk.api.session.user.model.User
import org.matrix.android.sdk.api.util.toMatrixItem import org.matrix.android.sdk.api.util.toMatrixItem
import org.matrix.android.sdk.internal.util.awaitCallback import org.matrix.android.sdk.internal.util.awaitCallback
@ -44,6 +42,7 @@ class UserCodeSharedViewModel @AssistedInject constructor(
@Assisted val initialState: UserCodeState, @Assisted val initialState: UserCodeState,
private val session: Session, private val session: Session,
private val stringProvider: StringProvider, private val stringProvider: StringProvider,
private val directRoomHelper: DirectRoomHelper,
private val rawService: RawService) : VectorViewModel<UserCodeState, UserCodeActions, UserCodeShareViewEvents>(initialState) { private val rawService: RawService) : VectorViewModel<UserCodeState, UserCodeActions, UserCodeShareViewEvents>(initialState) {
companion object : MvRxViewModelFactory<UserCodeSharedViewModel, UserCodeState> { companion object : MvRxViewModelFactory<UserCodeSharedViewModel, UserCodeState> {
@ -95,39 +94,20 @@ class UserCodeSharedViewModel @AssistedInject constructor(
private fun handleStartChatting(withUser: UserCodeActions.StartChattingWithUser) { private fun handleStartChatting(withUser: UserCodeActions.StartChattingWithUser) {
val mxId = withUser.matrixItem.id val mxId = withUser.matrixItem.id
val existing = session.getExistingDirectRoomWithUser(mxId)
setState { setState {
copy(mode = UserCodeState.Mode.SHOW) copy(mode = UserCodeState.Mode.SHOW)
} }
if (existing != null) { _viewEvents.post(UserCodeShareViewEvents.ShowWaitingScreen)
// navigate to this room viewModelScope.launch(Dispatchers.IO) {
_viewEvents.post(UserCodeShareViewEvents.NavigateToRoom(existing)) val roomId = try {
} else { directRoomHelper.ensureDMExists(mxId)
// we should create the room then navigate } catch (failure: Throwable) {
_viewEvents.post(UserCodeShareViewEvents.ShowWaitingScreen) _viewEvents.post(UserCodeShareViewEvents.ToastMessage(stringProvider.getString(R.string.invite_users_to_room_failure)))
viewModelScope.launch(Dispatchers.IO) { return@launch
val adminE2EByDefault = rawService.getElementWellknown(session.myUserId) } finally {
?.isE2EByDefault() _viewEvents.post(UserCodeShareViewEvents.HideWaitingScreen)
?: true
val roomParams = CreateRoomParams()
.apply {
invitedUserIds.add(mxId)
setDirectMessage()
enableEncryptionIfInvitedUsersSupportIt = adminE2EByDefault
}
val roomId =
try {
awaitCallback<String> { session.createRoom(roomParams, it) }
} catch (failure: Throwable) {
_viewEvents.post(UserCodeShareViewEvents.ToastMessage(stringProvider.getString(R.string.invite_users_to_room_failure)))
return@launch
} finally {
_viewEvents.post(UserCodeShareViewEvents.HideWaitingScreen)
}
_viewEvents.post(UserCodeShareViewEvents.NavigateToRoom(roomId))
} }
_viewEvents.post(UserCodeShareViewEvents.NavigateToRoom(roomId))
} }
} }

View File

@ -2774,4 +2774,7 @@
<string name="call_tile_ended">This call has ended</string> <string name="call_tile_ended">This call has ended</string>
<string name="call_tile_call_back">Call back</string> <string name="call_tile_call_back">Call back</string>
<string name="call_dial_pad_title">Dial pad</string> <string name="call_dial_pad_title">Dial pad</string>
<string name="call_dial_pad_lookup_error">"There was an error looking up the phone number"</string>
</resources> </resources>