Handling Control Messages longpress and deletion

pull/1518/head
ThomasSession 6 months ago
parent c50d38e85c
commit 94688c2b07

@ -130,6 +130,7 @@ import org.thoughtcrime.securesms.conversation.v2.mention.MentionViewModel
import org.thoughtcrime.securesms.conversation.v2.menus.ConversationActionModeCallback
import org.thoughtcrime.securesms.conversation.v2.menus.ConversationActionModeCallbackDelegate
import org.thoughtcrime.securesms.conversation.v2.menus.ConversationMenuHelper
import org.thoughtcrime.securesms.conversation.v2.messages.ControlMessageView
import org.thoughtcrime.securesms.conversation.v2.messages.VisibleMessageView
import org.thoughtcrime.securesms.conversation.v2.messages.VisibleMessageViewDelegate
import org.thoughtcrime.securesms.conversation.v2.search.SearchBottomBar
@ -1311,8 +1312,9 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
private fun showConversationReaction(message: MessageRecord, messageView: View) {
val messageContentView = when(messageView){
is VisibleMessageView -> messageView.messageContentView
else -> messageView
}
is ControlMessageView -> messageView.controlContentView
else -> null
} ?: return
val messageContentBitmap = try {
messageContentView.drawToBitmap()

@ -223,7 +223,6 @@ class ConversationReactionOverlay : FrameLayout {
endScale = spaceAvailableForItem / conversationItemSnapshot.height
endX += Util.halfOffsetFromScale(conversationItemSnapshot.width, endScale) * if (isMessageOnLeft) -1 else 1
endY = spaceForReactionBar - Util.halfOffsetFromScale(conversationItemSnapshot.height, endScale)
val contextMenuTop = endY + conversationItemSnapshot.height * endScale
reactionBarBackgroundY = reactionBarTopPadding //getReactionBarOffsetForTouch(selectedConversationModel.getBubbleY(), contextMenuTop + Util.halfOffsetFromScale(conversationItemSnapshot.getHeight(), endScale), menuPadding, reactionBarOffset, reactionBarHeight, reactionBarTopPadding, endY);
endApparentTop = endY + Util.halfOffsetFromScale(conversationItemSnapshot.height, endScale)
} else {
@ -272,11 +271,17 @@ class ConversationReactionOverlay : FrameLayout {
revealAnimatorSet.start()
if (isWideLayout) {
val scrubberRight = scrubberX + scrubberWidth
val offsetX = if (isMessageOnLeft) scrubberRight + menuPadding else scrubberX - contextMenu.getMaxWidth() - menuPadding
val offsetX = when {
isMessageOnLeft -> scrubberRight + menuPadding
else -> scrubberX - contextMenu.getMaxWidth() - menuPadding
}
contextMenu.show(offsetX.toInt(), Math.min(backgroundView.y, (overlayHeight - contextMenu.getMaxHeight()).toFloat()).toInt())
} else {
val contentX = if (isMessageOnLeft) scrubberHorizontalMargin.toFloat() else selectedConversationModel.bubbleX
val offsetX = if (isMessageOnLeft) contentX else -contextMenu.getMaxWidth() + contentX + bubbleWidth
val offsetX = when {
isMessageOnLeft -> contentX
else -> -contextMenu.getMaxWidth() + contentX + bubbleWidth
}
val menuTop = endApparentTop + conversationItemSnapshot.height * endScale
contextMenu.show(offsetX.toInt(), (menuTop + menuPadding).toInt())
}
@ -527,8 +532,12 @@ class ConversationReactionOverlay : FrameLayout {
val recipient = get(context).threadDatabase().getRecipientForThreadId(message.threadId)
?: return emptyList()
val userPublicKey = getLocalNumber(context)!!
// control messages and "marked as deleted" messages can only delete
val isDeleteOnly = message.isDeleted || message.isControlMessage
// Select message
if(!message.isDeleted) {
if(!isDeleteOnly) {
items += ActionItem(
R.attr.menu_select_icon,
R.string.select,
@ -538,15 +547,15 @@ class ConversationReactionOverlay : FrameLayout {
}
// Reply
val canWrite = openGroup == null || openGroup.canWrite
if (canWrite && !message.isPending && !message.isFailed && !message.isOpenGroupInvitation && !message.isDeleted) {
if (canWrite && !message.isPending && !message.isFailed && !message.isOpenGroupInvitation && !isDeleteOnly) {
items += ActionItem(R.attr.menu_reply_icon, R.string.reply, { handleActionItemClicked(Action.REPLY) }, R.string.AccessibilityId_reply)
}
// Copy message text
if (!containsControlMessage && hasText && !message.isDeleted) {
if (!containsControlMessage && hasText && !isDeleteOnly) {
items += ActionItem(R.attr.menu_copy_icon, R.string.copy, { handleActionItemClicked(Action.COPY_MESSAGE) })
}
// Copy Account ID
if (!recipient.isCommunityRecipient && message.isIncoming && !message.isDeleted) {
if (!recipient.isCommunityRecipient && message.isIncoming && !isDeleteOnly) {
items += ActionItem(R.attr.menu_copy_icon, R.string.accountIDCopy, { handleActionItemClicked(Action.COPY_ACCOUNT_ID) })
}
// Delete message
@ -555,15 +564,15 @@ class ConversationReactionOverlay : FrameLayout {
R.string.AccessibilityId_deleteMessage, message.subtitle, ThemeUtil.getThemedColor(context, R.attr.danger))
}
// Ban user
if (userCanBanSelectedUsers(context, message, openGroup, userPublicKey, blindedPublicKey) && !message.isDeleted) {
if (userCanBanSelectedUsers(context, message, openGroup, userPublicKey, blindedPublicKey) && !isDeleteOnly) {
items += ActionItem(R.attr.menu_block_icon, R.string.banUser, { handleActionItemClicked(Action.BAN_USER) })
}
// Ban and delete all
if (userCanBanSelectedUsers(context, message, openGroup, userPublicKey, blindedPublicKey) && !message.isDeleted) {
if (userCanBanSelectedUsers(context, message, openGroup, userPublicKey, blindedPublicKey) && !isDeleteOnly) {
items += ActionItem(R.attr.menu_trash_icon, R.string.banDeleteAll, { handleActionItemClicked(Action.BAN_AND_DELETE_ALL) })
}
// Message detail
if(!message.isDeleted) {
if(!isDeleteOnly) {
items += ActionItem(
R.attr.menu_info_icon,
R.string.messageInfo,
@ -578,7 +587,7 @@ class ConversationReactionOverlay : FrameLayout {
items += ActionItem(R.attr.menu_reply_icon, R.string.resync, { handleActionItemClicked(Action.RESYNC) })
}
// Save media..
if (message.isMms && !message.isDeleted) {
if (message.isMms && !isDeleteOnly) {
// ..but only provide the save option if the there is a media attachment which has finished downloading.
val mmsMessage = message as MediaMmsMessageRecord
if (mmsMessage.containsMediaSlide() && !mmsMessage.isMediaPending) {
@ -591,8 +600,8 @@ class ConversationReactionOverlay : FrameLayout {
}
// deleted messages have no emoji reactions
backgroundView.isVisible = !message.isDeleted
foregroundView.isVisible = !message.isDeleted
backgroundView.isVisible = !isDeleteOnly
foregroundView.isVisible = !isDeleteOnly
return items
}

@ -235,8 +235,6 @@ class ConversationViewModel(
// Refer to our figma document for info on message deletion [https://www.figma.com/design/kau6LggVcMMWmZRMibEo8F/Standardise-Message-Deletion?node-id=0-1&t=dEPcU0SZ9G2s4gh2-0]
//todo DELETION handle control messages deletion ( and make clickable )
//todo DELETION handle multi select scenarios
viewModelScope.launch(Dispatchers.IO) {
@ -304,7 +302,7 @@ class ConversationViewModel(
* otherwise they will appear as a special type of message
* that says something like "This message was deleted"
*/
fun deletedLocally(messages: Set<MessageRecord>) {
fun deleteLocally(messages: Set<MessageRecord>) {
// make sure to stop audio messages, if any
messages.filterIsInstance<MmsMessageRecord>()
.mapNotNull { it.slideDeck.audioSlide }
@ -734,7 +732,7 @@ class ConversationViewModel(
it.copy(deleteDeviceOnly = null)
}
deletedLocally(command.messages)
deleteLocally(command.messages)
}
is Commands.MarkAsDeletedForEveryone -> {
markAsDeletedForEveryone(command.data)

@ -6,6 +6,7 @@ import android.content.Intent
import android.util.AttributeSet
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.widget.LinearLayout
import androidx.core.content.res.ResourcesCompat
import androidx.core.view.isGone
@ -54,6 +55,8 @@ class ControlMessageView : LinearLayout {
@Inject lateinit var disappearingMessages: DisappearingMessages
val controlContentView: View get() = binding.controlContentView
init {
layoutParams = RecyclerView.LayoutParams(RecyclerView.LayoutParams.MATCH_PARENT, RecyclerView.LayoutParams.WRAP_CONTENT)
}
@ -84,7 +87,7 @@ class ControlMessageView : LinearLayout {
&& message.expiryMode != (MessagingModuleConfiguration.shared.storage.getExpirationConfiguration(message.threadId)?.expiryMode ?: ExpiryMode.NONE)
&& threadRecipient?.isGroupRecipient != true
followSetting.setOnClickListener { disappearingMessages.showFollowSettingDialog(context, message) }
binding.controlContentView.setOnClickListener { disappearingMessages.showFollowSettingDialog(context, message) }
}
}
message.isMediaSavedNotification -> {
@ -128,7 +131,7 @@ class ControlMessageView : LinearLayout {
}
// remove clicks by default
setOnClickListener(null)
binding.controlContentView.setOnClickListener(null)
hideInfo()
// handle click behaviour depending on criteria
@ -138,7 +141,7 @@ class ControlMessageView : LinearLayout {
// show a dedicated privacy dialog
!TextSecurePreferences.isCallNotificationsEnabled(context) -> {
showInfo()
setOnClickListener {
binding.controlContentView.setOnClickListener {
context.showSessionDialog {
val titleTxt = context.getSubbedString(
R.string.callsMissedCallFrom,
@ -165,7 +168,7 @@ class ControlMessageView : LinearLayout {
// show a dedicated permission dialog
!Permissions.hasAll(context, Manifest.permission.RECORD_AUDIO) -> {
showInfo()
setOnClickListener {
binding.controlContentView.setOnClickListener {
context.showSessionDialog {
val titleTxt = context.getSubbedString(
R.string.callsMissedCallFrom,
@ -201,11 +204,8 @@ class ControlMessageView : LinearLayout {
binding.callView.isVisible = message.isCallLog
// handle long clicked if it was passed on
//todo DELETION currently control messages lose their ability to be clickable due to the long click, like the "mised phone call" CM
Log.d("", "*** Has long click? $longPress")
longPress?.let {
binding.root.setOnLongClickListener {
Log.d("", "*** Long clicking")
binding.controlContentView.setOnLongClickListener {
longPress.invoke()
true
}

@ -552,7 +552,6 @@ class HomeActivity : PassphraseRequiredActionBarActivity(),
} else {
showMuteDialog(this) { until ->
lifecycleScope.launch(Dispatchers.IO) {
Log.d("", "**** until: $until")
recipientDatabase.setMuted(thread.recipient, until)
withContext(Dispatchers.Main) {
binding.recyclerView.adapter!!.notifyDataSetChanged()

@ -27,7 +27,7 @@
android:visibility="gone"
app:tint="?android:textColorTertiary"
tools:src="@drawable/ic_timer"
tools:visibility="visible"/>
tools:visibility="visible" />
<org.thoughtcrime.securesms.conversation.v2.components.ExpirationTimerView
android:id="@+id/expirationTimerView"
@ -37,47 +37,57 @@
android:visibility="gone"
app:tint="?android:textColorTertiary"
tools:src="@drawable/ic_timer"
tools:visibility="visible"/>
tools:visibility="visible" />
<TextView
android:id="@+id/textView"
android:contentDescription="@string/AccessibilityId_control_message"
<LinearLayout
android:id="@+id/controlContentView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:textColor="?android:textColorTertiary"
android:textSize="@dimen/very_small_font_size"
tools:text="You disabled disappearing messages" />
<FrameLayout
android:id="@+id/call_view"
style="@style/CallMessage"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
android:orientation="vertical">
<TextView
android:id="@+id/call_text_view"
android:textColor="?message_received_text_color"
android:textAlignment="center"
android:layout_gravity="center"
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:contentDescription="@string/AccessibilityId_control_message"
android:gravity="center"
tools:text="You missed a call"
android:textColor="?android:textColorTertiary"
android:textSize="@dimen/very_small_font_size"
tools:text="You disabled disappearing messages" />
<FrameLayout
android:id="@+id/call_view"
style="@style/CallMessage"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:drawableStartCompat="@drawable/ic_missed_call" />
android:layout_height="wrap_content"
android:orientation="horizontal">
</FrameLayout>
<TextView
android:id="@+id/call_text_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:gravity="center"
android:textAlignment="center"
android:textColor="?message_received_text_color"
app:drawableStartCompat="@drawable/ic_missed_call"
tools:text="You missed a call" />
<TextView
android:id="@+id/followSetting"
style="@style/Widget.Session.Button.Common.Borderless"
android:layout_marginTop="4dp"
android:textColor="@color/accent_green"
android:textSize="@dimen/very_small_font_size"
android:text="@string/disappearingMessagesFollowSetting"
android:contentDescription="@string/AccessibilityId_disappearingMessagesFollowSetting"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</FrameLayout>
<TextView
android:id="@+id/followSetting"
style="@style/Widget.Session.Button.Common.Borderless"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:background="@null"
android:contentDescription="@string/AccessibilityId_disappearingMessagesFollowSetting"
android:text="@string/disappearingMessagesFollowSetting"
android:textColor="@color/accent_green"
android:textSize="@dimen/very_small_font_size" />
</LinearLayout>
</LinearLayout>
Loading…
Cancel
Save