diff --git a/matrix-sdk-android/build.gradle b/matrix-sdk-android/build.gradle index 514d1accae..abc860d1ff 100644 --- a/matrix-sdk-android/build.gradle +++ b/matrix-sdk-android/build.gradle @@ -158,6 +158,9 @@ dependencies { // Bus implementation 'org.greenrobot:eventbus:3.1.1' + // Phone number https://github.com/google/libphonenumber + implementation 'com.googlecode.libphonenumber:libphonenumber:8.10.23' + debugImplementation 'com.airbnb.okreplay:okreplay:1.5.0' releaseImplementation 'com.airbnb.okreplay:noop:1.5.0' androidTestImplementation 'com.airbnb.okreplay:espresso:1.5.0' diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/identity/IdentityService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/identity/IdentityService.kt index 359569bd44..3a5a5df284 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/identity/IdentityService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/identity/IdentityService.kt @@ -23,9 +23,9 @@ import im.vector.matrix.android.api.util.Cancelable * Provides access to the identity server configuration and services identity server can provide */ interface IdentityService { - /** - * Return the default identity server of the homeserver (using Wellknown request) + * Return the default identity server of the homeserver (using Wellknown request). + * It may be different from the current configured identity server */ fun getDefaultIdentityServer(callback: MatrixCallback): Cancelable @@ -51,9 +51,11 @@ interface IdentityService { fun finalizeBindThreePid(threePid: ThreePid, callback: MatrixCallback): Cancelable /** - * @param code the code sent to the user phone number + * Submit the code that the identity server has sent to the user (in email or SMS) + * Once successful, you will have to call [finalizeBindThreePid] + * @param code the code sent to the user */ - fun submitValidationToken(pid: ThreePid, code: String, callback: MatrixCallback): Cancelable + fun submitValidationToken(threePid: ThreePid, code: String, callback: MatrixCallback): Cancelable /** * The request will actually be done on the homeserver diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/identity/ThreePid.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/identity/ThreePid.kt index 21977fd386..2a453ca1a6 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/identity/ThreePid.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/identity/ThreePid.kt @@ -16,11 +16,13 @@ package im.vector.matrix.android.api.session.identity +import com.google.i18n.phonenumbers.NumberParseException +import com.google.i18n.phonenumbers.PhoneNumberUtil import im.vector.matrix.android.internal.session.profile.ThirdPartyIdentifier sealed class ThreePid(open val value: String) { data class Email(val email: String) : ThreePid(email) - data class Msisdn(val msisdn: String, val countryCode: String? = null) : ThreePid(msisdn) + data class Msisdn(val msisdn: String) : ThreePid(msisdn) } internal fun ThreePid.toMedium(): String { @@ -29,3 +31,10 @@ internal fun ThreePid.toMedium(): String { is ThreePid.Msisdn -> ThirdPartyIdentifier.MEDIUM_MSISDN } } + +@Throws(NumberParseException::class) +internal fun ThreePid.Msisdn.getCountryCode(): String { + return with(PhoneNumberUtil.getInstance()) { + getRegionCodeForCountryCode(parse("+$msisdn", null).countryCode) + } +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/identity/BulkLookupTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/identity/BulkLookupTask.kt index af6e6de568..61792fdc43 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/identity/BulkLookupTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/identity/BulkLookupTask.kt @@ -86,7 +86,7 @@ internal class DefaultBulkLookupTask @Inject constructor( executeRequest(null) { apiCall = identityAPI.lookup(IdentityLookUpParams( hashedAddresses, - "sha256", + IdentityHashDetailResponse.ALGORITHM_SHA256, hashDetailResponse.pepper )) } @@ -103,7 +103,7 @@ internal class DefaultBulkLookupTask @Inject constructor( // Retrieve the new hash details val newHashDetailResponse = fetchAndStoreHashDetails(identityAPI) - if (hashDetailResponse.algorithms.contains("sha256").not()) { + if (hashDetailResponse.algorithms.contains(IdentityHashDetailResponse.ALGORITHM_SHA256).not()) { // TODO We should ask the user if he is ok to send their 3Pid in clear, but for the moment we do not do it // Also, what we have in cache is maybe outdated, the identity server maybe now support sha256 throw IdentityServiceError.BulkLookupSha256NotSupported diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/identity/DefaultIdentityService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/identity/DefaultIdentityService.kt index 8cbd4e92c0..ce3e555c66 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/identity/DefaultIdentityService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/identity/DefaultIdentityService.kt @@ -71,6 +71,7 @@ internal class DefaultIdentityService @Inject constructor( private val coroutineDispatchers: MatrixCoroutineDispatchers, private val updateUserAccountDataTask: UpdateUserAccountDataTask, private val bindThreePidsTask: BindThreePidsTask, + private val submitTokenForBindingTask: IdentitySubmitTokenForBindingTask, private val unbindThreePidsTask: UnbindThreePidsTask, private val identityApiProvider: IdentityApiProvider, private val accountDataDataSource: AccountDataDataSource @@ -132,8 +133,10 @@ internal class DefaultIdentityService @Inject constructor( } } - override fun submitValidationToken(pid: ThreePid, code: String, callback: MatrixCallback): Cancelable { - TODO("Not yet implemented") + override fun submitValidationToken(threePid: ThreePid, code: String, callback: MatrixCallback): Cancelable { + return GlobalScope.launchToCallback(coroutineDispatchers.main, callback) { + submitTokenForBindingTask.execute(IdentitySubmitTokenForBindingTask.Params(threePid, code)) + } } override fun unbindThreePid(threePid: ThreePid, callback: MatrixCallback): Cancelable { diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/identity/IdentityAPI.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/identity/IdentityAPI.kt index 06a5375fc1..8624bb4b6c 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/identity/IdentityAPI.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/identity/IdentityAPI.kt @@ -16,11 +16,13 @@ package im.vector.matrix.android.internal.session.identity +import im.vector.matrix.android.internal.auth.registration.SuccessResult import im.vector.matrix.android.internal.network.NetworkConstants import im.vector.matrix.android.internal.session.identity.model.IdentityAccountResponse import im.vector.matrix.android.internal.session.identity.model.IdentityHashDetailResponse import im.vector.matrix.android.internal.session.identity.model.IdentityLookUpParams import im.vector.matrix.android.internal.session.identity.model.IdentityLookUpResponse +import im.vector.matrix.android.internal.session.identity.model.IdentityRequestOwnershipParams import im.vector.matrix.android.internal.session.identity.model.IdentityRequestTokenForEmailBody import im.vector.matrix.android.internal.session.identity.model.IdentityRequestTokenForMsisdnBody import im.vector.matrix.android.internal.session.identity.model.IdentityRequestTokenResponse @@ -28,6 +30,7 @@ import retrofit2.Call import retrofit2.http.Body import retrofit2.http.GET import retrofit2.http.POST +import retrofit2.http.Path /** * Ref: https://matrix.org/docs/spec/identity_service/latest @@ -83,4 +86,13 @@ internal interface IdentityAPI { */ @POST(NetworkConstants.URI_IDENTITY_PATH_V2 + "validate/msisdn/requestToken") fun requestTokenToBindMsisdn(@Body body: IdentityRequestTokenForMsisdnBody): Call + + /** + * Validate ownership of an email address, or a phone number. + * Ref: + * - https://matrix.org/docs/spec/identity_service/latest#post-matrix-identity-v2-validate-msisdn-submittoken + * - https://matrix.org/docs/spec/identity_service/latest#post-matrix-identity-v2-validate-email-submittoken + */ + @POST(NetworkConstants.URI_IDENTITY_PATH_V2 + "validate/{medium}/submitToken") + fun submitToken(@Path("medium") medium: String, @Body body: IdentityRequestOwnershipParams): Call } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/identity/IdentityModule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/identity/IdentityModule.kt index d32461656f..1747ffe554 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/identity/IdentityModule.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/identity/IdentityModule.kt @@ -83,7 +83,6 @@ internal abstract class IdentityModule { .deleteRealmIfMigrationNeeded() .build() } - } @Binds @@ -99,6 +98,9 @@ internal abstract class IdentityModule { @Binds abstract fun bindIdentityRequestTokenForBindingTask(task: DefaultIdentityRequestTokenForBindingTask): IdentityRequestTokenForBindingTask + @Binds + abstract fun bindIdentitySubmitTokenForBindingTask(task: DefaultIdentitySubmitTokenForBindingTask): IdentitySubmitTokenForBindingTask + @Binds abstract fun bindBulkLookupTask(task: DefaultBulkLookupTask): BulkLookupTask diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/identity/IdentityRequestTokenForBindingTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/identity/IdentityRequestTokenForBindingTask.kt index e509684242..7eefb0255e 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/identity/IdentityRequestTokenForBindingTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/identity/IdentityRequestTokenForBindingTask.kt @@ -18,6 +18,7 @@ package im.vector.matrix.android.internal.session.identity import im.vector.matrix.android.api.session.identity.IdentityServiceError import im.vector.matrix.android.api.session.identity.ThreePid +import im.vector.matrix.android.api.session.identity.getCountryCode import im.vector.matrix.android.internal.di.UserId import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.session.identity.db.RealmIdentityServiceStore @@ -52,12 +53,14 @@ internal class DefaultIdentityRequestTokenForBindingTask @Inject constructor( sendAttempt = 1, email = params.threePid.email )) - is ThreePid.Msisdn -> identityAPI.requestTokenToBindMsisdn(IdentityRequestTokenForMsisdnBody( - clientSecret = clientSecret, - sendAttempt = 1, - phoneNumber = params.threePid.msisdn, - countryCode = params.threePid.countryCode - )) + is ThreePid.Msisdn -> { + identityAPI.requestTokenToBindMsisdn(IdentityRequestTokenForMsisdnBody( + clientSecret = clientSecret, + sendAttempt = 1, + phoneNumber = params.threePid.msisdn, + countryCode = params.threePid.getCountryCode() + )) + } } } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/identity/IdentitySubmitTokenForBindingTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/identity/IdentitySubmitTokenForBindingTask.kt new file mode 100644 index 0000000000..3abc53c226 --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/identity/IdentitySubmitTokenForBindingTask.kt @@ -0,0 +1,61 @@ +/* + * 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.matrix.android.internal.session.identity + +import im.vector.matrix.android.api.session.identity.IdentityServiceError +import im.vector.matrix.android.api.session.identity.ThreePid +import im.vector.matrix.android.api.session.identity.toMedium +import im.vector.matrix.android.internal.auth.registration.SuccessResult +import im.vector.matrix.android.internal.di.UserId +import im.vector.matrix.android.internal.network.executeRequest +import im.vector.matrix.android.internal.session.identity.db.RealmIdentityServiceStore +import im.vector.matrix.android.internal.session.identity.model.IdentityRequestOwnershipParams +import im.vector.matrix.android.internal.task.Task +import javax.inject.Inject + +internal interface IdentitySubmitTokenForBindingTask : Task { + data class Params( + val threePid: ThreePid, + val token: String + ) +} + +internal class DefaultIdentitySubmitTokenForBindingTask @Inject constructor( + private val identityApiProvider: IdentityApiProvider, + private val identityServiceStore: RealmIdentityServiceStore, + @UserId private val userId: String +) : IdentitySubmitTokenForBindingTask { + + override suspend fun execute(params: IdentitySubmitTokenForBindingTask.Params) { + val identityAPI = getIdentityApiAndEnsureTerms(identityApiProvider, userId) + val pendingThreePid = identityServiceStore.getPendingBinding(params.threePid) ?: throw IdentityServiceError.NoCurrentBindingError + + val tokenResponse = executeRequest(null) { + apiCall = identityAPI.submitToken( + params.threePid.toMedium(), + IdentityRequestOwnershipParams( + clientSecret = pendingThreePid.clientSecret, + sid = pendingThreePid.sid, + token = params.token + )) + } + + if (!tokenResponse.isSuccess()) { + throw IdentityServiceError.BindingError + } + } +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/identity/model/IdentityHashDetailResponse.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/identity/model/IdentityHashDetailResponse.kt index c32dd57627..d0e3d908e1 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/identity/model/IdentityHashDetailResponse.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/identity/model/IdentityHashDetailResponse.kt @@ -37,4 +37,9 @@ internal data class IdentityHashDetailResponse( */ @Json(name = "algorithms") val algorithms: List -) +) { + companion object{ + const val ALGORITHM_SHA256 = "sha256" + const val ALGORITHM_NONE = "none" + } +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/identity/model/IdentityRequestOwnershipParams.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/identity/model/IdentityRequestOwnershipParams.kt index d3f4778d7f..9da86cbc48 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/identity/model/IdentityRequestOwnershipParams.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/identity/model/IdentityRequestOwnershipParams.kt @@ -20,12 +20,21 @@ import com.squareup.moshi.JsonClass @JsonClass(generateAdapter = true) internal data class IdentityRequestOwnershipParams( + /** + * Required. The client secret that was supplied to the requestToken call. + */ @Json(name = "client_secret") - var clientSecret: String? = null, + val clientSecret: String, + /** + * Required. The session ID, generated by the requestToken call. + */ @Json(name = "sid") - var sid: String? = null, + val sid: String, + /** + * Required. The token generated by the requestToken call and sent to the user. + */ @Json(name = "token") - var token: String? = null + val token: String ) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/identity/model/IdentityRequestTokenBody.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/identity/model/IdentityRequestTokenBody.kt index 248d971201..3e92ebb1d2 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/identity/model/IdentityRequestTokenBody.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/identity/model/IdentityRequestTokenBody.kt @@ -21,7 +21,13 @@ import com.squareup.moshi.JsonClass // Just to consider common parameters private interface IdentityRequestTokenBody { + /** + * Required. A unique string generated by the client, and used to identify the validation attempt. + * It must be a string consisting of the characters [0-9a-zA-Z.=_-]. + * Its length must not exceed 255 characters and it must not be empty. + */ val clientSecret: String + val sendAttempt: Int } @@ -30,9 +36,19 @@ internal data class IdentityRequestTokenForEmailBody( @Json(name = "client_secret") override val clientSecret: String, + /** + * Required. The server will only send an email if the send_attempt is a number greater than the most + * recent one which it has seen, scoped to that email + client_secret pair. This is to avoid repeatedly + * sending the same email in the case of request retries between the POSTing user and the identity server. + * The client should increment this value if they desire a new email (e.g. a reminder) to be sent. + * If they do not, the server should respond with success but not resend the email. + */ @Json(name = "send_attempt") override val sendAttempt: Int, + /** + * Required. The email address to validate. + */ @Json(name = "email") val email: String ) : IdentityRequestTokenBody @@ -42,12 +58,25 @@ internal data class IdentityRequestTokenForMsisdnBody( @Json(name = "client_secret") override val clientSecret: String, + /** + * Required. The server will only send an SMS if the send_attempt is a number greater than the most recent one + * which it has seen, scoped to that country + phone_number + client_secret triple. This is to avoid repeatedly + * sending the same SMS in the case of request retries between the POSTing user and the identity server. + * The client should increment this value if they desire a new SMS (e.g. a reminder) to be sent. + */ @Json(name = "send_attempt") override val sendAttempt: Int, + /** + * Required. The phone number to validate. + */ @Json(name = "phone_number") val phoneNumber: String, + /** + * Required. The two-letter uppercase ISO-3166-1 alpha-2 country code that the number in phone_number + * should be parsed as if it were dialled from. + */ @Json(name = "country") - val countryCode: String? + val countryCode: String ) : IdentityRequestTokenBody diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/identity/model/IdentityRequestTokenResponse.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/identity/model/IdentityRequestTokenResponse.kt index 5acbacba88..53f62a519a 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/identity/model/IdentityRequestTokenResponse.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/identity/model/IdentityRequestTokenResponse.kt @@ -21,9 +21,17 @@ import com.squareup.moshi.JsonClass @JsonClass(generateAdapter = true) internal data class IdentityRequestTokenResponse( + /** + * Required. The session ID. Session IDs are opaque strings generated by the identity server. + * They must consist entirely of the characters [0-9a-zA-Z.=_-]. + * Their length must not exceed 255 characters and they must not be empty. + */ @Json(name = "sid") val sid: String, + /** + * Not documented + */ @Json(name = "success") val success: Boolean ) diff --git a/vector/src/main/java/im/vector/riotx/features/discovery/DiscoverySettingsController.kt b/vector/src/main/java/im/vector/riotx/features/discovery/DiscoverySettingsController.kt index 10597032fb..c8a16b37a2 100644 --- a/vector/src/main/java/im/vector/riotx/features/discovery/DiscoverySettingsController.kt +++ b/vector/src/main/java/im/vector/riotx/features/discovery/DiscoverySettingsController.kt @@ -132,7 +132,7 @@ class DiscoverySettingsController @Inject constructor( } SharedState.BINDING_IN_PROGRESS -> { buttonType(SettingsTextButtonItem.ButtonType.NORMAL) - buttonTitle("") + buttonTitle(null) } } } @@ -145,7 +145,7 @@ class DiscoverySettingsController @Inject constructor( interactionListener(object : SettingsItemText.Listener { override fun onValidate(code: String) { if (piState.threePid is ThreePid.Msisdn) { - listener?.checkMsisdnVerification(piState.threePid, code) + listener?.sendMsisdnVerificationCode(piState.threePid, code) } } }) @@ -299,7 +299,7 @@ class DiscoverySettingsController @Inject constructor( fun onTapRevoke(threePid: ThreePid) fun onTapShare(threePid: ThreePid) fun checkEmailVerification(threePid: ThreePid.Email) - fun checkMsisdnVerification(threePid: ThreePid.Msisdn, code: String) + fun sendMsisdnVerificationCode(threePid: ThreePid.Msisdn, code: String) fun onTapChangeIdentityServer() fun onTapDisconnectIdentityServer() fun onTapRetryToRetrieveBindings() diff --git a/vector/src/main/java/im/vector/riotx/features/discovery/DiscoverySettingsFragment.kt b/vector/src/main/java/im/vector/riotx/features/discovery/DiscoverySettingsFragment.kt index 2276432a8f..9358b791c8 100644 --- a/vector/src/main/java/im/vector/riotx/features/discovery/DiscoverySettingsFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/discovery/DiscoverySettingsFragment.kt @@ -67,7 +67,7 @@ class DiscoverySettingsFragment @Inject constructor( viewModel.observeViewEvents { when (it) { is DiscoverySettingsViewEvents.Failure -> { - // TODO Snackbar.make(view, throwable.toString(), Snackbar.LENGTH_LONG).show() + displayErrorDialog(it.throwable) } }.exhaustive } @@ -126,7 +126,7 @@ class DiscoverySettingsFragment @Inject constructor( viewModel.handle(DiscoverySettingsAction.FinalizeBind3pid(threePid)) } - override fun checkMsisdnVerification(threePid: ThreePid.Msisdn, code: String) { + override fun sendMsisdnVerificationCode(threePid: ThreePid.Msisdn, code: String) { viewModel.handle(DiscoverySettingsAction.SubmitMsisdnToken(threePid, code)) } diff --git a/vector/src/main/java/im/vector/riotx/features/discovery/DiscoverySettingsViewModel.kt b/vector/src/main/java/im/vector/riotx/features/discovery/DiscoverySettingsViewModel.kt index 7afae9800a..a680b8ce17 100644 --- a/vector/src/main/java/im/vector/riotx/features/discovery/DiscoverySettingsViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/discovery/DiscoverySettingsViewModel.kt @@ -24,7 +24,6 @@ import com.airbnb.mvrx.MvRxViewModelFactory import com.airbnb.mvrx.Success import com.airbnb.mvrx.Uninitialized import com.airbnb.mvrx.ViewModelContext -import com.google.i18n.phonenumbers.PhoneNumberUtil import com.squareup.inject.assisted.Assisted import com.squareup.inject.assisted.AssistedInject import im.vector.matrix.android.api.MatrixCallback @@ -166,18 +165,7 @@ class DiscoverySettingsViewModel @AssistedInject constructor( if (state.identityServer() == null) return@withState changeThreePidState(action.threePid, Loading()) - val threePid = if (action.threePid is ThreePid.Msisdn && action.threePid.countryCode == null) { - // Ensure we have a country code - - val phoneNumber = PhoneNumberUtil.getInstance() - .parse("+${action.threePid.msisdn}", null) - action.threePid.copy(countryCode = PhoneNumberUtil.getInstance().getRegionCodeForCountryCode(phoneNumber.countryCode) - ) - } else { - action.threePid - } - - identityService.startBindThreePid(threePid, object : MatrixCallback { + identityService.startBindThreePid(action.threePid, object : MatrixCallback { override fun onSuccess(data: Unit) { changeThreePidState(action.threePid, Success(SharedState.BINDING_IN_PROGRESS)) } @@ -286,8 +274,8 @@ class DiscoverySettingsViewModel @AssistedInject constructor( override fun onSuccess(data: Map) { setState { copy( - emailList = Success(toPidInfoList(data.filter { it.key is ThreePid.Email })), - phoneNumbersList = Success(toPidInfoList(data.filter { it.key is ThreePid.Msisdn })) + emailList = Success(data.filter { it.key is ThreePid.Email }.toPidInfoList()), + phoneNumbersList = Success(data.filter { it.key is ThreePid.Msisdn }.toPidInfoList()) ) } } @@ -312,8 +300,8 @@ class DiscoverySettingsViewModel @AssistedInject constructor( }) } - private fun toPidInfoList(threePidStatuses: Map): List { - return threePidStatuses.map { threePidStatus -> + private fun Map.toPidInfoList(): List { + return map { threePidStatus -> PidInfo( threePid = threePidStatus.key, isShared = Success(threePidStatus.value) @@ -328,7 +316,6 @@ class DiscoverySettingsViewModel @AssistedInject constructor( action.code, object : MatrixCallback { override fun onSuccess(data: Unit) { - // TODO This should be done in the task finalizeBind3pid(DiscoverySettingsAction.FinalizeBind3pid(action.threePid)) } diff --git a/vector/src/main/res/layout/item_settings_edit_text.xml b/vector/src/main/res/layout/item_settings_edit_text.xml index 7c6610b48d..e3f44910be 100644 --- a/vector/src/main/res/layout/item_settings_edit_text.xml +++ b/vector/src/main/res/layout/item_settings_edit_text.xml @@ -7,7 +7,6 @@ android:background="?attr/colorBackgroundFloating" android:orientation="vertical" android:paddingStart="@dimen/layout_horizontal_margin" - android:paddingTop="@dimen/layout_vertical_margin" android:paddingEnd="@dimen/layout_horizontal_margin" android:paddingBottom="@dimen/layout_vertical_margin">