srctree

Roee Hershberg parent 3073f386 b91fdfff
Add custom avatar image view

Co-authored-by: Robin Lindén <dev@robinlinden.eu>

inlinesplit
filename was Deleted added: 88, removed: 2, total 86
@@ -0,0 +1,80 @@
package ltd.evilcorp.atox.ui
 
import android.content.Context
import android.graphics.Canvas
import android.graphics.Paint
import android.net.Uri
import android.util.AttributeSet
import androidx.core.content.res.use
import androidx.core.view.doOnPreDraw
import com.google.android.material.imageview.ShapeableImageView
import kotlin.math.min
import kotlin.math.pow
import kotlin.math.sqrt
import ltd.evilcorp.atox.R
import ltd.evilcorp.core.vo.Contact
import ltd.evilcorp.core.vo.UserStatus
 
private const val STATUS_INDICATOR_SIZE_RATIO_WITH_AVATAR = 12f / 50
 
class AvatarImageView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) :
ShapeableImageView(context, attrs, defStyleAttr) {
 
private val statusIndicatorPaint = Paint().apply {
isAntiAlias = true
style = Paint.Style.FILL
color = colorFromStatus(context, UserStatus.None)
}
 
private val statusIndicatorVisible: Boolean = context.theme.obtainStyledAttributes(
attrs,
R.styleable.AvatarImageView,
0, 0
).use { it.getBoolean(R.styleable.AvatarImageView_statusIndicatorVisible, true) }
 
private var name = ""
private var publicKey = ""
private var avatarUri = ""
 
fun setFrom(contact: Contact) {
statusIndicatorPaint.color = colorByContactStatus(context, contact)
// Assigning to the object's properties as capturing those values in the doOnPreDraw's lambda
// either directly or using temporary `val` objects decreases performance of scrolling SIGNIFICANTLY.
name = contact.name
publicKey = contact.publicKey
avatarUri = contact.avatarUri
 
doOnPreDraw {
if (avatarUri.isNotEmpty()) {
setImageURI(Uri.parse(avatarUri))
} else {
setImageBitmap(AvatarFactory.create(resources, name, publicKey, Px(min(width, height))))
}
}
invalidate()
}
 
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
if (canvas == null || !statusIndicatorVisible) return
 
val size = min(width, height).toFloat()
 
// Calculating status indicator size and margin in relation to the overall size
val avatarImageRadius = size / 2
val avatarImageDiagonal = sqrt(size.pow(2) + size.pow(2)) // Pythagorean theorem
val avatarImageDistanceFromCorner = avatarImageDiagonal / 2 - avatarImageRadius
val statusIndicatorSize = size * STATUS_INDICATOR_SIZE_RATIO_WITH_AVATAR
val statusIndicatorDiagonal =
sqrt(statusIndicatorSize.pow(2) + statusIndicatorSize.pow(2)) // Pythagorean theorem
val statusIndicatorMarginDiagonal = avatarImageDistanceFromCorner - statusIndicatorDiagonal / 2
val statusIndicatorMargin =
sqrt(statusIndicatorMarginDiagonal.pow(2) / 2).toInt() // Pythagorean theorem
 
val radius = statusIndicatorSize / 2
val x = width - (width - size) / 2 - statusIndicatorMargin - radius
val y = height - (height - size) / 2 - statusIndicatorMargin - radius
 
canvas.drawCircle(x, y, radius, statusIndicatorPaint)
}
}
 
filename was Deleted added: 88, removed: 2, total 86
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="AvatarImageView">
<attr name="statusIndicatorVisible" format="boolean" />
</declare-styleable>
</resources>