Merge pull request #1963 from vector-im/feature/cleanup

Improve user avatar setting
This commit is contained in:
Benoit Marty 2020-08-20 13:56:43 +02:00 committed by GitHub
commit cd08c919e9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 59 additions and 89 deletions

View File

@ -11,6 +11,7 @@ Improvements 🙌:
- Ensure users do not accidentally ignore other users (#1890) - Ensure users do not accidentally ignore other users (#1890)
- Support new config.json format and config.domain.json files (#1682) - Support new config.json format and config.domain.json files (#1682)
- Increase Font size on Calling screen (#1643) - Increase Font size on Calling screen (#1643)
- Make the user's Avatar live in the general settings
Bugfix 🐛: Bugfix 🐛:
- Fix incorrect date format for some Asian languages (#1928) - Fix incorrect date format for some Asian languages (#1928)

View File

@ -21,6 +21,7 @@ package org.matrix.android.sdk.internal.session.profile
import android.net.Uri import android.net.Uri
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import com.zhuinden.monarchy.Monarchy import com.zhuinden.monarchy.Monarchy
import io.realm.kotlin.where
import org.matrix.android.sdk.api.MatrixCallback import org.matrix.android.sdk.api.MatrixCallback
import org.matrix.android.sdk.api.session.identity.ThreePid import org.matrix.android.sdk.api.session.identity.ThreePid
import org.matrix.android.sdk.api.session.profile.ProfileService import org.matrix.android.sdk.api.session.profile.ProfileService
@ -34,7 +35,6 @@ import org.matrix.android.sdk.internal.task.TaskExecutor
import org.matrix.android.sdk.internal.task.configureWith import org.matrix.android.sdk.internal.task.configureWith
import org.matrix.android.sdk.internal.task.launchToCallback import org.matrix.android.sdk.internal.task.launchToCallback
import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers
import io.realm.kotlin.where
import javax.inject.Inject import javax.inject.Inject
internal class DefaultProfileService @Inject constructor(private val taskExecutor: TaskExecutor, internal class DefaultProfileService @Inject constructor(private val taskExecutor: TaskExecutor,
@ -75,11 +75,7 @@ internal class DefaultProfileService @Inject constructor(private val taskExecuto
override fun updateAvatar(userId: String, newAvatarUri: Uri, fileName: String, matrixCallback: MatrixCallback<Unit>): Cancelable { override fun updateAvatar(userId: String, newAvatarUri: Uri, fileName: String, matrixCallback: MatrixCallback<Unit>): Cancelable {
return taskExecutor.executorScope.launchToCallback(coroutineDispatchers.main, matrixCallback) { return taskExecutor.executorScope.launchToCallback(coroutineDispatchers.main, matrixCallback) {
val response = fileUploader.uploadFromUri(newAvatarUri, fileName, "image/jpeg") val response = fileUploader.uploadFromUri(newAvatarUri, fileName, "image/jpeg")
setAvatarUrlTask setAvatarUrlTask.execute(SetAvatarUrlTask.Params(userId = userId, newAvatarUrl = response.contentUri))
.configureWith(SetAvatarUrlTask.Params(userId = userId, newAvatarUrl = response.contentUri)) {
callback = matrixCallback
}
.executeBy(taskExecutor)
} }
} }

View File

@ -1,51 +0,0 @@
/*
* Copyright 2018 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.core.preference
import android.content.Context
import android.util.AttributeSet
import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.room.Room
/**
* Specialized class to target a Room avatar preference.
* Based don the avatar preference class it redefines refreshAvatar() and
* add the new method setConfiguration().
*/
class RoomAvatarPreference : UserAvatarPreference {
private var mRoom: Room? = null
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle)
override fun refreshAvatar() {
if (null != mAvatarView && null != mRoom) {
// TODO
// VectorUtils.loadRoomAvatar(context, session, mAvatarView, mRoom)
}
}
fun setConfiguration(aSession: Session, aRoom: Room) {
mSession = aSession
mRoom = aRoom
refreshAvatar()
}
}

View File

@ -25,14 +25,11 @@ import androidx.preference.PreferenceViewHolder
import im.vector.app.R import im.vector.app.R
import im.vector.app.core.extensions.vectorComponent import im.vector.app.core.extensions.vectorComponent
import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.home.AvatarRenderer
import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.user.model.User
import org.matrix.android.sdk.api.util.MatrixItem
import org.matrix.android.sdk.api.util.toMatrixItem import org.matrix.android.sdk.api.util.toMatrixItem
open class UserAvatarPreference : Preference { class UserAvatarPreference : Preference {
private var mAvatarView: ImageView? = null
internal var mAvatarView: ImageView? = null
internal var mSession: Session? = null
private var mLoadingProgressBar: ProgressBar? = null private var mLoadingProgressBar: ProgressBar? = null
private var avatarRenderer: AvatarRenderer = context.vectorComponent().avatarRenderer() private var avatarRenderer: AvatarRenderer = context.vectorComponent().avatarRenderer()
@ -51,24 +48,11 @@ open class UserAvatarPreference : Preference {
override fun onBindViewHolder(holder: PreferenceViewHolder) { override fun onBindViewHolder(holder: PreferenceViewHolder) {
super.onBindViewHolder(holder) super.onBindViewHolder(holder)
mAvatarView = holder.itemView.findViewById(R.id.settings_avatar) mAvatarView = holder.itemView.findViewById(R.id.settings_avatar)
mLoadingProgressBar = holder.itemView.findViewById(R.id.avatar_update_progress_bar) mLoadingProgressBar = holder.itemView.findViewById(R.id.avatar_update_progress_bar)
refreshAvatar()
} }
open fun refreshAvatar() { fun refreshAvatar(user: User) {
val session = mSession ?: return mAvatarView?.let { avatarRenderer.render(user.toMatrixItem(), it) }
val view = mAvatarView ?: return
session.getUser(session.myUserId)?.let {
avatarRenderer.render(it.toMatrixItem(), view)
} ?: run {
avatarRenderer.render(MatrixItem.UserItem(session.myUserId), view)
}
}
fun setSession(session: Session) {
mSession = session
refreshAvatar()
} }
} }

View File

@ -21,7 +21,6 @@ import android.os.Bundle
import android.view.View import android.view.View
import androidx.annotation.CallSuper import androidx.annotation.CallSuper
import androidx.preference.PreferenceFragmentCompat import androidx.preference.PreferenceFragmentCompat
import org.matrix.android.sdk.api.session.Session
import im.vector.app.R import im.vector.app.R
import im.vector.app.core.di.DaggerScreenComponent import im.vector.app.core.di.DaggerScreenComponent
import im.vector.app.core.di.HasScreenInjector import im.vector.app.core.di.HasScreenInjector
@ -29,6 +28,9 @@ import im.vector.app.core.di.ScreenComponent
import im.vector.app.core.error.ErrorFormatter import im.vector.app.core.error.ErrorFormatter
import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.core.platform.VectorBaseActivity
import im.vector.app.core.utils.toast import im.vector.app.core.utils.toast
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.disposables.Disposable
import org.matrix.android.sdk.api.session.Session
import timber.log.Timber import timber.log.Timber
abstract class VectorSettingsBaseFragment : PreferenceFragmentCompat(), HasScreenInjector { abstract class VectorSettingsBaseFragment : PreferenceFragmentCompat(), HasScreenInjector {
@ -74,10 +76,31 @@ abstract class VectorSettingsBaseFragment : PreferenceFragmentCompat(), HasScree
mLoadingView = vectorActivity.findViewById(R.id.vector_settings_spinner_views) mLoadingView = vectorActivity.findViewById(R.id.vector_settings_spinner_views)
} }
@CallSuper
override fun onDestroyView() {
super.onDestroyView()
uiDisposables.clear()
}
override fun onDestroy() {
uiDisposables.dispose()
super.onDestroy()
}
abstract fun bindPref() abstract fun bindPref()
abstract var titleRes: Int abstract var titleRes: Int
/* ==========================================================================================
* Disposable
* ========================================================================================== */
private val uiDisposables = CompositeDisposable()
protected fun Disposable.disposeOnDestroyView() {
uiDisposables.add(this)
}
/* ========================================================================================== /* ==========================================================================================
* Protected * Protected
* ========================================================================================== */ * ========================================================================================== */

View File

@ -21,6 +21,7 @@ package im.vector.app.features.settings
import android.app.Activity import android.app.Activity
import android.content.Intent import android.content.Intent
import android.net.Uri import android.net.Uri
import android.os.Bundle
import android.text.Editable import android.text.Editable
import android.util.Patterns import android.util.Patterns
import android.view.View import android.view.View
@ -40,13 +41,6 @@ import com.bumptech.glide.load.engine.cache.DiskCache
import com.google.android.material.textfield.TextInputEditText import com.google.android.material.textfield.TextInputEditText
import com.google.android.material.textfield.TextInputLayout import com.google.android.material.textfield.TextInputLayout
import com.yalantis.ucrop.UCrop import com.yalantis.ucrop.UCrop
import im.vector.lib.multipicker.MultiPicker
import im.vector.lib.multipicker.entity.MultiPickerImageType
import org.matrix.android.sdk.api.MatrixCallback
import org.matrix.android.sdk.api.NoOpMatrixCallback
import org.matrix.android.sdk.api.failure.isInvalidPassword
import org.matrix.android.sdk.api.session.integrationmanager.IntegrationManagerConfig
import org.matrix.android.sdk.api.session.integrationmanager.IntegrationManagerService
import im.vector.app.R import im.vector.app.R
import im.vector.app.core.extensions.hideKeyboard import im.vector.app.core.extensions.hideKeyboard
import im.vector.app.core.extensions.showPassword import im.vector.app.core.extensions.showPassword
@ -68,10 +62,20 @@ import im.vector.app.features.MainActivityArgs
import im.vector.app.features.media.createUCropWithDefaultSettings import im.vector.app.features.media.createUCropWithDefaultSettings
import im.vector.app.features.themes.ThemeUtils import im.vector.app.features.themes.ThemeUtils
import im.vector.app.features.workers.signout.SignOutUiWorker import im.vector.app.features.workers.signout.SignOutUiWorker
import im.vector.lib.multipicker.MultiPicker
import im.vector.lib.multipicker.entity.MultiPickerImageType
import io.reactivex.android.schedulers.AndroidSchedulers
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import org.matrix.android.sdk.api.MatrixCallback
import org.matrix.android.sdk.api.NoOpMatrixCallback
import org.matrix.android.sdk.api.failure.isInvalidPassword
import org.matrix.android.sdk.api.session.integrationmanager.IntegrationManagerConfig
import org.matrix.android.sdk.api.session.integrationmanager.IntegrationManagerService
import org.matrix.android.sdk.rx.rx
import org.matrix.android.sdk.rx.unwrap
import java.io.File import java.io.File
import java.util.UUID import java.util.UUID
@ -120,10 +124,25 @@ class VectorSettingsGeneralFragment : VectorSettingsBaseFragment() {
} }
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
observeUserAvatar()
}
private fun observeUserAvatar() {
session.rx()
.liveUser(session.myUserId)
.unwrap()
.distinctUntilChanged { user -> user.avatarUrl }
.observeOn(AndroidSchedulers.mainThread())
.subscribe { mUserAvatarPreference.refreshAvatar(it) }
.disposeOnDestroyView()
}
override fun bindPref() { override fun bindPref() {
// Avatar // Avatar
mUserAvatarPreference.let { mUserAvatarPreference.let {
it.setSession(session)
it.onPreferenceClickListener = Preference.OnPreferenceClickListener { it.onPreferenceClickListener = Preference.OnPreferenceClickListener {
onUpdateAvatarClick() onUpdateAvatarClick()
false false
@ -447,8 +466,6 @@ class VectorSettingsGeneralFragment : VectorSettingsBaseFragment() {
session.updateAvatar(session.myUserId, uri, getFilenameFromUri(context, uri) ?: UUID.randomUUID().toString(), object : MatrixCallback<Unit> { session.updateAvatar(session.myUserId, uri, getFilenameFromUri(context, uri) ?: UUID.randomUUID().toString(), object : MatrixCallback<Unit> {
override fun onSuccess(data: Unit) { override fun onSuccess(data: Unit) {
if (!isAdded) return if (!isAdded) return
mUserAvatarPreference.refreshAvatar()
onCommonDone(null) onCommonDone(null)
} }