Use cache for user color

This commit is contained in:
Benoit Marty 2020-09-22 17:05:25 +02:00
parent bd72c0ca8d
commit 7c063972ac
11 changed files with 102 additions and 101 deletions

View file

@ -7,6 +7,7 @@ Features ✨:
Improvements 🙌:
- Add "show password" in import Megolm keys dialog
- Visually disable call buttons in menu and prohibit calling when permissions are insufficient (#2112)
- Use cache for user color
Bugfix 🐛:
- Long message cannot be sent/takes infinite time & blocks other messages #1397

View file

@ -36,6 +36,7 @@ import im.vector.app.features.crypto.verification.IncomingVerificationRequestHan
import im.vector.app.features.grouplist.SelectedGroupDataSource
import im.vector.app.features.home.AvatarRenderer
import im.vector.app.features.home.HomeRoomListDataSource
import im.vector.app.features.home.room.detail.timeline.helper.MatrixItemColorProvider
import im.vector.app.features.html.EventHtmlRenderer
import im.vector.app.features.html.VectorHtmlCompressor
import im.vector.app.features.login.ReAuthHelper
@ -71,6 +72,8 @@ interface VectorComponent {
fun matrix(): Matrix
fun matrixItemColorProvider(): MatrixItemColorProvider
fun sessionListener(): SessionListener
fun currentSession(): Session

View file

@ -1,39 +0,0 @@
/*
* Copyright 2019 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.utils
import androidx.annotation.ColorRes
import im.vector.app.R
import kotlin.math.abs
@ColorRes
fun getColorFromUserId(userId: String?): Int {
var hash = 0
userId?.toList()?.map { chr -> hash = (hash shl 5) - hash + chr.toInt() }
return when (abs(hash) % 8) {
1 -> R.color.riotx_username_2
2 -> R.color.riotx_username_3
3 -> R.color.riotx_username_4
4 -> R.color.riotx_username_5
5 -> R.color.riotx_username_6
6 -> R.color.riotx_username_7
7 -> R.color.riotx_username_8
else -> R.color.riotx_username_1
}
}

View file

@ -16,13 +16,11 @@
package im.vector.app.features.home
import android.content.Context
import android.graphics.Bitmap
import android.graphics.drawable.Drawable
import android.widget.ImageView
import androidx.annotation.AnyThread
import androidx.annotation.UiThread
import androidx.core.content.ContextCompat
import androidx.core.graphics.drawable.toBitmap
import com.amulyakhare.textdrawable.TextDrawable
import com.bumptech.glide.request.RequestOptions
@ -33,7 +31,7 @@ import im.vector.app.core.di.ActiveSessionHolder
import im.vector.app.core.glide.GlideApp
import im.vector.app.core.glide.GlideRequest
import im.vector.app.core.glide.GlideRequests
import im.vector.app.core.utils.getColorFromUserId
import im.vector.app.features.home.room.detail.timeline.helper.MatrixItemColorProvider
import org.matrix.android.sdk.api.extensions.tryOrNull
import org.matrix.android.sdk.api.session.content.ContentUrlResolver
import org.matrix.android.sdk.api.util.MatrixItem
@ -43,7 +41,8 @@ import javax.inject.Inject
* This helper centralise ways to retrieve avatar into ImageView or even generic Target<Drawable>
*/
class AvatarRenderer @Inject constructor(private val activeSessionHolder: ActiveSessionHolder) {
class AvatarRenderer @Inject constructor(private val activeSessionHolder: ActiveSessionHolder,
private val matrixItemColorProvider: MatrixItemColorProvider) {
companion object {
private const val THUMBNAIL_SIZE = 250
@ -51,8 +50,7 @@ class AvatarRenderer @Inject constructor(private val activeSessionHolder: Active
@UiThread
fun render(matrixItem: MatrixItem, imageView: ImageView) {
render(imageView.context,
GlideApp.with(imageView),
render(GlideApp.with(imageView),
matrixItem,
DrawableImageViewTarget(imageView))
}
@ -64,8 +62,7 @@ class AvatarRenderer @Inject constructor(private val activeSessionHolder: Active
@UiThread
fun render(matrixItem: MatrixItem, imageView: ImageView, glideRequests: GlideRequests) {
render(imageView.context,
glideRequests,
render(glideRequests,
matrixItem,
DrawableImageViewTarget(imageView))
}
@ -79,7 +76,7 @@ class AvatarRenderer @Inject constructor(private val activeSessionHolder: Active
displayName = mappedContact.displayName
)
val placeholder = getPlaceholderDrawable(imageView.context, matrixItem)
val placeholder = getPlaceholderDrawable(matrixItem)
GlideApp.with(imageView)
.load(mappedContact.photoURI)
.apply(RequestOptions.circleCropTransform())
@ -88,11 +85,10 @@ class AvatarRenderer @Inject constructor(private val activeSessionHolder: Active
}
@UiThread
fun render(context: Context,
glideRequests: GlideRequests,
fun render(glideRequests: GlideRequests,
matrixItem: MatrixItem,
target: Target<Drawable>) {
val placeholder = getPlaceholderDrawable(context, matrixItem)
val placeholder = getPlaceholderDrawable(matrixItem)
buildGlideRequest(glideRequests, matrixItem.avatarUrl)
.placeholder(placeholder)
.into(target)
@ -100,7 +96,7 @@ class AvatarRenderer @Inject constructor(private val activeSessionHolder: Active
@AnyThread
@Throws
fun shortcutDrawable(context: Context, glideRequests: GlideRequests, matrixItem: MatrixItem, iconSize: Int): Bitmap {
fun shortcutDrawable(glideRequests: GlideRequests, matrixItem: MatrixItem, iconSize: Int): Bitmap {
return glideRequests
.asBitmap()
.apply {
@ -108,7 +104,7 @@ class AvatarRenderer @Inject constructor(private val activeSessionHolder: Active
if (resolvedUrl != null) {
load(resolvedUrl)
} else {
val avatarColor = avatarColor(matrixItem, context)
val avatarColor = matrixItemColorProvider.getColor(matrixItem)
load(TextDrawable.builder()
.beginConfig()
.bold()
@ -130,8 +126,8 @@ class AvatarRenderer @Inject constructor(private val activeSessionHolder: Active
}
@AnyThread
fun getPlaceholderDrawable(context: Context, matrixItem: MatrixItem): Drawable {
val avatarColor = avatarColor(matrixItem, context)
fun getPlaceholderDrawable(matrixItem: MatrixItem): Drawable {
val avatarColor = matrixItemColorProvider.getColor(matrixItem)
return TextDrawable.builder()
.beginConfig()
.bold()
@ -152,11 +148,4 @@ class AvatarRenderer @Inject constructor(private val activeSessionHolder: Active
return activeSessionHolder.getSafeActiveSession()?.contentUrlResolver()
?.resolveThumbnail(avatarUrl, THUMBNAIL_SIZE, THUMBNAIL_SIZE, ContentUrlResolver.ThumbnailMethod.SCALE)
}
private fun avatarColor(matrixItem: MatrixItem, context: Context): Int {
return when (matrixItem) {
is MatrixItem.UserItem -> ContextCompat.getColor(context, getColorFromUserId(matrixItem.id))
else -> ContextCompat.getColor(context, getColorFromRoomId(matrixItem.id))
}
}
}

View file

@ -1,29 +0,0 @@
/*
* Copyright 2019 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 androidx.annotation.ColorRes
import im.vector.app.R
@ColorRes
fun getColorFromRoomId(roomId: String?): Int {
return when ((roomId?.toList()?.sumBy { it.toInt() } ?: 0) % 3) {
1 -> R.color.riotx_avatar_fill_2
2 -> R.color.riotx_avatar_fill_3
else -> R.color.riotx_avatar_fill_1
}
}

View file

@ -70,7 +70,7 @@ class ShortcutsHandler @Inject constructor(
.map { room ->
val intent = RoomDetailActivity.shortcutIntent(context, room.roomId)
val bitmap = try {
avatarRenderer.shortcutDrawable(context, GlideApp.with(context), room.toMatrixItem(), iconSize)
avatarRenderer.shortcutDrawable(GlideApp.with(context), room.toMatrixItem(), iconSize)
} catch (failure: Throwable) {
null
}

View file

@ -97,7 +97,6 @@ import im.vector.app.core.utils.colorizeMatchingText
import im.vector.app.core.utils.copyToClipboard
import im.vector.app.core.utils.createJSonViewerStyleProvider
import im.vector.app.core.utils.createUIHandler
import im.vector.app.core.utils.getColorFromUserId
import im.vector.app.core.utils.isValidUrl
import im.vector.app.core.utils.onPermissionResultAudioIpCall
import im.vector.app.core.utils.onPermissionResultVideoIpCall
@ -127,6 +126,7 @@ import im.vector.app.features.home.room.detail.timeline.action.EventSharedAction
import im.vector.app.features.home.room.detail.timeline.action.MessageActionsBottomSheet
import im.vector.app.features.home.room.detail.timeline.action.MessageSharedActionViewModel
import im.vector.app.features.home.room.detail.timeline.edithistory.ViewEditHistoryBottomSheet
import im.vector.app.features.home.room.detail.timeline.helper.MatrixItemColorProvider
import im.vector.app.features.home.room.detail.timeline.item.AbsMessageItem
import im.vector.app.features.home.room.detail.timeline.item.MessageFileItem
import im.vector.app.features.home.room.detail.timeline.item.MessageImageVideoItem
@ -217,7 +217,9 @@ class RoomDetailFragment @Inject constructor(
private val vectorPreferences: VectorPreferences,
private val colorProvider: ColorProvider,
private val notificationUtils: NotificationUtils,
private val webRtcPeerConnectionManager: WebRtcPeerConnectionManager) :
private val webRtcPeerConnectionManager: WebRtcPeerConnectionManager,
private val matrixItemColorProvider: MatrixItemColorProvider
) :
VectorBaseFragment(),
TimelineEventController.Callback,
VectorInviteView.Callback,
@ -790,7 +792,7 @@ class RoomDetailFragment @Inject constructor(
// switch to expanded bar
composerLayout.composerRelatedMessageTitle.apply {
text = event.senderInfo.disambiguatedDisplayName
setTextColor(ContextCompat.getColor(requireContext(), getColorFromUserId(event.root.senderId)))
setTextColor(matrixItemColorProvider.getColor(MatrixItem.UserItem(event.root.senderId ?: "@")))
}
val messageContent: MessageContent? = event.getLastMessageContent()

View file

@ -19,18 +19,20 @@ package im.vector.app.features.home.room.detail.timeline
import androidx.annotation.ColorInt
import im.vector.app.R
import im.vector.app.core.resources.ColorProvider
import im.vector.app.core.utils.getColorFromUserId
import im.vector.app.features.home.room.detail.timeline.helper.MatrixItemColorProvider
import im.vector.app.features.settings.VectorPreferences
import org.matrix.android.sdk.api.session.room.send.SendState
import org.matrix.android.sdk.api.util.MatrixItem
import javax.inject.Inject
class MessageColorProvider @Inject constructor(
private val colorProvider: ColorProvider,
private val matrixItemColorProvider: MatrixItemColorProvider,
private val vectorPreferences: VectorPreferences) {
@ColorInt
fun getMemberNameTextColor(userId: String): Int {
return colorProvider.getColor(getColorFromUserId(userId))
fun getMemberNameTextColor(matrixItem: MatrixItem): Int {
return matrixItemColorProvider.getColor(matrixItem)
}
@ColorInt

View file

@ -0,0 +1,72 @@
/*
* 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.room.detail.timeline.helper
import androidx.annotation.ColorInt
import androidx.annotation.ColorRes
import im.vector.app.R
import im.vector.app.core.resources.ColorProvider
import org.matrix.android.sdk.api.util.MatrixItem
import javax.inject.Inject
import javax.inject.Singleton
import kotlin.math.abs
@Singleton
class MatrixItemColorProvider @Inject constructor(
private val colorProvider: ColorProvider
) {
private val cache = mutableMapOf<String, Int>()
@ColorInt
fun getColor(matrixItem: MatrixItem): Int {
return cache.getOrPut(matrixItem.id) {
colorProvider.getColor(
when (matrixItem) {
is MatrixItem.UserItem -> getColorFromUserId(matrixItem.id)
else -> getColorFromRoomId(matrixItem.id)
}
)
}
}
@ColorRes
private fun getColorFromUserId(userId: String?): Int {
var hash = 0
userId?.toList()?.map { chr -> hash = (hash shl 5) - hash + chr.toInt() }
return when (abs(hash) % 8) {
1 -> R.color.riotx_username_2
2 -> R.color.riotx_username_3
3 -> R.color.riotx_username_4
4 -> R.color.riotx_username_5
5 -> R.color.riotx_username_6
6 -> R.color.riotx_username_7
7 -> R.color.riotx_username_8
else -> R.color.riotx_username_1
}
}
@ColorRes
private fun getColorFromRoomId(roomId: String?): Int {
return when ((roomId?.toList()?.sumBy { it.toInt() } ?: 0) % 3) {
1 -> R.color.riotx_avatar_fill_2
2 -> R.color.riotx_avatar_fill_3
else -> R.color.riotx_avatar_fill_1
}
}
}

View file

@ -85,7 +85,7 @@ abstract class AbsMessageItem<H : AbsMessageItem.Holder> : AbsBaseMessageItem<H>
super.unbind(holder)
}
private fun Attributes.getMemberNameColor() = messageColorProvider.getMemberNameTextColor(informationData.senderId)
private fun Attributes.getMemberNameColor() = messageColorProvider.getMemberNameTextColor(informationData.matrixItem)
abstract class Holder(@IdRes stubId: Int) : AbsBaseMessageItem.Holder(stubId) {
val avatarImageView by bind<ImageView>(R.id.messageAvatarImageView)

View file

@ -53,7 +53,7 @@ class PillImageSpan(private val glideRequests: GlideRequests,
@UiThread
fun bind(textView: TextView) {
tv = WeakReference(textView)
avatarRenderer.render(context, glideRequests, matrixItem, target)
avatarRenderer.render(glideRequests, matrixItem, target)
}
// ReplacementSpan *****************************************************************************
@ -99,7 +99,7 @@ class PillImageSpan(private val glideRequests: GlideRequests,
val icon = try {
avatarRenderer.getCachedDrawable(glideRequests, matrixItem)
} catch (exception: Exception) {
avatarRenderer.getPlaceholderDrawable(context, matrixItem)
avatarRenderer.getPlaceholderDrawable(matrixItem)
}
return ChipDrawable.createFromResource(context, R.xml.pill_view).apply {