Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -127,11 +127,7 @@ private void initializeScreenshotSecurity(boolean isResume) {
if (!isResume) {
getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE);
} else {
if (TextSecurePreferences.isScreenSecurityEnabled(this)) {
getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE);
} else {
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_SECURE);
}
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_SECURE);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ import org.thoughtcrime.securesms.components.emoji.EmojiImageView
import org.thoughtcrime.securesms.components.emoji.RecentEmojiPageModel
import org.thoughtcrime.securesms.components.menu.ActionItem
import org.thoughtcrime.securesms.conversation.v2.menus.ConversationMenuItemHelper.userCanBanSelectedUsers
import org.thoughtcrime.securesms.conversation.v2.menus.ConversationMenuItemHelper.userCanDeleteSelectedItems
import org.thoughtcrime.securesms.database.MmsSmsDatabase
import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord
import org.thoughtcrime.securesms.database.model.MessageRecord
Expand Down Expand Up @@ -559,10 +558,8 @@ class ConversationReactionOverlay : FrameLayout {
items += ActionItem(R.attr.menu_copy_icon, R.string.accountIDCopy, { handleActionItemClicked(Action.COPY_ACCOUNT_ID) })
}
// Delete message
if (userCanDeleteSelectedItems(context, message, openGroup, userPublicKey, blindedPublicKey)) {
items += ActionItem(R.attr.menu_trash_icon, R.string.delete, { handleActionItemClicked(Action.DELETE) },
R.string.AccessibilityId_deleteMessage, message.subtitle, ThemeUtil.getThemedColor(context, R.attr.danger))
}
items += ActionItem(R.attr.menu_trash_icon, R.string.delete, { handleActionItemClicked(Action.DELETE) },
R.string.AccessibilityId_deleteMessage, message.subtitle, ThemeUtil.getThemedColor(context, R.attr.danger))
// Ban user
if (userCanBanSelectedUsers(context, message, openGroup, userPublicKey, blindedPublicKey) && !isDeleteOnly) {
items += ActionItem(R.attr.menu_block_icon, R.string.banUser, { handleActionItemClicked(Action.BAN_USER) })
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import network.loki.messenger.R
import org.session.libsession.utilities.StringSubstitutionConstants.APP_NAME_KEY
import org.session.libsession.utilities.StringSubstitutionConstants.EMOJI_KEY
import org.thoughtcrime.securesms.conversation.v2.ConversationViewModel.Commands.*
import org.thoughtcrime.securesms.conversation.v2.ConversationViewModel.DeleteForEveryoneDialogData
import org.thoughtcrime.securesms.database.model.MessageRecord
import org.thoughtcrime.securesms.ui.AlertDialog
import org.thoughtcrime.securesms.ui.DialogButtonModel
import org.thoughtcrime.securesms.ui.GetString
Expand Down Expand Up @@ -48,9 +50,10 @@ fun ConversationV2Dialogs(
)
}

// delete message(s) for everyone
// delete message(s)
if(dialogsState.deleteEveryone != null){
var deleteForEveryone by remember { mutableStateOf(dialogsState.deleteEveryone.defaultToEveryone)}
val data = dialogsState.deleteEveryone
var deleteForEveryone by remember { mutableStateOf(data.defaultToEveryone)}

AlertDialog(
onDismissRequest = {
Expand All @@ -59,17 +62,17 @@ fun ConversationV2Dialogs(
},
title = pluralStringResource(
R.plurals.deleteMessage,
dialogsState.deleteEveryone.messages.size,
dialogsState.deleteEveryone.messages.size
data.messages.size,
data.messages.size
),
text = pluralStringResource(
R.plurals.deleteMessageConfirm,
dialogsState.deleteEveryone.messages.size,
dialogsState.deleteEveryone.messages.size
data.messages.size,
data.messages.size
),
content = {
// add warning text, if any
dialogsState.deleteEveryone.warning?.let {
data.warning?.let {
Text(
text = it,
textAlign = TextAlign.Center,
Expand Down Expand Up @@ -103,9 +106,9 @@ fun ConversationV2Dialogs(
),
option = RadioOption(
value = Unit,
title = GetString(stringResource(R.string.deleteMessageEveryone)),
title = GetString(data.deleteForEveryoneLabel),
selected = deleteForEveryone,
enabled = dialogsState.deleteEveryone.everyoneEnabled
enabled = data.everyoneEnabled
)
) {
deleteForEveryone = true
Expand All @@ -119,9 +122,9 @@ fun ConversationV2Dialogs(
// delete messages based on chosen option
sendCommand(
if(deleteForEveryone) MarkAsDeletedForEveryone(
dialogsState.deleteEveryone.copy(defaultToEveryone = deleteForEveryone)
data.copy(defaultToEveryone = deleteForEveryone)
)
else MarkAsDeletedLocally(dialogsState.deleteEveryone.messages)
else MarkAsDeletedLocally(data.messages)
)
}
),
Expand All @@ -132,76 +135,6 @@ fun ConversationV2Dialogs(
)
}

// delete message(s) for all my devices
if(dialogsState.deleteAllDevices != null){
var deleteAllDevices by remember { mutableStateOf(dialogsState.deleteAllDevices.defaultToEveryone) }

AlertDialog(
onDismissRequest = {
// hide dialog
sendCommand(HideDeleteAllDevicesDialog)
},
title = pluralStringResource(
R.plurals.deleteMessage,
dialogsState.deleteAllDevices.messages.size,
dialogsState.deleteAllDevices.messages.size
),
text = pluralStringResource(
R.plurals.deleteMessageConfirm,
dialogsState.deleteAllDevices.messages.size,
dialogsState.deleteAllDevices.messages.size
),
content = {
TitledRadioButton(
contentPadding = PaddingValues(
horizontal = LocalDimensions.current.xxsSpacing,
vertical = 0.dp
),
option = RadioOption(
value = Unit,
title = GetString(stringResource(R.string.deleteMessageDeviceOnly)),
selected = !deleteAllDevices
)
) {
deleteAllDevices = false
}

TitledRadioButton(
contentPadding = PaddingValues(
horizontal = LocalDimensions.current.xxsSpacing,
vertical = 0.dp
),
option = RadioOption(
value = Unit,
title = GetString(stringResource(R.string.deleteMessageDevicesAll)),
selected = deleteAllDevices
)
) {
deleteAllDevices = true
}
},
buttons = listOf(
DialogButtonModel(
text = GetString(stringResource(id = R.string.delete)),
color = LocalColors.current.danger,
onClick = {
// delete messages based on chosen option
sendCommand(
if(deleteAllDevices) MarkAsDeletedForEveryone(
dialogsState.deleteAllDevices.copy(defaultToEveryone = deleteAllDevices)
)
else MarkAsDeletedLocally(dialogsState.deleteAllDevices.messages)
)
}
),
DialogButtonModel(
GetString(stringResource(R.string.cancel))
)
)
)
}


// Clear emoji
if(dialogsState.clearAllEmoji != null){
AlertDialog(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -245,12 +245,12 @@ class ConversationViewModel(

// hashes are required if wanting to delete messages from the 'storage server'
// They are not required for communities OR if all messages are outgoing
// also we can only delete deleted messages (marked as deleted) locally
// also we can only delete deleted messages and control messages (marked as deleted) locally
val canDeleteForEveryone = messages.all{ !it.isDeleted && !it.isControlMessage } && (
messages.all { it.isOutgoing } ||
conversationType == MessageType.COMMUNITY ||
messages.all { lokiMessageDb.getMessageServerHash(it.id, it.isMms) != null
})
messages.all { lokiMessageDb.getMessageServerHash(it.id, it.isMms) != null }
)

// There are three types of dialogs for deletion:
// 1- Delete on device only OR all devices - Used for Note to self
Expand All @@ -260,11 +260,16 @@ class ConversationViewModel(
// the conversation is a note to self
conversationType == MessageType.NOTE_TO_SELF -> {
_dialogsState.update {
it.copy(deleteAllDevices = DeleteForEveryoneDialogData(
it.copy(deleteEveryone = DeleteForEveryoneDialogData(
messages = messages,
defaultToEveryone = false,
everyoneEnabled = true,
messageType = conversationType
everyoneEnabled = canDeleteForEveryone,
messageType = conversationType,
deleteForEveryoneLabel = application.getString(R.string.deleteMessageDevicesAll),
warning = if(canDeleteForEveryone) null else
application.resources.getQuantityString(
R.plurals.deleteMessageNoteToSelfWarning, messages.count(), messages.count()
)
)
)
}
Expand All @@ -278,6 +283,7 @@ class ConversationViewModel(
messages = messages,
defaultToEveryone = isAdmin.value,
everyoneEnabled = true,
deleteForEveryoneLabel = application.getString(R.string.deleteMessageEveryone),
messageType = conversationType
)
)
Expand All @@ -293,6 +299,7 @@ class ConversationViewModel(
defaultToEveryone = false,
everyoneEnabled = false, // disable 'delete for everyone' - can only delete locally in this case
messageType = conversationType,
deleteForEveryoneLabel = application.getString(R.string.deleteMessageEveryone),
warning = application.resources.getQuantityString(
R.plurals.deleteMessageWarning, messages.count(), messages.count()
)
Expand Down Expand Up @@ -548,7 +555,7 @@ class ConversationViewModel(
).show()
}

_dialogsState.update { it.copy(deleteAllDevices = data) }
_dialogsState.update { it.copy(deleteEveryone = data) }
}

// hide loading indicator
Expand All @@ -565,11 +572,8 @@ class ConversationViewModel(
try {
repository.deleteCommunityMessagesRemotely(threadId, data.messages)

// When this is done we simply need to remove the message locally
repository.markAsDeletedLocally(
messages = data.messages,
displayedMessage = application.getString(R.string.deleteMessageDeletedGlobally)
)
// When this is done we simply need to remove the message locally (leave nothing behind)
repository.deleteMessages(messages = data.messages, threadId = threadId)

// show confirmation toast
withContext(Dispatchers.Main) {
Expand Down Expand Up @@ -731,12 +735,6 @@ class ConversationViewModel(
}
}

is Commands.HideDeleteAllDevicesDialog -> {
_dialogsState.update {
it.copy(deleteAllDevices = null)
}
}

is Commands.MarkAsDeletedLocally -> {
// hide dialog first
_dialogsState.update {
Expand Down Expand Up @@ -818,15 +816,15 @@ class ConversationViewModel(
data class DialogsState(
val openLinkDialogUrl: String? = null,
val clearAllEmoji: ClearAllEmoji? = null,
val deleteEveryone: DeleteForEveryoneDialogData? = null,
val deleteAllDevices: DeleteForEveryoneDialogData? = null,
val deleteEveryone: DeleteForEveryoneDialogData? = null
)

data class DeleteForEveryoneDialogData(
val messages: Set<MessageRecord>,
val messageType: MessageType,
val defaultToEveryone: Boolean,
val everyoneEnabled: Boolean,
val deleteForEveryoneLabel: String,
val warning: String? = null
)

Expand All @@ -841,7 +839,6 @@ class ConversationViewModel(
data class ClearEmoji(val emoji:String, val messageId: MessageId) : Commands()

data object HideDeleteEveryoneDialog : Commands()
data object HideDeleteAllDevicesDialog : Commands()
data object HideClearEmoji : Commands()

data class MarkAsDeletedLocally(val messages: Set<MessageRecord>): Commands()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,6 @@ import org.thoughtcrime.securesms.groups.OpenGroupManager

object ConversationMenuItemHelper {

@JvmStatic
fun userCanDeleteSelectedItems(context: Context, message: MessageRecord, openGroup: OpenGroup?, userPublicKey: String, blindedPublicKey: String?): Boolean {
if (openGroup == null) return message.isOutgoing || !message.isOutgoing
if (message.isOutgoing) return true
return OpenGroupManager.isUserModerator(context, openGroup.groupId, userPublicKey, blindedPublicKey)
}

@JvmStatic
fun userCanBanSelectedUsers(context: Context, message: MessageRecord, openGroup: OpenGroup?, userPublicKey: String, blindedPublicKey: String?): Boolean {
if (openGroup == null) return false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,11 @@ class ControlMessageView : LinearLayout {
&& message.expiryMode != (MessagingModuleConfiguration.shared.storage.getExpirationConfiguration(message.threadId)?.expiryMode ?: ExpiryMode.NONE)
&& threadRecipient?.isGroupRecipient != true

binding.controlContentView.setOnClickListener { disappearingMessages.showFollowSettingDialog(context, message) }
if (followSetting.isVisible) {
binding.controlContentView.setOnClickListener { disappearingMessages.showFollowSettingDialog(context, message) }
} else {
binding.controlContentView.setOnClickListener(null)
}
}
}
message.isMediaSavedNotification -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ class VisibleMessageView : FrameLayout {
showStatusMessage(message)

// Emoji Reactions
if (message.reactions.isNotEmpty()) {
if (!message.isDeleted && message.reactions.isNotEmpty()) {
val capabilities = lokiThreadDb.getOpenGroupChat(threadID)?.server?.let { lokiApiDb.getServerCapabilities(it) }
if (capabilities.isNullOrEmpty() || capabilities.contains(OpenGroupApi.Capability.REACTIONS.name.lowercase())) {
emojiReactionsBinding.value.root.let { root ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1686,12 +1686,21 @@ open class Storage(
val timestamp = reaction.timestamp
val localId = reaction.localId
val isMms = reaction.isMms

val messageId = if (localId != null && localId > 0 && isMms != null) {
// bail early is the message is marked as deleted
val messagingDatabase: MessagingDatabase = if (isMms == true) DatabaseComponent.get(context).mmsDatabase()
else DatabaseComponent.get(context).smsDatabase()
if(messagingDatabase.getMessageRecord(localId)?.isDeleted == true) return

MessageId(localId, isMms)
} else if (timestamp != null && timestamp > 0) {
val messageRecord = DatabaseComponent.get(context).mmsSmsDatabase().getMessageForTimestamp(timestamp) ?: return
if (messageRecord.isDeleted) return

MessageId(messageRecord.id, messageRecord.isMms)
} else return

DatabaseComponent.get(context).reactionDatabase().addReaction(
messageId,
ReactionRecord(
Expand Down
13 changes: 7 additions & 6 deletions app/src/main/res/layout/view_deleted_message.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@
android:layout_height="wrap_content"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="horizontal"
android:padding="@dimen/small_spacing">
android:gravity="center_vertical"
android:paddingVertical="@dimen/small_spacing">

<ImageView
android:id="@+id/deletedMessageViewIconImageView"
android:layout_width="16dp"
android:layout_height="16dp"
android:layout_marginStart="@dimen/small_spacing"
android:src="?menu_trash_icon"
android:layout_width="19dp"
android:layout_height="19dp"
android:layout_marginStart="18dp"
android:src="@drawable/ic_delete"
app:tint="?android:textColorPrimary" />

<TextView
Expand All @@ -22,7 +23,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:layout_marginEnd="@dimen/small_spacing"
android:layout_marginEnd="@dimen/large_spacing"
android:textSize="@dimen/very_small_font_size"
android:textColor="?android:textColorPrimary"
tools:text="This message has been deleted"
Expand Down
6 changes: 0 additions & 6 deletions app/src/main/res/xml/preferences_privacy.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,6 @@
android:title="@string/lockApp"
android:summary="@string/lockAppDescription" />

<org.thoughtcrime.securesms.components.SwitchPreferenceCompat
android:defaultValue="@bool/screen_security_default"
android:key="pref_screen_security"
android:title="@string/screenshotNotifications"
android:summary="@string/screenshotNotificationsDescription" />

</PreferenceCategory>

<PreferenceCategory
Expand Down
Loading