mirror of
https://gitlab.linphone.org/BC/public/linphone-android.git
synced 2026-01-17 11:28:06 +00:00
Made chat message delivery bottom sheet generic to also use it to display emoji reactions lists
This commit is contained in:
parent
18f0d9109e
commit
f855426a9f
13 changed files with 269 additions and 168 deletions
|
|
@ -9,19 +9,19 @@ import androidx.recyclerview.widget.DiffUtil
|
|||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import org.linphone.R
|
||||
import org.linphone.databinding.ChatMessageDeliveryListCellBinding
|
||||
import org.linphone.ui.main.chat.model.ChatMessageParticipantDeliveryModel
|
||||
import org.linphone.databinding.ChatMessageBottomSheetListCellBinding
|
||||
import org.linphone.ui.main.chat.model.ChatMessageBottomSheetParticipantModel
|
||||
|
||||
class ChatMessageDeliveryAdapter(
|
||||
class ChatMessageBottomSheetAdapter(
|
||||
private val viewLifecycleOwner: LifecycleOwner
|
||||
) : ListAdapter<ChatMessageParticipantDeliveryModel, RecyclerView.ViewHolder>(
|
||||
ChatDeliveryDiffCallback()
|
||||
) : ListAdapter<ChatMessageBottomSheetParticipantModel, RecyclerView.ViewHolder>(
|
||||
ParticipantDiffCallback()
|
||||
) {
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
val binding: ChatMessageDeliveryListCellBinding = DataBindingUtil.inflate(
|
||||
val binding: ChatMessageBottomSheetListCellBinding = DataBindingUtil.inflate(
|
||||
LayoutInflater.from(parent.context),
|
||||
R.layout.chat_message_delivery_list_cell,
|
||||
R.layout.chat_message_bottom_sheet_list_cell,
|
||||
parent,
|
||||
false
|
||||
)
|
||||
|
|
@ -33,12 +33,12 @@ class ChatMessageDeliveryAdapter(
|
|||
}
|
||||
|
||||
inner class ViewHolder(
|
||||
val binding: ChatMessageDeliveryListCellBinding
|
||||
val binding: ChatMessageBottomSheetListCellBinding
|
||||
) : RecyclerView.ViewHolder(binding.root) {
|
||||
@UiThread
|
||||
fun bind(deliveryModel: ChatMessageParticipantDeliveryModel) {
|
||||
fun bind(bottomSheetModel: ChatMessageBottomSheetParticipantModel) {
|
||||
with(binding) {
|
||||
model = deliveryModel
|
||||
model = bottomSheetModel
|
||||
|
||||
lifecycleOwner = viewLifecycleOwner
|
||||
|
||||
|
|
@ -47,19 +47,19 @@ class ChatMessageDeliveryAdapter(
|
|||
}
|
||||
}
|
||||
|
||||
private class ChatDeliveryDiffCallback : DiffUtil.ItemCallback<ChatMessageParticipantDeliveryModel>() {
|
||||
private class ParticipantDiffCallback : DiffUtil.ItemCallback<ChatMessageBottomSheetParticipantModel>() {
|
||||
override fun areItemsTheSame(
|
||||
oldItem: ChatMessageParticipantDeliveryModel,
|
||||
newItem: ChatMessageParticipantDeliveryModel
|
||||
oldItem: ChatMessageBottomSheetParticipantModel,
|
||||
newItem: ChatMessageBottomSheetParticipantModel
|
||||
): Boolean {
|
||||
return oldItem.sipUri == newItem.sipUri
|
||||
}
|
||||
|
||||
override fun areContentsTheSame(
|
||||
oldItem: ChatMessageParticipantDeliveryModel,
|
||||
newItem: ChatMessageParticipantDeliveryModel
|
||||
oldItem: ChatMessageBottomSheetParticipantModel,
|
||||
newItem: ChatMessageBottomSheetParticipantModel
|
||||
): Boolean {
|
||||
return oldItem.time == newItem.time
|
||||
return oldItem.value == newItem.value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -50,6 +50,9 @@ class ConversationEventAdapter(
|
|||
val showDeliveryForChatMessageModelEvent: MutableLiveData<Event<ChatMessageModel>> by lazy {
|
||||
MutableLiveData<Event<ChatMessageModel>>()
|
||||
}
|
||||
val showReactionForChatMessageModelEvent: MutableLiveData<Event<ChatMessageModel>> by lazy {
|
||||
MutableLiveData<Event<ChatMessageModel>>()
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
return when (viewType) {
|
||||
|
|
@ -123,6 +126,9 @@ class ConversationEventAdapter(
|
|||
setShowDeliveryInfoClickListener {
|
||||
showDeliveryForChatMessageModelEvent.value = Event(message)
|
||||
}
|
||||
setShowReactionInfoClickListener {
|
||||
showReactionForChatMessageModelEvent.value = Event(message)
|
||||
}
|
||||
|
||||
lifecycleOwner = viewLifecycleOwner
|
||||
executePendingBindings()
|
||||
|
|
@ -140,6 +146,9 @@ class ConversationEventAdapter(
|
|||
setShowDeliveryInfoClickListener {
|
||||
showDeliveryForChatMessageModelEvent.value = Event(message)
|
||||
}
|
||||
setShowReactionInfoClickListener {
|
||||
showReactionForChatMessageModelEvent.value = Event(message)
|
||||
}
|
||||
|
||||
lifecycleOwner = viewLifecycleOwner
|
||||
executePendingBindings()
|
||||
|
|
|
|||
|
|
@ -56,10 +56,11 @@ import org.linphone.core.ChatMessage
|
|||
import org.linphone.core.tools.Log
|
||||
import org.linphone.databinding.ChatConversationFragmentBinding
|
||||
import org.linphone.databinding.ChatConversationLongPressMenuBinding
|
||||
import org.linphone.ui.main.chat.adapter.ChatMessageDeliveryAdapter
|
||||
import org.linphone.ui.main.chat.adapter.ChatMessageBottomSheetAdapter
|
||||
import org.linphone.ui.main.chat.adapter.ConversationEventAdapter
|
||||
import org.linphone.ui.main.chat.model.ChatMessageDeliveryModel
|
||||
import org.linphone.ui.main.chat.model.ChatMessageModel
|
||||
import org.linphone.ui.main.chat.model.ChatMessageReactionsModel
|
||||
import org.linphone.ui.main.chat.viewmodel.ConversationViewModel
|
||||
import org.linphone.ui.main.fragment.GenericFragment
|
||||
import org.linphone.utils.AppUtils
|
||||
|
|
@ -83,7 +84,7 @@ class ConversationFragment : GenericFragment() {
|
|||
|
||||
private lateinit var adapter: ConversationEventAdapter
|
||||
|
||||
private lateinit var deliveryAdapter: ChatMessageDeliveryAdapter
|
||||
private lateinit var bottomSheetAdapter: ChatMessageBottomSheetAdapter
|
||||
|
||||
private val pickMedia = registerForActivityResult(
|
||||
ActivityResultContracts.PickMultipleVisualMedia()
|
||||
|
|
@ -162,15 +163,15 @@ class ConversationFragment : GenericFragment() {
|
|||
binding.eventsList.setHasFixedSize(true)
|
||||
binding.eventsList.adapter = adapter
|
||||
|
||||
deliveryAdapter = ChatMessageDeliveryAdapter(viewLifecycleOwner)
|
||||
binding.messageDelivery.deliveryList.setHasFixedSize(true)
|
||||
binding.messageDelivery.deliveryList.adapter = deliveryAdapter
|
||||
|
||||
val layoutManager = LinearLayoutManager(requireContext())
|
||||
binding.eventsList.layoutManager = layoutManager
|
||||
|
||||
val deliveryLayoutManager = LinearLayoutManager(requireContext())
|
||||
binding.messageDelivery.deliveryList.layoutManager = deliveryLayoutManager
|
||||
bottomSheetAdapter = ChatMessageBottomSheetAdapter(viewLifecycleOwner)
|
||||
binding.messageBottomSheet.bottomSheetList.setHasFixedSize(true)
|
||||
binding.messageBottomSheet.bottomSheetList.adapter = bottomSheetAdapter
|
||||
|
||||
val bottomSheetLayoutManager = LinearLayoutManager(requireContext())
|
||||
binding.messageBottomSheet.bottomSheetList.layoutManager = bottomSheetLayoutManager
|
||||
|
||||
adapter.chatMessageLongPressEvent.observe(viewLifecycleOwner) {
|
||||
it.consume { model ->
|
||||
|
|
@ -195,13 +196,23 @@ class ConversationFragment : GenericFragment() {
|
|||
adapter.showDeliveryForChatMessageModelEvent.observe(viewLifecycleOwner) {
|
||||
it.consume { model ->
|
||||
if (viewModel.isGroup.value == true) {
|
||||
showDeliveryBottomSheetDialog(model)
|
||||
showDeliveryBottomSheetDialog(model, showDelivery = true)
|
||||
} else {
|
||||
Log.w("$TAG Conversation is not a group, not showing delivery bottom sheet")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
adapter.showReactionForChatMessageModelEvent.observe(viewLifecycleOwner) {
|
||||
it.consume { model ->
|
||||
if (viewModel.isGroup.value == true) {
|
||||
showDeliveryBottomSheetDialog(model, showReactions = true)
|
||||
} else {
|
||||
Log.w("$TAG Conversation is not a group, not showing reactions bottom sheet")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
binding.setOpenFilePickerClickListener {
|
||||
Log.i("$TAG Opening media picker")
|
||||
pickMedia.launch(
|
||||
|
|
@ -320,74 +331,141 @@ class ConversationFragment : GenericFragment() {
|
|||
}
|
||||
|
||||
@UiThread
|
||||
private fun showDeliveryBottomSheetDialog(chatMessageModel: ChatMessageModel) {
|
||||
val deliveryBottomSheetBehavior = BottomSheetBehavior.from(binding.messageDelivery.root)
|
||||
private fun showDeliveryBottomSheetDialog(
|
||||
chatMessageModel: ChatMessageModel,
|
||||
showDelivery: Boolean = false,
|
||||
showReactions: Boolean = false
|
||||
) {
|
||||
val deliveryBottomSheetBehavior = BottomSheetBehavior.from(binding.messageBottomSheet.root)
|
||||
deliveryBottomSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED
|
||||
|
||||
binding.messageDelivery.setHandleClickedListener {
|
||||
binding.messageBottomSheet.setHandleClickedListener {
|
||||
deliveryBottomSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED
|
||||
}
|
||||
|
||||
lifecycleScope.launch {
|
||||
withContext(Dispatchers.IO) {
|
||||
// Wait for previous bottom sheet to go away
|
||||
delay(200)
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
coreContext.postOnCoreThread {
|
||||
val model = ChatMessageDeliveryModel(chatMessageModel.chatMessage)
|
||||
|
||||
coreContext.postOnMainThread {
|
||||
model.deliveryModels.observe(viewLifecycleOwner) {
|
||||
deliveryAdapter.submitList(it)
|
||||
}
|
||||
|
||||
binding.messageDelivery.tabs.removeAllTabs()
|
||||
binding.messageDelivery.tabs.addTab(
|
||||
binding.messageDelivery.tabs.newTab().setText(model.readLabel.value).setId(
|
||||
ChatMessage.State.Displayed.toInt()
|
||||
)
|
||||
)
|
||||
binding.messageDelivery.tabs.addTab(
|
||||
binding.messageDelivery.tabs.newTab().setText(
|
||||
model.receivedLabel.value
|
||||
).setId(
|
||||
ChatMessage.State.DeliveredToUser.toInt()
|
||||
)
|
||||
)
|
||||
binding.messageDelivery.tabs.addTab(
|
||||
binding.messageDelivery.tabs.newTab().setText(model.sentLabel.value).setId(
|
||||
ChatMessage.State.Delivered.toInt()
|
||||
)
|
||||
)
|
||||
binding.messageDelivery.tabs.addTab(
|
||||
binding.messageDelivery.tabs.newTab().setText(
|
||||
model.errorLabel.value
|
||||
).setId(
|
||||
ChatMessage.State.NotDelivered.toInt()
|
||||
)
|
||||
)
|
||||
|
||||
binding.messageDelivery.tabs.setOnTabSelectedListener(object : OnTabSelectedListener {
|
||||
override fun onTabSelected(tab: TabLayout.Tab?) {
|
||||
val state = tab?.id ?: ChatMessage.State.Displayed.toInt()
|
||||
model.computeListForState(ChatMessage.State.fromInt(state))
|
||||
}
|
||||
|
||||
override fun onTabUnselected(tab: TabLayout.Tab?) {
|
||||
}
|
||||
|
||||
override fun onTabReselected(tab: TabLayout.Tab?) {
|
||||
}
|
||||
})
|
||||
|
||||
binding.messageDelivery.model = model
|
||||
|
||||
binding.messageDelivery.root.visibility = View.VISIBLE
|
||||
deliveryBottomSheetBehavior.state = BottomSheetBehavior.STATE_EXPANDED
|
||||
}
|
||||
if (showDelivery) {
|
||||
prepareBottomSheetForDeliveryStatus(chatMessageModel)
|
||||
} else if (showReactions) {
|
||||
prepareBottomSheetForReactions(chatMessageModel)
|
||||
}
|
||||
|
||||
binding.messageBottomSheet.root.visibility = View.VISIBLE
|
||||
deliveryBottomSheetBehavior.state = BottomSheetBehavior.STATE_EXPANDED
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@UiThread
|
||||
private fun prepareBottomSheetForDeliveryStatus(chatMessageModel: ChatMessageModel) {
|
||||
coreContext.postOnCoreThread {
|
||||
val model = ChatMessageDeliveryModel(chatMessageModel.chatMessage)
|
||||
|
||||
coreContext.postOnMainThread {
|
||||
val tabs = binding.messageBottomSheet.tabs
|
||||
tabs.removeAllTabs()
|
||||
tabs.addTab(
|
||||
tabs.newTab().setText(model.readLabel.value).setId(
|
||||
ChatMessage.State.Displayed.toInt()
|
||||
)
|
||||
)
|
||||
tabs.addTab(
|
||||
tabs.newTab().setText(
|
||||
model.receivedLabel.value
|
||||
).setId(
|
||||
ChatMessage.State.DeliveredToUser.toInt()
|
||||
)
|
||||
)
|
||||
tabs.addTab(
|
||||
tabs.newTab().setText(model.sentLabel.value).setId(
|
||||
ChatMessage.State.Delivered.toInt()
|
||||
)
|
||||
)
|
||||
tabs.addTab(
|
||||
tabs.newTab().setText(
|
||||
model.errorLabel.value
|
||||
).setId(
|
||||
ChatMessage.State.NotDelivered.toInt()
|
||||
)
|
||||
)
|
||||
|
||||
tabs.setOnTabSelectedListener(object : OnTabSelectedListener {
|
||||
override fun onTabSelected(tab: TabLayout.Tab?) {
|
||||
val state = tab?.id ?: ChatMessage.State.Displayed.toInt()
|
||||
bottomSheetAdapter.submitList(
|
||||
model.computeListForState(ChatMessage.State.fromInt(state))
|
||||
)
|
||||
}
|
||||
|
||||
override fun onTabUnselected(tab: TabLayout.Tab?) {
|
||||
}
|
||||
|
||||
override fun onTabReselected(tab: TabLayout.Tab?) {
|
||||
}
|
||||
})
|
||||
|
||||
val initialList = model.displayedModels
|
||||
bottomSheetAdapter.submitList(initialList)
|
||||
Log.i("$TAG Submitted [${initialList.size}] items for default delivery status list")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@UiThread
|
||||
private fun prepareBottomSheetForReactions(chatMessageModel: ChatMessageModel) {
|
||||
coreContext.postOnCoreThread {
|
||||
val model = ChatMessageReactionsModel(chatMessageModel.chatMessage)
|
||||
val totalCount = model.allReactions.size
|
||||
val label = getString(R.string.message_reactions_info_all_title, totalCount.toString())
|
||||
|
||||
coreContext.postOnMainThread {
|
||||
val tabs = binding.messageBottomSheet.tabs
|
||||
tabs.removeAllTabs()
|
||||
tabs.addTab(
|
||||
tabs.newTab().setText(label).setId(0).setTag("")
|
||||
)
|
||||
|
||||
var index = 1
|
||||
for (reaction in model.differentReactions.value.orEmpty()) {
|
||||
val count = model.reactionsMap[reaction]
|
||||
val tabLabel = getString(
|
||||
R.string.message_reactions_info_emoji_title,
|
||||
reaction,
|
||||
count.toString()
|
||||
)
|
||||
tabs.addTab(
|
||||
tabs.newTab().setText(tabLabel).setId(index).setTag(reaction)
|
||||
)
|
||||
index += 1
|
||||
}
|
||||
|
||||
tabs.setOnTabSelectedListener(object : OnTabSelectedListener {
|
||||
override fun onTabSelected(tab: TabLayout.Tab?) {
|
||||
val filter = tab?.tag.toString()
|
||||
if (filter.isEmpty()) {
|
||||
bottomSheetAdapter.submitList(model.allReactions)
|
||||
} else {
|
||||
bottomSheetAdapter.submitList(model.filterReactions(filter))
|
||||
}
|
||||
}
|
||||
|
||||
override fun onTabUnselected(tab: TabLayout.Tab?) {
|
||||
}
|
||||
|
||||
override fun onTabReselected(tab: TabLayout.Tab?) {
|
||||
}
|
||||
})
|
||||
|
||||
val initialList = model.allReactions
|
||||
bottomSheetAdapter.submitList(initialList)
|
||||
Log.i("$TAG Submitted [${initialList.size}] items for default reactions list")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,51 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2023 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.ui.main.chat.fragment
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.annotation.UiThread
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||
import org.linphone.databinding.ChatMessageDeliveryBottomSheetBinding
|
||||
import org.linphone.ui.main.chat.model.ChatMessageDeliveryModel
|
||||
import org.linphone.ui.main.chat.model.ChatMessageModel
|
||||
|
||||
@UiThread
|
||||
class MessageDeliveryDialogFragment(
|
||||
chatMessageModel: ChatMessageModel
|
||||
) : BottomSheetDialogFragment() {
|
||||
companion object {
|
||||
const val TAG = "MessageDeliveryDialogFragment"
|
||||
}
|
||||
|
||||
val model = ChatMessageDeliveryModel(chatMessageModel.chatMessage)
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
val view = ChatMessageDeliveryBottomSheetBinding.inflate(layoutInflater)
|
||||
view.model = model
|
||||
return view.root
|
||||
}
|
||||
}
|
||||
|
|
@ -3,15 +3,12 @@ package org.linphone.ui.main.chat.model
|
|||
import androidx.annotation.WorkerThread
|
||||
import org.linphone.LinphoneApplication.Companion.coreContext
|
||||
import org.linphone.core.Address
|
||||
import org.linphone.utils.TimestampUtils
|
||||
|
||||
class ChatMessageParticipantDeliveryModel @WorkerThread constructor(
|
||||
class ChatMessageBottomSheetParticipantModel @WorkerThread constructor(
|
||||
address: Address,
|
||||
timestamp: Long
|
||||
val value: String
|
||||
) {
|
||||
val sipUri = address.asStringUriOnly()
|
||||
|
||||
val avatarModel = coreContext.contactsManager.getContactAvatarModelForAddress(address)
|
||||
|
||||
val time = TimestampUtils.toString(timestamp)
|
||||
}
|
||||
|
|
@ -8,6 +8,7 @@ import org.linphone.core.ChatMessage
|
|||
import org.linphone.core.ChatMessage.State
|
||||
import org.linphone.core.tools.Log
|
||||
import org.linphone.utils.AppUtils
|
||||
import org.linphone.utils.TimestampUtils
|
||||
|
||||
class ChatMessageDeliveryModel @WorkerThread constructor(
|
||||
private val chatMessage: ChatMessage
|
||||
|
|
@ -24,34 +25,34 @@ class ChatMessageDeliveryModel @WorkerThread constructor(
|
|||
|
||||
val errorLabel = MutableLiveData<String>()
|
||||
|
||||
val deliveryModels = MutableLiveData<ArrayList<ChatMessageParticipantDeliveryModel>>()
|
||||
val displayedModels = arrayListOf<ChatMessageBottomSheetParticipantModel>()
|
||||
|
||||
private val displayedModels = arrayListOf<ChatMessageParticipantDeliveryModel>()
|
||||
private val deliveredModels = arrayListOf<ChatMessageBottomSheetParticipantModel>()
|
||||
|
||||
private val deliveredModels = arrayListOf<ChatMessageParticipantDeliveryModel>()
|
||||
private val sentModels = arrayListOf<ChatMessageBottomSheetParticipantModel>()
|
||||
|
||||
private val sentModels = arrayListOf<ChatMessageParticipantDeliveryModel>()
|
||||
|
||||
private val errorModels = arrayListOf<ChatMessageParticipantDeliveryModel>()
|
||||
private val errorModels = arrayListOf<ChatMessageBottomSheetParticipantModel>()
|
||||
|
||||
init {
|
||||
computeDeliveryStatus()
|
||||
|
||||
// TODO: add listener to update in real time the lists
|
||||
}
|
||||
|
||||
@UiThread
|
||||
fun computeListForState(state: State) {
|
||||
when (state) {
|
||||
fun computeListForState(state: State): ArrayList<ChatMessageBottomSheetParticipantModel> {
|
||||
return when (state) {
|
||||
State.DeliveredToUser -> {
|
||||
deliveryModels.value = deliveredModels
|
||||
deliveredModels
|
||||
}
|
||||
State.Delivered -> {
|
||||
deliveryModels.value = sentModels
|
||||
sentModels
|
||||
}
|
||||
State.NotDelivered -> {
|
||||
deliveryModels.value = errorModels
|
||||
errorModels
|
||||
}
|
||||
else -> {
|
||||
deliveryModels.value = displayedModels
|
||||
displayedModels
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -60,17 +61,17 @@ class ChatMessageDeliveryModel @WorkerThread constructor(
|
|||
private fun computeDeliveryStatus() {
|
||||
for (participant in chatMessage.getParticipantsByImdnState(State.Displayed)) {
|
||||
displayedModels.add(
|
||||
ChatMessageParticipantDeliveryModel(
|
||||
ChatMessageBottomSheetParticipantModel(
|
||||
participant.participant.address,
|
||||
participant.stateChangeTime
|
||||
TimestampUtils.timeToString(participant.stateChangeTime)
|
||||
)
|
||||
)
|
||||
}
|
||||
// Always add ourselves to prevent empty list
|
||||
displayedModels.add(
|
||||
ChatMessageParticipantDeliveryModel(
|
||||
ChatMessageBottomSheetParticipantModel(
|
||||
chatMessage.localAddress,
|
||||
chatMessage.time
|
||||
TimestampUtils.timeToString(chatMessage.time)
|
||||
)
|
||||
)
|
||||
val readCount = displayedModels.size.toString()
|
||||
|
|
@ -83,9 +84,9 @@ class ChatMessageDeliveryModel @WorkerThread constructor(
|
|||
|
||||
for (participant in chatMessage.getParticipantsByImdnState(State.DeliveredToUser)) {
|
||||
deliveredModels.add(
|
||||
ChatMessageParticipantDeliveryModel(
|
||||
ChatMessageBottomSheetParticipantModel(
|
||||
participant.participant.address,
|
||||
participant.stateChangeTime
|
||||
TimestampUtils.timeToString(participant.stateChangeTime)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
@ -99,9 +100,9 @@ class ChatMessageDeliveryModel @WorkerThread constructor(
|
|||
|
||||
for (participant in chatMessage.getParticipantsByImdnState(State.Delivered)) {
|
||||
sentModels.add(
|
||||
ChatMessageParticipantDeliveryModel(
|
||||
ChatMessageBottomSheetParticipantModel(
|
||||
participant.participant.address,
|
||||
participant.stateChangeTime
|
||||
TimestampUtils.timeToString(participant.stateChangeTime)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
@ -115,9 +116,9 @@ class ChatMessageDeliveryModel @WorkerThread constructor(
|
|||
|
||||
for (participant in chatMessage.getParticipantsByImdnState(State.NotDelivered)) {
|
||||
errorModels.add(
|
||||
ChatMessageParticipantDeliveryModel(
|
||||
ChatMessageBottomSheetParticipantModel(
|
||||
participant.participant.address,
|
||||
participant.stateChangeTime
|
||||
TimestampUtils.timeToString(participant.stateChangeTime)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
@ -129,7 +130,6 @@ class ChatMessageDeliveryModel @WorkerThread constructor(
|
|||
)
|
||||
)
|
||||
|
||||
deliveryModels.postValue(displayedModels)
|
||||
Log.i("$TAG Message ID [${chatMessage.messageId}] is in state [${chatMessage.state}]")
|
||||
Log.i(
|
||||
"$TAG There are [$readCount] that have read this message, [$receivedCount] that have received it, [$sentCount] that haven't received it yet and [$errorCount] that probably won't receive it due to an error"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,61 @@
|
|||
package org.linphone.ui.main.chat.model
|
||||
|
||||
import androidx.annotation.WorkerThread
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import org.linphone.core.ChatMessage
|
||||
import org.linphone.core.tools.Log
|
||||
|
||||
class ChatMessageReactionsModel @WorkerThread constructor(
|
||||
private val chatMessage: ChatMessage
|
||||
) {
|
||||
companion object {
|
||||
private const val TAG = "[Chat Message Reactions Model]"
|
||||
}
|
||||
|
||||
val allReactions = arrayListOf<ChatMessageBottomSheetParticipantModel>()
|
||||
|
||||
val differentReactions = MutableLiveData<ArrayList<String>>()
|
||||
|
||||
val reactionsMap = HashMap<String, Int>()
|
||||
|
||||
init {
|
||||
computeReactions()
|
||||
// TODO: add listener to update in real time the lists
|
||||
}
|
||||
|
||||
fun filterReactions(emoji: String): ArrayList<ChatMessageBottomSheetParticipantModel> {
|
||||
val filteredList = arrayListOf<ChatMessageBottomSheetParticipantModel>()
|
||||
|
||||
for (reaction in allReactions) {
|
||||
if (reaction.value == emoji) {
|
||||
filteredList.add(reaction)
|
||||
}
|
||||
}
|
||||
|
||||
return filteredList
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
private fun computeReactions() {
|
||||
reactionsMap.clear()
|
||||
allReactions.clear()
|
||||
|
||||
val differentReactionsList = arrayListOf<String>()
|
||||
for (reaction in chatMessage.reactions) {
|
||||
val body = reaction.body
|
||||
val count = reactionsMap.getOrDefault(body, 0)
|
||||
reactionsMap[body] = count + 1
|
||||
|
||||
allReactions.add(ChatMessageBottomSheetParticipantModel(reaction.fromAddress, body))
|
||||
|
||||
if (!differentReactionsList.contains(body)) {
|
||||
differentReactionsList.add(body)
|
||||
}
|
||||
}
|
||||
|
||||
Log.i(
|
||||
"$TAG [${differentReactionsList.size}] reactions found on a total of [${allReactions.size}]"
|
||||
)
|
||||
differentReactions.postValue(differentReactionsList)
|
||||
}
|
||||
}
|
||||
|
|
@ -13,6 +13,9 @@
|
|||
<variable
|
||||
name="showDeliveryInfoClickListener"
|
||||
type="View.OnClickListener" />
|
||||
<variable
|
||||
name="showReactionInfoClickListener"
|
||||
type="View.OnClickListener" />
|
||||
<variable
|
||||
name="model"
|
||||
type="org.linphone.ui.main.chat.model.ChatMessageModel" />
|
||||
|
|
@ -116,6 +119,7 @@
|
|||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/reactions"
|
||||
android:onClick="@{showReactionInfoClickListener}"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="2dp"
|
||||
|
|
|
|||
|
|
@ -13,6 +13,9 @@
|
|||
<variable
|
||||
name="showDeliveryInfoClickListener"
|
||||
type="View.OnClickListener" />
|
||||
<variable
|
||||
name="showReactionInfoClickListener"
|
||||
type="View.OnClickListener" />
|
||||
<variable
|
||||
name="model"
|
||||
type="org.linphone.ui.main.chat.model.ChatMessageModel" />
|
||||
|
|
@ -93,6 +96,7 @@
|
|||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/reactions"
|
||||
android:onClick="@{showReactionInfoClickListener}"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="2dp"
|
||||
|
|
|
|||
|
|
@ -235,9 +235,9 @@
|
|||
layout="@layout/chat_conversation_send_area"/>
|
||||
|
||||
<include
|
||||
android:id="@+id/message_delivery"
|
||||
android:id="@+id/message_bottom_sheet"
|
||||
android:visibility="gone"
|
||||
layout="@layout/chat_message_delivery_bottom_sheet" />
|
||||
layout="@layout/chat_message_bottom_sheet" />
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
||||
|
|
|
|||
|
|
@ -7,9 +7,6 @@
|
|||
<variable
|
||||
name="handleClickedListener"
|
||||
type="View.OnClickListener" />
|
||||
<variable
|
||||
name="model"
|
||||
type="org.linphone.ui.main.chat.model.ChatMessageDeliveryModel" />
|
||||
</data>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
|
|
@ -40,7 +37,7 @@
|
|||
android:background="@color/transparent_color"
|
||||
android:layout_marginBottom="16dp"
|
||||
app:layout_constraintTop_toBottomOf="@id/handle"
|
||||
app:layout_constraintBottom_toTopOf="@id/deliveryList"
|
||||
app:layout_constraintBottom_toTopOf="@id/bottom_sheet_list"
|
||||
app:tabMode="fixed"
|
||||
app:tabUnboundedRipple="true"
|
||||
app:tabRippleColor="@color/orange_main_100"
|
||||
|
|
@ -52,7 +49,7 @@
|
|||
app:tabSelectedTextColor="@color/gray_main2_600" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/deliveryList"
|
||||
android:id="@+id/bottom_sheet_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="250dp"
|
||||
android:nestedScrollingEnabled="true"
|
||||
|
|
@ -9,7 +9,7 @@
|
|||
<import type="org.linphone.core.ChatRoom.SecurityLevel" />
|
||||
<variable
|
||||
name="model"
|
||||
type="org.linphone.ui.main.chat.model.ChatMessageParticipantDeliveryModel" />
|
||||
type="org.linphone.ui.main.chat.model.ChatMessageBottomSheetParticipantModel" />
|
||||
</data>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
|
|
@ -72,7 +72,7 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:text="@{model.time, default=`16:18`}"
|
||||
android:text="@{model.value, default=`16:18`}"
|
||||
android:textSize="12sp"
|
||||
android:textColor="@color/gray_main2_600"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
|
|
@ -366,6 +366,8 @@
|
|||
<string name="message_delivery_info_received_title">Received (%s)</string>
|
||||
<string name="message_delivery_info_sent_title">Sent (%s)</string>
|
||||
<string name="message_delivery_info_error_title">Error (%s)</string>
|
||||
<string name="message_reactions_info_all_title">Reactions (%s)</string>
|
||||
<string name="message_reactions_info_emoji_title">%s (%s)</string>
|
||||
|
||||
<string name="meetings_list_empty">No meeting for the moment…</string>
|
||||
<string name="meeting_schedule_title">New meeting</string>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue