mirror of
https://github.com/nextcloud/talk-android
synced 2025-08-06 03:25:07 +01:00
fix: improves ConversationModel equals and hashCode to only contain fields important to the visual representation in the adapter
Signed-off-by: David Leibovych <ariedov@gmail.com>
This commit is contained in:
parent
1a4c4bed75
commit
c8aa4ddde4
@ -11,9 +11,18 @@
|
||||
package com.nextcloud.talk.extensions
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.BitmapShader
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Color
|
||||
import android.graphics.ColorFilter
|
||||
import android.graphics.Matrix
|
||||
import android.graphics.Paint
|
||||
import android.graphics.PixelFormat
|
||||
import android.graphics.Rect
|
||||
import android.graphics.RectF
|
||||
import android.graphics.Shader
|
||||
import android.graphics.drawable.BitmapDrawable
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.graphics.drawable.LayerDrawable
|
||||
import android.util.Log
|
||||
@ -21,6 +30,7 @@ import android.widget.ImageView
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.content.res.ResourcesCompat
|
||||
import androidx.core.graphics.createBitmap
|
||||
import androidx.core.graphics.drawable.toBitmap
|
||||
import androidx.core.graphics.drawable.toDrawable
|
||||
import coil.annotation.ExperimentalCoilApi
|
||||
import coil.imageLoader
|
||||
@ -42,6 +52,7 @@ import com.nextcloud.talk.utils.ApiUtils
|
||||
import com.nextcloud.talk.utils.DisplayUtils
|
||||
import com.nextcloud.talk.utils.TextDrawable
|
||||
import java.util.Locale
|
||||
import kotlin.math.min
|
||||
|
||||
private const val ROUNDING_PIXEL = 16f
|
||||
private const val TAG = "ImageViewExtensions"
|
||||
@ -291,18 +302,12 @@ fun ImageView.loadSystemAvatar(): io.reactivex.disposables.Disposable {
|
||||
)
|
||||
}
|
||||
|
||||
fun ImageView.loadNoteToSelfAvatar(): io.reactivex.disposables.Disposable {
|
||||
fun ImageView.loadNoteToSelfAvatar() {
|
||||
val layers = arrayOfNulls<Drawable>(2)
|
||||
layers[0] = ContextCompat.getDrawable(context, R.drawable.ic_launcher_background)
|
||||
layers[1] = ContextCompat.getDrawable(context, R.drawable.ic_note_to_self)
|
||||
val layerDrawable = LayerDrawable(layers)
|
||||
val data: Any = layerDrawable
|
||||
|
||||
return DisposableWrapper(
|
||||
load(data) {
|
||||
transformations(CircleCropTransformation())
|
||||
}
|
||||
)
|
||||
setImageDrawable(CircularDrawable(layerDrawable))
|
||||
}
|
||||
|
||||
fun ImageView.loadFirstLetterAvatar(name: String): io.reactivex.disposables.Disposable {
|
||||
@ -416,3 +421,76 @@ private class DisposableWrapper(private val disposable: coil.request.Disposable)
|
||||
|
||||
override fun isDisposed(): Boolean = disposable.isDisposed
|
||||
}
|
||||
|
||||
private class CircularDrawable(private val sourceDrawable: Drawable) : Drawable() {
|
||||
|
||||
private val bitmap: Bitmap = drawableToBitmap(sourceDrawable)
|
||||
private val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
|
||||
shader = BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)
|
||||
}
|
||||
|
||||
private val rect = RectF()
|
||||
private var radius = 0f
|
||||
|
||||
override fun onBoundsChange(bounds: Rect) {
|
||||
super.onBoundsChange(bounds)
|
||||
rect.set(bounds)
|
||||
|
||||
radius = min(rect.width() / 2.0f, rect.height() / 2.0f)
|
||||
|
||||
val matrix = Matrix()
|
||||
val scale: Float
|
||||
var dx = 0f
|
||||
var dy = 0f
|
||||
|
||||
if (bitmap.width * rect.height() > rect.width() * bitmap.height) {
|
||||
// Taller than wide, scale to height and center horizontally
|
||||
scale = rect.height() / bitmap.height.toFloat()
|
||||
dx = (rect.width() - bitmap.width * scale) * 0.5f
|
||||
} else {
|
||||
// Wider than tall, scale to width and center vertically
|
||||
scale = rect.width() / bitmap.width.toFloat()
|
||||
dy = (rect.height() - bitmap.height * scale) * 0.5f
|
||||
}
|
||||
|
||||
matrix.setScale(scale, scale)
|
||||
matrix.postTranslate(dx.toInt().toFloat() + rect.left, dy.toInt().toFloat() + rect.top)
|
||||
paint.shader.setLocalMatrix(matrix)
|
||||
}
|
||||
|
||||
override fun draw(canvas: Canvas) {
|
||||
canvas.drawCircle(rect.centerX(), rect.centerY(), radius, paint)
|
||||
}
|
||||
|
||||
override fun setAlpha(alpha: Int) {
|
||||
paint.alpha = alpha
|
||||
}
|
||||
|
||||
override fun setColorFilter(colorFilter: ColorFilter?) {
|
||||
paint.colorFilter = colorFilter
|
||||
}
|
||||
|
||||
@Deprecated("This method is no longer used in graphics optimizations",
|
||||
ReplaceWith("PixelFormat.TRANSLUCENT", "android.graphics.PixelFormat")
|
||||
)
|
||||
override fun getOpacity(): Int = PixelFormat.TRANSLUCENT
|
||||
|
||||
override fun getIntrinsicWidth(): Int = sourceDrawable.intrinsicWidth
|
||||
|
||||
override fun getIntrinsicHeight(): Int = sourceDrawable.intrinsicHeight
|
||||
|
||||
companion object {
|
||||
|
||||
private fun drawableToBitmap(drawable: Drawable): Bitmap {
|
||||
if (drawable is BitmapDrawable) {
|
||||
if (drawable.bitmap != null) {
|
||||
return drawable.bitmap
|
||||
}
|
||||
}
|
||||
|
||||
val width = if (drawable.intrinsicWidth > 0) drawable.intrinsicWidth else 1
|
||||
val height = if (drawable.intrinsicHeight > 0) drawable.intrinsicHeight else 1
|
||||
return drawable.toBitmap(width, height, Bitmap.Config.ARGB_8888)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -134,4 +134,108 @@ class ConversationModel(
|
||||
hasImportant = conversation.hasImportant
|
||||
)
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
other as ConversationModel
|
||||
|
||||
if (hasPassword != other.hasPassword) return false
|
||||
if (favorite != other.favorite) return false
|
||||
if (lastActivity != other.lastActivity) return false
|
||||
if (unreadMessages != other.unreadMessages) return false
|
||||
if (unreadMention != other.unreadMention) return false
|
||||
if (lobbyTimer != other.lobbyTimer) return false
|
||||
if (lastReadMessage != other.lastReadMessage) return false
|
||||
if (lastCommonReadMessage != other.lastCommonReadMessage) return false
|
||||
if (hasCall != other.hasCall) return false
|
||||
if (callFlag != other.callFlag) return false
|
||||
if (canStartCall != other.canStartCall) return false
|
||||
if (canLeaveConversation != other.canLeaveConversation) return false
|
||||
if (canDeleteConversation != other.canDeleteConversation) return false
|
||||
if (unreadMentionDirect != other.unreadMentionDirect) return false
|
||||
if (notificationCalls != other.notificationCalls) return false
|
||||
if (permissions != other.permissions) return false
|
||||
if (messageExpiration != other.messageExpiration) return false
|
||||
if (statusClearAt != other.statusClearAt) return false
|
||||
if (callRecording != other.callRecording) return false
|
||||
if (hasCustomAvatar != other.hasCustomAvatar) return false
|
||||
if (callStartTime != other.callStartTime) return false
|
||||
if (recordingConsentRequired != other.recordingConsentRequired) return false
|
||||
if (hasArchived != other.hasArchived) return false
|
||||
if (hasSensitive != other.hasSensitive) return false
|
||||
if (hasImportant != other.hasImportant) return false
|
||||
if (internalId != other.internalId) return false
|
||||
if (name != other.name) return false
|
||||
if (displayName != other.displayName) return false
|
||||
if (description != other.description) return false
|
||||
if (type != other.type) return false
|
||||
if (participantType != other.participantType) return false
|
||||
if (lastMessage != other.lastMessage) return false
|
||||
if (objectType != other.objectType) return false
|
||||
if (objectId != other.objectId) return false
|
||||
if (notificationLevel != other.notificationLevel) return false
|
||||
if (conversationReadOnlyState != other.conversationReadOnlyState) return false
|
||||
if (lobbyState != other.lobbyState) return false
|
||||
if (status != other.status) return false
|
||||
if (statusIcon != other.statusIcon) return false
|
||||
if (statusMessage != other.statusMessage) return false
|
||||
if (avatarVersion != other.avatarVersion) return false
|
||||
if (remoteServer != other.remoteServer) return false
|
||||
if (remoteToken != other.remoteToken) return false
|
||||
if (password != other.password) return false
|
||||
if (messageDraft != other.messageDraft) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = hasPassword.hashCode()
|
||||
result = 31 * result + favorite.hashCode()
|
||||
result = 31 * result + lastActivity.hashCode()
|
||||
result = 31 * result + unreadMessages
|
||||
result = 31 * result + unreadMention.hashCode()
|
||||
result = 31 * result + lobbyTimer.hashCode()
|
||||
result = 31 * result + lastReadMessage
|
||||
result = 31 * result + lastCommonReadMessage
|
||||
result = 31 * result + hasCall.hashCode()
|
||||
result = 31 * result + callFlag
|
||||
result = 31 * result + canStartCall.hashCode()
|
||||
result = 31 * result + canLeaveConversation.hashCode()
|
||||
result = 31 * result + canDeleteConversation.hashCode()
|
||||
result = 31 * result + unreadMentionDirect.hashCode()
|
||||
result = 31 * result + notificationCalls
|
||||
result = 31 * result + permissions
|
||||
result = 31 * result + messageExpiration
|
||||
result = 31 * result + (statusClearAt?.hashCode() ?: 0)
|
||||
result = 31 * result + callRecording
|
||||
result = 31 * result + hasCustomAvatar.hashCode()
|
||||
result = 31 * result + callStartTime.hashCode()
|
||||
result = 31 * result + recordingConsentRequired
|
||||
result = 31 * result + hasArchived.hashCode()
|
||||
result = 31 * result + hasSensitive.hashCode()
|
||||
result = 31 * result + hasImportant.hashCode()
|
||||
result = 31 * result + internalId.hashCode()
|
||||
result = 31 * result + name.hashCode()
|
||||
result = 31 * result + displayName.hashCode()
|
||||
result = 31 * result + description.hashCode()
|
||||
result = 31 * result + type.hashCode()
|
||||
result = 31 * result + participantType.hashCode()
|
||||
result = 31 * result + (lastMessage?.hashCode() ?: 0)
|
||||
result = 31 * result + objectType.hashCode()
|
||||
result = 31 * result + objectId.hashCode()
|
||||
result = 31 * result + notificationLevel.hashCode()
|
||||
result = 31 * result + conversationReadOnlyState.hashCode()
|
||||
result = 31 * result + lobbyState.hashCode()
|
||||
result = 31 * result + (status?.hashCode() ?: 0)
|
||||
result = 31 * result + (statusIcon?.hashCode() ?: 0)
|
||||
result = 31 * result + (statusMessage?.hashCode() ?: 0)
|
||||
result = 31 * result + avatarVersion.hashCode()
|
||||
result = 31 * result + (remoteServer?.hashCode() ?: 0)
|
||||
result = 31 * result + (remoteToken?.hashCode() ?: 0)
|
||||
result = 31 * result + (password?.hashCode() ?: 0)
|
||||
result = 31 * result + (messageDraft?.hashCode() ?: 0)
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user