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 ...@@ -84,7 +84,6 @@ import net.jami.model.Account.ComposingStatus
import net.jami.model.Interaction.InteractionStatus import net.jami.model.Interaction.InteractionStatus
import net.jami.utils.StringUtils import net.jami.utils.StringUtils
import java.io.File import java.io.File
import java.lang.ref.WeakReference
import java.text.DateFormat import java.text.DateFormat
import java.util.* import java.util.*
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
...@@ -743,12 +742,24 @@ class ConversationAdapter( ...@@ -743,12 +742,24 @@ class ConversationAdapter(
player.seekTo(1) 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 history = interaction.historyObservable.blockingFirst()
val lastElement = history.last() val lastElement = history.last()
val isDeleted = lastElement is TextMessage && lastElement.body.isNullOrEmpty() 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 convActionOpenText.isVisible = interaction is DataTransfer && interaction.isComplete
convActionDownloadText.isVisible = interaction is DataTransfer && interaction.isComplete convActionDownloadText.isVisible = interaction is DataTransfer && interaction.isComplete
convActionCopyText.isVisible = !isDeleted convActionCopyText.isVisible = !isDeleted
...@@ -756,77 +767,141 @@ class ConversationAdapter( ...@@ -756,77 +767,141 @@ class ConversationAdapter(
convActionDelete.isVisible = !isDeleted && !interaction.isIncoming convActionDelete.isVisible = !isDeleted && !interaction.isIncoming
convActionHistory.isVisible = !isDeleted && history.size > 1 convActionHistory.isVisible = !isDeleted && history.size > 1
root.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED) 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 if (convColor != 0
&& interaction.type == Interaction.InteractionType.TEXT && interaction.type == Interaction.InteractionType.TEXT
&& !interaction.isIncoming && !interaction.isIncoming
) { ) view.background?.setTint(convColor)
v.background?.setTint(convColor) else view.background?.setTintList(null)
} else { // Remove disposable.
v.background?.setTintList(null) 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 -> 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) presenter.sendReaction(interaction, (view as TextView).text)
popupWindow.get()?.dismiss() popupWindow.dismiss()
} }
convActionEmoji1.setOnClickListener(emojiCallback) )
convActionEmoji2.setOnClickListener(emojiCallback) }
convActionEmoji3.setOnClickListener(emojiCallback) textViews.forEach { it.setOnClickListener(emojiCallback) } // Set callback
convActionEmoji4.setOnClickListener(emojiCallback)
// Configure reply
convActionReply.setOnClickListener { convActionReply.setOnClickListener {
presenter.startReplyTo(interaction) presenter.startReplyTo(interaction)
popupWindow.get()?.dismiss() popupWindow.dismiss()
} }
convActionMore.setOnClickListener { convActionMore.setOnClickListener {
menuActions.isVisible = !menuActions.isVisible menuActions.isVisible = !menuActions.isVisible
} }
// Open file
convActionOpenText.setOnClickListener { convActionOpenText.setOnClickListener {
presenter.openFile(interaction) presenter.openFile(interaction)
} }
// Save file
convActionDownloadText.setOnClickListener { convActionDownloadText.setOnClickListener {
presenter.saveFile(interaction) presenter.saveFile(interaction)
} }
// Manage copy
convActionCopyText.setOnClickListener { convActionCopyText.setOnClickListener {
addToClipboard(lastElement.body) addToClipboard(lastElement.body)
popupWindow.get()?.dismiss() popupWindow.dismiss()
} }
// Manage Edit and Delete actions
if (!interaction.isIncoming) { if (!interaction.isIncoming) {
// Edit
convActionEdit.setOnClickListener { convActionEdit.setOnClickListener {
try { try {
val i = Intent(it.context, MessageEditActivity::class.java) val i = Intent(it.context, MessageEditActivity::class.java)
.setData(Uri.withAppendedPath(ConversationPath.toUri(interaction.account!!, interaction.conversationId!!), interaction.messageId)) .setData(Uri.withAppendedPath(ConversationPath.toUri(interaction.account!!, interaction.conversationId!!), interaction.messageId))
.setAction(Intent.ACTION_EDIT) .setAction(Intent.ACTION_EDIT)
.putExtra(Intent.EXTRA_TEXT, cvh.mMsgTxt!!.text.toString()) .putExtra(Intent.EXTRA_TEXT, conversationViewHolder.mMsgTxt!!.text.toString())
val options = ActivityOptionsCompat.makeSceneTransitionAnimation(conversationFragment.requireActivity(), cvh.mMsgTxt!!, "messageEdit") val options = ActivityOptionsCompat.makeSceneTransitionAnimation(conversationFragment.requireActivity(), conversationViewHolder.mMsgTxt!!, "messageEdit")
conversationFragment.startActivityForResult(i, ConversationFragment.REQUEST_CODE_EDIT_MESSAGE, options.toBundle()) conversationFragment.startActivityForResult(i, ConversationFragment.REQUEST_CODE_EDIT_MESSAGE, options.toBundle())
} catch (e: Exception) { } catch (e: Exception) {
Log.w(TAG, "Can't open picture", e) Log.w(TAG, "Can't open picture", e)
} }
popupWindow.get()?.dismiss() popupWindow.dismiss()
} }
// Delete
convActionDelete.setOnClickListener { convActionDelete.setOnClickListener {
presenter.deleteConversationItem(interaction) presenter.deleteConversationItem(interaction)
popupWindow.get()?.dismiss() popupWindow.dismiss()
} }
} else { } else {
convActionEdit.setOnClickListener(null) convActionEdit.setOnClickListener(null)
convActionDelete.setOnClickListener(null) convActionDelete.setOnClickListener(null)
} }
// Share
convActionShare.setOnClickListener { convActionShare.setOnClickListener {
if (interaction is DataTransfer) if (interaction is DataTransfer)
presenter.shareFile(interaction) presenter.shareFile(interaction)
else if (interaction is TextMessage) else if (interaction is TextMessage)
presenter.shareText(interaction) presenter.shareText(interaction)
popupWindow.get()?.dismiss() popupWindow.dismiss()
} }
// Message history
if (convActionHistory.isVisible) if (convActionHistory.isVisible)
convActionHistory.setOnClickListener { convActionHistory.setOnClickListener {
cvh.compositeDisposable.add( conversationViewHolder.compositeDisposable.add(
interaction.historyObservable.firstOrError().subscribe { c -> interaction.historyObservable.firstOrError().subscribe { c ->
Log.w(TAG, "Message history ${c.size}") Log.w(TAG, "Message history ${c.size}")
c.forEach { c.forEach {
...@@ -839,8 +914,9 @@ class ConversationAdapter( ...@@ -839,8 +914,9 @@ class ConversationAdapter(
{ dialog, which -> dialog.dismiss() } { dialog, which -> dialog.dismiss() }
.create() .create()
.show() .show()
}) }
popupWindow.get()?.dismiss() )
popupWindow.dismiss()
} }
} }
} }
......
...@@ -15,49 +15,17 @@ ...@@ -15,49 +15,17 @@
android:orientation="horizontal" android:orientation="horizontal"
android:padding="8dp"> android:padding="8dp">
<TextView <include layout="@layout/item_reaction_chip_18"
android:id="@+id/conv_action_emoji1" 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" />
<TextView <include layout="@layout/item_reaction_chip_18"
android:id="@+id/conv_action_emoji2" 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" />
<TextView <include layout="@layout/item_reaction_chip_18"
android:id="@+id/conv_action_emoji3" 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" />
<TextView <include layout="@layout/item_reaction_chip_18"
android:id="@+id/conv_action_emoji4" 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" />
<ImageView <ImageView
android:visibility="gone" android:visibility="gone"
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment