Trying to improve chat rooms display performances

This commit is contained in:
Sylvain Berfini 2022-06-09 16:08:07 +02:00
parent e6c842cd35
commit f94b65ed0a
2 changed files with 60 additions and 40 deletions

View file

@ -28,7 +28,7 @@ import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.*
import org.linphone.LinphoneApplication.Companion.coreContext import org.linphone.LinphoneApplication.Companion.coreContext
import org.linphone.LinphoneApplication.Companion.corePreferences import org.linphone.LinphoneApplication.Companion.corePreferences
import org.linphone.R import org.linphone.R
@ -53,8 +53,8 @@ class ChatRoomViewModel(val chatRoom: ChatRoom) : ViewModel(), ContactDataInterf
override val contact: MutableLiveData<Friend> = MutableLiveData<Friend>() override val contact: MutableLiveData<Friend> = MutableLiveData<Friend>()
override val displayName: MutableLiveData<String> = MutableLiveData<String>() override val displayName: MutableLiveData<String> = MutableLiveData<String>()
override val securityLevel: MutableLiveData<ChatRoomSecurityLevel> = MutableLiveData<ChatRoomSecurityLevel>() override val securityLevel: MutableLiveData<ChatRoomSecurityLevel> = MutableLiveData<ChatRoomSecurityLevel>()
override val showGroupChatAvatar: Boolean = chatRoom.hasCapability(ChatRoomCapabilities.Conference.toInt()) && override val showGroupChatAvatar: Boolean
!chatRoom.hasCapability(ChatRoomCapabilities.OneToOne.toInt()) get() = conferenceChatRoom && !oneToOneChatRoom
override val coroutineScope: CoroutineScope = viewModelScope override val coroutineScope: CoroutineScope = viewModelScope
val subject = MutableLiveData<String>() val subject = MutableLiveData<String>()
@ -67,8 +67,6 @@ class ChatRoomViewModel(val chatRoom: ChatRoom) : ViewModel(), ContactDataInterf
val lastMessageText = MutableLiveData<SpannableStringBuilder>() val lastMessageText = MutableLiveData<SpannableStringBuilder>()
val callInProgress = MutableLiveData<Boolean>()
val remoteIsComposing = MutableLiveData<Boolean>() val remoteIsComposing = MutableLiveData<Boolean>()
val composingList = MutableLiveData<String>() val composingList = MutableLiveData<String>()
@ -81,13 +79,25 @@ class ChatRoomViewModel(val chatRoom: ChatRoom) : ViewModel(), ContactDataInterf
val ephemeralEnabled = MutableLiveData<Boolean>() val ephemeralEnabled = MutableLiveData<Boolean>()
val basicChatRoom: Boolean = chatRoom.hasCapability(ChatRoomCapabilities.Basic.toInt()) val basicChatRoom: Boolean by lazy {
chatRoom.hasCapability(ChatRoomCapabilities.Basic.toInt())
}
val oneToOneChatRoom: Boolean = chatRoom.hasCapability(ChatRoomCapabilities.OneToOne.toInt()) val oneToOneChatRoom: Boolean by lazy {
chatRoom.hasCapability(ChatRoomCapabilities.OneToOne.toInt())
}
val encryptedChatRoom: Boolean = chatRoom.hasCapability(ChatRoomCapabilities.Encrypted.toInt()) private val conferenceChatRoom: Boolean by lazy {
chatRoom.hasCapability(ChatRoomCapabilities.Conference.toInt())
}
val ephemeralChatRoom: Boolean = chatRoom.hasCapability(ChatRoomCapabilities.Ephemeral.toInt()) val encryptedChatRoom: Boolean by lazy {
chatRoom.hasCapability(ChatRoomCapabilities.Encrypted.toInt())
}
val ephemeralChatRoom: Boolean by lazy {
chatRoom.hasCapability(ChatRoomCapabilities.Ephemeral.toInt())
}
val meAdmin: MutableLiveData<Boolean> by lazy { val meAdmin: MutableLiveData<Boolean> by lazy {
MutableLiveData<Boolean>() MutableLiveData<Boolean>()
@ -130,18 +140,9 @@ class ChatRoomViewModel(val chatRoom: ChatRoom) : ViewModel(), ContactDataInterf
} }
private val coreListener: CoreListenerStub = object : CoreListenerStub() { private val coreListener: CoreListenerStub = object : CoreListenerStub() {
override fun onCallStateChanged(
core: Core,
call: Call,
state: Call.State,
message: String
) {
callInProgress.value = core.callsNb > 0
}
override fun onChatRoomRead(core: Core, room: ChatRoom) { override fun onChatRoomRead(core: Core, room: ChatRoom) {
if (room == chatRoom) { if (room == chatRoom) {
unreadMessagesCount.value = 0 updateUnreadMessageCount()
} }
} }
} }
@ -161,7 +162,7 @@ class ChatRoomViewModel(val chatRoom: ChatRoom) : ViewModel(), ContactDataInterf
} }
override fun onChatMessageReceived(chatRoom: ChatRoom, eventLog: EventLog) { override fun onChatMessageReceived(chatRoom: ChatRoom, eventLog: EventLog) {
unreadMessagesCount.value = chatRoom.unreadMessagesCount updateUnreadMessageCount()
formatLastMessage(eventLog.chatMessage) formatLastMessage(eventLog.chatMessage)
} }
@ -228,7 +229,7 @@ class ChatRoomViewModel(val chatRoom: ChatRoom) : ViewModel(), ContactDataInterf
chatRoom.addListener(chatRoomListener) chatRoom.addListener(chatRoomListener)
coreContext.contactsManager.addListener(contactsUpdatedListener) coreContext.contactsManager.addListener(contactsUpdatedListener)
unreadMessagesCount.value = chatRoom.unreadMessagesCount updateUnreadMessageCount()
subject.value = chatRoom.subject subject.value = chatRoom.subject
updateSecurityIcon() updateSecurityIcon()
@ -239,12 +240,9 @@ class ChatRoomViewModel(val chatRoom: ChatRoom) : ViewModel(), ContactDataInterf
updateParticipants() updateParticipants()
updateLastMessageToDisplay() updateLastMessageToDisplay()
callInProgress.value = chatRoom.core.callsNb > 0
updateRemotesComposing() updateRemotesComposing()
notificationsMuted.value = areNotificationsMuted() notificationsMuted.value = areNotificationsMuted()
if (corePreferences.enableAnimations) bounceAnimator.start()
} }
override fun onCleared() { override fun onCleared() {
@ -261,17 +259,17 @@ class ChatRoomViewModel(val chatRoom: ChatRoom) : ViewModel(), ContactDataInterf
fun contactLookup() { fun contactLookup() {
displayName.value = when { displayName.value = when {
chatRoom.hasCapability(ChatRoomCapabilities.Basic.toInt()) -> LinphoneUtils.getDisplayName( basicChatRoom -> LinphoneUtils.getDisplayName(
chatRoom.peerAddress chatRoom.peerAddress
) )
chatRoom.hasCapability(ChatRoomCapabilities.OneToOne.toInt()) -> LinphoneUtils.getDisplayName( oneToOneChatRoom -> LinphoneUtils.getDisplayName(
chatRoom.participants.firstOrNull()?.address ?: chatRoom.peerAddress chatRoom.participants.firstOrNull()?.address ?: chatRoom.peerAddress
) )
chatRoom.hasCapability(ChatRoomCapabilities.Conference.toInt()) -> chatRoom.subject.orEmpty() conferenceChatRoom -> chatRoom.subject.orEmpty()
else -> chatRoom.peerAddress.asStringUriOnly() else -> chatRoom.peerAddress.asStringUriOnly()
} }
if (chatRoom.hasCapability(ChatRoomCapabilities.OneToOne.toInt())) { if (oneToOneChatRoom) {
searchMatchingContact() searchMatchingContact()
} else { } else {
getParticipantsNames() getParticipantsNames()
@ -350,11 +348,17 @@ class ChatRoomViewModel(val chatRoom: ChatRoom) : ViewModel(), ContactDataInterf
builder.trim() builder.trim()
lastMessageText.value = builder lastMessageText.value = builder
lastUpdate.value = TimestampUtils.toString(chatRoom.lastUpdateTime, true)
val lastUpdateTime = chatRoom.lastUpdateTime
viewModelScope.launch {
withContext(Dispatchers.IO) {
lastUpdate.postValue(TimestampUtils.toString(lastUpdateTime, true))
}
}
} }
fun getRemoteAddress(): Address? { fun getRemoteAddress(): Address? {
return if (chatRoom.hasCapability(ChatRoomCapabilities.Basic.toInt())) { return if (basicChatRoom) {
chatRoom.peerAddress chatRoom.peerAddress
} else { } else {
if (chatRoom.participants.isNotEmpty()) { if (chatRoom.participants.isNotEmpty()) {
@ -388,14 +392,15 @@ class ChatRoomViewModel(val chatRoom: ChatRoom) : ViewModel(), ContactDataInterf
} }
private fun updateSecurityIcon() { private fun updateSecurityIcon() {
securityLevel.value = chatRoom.securityLevel val level = chatRoom.securityLevel
securityLevel.value = level
securityLevelIcon.value = when (chatRoom.securityLevel) { securityLevelIcon.value = when (level) {
ChatRoomSecurityLevel.Safe -> R.drawable.security_2_indicator ChatRoomSecurityLevel.Safe -> R.drawable.security_2_indicator
ChatRoomSecurityLevel.Encrypted -> R.drawable.security_1_indicator ChatRoomSecurityLevel.Encrypted -> R.drawable.security_1_indicator
else -> R.drawable.security_alert_indicator else -> R.drawable.security_alert_indicator
} }
securityLevelContentDescription.value = when (chatRoom.securityLevel) { securityLevelContentDescription.value = when (level) {
ChatRoomSecurityLevel.Safe -> R.string.content_description_security_level_safe ChatRoomSecurityLevel.Safe -> R.string.content_description_security_level_safe
ChatRoomSecurityLevel.Encrypted -> R.string.content_description_security_level_encrypted ChatRoomSecurityLevel.Encrypted -> R.string.content_description_security_level_encrypted
else -> R.string.content_description_security_level_unsafe else -> R.string.content_description_security_level_unsafe
@ -403,7 +408,9 @@ class ChatRoomViewModel(val chatRoom: ChatRoom) : ViewModel(), ContactDataInterf
} }
private fun updateRemotesComposing() { private fun updateRemotesComposing() {
remoteIsComposing.value = chatRoom.isRemoteComposing val isComposing = chatRoom.isRemoteComposing
remoteIsComposing.value = isComposing
if (!isComposing) return
var composing = "" var composing = ""
for (address in chatRoom.composingAddresses) { for (address in chatRoom.composingAddresses) {
@ -415,20 +422,27 @@ class ChatRoomViewModel(val chatRoom: ChatRoom) : ViewModel(), ContactDataInterf
} }
private fun updateParticipants() { private fun updateParticipants() {
peerSipUri.value = if (oneToOneChatRoom && !chatRoom.hasCapability(ChatRoomCapabilities.Basic.toInt())) peerSipUri.value = if (oneToOneChatRoom && !basicChatRoom)
chatRoom.participants.firstOrNull()?.address?.asStringUriOnly() chatRoom.participants.firstOrNull()?.address?.asStringUriOnly()
?: chatRoom.peerAddress.asStringUriOnly() ?: chatRoom.peerAddress.asStringUriOnly()
else chatRoom.peerAddress.asStringUriOnly() else chatRoom.peerAddress.asStringUriOnly()
oneParticipantOneDevice = chatRoom.hasCapability(ChatRoomCapabilities.OneToOne.toInt()) && oneParticipantOneDevice = oneToOneChatRoom &&
chatRoom.me?.devices?.size == 1 && chatRoom.me?.devices?.size == 1 &&
chatRoom.participants.firstOrNull()?.devices?.size == 1 chatRoom.participants.firstOrNull()?.devices?.size == 1
addressToCall = if (chatRoom.hasCapability(ChatRoomCapabilities.Basic.toInt())) addressToCall = if (basicChatRoom)
chatRoom.peerAddress chatRoom.peerAddress
else else
chatRoom.participants.firstOrNull()?.address chatRoom.participants.firstOrNull()?.address
onlyParticipantOnlyDeviceAddress = chatRoom.participants.firstOrNull()?.devices?.firstOrNull()?.address onlyParticipantOnlyDeviceAddress = chatRoom.participants.firstOrNull()?.devices?.firstOrNull()?.address
} }
private fun updateUnreadMessageCount() {
val count = chatRoom.unreadMessagesCount
unreadMessagesCount.value = count
if (count > 0 && corePreferences.enableAnimations) bounceAnimator.start()
else if (count == 0 && bounceAnimator.isStarted) bounceAnimator.end()
}
} }

View file

@ -342,11 +342,15 @@ private suspend fun loadContactPictureWithCoil(
error( error(
if (contact.showGroupChatAvatar) { if (contact.showGroupChatAvatar) {
val bg = AppCompatResources.getDrawable(context, R.drawable.generated_avatar_bg) val bg = AppCompatResources.getDrawable(context, R.drawable.generated_avatar_bg)
withContext(Dispatchers.Main) {
imageView.background = bg imageView.background = bg
}
AppCompatResources.getDrawable(context, R.drawable.icon_multiple_contacts_avatar) AppCompatResources.getDrawable(context, R.drawable.icon_multiple_contacts_avatar)
} else if (displayName.isEmpty() || AppUtils.getInitials(displayName) == "+") { } else if (displayName.isEmpty() || AppUtils.getInitials(displayName) == "+") {
val bg = AppCompatResources.getDrawable(context, R.drawable.generated_avatar_bg) val bg = AppCompatResources.getDrawable(context, R.drawable.generated_avatar_bg)
withContext(Dispatchers.Main) {
imageView.background = bg imageView.background = bg
}
AppCompatResources.getDrawable(context, R.drawable.icon_single_contact_avatar) AppCompatResources.getDrawable(context, R.drawable.icon_single_contact_avatar)
} else { } else {
val builder = ContactAvatarGenerator(context) val builder = ContactAvatarGenerator(context)
@ -369,7 +373,9 @@ private suspend fun loadContactPictureWithCoil(
} }
} else { } else {
val bg = AppCompatResources.getDrawable(imageView.context, R.drawable.generated_avatar_bg) val bg = AppCompatResources.getDrawable(imageView.context, R.drawable.generated_avatar_bg)
withContext(Dispatchers.Main) {
imageView.background = bg imageView.background = bg
}
imageView.load(R.drawable.icon_single_contact_avatar) imageView.load(R.drawable.icon_single_contact_avatar)
} }
} }