mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-21 17:29:32 +01:00
Add double tap editing feature.
This commit is contained in:
committed by
Greyson Parrelli
parent
84e654efb2
commit
ffc1463cda
@@ -40,6 +40,7 @@ import android.text.style.StyleSpan;
|
||||
import android.text.style.URLSpan;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.TypedValue;
|
||||
import android.view.GestureDetector;
|
||||
import android.view.HapticFeedbackConstants;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.TouchDelegate;
|
||||
@@ -256,6 +257,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
|
||||
private final UrlClickListener urlClickListener = new UrlClickListener();
|
||||
private final Rect thumbnailMaskingRect = new Rect();
|
||||
private final TouchDelegateChangedListener touchDelegateChangedListener = new TouchDelegateChangedListener();
|
||||
private final DoubleTapEditTouchListener doubleTapEditTouchListener = new DoubleTapEditTouchListener();
|
||||
private final GiftMessageViewCallback giftMessageViewCallback = new GiftMessageViewCallback();
|
||||
|
||||
private final Context context;
|
||||
@@ -351,6 +353,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
|
||||
|
||||
setOnClickListener(new ClickListener(null));
|
||||
|
||||
bodyText.setOnTouchListener(doubleTapEditTouchListener);
|
||||
bodyText.setOnLongClickListener(passthroughClickListener);
|
||||
bodyText.setOnClickListener(passthroughClickListener);
|
||||
footer.setOnTouchDelegateChangedListener(touchDelegateChangedListener);
|
||||
@@ -2438,6 +2441,24 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
|
||||
}
|
||||
}
|
||||
|
||||
private class DoubleTapEditTouchListener implements View.OnTouchListener {
|
||||
private final GestureDetector gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
|
||||
@Override
|
||||
public boolean onDoubleTap(MotionEvent e) {
|
||||
if (eventListener != null && batchSelected.isEmpty()) {
|
||||
eventListener.onItemDoubleClick(getMultiselectPartForLatestTouch());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
@Override
|
||||
public boolean onTouch(View v, MotionEvent event) {
|
||||
return gestureDetector.onTouchEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
private class AttachmentDownloadClickListener implements SlidesClickedListener {
|
||||
@Override
|
||||
public void onClick(View v, final List<Slide> slides) {
|
||||
|
||||
@@ -277,6 +277,7 @@ class ScheduledMessagesBottomSheet : FixedRoundedCornerBottomSheetDialogFragment
|
||||
override fun onShowSafetyTips(forGroup: Boolean) = Unit
|
||||
override fun onReportSpamLearnMoreClicked() = Unit
|
||||
override fun onMessageRequestAcceptOptionsClicked() = Unit
|
||||
override fun onItemDoubleClick(item: MultiselectPart) = Unit
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
@@ -261,6 +261,7 @@ class MessageQuotesBottomSheet : FixedRoundedCornerBottomSheetDialogFragment() {
|
||||
override fun onShowSafetyTips(forGroup: Boolean) = Unit
|
||||
override fun onReportSpamLearnMoreClicked() = Unit
|
||||
override fun onMessageRequestAcceptOptionsClicked() = Unit
|
||||
override fun onItemDoubleClick(item: MultiselectPart) = Unit
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
@@ -168,6 +168,7 @@ class EditMessageHistoryDialog : FixedRoundedCornerBottomSheetDialogFragment() {
|
||||
override fun onShowSafetyTips(forGroup: Boolean) = Unit
|
||||
override fun onReportSpamLearnMoreClicked() = Unit
|
||||
override fun onMessageRequestAcceptOptionsClicked() = Unit
|
||||
override fun onItemDoubleClick(item: MultiselectPart) = Unit
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
@@ -351,7 +351,8 @@ class ConversationFragment :
|
||||
ConversationBottomSheetCallback,
|
||||
SafetyNumberBottomSheet.Callbacks,
|
||||
EnableCallNotificationSettingsDialog.Callback,
|
||||
MultiselectForwardBottomSheet.Callback {
|
||||
MultiselectForwardBottomSheet.Callback,
|
||||
DoubleTapEditEducationSheet.Callback {
|
||||
|
||||
companion object {
|
||||
private val TAG = Log.tag(ConversationFragment::class.java)
|
||||
@@ -2755,6 +2756,20 @@ class ConversationFragment :
|
||||
RecipientBottomSheetDialogFragment.show(childFragmentManager, recipientId, groupId)
|
||||
}
|
||||
|
||||
override fun onItemDoubleClick(item: MultiselectPart) {
|
||||
Log.d(TAG, "onItemDoubleClick")
|
||||
if (!isValidEditMessageSend(item.getMessageRecord(), System.currentTimeMillis())) {
|
||||
return
|
||||
}
|
||||
|
||||
if (SignalStore.uiHints().hasSeenDoubleTapEditEducationSheet) {
|
||||
onDoubleTapEditEducationSheetNext(item.conversationMessage)
|
||||
return
|
||||
}
|
||||
|
||||
DoubleTapEditEducationSheet(item).show(childFragmentManager, DoubleTapEditEducationSheet.KEY)
|
||||
}
|
||||
|
||||
override fun onMessageWithErrorClicked(messageRecord: MessageRecord) {
|
||||
val recipientId = viewModel.recipientSnapshot?.id ?: return
|
||||
if (messageRecord.isIdentityMismatchFailure) {
|
||||
@@ -4307,4 +4322,8 @@ class ConversationFragment :
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDoubleTapEditEducationSheetNext(conversationMessage: ConversationMessage) {
|
||||
handleEditMessage(conversationMessage)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
package org.thoughtcrime.securesms.conversation.v2
|
||||
|
||||
import android.content.DialogInterface
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import com.google.android.material.button.MaterialButton
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.components.FixedRoundedCornerBottomSheetDialogFragment
|
||||
import org.thoughtcrime.securesms.conversation.ConversationMessage
|
||||
import org.thoughtcrime.securesms.conversation.mutiselect.MultiselectPart
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.util.fragments.requireListener
|
||||
|
||||
/**
|
||||
* Shows an education sheet to users explaining how double tapping a sent message within 24hrs will allow them to edit it
|
||||
*/
|
||||
class DoubleTapEditEducationSheet(private val item: MultiselectPart) : FixedRoundedCornerBottomSheetDialogFragment() {
|
||||
|
||||
companion object {
|
||||
const val KEY = "DOUBLE_TAP_EDIT_EDU"
|
||||
}
|
||||
|
||||
override val peekHeightPercentage: Float = 1f
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
return inflater.inflate(R.layout.conversation_item_double_tap_edit_education_sheet, container, false)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
SignalStore.uiHints().hasSeenDoubleTapEditEducationSheet = true
|
||||
|
||||
view.findViewById<MaterialButton>(R.id.got_it).setOnClickListener {
|
||||
requireListener<Callback>().onDoubleTapEditEducationSheetNext(item.conversationMessage)
|
||||
dismissAllowingStateLoss()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCancel(dialog: DialogInterface) {
|
||||
super.onCancel(dialog)
|
||||
requireListener<Callback>().onDoubleTapEditEducationSheetNext(item.conversationMessage)
|
||||
}
|
||||
|
||||
interface Callback {
|
||||
fun onDoubleTapEditEducationSheetNext(conversationMessage: ConversationMessage)
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,8 @@ import android.text.style.ClickableSpan
|
||||
import android.text.style.ForegroundColorSpan
|
||||
import android.text.style.URLSpan
|
||||
import android.util.TypedValue
|
||||
import android.view.GestureDetector
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.content.ContextCompat
|
||||
@@ -110,6 +112,19 @@ open class V2ConversationItemTextOnlyViewHolder<Model : MappingModel<Model>>(
|
||||
private val senderDrawable = ChatColorsDrawable(conversationContext::getChatColorsData)
|
||||
private val bodyBubbleLayoutTransition = BodyBubbleLayoutTransition()
|
||||
|
||||
private val gestureDetector = GestureDetector(
|
||||
context,
|
||||
object : GestureDetector.SimpleOnGestureListener() {
|
||||
override fun onDoubleTap(e: MotionEvent): Boolean {
|
||||
if (conversationContext.selectedItems.isEmpty()) {
|
||||
conversationContext.clickListener.onItemDoubleClick(getMultiselectPartForLatestTouch())
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
protected lateinit var shape: V2ConversationItemShape.MessageShape
|
||||
|
||||
private val replyDelegate = object : V2ConversationItemLayout.OnMeasureListener {
|
||||
@@ -139,6 +154,7 @@ open class V2ConversationItemTextOnlyViewHolder<Model : MappingModel<Model>>(
|
||||
)
|
||||
}
|
||||
|
||||
binding.body.setOnTouchListener { _, event -> gestureDetector.onTouchEvent(event) }
|
||||
binding.root.setOnClickListener { onBubbleClicked() }
|
||||
binding.root.setOnLongClickListener {
|
||||
conversationContext.clickListener.onItemLongClick(binding.root, getMultiselectPartForLatestTouch())
|
||||
|
||||
Reference in New Issue
Block a user