Added fake event to indicate first unread message & unread message count in chat messages list

This commit is contained in:
Sylvain Berfini 2021-10-26 14:15:11 +02:00
parent 7c5feb041a
commit c2b06e5cfd
4 changed files with 121 additions and 8 deletions

View file

@ -24,6 +24,7 @@ import android.content.ClipboardManager
import android.content.Context
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.PopupWindow
import androidx.databinding.DataBindingUtil
@ -43,16 +44,16 @@ import org.linphone.core.ChatMessage
import org.linphone.core.ChatRoomCapabilities
import org.linphone.core.Content
import org.linphone.core.EventLog
import org.linphone.databinding.ChatEventListCellBinding
import org.linphone.databinding.ChatMessageListCellBinding
import org.linphone.databinding.ChatMessageLongPressMenuBindingImpl
import org.linphone.databinding.*
import org.linphone.utils.AppUtils
import org.linphone.utils.Event
import org.linphone.utils.HeaderAdapter
class ChatMessagesListAdapter(
selectionVM: ListTopBarViewModel,
private val viewLifecycleOwner: LifecycleOwner
) : SelectionListAdapter<EventLogData, RecyclerView.ViewHolder>(selectionVM, ChatMessageDiffCallback()) {
) : SelectionListAdapter<EventLogData, RecyclerView.ViewHolder>(selectionVM, ChatMessageDiffCallback()),
HeaderAdapter {
companion object {
const val MAX_TIME_TO_GROUP_MESSAGES = 60 // 1 minute
}
@ -97,6 +98,9 @@ class ChatMessagesListAdapter(
private var contextMenuDisabled: Boolean = false
private var unreadMessagesCount: Int = 0
private var firstUnreadMessagePosition: Int = -1
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return when (viewType) {
EventLog.Type.ConferenceChatMessage.toInt() -> createChatMessageViewHolder(parent)
@ -133,10 +137,59 @@ class ChatMessagesListAdapter(
return eventLog.eventLog.type.toInt()
}
override fun onCurrentListChanged(
previousList: MutableList<EventLogData>,
currentList: MutableList<EventLogData>
) {
// Need to wait for messages to be added before computing new first unread message position
firstUnreadMessagePosition = -1
}
override fun displayHeaderForPosition(position: Int): Boolean {
if (unreadMessagesCount > 0 && firstUnreadMessagePosition == -1) {
computeFirstUnreadMessagePosition()
}
return position == firstUnreadMessagePosition
}
override fun getHeaderViewForPosition(context: Context, position: Int): View {
val binding: ChatUnreadMessagesListHeaderBinding = DataBindingUtil.inflate(
LayoutInflater.from(context),
R.layout.chat_unread_messages_list_header, null, false
)
binding.title = AppUtils.getStringWithPlural(R.plurals.chat_room_unread_messages_event, unreadMessagesCount)
binding.executePendingBindings()
return binding.root
}
fun disableContextMenu() {
contextMenuDisabled = true
}
fun setUnreadMessageCount(count: Int, forceUpdate: Boolean) {
// Once list has been filled once, don't show the unread message header
// when new messages are added to the history whilst it is visible
unreadMessagesCount = if (itemCount == 0 || forceUpdate) count else 0
firstUnreadMessagePosition = -1
}
private fun computeFirstUnreadMessagePosition() {
if (unreadMessagesCount > 0) {
var messageCount = 0
for (position in itemCount - 1 downTo 0) {
val eventLog = getItem(position)
val data = eventLog.data
if (data is ChatMessageData) {
messageCount += 1
if (messageCount == unreadMessagesCount) {
firstUnreadMessagePosition = position
break
}
}
}
}
}
inner class ChatMessageViewHolder(
val binding: ChatMessageListCellBinding
) : RecyclerView.ViewHolder(binding.root) {

View file

@ -80,7 +80,6 @@ class DetailChatRoomFragment : MasterFragment<ChatRoomDetailFragmentBinding, Cha
// But only if user hasn't initiated a scroll up in the messages history
if (viewModel.isUserScrollingUp.value == false) {
scrollToBottom()
viewModel.chatRoom.markAsRead()
} else {
Log.w("[Chat Room] User has scrolled up manually in the messages history, don't scroll to the newly added message at the bottom & don't mark the chat room as read")
}
@ -94,7 +93,9 @@ class DetailChatRoomFragment : MasterFragment<ChatRoomDetailFragmentBinding, Cha
override fun onDestroyView() {
if (_adapter != null) {
adapter.unregisterAdapterDataObserver(observer)
try {
adapter.unregisterAdapterDataObserver(observer)
} catch (ise: IllegalStateException) {}
}
binding.chatMessagesList.adapter = null
super.onDestroyView()
@ -176,6 +177,10 @@ class DetailChatRoomFragment : MasterFragment<ChatRoomDetailFragmentBinding, Cha
layoutManager.stackFromEnd = true
binding.chatMessagesList.layoutManager = layoutManager
// Displays unread messages header
val headerItemDecoration = RecyclerViewHeaderDecoration(requireContext(), adapter)
binding.chatMessagesList.addItemDecoration(headerItemDecoration)
// Swipe action
/*val swipeConfiguration = RecyclerViewSwipeConfiguration()
swipeConfiguration.leftToRightAction = RecyclerViewSwipeConfiguration.Action(icon = R.drawable.menu_reply_default)
@ -235,6 +240,7 @@ class DetailChatRoomFragment : MasterFragment<ChatRoomDetailFragmentBinding, Cha
listViewModel.events.observe(
viewLifecycleOwner,
{ events ->
adapter.setUnreadMessageCount(viewModel.chatRoom.unreadMessagesCount, viewModel.isUserScrollingUp.value == true)
adapter.submitList(events)
}
)
@ -388,7 +394,11 @@ class DetailChatRoomFragment : MasterFragment<ChatRoomDetailFragmentBinding, Cha
}
val index = events.indexOf(eventLog)
try {
binding.chatMessagesList.smoothScrollToPosition(index)
if (corePreferences.enableAnimations) {
binding.chatMessagesList.smoothScrollToPosition(index)
} else {
binding.chatMessagesList.scrollToPosition(index)
}
} catch (iae: IllegalArgumentException) {
Log.e("[Chat Room] Can't scroll to position $index")
}
@ -542,6 +552,7 @@ class DetailChatRoomFragment : MasterFragment<ChatRoomDetailFragmentBinding, Cha
// Prevent notifications for this chat room to be displayed
val peerAddress = viewModel.chatRoom.peerAddress.asStringUriOnly()
coreContext.notificationsManager.currentlyDisplayedChatRoomAddress = peerAddress
Log.i("[Chat Room] Fragment resuming, mark chat room as read")
viewModel.chatRoom.markAsRead()
} else {
Log.e("[Chat Room] Fragment resuming but viewModel lateinit property isn't initialized!")
@ -572,6 +583,11 @@ class DetailChatRoomFragment : MasterFragment<ChatRoomDetailFragmentBinding, Cha
override fun goBack() {
if (!findNavController().popBackStack()) {
if (sharedViewModel.isSlidingPaneSlideable.value == true) {
if (_adapter != null) {
try {
adapter.unregisterAdapterDataObserver(observer)
} catch (ise: IllegalStateException) {}
}
sharedViewModel.closeSlidingPaneEvent.value = Event(true)
} else {
navigateToEmptyChatRoom()
@ -738,7 +754,11 @@ class DetailChatRoomFragment : MasterFragment<ChatRoomDetailFragmentBinding, Cha
private fun smoothScrollToPosition() {
if (_adapter != null && adapter.itemCount > 0) {
binding.chatMessagesList.smoothScrollToPosition(adapter.itemCount - 1)
if (corePreferences.enableAnimations) {
binding.chatMessagesList.smoothScrollToPosition(adapter.itemCount - 1)
} else {
binding.chatMessagesList.scrollToPosition(adapter.itemCount - 1)
}
}
}

View file

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="title"
type="String" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp"
android:gravity="center"
android:background="@drawable/event_decoration_gray"
android:orientation="horizontal">
<TextView
android:text="@{title}"
android:textSize="13sp"
android:fontFamily="sans-serif"
android:lineSpacingExtra="0sp"
android:textStyle="italic"
android:textColor="@color/light_grey_color"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingRight="5dp"
android:paddingLeft="5dp"
android:background="?attr/backgroundColor" />
</LinearLayout>
</layout>

View file

@ -221,6 +221,12 @@
<string name="chat_room_sending_message_hint">Message</string>
<string name="chat_message_voice_recording_hold_to_record">Hold button to record voice message</string>
<string name="chat_message_voice_recording_playback_low_volume">Your media volume is low, you may want to increase it</string>
<string name="chat_room_unread_message">%1$d unread message</string>
<string name="chat_room_unread_messages">%1$d unread messages</string>
<plurals name="chat_room_unread_messages_event">
<item quantity="one">@string/chat_room_unread_message</item>
<item quantity="other">@string/chat_room_unread_messages</item>
</plurals>
<!-- Recordings -->
<string name="recordings_empty_list">No recordings</string>