Merge pull request #1129 from vector-im/feature/update_password

Change password function implemented.
This commit is contained in:
Benoit Marty 2020-04-16 11:26:33 +02:00 committed by GitHub
commit ea03f76847
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 439 additions and 83 deletions

View File

@ -2,6 +2,7 @@ Changes in RiotX 0.19.0 (2020-XX-XX)
===================================================
Features ✨:
- Change password (#528)
- Cross-Signing | Support SSSS secret sharing (#944)
- Cross-Signing | Verify new session from existing session (#1134)
- Cross-Signing | Bootstraping cross signing with 4S from mobile (#985)

View File

@ -31,3 +31,9 @@ fun Throwable.shouldBeRetried(): Boolean {
return this is Failure.NetworkConnection
|| (this is Failure.ServerError && error.code == MatrixError.M_LIMIT_EXCEEDED)
}
fun Throwable.isInvalidPassword(): Boolean {
return this is Failure.ServerError
&& error.code == MatrixError.M_FORBIDDEN
&& error.message == "Invalid password"
}

View File

@ -21,6 +21,7 @@ import androidx.lifecycle.LiveData
import im.vector.matrix.android.api.auth.data.SessionParams
import im.vector.matrix.android.api.failure.GlobalError
import im.vector.matrix.android.api.pushrules.PushRuleService
import im.vector.matrix.android.api.session.account.AccountService
import im.vector.matrix.android.api.session.accountdata.AccountDataService
import im.vector.matrix.android.api.session.cache.CacheService
import im.vector.matrix.android.api.session.content.ContentUploadStateTracker
@ -59,7 +60,8 @@ interface Session :
InitialSyncProgressService,
HomeServerCapabilitiesService,
SecureStorageService,
AccountDataService {
AccountDataService,
AccountService {
/**
* The params associated to the session

View File

@ -0,0 +1,33 @@
/*
* 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.api.session.account
import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.util.Cancelable
/**
* This interface defines methods to manage the account. It's implemented at the session level.
*/
interface AccountService {
/**
* Ask the homeserver to change the password.
* @param password Current password.
* @param newPassword New password
*/
fun changePassword(password: String, newPassword: String, callback: MatrixCallback<Unit>): Cancelable
}

View File

@ -0,0 +1,42 @@
/*
* 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.api.session.account.model
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import im.vector.matrix.android.internal.crypto.model.rest.UserPasswordAuth
/**
* Class to pass request parameters to update the password.
*/
@JsonClass(generateAdapter = true)
internal data class ChangePasswordParams(
@Json(name = "auth")
val auth: UserPasswordAuth? = null,
@Json(name = "new_password")
val newPassword: String? = null
) {
companion object {
fun create(userId: String, oldPassword: String, newPassword: String): ChangePasswordParams {
return ChangePasswordParams(
auth = UserPasswordAuth(user = userId, password = oldPassword),
newPassword = newPassword
)
}
}
}

View File

@ -17,6 +17,10 @@
package im.vector.matrix.android.api.session.homeserver
data class HomeServerCapabilities(
/**
* True if it is possible to change the password of the account.
*/
val canChangePassword: Boolean = true,
/**
* Max size of file which can be uploaded to the homeserver in bytes. [MAX_UPLOAD_FILE_SIZE_UNKNOWN] if unknown or not retrieved yet
*/

View File

@ -21,7 +21,7 @@ import com.squareup.moshi.JsonClass
import im.vector.matrix.android.internal.auth.data.LoginFlowTypes
/**
* This class provides the authentication data to delete a device
* This class provides the authentication data by using user and password
*/
@JsonClass(generateAdapter = true)
data class UserPasswordAuth(

View File

@ -26,12 +26,14 @@ internal object HomeServerCapabilitiesMapper {
fun map(entity: HomeServerCapabilitiesEntity): HomeServerCapabilities {
return HomeServerCapabilities(
canChangePassword = entity.canChangePassword,
maxUploadFileSize = entity.maxUploadFileSize
)
}
fun map(domain: HomeServerCapabilities): HomeServerCapabilitiesEntity {
return HomeServerCapabilitiesEntity(
canChangePassword = domain.canChangePassword,
maxUploadFileSize = domain.maxUploadFileSize
)
}

View File

@ -20,6 +20,7 @@ import im.vector.matrix.android.api.session.homeserver.HomeServerCapabilities
import io.realm.RealmObject
internal open class HomeServerCapabilitiesEntity(
var canChangePassword: Boolean = true,
var maxUploadFileSize: Long = HomeServerCapabilities.MAX_UPLOAD_FILE_SIZE_UNKNOWN,
var lastUpdatedTimestamp: Long = 0L
) : RealmObject() {

View File

@ -25,6 +25,7 @@ import im.vector.matrix.android.api.failure.GlobalError
import im.vector.matrix.android.api.pushrules.PushRuleService
import im.vector.matrix.android.api.session.InitialSyncProgressService
import im.vector.matrix.android.api.session.Session
import im.vector.matrix.android.api.session.account.AccountService
import im.vector.matrix.android.api.session.accountdata.AccountDataService
import im.vector.matrix.android.api.session.cache.CacheService
import im.vector.matrix.android.api.session.content.ContentUploadStateTracker
@ -94,6 +95,7 @@ internal class DefaultSession @Inject constructor(
private val homeServerCapabilitiesService: Lazy<HomeServerCapabilitiesService>,
private val accountDataService: Lazy<AccountDataService>,
private val _sharedSecretStorageService: Lazy<SharedSecretStorageService>,
private val accountService: Lazy<AccountService>,
private val timelineEventDecryptor: TimelineEventDecryptor,
private val shieldTrustUpdater: ShieldTrustUpdater)
: Session,
@ -110,7 +112,8 @@ internal class DefaultSession @Inject constructor(
SecureStorageService by secureStorageService.get(),
HomeServerCapabilitiesService by homeServerCapabilitiesService.get(),
ProfileService by profileService.get(),
AccountDataService by accountDataService.get() {
AccountDataService by accountDataService.get(),
AccountService by accountService.get() {
override val sharedSecretStorageService: SharedSecretStorageService
get() = _sharedSecretStorageService.get()

View File

@ -28,6 +28,7 @@ import im.vector.matrix.android.internal.crypto.verification.SendVerificationMes
import im.vector.matrix.android.internal.di.MatrixComponent
import im.vector.matrix.android.internal.di.SessionAssistedInjectModule
import im.vector.matrix.android.internal.network.NetworkConnectivityChecker
import im.vector.matrix.android.internal.session.account.AccountModule
import im.vector.matrix.android.internal.session.cache.CacheModule
import im.vector.matrix.android.internal.session.content.ContentModule
import im.vector.matrix.android.internal.session.content.UploadContentWorker
@ -55,24 +56,25 @@ import im.vector.matrix.android.internal.task.TaskExecutor
import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers
@Component(dependencies = [MatrixComponent::class],
modules = [
SessionModule::class,
RoomModule::class,
SyncModule::class,
HomeServerCapabilitiesModule::class,
SignOutModule::class,
GroupModule::class,
UserModule::class,
FilterModule::class,
GroupModule::class,
ContentModule::class,
CacheModule::class,
CryptoModule::class,
PushersModule::class,
AccountDataModule::class,
ProfileModule::class,
SessionAssistedInjectModule::class
]
modules = [
SessionModule::class,
RoomModule::class,
SyncModule::class,
HomeServerCapabilitiesModule::class,
SignOutModule::class,
GroupModule::class,
UserModule::class,
FilterModule::class,
GroupModule::class,
ContentModule::class,
CacheModule::class,
CryptoModule::class,
PushersModule::class,
AccountDataModule::class,
ProfileModule::class,
SessionAssistedInjectModule::class,
AccountModule::class
]
)
@SessionScope
internal interface SessionComponent {

View File

@ -0,0 +1,34 @@
/*
* 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.account
import im.vector.matrix.android.api.session.account.model.ChangePasswordParams
import im.vector.matrix.android.internal.network.NetworkConstants
import retrofit2.Call
import retrofit2.http.Body
import retrofit2.http.Headers
import retrofit2.http.POST
internal interface AccountAPI {
/**
* Ask the homeserver to change the password with the provided new password.
* @param params parameters to change password.
*/
@POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "account/password")
fun changePassword(@Body params: ChangePasswordParams): Call<Unit>
}

View File

@ -0,0 +1,44 @@
/*
* 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.account
import dagger.Binds
import dagger.Module
import dagger.Provides
import im.vector.matrix.android.api.session.account.AccountService
import im.vector.matrix.android.internal.session.SessionScope
import retrofit2.Retrofit
@Module
internal abstract class AccountModule {
@Module
companion object {
@Provides
@JvmStatic
@SessionScope
fun providesAccountAPI(retrofit: Retrofit): AccountAPI {
return retrofit.create(AccountAPI::class.java)
}
}
@Binds
abstract fun bindChangePasswordTask(task: DefaultChangePasswordTask): ChangePasswordTask
@Binds
abstract fun bindAccountService(service: DefaultAccountService): AccountService
}

View File

@ -0,0 +1,76 @@
/*
* 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.account
import im.vector.matrix.android.api.failure.Failure
import im.vector.matrix.android.api.session.account.model.ChangePasswordParams
import im.vector.matrix.android.internal.auth.registration.RegistrationFlowResponse
import im.vector.matrix.android.internal.di.MoshiProvider
import im.vector.matrix.android.internal.di.UserId
import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.task.Task
import org.greenrobot.eventbus.EventBus
import javax.inject.Inject
internal interface ChangePasswordTask : Task<ChangePasswordTask.Params, Unit> {
data class Params(
val password: String,
val newPassword: String
)
}
internal class DefaultChangePasswordTask @Inject constructor(
private val accountAPI: AccountAPI,
private val eventBus: EventBus,
@UserId private val userId: String
) : ChangePasswordTask {
override suspend fun execute(params: ChangePasswordTask.Params) {
val changePasswordParams = ChangePasswordParams.create(userId, params.password, params.newPassword)
try {
executeRequest<Unit>(eventBus) {
apiCall = accountAPI.changePassword(changePasswordParams)
}
} catch (throwable: Throwable) {
if (throwable is Failure.OtherServerError
&& throwable.httpCode == 401
/* Avoid infinite loop */
&& changePasswordParams.auth?.session == null) {
try {
MoshiProvider.providesMoshi()
.adapter(RegistrationFlowResponse::class.java)
.fromJson(throwable.errorBody)
} catch (e: Exception) {
null
}?.let {
// Retry with authentication
try {
executeRequest<Unit>(eventBus) {
apiCall = accountAPI.changePassword(
changePasswordParams.copy(auth = changePasswordParams.auth?.copy(session = it.session))
)
}
return
} catch (failure: Throwable) {
throw failure
}
}
}
throw throwable
}
}
}

View File

@ -0,0 +1,36 @@
/*
* 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.account
import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.session.account.AccountService
import im.vector.matrix.android.api.util.Cancelable
import im.vector.matrix.android.internal.task.TaskExecutor
import im.vector.matrix.android.internal.task.configureWith
import javax.inject.Inject
internal class DefaultAccountService @Inject constructor(private val changePasswordTask: ChangePasswordTask,
private val taskExecutor: TaskExecutor) : AccountService {
override fun changePassword(password: String, newPassword: String, callback: MatrixCallback<Unit>): Cancelable {
return changePasswordTask
.configureWith(ChangePasswordTask.Params(password, newPassword)) {
this.callback = callback
}
.executeBy(taskExecutor)
}
}

View File

@ -22,6 +22,12 @@ import retrofit2.http.GET
internal interface CapabilitiesAPI {
/**
* Request the homeserver capabilities
*/
@GET(NetworkConstants.URI_API_PREFIX_PATH_R0 + "capabilities")
fun getCapabilities(): Call<GetCapabilitiesResult>
/**
* Request the upload capabilities
*/

View File

@ -51,15 +51,23 @@ internal class DefaultGetHomeServerCapabilitiesTask @Inject constructor(
apiCall = capabilitiesAPI.getUploadCapabilities()
}
val capabilities = runCatching {
executeRequest<GetCapabilitiesResult>(eventBus) {
apiCall = capabilitiesAPI.getCapabilities()
}
}.getOrNull()
// TODO Add other call here (get version, etc.)
insertInDb(uploadCapabilities)
insertInDb(capabilities, uploadCapabilities)
}
private suspend fun insertInDb(getUploadCapabilitiesResult: GetUploadCapabilitiesResult) {
private suspend fun insertInDb(getCapabilitiesResult: GetCapabilitiesResult?, getUploadCapabilitiesResult: GetUploadCapabilitiesResult) {
monarchy.awaitTransaction { realm ->
val homeServerCapabilitiesEntity = HomeServerCapabilitiesEntity.getOrCreate(realm)
homeServerCapabilitiesEntity.canChangePassword = getCapabilitiesResult.canChangePassword()
homeServerCapabilitiesEntity.maxUploadFileSize = getUploadCapabilitiesResult.maxUploadSize
?: HomeServerCapabilities.MAX_UPLOAD_FILE_SIZE_UNKNOWN

View File

@ -0,0 +1,58 @@
/*
* 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.homeserver
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import im.vector.matrix.android.api.extensions.orTrue
/**
* Ref: https://matrix.org/docs/spec/client_server/latest#get-matrix-client-r0-capabilities
*/
@JsonClass(generateAdapter = true)
internal data class GetCapabilitiesResult(
/**
* Required. The custom capabilities the server supports, using the Java package naming convention.
*/
@Json(name = "capabilities")
val capabilities: Capabilities? = null
)
@JsonClass(generateAdapter = true)
internal data class Capabilities(
/**
* Capability to indicate if the user can change their password.
*/
@Json(name = "m.change_password")
val changePassword: ChangePassword? = null
// No need for m.room_versions for the moment
)
@JsonClass(generateAdapter = true)
internal data class ChangePassword(
/**
* Required. True if the user can change their password, false otherwise.
*/
@Json(name = "enabled")
val enabled: Boolean?
)
// The spec says: If not present, the client should assume that password changes are possible via the API
internal fun GetCapabilitiesResult?.canChangePassword(): Boolean {
return this?.capabilities?.changePassword?.enabled.orTrue()
}

View File

@ -20,7 +20,7 @@ import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true)
data class GetUploadCapabilitiesResult(
internal data class GetUploadCapabilitiesResult(
/**
* The maximum size an upload can be in bytes. Clients SHOULD use this as a guide when uploading content.
* If not listed or null, the size limit should be treated as unknown.

View File

@ -18,6 +18,7 @@ package im.vector.riotx.core.error
import im.vector.matrix.android.api.failure.Failure
import im.vector.matrix.android.api.failure.MatrixError
import im.vector.matrix.android.api.failure.isInvalidPassword
import im.vector.riotx.R
import im.vector.riotx.core.resources.StringProvider
import java.net.HttpURLConnection
@ -54,8 +55,7 @@ class DefaultErrorFormatter @Inject constructor(
// Special case for terms and conditions
stringProvider.getString(R.string.error_terms_not_accepted)
}
throwable.error.code == MatrixError.M_FORBIDDEN
&& throwable.error.message == "Invalid password" -> {
throwable.isInvalidPassword() -> {
stringProvider.getString(R.string.auth_invalid_login_param)
}
throwable.error.code == MatrixError.M_USER_IN_USE -> {
@ -67,7 +67,7 @@ class DefaultErrorFormatter @Inject constructor(
throwable.error.code == MatrixError.M_NOT_JSON -> {
stringProvider.getString(R.string.login_error_not_json)
}
throwable.error.code == MatrixError.M_THREEPID_DENIED -> {
throwable.error.code == MatrixError.M_THREEPID_DENIED -> {
stringProvider.getString(R.string.login_error_threepid_denied)
}
throwable.error.code == MatrixError.M_LIMIT_EXCEEDED -> {

View File

@ -28,6 +28,7 @@ import com.airbnb.mvrx.Success
import com.jakewharton.rxbinding3.widget.textChanges
import im.vector.matrix.android.api.failure.Failure
import im.vector.matrix.android.api.failure.MatrixError
import im.vector.matrix.android.api.failure.isInvalidPassword
import im.vector.riotx.R
import im.vector.riotx.core.extensions.hideKeyboard
import im.vector.riotx.core.extensions.showPassword
@ -209,10 +210,7 @@ class LoginFragment @Inject constructor() : AbstractLoginFragment() {
} else {
// Trick to display the error without text.
loginFieldTil.error = " "
if (error is Failure.ServerError
&& error.error.code == MatrixError.M_FORBIDDEN
&& error.error.message == "Invalid password"
&& spaceInPassword()) {
if (error.isInvalidPassword() && spaceInPassword()) {
passwordFieldTil.error = getString(R.string.auth_invalid_login_param_space_in_password)
} else {
passwordFieldTil.error = errorFormatter.toHumanReadable(error)

View File

@ -35,6 +35,8 @@ import com.bumptech.glide.Glide
import com.bumptech.glide.load.engine.cache.DiskCache
import com.google.android.material.textfield.TextInputEditText
import com.google.android.material.textfield.TextInputLayout
import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.failure.isInvalidPassword
import im.vector.riotx.R
import im.vector.riotx.core.extensions.hideKeyboard
import im.vector.riotx.core.extensions.showPassword
@ -108,10 +110,14 @@ class VectorSettingsGeneralFragment : VectorSettingsBaseFragment() {
}
// Password
mPasswordPreference.onPreferenceClickListener = Preference.OnPreferenceClickListener {
notImplemented()
// onPasswordUpdateClick()
false
// Hide the preference if password can not be updated
if (session.getHomeServerCapabilities().canChangePassword) {
mPasswordPreference.onPreferenceClickListener = Preference.OnPreferenceClickListener {
onPasswordUpdateClick()
false
}
} else {
mPasswordPreference.isVisible = false
}
// Add Email
@ -684,21 +690,20 @@ class VectorSettingsGeneralFragment : VectorSettingsBaseFragment() {
var passwordShown = false
showPassword.setOnClickListener(object : View.OnClickListener {
override fun onClick(v: View?) {
passwordShown = !passwordShown
showPassword.setOnClickListener {
passwordShown = !passwordShown
oldPasswordText.showPassword(passwordShown)
newPasswordText.showPassword(passwordShown)
confirmNewPasswordText.showPassword(passwordShown)
oldPasswordText.showPassword(passwordShown)
newPasswordText.showPassword(passwordShown)
confirmNewPasswordText.showPassword(passwordShown)
showPassword.setImageResource(if (passwordShown) R.drawable.ic_eye_closed_black else R.drawable.ic_eye_black)
}
})
showPassword.setImageResource(if (passwordShown) R.drawable.ic_eye_closed_black else R.drawable.ic_eye_black)
}
val dialog = AlertDialog.Builder(activity)
.setView(view)
.setPositiveButton(R.string.settings_change_password_submit, null)
.setCancelable(false)
.setPositiveButton(R.string.settings_change_password, null)
.setNegativeButton(R.string.cancel, null)
.setOnDismissListener {
view.hideKeyboard()
@ -707,12 +712,13 @@ class VectorSettingsGeneralFragment : VectorSettingsBaseFragment() {
dialog.setOnShowListener {
val updateButton = dialog.getButton(AlertDialog.BUTTON_POSITIVE)
val cancelButton = dialog.getButton(AlertDialog.BUTTON_NEGATIVE)
updateButton.isEnabled = false
fun updateUi() {
val oldPwd = oldPasswordText.text.toString().trim()
val newPwd = newPasswordText.text.toString().trim()
val newConfirmPwd = confirmNewPasswordText.text.toString().trim()
val oldPwd = oldPasswordText.text.toString()
val newPwd = newPasswordText.text.toString()
val newConfirmPwd = confirmNewPasswordText.text.toString()
updateButton.isEnabled = oldPwd.isNotEmpty() && newPwd.isNotEmpty() && newPwd == newConfirmPwd
@ -750,6 +756,7 @@ class VectorSettingsGeneralFragment : VectorSettingsBaseFragment() {
confirmNewPasswordText.isEnabled = false
changePasswordLoader.isVisible = true
updateButton.isEnabled = false
cancelButton.isEnabled = false
} else {
showPassword.isEnabled = true
oldPasswordText.isEnabled = true
@ -757,6 +764,7 @@ class VectorSettingsGeneralFragment : VectorSettingsBaseFragment() {
confirmNewPasswordText.isEnabled = true
changePasswordLoader.isVisible = false
updateButton.isEnabled = true
cancelButton.isEnabled = true
}
}
@ -768,47 +776,32 @@ class VectorSettingsGeneralFragment : VectorSettingsBaseFragment() {
view.hideKeyboard()
val oldPwd = oldPasswordText.text.toString().trim()
val newPwd = newPasswordText.text.toString().trim()
val oldPwd = oldPasswordText.text.toString()
val newPwd = newPasswordText.text.toString()
notImplemented()
/* TODO
showPasswordLoadingView(true)
session.updatePassword(oldPwd, newPwd, object : MatrixCallback<Unit> {
private fun onDone(@StringRes textResId: Int) {
session.changePassword(oldPwd, newPwd, object : MatrixCallback<Unit> {
override fun onSuccess(data: Unit) {
if (!isAdded) {
return
}
showPasswordLoadingView(false)
dialog.dismiss()
activity.toast(R.string.settings_password_updated)
}
if (textResId == R.string.settings_fail_to_update_password_invalid_current_password) {
oldPasswordTil.error = getString(textResId)
} else {
dialog.dismiss()
activity.toast(textResId, Toast.LENGTH_LONG)
override fun onFailure(failure: Throwable) {
if (!isAdded) {
return
}
}
override fun onSuccess(info: Void?) {
onDone(R.string.settings_password_updated)
}
override fun onNetworkError(e: Exception) {
onDone(R.string.settings_fail_to_update_password)
}
override fun onMatrixError(e: MatrixError) {
if (e.error == "Invalid password") {
onDone(R.string.settings_fail_to_update_password_invalid_current_password)
showPasswordLoadingView(false)
if (failure.isInvalidPassword()) {
oldPasswordTil.error = getString(R.string.settings_fail_to_update_password_invalid_current_password)
} else {
dialog.dismiss()
onDone(R.string.settings_fail_to_update_password)
oldPasswordTil.error = getString(R.string.settings_fail_to_update_password)
}
}
override fun onUnexpectedError(e: Exception) {
onDone(R.string.settings_fail_to_update_password)
}
})
*/
}
}
dialog.show()

View File

@ -39,7 +39,8 @@
android:id="@+id/change_password_old_pwd_til"
style="@style/VectorTextInputLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_height="wrap_content"
app:errorEnabled="true">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/change_password_old_pwd_text"
@ -53,7 +54,9 @@
<com.google.android.material.textfield.TextInputLayout
style="@style/VectorTextInputLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
app:errorEnabled="true">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/change_password_new_pwd_text"
@ -69,6 +72,7 @@
style="@style/VectorTextInputLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
app:errorEnabled="true">
<com.google.android.material.textfield.TextInputEditText

View File

@ -29,4 +29,7 @@
<!-- END Strings added by Others -->
<!-- BEGIN Strings added by Benoit -->
<string name="change_password_summary">Set a new account password…</string>
<!---->
</resources>

View File

@ -19,7 +19,7 @@
<im.vector.riotx.core.preference.VectorPreference
android:key="SETTINGS_CHANGE_PASSWORD_PREFERENCE_KEY"
android:summary="@string/password_hint"
android:summary="@string/change_password_summary"
android:title="@string/settings_password" />
<!-- Email will be added here -->