Pills : handle avatar

This commit is contained in:
ganfra 2019-02-27 17:17:47 +01:00
parent 63bf4355b9
commit adc51529f2
4 changed files with 46 additions and 44 deletions

View file

@ -60,6 +60,7 @@ dependencies {
def epoxy_version = "3.0.0" def epoxy_version = "3.0.0"
def arrow_version = "0.8.2" def arrow_version = "0.8.2"
def coroutines_version = "1.0.1"
def markwon_version = '3.0.0-SNAPSHOT' def markwon_version = '3.0.0-SNAPSHOT'
implementation project(":matrix-sdk-android") implementation project(":matrix-sdk-android")
@ -67,6 +68,8 @@ dependencies {
implementation 'com.android.support:multidex:1.0.3' implementation 'com.android.support:multidex:1.0.3'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version"
implementation 'androidx.appcompat:appcompat:1.1.0-alpha01' implementation 'androidx.appcompat:appcompat:1.1.0-alpha01'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3' implementation 'androidx.constraintlayout:constraintlayout:1.1.3'

View file

@ -22,8 +22,6 @@ import android.widget.ImageView
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import com.amulyakhare.textdrawable.TextDrawable import com.amulyakhare.textdrawable.TextDrawable
import com.bumptech.glide.request.RequestOptions import com.bumptech.glide.request.RequestOptions
import com.bumptech.glide.request.target.SimpleTarget
import com.bumptech.glide.request.transition.Transition
import im.vector.matrix.android.api.Matrix import im.vector.matrix.android.api.Matrix
import im.vector.matrix.android.api.MatrixPatterns import im.vector.matrix.android.api.MatrixPatterns
import im.vector.matrix.android.api.session.room.model.RoomMember import im.vector.matrix.android.api.session.room.model.RoomMember
@ -31,6 +29,8 @@ import im.vector.matrix.android.api.session.room.model.RoomSummary
import im.vector.riotredesign.R import im.vector.riotredesign.R
import im.vector.riotredesign.core.glide.GlideApp import im.vector.riotredesign.core.glide.GlideApp
import im.vector.riotredesign.core.glide.GlideRequest import im.vector.riotredesign.core.glide.GlideRequest
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
object AvatarRenderer { object AvatarRenderer {
@ -46,53 +46,47 @@ object AvatarRenderer {
if (name.isNullOrEmpty()) { if (name.isNullOrEmpty()) {
return return
} }
buildGlideRequest(imageView.context, name, avatarUrl).into(imageView) val placeholder = buildPlaceholderDrawable(imageView.context, name)
buildGlideRequest(imageView.context, avatarUrl)
.placeholder(placeholder)
.into(imageView)
} }
fun load(context: Context, avatarUrl: String?, name: String?, callback: Callback) { fun load(context: Context, avatarUrl: String?, name: String?, size: Int, callback: Callback) {
if (name.isNullOrEmpty()) { if (name.isNullOrEmpty()) {
return return
} }
buildGlideRequest(context, name, avatarUrl).into(CallbackTarget(callback)) val request = buildGlideRequest(context, avatarUrl)
GlobalScope.launch {
val placeholder = buildPlaceholderDrawable(context, name)
callback.onDrawableUpdated(placeholder)
try {
val drawable = request.submit(size, size).get()
callback.onDrawableUpdated(drawable)
} catch (exception: Exception) {
callback.onDrawableUpdated(placeholder)
}
}
} }
private fun buildGlideRequest(context: Context, name: String, avatarUrl: String?): GlideRequest<Drawable> { private fun buildGlideRequest(context: Context, avatarUrl: String?): GlideRequest<Drawable> {
val resolvedUrl = Matrix.getInstance().currentSession.contentUrlResolver().resolveFullSize(avatarUrl) val resolvedUrl = Matrix.getInstance().currentSession.contentUrlResolver().resolveFullSize(avatarUrl)
return GlideApp
.with(context)
.load(resolvedUrl)
.apply(RequestOptions.circleCropTransform())
}
private fun buildPlaceholderDrawable(context: Context, name: String): Drawable {
val avatarColor = ContextCompat.getColor(context, R.color.pale_teal) val avatarColor = ContextCompat.getColor(context, R.color.pale_teal)
val isNameUserId = MatrixPatterns.isUserId(name) val isNameUserId = MatrixPatterns.isUserId(name)
val firstLetterIndex = if (isNameUserId) 1 else 0 val firstLetterIndex = if (isNameUserId) 1 else 0
val firstLetter = name[firstLetterIndex].toString().toUpperCase() val firstLetter = name[firstLetterIndex].toString().toUpperCase()
val fallbackDrawable = TextDrawable.builder().buildRound(firstLetter, avatarColor) return TextDrawable.builder().buildRound(firstLetter, avatarColor)
return GlideApp
.with(context)
.load(resolvedUrl)
.placeholder(fallbackDrawable)
.apply(RequestOptions.circleCropTransform())
} }
interface Callback { interface Callback {
fun onDrawableUpdated(drawable: Drawable?) fun onDrawableUpdated(drawable: Drawable?)
fun onDestroy()
} }
private class CallbackTarget(private val callback: Callback) : SimpleTarget<Drawable>() {
override fun onDestroy() {
callback.onDestroy()
}
override fun onResourceReady(resource: Drawable, transition: Transition<in Drawable>?) {
callback.onDrawableUpdated(resource)
}
override fun onLoadStarted(placeholder: Drawable?) {
callback.onDrawableUpdated(placeholder)
}
override fun onLoadFailed(errorDrawable: Drawable?) {
callback.onDrawableUpdated(errorDrawable)
}
}
} }

View file

@ -27,15 +27,18 @@ import java.lang.ref.WeakReference
object PillDrawableFactory { object PillDrawableFactory {
fun create(context: Context, userId: String, user: User?): Drawable { fun create(context: Context, userId: String, user: User?): Drawable {
val textPadding = context.resources.getDimension(R.dimen.pill_text_padding)
val chipDrawable = ChipDrawable.createFromResource(context, R.xml.pill_view).apply { val chipDrawable = ChipDrawable.createFromResource(context, R.xml.pill_view).apply {
setText(user?.displayName ?: userId) setText(user?.displayName ?: userId)
textEndPadding = 8f textEndPadding = textPadding
textStartPadding = 8f textStartPadding = textPadding
setBounds(0, 0, intrinsicWidth, (intrinsicHeight / 1.5f).toInt()) setChipMinHeightResource(R.dimen.pill_min_height)
setChipIconSizeResource(R.dimen.pill_avatar_size)
setBounds(0, 0, intrinsicWidth, intrinsicHeight)
} }
val avatarRendererCallback = AvatarRendererChipCallback(chipDrawable) val avatarRendererCallback = AvatarRendererChipCallback(chipDrawable)
// TODO: need to work on getting drawable async AvatarRenderer.load(context, user?.avatarUrl, user?.displayName, 80, avatarRendererCallback)
//AvatarRenderer.load(context, user?.avatarUrl, user?.displayName, avatarRendererCallback)
return chipDrawable return chipDrawable
} }
@ -43,19 +46,14 @@ object PillDrawableFactory {
private val weakChipDrawable = WeakReference<ChipDrawable>(chipDrawable) private val weakChipDrawable = WeakReference<ChipDrawable>(chipDrawable)
override fun onDestroy() {
weakChipDrawable.clear()
}
override fun onDrawableUpdated(drawable: Drawable?) { override fun onDrawableUpdated(drawable: Drawable?) {
weakChipDrawable.get()?.apply { weakChipDrawable.get()?.apply {
chipIcon = drawable chipIcon = drawable
setBounds(0, 0, intrinsicWidth, (intrinsicHeight / 1.5f).toInt()) setBounds(0, 0, intrinsicWidth, intrinsicHeight)
} }
} }
} }
} }

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="pill_avatar_size">16dp</dimen>
<dimen name="pill_min_height">20dp</dimen>
<dimen name="pill_text_padding">4dp</dimen>
</resources>