Added fake event to indicate first unread message & unread message count in chat messages list
This commit is contained in:
parent
7c5feb041a
commit
c2b06e5cfd
4 changed files with 121 additions and 8 deletions
|
@ -24,6 +24,7 @@ import android.content.ClipboardManager
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.view.Gravity
|
import android.view.Gravity
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.PopupWindow
|
import android.widget.PopupWindow
|
||||||
import androidx.databinding.DataBindingUtil
|
import androidx.databinding.DataBindingUtil
|
||||||
|
@ -43,16 +44,16 @@ import org.linphone.core.ChatMessage
|
||||||
import org.linphone.core.ChatRoomCapabilities
|
import org.linphone.core.ChatRoomCapabilities
|
||||||
import org.linphone.core.Content
|
import org.linphone.core.Content
|
||||||
import org.linphone.core.EventLog
|
import org.linphone.core.EventLog
|
||||||
import org.linphone.databinding.ChatEventListCellBinding
|
import org.linphone.databinding.*
|
||||||
import org.linphone.databinding.ChatMessageListCellBinding
|
|
||||||
import org.linphone.databinding.ChatMessageLongPressMenuBindingImpl
|
|
||||||
import org.linphone.utils.AppUtils
|
import org.linphone.utils.AppUtils
|
||||||
import org.linphone.utils.Event
|
import org.linphone.utils.Event
|
||||||
|
import org.linphone.utils.HeaderAdapter
|
||||||
|
|
||||||
class ChatMessagesListAdapter(
|
class ChatMessagesListAdapter(
|
||||||
selectionVM: ListTopBarViewModel,
|
selectionVM: ListTopBarViewModel,
|
||||||
private val viewLifecycleOwner: LifecycleOwner
|
private val viewLifecycleOwner: LifecycleOwner
|
||||||
) : SelectionListAdapter<EventLogData, RecyclerView.ViewHolder>(selectionVM, ChatMessageDiffCallback()) {
|
) : SelectionListAdapter<EventLogData, RecyclerView.ViewHolder>(selectionVM, ChatMessageDiffCallback()),
|
||||||
|
HeaderAdapter {
|
||||||
companion object {
|
companion object {
|
||||||
const val MAX_TIME_TO_GROUP_MESSAGES = 60 // 1 minute
|
const val MAX_TIME_TO_GROUP_MESSAGES = 60 // 1 minute
|
||||||
}
|
}
|
||||||
|
@ -97,6 +98,9 @@ class ChatMessagesListAdapter(
|
||||||
|
|
||||||
private var contextMenuDisabled: Boolean = false
|
private var contextMenuDisabled: Boolean = false
|
||||||
|
|
||||||
|
private var unreadMessagesCount: Int = 0
|
||||||
|
private var firstUnreadMessagePosition: Int = -1
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||||
return when (viewType) {
|
return when (viewType) {
|
||||||
EventLog.Type.ConferenceChatMessage.toInt() -> createChatMessageViewHolder(parent)
|
EventLog.Type.ConferenceChatMessage.toInt() -> createChatMessageViewHolder(parent)
|
||||||
|
@ -133,10 +137,59 @@ class ChatMessagesListAdapter(
|
||||||
return eventLog.eventLog.type.toInt()
|
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() {
|
fun disableContextMenu() {
|
||||||
contextMenuDisabled = true
|
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(
|
inner class ChatMessageViewHolder(
|
||||||
val binding: ChatMessageListCellBinding
|
val binding: ChatMessageListCellBinding
|
||||||
) : RecyclerView.ViewHolder(binding.root) {
|
) : RecyclerView.ViewHolder(binding.root) {
|
||||||
|
|
|
@ -80,7 +80,6 @@ class DetailChatRoomFragment : MasterFragment<ChatRoomDetailFragmentBinding, Cha
|
||||||
// But only if user hasn't initiated a scroll up in the messages history
|
// But only if user hasn't initiated a scroll up in the messages history
|
||||||
if (viewModel.isUserScrollingUp.value == false) {
|
if (viewModel.isUserScrollingUp.value == false) {
|
||||||
scrollToBottom()
|
scrollToBottom()
|
||||||
viewModel.chatRoom.markAsRead()
|
|
||||||
} else {
|
} 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")
|
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() {
|
override fun onDestroyView() {
|
||||||
if (_adapter != null) {
|
if (_adapter != null) {
|
||||||
adapter.unregisterAdapterDataObserver(observer)
|
try {
|
||||||
|
adapter.unregisterAdapterDataObserver(observer)
|
||||||
|
} catch (ise: IllegalStateException) {}
|
||||||
}
|
}
|
||||||
binding.chatMessagesList.adapter = null
|
binding.chatMessagesList.adapter = null
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
|
@ -176,6 +177,10 @@ class DetailChatRoomFragment : MasterFragment<ChatRoomDetailFragmentBinding, Cha
|
||||||
layoutManager.stackFromEnd = true
|
layoutManager.stackFromEnd = true
|
||||||
binding.chatMessagesList.layoutManager = layoutManager
|
binding.chatMessagesList.layoutManager = layoutManager
|
||||||
|
|
||||||
|
// Displays unread messages header
|
||||||
|
val headerItemDecoration = RecyclerViewHeaderDecoration(requireContext(), adapter)
|
||||||
|
binding.chatMessagesList.addItemDecoration(headerItemDecoration)
|
||||||
|
|
||||||
// Swipe action
|
// Swipe action
|
||||||
/*val swipeConfiguration = RecyclerViewSwipeConfiguration()
|
/*val swipeConfiguration = RecyclerViewSwipeConfiguration()
|
||||||
swipeConfiguration.leftToRightAction = RecyclerViewSwipeConfiguration.Action(icon = R.drawable.menu_reply_default)
|
swipeConfiguration.leftToRightAction = RecyclerViewSwipeConfiguration.Action(icon = R.drawable.menu_reply_default)
|
||||||
|
@ -235,6 +240,7 @@ class DetailChatRoomFragment : MasterFragment<ChatRoomDetailFragmentBinding, Cha
|
||||||
listViewModel.events.observe(
|
listViewModel.events.observe(
|
||||||
viewLifecycleOwner,
|
viewLifecycleOwner,
|
||||||
{ events ->
|
{ events ->
|
||||||
|
adapter.setUnreadMessageCount(viewModel.chatRoom.unreadMessagesCount, viewModel.isUserScrollingUp.value == true)
|
||||||
adapter.submitList(events)
|
adapter.submitList(events)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -388,7 +394,11 @@ class DetailChatRoomFragment : MasterFragment<ChatRoomDetailFragmentBinding, Cha
|
||||||
}
|
}
|
||||||
val index = events.indexOf(eventLog)
|
val index = events.indexOf(eventLog)
|
||||||
try {
|
try {
|
||||||
binding.chatMessagesList.smoothScrollToPosition(index)
|
if (corePreferences.enableAnimations) {
|
||||||
|
binding.chatMessagesList.smoothScrollToPosition(index)
|
||||||
|
} else {
|
||||||
|
binding.chatMessagesList.scrollToPosition(index)
|
||||||
|
}
|
||||||
} catch (iae: IllegalArgumentException) {
|
} catch (iae: IllegalArgumentException) {
|
||||||
Log.e("[Chat Room] Can't scroll to position $index")
|
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
|
// Prevent notifications for this chat room to be displayed
|
||||||
val peerAddress = viewModel.chatRoom.peerAddress.asStringUriOnly()
|
val peerAddress = viewModel.chatRoom.peerAddress.asStringUriOnly()
|
||||||
coreContext.notificationsManager.currentlyDisplayedChatRoomAddress = peerAddress
|
coreContext.notificationsManager.currentlyDisplayedChatRoomAddress = peerAddress
|
||||||
|
Log.i("[Chat Room] Fragment resuming, mark chat room as read")
|
||||||
viewModel.chatRoom.markAsRead()
|
viewModel.chatRoom.markAsRead()
|
||||||
} else {
|
} else {
|
||||||
Log.e("[Chat Room] Fragment resuming but viewModel lateinit property isn't initialized!")
|
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() {
|
override fun goBack() {
|
||||||
if (!findNavController().popBackStack()) {
|
if (!findNavController().popBackStack()) {
|
||||||
if (sharedViewModel.isSlidingPaneSlideable.value == true) {
|
if (sharedViewModel.isSlidingPaneSlideable.value == true) {
|
||||||
|
if (_adapter != null) {
|
||||||
|
try {
|
||||||
|
adapter.unregisterAdapterDataObserver(observer)
|
||||||
|
} catch (ise: IllegalStateException) {}
|
||||||
|
}
|
||||||
sharedViewModel.closeSlidingPaneEvent.value = Event(true)
|
sharedViewModel.closeSlidingPaneEvent.value = Event(true)
|
||||||
} else {
|
} else {
|
||||||
navigateToEmptyChatRoom()
|
navigateToEmptyChatRoom()
|
||||||
|
@ -738,7 +754,11 @@ class DetailChatRoomFragment : MasterFragment<ChatRoomDetailFragmentBinding, Cha
|
||||||
|
|
||||||
private fun smoothScrollToPosition() {
|
private fun smoothScrollToPosition() {
|
||||||
if (_adapter != null && adapter.itemCount > 0) {
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
34
app/src/main/res/layout/chat_unread_messages_list_header.xml
Normal file
34
app/src/main/res/layout/chat_unread_messages_list_header.xml
Normal 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>
|
|
@ -221,6 +221,12 @@
|
||||||
<string name="chat_room_sending_message_hint">Message</string>
|
<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_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_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 -->
|
<!-- Recordings -->
|
||||||
<string name="recordings_empty_list">No recordings</string>
|
<string name="recordings_empty_list">No recordings</string>
|
||||||
|
|
Loading…
Reference in a new issue