From b091f768dfe7bc7bcd30b0f73f90055102e92ba3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrien=20B=C3=A9raud?= <adrien.beraud@savoirfairelinux.com> Date: Thu, 29 Feb 2024 15:10:15 -0500 Subject: [PATCH] add AvatarView Change-Id: I89083884e74c1fccd2695e06e32128502c381fd3 --- .../main/java/cx/ring/utils/DeviceUtils.kt | 8 +- .../src/main/java/cx/ring/views/AvatarView.kt | 81 +++++++++++++++++++ .../app/src/main/res/values/attrs.xml | 8 ++ 3 files changed, 95 insertions(+), 2 deletions(-) create mode 100644 jami-android/app/src/main/java/cx/ring/views/AvatarView.kt diff --git a/jami-android/app/src/main/java/cx/ring/utils/DeviceUtils.kt b/jami-android/app/src/main/java/cx/ring/utils/DeviceUtils.kt index bd083dbc4..293fdab2c 100644 --- a/jami-android/app/src/main/java/cx/ring/utils/DeviceUtils.kt +++ b/jami-android/app/src/main/java/cx/ring/utils/DeviceUtils.kt @@ -27,8 +27,12 @@ import io.reactivex.rxjava3.schedulers.Schedulers object DeviceUtils { fun isTv(context: Context): Boolean = - context.getSystemService(UiModeManager::class.java) - .currentModeType == Configuration.UI_MODE_TYPE_TELEVISION + try { + context.getSystemService(UiModeManager::class.java) + .currentModeType == Configuration.UI_MODE_TYPE_TELEVISION + } catch (e: Throwable) { + false + } fun getStatusBarHeight(context: Context): Int { val resourceId = context.resources diff --git a/jami-android/app/src/main/java/cx/ring/views/AvatarView.kt b/jami-android/app/src/main/java/cx/ring/views/AvatarView.kt new file mode 100644 index 000000000..42c548700 --- /dev/null +++ b/jami-android/app/src/main/java/cx/ring/views/AvatarView.kt @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2004-2024 Savoir-faire Linux Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ +package cx.ring.views + +import android.content.Context +import android.graphics.Canvas +import android.util.AttributeSet +import android.view.View +import androidx.core.content.res.use +import cx.ring.R +import cx.ring.utils.BitmapUtils +import kotlin.math.min + +class AvatarView @JvmOverloads constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int = 0, defStyleRes: Int = 0) : + View(context, attrs, defStyleAttr, defStyleRes) { + + private var avatarDrawable: AvatarDrawable? = null + + init { + context.obtainStyledAttributes(attrs, R.styleable.AvatarView).use { typedArray -> + val uri = typedArray.getString(R.styleable.AvatarView_uri) + if (uri != null || isInEditMode) { + val username = typedArray.getString(R.styleable.AvatarView_username) + val displayName = typedArray.getString(R.styleable.AvatarView_displayName) + val avatar = typedArray.getDrawable(R.styleable.AvatarView_avatar) + val cropCircle = typedArray.getBoolean(R.styleable.AvatarView_cropCircle, true) + setAvatar(AvatarDrawable.Builder() + .withId(uri) + .withNameData(displayName, username) + .withPhoto(avatar?.let { BitmapUtils.drawableToBitmap(it) }) + .withCircleCrop(cropCircle) + .build(context)) + } + } + } + + /** Returns true if the avatar was set if it was previously empty. */ + fun setAvatar(avatar: AvatarDrawable?): Boolean { + val noPrevious = avatarDrawable == null + avatarDrawable = avatar + avatar?.setBounds(paddingLeft, paddingTop, width - paddingRight, height - paddingBottom) + invalidate() + return noPrevious + } + + override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { + val measuredWidth = MeasureSpec.getSize(widthMeasureSpec) + val measuredHeight = MeasureSpec.getSize(heightMeasureSpec) + val paddingW = paddingLeft + paddingRight + val paddingH = paddingTop + paddingBottom + val size = min(measuredWidth - paddingW, measuredHeight - paddingH) + setMeasuredDimension(size + paddingW, size + paddingH) + } + + override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { + avatarDrawable?.setBounds( + paddingLeft, + paddingTop, + w - paddingRight, + h - paddingBottom + ) + } + + override fun onDraw(canvas: Canvas) { + avatarDrawable?.draw(canvas) + } +} \ No newline at end of file diff --git a/jami-android/app/src/main/res/values/attrs.xml b/jami-android/app/src/main/res/values/attrs.xml index 8e026b936..9851c8dc9 100644 --- a/jami-android/app/src/main/res/values/attrs.xml +++ b/jami-android/app/src/main/res/values/attrs.xml @@ -11,6 +11,14 @@ <attr name="text" format="string" /> </declare-styleable> + <declare-styleable name="AvatarView"> + <attr name="uri" format="string" /> + <attr name="username" format="string" /> + <attr name="displayName" format="string" /> + <attr name="avatar" format="reference" /> + <attr name="cropCircle" format="boolean" /> + </declare-styleable> + <declare-styleable name="SwitchButton"> <attr name="backColor" format="color|reference"/> <attr name="status" format="string"/> -- GitLab