Merge pull request #1530 from vector-im/feature/display_name

Add capability to change the display name (#1529)
This commit is contained in:
Benoit Marty 2020-06-23 13:52:51 +02:00 committed by GitHub
commit d075cbf69b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 118 additions and 37 deletions

View File

@ -7,6 +7,7 @@
<w>ciphertext</w> <w>ciphertext</w>
<w>coroutine</w> <w>coroutine</w>
<w>decryptor</w> <w>decryptor</w>
<w>displayname</w>
<w>emoji</w> <w>emoji</w>
<w>emojis</w> <w>emojis</w>
<w>fdroid</w> <w>fdroid</w>

View File

@ -3,6 +3,7 @@ Changes in RiotX 0.23.0 (2020-XX-XX)
Features ✨: Features ✨:
- Call with WebRTC support (##611) - Call with WebRTC support (##611)
- Add capability to change the display name (#1529)
Improvements 🙌: Improvements 🙌:
- "Add Matrix app" menu is now always visible (#1495) - "Add Matrix app" menu is now always visible (#1495)

View File

@ -35,12 +35,19 @@ interface ProfileService {
} }
/** /**
* Return the current dispayname for this user * Return the current display name for this user
* @param userId the userId param to look for * @param userId the userId param to look for
* *
*/ */
fun getDisplayName(userId: String, matrixCallback: MatrixCallback<Optional<String>>): Cancelable fun getDisplayName(userId: String, matrixCallback: MatrixCallback<Optional<String>>): Cancelable
/**
* Update the display name for this user
* @param userId the userId to update the display name of
* @param newDisplayName the new display name of the user
*/
fun setDisplayName(userId: String, newDisplayName: String, matrixCallback: MatrixCallback<Unit>): Cancelable
/** /**
* Return the current avatarUrl for this user. * Return the current avatarUrl for this user.
* @param userId the userId param to look for * @param userId the userId param to look for

View File

@ -34,7 +34,8 @@ import javax.inject.Inject
internal class DefaultProfileService @Inject constructor(private val taskExecutor: TaskExecutor, internal class DefaultProfileService @Inject constructor(private val taskExecutor: TaskExecutor,
private val monarchy: Monarchy, private val monarchy: Monarchy,
private val refreshUserThreePidsTask: RefreshUserThreePidsTask, private val refreshUserThreePidsTask: RefreshUserThreePidsTask,
private val getProfileInfoTask: GetProfileInfoTask) : ProfileService { private val getProfileInfoTask: GetProfileInfoTask,
private val setDisplayNameTask: SetDisplayNameTask) : ProfileService {
override fun getDisplayName(userId: String, matrixCallback: MatrixCallback<Optional<String>>): Cancelable { override fun getDisplayName(userId: String, matrixCallback: MatrixCallback<Optional<String>>): Cancelable {
val params = GetProfileInfoTask.Params(userId) val params = GetProfileInfoTask.Params(userId)
@ -54,6 +55,14 @@ internal class DefaultProfileService @Inject constructor(private val taskExecuto
.executeBy(taskExecutor) .executeBy(taskExecutor)
} }
override fun setDisplayName(userId: String, newDisplayName: String, matrixCallback: MatrixCallback<Unit>): Cancelable {
return setDisplayNameTask
.configureWith(SetDisplayNameTask.Params(userId = userId, newDisplayName = newDisplayName)) {
callback = matrixCallback
}
.executeBy(taskExecutor)
}
override fun getAvatarUrl(userId: String, matrixCallback: MatrixCallback<Optional<String>>): Cancelable { override fun getAvatarUrl(userId: String, matrixCallback: MatrixCallback<Optional<String>>): Cancelable {
val params = GetProfileInfoTask.Params(userId) val params = GetProfileInfoTask.Params(userId)
return getProfileInfoTask return getProfileInfoTask

View File

@ -23,6 +23,7 @@ import retrofit2.Call
import retrofit2.http.Body import retrofit2.http.Body
import retrofit2.http.GET import retrofit2.http.GET
import retrofit2.http.POST import retrofit2.http.POST
import retrofit2.http.PUT
import retrofit2.http.Path import retrofit2.http.Path
internal interface ProfileAPI { internal interface ProfileAPI {
@ -42,6 +43,12 @@ internal interface ProfileAPI {
@GET(NetworkConstants.URI_API_PREFIX_PATH_R0 + "account/3pid") @GET(NetworkConstants.URI_API_PREFIX_PATH_R0 + "account/3pid")
fun getThreePIDs(): Call<AccountThreePidsResponse> fun getThreePIDs(): Call<AccountThreePidsResponse>
/**
* Change user display name
*/
@PUT(NetworkConstants.URI_API_PREFIX_PATH_R0 + "profile/{userId}/displayname")
fun setDisplayName(@Path("userId") userId: String, @Body body: SetDisplayNameBody): Call<Unit>
/** /**
* Bind a threePid * Bind a threePid
* Ref: https://matrix.org/docs/spec/client_server/latest#post-matrix-client-r0-account-3pid-bind * Ref: https://matrix.org/docs/spec/client_server/latest#post-matrix-client-r0-account-3pid-bind

View File

@ -51,4 +51,7 @@ internal abstract class ProfileModule {
@Binds @Binds
abstract fun bindUnbindThreePidsTask(task: DefaultUnbindThreePidsTask): UnbindThreePidsTask abstract fun bindUnbindThreePidsTask(task: DefaultUnbindThreePidsTask): UnbindThreePidsTask
@Binds
abstract fun bindSetDisplayNameTask(task: DefaultSetDisplayNameTask): SetDisplayNameTask
} }

View File

@ -0,0 +1,28 @@
/*
* 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.profile
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true)
internal data class SetDisplayNameBody(
/**
* The new display name for this user.
*/
@Json(name = "displayname")
val displayName: String
)

View File

@ -0,0 +1,43 @@
/*
* 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.profile
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 abstract class SetDisplayNameTask : Task<SetDisplayNameTask.Params, Unit> {
data class Params(
val userId: String,
val newDisplayName: String
)
}
internal class DefaultSetDisplayNameTask @Inject constructor(
private val profileAPI: ProfileAPI,
private val eventBus: EventBus) : SetDisplayNameTask() {
override suspend fun execute(params: Params) {
return executeRequest(eventBus) {
val body = SetDisplayNameBody(
displayName = params.newDisplayName
)
apiCall = profileAPI.setDisplayName(params.userId, body)
}
}
}

View File

@ -33,8 +33,8 @@
<string name="notice_display_name_set_by_you">You set your display name to %1$s</string> <string name="notice_display_name_set_by_you">You set your display name to %1$s</string>
<string name="notice_display_name_changed_from">%1$s changed their display name from %2$s to %3$s</string> <string name="notice_display_name_changed_from">%1$s changed their display name from %2$s to %3$s</string>
<string name="notice_display_name_changed_from_by_you">You changed your display name from %1$s to %2$s</string> <string name="notice_display_name_changed_from_by_you">You changed your display name from %1$s to %2$s</string>
<string name="notice_display_name_removed">%1$s removed their display name (%2$s)</string> <string name="notice_display_name_removed">%1$s removed their display name (it was %2$s)</string>
<string name="notice_display_name_removed_by_you">You removed your display name (%1$s)</string> <string name="notice_display_name_removed_by_you">You removed your display name (it was %1$s)</string>
<string name="notice_room_topic_changed">%1$s changed the topic to: %2$s</string> <string name="notice_room_topic_changed">%1$s changed the topic to: %2$s</string>
<string name="notice_room_topic_changed_by_you">You changed the topic to: %1$s</string> <string name="notice_room_topic_changed_by_you">You changed the topic to: %1$s</string>
<string name="notice_room_name_changed">%1$s changed the room name to: %2$s</string> <string name="notice_room_name_changed">%1$s changed the room name to: %2$s</string>

View File

@ -74,7 +74,6 @@ class VectorPreferences @Inject constructor(private val context: Context) {
const val SETTINGS_SECURE_MESSAGE_RECOVERY_PREFERENCE_KEY = "SETTINGS_SECURE_MESSAGE_RECOVERY_PREFERENCE_KEY" const val SETTINGS_SECURE_MESSAGE_RECOVERY_PREFERENCE_KEY = "SETTINGS_SECURE_MESSAGE_RECOVERY_PREFERENCE_KEY"
// user // user
const val SETTINGS_DISPLAY_NAME_PREFERENCE_KEY = "SETTINGS_DISPLAY_NAME_PREFERENCE_KEY"
const val SETTINGS_PROFILE_PICTURE_PREFERENCE_KEY = "SETTINGS_PROFILE_PICTURE_PREFERENCE_KEY" const val SETTINGS_PROFILE_PICTURE_PREFERENCE_KEY = "SETTINGS_PROFILE_PICTURE_PREFERENCE_KEY"
// contacts // contacts

View File

@ -79,7 +79,7 @@ class VectorSettingsGeneralFragment : VectorSettingsBaseFragment() {
findPreference<UserAvatarPreference>(VectorPreferences.SETTINGS_PROFILE_PICTURE_PREFERENCE_KEY)!! findPreference<UserAvatarPreference>(VectorPreferences.SETTINGS_PROFILE_PICTURE_PREFERENCE_KEY)!!
} }
private val mDisplayNamePreference by lazy { private val mDisplayNamePreference by lazy {
findPreference<EditTextPreference>(VectorPreferences.SETTINGS_DISPLAY_NAME_PREFERENCE_KEY)!! findPreference<EditTextPreference>("SETTINGS_DISPLAY_NAME_PREFERENCE_KEY")!!
} }
private val mPasswordPreference by lazy { private val mPasswordPreference by lazy {
findPreference<VectorPreference>(VectorPreferences.SETTINGS_CHANGE_PASSWORD_PREFERENCE_KEY)!! findPreference<VectorPreference>(VectorPreferences.SETTINGS_CHANGE_PASSWORD_PREFERENCE_KEY)!!
@ -122,7 +122,9 @@ class VectorSettingsGeneralFragment : VectorSettingsBaseFragment() {
it.summary = session.getUser(session.myUserId)?.displayName ?: "" it.summary = session.getUser(session.myUserId)?.displayName ?: ""
it.text = it.summary.toString() it.text = it.summary.toString()
it.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue -> it.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue ->
onDisplayNameClick(newValue?.let { (it as String).trim() }) newValue
?.let { value -> (value as? String)?.trim() }
?.let { value -> onDisplayNameChanged(value) }
false false
} }
} }
@ -857,45 +859,25 @@ class VectorSettingsGeneralFragment : VectorSettingsBaseFragment() {
/** /**
* Update the displayname. * Update the displayname.
*/ */
private fun onDisplayNameClick(value: String?) { private fun onDisplayNameChanged(value: String) {
notImplemented() val currentDisplayName = session.getUser(session.myUserId)?.displayName ?: ""
/* TODO if (currentDisplayName != value) {
if (!TextUtils.equals(session.myUser.displayname, value)) {
displayLoadingView() displayLoadingView()
session.myUser.updateDisplayName(value, object : MatrixCallback<Unit> { session.setDisplayName(session.myUserId, value, object : MatrixCallback<Unit> {
override fun onSuccess(info: Void?) { override fun onSuccess(data: Unit) {
if (!isAdded) return
// refresh the settings value // refresh the settings value
PreferenceManager.getDefaultSharedPreferences(activity).edit { mDisplayNamePreference.summary = value
putString(VectorPreferences.SETTINGS_DISPLAY_NAME_PREFERENCE_KEY, value)
}
onCommonDone(null) onCommonDone(null)
refreshDisplay()
} }
override fun onNetworkError(e: Exception) { override fun onFailure(failure: Throwable) {
onCommonDone(e.localizedMessage) if (!isAdded) return
} onCommonDone(failure.localizedMessage)
override fun onMatrixError(e: MatrixError) {
if (MatrixError.M_CONSENT_NOT_GIVEN == e.errcode) {
activity?.runOnUiThread {
hideLoadingView()
(activity as VectorAppCompatActivity).consentNotGivenHelper.displayDialog(e)
}
} else {
onCommonDone(e.localizedMessage)
}
}
override fun onUnexpectedError(e: Exception) {
onCommonDone(e.localizedMessage)
} }
}) })
} }
*/
} }
companion object { companion object {

View File

@ -14,6 +14,7 @@
<im.vector.riotx.core.preference.VectorEditTextPreference <im.vector.riotx.core.preference.VectorEditTextPreference
android:key="SETTINGS_DISPLAY_NAME_PREFERENCE_KEY" android:key="SETTINGS_DISPLAY_NAME_PREFERENCE_KEY"
android:persistent="false"
android:summary="@string/settings_display_name" android:summary="@string/settings_display_name"
android:title="@string/settings_display_name" /> android:title="@string/settings_display_name" />