Proper fix for chat rooms blinking
This commit is contained in:
parent
8338ea8814
commit
31e30e6214
5 changed files with 81 additions and 55 deletions
|
@ -33,12 +33,11 @@ import org.linphone.activities.main.viewmodels.ListTopBarViewModel
|
|||
import org.linphone.core.ChatRoom
|
||||
import org.linphone.databinding.ChatRoomListCellBinding
|
||||
import org.linphone.utils.Event
|
||||
import org.linphone.utils.LinphoneUtils
|
||||
|
||||
class ChatRoomsListAdapter(
|
||||
selectionVM: ListTopBarViewModel,
|
||||
private val viewLifecycleOwner: LifecycleOwner
|
||||
) : SelectionListAdapter<ChatRoom, RecyclerView.ViewHolder>(selectionVM, ChatRoomDiffCallback()) {
|
||||
) : SelectionListAdapter<ChatRoomData, RecyclerView.ViewHolder>(selectionVM, ChatRoomDiffCallback()) {
|
||||
val selectedChatRoomEvent: MutableLiveData<Event<ChatRoom>> by lazy {
|
||||
MutableLiveData<Event<ChatRoom>>()
|
||||
}
|
||||
|
@ -57,11 +56,6 @@ class ChatRoomsListAdapter(
|
|||
(holder as ViewHolder).bind(getItem(position))
|
||||
}
|
||||
|
||||
override fun getItemId(position: Int): Long {
|
||||
val room = getItem(position)
|
||||
return LinphoneUtils.getChatRoomId(room).hashCode().toLong()
|
||||
}
|
||||
|
||||
fun forwardPending(pending: Boolean) {
|
||||
isForwardPending = pending
|
||||
notifyItemRangeChanged(0, itemCount)
|
||||
|
@ -70,9 +64,10 @@ class ChatRoomsListAdapter(
|
|||
inner class ViewHolder(
|
||||
private val binding: ChatRoomListCellBinding
|
||||
) : RecyclerView.ViewHolder(binding.root) {
|
||||
fun bind(chatRoom: ChatRoom) {
|
||||
fun bind(chatRoomData: ChatRoomData) {
|
||||
with(binding) {
|
||||
data = ChatRoomData(chatRoom)
|
||||
chatRoomData.update()
|
||||
data = chatRoomData
|
||||
|
||||
lifecycleOwner = viewLifecycleOwner
|
||||
|
||||
|
@ -90,7 +85,7 @@ class ChatRoomsListAdapter(
|
|||
if (selectionViewModel.isEditionEnabled.value == true) {
|
||||
selectionViewModel.onToggleSelect(bindingAdapterPosition)
|
||||
} else {
|
||||
selectedChatRoomEvent.value = Event(chatRoom)
|
||||
selectedChatRoomEvent.value = Event(chatRoomData.chatRoom)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -109,17 +104,17 @@ class ChatRoomsListAdapter(
|
|||
}
|
||||
}
|
||||
|
||||
private class ChatRoomDiffCallback : DiffUtil.ItemCallback<ChatRoom>() {
|
||||
private class ChatRoomDiffCallback : DiffUtil.ItemCallback<ChatRoomData>() {
|
||||
override fun areItemsTheSame(
|
||||
oldItem: ChatRoom,
|
||||
newItem: ChatRoom
|
||||
oldItem: ChatRoomData,
|
||||
newItem: ChatRoomData
|
||||
): Boolean {
|
||||
return oldItem == newItem
|
||||
return oldItem.id == newItem.id
|
||||
}
|
||||
|
||||
override fun areContentsTheSame(
|
||||
oldItem: ChatRoom,
|
||||
newItem: ChatRoom
|
||||
oldItem: ChatRoomData,
|
||||
newItem: ChatRoomData
|
||||
): Boolean {
|
||||
return false // To force redraw
|
||||
}
|
||||
|
|
|
@ -31,13 +31,14 @@ import org.linphone.LinphoneApplication.Companion.coreContext
|
|||
import org.linphone.LinphoneApplication.Companion.corePreferences
|
||||
import org.linphone.R
|
||||
import org.linphone.contact.ContactDataInterface
|
||||
import org.linphone.contact.ContactsUpdatedListenerStub
|
||||
import org.linphone.core.*
|
||||
import org.linphone.core.tools.Log
|
||||
import org.linphone.utils.AppUtils
|
||||
import org.linphone.utils.LinphoneUtils
|
||||
import org.linphone.utils.TimestampUtils
|
||||
|
||||
class ChatRoomData(private val chatRoom: ChatRoom) : ContactDataInterface {
|
||||
class ChatRoomData(val chatRoom: ChatRoom) : ContactDataInterface {
|
||||
override val contact: MutableLiveData<Friend> = MutableLiveData<Friend>()
|
||||
override val displayName: MutableLiveData<String> = MutableLiveData<String>()
|
||||
override val securityLevel: MutableLiveData<ChatRoomSecurityLevel> = MutableLiveData<ChatRoomSecurityLevel>()
|
||||
|
@ -46,6 +47,8 @@ class ChatRoomData(private val chatRoom: ChatRoom) : ContactDataInterface {
|
|||
override val presenceStatus: MutableLiveData<ConsolidatedPresence> = MutableLiveData<ConsolidatedPresence>()
|
||||
override val coroutineScope: CoroutineScope = coreContext.coroutineScope
|
||||
|
||||
val id = LinphoneUtils.getChatRoomId(chatRoom)
|
||||
|
||||
val unreadMessagesCount = MutableLiveData<Int>()
|
||||
|
||||
val subject = MutableLiveData<String>()
|
||||
|
@ -82,7 +85,26 @@ class ChatRoomData(private val chatRoom: ChatRoom) : ContactDataInterface {
|
|||
chatRoom.hasCapability(ChatRoomCapabilities.Encrypted.toInt())
|
||||
}
|
||||
|
||||
private val contactsListener = object : ContactsUpdatedListenerStub() {
|
||||
override fun onContactsUpdated() {
|
||||
if (oneToOneChatRoom && contact.value == null) {
|
||||
searchMatchingContact()
|
||||
if (contact.value != null) {
|
||||
formatLastMessage(chatRoom.lastMessageInHistory)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
coreContext.contactsManager.addListener(contactsListener)
|
||||
}
|
||||
|
||||
fun destroy() {
|
||||
coreContext.contactsManager.removeListener(contactsListener)
|
||||
}
|
||||
|
||||
fun update() {
|
||||
unreadMessagesCount.value = chatRoom.unreadMessagesCount
|
||||
presenceStatus.value = ConsolidatedPresence.Offline
|
||||
|
||||
|
@ -96,6 +118,11 @@ class ChatRoomData(private val chatRoom: ChatRoom) : ContactDataInterface {
|
|||
notificationsMuted.value = areNotificationsMuted()
|
||||
}
|
||||
|
||||
fun markAsRead() {
|
||||
chatRoom.markAsRead()
|
||||
unreadMessagesCount.value = 0
|
||||
}
|
||||
|
||||
private fun updateSecurityIcon() {
|
||||
val level = chatRoom.securityLevel
|
||||
securityLevel.value = level
|
||||
|
@ -133,8 +160,9 @@ class ChatRoomData(private val chatRoom: ChatRoom) : ContactDataInterface {
|
|||
val remoteAddress = if (basicChatRoom) {
|
||||
chatRoom.peerAddress
|
||||
} else {
|
||||
if (chatRoom.participants.isNotEmpty()) {
|
||||
chatRoom.participants[0].address
|
||||
val participants = chatRoom.participants
|
||||
if (participants.isNotEmpty()) {
|
||||
participants.first().address
|
||||
} else {
|
||||
Log.e("[Chat Room] ${chatRoom.peerAddress} doesn't have any participant (state ${chatRoom.state})!")
|
||||
null
|
||||
|
|
|
@ -156,7 +156,6 @@ class MasterChatRoomsFragment : MasterFragment<ChatRoomMasterFragmentBinding, Ch
|
|||
_adapter = ChatRoomsListAdapter(listSelectionViewModel, viewLifecycleOwner)
|
||||
// SubmitList is done on a background thread
|
||||
// We need this adapter data observer to know when to scroll
|
||||
adapter.setHasStableIds(true)
|
||||
adapter.registerAdapterDataObserver(observer)
|
||||
|
||||
binding.chatList.setHasFixedSize(true)
|
||||
|
@ -185,9 +184,8 @@ class MasterChatRoomsFragment : MasterFragment<ChatRoomMasterFragmentBinding, Ch
|
|||
if (index < 0 || index >= adapter.currentList.size) {
|
||||
Log.e("[Chat] Index is out of bound, can't mark chat room as read")
|
||||
} else {
|
||||
val chatRoom = adapter.currentList[viewHolder.bindingAdapterPosition]
|
||||
chatRoom.markAsRead()
|
||||
adapter.notifyItemChanged(viewHolder.bindingAdapterPosition)
|
||||
val data = adapter.currentList[viewHolder.bindingAdapterPosition]
|
||||
data.markAsRead()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -209,7 +207,7 @@ class MasterChatRoomsFragment : MasterFragment<ChatRoomMasterFragmentBinding, Ch
|
|||
viewModel.showDeleteButton(
|
||||
{
|
||||
val deletedChatRoom =
|
||||
adapter.currentList[index]
|
||||
adapter.currentList[index].chatRoom
|
||||
listViewModel.deleteChatRoom(deletedChatRoom)
|
||||
if (!binding.slidingPane.isSlideable &&
|
||||
deletedChatRoom == sharedViewModel.selectedChatRoom.value
|
||||
|
@ -382,7 +380,7 @@ class MasterChatRoomsFragment : MasterFragment<ChatRoomMasterFragmentBinding, Ch
|
|||
val list = ArrayList<ChatRoom>()
|
||||
var closeSlidingPane = false
|
||||
for (index in indexesOfItemToDelete) {
|
||||
val chatRoom = adapter.currentList[index]
|
||||
val chatRoom = adapter.currentList[index].chatRoom
|
||||
list.add(chatRoom)
|
||||
|
||||
if (chatRoom == sharedViewModel.selectedChatRoom.value) {
|
||||
|
|
|
@ -22,16 +22,16 @@ package org.linphone.activities.main.chat.viewmodels
|
|||
import androidx.lifecycle.MutableLiveData
|
||||
import org.linphone.LinphoneApplication.Companion.coreContext
|
||||
import org.linphone.R
|
||||
import org.linphone.activities.main.chat.data.ChatRoomData
|
||||
import org.linphone.activities.main.viewmodels.MessageNotifierViewModel
|
||||
import org.linphone.compatibility.Compatibility
|
||||
import org.linphone.contact.ContactsUpdatedListenerStub
|
||||
import org.linphone.core.*
|
||||
import org.linphone.core.tools.Log
|
||||
import org.linphone.utils.Event
|
||||
import org.linphone.utils.LinphoneUtils
|
||||
|
||||
class ChatRoomsListViewModel : MessageNotifierViewModel() {
|
||||
val chatRooms = MutableLiveData<ArrayList<ChatRoom>>()
|
||||
val chatRooms = MutableLiveData<ArrayList<ChatRoomData>>()
|
||||
|
||||
val fileSharingPending = MutableLiveData<Boolean>()
|
||||
|
||||
|
@ -45,10 +45,31 @@ class ChatRoomsListViewModel : MessageNotifierViewModel() {
|
|||
MutableLiveData<Event<Int>>()
|
||||
}
|
||||
|
||||
private val chatRoomListener = object : ChatRoomListenerStub() {
|
||||
override fun onStateChanged(chatRoom: ChatRoom, newState: ChatRoom.State) {
|
||||
if (newState == ChatRoom.State.Deleted) {
|
||||
Log.i("[Chat Rooms] Chat room [${LinphoneUtils.getChatRoomId(chatRoom)}] is in Deleted state, removing it from list")
|
||||
val list = arrayListOf<ChatRoomData>()
|
||||
val id = LinphoneUtils.getChatRoomId(chatRoom)
|
||||
for (data in chatRooms.value.orEmpty()) {
|
||||
if (data.id != id) {
|
||||
list.add(data)
|
||||
}
|
||||
}
|
||||
chatRooms.value = list
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val listener: CoreListenerStub = object : CoreListenerStub() {
|
||||
override fun onChatRoomStateChanged(core: Core, chatRoom: ChatRoom, state: ChatRoom.State) {
|
||||
if (state == ChatRoom.State.Created) {
|
||||
updateChatRooms()
|
||||
Log.i("[Chat Rooms] Chat room [${LinphoneUtils.getChatRoomId(chatRoom)}] is in Created state, adding it to list")
|
||||
val data = ChatRoomData(chatRoom)
|
||||
val list = arrayListOf<ChatRoomData>()
|
||||
list.add(data)
|
||||
list.addAll(chatRooms.value.orEmpty())
|
||||
chatRooms.value = list
|
||||
} else if (state == ChatRoom.State.TerminationFailed) {
|
||||
Log.e("[Chat Rooms] Group chat room removal for address ${chatRoom.peerAddress.asStringUriOnly()} has failed !")
|
||||
onMessageToNotifyEvent.value = Event(R.string.chat_room_removal_failed_snack)
|
||||
|
@ -80,31 +101,15 @@ class ChatRoomsListViewModel : MessageNotifierViewModel() {
|
|||
}
|
||||
}
|
||||
|
||||
private val chatRoomListener = object : ChatRoomListenerStub() {
|
||||
override fun onStateChanged(chatRoom: ChatRoom, newState: ChatRoom.State) {
|
||||
if (newState == ChatRoom.State.Deleted) {
|
||||
updateChatRooms()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val contactsListener = object : ContactsUpdatedListenerStub() {
|
||||
override fun onContactsUpdated() {
|
||||
updateChatRooms()
|
||||
}
|
||||
}
|
||||
|
||||
private var chatRoomsToDeleteCount = 0
|
||||
|
||||
init {
|
||||
groupChatAvailable.value = LinphoneUtils.isGroupChatAvailable()
|
||||
updateChatRooms()
|
||||
coreContext.core.addListener(listener)
|
||||
coreContext.contactsManager.addListener(contactsListener)
|
||||
}
|
||||
|
||||
override fun onCleared() {
|
||||
coreContext.contactsManager.removeListener(contactsListener)
|
||||
coreContext.core.removeListener(listener)
|
||||
|
||||
super.onCleared()
|
||||
|
@ -139,8 +144,12 @@ class ChatRoomsListViewModel : MessageNotifierViewModel() {
|
|||
}
|
||||
|
||||
fun updateChatRooms() {
|
||||
val list = arrayListOf<ChatRoom>()
|
||||
list.addAll(coreContext.core.chatRooms)
|
||||
chatRooms.value.orEmpty().forEach(ChatRoomData::destroy)
|
||||
|
||||
val list = arrayListOf<ChatRoomData>()
|
||||
for (chatRoom in coreContext.core.chatRooms) {
|
||||
list.add(ChatRoomData(chatRoom))
|
||||
}
|
||||
chatRooms.value = list
|
||||
}
|
||||
|
||||
|
@ -151,15 +160,16 @@ class ChatRoomsListViewModel : MessageNotifierViewModel() {
|
|||
}
|
||||
|
||||
private fun reorderChatRooms() {
|
||||
val list = arrayListOf<ChatRoom>()
|
||||
val list = arrayListOf<ChatRoomData>()
|
||||
list.addAll(chatRooms.value.orEmpty())
|
||||
list.sortByDescending { chatRoom -> chatRoom.lastUpdateTime }
|
||||
list.sortByDescending { data -> data.chatRoom.lastUpdateTime }
|
||||
chatRooms.value = list
|
||||
}
|
||||
|
||||
private fun findChatRoomIndex(chatRoom: ChatRoom): Int {
|
||||
for ((index, cr) in chatRooms.value.orEmpty().withIndex()) {
|
||||
if (LinphoneUtils.areChatRoomsTheSame(cr, chatRoom)) {
|
||||
val id = LinphoneUtils.getChatRoomId(chatRoom)
|
||||
for ((index, data) in chatRooms.value.orEmpty().withIndex()) {
|
||||
if (id == data.id) {
|
||||
return index
|
||||
}
|
||||
}
|
||||
|
|
|
@ -224,11 +224,6 @@ class LinphoneUtils {
|
|||
)
|
||||
}
|
||||
|
||||
fun areChatRoomsTheSame(chatRoom1: ChatRoom, chatRoom2: ChatRoom): Boolean {
|
||||
return chatRoom1.localAddress.weakEqual(chatRoom2.localAddress) &&
|
||||
chatRoom1.peerAddress.weakEqual(chatRoom2.peerAddress)
|
||||
}
|
||||
|
||||
fun getChatRoomId(room: ChatRoom): String {
|
||||
return getChatRoomId(room.localAddress, room.peerAddress)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue