diff --git a/app/src/main/java/org/linphone/activities/main/chat/viewmodels/ChatRoomViewModel.kt b/app/src/main/java/org/linphone/activities/main/chat/viewmodels/ChatRoomViewModel.kt index de247fd3e..52119c219 100644 --- a/app/src/main/java/org/linphone/activities/main/chat/viewmodels/ChatRoomViewModel.kt +++ b/app/src/main/java/org/linphone/activities/main/chat/viewmodels/ChatRoomViewModel.kt @@ -27,6 +27,8 @@ import android.view.animation.LinearInterpolator import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.viewModelScope +import kotlinx.coroutines.CoroutineScope import org.linphone.LinphoneApplication.Companion.coreContext import org.linphone.LinphoneApplication.Companion.corePreferences import org.linphone.R @@ -53,6 +55,7 @@ class ChatRoomViewModel(val chatRoom: ChatRoom) : ViewModel(), ContactDataInterf override val securityLevel: MutableLiveData = MutableLiveData() override val showGroupChatAvatar: Boolean = chatRoom.hasCapability(ChatRoomCapabilities.Conference.toInt()) && !chatRoom.hasCapability(ChatRoomCapabilities.OneToOne.toInt()) + override val coroutineScope: CoroutineScope = viewModelScope val subject = MutableLiveData() diff --git a/app/src/main/java/org/linphone/activities/main/contact/viewmodels/ContactEditorViewModel.kt b/app/src/main/java/org/linphone/activities/main/contact/viewmodels/ContactEditorViewModel.kt index 619a87b47..227e6a5a7 100644 --- a/app/src/main/java/org/linphone/activities/main/contact/viewmodels/ContactEditorViewModel.kt +++ b/app/src/main/java/org/linphone/activities/main/contact/viewmodels/ContactEditorViewModel.kt @@ -25,8 +25,10 @@ import android.media.ExifInterface import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.viewModelScope import java.io.ByteArrayOutputStream import java.io.IOException +import kotlinx.coroutines.CoroutineScope import org.linphone.LinphoneApplication.Companion.coreContext import org.linphone.LinphoneApplication.Companion.corePreferences import org.linphone.activities.main.contact.data.NumberOrAddressEditorData @@ -50,6 +52,7 @@ class ContactEditorViewModel(val c: Friend?) : ViewModel(), ContactDataInterface override val contact: MutableLiveData = MutableLiveData() override val displayName: MutableLiveData = MutableLiveData() override val securityLevel: MutableLiveData = MutableLiveData() + override val coroutineScope: CoroutineScope = viewModelScope val firstName = MutableLiveData() diff --git a/app/src/main/java/org/linphone/activities/main/contact/viewmodels/ContactViewModel.kt b/app/src/main/java/org/linphone/activities/main/contact/viewmodels/ContactViewModel.kt index 0acc03410..f8f0b63fb 100644 --- a/app/src/main/java/org/linphone/activities/main/contact/viewmodels/ContactViewModel.kt +++ b/app/src/main/java/org/linphone/activities/main/contact/viewmodels/ContactViewModel.kt @@ -24,6 +24,8 @@ import android.provider.ContactsContract import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.viewModelScope +import kotlinx.coroutines.CoroutineScope import org.linphone.LinphoneApplication.Companion.coreContext import org.linphone.LinphoneApplication.Companion.corePreferences import org.linphone.R @@ -52,6 +54,7 @@ class ContactViewModel(friend: Friend, async: Boolean = false) : MessageNotifier override val contact: MutableLiveData = MutableLiveData() override val displayName: MutableLiveData = MutableLiveData() override val securityLevel: MutableLiveData = MutableLiveData() + override val coroutineScope: CoroutineScope = viewModelScope var fullName = "" diff --git a/app/src/main/java/org/linphone/contact/ContactDataInterface.kt b/app/src/main/java/org/linphone/contact/ContactDataInterface.kt index 892e30d61..5bf254462 100644 --- a/app/src/main/java/org/linphone/contact/ContactDataInterface.kt +++ b/app/src/main/java/org/linphone/contact/ContactDataInterface.kt @@ -20,6 +20,8 @@ package org.linphone.contact import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.viewModelScope +import kotlinx.coroutines.CoroutineScope import org.linphone.LinphoneApplication.Companion.coreContext import org.linphone.activities.main.viewmodels.MessageNotifierViewModel import org.linphone.core.Address @@ -36,12 +38,15 @@ interface ContactDataInterface { val showGroupChatAvatar: Boolean get() = false + + val coroutineScope: CoroutineScope } open class GenericContactData(private val sipAddress: Address) : ContactDataInterface { final override val contact: MutableLiveData = MutableLiveData() final override val displayName: MutableLiveData = MutableLiveData() final override val securityLevel: MutableLiveData = MutableLiveData() + final override val coroutineScope: CoroutineScope = coreContext.coroutineScope init { securityLevel.value = ChatRoomSecurityLevel.ClearText @@ -63,6 +68,7 @@ abstract class GenericContactViewModel(private val sipAddress: Address) : Messag final override val contact: MutableLiveData = MutableLiveData() final override val displayName: MutableLiveData = MutableLiveData() final override val securityLevel: MutableLiveData = MutableLiveData() + final override val coroutineScope: CoroutineScope = viewModelScope init { securityLevel.value = ChatRoomSecurityLevel.ClearText diff --git a/app/src/main/java/org/linphone/contact/ContactSelectionData.kt b/app/src/main/java/org/linphone/contact/ContactSelectionData.kt index e6c410b9c..83e3e96d0 100644 --- a/app/src/main/java/org/linphone/contact/ContactSelectionData.kt +++ b/app/src/main/java/org/linphone/contact/ContactSelectionData.kt @@ -20,6 +20,7 @@ package org.linphone.contact import androidx.lifecycle.MutableLiveData +import kotlinx.coroutines.CoroutineScope import org.linphone.LinphoneApplication.Companion.coreContext import org.linphone.core.* import org.linphone.utils.LinphoneUtils @@ -28,6 +29,7 @@ class ContactSelectionData(private val searchResult: SearchResult) : ContactData override val contact: MutableLiveData = MutableLiveData() override val displayName: MutableLiveData = MutableLiveData() override val securityLevel: MutableLiveData = MutableLiveData() + override val coroutineScope: CoroutineScope = coreContext.coroutineScope val isDisabled: MutableLiveData by lazy { MutableLiveData() diff --git a/app/src/main/java/org/linphone/core/CoreContext.kt b/app/src/main/java/org/linphone/core/CoreContext.kt index bddd1ead0..e8d1f3b55 100644 --- a/app/src/main/java/org/linphone/core/CoreContext.kt +++ b/app/src/main/java/org/linphone/core/CoreContext.kt @@ -118,8 +118,9 @@ class CoreContext( MutableLiveData>() } + val coroutineScope = CoroutineScope(Dispatchers.Main + SupervisorJob()) + private val loggingService = Factory.instance().loggingService - private val coroutineScope = CoroutineScope(Dispatchers.Main + SupervisorJob()) private var overlayX = 0f private var overlayY = 0f diff --git a/app/src/main/java/org/linphone/utils/DataBindingUtils.kt b/app/src/main/java/org/linphone/utils/DataBindingUtils.kt index adc5350f4..a4c440c9f 100644 --- a/app/src/main/java/org/linphone/utils/DataBindingUtils.kt +++ b/app/src/main/java/org/linphone/utils/DataBindingUtils.kt @@ -42,7 +42,9 @@ import coil.request.CachePolicy import coil.request.videoFrameMillis import coil.transform.CircleCropTransformation import com.google.android.material.switchmaterial.SwitchMaterial +import kotlinx.coroutines.* import org.linphone.BR +import org.linphone.LinphoneApplication.Companion.coreContext import org.linphone.LinphoneApplication.Companion.corePreferences import org.linphone.R import org.linphone.activities.GenericActivity @@ -320,7 +322,7 @@ fun loadImageWithCoil(imageView: ImageView, path: String?) { } } -private fun loadContactPictureWithCoil( +private suspend fun loadContactPictureWithCoil( imageView: ImageView, contact: ContactDataInterface?, useThumbnail: Boolean, @@ -329,76 +331,100 @@ private fun loadContactPictureWithCoil( color: Int = 0, textColor: Int = 0 ) { - if (contact != null) { - val context = imageView.context - val displayName = contact.contact.value?.name ?: contact.displayName.value.orEmpty() - val source = contact.contact.value?.getPictureUri(useThumbnail) - imageView.load(source) { - transformations(CircleCropTransformation()) - error( - if (contact.showGroupChatAvatar) { - val bg = AppCompatResources.getDrawable(context, R.drawable.generated_avatar_bg) - imageView.background = bg - AppCompatResources.getDrawable(context, R.drawable.icon_multiple_contacts_avatar) - } else if (displayName.isEmpty() || AppUtils.getInitials(displayName) == "+") { - val bg = AppCompatResources.getDrawable(context, R.drawable.generated_avatar_bg) - imageView.background = bg - AppCompatResources.getDrawable(context, R.drawable.icon_single_contact_avatar) - } else { - val builder = ContactAvatarGenerator(context) - builder.setLabel(displayName) - 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() + coroutineScope { + withContext(Dispatchers.IO) { + if (contact != null) { + val context = imageView.context + val displayName = contact.contact.value?.name ?: contact.displayName.value.orEmpty() + val source = contact.contact.value?.getPictureUri(useThumbnail) + imageView.load(source) { + transformations(CircleCropTransformation()) + error( + if (contact.showGroupChatAvatar) { + val bg = AppCompatResources.getDrawable(context, R.drawable.generated_avatar_bg) + imageView.background = bg + AppCompatResources.getDrawable(context, R.drawable.icon_multiple_contacts_avatar) + } else if (displayName.isEmpty() || AppUtils.getInitials(displayName) == "+") { + val bg = AppCompatResources.getDrawable(context, R.drawable.generated_avatar_bg) + imageView.background = bg + AppCompatResources.getDrawable(context, R.drawable.icon_single_contact_avatar) + } else { + val builder = ContactAvatarGenerator(context) + builder.setLabel(displayName) + 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() + } + ) } - ) + } else { + val bg = AppCompatResources.getDrawable(imageView.context, R.drawable.generated_avatar_bg) + imageView.background = bg + imageView.load(R.drawable.icon_single_contact_avatar) + } } - } else { - val bg = AppCompatResources.getDrawable(imageView.context, R.drawable.generated_avatar_bg) - imageView.background = bg - imageView.load(R.drawable.icon_single_contact_avatar) } } @BindingAdapter("coilContact") fun loadContactPictureWithCoil(imageView: ImageView, contact: ContactDataInterface?) { - loadContactPictureWithCoil(imageView, contact, true) + val coroutineScope = contact?.coroutineScope ?: coreContext.coroutineScope + coroutineScope.launch { + withContext(Dispatchers.Main) { + loadContactPictureWithCoil(imageView, contact, true) + } + } } @BindingAdapter("coilContactBig") fun loadBigContactPictureWithCoil(imageView: ImageView, contact: ContactDataInterface?) { - loadContactPictureWithCoil( - imageView, contact, false, - R.dimen.contact_avatar_big_size, R.dimen.contact_avatar_text_big_size - ) + val coroutineScope = contact?.coroutineScope ?: coreContext.coroutineScope + coroutineScope.launch { + withContext(Dispatchers.Main) { + loadContactPictureWithCoil( + imageView, contact, false, + R.dimen.contact_avatar_big_size, R.dimen.contact_avatar_text_big_size + ) + } + } } @BindingAdapter("coilVoipContactAlt") fun loadVoipContactPictureWithCoilAlt(imageView: ImageView, contact: ContactDataInterface?) { - loadContactPictureWithCoil( - imageView, contact, false, - R.dimen.voip_contact_avatar_max_size, R.dimen.voip_contact_avatar_text_size, - R.attr.voipParticipantBackgroundColor, R.color.white_color - ) + val coroutineScope = contact?.coroutineScope ?: coreContext.coroutineScope + coroutineScope.launch { + withContext(Dispatchers.Main) { + loadContactPictureWithCoil( + imageView, contact, false, + R.dimen.voip_contact_avatar_max_size, R.dimen.voip_contact_avatar_text_size, + R.attr.voipParticipantBackgroundColor, R.color.white_color + ) + } + } } @BindingAdapter("coilVoipContact") fun loadVoipContactPictureWithCoil(imageView: ImageView, contact: ContactDataInterface?) { - loadContactPictureWithCoil( - imageView, contact, false, - R.dimen.voip_contact_avatar_max_size, R.dimen.voip_contact_avatar_text_size, - R.attr.voipBackgroundColor, R.color.white_color - ) + val coroutineScope = contact?.coroutineScope ?: coreContext.coroutineScope + coroutineScope.launch { + withContext(Dispatchers.Main) { + loadContactPictureWithCoil( + imageView, contact, false, + R.dimen.voip_contact_avatar_max_size, R.dimen.voip_contact_avatar_text_size, + R.attr.voipBackgroundColor, R.color.white_color + ) + } + } } @BindingAdapter("coilGoneIfError")