diff --git a/vector/src/main/java/im/vector/app/core/error/ErrorFormatter.kt b/vector/src/main/java/im/vector/app/core/error/ErrorFormatter.kt index b5f45e6586..c0219b26e2 100644 --- a/vector/src/main/java/im/vector/app/core/error/ErrorFormatter.kt +++ b/vector/src/main/java/im/vector/app/core/error/ErrorFormatter.kt @@ -116,7 +116,9 @@ class DefaultErrorFormatter @Inject constructor( throwable.localizedMessage } } - is DialPadLookup.Failure -> + is DialPadLookup.Failure.NumberIsYours -> + stringProvider.getString(R.string.cannot_call_yourself) + is DialPadLookup.Failure.NoResult -> stringProvider.getString(R.string.call_dial_pad_lookup_error) else -> throwable.localizedMessage } diff --git a/vector/src/main/java/im/vector/app/features/call/dialpad/DialPadLookup.kt b/vector/src/main/java/im/vector/app/features/call/dialpad/DialPadLookup.kt index d8421ee0c7..fd1dfba2a4 100644 --- a/vector/src/main/java/im/vector/app/features/call/dialpad/DialPadLookup.kt +++ b/vector/src/main/java/im/vector/app/features/call/dialpad/DialPadLookup.kt @@ -29,13 +29,16 @@ class DialPadLookup @Inject constructor( private val webRtcCallManager: WebRtcCallManager, private val directRoomHelper: DirectRoomHelper ) { - class Failure : Throwable() + sealed class Failure : Throwable(){ + object NoResult: Failure() + object NumberIsYours: Failure() + } data class Result(val userId: String, val roomId: String) suspend fun lookupPhoneNumber(phoneNumber: String): Result { session.vectorCallService.protocolChecker.awaitCheckProtocols() - val thirdPartyUser = session.pstnLookup(phoneNumber, webRtcCallManager.supportedPSTNProtocol).firstOrNull() ?: throw IllegalStateException() + val thirdPartyUser = session.pstnLookup(phoneNumber, webRtcCallManager.supportedPSTNProtocol).firstOrNull() ?: throw Failure.NoResult // check to see if this is a virtual user, in which case we should find the native user val nativeUserId = if (webRtcCallManager.supportsVirtualRooms) { val nativeLookupResults = session.sipNativeLookup(thirdPartyUser.userId) @@ -43,6 +46,7 @@ class DialPadLookup @Inject constructor( } else { thirdPartyUser.userId } + if(nativeUserId == session.myUserId) throw Failure.NumberIsYours val roomId = directRoomHelper.ensureDMExists(nativeUserId) return Result(userId = nativeUserId, roomId = roomId) } diff --git a/vector/src/main/java/im/vector/app/features/call/lookup/ThirdPartyLookup.kt b/vector/src/main/java/im/vector/app/features/call/lookup/ThirdPartyLookup.kt index 1e9834059f..dfdc58f78f 100644 --- a/vector/src/main/java/im/vector/app/features/call/lookup/ThirdPartyLookup.kt +++ b/vector/src/main/java/im/vector/app/features/call/lookup/ThirdPartyLookup.kt @@ -16,10 +16,13 @@ package im.vector.app.features.call.lookup +import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.thirdparty.model.ThirdPartyUser +private const val LOOKUP_SUCCESS_FIELD = "lookup_success" + suspend fun Session.pstnLookup(phoneNumber: String, protocol: String?): List { if (protocol == null) return emptyList() return tryOrNull { @@ -36,7 +39,11 @@ suspend fun Session.sipVirtualLookup(nativeMxid: String): List { protocol = PROTOCOL_SIP_VIRTUAL, fields = mapOf("native_mxid" to nativeMxid) ) - }.orEmpty() + } + .orEmpty() + .filter { + (it.fields[LOOKUP_SUCCESS_FIELD] as? Boolean).orFalse() + } } suspend fun Session.sipNativeLookup(virtualMxid: String): List { @@ -45,5 +52,9 @@ suspend fun Session.sipNativeLookup(virtualMxid: String): List { protocol = PROTOCOL_SIP_NATIVE, fields = mapOf("virtual_mxid" to virtualMxid) ) - }.orEmpty() + } + .orEmpty() + .filter { + (it.fields[LOOKUP_SUCCESS_FIELD] as? Boolean).orFalse() + } } diff --git a/vector/src/main/java/im/vector/app/features/home/HomeDetailFragment.kt b/vector/src/main/java/im/vector/app/features/home/HomeDetailFragment.kt index 28a0ef6d7d..5cdaf12889 100644 --- a/vector/src/main/java/im/vector/app/features/home/HomeDetailFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/HomeDetailFragment.kt @@ -151,6 +151,14 @@ class HomeDetailFragment @Inject constructor( updateTabVisibilitySafely(R.id.bottom_action_dial_pad, showDialPadTab) } + viewModel.observeViewEvents { viewEvent -> + when (viewEvent) { + HomeDetailViewEvents.CallStarted -> dismissLoadingDialog() + is HomeDetailViewEvents.FailToCall -> showFailure(viewEvent.failure) + HomeDetailViewEvents.Loading -> showLoadingDialog() + } + } + unknownDeviceDetectorSharedViewModel.subscribe { state -> state.unknownSessions.invoke()?.let { unknownDevices -> // Timber.v("## Detector Triggerred in fragment - ${unknownDevices.firstOrNull()}") @@ -193,8 +201,6 @@ class HomeDetailFragment @Inject constructor( callManager.checkForProtocolsSupportIfNeeded() } - - private fun promptForNewUnknownDevices(uid: String, state: UnknownDevicesState, newest: DeviceInfo) { val user = state.myMatrixItem alertManager.postVectorAlert( diff --git a/vector/src/main/java/im/vector/app/features/home/HomeDetailViewEvents.kt b/vector/src/main/java/im/vector/app/features/home/HomeDetailViewEvents.kt new file mode 100644 index 0000000000..a0ff67dc0a --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/home/HomeDetailViewEvents.kt @@ -0,0 +1,25 @@ +/* + * 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.home + +import im.vector.app.core.platform.VectorViewEvents + +sealed class HomeDetailViewEvents : VectorViewEvents { + object Loading : HomeDetailViewEvents() + object CallStarted : HomeDetailViewEvents() + data class FailToCall(val failure: Throwable) : HomeDetailViewEvents() +} diff --git a/vector/src/main/java/im/vector/app/features/home/HomeDetailViewModel.kt b/vector/src/main/java/im/vector/app/features/home/HomeDetailViewModel.kt index 004f0909f4..c367ca936a 100644 --- a/vector/src/main/java/im/vector/app/features/home/HomeDetailViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/HomeDetailViewModel.kt @@ -59,7 +59,7 @@ class HomeDetailViewModel @AssistedInject constructor(@Assisted initialState: Ho private val callManager: WebRtcCallManager, private val directRoomHelper: DirectRoomHelper, private val appStateHandler: AppStateHandler) - : VectorViewModel(initialState), + : VectorViewModel(initialState), CallProtocolsChecker.Listener { @AssistedFactory @@ -98,8 +98,8 @@ class HomeDetailViewModel @AssistedInject constructor(@Assisted initialState: Ho override fun handle(action: HomeDetailAction) { when (action) { - is HomeDetailAction.SwitchTab -> handleSwitchTab(action) - HomeDetailAction.MarkAllRoomsRead -> handleMarkAllRoomsRead() + is HomeDetailAction.SwitchTab -> handleSwitchTab(action) + HomeDetailAction.MarkAllRoomsRead -> handleMarkAllRoomsRead() is HomeDetailAction.StartCallWithPhoneNumber -> handleStartCallWithPhoneNumber(action) } } @@ -107,10 +107,12 @@ class HomeDetailViewModel @AssistedInject constructor(@Assisted initialState: Ho private fun handleStartCallWithPhoneNumber(action: HomeDetailAction.StartCallWithPhoneNumber) { viewModelScope.launch { try { + _viewEvents.post(HomeDetailViewEvents.Loading) val result = DialPadLookup(session, callManager, directRoomHelper).lookupPhoneNumber(action.phoneNumber) callManager.startOutgoingCall(result.roomId, result.userId, isVideoCall = false) + _viewEvents.post(HomeDetailViewEvents.CallStarted) } catch (failure: Throwable) { - Timber.v(failure) + _viewEvents.post(HomeDetailViewEvents.FailToCall(failure)) } } } @@ -120,7 +122,7 @@ class HomeDetailViewModel @AssistedInject constructor(@Assisted initialState: Ho setState { copy(currentTab = action.tab) } - if(action.tab is HomeTab.RoomList) { + if (action.tab is HomeTab.RoomList) { uiStateRepository.storeDisplayMode(action.tab.displayMode) } } @@ -141,7 +143,6 @@ class HomeDetailViewModel @AssistedInject constructor(@Assisted initialState: Ho } } - // PRIVATE METHODS ***************************************************************************** private fun handleMarkAllRoomsRead() = withState { _ -> @@ -176,11 +177,11 @@ class HomeDetailViewModel @AssistedInject constructor(@Assisted initialState: Ho private fun observeRoomGroupingMethod() { appStateHandler.selectedRoomGroupingObservable .subscribe { - setState { - copy( - roomGroupingMethod = it.orNull() ?: RoomGroupingMethod.BySpace(null) - ) - } + setState { + copy( + roomGroupingMethod = it.orNull() ?: RoomGroupingMethod.BySpace(null) + ) + } } .disposeOnClear() } @@ -203,7 +204,7 @@ class HomeDetailViewModel @AssistedInject constructor(@Assisted initialState: Ho is RoomGroupingMethod.ByLegacyGroup -> { // TODO!! } - is RoomGroupingMethod.BySpace -> { + is RoomGroupingMethod.BySpace -> { val activeSpaceRoomId = groupingMethod.spaceSummary?.roomId val dmInvites = session.getRoomSummaries( roomSummaryQueryParams {