Skip to content

Commit 6799085

Browse files
Merge pull request #5905 from nextcloud/feat/5240/messageDoubleTap
👇👇 Add message double tap action
2 parents 5c346a8 + a0f61e9 commit 6799085

7 files changed

Lines changed: 137 additions & 39 deletions

app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingDeckCardViewHolder.kt

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import android.annotation.SuppressLint
1111
import android.content.Context
1212
import android.content.Intent
1313
import android.util.Log
14+
import android.view.GestureDetector
15+
import android.view.MotionEvent
1416
import android.view.View
1517
import android.widget.ImageView
1618
import androidx.core.content.ContextCompat
@@ -74,7 +76,7 @@ class IncomingDeckCardViewHolder(incomingView: View, payload: Any) :
7476
var boardName: String? = null
7577
var cardLink: String? = null
7678

77-
@SuppressLint("SetTextI18n")
79+
@SuppressLint("SetTextI18n", "ClickableViewAccessibility")
7880
override fun onBind(message: ChatMessage) {
7981
super.onBind(message)
8082
this.message = message
@@ -95,9 +97,22 @@ class IncomingDeckCardViewHolder(incomingView: View, payload: Any) :
9597
// parent message handling
9698
setParentMessageDataOnMessageItem(message)
9799

98-
binding.cardView.setOnLongClickListener { l: View? ->
99-
commonMessageInterface.onOpenMessageActionsDialog(message)
100-
true
100+
binding.cardView.isLongClickable = true
101+
val cardViewGestureDetector = GestureDetector(
102+
context,
103+
object : GestureDetector.SimpleOnGestureListener() {
104+
override fun onLongPress(e: MotionEvent) {
105+
commonMessageInterface.onOpenMessageActionsDialog(message)
106+
}
107+
override fun onDoubleTap(e: MotionEvent): Boolean {
108+
commonMessageInterface.onOpenMessageActionsDialog(message)
109+
return true
110+
}
111+
}
112+
)
113+
binding.cardView.setOnTouchListener { _, event ->
114+
cardViewGestureDetector.onTouchEvent(event)
115+
false
101116
}
102117

103118
binding.cardView.setOnClickListener {

app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingLinkPreviewMessageViewHolder.kt

Lines changed: 39 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@ package com.nextcloud.talk.adapters.messages
99

1010
import android.annotation.SuppressLint
1111
import android.content.Context
12+
import android.text.Spanned
1213
import android.util.Log
14+
import android.view.GestureDetector
15+
import android.view.MotionEvent
1316
import android.view.View
1417
import androidx.core.content.ContextCompat
1518
import autodagger.AutoInjector
@@ -64,27 +67,14 @@ class IncomingLinkPreviewMessageViewHolder(incomingView: View, payload: Any) :
6467

6568
lateinit var commonMessageInterface: CommonMessageInterface
6669

67-
@SuppressLint("SetTextI18n")
70+
@SuppressLint("SetTextI18n", "ClickableViewAccessibility")
6871
override fun onBind(message: ChatMessage) {
6972
super.onBind(message)
7073
this.message = message
7174
sharedApplication!!.componentApplication.inject(this)
7275
binding.messageTime.text = dateUtils.getLocalTimeStringFromTimestamp(message.timestamp)
7376

74-
var processedMessageText = messageUtils.enrichChatMessageText(
75-
binding.messageText.context,
76-
message,
77-
true,
78-
viewThemeUtils
79-
)
80-
81-
processedMessageText = messageUtils.processMessageParameters(
82-
binding.messageText.context,
83-
viewThemeUtils,
84-
processedMessageText!!,
85-
message,
86-
itemView
87-
)
77+
val processedMessageText = processMessageText(message)
8878

8979
binding.messageText.text = processedMessageText
9080

@@ -103,9 +93,22 @@ class IncomingLinkPreviewMessageViewHolder(incomingView: View, payload: Any) :
10393
binding.referenceInclude,
10494
itemView.context
10595
)
106-
binding.referenceInclude.referenceWrapper.setOnLongClickListener { l: View? ->
107-
commonMessageInterface.onOpenMessageActionsDialog(message)
108-
true
96+
binding.referenceInclude.referenceWrapper.isLongClickable = true
97+
val referenceWrapperGestureDetector = GestureDetector(
98+
context,
99+
object : GestureDetector.SimpleOnGestureListener() {
100+
override fun onLongPress(e: MotionEvent) {
101+
commonMessageInterface.onOpenMessageActionsDialog(message)
102+
}
103+
override fun onDoubleTap(e: MotionEvent): Boolean {
104+
commonMessageInterface.onOpenMessageActionsDialog(message)
105+
return true
106+
}
107+
}
108+
)
109+
binding.referenceInclude.referenceWrapper.setOnTouchListener { _, event ->
110+
referenceWrapperGestureDetector.onTouchEvent(event)
111+
false
109112
}
110113

111114
itemView.setTag(R.string.replyable_message_view_tag, message.replyable)
@@ -134,6 +137,24 @@ class IncomingLinkPreviewMessageViewHolder(incomingView: View, payload: Any) :
134137
)
135138
}
136139

140+
private fun processMessageText(message: ChatMessage): Spanned? {
141+
var processedMessageText = messageUtils.enrichChatMessageText(
142+
binding.messageText.context,
143+
message,
144+
true,
145+
viewThemeUtils
146+
)
147+
148+
processedMessageText = messageUtils.processMessageParameters(
149+
binding.messageText.context,
150+
viewThemeUtils,
151+
processedMessageText!!,
152+
message,
153+
itemView
154+
)
155+
return processedMessageText
156+
}
157+
137158
private fun longClickOnReaction(chatMessage: ChatMessage) {
138159
commonMessageInterface.onLongClickReactions(chatMessage)
139160
}

app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingTextMessageViewHolder.kt

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,12 @@
99
*/
1010
package com.nextcloud.talk.adapters.messages
1111

12+
import android.annotation.SuppressLint
1213
import android.content.Context
1314
import android.util.Log
1415
import android.util.TypedValue
16+
import android.view.GestureDetector
17+
import android.view.MotionEvent
1518
import android.view.View
1619
import android.view.ViewGroup
1720
import android.widget.CheckBox
@@ -98,6 +101,7 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) :
98101
processMessage(message, hasCheckboxes)
99102
}
100103

104+
@SuppressLint("ClickableViewAccessibility")
101105
@Suppress("LongMethod")
102106
private fun processMessage(message: ChatMessage, hasCheckboxes: Boolean) {
103107
var textSize = context.resources!!.getDimension(R.dimen.chat_text_size)
@@ -181,9 +185,22 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) :
181185
View.GONE
182186
}
183187

184-
binding.messageQuote.quotedChatMessageView.setOnLongClickListener { l: View? ->
185-
commonMessageInterface.onOpenMessageActionsDialog(message)
186-
true
188+
binding.messageQuote.quotedChatMessageView.isLongClickable = true
189+
val quotedChatMessageViewGestureDetector = GestureDetector(
190+
context,
191+
object : GestureDetector.SimpleOnGestureListener() {
192+
override fun onLongPress(e: MotionEvent) {
193+
commonMessageInterface.onOpenMessageActionsDialog(message)
194+
}
195+
override fun onDoubleTap(e: MotionEvent): Boolean {
196+
commonMessageInterface.onOpenMessageActionsDialog(message)
197+
return true
198+
}
199+
}
200+
)
201+
binding.messageQuote.quotedChatMessageView.setOnTouchListener { _, event ->
202+
quotedChatMessageViewGestureDetector.onTouchEvent(event)
203+
false
187204
}
188205

189206
itemView.setTag(R.string.replyable_message_view_tag, message.replyable)

app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingVoiceMessageViewHolder.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,6 @@ class IncomingVoiceMessageViewHolder(incomingView: View, payload: Any) :
9595
binding.messageTime.text = dateUtils.getLocalTimeStringFromTimestamp(message.timestamp)
9696

9797
setAvatarAndAuthorOnMessageItem(message)
98-
9998
colorizeMessageBubble(message)
10099

101100
itemView.isSelected = false

app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingLinkPreviewMessageViewHolder.kt

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ package com.nextcloud.talk.adapters.messages
1111
import android.annotation.SuppressLint
1212
import android.content.Context
1313
import android.util.Log
14+
import android.view.GestureDetector
15+
import android.view.MotionEvent
1416
import android.view.View
1517
import androidx.appcompat.content.res.AppCompatResources
1618
import autodagger.AutoInjector
@@ -67,7 +69,7 @@ class OutcomingLinkPreviewMessageViewHolder(outcomingView: View, payload: Any) :
6769

6870
lateinit var commonMessageInterface: CommonMessageInterface
6971

70-
@SuppressLint("SetTextI18n")
72+
@SuppressLint("SetTextI18n", "ClickableViewAccessibility")
7173
override fun onBind(message: ChatMessage) {
7274
super.onBind(message)
7375
this.message = message
@@ -87,7 +89,6 @@ class OutcomingLinkPreviewMessageViewHolder(outcomingView: View, payload: Any) :
8789
)
8890

8991
binding.messageText.text = processedMessageText
90-
9192
itemView.isSelected = false
9293

9394
// parent message handling
@@ -114,15 +115,23 @@ class OutcomingLinkPreviewMessageViewHolder(outcomingView: View, payload: Any) :
114115

115116
binding.checkMark.contentDescription = readStatusContentDescriptionString
116117

117-
LinkPreview().showLink(
118-
message,
119-
ncApi,
120-
binding.referenceInclude,
121-
itemView.context
118+
LinkPreview().showLink(message, ncApi, binding.referenceInclude, itemView.context)
119+
binding.referenceInclude.referenceWrapper.isLongClickable = true
120+
val referenceWrapperGestureDetector = GestureDetector(
121+
context,
122+
object : GestureDetector.SimpleOnGestureListener() {
123+
override fun onLongPress(e: MotionEvent) {
124+
commonMessageInterface.onOpenMessageActionsDialog(message)
125+
}
126+
override fun onDoubleTap(e: MotionEvent): Boolean {
127+
commonMessageInterface.onOpenMessageActionsDialog(message)
128+
return true
129+
}
130+
}
122131
)
123-
binding.referenceInclude.referenceWrapper.setOnLongClickListener { l: View? ->
124-
commonMessageInterface.onOpenMessageActionsDialog(message)
125-
true
132+
binding.referenceInclude.referenceWrapper.setOnTouchListener { _, event ->
133+
referenceWrapperGestureDetector.onTouchEvent(event)
134+
false
126135
}
127136

128137
itemView.setTag(R.string.replyable_message_view_tag, message.replyable)

app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingTextMessageViewHolder.kt

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,12 @@
99
*/
1010
package com.nextcloud.talk.adapters.messages
1111

12+
import android.annotation.SuppressLint
1213
import android.content.Context
1314
import android.util.Log
1415
import android.util.TypedValue
16+
import android.view.GestureDetector
17+
import android.view.MotionEvent
1518
import android.view.View
1619
import android.view.ViewGroup
1720
import android.widget.CheckBox
@@ -102,6 +105,7 @@ class OutcomingTextMessageViewHolder(itemView: View) :
102105
processMessage(message, hasCheckboxes)
103106
}
104107

108+
@SuppressLint("ClickableViewAccessibility")
105109
@Suppress("Detekt.LongMethod")
106110
private fun processMessage(message: ChatMessage, hasCheckboxes: Boolean) {
107111
var isBubbled = true
@@ -196,9 +200,22 @@ class OutcomingTextMessageViewHolder(itemView: View) :
196200
View.GONE
197201
}
198202

199-
binding.messageQuote.quotedChatMessageView.setOnLongClickListener { l: View? ->
200-
commonMessageInterface.onOpenMessageActionsDialog(message)
201-
true
203+
binding.messageQuote.quotedChatMessageView.isLongClickable = true
204+
val quotedChatMessageViewGestureDetector = GestureDetector(
205+
context,
206+
object : GestureDetector.SimpleOnGestureListener() {
207+
override fun onLongPress(e: MotionEvent) {
208+
commonMessageInterface.onOpenMessageActionsDialog(message)
209+
}
210+
override fun onDoubleTap(e: MotionEvent): Boolean {
211+
commonMessageInterface.onOpenMessageActionsDialog(message)
212+
return true
213+
}
214+
}
215+
)
216+
binding.messageQuote.quotedChatMessageView.setOnTouchListener { _, event ->
217+
quotedChatMessageViewGestureDetector.onTouchEvent(event)
218+
false
202219
}
203220

204221
binding.checkMark.visibility = View.INVISIBLE

app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import android.net.Uri
2929
import android.os.Build
3030
import android.os.Bundle
3131
import android.os.Handler
32+
import android.os.SystemClock
3233
import android.provider.ContactsContract
3334
import android.provider.MediaStore
3435
import android.provider.Settings
@@ -39,6 +40,7 @@ import android.view.Gravity
3940
import android.view.Menu
4041
import android.view.MenuItem
4142
import android.view.View
43+
import android.view.ViewConfiguration
4244
import android.view.ViewGroup
4345
import android.view.WindowManager
4446
import android.view.animation.AccelerateDecelerateInterpolator
@@ -263,6 +265,7 @@ class ChatActivity :
263265
MessagesListAdapter.OnLoadMoreListener,
264266
MessagesListAdapter.Formatter<Date>,
265267
MessagesListAdapter.OnMessageViewLongClickListener<IMessage>,
268+
MessagesListAdapter.OnMessageClickListener<IMessage>,
266269
ContentChecker<ChatMessage>,
267270
VoiceMessageInterface,
268271
CommonMessageInterface,
@@ -386,6 +389,8 @@ class ChatActivity :
386389
var credentials: String? = null
387390
var currentConversation: ConversationModel? = null
388391
var adapter: TalkMessagesListAdapter<ChatMessage>? = null
392+
private var lastMessageClickTime = 0L
393+
private var lastMessageId = ""
389394
var mentionAutocomplete: Autocomplete<*>? = null
390395
var layoutManager: LinearLayoutManager? = null
391396
var pullChatMessagesPending = false
@@ -1644,6 +1649,7 @@ class ChatActivity :
16441649
adapter?.setLoadMoreListener(this)
16451650
adapter?.setDateHeadersFormatter { format(it) }
16461651
adapter?.setOnMessageViewLongClickListener { view, message -> onMessageViewLongClick(view, message) }
1652+
adapter?.setOnMessageClickListener { message -> onMessageClick(message) }
16471653

16481654
adapter?.registerViewClickListener(
16491655
R.id.playPauseBtn
@@ -4087,6 +4093,20 @@ class ChatActivity :
40874093
openMessageActionsDialog(message)
40884094
}
40894095

4096+
override fun onMessageClick(message: IMessage) {
4097+
val now = SystemClock.elapsedRealtime()
4098+
if (now - lastMessageClickTime < ViewConfiguration.getDoubleTapTimeout() &&
4099+
message.id?.equals(lastMessageId) == true
4100+
) {
4101+
openMessageActionsDialog(message)
4102+
lastMessageClickTime = 0L
4103+
lastMessageId = ""
4104+
} else {
4105+
lastMessageClickTime = now
4106+
lastMessageId = message.id
4107+
}
4108+
}
4109+
40904110
override fun onPreviewMessageLongClick(chatMessage: ChatMessage) {
40914111
onOpenMessageActionsDialog(chatMessage)
40924112
}

0 commit comments

Comments
 (0)