Should improve scrolling performances in conversation
This commit is contained in:
parent
e2a04f2e95
commit
5cf34edc07
7 changed files with 107 additions and 74 deletions
|
@ -36,6 +36,7 @@ import org.linphone.R
|
|||
import org.linphone.activities.main.adapters.SelectionListAdapter
|
||||
import org.linphone.activities.main.chat.data.ChatMessageData
|
||||
import org.linphone.activities.main.chat.data.EventData
|
||||
import org.linphone.activities.main.chat.data.EventLogData
|
||||
import org.linphone.activities.main.chat.data.OnContentClickedListener
|
||||
import org.linphone.activities.main.viewmodels.ListTopBarViewModel
|
||||
import org.linphone.core.ChatMessage
|
||||
|
@ -51,7 +52,7 @@ import org.linphone.utils.Event
|
|||
class ChatMessagesListAdapter(
|
||||
selectionVM: ListTopBarViewModel,
|
||||
private val viewLifecycleOwner: LifecycleOwner
|
||||
) : SelectionListAdapter<EventLog, RecyclerView.ViewHolder>(selectionVM, ChatMessageDiffCallback()) {
|
||||
) : SelectionListAdapter<EventLogData, RecyclerView.ViewHolder>(selectionVM, ChatMessageDiffCallback()) {
|
||||
companion object {
|
||||
const val MAX_TIME_TO_GROUP_MESSAGES = 60 // 1 minute
|
||||
}
|
||||
|
@ -127,7 +128,7 @@ class ChatMessagesListAdapter(
|
|||
|
||||
override fun getItemViewType(position: Int): Int {
|
||||
val eventLog = getItem(position)
|
||||
return eventLog.type.toInt()
|
||||
return eventLog.eventLog.type.toInt()
|
||||
}
|
||||
|
||||
fun disableContextMenu() {
|
||||
|
@ -137,12 +138,13 @@ class ChatMessagesListAdapter(
|
|||
inner class ChatMessageViewHolder(
|
||||
val binding: ChatMessageListCellBinding
|
||||
) : RecyclerView.ViewHolder(binding.root) {
|
||||
fun bind(eventLog: EventLog) {
|
||||
fun bind(eventLog: EventLogData) {
|
||||
with(binding) {
|
||||
if (eventLog.type == EventLog.Type.ConferenceChatMessage) {
|
||||
val chatMessage = eventLog.chatMessage
|
||||
chatMessage ?: return
|
||||
val chatMessageViewModel = ChatMessageData(chatMessage, contentClickedListener)
|
||||
if (eventLog.eventLog.type == EventLog.Type.ConferenceChatMessage) {
|
||||
val chatMessageViewModel = eventLog.data as ChatMessageData
|
||||
chatMessageViewModel.setContentClickListener(contentClickedListener)
|
||||
|
||||
val chatMessage = chatMessageViewModel.chatMessage
|
||||
data = chatMessageViewModel
|
||||
|
||||
lifecycleOwner = viewLifecycleOwner
|
||||
|
@ -165,8 +167,8 @@ class ChatMessagesListAdapter(
|
|||
|
||||
if (adapterPosition > 0) {
|
||||
val previousItem = getItem(adapterPosition - 1)
|
||||
if (previousItem.type == EventLog.Type.ConferenceChatMessage) {
|
||||
val previousMessage = previousItem.chatMessage
|
||||
if (previousItem.eventLog.type == EventLog.Type.ConferenceChatMessage) {
|
||||
val previousMessage = previousItem.eventLog.chatMessage
|
||||
if (previousMessage != null && previousMessage.fromAddress.weakEqual(chatMessage.fromAddress)) {
|
||||
if (chatMessage.time - previousMessage.time < MAX_TIME_TO_GROUP_MESSAGES) {
|
||||
hasPrevious = true
|
||||
|
@ -177,8 +179,8 @@ class ChatMessagesListAdapter(
|
|||
|
||||
if (adapterPosition >= 0 && adapterPosition < itemCount - 1) {
|
||||
val nextItem = getItem(adapterPosition + 1)
|
||||
if (nextItem.type == EventLog.Type.ConferenceChatMessage) {
|
||||
val nextMessage = nextItem.chatMessage
|
||||
if (nextItem.eventLog.type == EventLog.Type.ConferenceChatMessage) {
|
||||
val nextMessage = nextItem.eventLog.chatMessage
|
||||
if (nextMessage != null && nextMessage.fromAddress.weakEqual(chatMessage.fromAddress)) {
|
||||
if (nextMessage.time - chatMessage.time < MAX_TIME_TO_GROUP_MESSAGES) {
|
||||
hasNext = true
|
||||
|
@ -319,9 +321,9 @@ class ChatMessagesListAdapter(
|
|||
inner class EventViewHolder(
|
||||
private val binding: ChatEventListCellBinding
|
||||
) : RecyclerView.ViewHolder(binding.root) {
|
||||
fun bind(eventLog: EventLog) {
|
||||
fun bind(eventLog: EventLogData) {
|
||||
with(binding) {
|
||||
val eventViewModel = EventData(eventLog)
|
||||
val eventViewModel = eventLog.data as EventData
|
||||
data = eventViewModel
|
||||
|
||||
binding.lifecycleOwner = viewLifecycleOwner
|
||||
|
@ -344,24 +346,24 @@ class ChatMessagesListAdapter(
|
|||
}
|
||||
}
|
||||
|
||||
private class ChatMessageDiffCallback : DiffUtil.ItemCallback<EventLog>() {
|
||||
private class ChatMessageDiffCallback : DiffUtil.ItemCallback<EventLogData>() {
|
||||
override fun areItemsTheSame(
|
||||
oldItem: EventLog,
|
||||
newItem: EventLog
|
||||
oldItem: EventLogData,
|
||||
newItem: EventLogData
|
||||
): Boolean {
|
||||
return if (oldItem.type == EventLog.Type.ConferenceChatMessage &&
|
||||
newItem.type == EventLog.Type.ConferenceChatMessage) {
|
||||
oldItem.chatMessage?.time == newItem.chatMessage?.time &&
|
||||
oldItem.chatMessage?.isOutgoing == newItem.chatMessage?.isOutgoing
|
||||
} else oldItem.notifyId == newItem.notifyId
|
||||
return if (oldItem.eventLog.type == EventLog.Type.ConferenceChatMessage &&
|
||||
newItem.eventLog.type == EventLog.Type.ConferenceChatMessage) {
|
||||
oldItem.eventLog.chatMessage?.time == newItem.eventLog.chatMessage?.time &&
|
||||
oldItem.eventLog.chatMessage?.isOutgoing == newItem.eventLog.chatMessage?.isOutgoing
|
||||
} else oldItem.eventLog.notifyId == newItem.eventLog.notifyId
|
||||
}
|
||||
|
||||
override fun areContentsTheSame(
|
||||
oldItem: EventLog,
|
||||
newItem: EventLog
|
||||
oldItem: EventLogData,
|
||||
newItem: EventLogData
|
||||
): Boolean {
|
||||
return if (newItem.type == EventLog.Type.ConferenceChatMessage) {
|
||||
newItem.chatMessage?.state == ChatMessage.State.Displayed
|
||||
} else false
|
||||
return if (newItem.eventLog.type == EventLog.Type.ConferenceChatMessage) {
|
||||
newItem.eventLog.chatMessage?.state == ChatMessage.State.Displayed
|
||||
} else true
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,8 +39,10 @@ import org.linphone.utils.ImageUtils
|
|||
class ChatMessageContentData(
|
||||
private val chatMessage: ChatMessage,
|
||||
private val contentIndex: Int,
|
||||
private val listener: OnContentClickedListener?
|
||||
|
||||
) {
|
||||
var listener: OnContentClickedListener? = null
|
||||
|
||||
val isImage = MutableLiveData<Boolean>()
|
||||
val isVideo = MutableLiveData<Boolean>()
|
||||
val isAudio = MutableLiveData<Boolean>()
|
||||
|
|
|
@ -31,10 +31,9 @@ import org.linphone.core.ChatMessageListenerStub
|
|||
import org.linphone.utils.AppUtils
|
||||
import org.linphone.utils.TimestampUtils
|
||||
|
||||
class ChatMessageData(
|
||||
val chatMessage: ChatMessage,
|
||||
class ChatMessageData(val chatMessage: ChatMessage) : GenericContactData(chatMessage.fromAddress) {
|
||||
private var contentListener: OnContentClickedListener? = null
|
||||
) : GenericContactData(chatMessage.fromAddress) {
|
||||
|
||||
val sendInProgress = MutableLiveData<Boolean>()
|
||||
|
||||
val transferInProgress = MutableLiveData<Boolean>()
|
||||
|
@ -120,6 +119,14 @@ class ChatMessageData(
|
|||
}
|
||||
}
|
||||
|
||||
fun setContentClickListener(listener: OnContentClickedListener) {
|
||||
contentListener = listener
|
||||
|
||||
for (data in contents.value.orEmpty()) {
|
||||
data.listener = listener
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateChatMessageState(state: ChatMessage.State) {
|
||||
transferInProgress.value = state == ChatMessage.State.FileTransferInProgress
|
||||
|
||||
|
@ -145,7 +152,9 @@ class ChatMessageData(
|
|||
for (index in 0 until contentsList.size) {
|
||||
val content = contentsList[index]
|
||||
if (content.isFileTransfer || content.isFile) {
|
||||
list.add(ChatMessageContentData(chatMessage, index, contentListener))
|
||||
val data = ChatMessageContentData(chatMessage, index)
|
||||
data.listener = contentListener
|
||||
list.add(data)
|
||||
} else if (content.isText) {
|
||||
val spannable = Spannable.Factory.getInstance().newSpannable(content.utf8Text)
|
||||
LinkifyCompat.addLinks(spannable, Linkify.WEB_URLS)
|
||||
|
|
|
@ -23,12 +23,19 @@ import android.content.Context
|
|||
import androidx.lifecycle.MutableLiveData
|
||||
import org.linphone.LinphoneApplication.Companion.coreContext
|
||||
import org.linphone.R
|
||||
import org.linphone.contact.Contact
|
||||
import org.linphone.contact.GenericContactData
|
||||
import org.linphone.core.EventLog
|
||||
import org.linphone.core.tools.Log
|
||||
import org.linphone.utils.LinphoneUtils
|
||||
|
||||
class EventData(private val eventLog: EventLog) {
|
||||
class EventData(private val eventLog: EventLog) : GenericContactData(
|
||||
if (eventLog.type == EventLog.Type.ConferenceSecurityEvent) {
|
||||
eventLog.securityEventFaultyDeviceAddress!!
|
||||
} else {
|
||||
if (eventLog.participantAddress == null) {
|
||||
eventLog.peerAddress!!
|
||||
} else {
|
||||
eventLog.participantAddress!!
|
||||
}
|
||||
}) {
|
||||
val text = MutableLiveData<String>()
|
||||
|
||||
val isSecurity: Boolean by lazy {
|
||||
|
@ -38,32 +45,12 @@ class EventData(private val eventLog: EventLog) {
|
|||
}
|
||||
}
|
||||
|
||||
private val contact: Contact? by lazy {
|
||||
val address = eventLog.participantAddress ?: eventLog.securityEventFaultyDeviceAddress
|
||||
if (address != null) {
|
||||
coreContext.contactsManager.findContactByAddress(address)
|
||||
} else {
|
||||
Log.e("[Event ViewModel] Unexpected null address for event $eventLog")
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
private val displayName: String by lazy {
|
||||
val address = eventLog.participantAddress ?: eventLog.securityEventFaultyDeviceAddress
|
||||
if (address != null) {
|
||||
LinphoneUtils.getDisplayName(address)
|
||||
} else {
|
||||
Log.e("[Event ViewModel] Unexpected null address for event $eventLog")
|
||||
""
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
updateEventText()
|
||||
}
|
||||
|
||||
private fun getName(): String {
|
||||
return contact?.fullName ?: displayName
|
||||
return contact.value?.fullName ?: displayName
|
||||
}
|
||||
|
||||
private fun updateEventText() {
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2021 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.linphone.activities.main.chat.data
|
||||
|
||||
import org.linphone.contact.GenericContactData
|
||||
import org.linphone.core.EventLog
|
||||
|
||||
class EventLogData(val eventLog: EventLog) {
|
||||
val data: GenericContactData = if (eventLog.type == EventLog.Type.ConferenceChatMessage) {
|
||||
ChatMessageData(eventLog.chatMessage!!)
|
||||
} else {
|
||||
EventData(eventLog)
|
||||
}
|
||||
}
|
|
@ -47,6 +47,7 @@ import org.linphone.activities.*
|
|||
import org.linphone.activities.main.MainActivity
|
||||
import org.linphone.activities.main.chat.ChatScrollListener
|
||||
import org.linphone.activities.main.chat.adapters.ChatMessagesListAdapter
|
||||
import org.linphone.activities.main.chat.data.EventLogData
|
||||
import org.linphone.activities.main.chat.viewmodels.*
|
||||
import org.linphone.activities.main.fragments.MasterFragment
|
||||
import org.linphone.activities.main.viewmodels.DialogViewModel
|
||||
|
@ -345,7 +346,7 @@ class DetailChatRoomFragment : MasterFragment<ChatRoomDetailFragmentBinding, Cha
|
|||
}
|
||||
|
||||
override fun deleteItems(indexesOfItemToDelete: ArrayList<Int>) {
|
||||
val list = ArrayList<EventLog>()
|
||||
val list = ArrayList<EventLogData>()
|
||||
for (index in indexesOfItemToDelete) {
|
||||
val eventLog = adapter.currentList[index]
|
||||
list.add(eventLog)
|
||||
|
|
|
@ -24,6 +24,7 @@ import androidx.lifecycle.ViewModel
|
|||
import androidx.lifecycle.ViewModelProvider
|
||||
import java.util.*
|
||||
import org.linphone.LinphoneApplication.Companion.coreContext
|
||||
import org.linphone.activities.main.chat.data.EventLogData
|
||||
import org.linphone.core.*
|
||||
import org.linphone.core.tools.Log
|
||||
import org.linphone.mediastream.Version
|
||||
|
@ -45,7 +46,7 @@ class ChatMessagesListViewModel(private val chatRoom: ChatRoom) : ViewModel() {
|
|||
private const val MESSAGES_PER_PAGE = 20
|
||||
}
|
||||
|
||||
val events = MutableLiveData<ArrayList<EventLog>>()
|
||||
val events = MutableLiveData<ArrayList<EventLogData>>()
|
||||
|
||||
val messageUpdatedEvent: MutableLiveData<Event<Int>> by lazy {
|
||||
MutableLiveData<Event<Int>>()
|
||||
|
@ -67,8 +68,8 @@ class ChatMessagesListViewModel(private val chatRoom: ChatRoom) : ViewModel() {
|
|||
chatMessage ?: return
|
||||
chatMessage.userData = events.value.orEmpty().size
|
||||
|
||||
val existingEvent = events.value.orEmpty().find {
|
||||
it.type == EventLog.Type.ConferenceChatMessage && it.chatMessage == chatMessage
|
||||
val existingEvent = events.value.orEmpty().find { data ->
|
||||
data.eventLog == eventLog
|
||||
}
|
||||
if (existingEvent != null) {
|
||||
Log.w("[Chat Messages] Found already present chat message, don't add it it's probably the result of an auto download")
|
||||
|
@ -165,19 +166,19 @@ class ChatMessagesListViewModel(private val chatRoom: ChatRoom) : ViewModel() {
|
|||
LinphoneUtils.deleteFilesAttachedToChatMessage(chatMessage)
|
||||
chatRoom.deleteMessage(chatMessage)
|
||||
|
||||
val list = arrayListOf<EventLog>()
|
||||
val list = arrayListOf<EventLogData>()
|
||||
list.addAll(events.value.orEmpty())
|
||||
list.removeAt(position)
|
||||
events.value = list
|
||||
}
|
||||
|
||||
fun deleteEventLogs(listToDelete: ArrayList<EventLog>) {
|
||||
val list = arrayListOf<EventLog>()
|
||||
fun deleteEventLogs(listToDelete: ArrayList<EventLogData>) {
|
||||
val list = arrayListOf<EventLogData>()
|
||||
list.addAll(events.value.orEmpty())
|
||||
|
||||
for (eventLog in listToDelete) {
|
||||
LinphoneUtils.deleteFilesAttachedToEventLog(eventLog)
|
||||
eventLog.deleteFromDatabase()
|
||||
LinphoneUtils.deleteFilesAttachedToEventLog(eventLog.eventLog)
|
||||
eventLog.eventLog.deleteFromDatabase()
|
||||
list.remove(eventLog)
|
||||
}
|
||||
|
||||
|
@ -195,9 +196,9 @@ class ChatMessagesListViewModel(private val chatRoom: ChatRoom) : ViewModel() {
|
|||
}
|
||||
|
||||
val history: Array<EventLog> = chatRoom.getHistoryRangeEvents(totalItemsCount, upperBound)
|
||||
val list = arrayListOf<EventLog>()
|
||||
for (message in history) {
|
||||
list.add(message)
|
||||
val list = arrayListOf<EventLogData>()
|
||||
for (eventLog in history) {
|
||||
list.add(EventLogData(eventLog))
|
||||
}
|
||||
list.addAll(events.value.orEmpty())
|
||||
events.value = list
|
||||
|
@ -205,19 +206,19 @@ class ChatMessagesListViewModel(private val chatRoom: ChatRoom) : ViewModel() {
|
|||
}
|
||||
|
||||
private fun addEvent(eventLog: EventLog) {
|
||||
val list = arrayListOf<EventLog>()
|
||||
val list = arrayListOf<EventLogData>()
|
||||
list.addAll(events.value.orEmpty())
|
||||
if (!list.contains(eventLog)) {
|
||||
list.add(eventLog)
|
||||
list.add(EventLogData(eventLog))
|
||||
}
|
||||
events.value = list
|
||||
}
|
||||
|
||||
private fun getEvents(): ArrayList<EventLog> {
|
||||
val list = arrayListOf<EventLog>()
|
||||
private fun getEvents(): ArrayList<EventLogData> {
|
||||
val list = arrayListOf<EventLogData>()
|
||||
val history = chatRoom.getHistoryEvents(MESSAGES_PER_PAGE)
|
||||
for (message in history) {
|
||||
list.add(message)
|
||||
for (eventLog in history) {
|
||||
list.add(EventLogData(eventLog))
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue