Skip to content
Snippets Groups Projects
Commit 1db779e4 authored by Pierre Nicolas's avatar Pierre Nicolas :joy: Committed by Adrien Béraud
Browse files

conversation: improve menu conversation popup

User can see which emoji he already sent
Clicking on sent emoji, he can remove it.
Clicking on unsent emoji, he can send it.

GitLab: #1204

Change-Id: I0ce8dcdfba3b1e2e19427980eecb2d049a81d355
parent e3e55a26
Branches
Tags
No related merge requests found
......@@ -84,7 +84,6 @@ import net.jami.model.Account.ComposingStatus
import net.jami.model.Interaction.InteractionStatus
import net.jami.utils.StringUtils
import java.io.File
import java.lang.ref.WeakReference
import java.text.DateFormat
import java.util.*
import java.util.concurrent.TimeUnit
......@@ -743,12 +742,24 @@ class ConversationAdapter(
player.seekTo(1)
}
private fun openItemMenu(cvh: ConversationViewHolder, v: View, interaction: Interaction) {
MenuConversationBinding.inflate(LayoutInflater.from(v.context)).apply {
/**
* Display and manage the popup that allows user to react/reply/share/edit/delete message ...
*
* @param conversationViewHolder the view layout.
* @param view
* @param interaction
*/
private fun openItemMenu(
conversationViewHolder: ConversationViewHolder, view: View, interaction: Interaction
) {
// Inflate design from XML.
MenuConversationBinding.inflate(LayoutInflater.from(view.context)).apply {
val history = interaction.historyObservable.blockingFirst()
val lastElement = history.last()
val isDeleted = lastElement is TextMessage && lastElement.body.isNullOrEmpty()
Log.w(TAG, "isDeleted $isDeleted ${history.size}")
// Configure what should be displayed
convActionOpenText.isVisible = interaction is DataTransfer && interaction.isComplete
convActionDownloadText.isVisible = interaction is DataTransfer && interaction.isComplete
convActionCopyText.isVisible = !isDeleted
......@@ -756,77 +767,141 @@ class ConversationAdapter(
convActionDelete.isVisible = !isDeleted && !interaction.isIncoming
convActionHistory.isVisible = !isDeleted && history.size > 1
root.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED)
val popupWindow = WeakReference(PopupWindow(root, LinearLayout.LayoutParams.WRAP_CONTENT, root.measuredHeight, true).apply {
setOnDismissListener {
// The popup that display all the buttons
val popupWindow = PopupWindow(
root, LinearLayout.LayoutParams.WRAP_CONTENT, root.measuredHeight, true
)
.apply {
elevation = view.context.resources.getDimension(R.dimen.call_preview_elevation)
showAsDropDown(view)
}
val textViews = listOf(
convActionEmoji1.chip, convActionEmoji2.chip,
convActionEmoji3.chip, convActionEmoji4.chip
)
convActionEmoji1.chip.text = view.context.getString(R.string.default_emoji_1)
convActionEmoji2.chip.text = view.context.getString(R.string.default_emoji_2)
convActionEmoji3.chip.text = view.context.getString(R.string.default_emoji_3)
convActionEmoji4.chip.text = view.context.getString(R.string.default_emoji_4)
// Subscribe on reactions to allows user to see which reaction he already selected.
val disposable = interaction.reactionObservable
.observeOn(DeviceUtils.uiScheduler)
.subscribe { reactions ->
textViews.forEach { textView ->
// Set checked reactions already sent.
textView.isChecked = reactions.any {
(textView.text == it.body) && (it.contact?.isUser == true)
}
}
popupWindow.update()
}
conversationViewHolder.compositeDisposable.add(disposable)
popupWindow.setOnDismissListener {
if (convColor != 0
&& interaction.type == Interaction.InteractionType.TEXT
&& !interaction.isIncoming
) {
v.background?.setTint(convColor)
} else {
v.background?.setTintList(null)
}
) view.background?.setTint(convColor)
else view.background?.setTintList(null)
// Remove disposable.
conversationViewHolder.compositeDisposable.remove(disposable)
}
elevation = v.context.resources.getDimension(R.dimen.call_preview_elevation)
showAsDropDown(v)
})
// Callback executed when emoji is clicked.
// We want to know if the reaction is already set.
// If set we want to remove, else we want to append.
val emojiCallback = View.OnClickListener { view ->
// Subscribe to know which are the current reactions.
conversationViewHolder.compositeDisposable.add(interaction.reactionObservable
.observeOn(DeviceUtils.uiScheduler)
.firstOrError()
.subscribe { reactions ->
// Try to find a reaction having corresponding to the one clicked.
val reaction = reactions.firstOrNull {
(it.body == (view as TextView).text) && (it.contact?.isUser == true)
}
if (reaction != null)
// Previously, it was not forbidden to send multiple times the same
// reaction. Hence, we only remove the first one.
presenter.removeReaction(reaction)
else // If null, it means we didn't find anything. So let's send it.
presenter.sendReaction(interaction, (view as TextView).text)
popupWindow.get()?.dismiss()
popupWindow.dismiss()
}
convActionEmoji1.setOnClickListener(emojiCallback)
convActionEmoji2.setOnClickListener(emojiCallback)
convActionEmoji3.setOnClickListener(emojiCallback)
convActionEmoji4.setOnClickListener(emojiCallback)
)
}
textViews.forEach { it.setOnClickListener(emojiCallback) } // Set callback
// Configure reply
convActionReply.setOnClickListener {
presenter.startReplyTo(interaction)
popupWindow.get()?.dismiss()
popupWindow.dismiss()
}
convActionMore.setOnClickListener {
menuActions.isVisible = !menuActions.isVisible
}
// Open file
convActionOpenText.setOnClickListener {
presenter.openFile(interaction)
}
// Save file
convActionDownloadText.setOnClickListener {
presenter.saveFile(interaction)
}
// Manage copy
convActionCopyText.setOnClickListener {
addToClipboard(lastElement.body)
popupWindow.get()?.dismiss()
popupWindow.dismiss()
}
// Manage Edit and Delete actions
if (!interaction.isIncoming) {
// Edit
convActionEdit.setOnClickListener {
try {
val i = Intent(it.context, MessageEditActivity::class.java)
.setData(Uri.withAppendedPath(ConversationPath.toUri(interaction.account!!, interaction.conversationId!!), interaction.messageId))
.setAction(Intent.ACTION_EDIT)
.putExtra(Intent.EXTRA_TEXT, cvh.mMsgTxt!!.text.toString())
val options = ActivityOptionsCompat.makeSceneTransitionAnimation(conversationFragment.requireActivity(), cvh.mMsgTxt!!, "messageEdit")
.putExtra(Intent.EXTRA_TEXT, conversationViewHolder.mMsgTxt!!.text.toString())
val options = ActivityOptionsCompat.makeSceneTransitionAnimation(conversationFragment.requireActivity(), conversationViewHolder.mMsgTxt!!, "messageEdit")
conversationFragment.startActivityForResult(i, ConversationFragment.REQUEST_CODE_EDIT_MESSAGE, options.toBundle())
} catch (e: Exception) {
Log.w(TAG, "Can't open picture", e)
}
popupWindow.get()?.dismiss()
popupWindow.dismiss()
}
// Delete
convActionDelete.setOnClickListener {
presenter.deleteConversationItem(interaction)
popupWindow.get()?.dismiss()
popupWindow.dismiss()
}
} else {
convActionEdit.setOnClickListener(null)
convActionDelete.setOnClickListener(null)
}
// Share
convActionShare.setOnClickListener {
if (interaction is DataTransfer)
presenter.shareFile(interaction)
else if (interaction is TextMessage)
presenter.shareText(interaction)
popupWindow.get()?.dismiss()
popupWindow.dismiss()
}
// Message history
if (convActionHistory.isVisible)
convActionHistory.setOnClickListener {
cvh.compositeDisposable.add(
conversationViewHolder.compositeDisposable.add(
interaction.historyObservable.firstOrError().subscribe { c ->
Log.w(TAG, "Message history ${c.size}")
c.forEach {
......@@ -839,8 +914,9 @@ class ConversationAdapter(
{ dialog, which -> dialog.dismiss() }
.create()
.show()
})
popupWindow.get()?.dismiss()
}
)
popupWindow.dismiss()
}
}
}
......
......@@ -15,49 +15,17 @@
android:orientation="horizontal"
android:padding="8dp">
<TextView
android:id="@+id/conv_action_emoji1"
android:layout_width="36dp"
android:layout_height="36dp"
android:background="?selectableItemBackgroundBorderless"
android:clickable="true"
android:focusable="true"
android:gravity="center"
android:text="@string/default_emoji_1"
android:textSize="18dp" />
<include layout="@layout/item_reaction_chip_18"
android:id="@+id/conv_action_emoji1"/>
<TextView
android:id="@+id/conv_action_emoji2"
android:layout_width="36dp"
android:layout_height="36dp"
android:background="?selectableItemBackgroundBorderless"
android:clickable="true"
android:focusable="true"
android:gravity="center"
android:text="@string/default_emoji_2"
android:textSize="18dp" />
<include layout="@layout/item_reaction_chip_18"
android:id="@+id/conv_action_emoji2"/>
<TextView
android:id="@+id/conv_action_emoji3"
android:layout_width="36dp"
android:layout_height="36dp"
android:background="?selectableItemBackgroundBorderless"
android:clickable="true"
android:focusable="true"
android:gravity="center"
android:text="@string/default_emoji_3"
android:textSize="18dp" />
<include layout="@layout/item_reaction_chip_18"
android:id="@+id/conv_action_emoji3"/>
<TextView
android:id="@+id/conv_action_emoji4"
android:layout_width="36dp"
android:layout_height="36dp"
android:background="?selectableItemBackgroundBorderless"
android:clickable="true"
android:focusable="true"
android:gravity="center"
android:text="@string/default_emoji_5"
android:textSize="18dp" />
<include layout="@layout/item_reaction_chip_18"
android:id="@+id/conv_action_emoji4"/>
<ImageView
android:visibility="gone"
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment