From 170e4417445cf7cf7c254c60db9b342449a88dbd Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 19 Oct 2023 10:00:27 +0200 Subject: [PATCH] Trying to optimize the ContactAvatarModel use --- .../org/linphone/contacts/ContactsManager.kt | 39 +++++++++++ .../org/linphone/ui/call/model/CallModel.kt | 6 +- .../ui/call/viewmodel/CurrentCallViewModel.kt | 3 + .../fragment/StartConversationFragment.kt | 4 +- .../chat/model/ChatMessageDeliveryModel.kt | 12 ++-- .../ui/main/chat/model/ChatMessageModel.kt | 27 +------- .../ui/main/chat/model/ConversationModel.kt | 13 +--- .../ui/main/chat/model/ParticipantModel.kt | 8 +-- .../viewmodel/ConversationInfoViewModel.kt | 66 +++++-------------- .../chat/viewmodel/ConversationViewModel.kt | 56 +++++----------- .../viewmodel/StartConversationViewModel.kt | 5 +- .../main/contacts/model/ContactAvatarModel.kt | 10 ++- .../contacts/viewmodel/ContactViewModel.kt | 2 + .../viewmodel/ContactsListViewModel.kt | 1 + .../ui/main/history/model/CallLogModel.kt | 3 +- .../history/viewmodel/StartCallViewModel.kt | 5 +- .../main/meetings/model/ParticipantModel.kt | 10 +-- .../res/layout/chat_delivery_list_cell.xml | 12 ++-- .../res/layout/chat_participant_list_cell.xml | 12 ++-- 19 files changed, 127 insertions(+), 167 deletions(-) diff --git a/app/src/main/java/org/linphone/contacts/ContactsManager.kt b/app/src/main/java/org/linphone/contacts/ContactsManager.kt index f6161255f..9b22c4fd6 100644 --- a/app/src/main/java/org/linphone/contacts/ContactsManager.kt +++ b/app/src/main/java/org/linphone/contacts/ContactsManager.kt @@ -43,6 +43,7 @@ import org.linphone.core.FriendList import org.linphone.core.FriendListListenerStub import org.linphone.core.tools.Log import org.linphone.ui.main.MainActivity +import org.linphone.ui.main.contacts.model.ContactAvatarModel import org.linphone.ui.main.contacts.model.ContactNumberOrAddressClickListener import org.linphone.ui.main.contacts.model.ContactNumberOrAddressModel import org.linphone.ui.main.model.isInSecureMode @@ -61,12 +62,18 @@ class ContactsManager @UiThread constructor(context: Context) { private val listeners = arrayListOf() + private val avatarsMap = hashMapOf() + private val friendListListener: FriendListListenerStub = object : FriendListListenerStub() { @WorkerThread override fun onPresenceReceived(list: FriendList, friends: Array) { Log.i( "$TAG Presence received for list [${list.displayName}] and [${friends.size}] friends" ) + + avatarsMap.values.forEach(ContactAvatarModel::destroy) + avatarsMap.clear() + for (listener in listeners) { listener.onContactsLoaded() } @@ -127,6 +134,10 @@ class ContactsManager @UiThread constructor(context: Context) { @UiThread fun onNativeContactsLoaded() { nativeContactsLoaded = true + + avatarsMap.values.forEach(ContactAvatarModel::destroy) + avatarsMap.clear() + coreContext.postOnCoreThread { notifyContactsListChanged() } @@ -173,6 +184,34 @@ class ContactsManager @UiThread constructor(context: Context) { return findContactByAddress(address)?.name ?: LinphoneUtils.getDisplayName(address) } + @WorkerThread + fun getContactAvatarModelForAddress(address: Address?): ContactAvatarModel { + if (address == null) { + val fakeFriend = coreContext.core.createFriend() + return ContactAvatarModel(fakeFriend) + } + + val clone = address.clone() + clone.clean() + val key = clone.asStringUriOnly() + + val foundInMap = if (avatarsMap.keys.contains(key)) avatarsMap[key] else null + if (foundInMap != null) return foundInMap + + val friend = coreContext.contactsManager.findContactByAddress(clone) + val avatar = if (friend != null) { + ContactAvatarModel(friend) + } else { + val fakeFriend = coreContext.core.createFriend() + fakeFriend.address = clone + ContactAvatarModel(fakeFriend) + } + + avatarsMap[key] = avatar + + return avatar + } + @WorkerThread fun onCoreStarted(core: Core) { core.addListener(coreListener) diff --git a/app/src/main/java/org/linphone/ui/call/model/CallModel.kt b/app/src/main/java/org/linphone/ui/call/model/CallModel.kt index c4de2c22b..fe1a63d73 100644 --- a/app/src/main/java/org/linphone/ui/call/model/CallModel.kt +++ b/app/src/main/java/org/linphone/ui/call/model/CallModel.kt @@ -57,9 +57,9 @@ class CallModel @WorkerThread constructor(val call: Call) { call.addListener(callListener) displayName.postValue(friend?.name ?: LinphoneUtils.getDisplayName(call.remoteAddress)) - if (friend != null) { - contact.postValue(ContactAvatarModel(friend)) - } + contact.postValue( + coreContext.contactsManager.getContactAvatarModelForAddress(call.remoteAddress) + ) state.postValue(LinphoneUtils.callStateToString(call.state)) isPaused.postValue(LinphoneUtils.isCallPaused(call.state)) diff --git a/app/src/main/java/org/linphone/ui/call/viewmodel/CurrentCallViewModel.kt b/app/src/main/java/org/linphone/ui/call/viewmodel/CurrentCallViewModel.kt index 88b3b6849..9af83ced8 100644 --- a/app/src/main/java/org/linphone/ui/call/viewmodel/CurrentCallViewModel.kt +++ b/app/src/main/java/org/linphone/ui/call/viewmodel/CurrentCallViewModel.kt @@ -396,6 +396,7 @@ class CurrentCallViewModel @UiThread constructor() : ViewModel() { coreContext.postOnCoreThread { core -> core.removeListener(coreListener) + contact.value?.destroy() if (::currentCall.isInitialized) { currentCall.removeListener(callListener) @@ -712,6 +713,8 @@ class CurrentCallViewModel @UiThread constructor() : ViewModel() { @WorkerThread private fun configureCall(call: Call) { + contact.value?.destroy() + currentCall = call call.addListener(callListener) diff --git a/app/src/main/java/org/linphone/ui/main/chat/fragment/StartConversationFragment.kt b/app/src/main/java/org/linphone/ui/main/chat/fragment/StartConversationFragment.kt index 452827579..ff5233fb5 100644 --- a/app/src/main/java/org/linphone/ui/main/chat/fragment/StartConversationFragment.kt +++ b/app/src/main/java/org/linphone/ui/main/chat/fragment/StartConversationFragment.kt @@ -28,6 +28,7 @@ import androidx.annotation.WorkerThread import androidx.core.view.doOnPreDraw import androidx.lifecycle.ViewModelProvider import androidx.recyclerview.widget.LinearLayoutManager +import org.linphone.LinphoneApplication.Companion.coreContext import org.linphone.R import org.linphone.core.Address import org.linphone.core.Friend @@ -35,7 +36,6 @@ import org.linphone.core.tools.Log import org.linphone.databinding.StartChatFragmentBinding import org.linphone.ui.main.MainActivity import org.linphone.ui.main.chat.viewmodel.StartConversationViewModel -import org.linphone.ui.main.contacts.model.ContactAvatarModel import org.linphone.ui.main.fragment.GenericAddressPickerFragment import org.linphone.ui.main.history.adapter.ContactsAndSuggestionsListAdapter import org.linphone.ui.main.model.SelectedAddressModel @@ -132,7 +132,7 @@ class StartConversationFragment : GenericAddressPickerFragment() { @WorkerThread override fun onAddressSelected(address: Address, friend: Friend) { if (viewModel.multipleSelectionMode.value == true) { - val avatarModel = ContactAvatarModel(friend) + val avatarModel = coreContext.contactsManager.getContactAvatarModelForAddress(address) val model = SelectedAddressModel(address, avatarModel) { viewModel.removeAddressModelFromSelection(it) } diff --git a/app/src/main/java/org/linphone/ui/main/chat/model/ChatMessageDeliveryModel.kt b/app/src/main/java/org/linphone/ui/main/chat/model/ChatMessageDeliveryModel.kt index bb04024bc..eba841549 100644 --- a/app/src/main/java/org/linphone/ui/main/chat/model/ChatMessageDeliveryModel.kt +++ b/app/src/main/java/org/linphone/ui/main/chat/model/ChatMessageDeliveryModel.kt @@ -1,14 +1,18 @@ package org.linphone.ui.main.chat.model import androidx.annotation.WorkerThread -import org.linphone.core.Friend +import org.linphone.LinphoneApplication import org.linphone.core.ParticipantImdnState -import org.linphone.ui.main.contacts.model.ContactAvatarModel import org.linphone.utils.TimestampUtils class ChatMessageDeliveryModel @WorkerThread constructor( - friend: Friend, imdnState: ParticipantImdnState -) : ContactAvatarModel(friend) { +) { + val address = imdnState.participant.address + + val avatarModel = LinphoneApplication.coreContext.contactsManager.getContactAvatarModelForAddress( + address + ) + val time = TimestampUtils.toString(imdnState.stateChangeTime) } diff --git a/app/src/main/java/org/linphone/ui/main/chat/model/ChatMessageModel.kt b/app/src/main/java/org/linphone/ui/main/chat/model/ChatMessageModel.kt index b54093edb..ae5658920 100644 --- a/app/src/main/java/org/linphone/ui/main/chat/model/ChatMessageModel.kt +++ b/app/src/main/java/org/linphone/ui/main/chat/model/ChatMessageModel.kt @@ -28,7 +28,6 @@ import org.linphone.core.Address import org.linphone.core.ChatMessage import org.linphone.core.ChatMessageListenerStub import org.linphone.core.ChatMessageReaction -import org.linphone.core.ParticipantImdnState import org.linphone.core.tools.Log import org.linphone.ui.main.contacts.model.ContactAvatarModel import org.linphone.utils.Event @@ -133,30 +132,10 @@ class ChatMessageModel @WorkerThread constructor( private fun computeDeliveryStatus() { val list = arrayListOf() - for (participant in chatMessage.getParticipantsByImdnState(ChatMessage.State.Displayed)) { - list.add(getDeliveryModelForAddress(participant)) - } + /*for (participant in chatMessage.getParticipantsByImdnState(ChatMessage.State.Displayed)) { + list.add(ChatMessageDeliveryModel(participant)) + }*/ deliveryModels.postValue(list) } - - @WorkerThread - private fun getDeliveryModelForAddress(participantImdnState: ParticipantImdnState): ChatMessageDeliveryModel { - val address = participantImdnState.participant.address - Log.i("$TAG Looking for participant model with address [${address.asStringUriOnly()}]") - - val clone = address.clone() - clone.clean() - - val friend = coreContext.contactsManager.findContactByAddress(clone) - val avatar = if (friend != null) { - ChatMessageDeliveryModel(friend, participantImdnState) - } else { - val fakeFriend = coreContext.core.createFriend() - fakeFriend.address = clone - ChatMessageDeliveryModel(fakeFriend, participantImdnState) - } - - return avatar - } } 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 0b6157fd4..ff284e177 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 @@ -149,16 +149,9 @@ class ConversationModel @WorkerThread constructor(private val chatRoom: ChatRoom model.setPicturesFromFriends(friends) avatarModel.postValue(model) } else { - val friend = coreContext.contactsManager.findContactByAddress(address) - if (friend != null) { - val model = ContactAvatarModel(friend) - avatarModel.postValue(model) - } else { - val fakeFriend = coreContext.core.createFriend() - fakeFriend.address = address - val model = ContactAvatarModel(fakeFriend) - avatarModel.postValue(model) - } + avatarModel.postValue( + coreContext.contactsManager.getContactAvatarModelForAddress(address) + ) } isMuted.postValue(chatRoom.muted) diff --git a/app/src/main/java/org/linphone/ui/main/chat/model/ParticipantModel.kt b/app/src/main/java/org/linphone/ui/main/chat/model/ParticipantModel.kt index 61b1c49ec..102e78d5a 100644 --- a/app/src/main/java/org/linphone/ui/main/chat/model/ParticipantModel.kt +++ b/app/src/main/java/org/linphone/ui/main/chat/model/ParticipantModel.kt @@ -22,19 +22,19 @@ package org.linphone.ui.main.chat.model import android.view.View import androidx.annotation.UiThread import androidx.annotation.WorkerThread +import org.linphone.LinphoneApplication.Companion.coreContext import org.linphone.core.Address -import org.linphone.core.Friend -import org.linphone.ui.main.contacts.model.ContactAvatarModel class ParticipantModel @WorkerThread constructor( - friend: Friend, val address: Address, val isMyselfAdmin: Boolean, val isParticipantAdmin: Boolean, private val onMenuClicked: ((view: View, model: ParticipantModel) -> Unit)? = null -) : ContactAvatarModel(friend) { +) { val sipUri = address.asStringUriOnly() + val avatarModel = coreContext.contactsManager.getContactAvatarModelForAddress(address) + @UiThread fun openMenu(view: View) { onMenuClicked?.invoke(view, this) diff --git a/app/src/main/java/org/linphone/ui/main/chat/viewmodel/ConversationInfoViewModel.kt b/app/src/main/java/org/linphone/ui/main/chat/viewmodel/ConversationInfoViewModel.kt index 0b0cb6ec4..8626c2b20 100644 --- a/app/src/main/java/org/linphone/ui/main/chat/viewmodel/ConversationInfoViewModel.kt +++ b/app/src/main/java/org/linphone/ui/main/chat/viewmodel/ConversationInfoViewModel.kt @@ -25,7 +25,6 @@ import androidx.annotation.WorkerThread import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import org.linphone.LinphoneApplication.Companion.coreContext -import org.linphone.core.Address import org.linphone.core.ChatRoom import org.linphone.core.ChatRoomListenerStub import org.linphone.core.EventLog @@ -74,8 +73,6 @@ class ConversationInfoViewModel @UiThread constructor() : ViewModel() { private lateinit var chatRoom: ChatRoom - private val avatarsMap = hashMapOf() - private val chatRoomListener = object : ChatRoomListenerStub() { @WorkerThread override fun onParticipantAdded(chatRoom: ChatRoom, eventLog: EventLog) { @@ -122,9 +119,6 @@ class ConversationInfoViewModel @UiThread constructor() : ViewModel() { if (::chatRoom.isInitialized) { chatRoom.removeListener(chatRoomListener) } - - avatarModel.value?.destroy() - avatarsMap.values.forEach(ParticipantModel::destroy) } } @@ -285,71 +279,43 @@ class ConversationInfoViewModel @UiThread constructor() : ViewModel() { @WorkerThread private fun computeParticipantsList() { - avatarModel.value?.destroy() - avatarsMap.values.forEach(ParticipantModel::destroy) - val groupChatRoom = isChatRoomAGroup() + val selfAdmin = chatRoom.me?.isAdmin == true val friends = arrayListOf() val participantsList = arrayListOf() if (chatRoom.hasCapability(ChatRoom.Capabilities.Basic.toInt())) { - val model = getParticipantModelForAddress(chatRoom.peerAddress, false) - friends.add(model.friend) + val model = ParticipantModel(chatRoom.peerAddress, selfAdmin, false) { view, model -> + // openMenu + showParticipantAdminPopupMenuEvent.postValue(Event(Pair(view, model))) + } + friends.add(model.avatarModel.friend) participantsList.add(model) } else { for (participant in chatRoom.participants) { - val model = getParticipantModelForAddress( - participant.address, - if (groupChatRoom) participant.isAdmin else false - ) - friends.add(model.friend) + val isParticipantAdmin = if (groupChatRoom) participant.isAdmin else false + val model = ParticipantModel(participant.address, selfAdmin, isParticipantAdmin) { view, model -> + // openMenu + showParticipantAdminPopupMenuEvent.postValue(Event(Pair(view, model))) + } + friends.add(model.avatarModel.friend) participantsList.add(model) } } val avatar = if (groupChatRoom) { val fakeFriend = coreContext.core.createFriend() - ContactAvatarModel(fakeFriend) + val model = ContactAvatarModel(fakeFriend) + model.setPicturesFromFriends(friends) + model } else { - participantsList.first() + participantsList.first().avatarModel } - avatar.setPicturesFromFriends(friends) avatarModel.postValue(avatar) participants.postValue(participantsList) } - @WorkerThread - private fun getParticipantModelForAddress(address: Address, isAdmin: Boolean): ParticipantModel { - Log.i("$TAG Looking for participant model with address [${address?.asStringUriOnly()}]") - val selfAdmin = chatRoom.me?.isAdmin == true - - val clone = address.clone() - clone.clean() - val key = clone.asStringUriOnly() - - val foundInMap = if (avatarsMap.keys.contains(key)) avatarsMap[key] else null - if (foundInMap != null) return foundInMap - - val friend = coreContext.contactsManager.findContactByAddress(clone) - val avatar = if (friend != null) { - ParticipantModel(friend, clone, selfAdmin, isAdmin) { view, model -> - // openMenu - showParticipantAdminPopupMenuEvent.postValue(Event(Pair(view, model))) - } - } else { - val fakeFriend = coreContext.core.createFriend() - fakeFriend.address = clone - ParticipantModel(fakeFriend, clone, selfAdmin, isAdmin) { view, model -> - // openMenu - showParticipantAdminPopupMenuEvent.postValue(Event(Pair(view, model))) - } - } - - avatarsMap[key] = avatar - return avatar - } - @WorkerThread private fun isChatRoomAGroup(): Boolean { return if (::chatRoom.isInitialized) { 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 b9582eb47..012d8e55c 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 @@ -80,8 +80,6 @@ class ConversationViewModel @UiThread constructor() : ViewModel() { private lateinit var chatRoom: ChatRoom - private val avatarsMap = hashMapOf() - private val chatRoomListener = object : ChatRoomListenerStub() { @WorkerThread override fun onChatMessageSending(chatRoom: ChatRoom, eventLog: EventLog) { @@ -91,7 +89,9 @@ class ConversationViewModel @UiThread constructor() : ViewModel() { val list = arrayListOf() list.addAll(events.value.orEmpty()) - val avatarModel = getAvatarModelForAddress(message?.localAddress) + val avatarModel = coreContext.contactsManager.getContactAvatarModelForAddress( + message?.localAddress + ) val lastEvent = events.value.orEmpty().lastOrNull() val group = if (lastEvent != null) { shouldWeGroupTwoEvents(eventLog, lastEvent.eventLog) @@ -144,6 +144,7 @@ class ConversationViewModel @UiThread constructor() : ViewModel() { init { searchBarVisible.value = false + isEmojiPickerOpen.value = false } override fun onCleared() { @@ -151,9 +152,7 @@ class ConversationViewModel @UiThread constructor() : ViewModel() { coreContext.postOnCoreThread { chatRoom.removeListener(chatRoomListener) - avatarModel.value?.destroy() events.value.orEmpty().forEach(EventLogModel::destroy) - avatarsMap.values.forEach(ContactAvatarModel::destroy) } } @@ -300,11 +299,12 @@ class ConversationViewModel @UiThread constructor() : ViewModel() { val avatar = if (group) { val fakeFriend = coreContext.core.createFriend() - ContactAvatarModel(fakeFriend) + val model = ContactAvatarModel(fakeFriend) + model.setPicturesFromFriends(friends) + model } else { - getAvatarModelForAddress(address) + coreContext.contactsManager.getContactAvatarModelForAddress(address) } - avatar.setPicturesFromFriends(friends) avatarModel.postValue(avatar) computeEvents() @@ -329,7 +329,9 @@ class ConversationViewModel @UiThread constructor() : ViewModel() { // Handle all events in group, then re-start a new group with current item var index = 0 for (groupedEvent in groupedEventLogs) { - val avatar = getAvatarModelForAddress(groupedEvent.chatMessage?.fromAddress) + val avatar = coreContext.contactsManager.getContactAvatarModelForAddress( + groupedEvent.chatMessage?.fromAddress + ) val model = EventLogModel( groupedEvent, avatar, @@ -355,7 +357,9 @@ class ConversationViewModel @UiThread constructor() : ViewModel() { if (event.type == EventLog.Type.ConferenceChatMessage) { val message = event.chatMessage ?: continue val fromAddress = message.fromAddress - val model = getAvatarModelForAddress(fromAddress) + val model = coreContext.contactsManager.getContactAvatarModelForAddress( + fromAddress + ) if ( !model.name.value.orEmpty().contains(filter, ignoreCase = true) && !fromAddress.asStringUriOnly().contains(filter, ignoreCase = true) && @@ -407,40 +411,12 @@ class ConversationViewModel @UiThread constructor() : ViewModel() { } } - @WorkerThread - private fun getAvatarModelForAddress(address: Address?): ContactAvatarModel { - Log.i("$TAG Looking for avatar model with address [${address?.asStringUriOnly()}]") - if (address == null) { - val fakeFriend = coreContext.core.createFriend() - return ContactAvatarModel(fakeFriend) - } - - val clone = address.clone() - clone.clean() - val key = clone.asStringUriOnly() - - val foundInMap = if (avatarsMap.keys.contains(key)) avatarsMap[key] else null - if (foundInMap != null) return foundInMap - - val friend = coreContext.contactsManager.findContactByAddress(clone) - val avatar = if (friend != null) { - ContactAvatarModel(friend) - } else { - val fakeFriend = coreContext.core.createFriend() - fakeFriend.address = clone - ContactAvatarModel(fakeFriend) - } - - avatarsMap[key] = avatar - return avatar - } - @WorkerThread private fun computeComposingLabel() { - var composingFriends = arrayListOf() + val composingFriends = arrayListOf() var label = "" for (address in chatRoom.composingAddresses) { - val avatar = getAvatarModelForAddress(address) + val avatar = coreContext.contactsManager.getContactAvatarModelForAddress(address) val name = avatar.name.value ?: LinphoneUtils.getDisplayName(address) composingFriends.add(name) label += "$name, " 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 2c1453171..b3f2cd9cd 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 @@ -36,7 +36,6 @@ import org.linphone.core.MagicSearch import org.linphone.core.MagicSearchListenerStub import org.linphone.core.SearchResult import org.linphone.core.tools.Log -import org.linphone.ui.main.contacts.model.ContactAvatarModel import org.linphone.ui.main.history.model.ContactOrSuggestionModel import org.linphone.ui.main.model.isInSecureMode import org.linphone.ui.main.viewmodel.AddressSelectionViewModel @@ -356,7 +355,9 @@ class StartConversationViewModel @UiThread constructor() : AddressSelectionViewM val friend = coreContext.contactsManager.findContactByAddress(address) if (friend != null) { val model = ContactOrSuggestionModel(address, friend) - val avatarModel = ContactAvatarModel(friend) + val avatarModel = coreContext.contactsManager.getContactAvatarModelForAddress( + address + ) model.avatarModel.postValue(avatarModel) val currentLetter = friend.name?.get(0).toString() 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 469ebbac9..52134c221 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 @@ -36,7 +36,7 @@ import org.linphone.ui.main.model.isInSecureMode import org.linphone.utils.AppUtils import org.linphone.utils.TimestampUtils -open class ContactAvatarModel @WorkerThread constructor(val friend: Friend) : AbstractAvatarModel() { +class ContactAvatarModel @WorkerThread constructor(val friend: Friend) : AbstractAvatarModel() { companion object { private const val TAG = "[Contact Avatar Model]" } @@ -66,7 +66,9 @@ open class ContactAvatarModel @WorkerThread constructor(val friend: Friend) : Ab } init { - friend.addListener(friendListener) + if (friend.addresses.isNotEmpty()) { + friend.addListener(friendListener) + } initials.postValue(AppUtils.getInitials(friend.name.orEmpty())) trust.postValue(SecurityLevel.Encrypted) // TODO FIXME: use API @@ -79,7 +81,9 @@ open class ContactAvatarModel @WorkerThread constructor(val friend: Friend) : Ab @WorkerThread fun destroy() { - friend.removeListener(friendListener) + if (friend.addresses.isNotEmpty()) { + friend.removeListener(friendListener) + } } @WorkerThread diff --git a/app/src/main/java/org/linphone/ui/main/contacts/viewmodel/ContactViewModel.kt b/app/src/main/java/org/linphone/ui/main/contacts/viewmodel/ContactViewModel.kt index 50a20f56c..0263a52a9 100644 --- a/app/src/main/java/org/linphone/ui/main/contacts/viewmodel/ContactViewModel.kt +++ b/app/src/main/java/org/linphone/ui/main/contacts/viewmodel/ContactViewModel.kt @@ -160,6 +160,7 @@ class ContactViewModel @UiThread constructor() : ViewModel() { coreContext.postOnCoreThread { coreContext.contactsManager.removeListener(contactsListener) + contact.value?.destroy() } } @@ -183,6 +184,7 @@ class ContactViewModel @UiThread constructor() : ViewModel() { fun refreshContactInfo() { isFavourite.postValue(friend.starred) + contact.value?.destroy() contact.postValue(ContactAvatarModel(friend)) val organization = friend.organization diff --git a/app/src/main/java/org/linphone/ui/main/contacts/viewmodel/ContactsListViewModel.kt b/app/src/main/java/org/linphone/ui/main/contacts/viewmodel/ContactsListViewModel.kt index 3a2abad02..666560c3b 100644 --- a/app/src/main/java/org/linphone/ui/main/contacts/viewmodel/ContactsListViewModel.kt +++ b/app/src/main/java/org/linphone/ui/main/contacts/viewmodel/ContactsListViewModel.kt @@ -107,6 +107,7 @@ class ContactsListViewModel @UiThread constructor() : AbstractTopBarViewModel() coreContext.postOnCoreThread { magicSearch.removeListener(magicSearchListener) coreContext.contactsManager.removeListener(contactsListener) + contactsList.value.orEmpty().forEach(ContactAvatarModel::destroy) } super.onCleared() } diff --git a/app/src/main/java/org/linphone/ui/main/history/model/CallLogModel.kt b/app/src/main/java/org/linphone/ui/main/history/model/CallLogModel.kt index bb4a27cd5..d42433e11 100644 --- a/app/src/main/java/org/linphone/ui/main/history/model/CallLogModel.kt +++ b/app/src/main/java/org/linphone/ui/main/history/model/CallLogModel.kt @@ -43,15 +43,14 @@ class CallLogModel @WorkerThread constructor(private val callLog: CallLog) { dateTime.postValue(displayedDate) val friend = coreContext.contactsManager.findContactByAddress(address) + avatarModel = coreContext.contactsManager.getContactAvatarModelForAddress(address) if (friend != null) { friendRefKey = friend.refKey - avatarModel = ContactAvatarModel(friend) friendExists = true } else { val fakeFriend = coreContext.core.createFriend() fakeFriend.address = address friendRefKey = null - avatarModel = ContactAvatarModel(fakeFriend) friendExists = false } 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 e811a8afb..15c422b74 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 @@ -34,7 +34,6 @@ import org.linphone.core.MagicSearch import org.linphone.core.MagicSearchListenerStub import org.linphone.core.SearchResult import org.linphone.core.tools.Log -import org.linphone.ui.main.contacts.model.ContactAvatarModel import org.linphone.ui.main.history.model.ContactOrSuggestionModel import org.linphone.ui.main.history.model.NumpadModel import org.linphone.ui.main.model.isInSecureMode @@ -197,7 +196,9 @@ class StartCallViewModel @UiThread constructor() : ViewModel() { val friend = coreContext.contactsManager.findContactByAddress(address) if (friend != null) { val model = ContactOrSuggestionModel(address, friend) - val avatarModel = ContactAvatarModel(friend) + val avatarModel = coreContext.contactsManager.getContactAvatarModelForAddress( + address + ) model.avatarModel.postValue(avatarModel) val currentLetter = friend.name?.get(0).toString() diff --git a/app/src/main/java/org/linphone/ui/main/meetings/model/ParticipantModel.kt b/app/src/main/java/org/linphone/ui/main/meetings/model/ParticipantModel.kt index caec44af6..c15e18881 100644 --- a/app/src/main/java/org/linphone/ui/main/meetings/model/ParticipantModel.kt +++ b/app/src/main/java/org/linphone/ui/main/meetings/model/ParticipantModel.kt @@ -29,19 +29,11 @@ class ParticipantModel @WorkerThread constructor(address: Address, val isOrganiz val avatarModel = MutableLiveData() init { - val friend = coreContext.contactsManager.findContactByAddress(address) - val avatar = if (friend != null) { - ContactAvatarModel(friend) - } else { - val fakeFriend = coreContext.core.createFriend() - fakeFriend.address = address - ContactAvatarModel(fakeFriend) - } + val avatar = coreContext.contactsManager.getContactAvatarModelForAddress(address) avatarModel.postValue(avatar) } @WorkerThread fun destroy() { - avatarModel.value?.destroy() } } diff --git a/app/src/main/res/layout/chat_delivery_list_cell.xml b/app/src/main/res/layout/chat_delivery_list_cell.xml index b3d4fb556..4e99c4c10 100644 --- a/app/src/main/res/layout/chat_delivery_list_cell.xml +++ b/app/src/main/res/layout/chat_delivery_list_cell.xml @@ -26,7 +26,7 @@ android:layout_height="@dimen/avatar_list_cell_size" android:layout_marginTop="5dp" android:layout_marginBottom="5dp" - coilAvatar="@{model}" + coilAvatar="@{model.avatarModel}" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> @@ -38,8 +38,8 @@ android:layout_marginEnd="@dimen/avatar_presence_badge_end_margin" android:background="@drawable/led_background" android:padding="@dimen/avatar_presence_badge_padding" - app:presenceIcon="@{model.presenceStatus}" - android:visibility="@{model.presenceStatus == ConsolidatedPresence.Offline ? View.GONE : View.VISIBLE}" + app:presenceIcon="@{model.avatarModel.presenceStatus}" + android:visibility="@{model.avatarModel.presenceStatus == ConsolidatedPresence.Offline ? View.GONE : View.VISIBLE}" app:layout_constraintEnd_toEndOf="@id/avatar" app:layout_constraintBottom_toBottomOf="@id/avatar"/> @@ -47,8 +47,8 @@ android:id="@+id/trust_badge" android:layout_width="@dimen/avatar_presence_badge_size" android:layout_height="@dimen/avatar_presence_badge_size" - android:src="@{model.trust == SecurityLevel.Safe ? @drawable/trusted : @drawable/not_trusted, default=@drawable/trusted}" - android:visibility="@{model.trust == SecurityLevel.Safe || model.trust == SecurityLevel.Unsafe ? View.VISIBLE : View.GONE}" + android:src="@{model.avatarModel.trust == SecurityLevel.Safe ? @drawable/trusted : @drawable/not_trusted, default=@drawable/trusted}" + android:visibility="@{model.avatarModel.trust == SecurityLevel.Safe || model.avatarModel.trust == SecurityLevel.Unsafe ? View.VISIBLE : View.GONE}" app:layout_constraintStart_toStartOf="@id/avatar" app:layout_constraintBottom_toBottomOf="@id/avatar"/> @@ -57,7 +57,7 @@ android:id="@+id/name" android:layout_width="0dp" android:layout_height="wrap_content" - android:text="@{model.name, default=`John Doe`}" + android:text="@{model.avatarModel.name, default=`John Doe`}" android:textSize="14sp" android:layout_marginStart="10dp" app:layout_constraintVertical_chainStyle="packed" diff --git a/app/src/main/res/layout/chat_participant_list_cell.xml b/app/src/main/res/layout/chat_participant_list_cell.xml index bfbfbeb48..c32968e99 100644 --- a/app/src/main/res/layout/chat_participant_list_cell.xml +++ b/app/src/main/res/layout/chat_participant_list_cell.xml @@ -26,7 +26,7 @@ android:layout_height="@dimen/avatar_list_cell_size" android:layout_marginTop="5dp" android:layout_marginBottom="5dp" - coilAvatar="@{model}" + coilAvatar="@{model.avatarModel}" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> @@ -38,8 +38,8 @@ android:layout_marginEnd="@dimen/avatar_presence_badge_end_margin" android:background="@drawable/led_background" android:padding="@dimen/avatar_presence_badge_padding" - app:presenceIcon="@{model.presenceStatus}" - android:visibility="@{model.presenceStatus == ConsolidatedPresence.Offline ? View.GONE : View.VISIBLE}" + app:presenceIcon="@{model.avatarModel.presenceStatus}" + android:visibility="@{model.avatarModel.presenceStatus == ConsolidatedPresence.Offline ? View.GONE : View.VISIBLE}" app:layout_constraintEnd_toEndOf="@id/avatar" app:layout_constraintBottom_toBottomOf="@id/avatar"/> @@ -47,8 +47,8 @@ android:id="@+id/trust_badge" android:layout_width="@dimen/avatar_presence_badge_size" android:layout_height="@dimen/avatar_presence_badge_size" - android:src="@{model.trust == SecurityLevel.Safe ? @drawable/trusted : @drawable/not_trusted, default=@drawable/trusted}" - android:visibility="@{model.trust == SecurityLevel.Safe || model.trust == SecurityLevel.Unsafe ? View.VISIBLE : View.GONE}" + android:src="@{model.avatarModel.trust == SecurityLevel.Safe ? @drawable/trusted : @drawable/not_trusted, default=@drawable/trusted}" + android:visibility="@{model.avatarModel.trust == SecurityLevel.Safe || model.avatarModel.trust == SecurityLevel.Unsafe ? View.VISIBLE : View.GONE}" app:layout_constraintStart_toStartOf="@id/avatar" app:layout_constraintBottom_toBottomOf="@id/avatar"/> @@ -57,7 +57,7 @@ android:id="@+id/name" android:layout_width="0dp" android:layout_height="wrap_content" - android:text="@{model.name, default=`John Doe`}" + android:text="@{model.avatarModel.name, default=`John Doe`}" android:textSize="14sp" android:layout_marginStart="10dp" app:layout_constraintVertical_chainStyle="packed"