From e4a3ec37c5606bf2b50805ad7195bae8f1c5626a Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Sat, 14 Oct 2023 14:36:22 +0200 Subject: [PATCH] Started removing AvatarView dependency --- .../linphone/contacts/AbstractAvatarModel.kt | 14 ++ .../org/linphone/contacts/AvatarGenerator.kt | 107 ++++++++++++++ .../ui/call/fragment/ActiveCallFragment.kt | 5 +- .../chat/adapter/ConversationsListAdapter.kt | 2 +- .../ui/main/chat/model/ConversationModel.kt | 6 +- .../chat/viewmodel/ConversationViewModel.kt | 5 +- .../viewmodel/StartConversationViewModel.kt | 5 +- .../main/contacts/model/ContactAvatarModel.kt | 15 +- .../ContactsAndSuggestionsListAdapter.kt | 2 +- .../history/model/ContactOrSuggestionModel.kt | 3 +- .../history/viewmodel/StartCallViewModel.kt | 5 +- .../linphone/ui/main/model/AccountModel.kt | 14 +- .../viewmodel/AccountProfileViewModel.kt | 2 +- .../org/linphone/utils/DataBindingUtils.kt | 134 +++++++++++++++--- app/src/main/res/layout/account_list_cell.xml | 11 +- .../res/layout/account_profile_fragment.xml | 18 +-- .../main/res/layout/call_active_fragment.xml | 12 +- .../main/res/layout/call_ended_fragment.xml | 11 +- .../res/layout/call_incoming_fragment.xml | 11 +- app/src/main/res/layout/call_list_cell.xml | 11 +- .../res/layout/call_outgoing_fragment.xml | 11 +- .../main/res/layout/chat_bubble_incoming.xml | 2 +- .../res/layout/chat_conversation_fragment.xml | 11 +- app/src/main/res/layout/chat_list_cell.xml | 11 +- .../layout/contact_favourite_list_cell.xml | 11 +- app/src/main/res/layout/contact_fragment.xml | 11 +- app/src/main/res/layout/contact_list_cell.xml | 11 +- .../res/layout/history_contact_fragment.xml | 11 +- app/src/main/res/layout/history_list_cell.xml | 11 +- .../layout/meeting_participant_list_cell.xml | 11 +- app/src/main/res/layout/top_bar.xml | 11 +- app/src/main/res/values/dimen.xml | 5 + 32 files changed, 307 insertions(+), 203 deletions(-) create mode 100644 app/src/main/java/org/linphone/contacts/AbstractAvatarModel.kt create mode 100644 app/src/main/java/org/linphone/contacts/AvatarGenerator.kt diff --git a/app/src/main/java/org/linphone/contacts/AbstractAvatarModel.kt b/app/src/main/java/org/linphone/contacts/AbstractAvatarModel.kt new file mode 100644 index 000000000..913f239c1 --- /dev/null +++ b/app/src/main/java/org/linphone/contacts/AbstractAvatarModel.kt @@ -0,0 +1,14 @@ +package org.linphone.contacts + +import androidx.lifecycle.MutableLiveData +import org.linphone.core.ChatRoom + +abstract class AbstractAvatarModel { + val trust = MutableLiveData() + + val showTrust = MutableLiveData() + + val initials = MutableLiveData() + + val images = MutableLiveData>() +} diff --git a/app/src/main/java/org/linphone/contacts/AvatarGenerator.kt b/app/src/main/java/org/linphone/contacts/AvatarGenerator.kt new file mode 100644 index 000000000..f41c012ab --- /dev/null +++ b/app/src/main/java/org/linphone/contacts/AvatarGenerator.kt @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2010-2022 Belledonne Communications SARL. + * + * This file is part of linphone-android + * (see https://www.linphone.org). + * + * 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 . + */ +package org.linphone.contacts + +import android.content.Context +import android.graphics.* +import android.graphics.drawable.BitmapDrawable +import android.text.TextPaint +import android.util.TypedValue +import androidx.core.content.ContextCompat +import androidx.core.content.res.ResourcesCompat +import org.linphone.R +import org.linphone.utils.AppUtils + +class AvatarGenerator(private val context: Context) { + private var textSize: Float + private var textColor: Int + private var avatarSize: Int + private var initials = " " + private var backgroundColor: Int + + init { + backgroundColor = ContextCompat.getColor(context, R.color.gray_main2_200) + + textColor = ContextCompat.getColor(context, R.color.gray_main2_600) + + textSize = AppUtils.getDimension(R.dimen.avatar_initials_text_size) + + avatarSize = AppUtils.getDimension(R.dimen.avatar_list_cell_size).toInt() + } + + fun setTextSize(size: Float) = apply { + textSize = size + } + + fun setTextColorResource(resource: Int) = apply { + textColor = ContextCompat.getColor(context, resource) + } + + fun setAvatarSize(size: Int) = apply { + avatarSize = size + } + + fun setInitials(label: String) = apply { + initials = label + } + + fun setBackgroundColorAttribute(attribute: Int) = apply { + val theme = context.theme + val backgroundColorTypedValue = TypedValue() + theme.resolveAttribute(attribute, backgroundColorTypedValue, true) + backgroundColor = ContextCompat.getColor(context, backgroundColorTypedValue.resourceId) + } + + fun build(): BitmapDrawable { + val textPainter = getTextPainter() + val painter = getPainter() + + val bitmap = Bitmap.createBitmap(avatarSize, avatarSize, Bitmap.Config.ARGB_8888) + val canvas = Canvas(bitmap) + val areaRect = Rect(0, 0, avatarSize, avatarSize) + val bounds = RectF(areaRect) + bounds.right = textPainter.measureText(initials, 0, initials.length) + bounds.bottom = textPainter.descent() - textPainter.ascent() + bounds.left += (areaRect.width() - bounds.right) / 2.0f + bounds.top += (areaRect.height() - bounds.bottom) / 2.0f + + val halfSize = (avatarSize / 2).toFloat() + canvas.drawCircle(halfSize, halfSize, halfSize, painter) + canvas.drawText(initials, bounds.left, bounds.top - textPainter.ascent(), textPainter) + + return BitmapDrawable(context.resources, bitmap) + } + + private fun getTextPainter(): TextPaint { + val textPainter = TextPaint() + textPainter.isAntiAlias = true + textPainter.textSize = textSize + textPainter.color = textColor + textPainter.typeface = ResourcesCompat.getFont(context, R.font.noto_sans_800) + return textPainter + } + + private fun getPainter(): Paint { + val painter = Paint() + painter.isAntiAlias = true + painter.color = backgroundColor + return painter + } +} diff --git a/app/src/main/java/org/linphone/ui/call/fragment/ActiveCallFragment.kt b/app/src/main/java/org/linphone/ui/call/fragment/ActiveCallFragment.kt index a9e9074e4..928a31d69 100644 --- a/app/src/main/java/org/linphone/ui/call/fragment/ActiveCallFragment.kt +++ b/app/src/main/java/org/linphone/ui/call/fragment/ActiveCallFragment.kt @@ -44,7 +44,6 @@ import org.linphone.ui.call.model.ZrtpSasConfirmationDialogModel import org.linphone.ui.call.viewmodel.CallsViewModel import org.linphone.ui.call.viewmodel.CurrentCallViewModel import org.linphone.ui.call.viewmodel.SharedCallViewModel -import org.linphone.utils.AppUtils import org.linphone.utils.DialogUtils import org.linphone.utils.Event import org.linphone.utils.addCharacterAtPosition @@ -167,9 +166,9 @@ class ActiveCallFragment : GenericCallFragment() { R.drawable.trusted, doNotTint = true ) - binding.avatar.avatarBorderWidth = AppUtils.getDimension( + /*binding.avatar.avatarBorderWidth = AppUtils.getDimension( R.dimen.avatar_trust_border_width - ).toInt() + ).toInt()*/ // TODO FIXME: show blue border } } diff --git a/app/src/main/java/org/linphone/ui/main/chat/adapter/ConversationsListAdapter.kt b/app/src/main/java/org/linphone/ui/main/chat/adapter/ConversationsListAdapter.kt index edd4dc87e..031a9bbc2 100644 --- a/app/src/main/java/org/linphone/ui/main/chat/adapter/ConversationsListAdapter.kt +++ b/app/src/main/java/org/linphone/ui/main/chat/adapter/ConversationsListAdapter.kt @@ -80,7 +80,7 @@ class ConversationsListAdapter( } override fun areContentsTheSame(oldItem: ConversationModel, newItem: ConversationModel): Boolean { - return oldItem.avatarModel.id == newItem.avatarModel.id + return oldItem.avatarModel.value?.id == newItem.avatarModel.value?.id } } } diff --git a/app/src/main/java/org/linphone/ui/main/chat/model/ConversationModel.kt b/app/src/main/java/org/linphone/ui/main/chat/model/ConversationModel.kt index 821034c25..4a9df93f5 100644 --- a/app/src/main/java/org/linphone/ui/main/chat/model/ConversationModel.kt +++ b/app/src/main/java/org/linphone/ui/main/chat/model/ConversationModel.kt @@ -76,7 +76,7 @@ class ConversationModel @WorkerThread constructor(private val chatRoom: ChatRoom val unreadMessageCount = MutableLiveData() - val avatarModel: ContactAvatarModel + val avatarModel = MutableLiveData() val groupAvatarModel: GroupAvatarModel @@ -147,11 +147,11 @@ class ConversationModel @WorkerThread constructor(private val chatRoom: ChatRoom } val friend = coreContext.contactsManager.findContactByAddress(address) if (friend != null) { - avatarModel = ContactAvatarModel(friend) + avatarModel.postValue(ContactAvatarModel(friend)) } else { val fakeFriend = coreContext.core.createFriend() fakeFriend.address = address - avatarModel = ContactAvatarModel(fakeFriend) + avatarModel.postValue(ContactAvatarModel(fakeFriend)) } groupAvatarModel = GroupAvatarModel(friends) diff --git a/app/src/main/java/org/linphone/ui/main/chat/viewmodel/ConversationViewModel.kt b/app/src/main/java/org/linphone/ui/main/chat/viewmodel/ConversationViewModel.kt index c6b456c1b..d8f376b2b 100644 --- a/app/src/main/java/org/linphone/ui/main/chat/viewmodel/ConversationViewModel.kt +++ b/app/src/main/java/org/linphone/ui/main/chat/viewmodel/ConversationViewModel.kt @@ -257,7 +257,10 @@ class ConversationViewModel @UiThread constructor() : ViewModel() { } @WorkerThread - private fun processGroupedEvents(groupedEventLogs: ArrayList, isGroupChatRoom: Boolean): ArrayList { + private fun processGroupedEvents( + groupedEventLogs: ArrayList, + isGroupChatRoom: Boolean + ): ArrayList { val eventsList = arrayListOf() // Handle all events in group, then re-start a new group with current item diff --git a/app/src/main/java/org/linphone/ui/main/chat/viewmodel/StartConversationViewModel.kt b/app/src/main/java/org/linphone/ui/main/chat/viewmodel/StartConversationViewModel.kt index d4ec27fb8..24be5cb37 100644 --- a/app/src/main/java/org/linphone/ui/main/chat/viewmodel/StartConversationViewModel.kt +++ b/app/src/main/java/org/linphone/ui/main/chat/viewmodel/StartConversationViewModel.kt @@ -127,14 +127,15 @@ class StartConversationViewModel @UiThread constructor() : ViewModel() { val friend = coreContext.contactsManager.findContactByAddress(address) if (friend != null) { val model = ContactOrSuggestionModel(address, friend) - model.contactAvatarModel = ContactAvatarModel(friend) + val avatarModel = ContactAvatarModel(friend) + model.avatarModel.postValue(avatarModel) val currentLetter = friend.name?.get(0).toString() val displayLetter = previousLetter.isEmpty() || currentLetter != previousLetter if (currentLetter != previousLetter) { previousLetter = currentLetter } - model.contactAvatarModel.firstContactStartingByThatLetter.postValue( + avatarModel.firstContactStartingByThatLetter.postValue( displayLetter ) diff --git a/app/src/main/java/org/linphone/ui/main/contacts/model/ContactAvatarModel.kt b/app/src/main/java/org/linphone/ui/main/contacts/model/ContactAvatarModel.kt index 51cf018ee..0c35d27d4 100644 --- a/app/src/main/java/org/linphone/ui/main/contacts/model/ContactAvatarModel.kt +++ b/app/src/main/java/org/linphone/ui/main/contacts/model/ContactAvatarModel.kt @@ -24,16 +24,19 @@ import android.net.Uri import android.provider.ContactsContract import androidx.annotation.WorkerThread import androidx.lifecycle.MutableLiveData +import org.linphone.LinphoneApplication.Companion.coreContext import org.linphone.R +import org.linphone.contacts.AbstractAvatarModel import org.linphone.core.ChatRoom.SecurityLevel import org.linphone.core.ConsolidatedPresence import org.linphone.core.Friend import org.linphone.core.FriendListenerStub import org.linphone.core.tools.Log +import org.linphone.ui.main.model.isInSecureMode import org.linphone.utils.AppUtils import org.linphone.utils.TimestampUtils -class ContactAvatarModel @WorkerThread constructor(val friend: Friend) { +class ContactAvatarModel @WorkerThread constructor(val friend: Friend) : AbstractAvatarModel() { companion object { private const val TAG = "[Contact Avatar Model]" } @@ -42,10 +45,6 @@ class ContactAvatarModel @WorkerThread constructor(val friend: Friend) { val starred = friend.starred - val avatar = MutableLiveData() - - val initials = AppUtils.getInitials(friend.name.orEmpty()) - val lastPresenceInfo = MutableLiveData() val presenceStatus = MutableLiveData() @@ -56,8 +55,6 @@ class ContactAvatarModel @WorkerThread constructor(val friend: Friend) { val firstContactStartingByThatLetter = MutableLiveData() - val trust = MutableLiveData() - private val friendListener = object : FriendListenerStub() { @WorkerThread override fun onPresenceReceived(fr: Friend) { @@ -71,11 +68,13 @@ class ContactAvatarModel @WorkerThread constructor(val friend: Friend) { init { friend.addListener(friendListener) + initials.postValue(AppUtils.getInitials(friend.name.orEmpty())) trust.postValue(SecurityLevel.Safe) // TODO FIXME: use API + showTrust.postValue(coreContext.core.defaultAccount?.isInSecureMode()) + images.postValue(arrayListOf(getAvatarUri().toString())) name.postValue(friend.name) computePresence() - avatar.postValue(getAvatarUri()) } @WorkerThread diff --git a/app/src/main/java/org/linphone/ui/main/history/adapter/ContactsAndSuggestionsListAdapter.kt b/app/src/main/java/org/linphone/ui/main/history/adapter/ContactsAndSuggestionsListAdapter.kt index 21d803f44..d9af1a94a 100644 --- a/app/src/main/java/org/linphone/ui/main/history/adapter/ContactsAndSuggestionsListAdapter.kt +++ b/app/src/main/java/org/linphone/ui/main/history/adapter/ContactsAndSuggestionsListAdapter.kt @@ -104,7 +104,7 @@ class ContactsAndSuggestionsListAdapter( @UiThread fun bind(contactOrSuggestionModel: ContactOrSuggestionModel) { with(binding) { - model = contactOrSuggestionModel.contactAvatarModel + model = contactOrSuggestionModel.avatarModel.value lifecycleOwner = viewLifecycleOwner diff --git a/app/src/main/java/org/linphone/ui/main/history/model/ContactOrSuggestionModel.kt b/app/src/main/java/org/linphone/ui/main/history/model/ContactOrSuggestionModel.kt index 5da68453e..ddcf157ad 100644 --- a/app/src/main/java/org/linphone/ui/main/history/model/ContactOrSuggestionModel.kt +++ b/app/src/main/java/org/linphone/ui/main/history/model/ContactOrSuggestionModel.kt @@ -21,6 +21,7 @@ package org.linphone.ui.main.history.model import androidx.annotation.UiThread import androidx.annotation.WorkerThread +import androidx.lifecycle.MutableLiveData import org.linphone.core.Address import org.linphone.core.Friend import org.linphone.ui.main.contacts.model.ContactAvatarModel @@ -42,7 +43,7 @@ class ContactOrSuggestionModel @WorkerThread constructor( val initials = AppUtils.getInitials(name) - lateinit var contactAvatarModel: ContactAvatarModel + val avatarModel = MutableLiveData() @UiThread fun onClicked() { diff --git a/app/src/main/java/org/linphone/ui/main/history/viewmodel/StartCallViewModel.kt b/app/src/main/java/org/linphone/ui/main/history/viewmodel/StartCallViewModel.kt index 15d2b1144..e811a8afb 100644 --- a/app/src/main/java/org/linphone/ui/main/history/viewmodel/StartCallViewModel.kt +++ b/app/src/main/java/org/linphone/ui/main/history/viewmodel/StartCallViewModel.kt @@ -197,14 +197,15 @@ class StartCallViewModel @UiThread constructor() : ViewModel() { val friend = coreContext.contactsManager.findContactByAddress(address) if (friend != null) { val model = ContactOrSuggestionModel(address, friend) - model.contactAvatarModel = ContactAvatarModel(friend) + val avatarModel = ContactAvatarModel(friend) + model.avatarModel.postValue(avatarModel) val currentLetter = friend.name?.get(0).toString() val displayLetter = previousLetter.isEmpty() || currentLetter != previousLetter if (currentLetter != previousLetter) { previousLetter = currentLetter } - model.contactAvatarModel.firstContactStartingByThatLetter.postValue( + avatarModel.firstContactStartingByThatLetter.postValue( displayLetter ) diff --git a/app/src/main/java/org/linphone/ui/main/model/AccountModel.kt b/app/src/main/java/org/linphone/ui/main/model/AccountModel.kt index d3872c058..27cfbe309 100644 --- a/app/src/main/java/org/linphone/ui/main/model/AccountModel.kt +++ b/app/src/main/java/org/linphone/ui/main/model/AccountModel.kt @@ -25,6 +25,7 @@ import androidx.annotation.WorkerThread import androidx.lifecycle.MutableLiveData import org.linphone.LinphoneApplication.Companion.coreContext import org.linphone.R +import org.linphone.contacts.AbstractAvatarModel import org.linphone.core.Account import org.linphone.core.AccountListenerStub import org.linphone.core.ChatMessage @@ -40,17 +41,13 @@ class AccountModel @WorkerThread constructor( val account: Account, private val onMenuClicked: ((view: View, account: Account) -> Unit)? = null, private val onSetAsDefault: ((account: Account) -> Unit)? = null -) { +) : AbstractAvatarModel() { companion object { private const val TAG = "[Account Model]" } val displayName = MutableLiveData() - val avatar = MutableLiveData() - - val initials = MutableLiveData() - val registrationState = MutableLiveData() val registrationStateLabel = MutableLiveData() @@ -59,8 +56,6 @@ class AccountModel @WorkerThread constructor( val isDefault = MutableLiveData() - val showTrust = MutableLiveData() - val notificationsCount = MutableLiveData() private val accountListener = object : AccountListenerStub() { @@ -99,6 +94,7 @@ class AccountModel @WorkerThread constructor( account.addListener(accountListener) coreContext.core.addListener(coreListener) + trust.postValue(ChatRoom.SecurityLevel.Safe) showTrust.postValue(account.isInSecureMode()) update() @@ -155,8 +151,8 @@ class AccountModel @WorkerThread constructor( initials.postValue(AppUtils.getInitials(name)) val pictureUri = account.params.pictureUri.orEmpty() - if (pictureUri != avatar.value) { - avatar.postValue(pictureUri) + if (pictureUri != images.value?.firstOrNull()) { + images.postValue(arrayListOf(pictureUri)) Log.d("$TAG Account picture URI is [$pictureUri]") } diff --git a/app/src/main/java/org/linphone/ui/main/settings/viewmodel/AccountProfileViewModel.kt b/app/src/main/java/org/linphone/ui/main/settings/viewmodel/AccountProfileViewModel.kt index 7d3ad593d..14e7d2dc6 100644 --- a/app/src/main/java/org/linphone/ui/main/settings/viewmodel/AccountProfileViewModel.kt +++ b/app/src/main/java/org/linphone/ui/main/settings/viewmodel/AccountProfileViewModel.kt @@ -173,7 +173,7 @@ class AccountProfileViewModel @UiThread constructor() : ViewModel() { copy.pictureUri = null } - accountModel.value?.avatar?.postValue(path) + accountModel.value?.images?.postValue(arrayListOf(path)) account.params = copy account.refreshRegister() } diff --git a/app/src/main/java/org/linphone/utils/DataBindingUtils.kt b/app/src/main/java/org/linphone/utils/DataBindingUtils.kt index 575d4bd8b..4bbbf3ecb 100644 --- a/app/src/main/java/org/linphone/utils/DataBindingUtils.kt +++ b/app/src/main/java/org/linphone/utils/DataBindingUtils.kt @@ -19,6 +19,7 @@ */ package org.linphone.utils +import android.annotation.SuppressLint import android.content.Context import android.graphics.PorterDuff import android.text.Editable @@ -31,7 +32,9 @@ import android.widget.EditText import android.widget.ImageView import androidx.annotation.ColorInt import androidx.annotation.ColorRes +import androidx.annotation.DimenRes import androidx.annotation.UiThread +import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.widget.AppCompatEditText import androidx.appcompat.widget.AppCompatTextView import androidx.core.view.ViewCompat @@ -43,19 +46,24 @@ import androidx.databinding.ViewDataBinding import androidx.emoji2.emojipicker.EmojiPickerView import androidx.emoji2.emojipicker.EmojiViewItem import androidx.lifecycle.LifecycleOwner -import androidx.lifecycle.findViewTreeLifecycleOwner +import androidx.lifecycle.lifecycleScope +import coil.dispose import coil.load import coil.transform.CircleCropTransformation import io.getstream.avatarview.AvatarView import io.getstream.avatarview.coil.loadImage +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import org.linphone.BR import org.linphone.R +import org.linphone.contacts.AbstractAvatarModel +import org.linphone.contacts.AvatarGenerator import org.linphone.core.ChatRoom import org.linphone.core.ConsolidatedPresence import org.linphone.core.tools.Log -import org.linphone.ui.main.contacts.model.ContactAvatarModel import org.linphone.ui.main.contacts.model.GroupAvatarModel -import org.linphone.ui.main.model.AccountModel /** * This file contains all the data binding necessary for the app @@ -173,17 +181,6 @@ fun AppCompatTextView.setDrawableTint(@ColorInt color: Int) { } } -@UiThread -@BindingAdapter("coil") -fun ImageView.loadCircleFileWithCoil(file: String?) { - Log.i("[Data Binding Utils] Loading file [$file] with coil") - if (file != null) { - load(file) { - transformations(CircleCropTransformation()) - } - } -} - @UiThread @BindingAdapter("presenceIcon") fun ImageView.setPresenceIcon(presence: ConsolidatedPresence?) { @@ -209,6 +206,106 @@ fun AppCompatTextView.setColor(@ColorRes color: Int) { } @UiThread +@BindingAdapter("coil") +fun ImageView.loadCircleFileWithCoil(file: String?) { + Log.i("[Data Binding Utils] Loading file [$file] with coil") + if (file != null) { + load(file) { + transformations(CircleCropTransformation()) + } + } +} + +@UiThread +@BindingAdapter("coilAvatar") +fun ImageView.loadAvatarWithCoil(model: AbstractAvatarModel?) { + val imageView = this + (context as AppCompatActivity).lifecycleScope.launch { + loadContactPictureWithCoil(imageView, model) + } +} + +@UiThread +@BindingAdapter("coilBubbleAvatar") +fun ImageView.loadBubbleAvatarWithCoil(model: AbstractAvatarModel?) { + val imageView = this + (context as AppCompatActivity).lifecycleScope.launch { + withContext(Dispatchers.IO) { + val size = R.dimen.avatar_bubble_size + val initialsSize = R.dimen.avatar_initials_bubble_text_size + loadContactPictureWithCoil(imageView, model, size = size, textSize = initialsSize) + } + } +} + +@UiThread +@BindingAdapter("coilBigAvatar") +fun ImageView.loadBigAvatarWithCoil(model: AbstractAvatarModel?) { + val imageView = this + (context as AppCompatActivity).lifecycleScope.launch { + withContext(Dispatchers.IO) { + val size = R.dimen.avatar_big_size + val initialsSize = R.dimen.avatar_initials_big_text_size + loadContactPictureWithCoil(imageView, model, size = size, textSize = initialsSize) + } + } +} + +@UiThread +@BindingAdapter("coilCallAvatar") +fun ImageView.loadCallAvatarWithCoil(model: AbstractAvatarModel?) { + val imageView = this + (context as AppCompatActivity).lifecycleScope.launch { + withContext(Dispatchers.IO) { + val size = R.dimen.avatar_in_call_size + val initialsSize = R.dimen.avatar_initials_call_text_size + loadContactPictureWithCoil(imageView, model, size = size, textSize = initialsSize) + } + } +} + +@SuppressLint("ResourceType") +private suspend fun loadContactPictureWithCoil( + imageView: ImageView, + model: AbstractAvatarModel?, + @DimenRes size: Int = 0, + @DimenRes textSize: Int = 0 +) { + withContext(Dispatchers.IO) { + imageView.dispose() + + val context = imageView.context + if (model != null) { + val image = model.images.value?.firstOrNull() + imageView.load(image) { + transformations(CircleCropTransformation()) + error( + coroutineScope { + withContext(Dispatchers.IO) { + val builder = AvatarGenerator(context) + builder.setInitials(model.initials.value.orEmpty()) + if (size > 0) { + builder.setAvatarSize(AppUtils.getDimension(size).toInt()) + } + if (textSize > 0) { + builder.setTextSize(AppUtils.getDimension(textSize)) + } + /*if (color > 0) { + builder.setBackgroundColorAttribute(color) + } + if (textColor > 0) { + builder.setTextColorResource(textColor) + }*/ + builder.build() + } + } + ) + } + } + } +} + +/*@UiThread @BindingAdapter("avatarInitials") fun AvatarView.loadInitials(initials: String?) { Log.i("[Data Binding Utils] Displaying initials [$initials] on AvatarView") @@ -288,7 +385,7 @@ fun AvatarView.loadContactAvatar(contact: ContactAvatarModel?) { avatarBorderWidth = AppUtils.getDimension(R.dimen.avatar_trust_border_width).toInt() } - ChatRoom.SecurityLevel.Encrypted -> { + ChatRoom.SecurityLevel.Safe -> { avatarBorderColor = resources.getColor(R.color.blue_info_500, context.theme) avatarBorderWidth = @@ -309,12 +406,7 @@ fun AvatarView.loadContactAvatar(contact: ContactAvatarModel?) { } ) } -} - -@BindingAdapter("contactPicture") -fun ImageView.loadContactPicture(contact: ContactAvatarModel?) { - loadCircleFileWithCoil(contact?.avatar?.value?.toString()) -} +}*/ @UiThread @BindingAdapter("groupAvatar") diff --git a/app/src/main/res/layout/account_list_cell.xml b/app/src/main/res/layout/account_list_cell.xml index f42327f01..b9ded3d37 100644 --- a/app/src/main/res/layout/account_list_cell.xml +++ b/app/src/main/res/layout/account_list_cell.xml @@ -25,7 +25,7 @@ app:barrierDirection="right" app:constraint_referenced_ids="name, register_status" /> - diff --git a/app/src/main/res/layout/account_profile_fragment.xml b/app/src/main/res/layout/account_profile_fragment.xml index 3ae4ef4c1..aac203806 100644 --- a/app/src/main/res/layout/account_profile_fragment.xml +++ b/app/src/main/res/layout/account_profile_fragment.xml @@ -84,7 +84,7 @@ app:constraint_referenced_ids="sip_address, sip_address_label, display_name, display_name_label, details_background" android:visibility="@{viewModel.expandDetails ? View.VISIBLE : View.GONE}" /> - @@ -125,7 +117,7 @@ android:textSize="14sp" android:drawableStart="@drawable/camera" android:drawablePadding="3dp" - android:visibility="@{viewModel.accountModel.avatar.empty ? View.VISIBLE : View.GONE, default=gone}" + android:visibility="@{viewModel.accountModel.images.size() == 0 ? View.VISIBLE : View.GONE, default=gone}" app:layout_constraintTop_toBottomOf="@id/avatar" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent"/> @@ -141,7 +133,7 @@ android:textSize="14sp" android:drawableStart="@drawable/pencil_simple" android:drawablePadding="3dp" - android:visibility="@{viewModel.accountModel.avatar.empty ? View.GONE : View.VISIBLE}" + android:visibility="@{viewModel.accountModel.images.size() == 0 ? View.GONE : View.VISIBLE}" app:layout_constraintHorizontal_chainStyle="packed" app:layout_constraintTop_toBottomOf="@id/avatar" app:layout_constraintStart_toStartOf="parent" @@ -159,7 +151,7 @@ android:textSize="14sp" android:drawableStart="@drawable/trash_simple" android:drawablePadding="3dp" - android:visibility="@{viewModel.accountModel.avatar.empty ? View.GONE : View.VISIBLE}" + android:visibility="@{viewModel.accountModel.images.size() == 0 ? View.GONE : View.VISIBLE}" app:layout_constraintTop_toBottomOf="@id/avatar" app:layout_constraintStart_toEndOf="@id/edit_picture_label" app:layout_constraintEnd_toEndOf="parent"/> diff --git a/app/src/main/res/layout/call_active_fragment.xml b/app/src/main/res/layout/call_active_fragment.xml index 9f06353e8..588a6920f 100644 --- a/app/src/main/res/layout/call_active_fragment.xml +++ b/app/src/main/res/layout/call_active_fragment.xml @@ -60,21 +60,13 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" /> - - - - diff --git a/app/src/main/res/layout/call_outgoing_fragment.xml b/app/src/main/res/layout/call_outgoing_fragment.xml index d9288df41..d2f10e2af 100644 --- a/app/src/main/res/layout/call_outgoing_fragment.xml +++ b/app/src/main/res/layout/call_outgoing_fragment.xml @@ -76,19 +76,12 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" /> - diff --git a/app/src/main/res/layout/chat_conversation_fragment.xml b/app/src/main/res/layout/chat_conversation_fragment.xml index ed26f416c..8c0ce5a05 100644 --- a/app/src/main/res/layout/chat_conversation_fragment.xml +++ b/app/src/main/res/layout/chat_conversation_fragment.xml @@ -41,7 +41,7 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="@id/title"/> - diff --git a/app/src/main/res/layout/chat_list_cell.xml b/app/src/main/res/layout/chat_list_cell.xml index db2ec2e49..1f95a8293 100644 --- a/app/src/main/res/layout/chat_list_cell.xml +++ b/app/src/main/res/layout/chat_list_cell.xml @@ -30,22 +30,15 @@ android:paddingBottom="4dp" android:background="@drawable/primary_cell_background"> - diff --git a/app/src/main/res/layout/contact_favourite_list_cell.xml b/app/src/main/res/layout/contact_favourite_list_cell.xml index 2061436e4..28091f353 100644 --- a/app/src/main/res/layout/contact_favourite_list_cell.xml +++ b/app/src/main/res/layout/contact_favourite_list_cell.xml @@ -26,20 +26,13 @@ android:padding="5dp" android:background="@drawable/primary_cell_background"> - diff --git a/app/src/main/res/layout/contact_fragment.xml b/app/src/main/res/layout/contact_fragment.xml index 819eafadb..17e870ea0 100644 --- a/app/src/main/res/layout/contact_fragment.xml +++ b/app/src/main/res/layout/contact_fragment.xml @@ -96,21 +96,14 @@ app:constraint_referenced_ids="trusted_devices_count, trust_background, trusted_devices_progress, devices, trusted_devices_progress_label" android:visibility="@{viewModel.expandDevicesTrust ? View.VISIBLE : View.GONE}" /> - diff --git a/app/src/main/res/layout/contact_list_cell.xml b/app/src/main/res/layout/contact_list_cell.xml index e53fad32a..5e21dcd8c 100644 --- a/app/src/main/res/layout/contact_list_cell.xml +++ b/app/src/main/res/layout/contact_list_cell.xml @@ -52,7 +52,7 @@ app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent"/> - diff --git a/app/src/main/res/layout/history_contact_fragment.xml b/app/src/main/res/layout/history_contact_fragment.xml index 6d6a7ff82..5d70a86b6 100644 --- a/app/src/main/res/layout/history_contact_fragment.xml +++ b/app/src/main/res/layout/history_contact_fragment.xml @@ -71,20 +71,13 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent"/> - diff --git a/app/src/main/res/layout/history_list_cell.xml b/app/src/main/res/layout/history_list_cell.xml index 90318ea80..73a749278 100644 --- a/app/src/main/res/layout/history_list_cell.xml +++ b/app/src/main/res/layout/history_list_cell.xml @@ -29,7 +29,7 @@ android:layout_height="wrap_content" android:background="@drawable/primary_cell_background"> - diff --git a/app/src/main/res/layout/meeting_participant_list_cell.xml b/app/src/main/res/layout/meeting_participant_list_cell.xml index ef3548a50..cce275f41 100644 --- a/app/src/main/res/layout/meeting_participant_list_cell.xml +++ b/app/src/main/res/layout/meeting_participant_list_cell.xml @@ -15,7 +15,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content"> - diff --git a/app/src/main/res/layout/top_bar.xml b/app/src/main/res/layout/top_bar.xml index dbbceaa93..670960386 100644 --- a/app/src/main/res/layout/top_bar.xml +++ b/app/src/main/res/layout/top_bar.xml @@ -34,21 +34,14 @@ app:constraint_referenced_ids="title, search" app:barrierDirection="bottom" /> - diff --git a/app/src/main/res/values/dimen.xml b/app/src/main/res/values/dimen.xml index 8fcf8bfb7..4c8ca7370 100644 --- a/app/src/main/res/values/dimen.xml +++ b/app/src/main/res/values/dimen.xml @@ -29,6 +29,11 @@ 5dp 2dp + 16sp + 14sp + 21sp + 36sp + 11dp 20dp