mirror of
https://github.com/oxen-io/session-android.git
synced 2024-11-30 13:35:18 +00:00
Replace default action message request behavior (#927)
* refactor: add a block action and change default message request behavior to decline/delete * refactor: move log calls, add block & delete menu option * refactor: migrate some more actions into ConversationActivityV2.kt and only show message request incoming menu if it's an incoming message request * refactor: change block behaviour to be in the message request actions * refactor: use block user copy * refactor: parameters for ConversationMenuHelper interface cleaned up
This commit is contained in:
parent
aa43ab2a2e
commit
9f8ed4daf2
@ -1,8 +1,8 @@
|
|||||||
package org.thoughtcrime.securesms
|
package org.thoughtcrime.securesms
|
||||||
|
|
||||||
import android.util.Log
|
|
||||||
import nl.komponents.kovenant.Kovenant
|
import nl.komponents.kovenant.Kovenant
|
||||||
import nl.komponents.kovenant.jvm.asDispatcher
|
import nl.komponents.kovenant.jvm.asDispatcher
|
||||||
|
import org.session.libsignal.utilities.Log
|
||||||
import org.session.libsignal.utilities.ThreadUtils
|
import org.session.libsignal.utilities.ThreadUtils
|
||||||
import java.util.concurrent.Executors
|
import java.util.concurrent.Executors
|
||||||
|
|
||||||
|
@ -19,7 +19,6 @@ import android.os.Bundle
|
|||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
import android.text.TextUtils
|
import android.text.TextUtils
|
||||||
import android.util.Log
|
|
||||||
import android.util.Pair
|
import android.util.Pair
|
||||||
import android.util.TypedValue
|
import android.util.TypedValue
|
||||||
import android.view.ActionMode
|
import android.view.ActionMode
|
||||||
@ -56,6 +55,7 @@ import org.session.libsession.messaging.contacts.Contact
|
|||||||
import org.session.libsession.messaging.mentions.Mention
|
import org.session.libsession.messaging.mentions.Mention
|
||||||
import org.session.libsession.messaging.mentions.MentionsManager
|
import org.session.libsession.messaging.mentions.MentionsManager
|
||||||
import org.session.libsession.messaging.messages.control.DataExtractionNotification
|
import org.session.libsession.messaging.messages.control.DataExtractionNotification
|
||||||
|
import org.session.libsession.messaging.messages.control.ExpirationTimerUpdate
|
||||||
import org.session.libsession.messaging.messages.signal.OutgoingMediaMessage
|
import org.session.libsession.messaging.messages.signal.OutgoingMediaMessage
|
||||||
import org.session.libsession.messaging.messages.signal.OutgoingTextMessage
|
import org.session.libsession.messaging.messages.signal.OutgoingTextMessage
|
||||||
import org.session.libsession.messaging.messages.visible.Reaction
|
import org.session.libsession.messaging.messages.visible.Reaction
|
||||||
@ -79,9 +79,11 @@ import org.session.libsession.utilities.recipients.RecipientModifiedListener
|
|||||||
import org.session.libsignal.crypto.MnemonicCodec
|
import org.session.libsignal.crypto.MnemonicCodec
|
||||||
import org.session.libsignal.utilities.IdPrefix
|
import org.session.libsignal.utilities.IdPrefix
|
||||||
import org.session.libsignal.utilities.ListenableFuture
|
import org.session.libsignal.utilities.ListenableFuture
|
||||||
|
import org.session.libsignal.utilities.Log
|
||||||
import org.session.libsignal.utilities.guava.Optional
|
import org.session.libsignal.utilities.guava.Optional
|
||||||
import org.session.libsignal.utilities.hexEncodedPrivateKey
|
import org.session.libsignal.utilities.hexEncodedPrivateKey
|
||||||
import org.thoughtcrime.securesms.ApplicationContext
|
import org.thoughtcrime.securesms.ApplicationContext
|
||||||
|
import org.thoughtcrime.securesms.ExpirationDialog
|
||||||
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
|
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
|
||||||
import org.thoughtcrime.securesms.audio.AudioRecorder
|
import org.thoughtcrime.securesms.audio.AudioRecorder
|
||||||
import org.thoughtcrime.securesms.contacts.SelectContactsActivity.Companion.selectedContactsKey
|
import org.thoughtcrime.securesms.contacts.SelectContactsActivity.Companion.selectedContactsKey
|
||||||
@ -116,6 +118,7 @@ import org.thoughtcrime.securesms.database.LokiThreadDatabase
|
|||||||
import org.thoughtcrime.securesms.database.MmsDatabase
|
import org.thoughtcrime.securesms.database.MmsDatabase
|
||||||
import org.thoughtcrime.securesms.database.MmsSmsDatabase
|
import org.thoughtcrime.securesms.database.MmsSmsDatabase
|
||||||
import org.thoughtcrime.securesms.database.ReactionDatabase
|
import org.thoughtcrime.securesms.database.ReactionDatabase
|
||||||
|
import org.thoughtcrime.securesms.database.RecipientDatabase
|
||||||
import org.thoughtcrime.securesms.database.SessionContactDatabase
|
import org.thoughtcrime.securesms.database.SessionContactDatabase
|
||||||
import org.thoughtcrime.securesms.database.SmsDatabase
|
import org.thoughtcrime.securesms.database.SmsDatabase
|
||||||
import org.thoughtcrime.securesms.database.Storage
|
import org.thoughtcrime.securesms.database.Storage
|
||||||
@ -168,7 +171,8 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
|
|||||||
InputBarRecordingViewDelegate, AttachmentManager.AttachmentListener, ActivityDispatcher,
|
InputBarRecordingViewDelegate, AttachmentManager.AttachmentListener, ActivityDispatcher,
|
||||||
ConversationActionModeCallbackDelegate, VisibleMessageViewDelegate, RecipientModifiedListener,
|
ConversationActionModeCallbackDelegate, VisibleMessageViewDelegate, RecipientModifiedListener,
|
||||||
SearchBottomBar.EventListener, LoaderManager.LoaderCallbacks<Cursor>,
|
SearchBottomBar.EventListener, LoaderManager.LoaderCallbacks<Cursor>,
|
||||||
OnReactionSelectedListener, ReactWithAnyEmojiDialogFragment.Callback, ReactionsDialogFragment.Callback {
|
OnReactionSelectedListener, ReactWithAnyEmojiDialogFragment.Callback, ReactionsDialogFragment.Callback,
|
||||||
|
ConversationMenuHelper.ConversationMenuListener {
|
||||||
|
|
||||||
private var binding: ActivityConversationV2Binding? = null
|
private var binding: ActivityConversationV2Binding? = null
|
||||||
|
|
||||||
@ -178,6 +182,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
|
|||||||
@Inject lateinit var lokiThreadDb: LokiThreadDatabase
|
@Inject lateinit var lokiThreadDb: LokiThreadDatabase
|
||||||
@Inject lateinit var sessionContactDb: SessionContactDatabase
|
@Inject lateinit var sessionContactDb: SessionContactDatabase
|
||||||
@Inject lateinit var groupDb: GroupDatabase
|
@Inject lateinit var groupDb: GroupDatabase
|
||||||
|
@Inject lateinit var recipientDb: RecipientDatabase
|
||||||
@Inject lateinit var lokiApiDb: LokiAPIDatabase
|
@Inject lateinit var lokiApiDb: LokiAPIDatabase
|
||||||
@Inject lateinit var smsDb: SmsDatabase
|
@Inject lateinit var smsDb: SmsDatabase
|
||||||
@Inject lateinit var mmsDb: MmsDatabase
|
@Inject lateinit var mmsDb: MmsDatabase
|
||||||
@ -605,9 +610,8 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onPrepareOptionsMenu(menu: Menu): Boolean {
|
override fun onPrepareOptionsMenu(menu: Menu): Boolean {
|
||||||
|
val recipient = viewModel.recipient ?: return false
|
||||||
if (!isMessageRequestThread()) {
|
if (!isMessageRequestThread()) {
|
||||||
val recipient = viewModel.recipient
|
|
||||||
if (recipient != null) {
|
|
||||||
ConversationMenuHelper.onPrepareOptionsMenu(
|
ConversationMenuHelper.onPrepareOptionsMenu(
|
||||||
menu,
|
menu,
|
||||||
menuInflater,
|
menuInflater,
|
||||||
@ -616,7 +620,6 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
|
|||||||
this
|
this
|
||||||
) { onOptionsItemSelected(it) }
|
) { onOptionsItemSelected(it) }
|
||||||
}
|
}
|
||||||
}
|
|
||||||
super.onPrepareOptionsMenu(menu)
|
super.onPrepareOptionsMenu(menu)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -666,6 +669,9 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
|
|||||||
binding?.acceptMessageRequestButton?.setOnClickListener {
|
binding?.acceptMessageRequestButton?.setOnClickListener {
|
||||||
acceptMessageRequest()
|
acceptMessageRequest()
|
||||||
}
|
}
|
||||||
|
binding?.messageRequestBlock?.setOnClickListener {
|
||||||
|
block(deleteThread = true)
|
||||||
|
}
|
||||||
binding?.declineMessageRequestButton?.setOnClickListener {
|
binding?.declineMessageRequestButton?.setOnClickListener {
|
||||||
viewModel.declineMessageRequest()
|
viewModel.declineMessageRequest()
|
||||||
lifecycleScope.launch(Dispatchers.IO) {
|
lifecycleScope.launch(Dispatchers.IO) {
|
||||||
@ -937,6 +943,58 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
|
|||||||
} ?: false
|
} ?: false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun block(deleteThread: Boolean) {
|
||||||
|
val title = R.string.RecipientPreferenceActivity_block_this_contact_question
|
||||||
|
val message = R.string.RecipientPreferenceActivity_you_will_no_longer_receive_messages_and_calls_from_this_contact
|
||||||
|
AlertDialog.Builder(this)
|
||||||
|
.setTitle(title)
|
||||||
|
.setMessage(message)
|
||||||
|
.setNegativeButton(android.R.string.cancel, null)
|
||||||
|
.setPositiveButton(R.string.RecipientPreferenceActivity_block) { _, _ ->
|
||||||
|
viewModel.block()
|
||||||
|
if (deleteThread) {
|
||||||
|
viewModel.deleteThread()
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
}.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun copySessionID(sessionId: String) {
|
||||||
|
val clip = ClipData.newPlainText("Session ID", sessionId)
|
||||||
|
val manager = getSystemService(PassphraseRequiredActionBarActivity.CLIPBOARD_SERVICE) as ClipboardManager
|
||||||
|
manager.setPrimaryClip(clip)
|
||||||
|
Toast.makeText(this, R.string.copied_to_clipboard, Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showExpiringMessagesDialog(thread: Recipient) {
|
||||||
|
if (thread.isClosedGroupRecipient) {
|
||||||
|
val group = groupDb.getGroup(thread.address.toGroupString()).orNull()
|
||||||
|
if (group?.isActive == false) { return }
|
||||||
|
}
|
||||||
|
ExpirationDialog.show(this, thread.expireMessages) { expirationTime: Int ->
|
||||||
|
recipientDb.setExpireMessages(thread, expirationTime)
|
||||||
|
val message = ExpirationTimerUpdate(expirationTime)
|
||||||
|
message.recipient = thread.address.serialize()
|
||||||
|
message.sentTimestamp = System.currentTimeMillis()
|
||||||
|
val expiringMessageManager = ApplicationContext.getInstance(this).expiringMessageManager
|
||||||
|
expiringMessageManager.setExpirationTimer(message)
|
||||||
|
MessageSender.send(message, thread.address)
|
||||||
|
invalidateOptionsMenu()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun unblock() {
|
||||||
|
val title = R.string.ConversationActivity_unblock_this_contact_question
|
||||||
|
val message = R.string.ConversationActivity_you_will_once_again_be_able_to_receive_messages_and_calls_from_this_contact
|
||||||
|
AlertDialog.Builder(this)
|
||||||
|
.setTitle(title)
|
||||||
|
.setMessage(message)
|
||||||
|
.setNegativeButton(android.R.string.cancel, null)
|
||||||
|
.setPositiveButton(R.string.ConversationActivity_unblock) { _, _ ->
|
||||||
|
viewModel.unblock()
|
||||||
|
}.show()
|
||||||
|
}
|
||||||
|
|
||||||
// `position` is the adapter position; not the visual position
|
// `position` is the adapter position; not the visual position
|
||||||
private fun handlePress(message: MessageRecord, position: Int, view: VisibleMessageView, event: MotionEvent) {
|
private fun handlePress(message: MessageRecord, position: Int, view: VisibleMessageView, event: MotionEvent) {
|
||||||
val actionMode = this.actionMode
|
val actionMode = this.actionMode
|
||||||
|
@ -64,13 +64,24 @@ class ConversationViewModel(
|
|||||||
repository.inviteContacts(threadId, contacts)
|
repository.inviteContacts(threadId, contacts)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun block() {
|
||||||
|
val recipient = recipient ?: return Log.w("Loki", "Recipient was null for block action")
|
||||||
|
if (recipient.isContactRecipient) {
|
||||||
|
repository.setBlocked(recipient, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun unblock() {
|
fun unblock() {
|
||||||
val recipient = recipient ?: return Log.w("Loki", "Recipient was null for unblock action")
|
val recipient = recipient ?: return Log.w("Loki", "Recipient was null for unblock action")
|
||||||
if (recipient.isContactRecipient) {
|
if (recipient.isContactRecipient) {
|
||||||
repository.unblock(recipient)
|
repository.setBlocked(recipient, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun deleteThread() = viewModelScope.launch {
|
||||||
|
repository.deleteThread(threadId)
|
||||||
|
}
|
||||||
|
|
||||||
fun deleteLocally(message: MessageRecord) {
|
fun deleteLocally(message: MessageRecord) {
|
||||||
val recipient = recipient ?: return Log.w("Loki", "Recipient was null for delete locally action")
|
val recipient = recipient ?: return Log.w("Loki", "Recipient was null for delete locally action")
|
||||||
repository.deleteLocally(recipient, message)
|
repository.deleteLocally(recipient, message)
|
||||||
@ -130,8 +141,7 @@ class ConversationViewModel(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun declineMessageRequest() {
|
fun declineMessageRequest() {
|
||||||
val recipient = recipient ?: return Log.w("Loki", "Recipient was null for decline message request action")
|
repository.declineMessageRequest(threadId)
|
||||||
repository.declineMessageRequest(threadId, recipient)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showMessage(message: String) {
|
private fun showMessage(message: String) {
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
package org.thoughtcrime.securesms.conversation.v2.menus
|
package org.thoughtcrime.securesms.conversation.v2.menus
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.ClipData
|
|
||||||
import android.content.ClipboardManager
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.graphics.BitmapFactory
|
import android.graphics.BitmapFactory
|
||||||
@ -24,7 +22,6 @@ import androidx.core.content.pm.ShortcutInfoCompat
|
|||||||
import androidx.core.content.pm.ShortcutManagerCompat
|
import androidx.core.content.pm.ShortcutManagerCompat
|
||||||
import androidx.core.graphics.drawable.IconCompat
|
import androidx.core.graphics.drawable.IconCompat
|
||||||
import network.loki.messenger.R
|
import network.loki.messenger.R
|
||||||
import org.session.libsession.messaging.messages.control.ExpirationTimerUpdate
|
|
||||||
import org.session.libsession.messaging.sending_receiving.MessageSender
|
import org.session.libsession.messaging.sending_receiving.MessageSender
|
||||||
import org.session.libsession.messaging.sending_receiving.leave
|
import org.session.libsession.messaging.sending_receiving.leave
|
||||||
import org.session.libsession.utilities.ExpirationUtil
|
import org.session.libsession.utilities.ExpirationUtil
|
||||||
@ -33,11 +30,8 @@ import org.session.libsession.utilities.TextSecurePreferences
|
|||||||
import org.session.libsession.utilities.recipients.Recipient
|
import org.session.libsession.utilities.recipients.Recipient
|
||||||
import org.session.libsignal.utilities.guava.Optional
|
import org.session.libsignal.utilities.guava.Optional
|
||||||
import org.session.libsignal.utilities.toHexString
|
import org.session.libsignal.utilities.toHexString
|
||||||
import org.thoughtcrime.securesms.ApplicationContext
|
|
||||||
import org.thoughtcrime.securesms.ExpirationDialog
|
|
||||||
import org.thoughtcrime.securesms.MediaOverviewActivity
|
import org.thoughtcrime.securesms.MediaOverviewActivity
|
||||||
import org.thoughtcrime.securesms.MuteDialog
|
import org.thoughtcrime.securesms.MuteDialog
|
||||||
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
|
|
||||||
import org.thoughtcrime.securesms.ShortcutLauncherActivity
|
import org.thoughtcrime.securesms.ShortcutLauncherActivity
|
||||||
import org.thoughtcrime.securesms.calls.WebRtcCallActivity
|
import org.thoughtcrime.securesms.calls.WebRtcCallActivity
|
||||||
import org.thoughtcrime.securesms.contacts.SelectContactsActivity
|
import org.thoughtcrime.securesms.contacts.SelectContactsActivity
|
||||||
@ -156,7 +150,8 @@ object ConversationMenuHelper {
|
|||||||
R.id.menu_expiring_messages -> { showExpiringMessagesDialog(context, thread) }
|
R.id.menu_expiring_messages -> { showExpiringMessagesDialog(context, thread) }
|
||||||
R.id.menu_expiring_messages_off -> { showExpiringMessagesDialog(context, thread) }
|
R.id.menu_expiring_messages_off -> { showExpiringMessagesDialog(context, thread) }
|
||||||
R.id.menu_unblock -> { unblock(context, thread) }
|
R.id.menu_unblock -> { unblock(context, thread) }
|
||||||
R.id.menu_block -> { block(context, thread) }
|
R.id.menu_block -> { block(context, thread, deleteThread = false) }
|
||||||
|
R.id.menu_block_delete -> { blockAndDelete(context, thread) }
|
||||||
R.id.menu_copy_session_id -> { copySessionID(context, thread) }
|
R.id.menu_copy_session_id -> { copySessionID(context, thread) }
|
||||||
R.id.menu_edit_group -> { editClosedGroup(context, thread) }
|
R.id.menu_edit_group -> { editClosedGroup(context, thread) }
|
||||||
R.id.menu_leave_group -> { leaveClosedGroup(context, thread) }
|
R.id.menu_leave_group -> { leaveClosedGroup(context, thread) }
|
||||||
@ -246,59 +241,32 @@ object ConversationMenuHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun showExpiringMessagesDialog(context: Context, thread: Recipient) {
|
private fun showExpiringMessagesDialog(context: Context, thread: Recipient) {
|
||||||
if (thread.isClosedGroupRecipient) {
|
val listener = context as? ConversationMenuListener ?: return
|
||||||
val group = DatabaseComponent.get(context).groupDatabase().getGroup(thread.address.toGroupString()).orNull()
|
listener.showExpiringMessagesDialog(thread)
|
||||||
if (group?.isActive == false) { return }
|
|
||||||
}
|
|
||||||
ExpirationDialog.show(context, thread.expireMessages) { expirationTime: Int ->
|
|
||||||
DatabaseComponent.get(context).recipientDatabase().setExpireMessages(thread, expirationTime)
|
|
||||||
val message = ExpirationTimerUpdate(expirationTime)
|
|
||||||
message.recipient = thread.address.serialize()
|
|
||||||
message.sentTimestamp = System.currentTimeMillis()
|
|
||||||
val expiringMessageManager = ApplicationContext.getInstance(context).expiringMessageManager
|
|
||||||
expiringMessageManager.setExpirationTimer(message)
|
|
||||||
MessageSender.send(message, thread.address)
|
|
||||||
val activity = context as AppCompatActivity
|
|
||||||
activity.invalidateOptionsMenu()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun unblock(context: Context, thread: Recipient) {
|
private fun unblock(context: Context, thread: Recipient) {
|
||||||
if (!thread.isContactRecipient) { return }
|
if (!thread.isContactRecipient) { return }
|
||||||
val title = R.string.ConversationActivity_unblock_this_contact_question
|
val listener = context as? ConversationMenuListener ?: return
|
||||||
val message = R.string.ConversationActivity_you_will_once_again_be_able_to_receive_messages_and_calls_from_this_contact
|
listener.unblock()
|
||||||
AlertDialog.Builder(context)
|
|
||||||
.setTitle(title)
|
|
||||||
.setMessage(message)
|
|
||||||
.setNegativeButton(android.R.string.cancel, null)
|
|
||||||
.setPositiveButton(R.string.ConversationActivity_unblock) { _, _ ->
|
|
||||||
DatabaseComponent.get(context).recipientDatabase()
|
|
||||||
.setBlocked(thread, false)
|
|
||||||
}.show()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun block(context: Context, thread: Recipient) {
|
private fun block(context: Context, thread: Recipient, deleteThread: Boolean) {
|
||||||
if (!thread.isContactRecipient) { return }
|
if (!thread.isContactRecipient) { return }
|
||||||
val title = R.string.RecipientPreferenceActivity_block_this_contact_question
|
val listener = context as? ConversationMenuListener ?: return
|
||||||
val message = R.string.RecipientPreferenceActivity_you_will_no_longer_receive_messages_and_calls_from_this_contact
|
listener.block(deleteThread)
|
||||||
AlertDialog.Builder(context)
|
}
|
||||||
.setTitle(title)
|
|
||||||
.setMessage(message)
|
private fun blockAndDelete(context: Context, thread: Recipient) {
|
||||||
.setNegativeButton(android.R.string.cancel, null)
|
if (!thread.isContactRecipient) { return }
|
||||||
.setPositiveButton(R.string.RecipientPreferenceActivity_block) { _, _ ->
|
val listener = context as? ConversationMenuListener ?: return
|
||||||
DatabaseComponent.get(context).recipientDatabase()
|
listener.block(deleteThread = true)
|
||||||
.setBlocked(thread, true)
|
|
||||||
}.show()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun copySessionID(context: Context, thread: Recipient) {
|
private fun copySessionID(context: Context, thread: Recipient) {
|
||||||
if (!thread.isContactRecipient) { return }
|
if (!thread.isContactRecipient) { return }
|
||||||
val sessionID = thread.address.toString()
|
val listener = context as? ConversationMenuListener ?: return
|
||||||
val clip = ClipData.newPlainText("Session ID", sessionID)
|
listener.copySessionID(thread.address.toString())
|
||||||
val activity = context as AppCompatActivity
|
|
||||||
val manager = activity.getSystemService(PassphraseRequiredActionBarActivity.CLIPBOARD_SERVICE) as ClipboardManager
|
|
||||||
manager.setPrimaryClip(clip)
|
|
||||||
Toast.makeText(context, R.string.copied_to_clipboard, Toast.LENGTH_SHORT).show()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun editClosedGroup(context: Context, thread: Recipient) {
|
private fun editClosedGroup(context: Context, thread: Recipient) {
|
||||||
@ -371,4 +339,11 @@ object ConversationMenuHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface ConversationMenuListener {
|
||||||
|
fun block(deleteThread: Boolean = false)
|
||||||
|
fun unblock()
|
||||||
|
fun copySessionID(sessionId: String)
|
||||||
|
fun showExpiringMessagesDialog(thread: Recipient)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,21 +1,13 @@
|
|||||||
package org.thoughtcrime.securesms.conversation.v2.utilities
|
package org.thoughtcrime.securesms.conversation.v2.utilities
|
||||||
|
|
||||||
import android.animation.ValueAnimator
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.graphics.Canvas
|
import android.graphics.Canvas
|
||||||
import android.graphics.Interpolator
|
|
||||||
import android.graphics.Paint
|
import android.graphics.Paint
|
||||||
import android.graphics.Rect
|
import android.graphics.Rect
|
||||||
import android.os.SystemClock
|
import android.os.SystemClock
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
import android.util.Log
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.animation.AccelerateDecelerateInterpolator
|
|
||||||
import android.view.animation.Animation
|
|
||||||
import android.view.animation.AnimationSet
|
|
||||||
import android.view.animation.AnimationUtils
|
|
||||||
import androidx.core.content.res.ResourcesCompat
|
import androidx.core.content.res.ResourcesCompat
|
||||||
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
|
|
||||||
import network.loki.messenger.R
|
import network.loki.messenger.R
|
||||||
import kotlin.math.sin
|
import kotlin.math.sin
|
||||||
|
|
||||||
|
@ -76,17 +76,32 @@ class MessageRequestsActivity : PassphraseRequiredActionBarActivity(), Conversat
|
|||||||
push(intent)
|
push(intent)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onLongConversationClick(thread: ThreadRecord) {
|
override fun onBlockConversationClick(thread: ThreadRecord) {
|
||||||
val dialog = AlertDialog.Builder(this)
|
val dialog = AlertDialog.Builder(this)
|
||||||
dialog.setMessage(resources.getString(R.string.message_requests_delete_message))
|
dialog.setTitle(R.string.RecipientPreferenceActivity_block_this_contact_question)
|
||||||
dialog.setPositiveButton(R.string.yes) { _, _ ->
|
.setMessage(R.string.message_requests_block_message)
|
||||||
|
.setPositiveButton(R.string.recipient_preferences__block) { _, _ ->
|
||||||
|
viewModel.blockMessageRequest(thread)
|
||||||
|
LoaderManager.getInstance(this).restartLoader(0, null, this)
|
||||||
|
}
|
||||||
|
.setNegativeButton(R.string.no) { _, _ ->
|
||||||
|
// Do nothing
|
||||||
|
}
|
||||||
|
dialog.create().show()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDeleteConversationClick(thread: ThreadRecord) {
|
||||||
|
val dialog = AlertDialog.Builder(this)
|
||||||
|
dialog.setTitle(R.string.decline)
|
||||||
|
.setMessage(resources.getString(R.string.message_requests_decline_message))
|
||||||
|
.setPositiveButton(R.string.decline) { _,_ ->
|
||||||
viewModel.deleteMessageRequest(thread)
|
viewModel.deleteMessageRequest(thread)
|
||||||
LoaderManager.getInstance(this).restartLoader(0, null, this)
|
LoaderManager.getInstance(this).restartLoader(0, null, this)
|
||||||
lifecycleScope.launch(Dispatchers.IO) {
|
lifecycleScope.launch(Dispatchers.IO) {
|
||||||
ConfigurationMessageUtilities.forceSyncConfigurationNowIfNeeded(this@MessageRequestsActivity)
|
ConfigurationMessageUtilities.forceSyncConfigurationNowIfNeeded(this@MessageRequestsActivity)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dialog.setNegativeButton(R.string.no) { _, _ ->
|
.setNegativeButton(R.string.no) { _, _ ->
|
||||||
// Do nothing
|
// Do nothing
|
||||||
}
|
}
|
||||||
dialog.create().show()
|
dialog.create().show()
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package org.thoughtcrime.securesms.messagerequests
|
package org.thoughtcrime.securesms.messagerequests
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.content.res.ColorStateList
|
||||||
import android.database.Cursor
|
import android.database.Cursor
|
||||||
import android.text.SpannableString
|
import android.text.SpannableString
|
||||||
import android.text.style.ForegroundColorSpan
|
import android.text.style.ForegroundColorSpan
|
||||||
@ -8,6 +9,7 @@ import android.view.ViewGroup
|
|||||||
import android.widget.PopupMenu
|
import android.widget.PopupMenu
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import network.loki.messenger.R
|
import network.loki.messenger.R
|
||||||
|
import org.session.libsignal.utilities.Log
|
||||||
import org.thoughtcrime.securesms.database.CursorRecyclerViewAdapter
|
import org.thoughtcrime.securesms.database.CursorRecyclerViewAdapter
|
||||||
import org.thoughtcrime.securesms.database.model.ThreadRecord
|
import org.thoughtcrime.securesms.database.model.ThreadRecord
|
||||||
import org.thoughtcrime.securesms.dependencies.DatabaseComponent
|
import org.thoughtcrime.securesms.dependencies.DatabaseComponent
|
||||||
@ -49,7 +51,9 @@ class MessageRequestsAdapter(
|
|||||||
popupMenu.menuInflater.inflate(R.menu.menu_message_request, popupMenu.menu)
|
popupMenu.menuInflater.inflate(R.menu.menu_message_request, popupMenu.menu)
|
||||||
popupMenu.setOnMenuItemClickListener { menuItem ->
|
popupMenu.setOnMenuItemClickListener { menuItem ->
|
||||||
if (menuItem.itemId == R.id.menu_delete_message_request) {
|
if (menuItem.itemId == R.id.menu_delete_message_request) {
|
||||||
listener.onLongConversationClick(view.thread!!)
|
listener.onDeleteConversationClick(view.thread!!)
|
||||||
|
} else if (menuItem.itemId == R.id.menu_block_message_request) {
|
||||||
|
listener.onBlockConversationClick(view.thread!!)
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
@ -57,6 +61,7 @@ class MessageRequestsAdapter(
|
|||||||
val item = popupMenu.menu.getItem(i)
|
val item = popupMenu.menu.getItem(i)
|
||||||
val s = SpannableString(item.title)
|
val s = SpannableString(item.title)
|
||||||
s.setSpan(ForegroundColorSpan(context.getColor(R.color.destructive)), 0, s.length, 0)
|
s.setSpan(ForegroundColorSpan(context.getColor(R.color.destructive)), 0, s.length, 0)
|
||||||
|
item.iconTintList = ColorStateList.valueOf(context.getColor(R.color.destructive))
|
||||||
item.title = s
|
item.title = s
|
||||||
}
|
}
|
||||||
popupMenu.forceShowIcon()
|
popupMenu.forceShowIcon()
|
||||||
@ -70,5 +75,6 @@ class MessageRequestsAdapter(
|
|||||||
|
|
||||||
interface ConversationClickListener {
|
interface ConversationClickListener {
|
||||||
fun onConversationClick(thread: ThreadRecord)
|
fun onConversationClick(thread: ThreadRecord)
|
||||||
fun onLongConversationClick(thread: ThreadRecord)
|
fun onBlockConversationClick(thread: ThreadRecord)
|
||||||
|
fun onDeleteConversationClick(thread: ThreadRecord)
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,14 @@ class MessageRequestsViewModel @Inject constructor(
|
|||||||
private val repository: ConversationRepository
|
private val repository: ConversationRepository
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
|
|
||||||
|
fun blockMessageRequest(thread: ThreadRecord) = viewModelScope.launch {
|
||||||
|
val recipient = thread.recipient
|
||||||
|
if (recipient.isContactRecipient) {
|
||||||
|
repository.setBlocked(recipient, true)
|
||||||
|
deleteMessageRequest(thread)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun deleteMessageRequest(thread: ThreadRecord) = viewModelScope.launch {
|
fun deleteMessageRequest(thread: ThreadRecord) = viewModelScope.launch {
|
||||||
repository.deleteMessageRequest(thread)
|
repository.deleteMessageRequest(thread)
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,7 @@ interface ConversationRepository {
|
|||||||
fun saveDraft(threadId: Long, text: String)
|
fun saveDraft(threadId: Long, text: String)
|
||||||
fun getDraft(threadId: Long): String?
|
fun getDraft(threadId: Long): String?
|
||||||
fun inviteContacts(threadId: Long, contacts: List<Recipient>)
|
fun inviteContacts(threadId: Long, contacts: List<Recipient>)
|
||||||
fun unblock(recipient: Recipient)
|
fun setBlocked(recipient: Recipient, blocked: Boolean)
|
||||||
fun deleteLocally(recipient: Recipient, message: MessageRecord)
|
fun deleteLocally(recipient: Recipient, message: MessageRecord)
|
||||||
fun setApproved(recipient: Recipient, isApproved: Boolean)
|
fun setApproved(recipient: Recipient, isApproved: Boolean)
|
||||||
|
|
||||||
@ -58,13 +58,15 @@ interface ConversationRepository {
|
|||||||
|
|
||||||
suspend fun banAndDeleteAll(threadId: Long, recipient: Recipient): ResultOf<Unit>
|
suspend fun banAndDeleteAll(threadId: Long, recipient: Recipient): ResultOf<Unit>
|
||||||
|
|
||||||
|
suspend fun deleteThread(threadId: Long): ResultOf<Unit>
|
||||||
|
|
||||||
suspend fun deleteMessageRequest(thread: ThreadRecord): ResultOf<Unit>
|
suspend fun deleteMessageRequest(thread: ThreadRecord): ResultOf<Unit>
|
||||||
|
|
||||||
suspend fun clearAllMessageRequests(): ResultOf<Unit>
|
suspend fun clearAllMessageRequests(): ResultOf<Unit>
|
||||||
|
|
||||||
suspend fun acceptMessageRequest(threadId: Long, recipient: Recipient): ResultOf<Unit>
|
suspend fun acceptMessageRequest(threadId: Long, recipient: Recipient): ResultOf<Unit>
|
||||||
|
|
||||||
fun declineMessageRequest(threadId: Long, recipient: Recipient)
|
fun declineMessageRequest(threadId: Long)
|
||||||
|
|
||||||
fun hasReceived(threadId: Long): Boolean
|
fun hasReceived(threadId: Long): Boolean
|
||||||
|
|
||||||
@ -125,8 +127,8 @@ class DefaultConversationRepository @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun unblock(recipient: Recipient) {
|
override fun setBlocked(recipient: Recipient, blocked: Boolean) {
|
||||||
recipientDb.setBlocked(recipient, false)
|
recipientDb.setBlocked(recipient, blocked)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun deleteLocally(recipient: Recipient, message: MessageRecord) {
|
override fun deleteLocally(recipient: Recipient, message: MessageRecord) {
|
||||||
@ -248,9 +250,15 @@ class DefaultConversationRepository @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun deleteThread(threadId: Long): ResultOf<Unit> {
|
||||||
|
sessionJobDb.cancelPendingMessageSendJobs(threadId)
|
||||||
|
threadDb.deleteConversation(threadId)
|
||||||
|
return ResultOf.Success(Unit)
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun deleteMessageRequest(thread: ThreadRecord): ResultOf<Unit> {
|
override suspend fun deleteMessageRequest(thread: ThreadRecord): ResultOf<Unit> {
|
||||||
sessionJobDb.cancelPendingMessageSendJobs(thread.threadId)
|
sessionJobDb.cancelPendingMessageSendJobs(thread.threadId)
|
||||||
recipientDb.setBlocked(thread.recipient, true)
|
threadDb.deleteConversation(thread.threadId)
|
||||||
return ResultOf.Success(Unit)
|
return ResultOf.Success(Unit)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -275,8 +283,9 @@ class DefaultConversationRepository @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun declineMessageRequest(threadId: Long, recipient: Recipient) {
|
override fun declineMessageRequest(threadId: Long) {
|
||||||
recipientDb.setBlocked(recipient, true)
|
sessionJobDb.cancelPendingMessageSendJobs(threadId)
|
||||||
|
threadDb.deleteConversation(threadId)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun hasReceived(threadId: Long): Boolean {
|
override fun hasReceived(threadId: Long): Boolean {
|
||||||
|
@ -201,6 +201,17 @@
|
|||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
tools:visibility="visible">
|
tools:visibility="visible">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/messageRequestBlock"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:textColor="@color/destructive"
|
||||||
|
android:paddingHorizontal="@dimen/massive_spacing"
|
||||||
|
android:paddingVertical="@dimen/small_spacing"
|
||||||
|
android:textSize="@dimen/text_size"
|
||||||
|
android:text="@string/activity_conversation_block_user"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/sendAcceptsTextView"
|
android:id="@+id/sendAcceptsTextView"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
27
app/src/main/res/layout/layout_conversation_block_icon.xml
Normal file
27
app/src/main/res/layout/layout_conversation_block_icon.xml
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
style="@android:style/Widget.ActionButton"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="center"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_margin="@dimen/very_small_spacing"
|
||||||
|
android:layout_width="13dp"
|
||||||
|
android:layout_height="13dp"
|
||||||
|
android:src="@drawable/ic_baseline_block_24"
|
||||||
|
app:tint="@color/destructive" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:textColor="@color/destructive"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:text="@string/recipient_preferences__block"
|
||||||
|
/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
11
app/src/main/res/menu/menu_conversation_block_icon.xml
Normal file
11
app/src/main/res/menu/menu_conversation_block_icon.xml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
|
||||||
|
<item
|
||||||
|
app:actionLayout="@layout/layout_conversation_block_icon"
|
||||||
|
app:showAsAction="always"
|
||||||
|
android:title="@string/recipient_preferences__block"
|
||||||
|
android:id="@+id/menu_block_delete" />
|
||||||
|
|
||||||
|
</menu>
|
@ -4,6 +4,11 @@
|
|||||||
<item
|
<item
|
||||||
android:id="@+id/menu_delete_message_request"
|
android:id="@+id/menu_delete_message_request"
|
||||||
android:icon="@drawable/ic_delete_24"
|
android:icon="@drawable/ic_delete_24"
|
||||||
android:title="@string/delete"/>
|
android:title="@string/decline"/>
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/menu_block_message_request"
|
||||||
|
android:icon="@drawable/ic_baseline_block_24"
|
||||||
|
android:title="@string/RecipientPreferenceActivity_block"/>
|
||||||
|
|
||||||
</menu>
|
</menu>
|
||||||
|
@ -41,6 +41,7 @@
|
|||||||
<dimen name="input_bar_button_expanded_size">48dp</dimen>
|
<dimen name="input_bar_button_expanded_size">48dp</dimen>
|
||||||
|
|
||||||
<!-- Distances -->
|
<!-- Distances -->
|
||||||
|
<dimen name="very_small_spacing">4dp</dimen>
|
||||||
<dimen name="small_spacing">8dp</dimen>
|
<dimen name="small_spacing">8dp</dimen>
|
||||||
<dimen name="medium_spacing">16dp</dimen>
|
<dimen name="medium_spacing">16dp</dimen>
|
||||||
<dimen name="large_spacing">24dp</dimen>
|
<dimen name="large_spacing">24dp</dimen>
|
||||||
|
@ -865,6 +865,7 @@
|
|||||||
<string name="dialog_download_button_title">Download</string>
|
<string name="dialog_download_button_title">Download</string>
|
||||||
|
|
||||||
<string name="activity_conversation_blocked_banner_text">%s is blocked. Unblock them?</string>
|
<string name="activity_conversation_blocked_banner_text">%s is blocked. Unblock them?</string>
|
||||||
|
<string name="activity_conversation_block_user">Block User</string>
|
||||||
|
|
||||||
<string name="activity_conversation_attachment_prep_failed">Failed to prepare attachment for sending.</string>
|
<string name="activity_conversation_attachment_prep_failed">Failed to prepare attachment for sending.</string>
|
||||||
<string name="media">Media</string>
|
<string name="media">Media</string>
|
||||||
@ -894,7 +895,8 @@
|
|||||||
<string name="accept">Accept</string>
|
<string name="accept">Accept</string>
|
||||||
<string name="decline">Decline</string>
|
<string name="decline">Decline</string>
|
||||||
<string name="message_requests_clear_all">Clear All</string>
|
<string name="message_requests_clear_all">Clear All</string>
|
||||||
<string name="message_requests_delete_message">Are you sure you want to delete this message request?</string>
|
<string name="message_requests_decline_message">Are you sure you want to decline this message request?</string>
|
||||||
|
<string name="message_requests_block_message">Are you sure you want to block this message request?</string>
|
||||||
<string name="message_requests_deleted">Message request deleted</string>
|
<string name="message_requests_deleted">Message request deleted</string>
|
||||||
<string name="message_requests_clear_all_message">Are you sure you want to clear all message requests?</string>
|
<string name="message_requests_clear_all_message">Are you sure you want to clear all message requests?</string>
|
||||||
<string name="message_requests_cleared">Message requests deleted</string>
|
<string name="message_requests_cleared">Message requests deleted</string>
|
||||||
|
@ -81,7 +81,7 @@ class ConversationViewModelTest: BaseViewModelTest() {
|
|||||||
|
|
||||||
viewModel.unblock()
|
viewModel.unblock()
|
||||||
|
|
||||||
verify(repository).unblock(recipient)
|
verify(repository).setBlocked(recipient, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -173,7 +173,7 @@ class ConversationViewModelTest: BaseViewModelTest() {
|
|||||||
fun `should decline message request`() {
|
fun `should decline message request`() {
|
||||||
viewModel.declineMessageRequest()
|
viewModel.declineMessageRequest()
|
||||||
|
|
||||||
verify(repository).declineMessageRequest(threadId, recipient)
|
verify(repository).declineMessageRequest(threadId)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package org.session.libsession.messaging.sending_receiving
|
package org.session.libsession.messaging.sending_receiving
|
||||||
|
|
||||||
import android.util.Log
|
|
||||||
import com.goterl.lazysodium.LazySodiumAndroid
|
import com.goterl.lazysodium.LazySodiumAndroid
|
||||||
import com.goterl.lazysodium.SodiumAndroid
|
import com.goterl.lazysodium.SodiumAndroid
|
||||||
import com.goterl.lazysodium.interfaces.Box
|
import com.goterl.lazysodium.interfaces.Box
|
||||||
@ -12,6 +11,7 @@ import org.session.libsession.messaging.utilities.SodiumUtilities
|
|||||||
import org.session.libsignal.crypto.ecc.ECKeyPair
|
import org.session.libsignal.crypto.ecc.ECKeyPair
|
||||||
import org.session.libsignal.utilities.Hex
|
import org.session.libsignal.utilities.Hex
|
||||||
import org.session.libsignal.utilities.IdPrefix
|
import org.session.libsignal.utilities.IdPrefix
|
||||||
|
import org.session.libsignal.utilities.Log
|
||||||
import org.session.libsignal.utilities.hexEncodedPublicKey
|
import org.session.libsignal.utilities.hexEncodedPublicKey
|
||||||
import org.session.libsignal.utilities.removingIdPrefixIfNeeded
|
import org.session.libsignal.utilities.removingIdPrefixIfNeeded
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user