refactor: moving the trusted download dialogs and logic to be auto-download and show visibilities based on download status not trusted status

This commit is contained in:
0x330a
2022-11-10 17:43:40 +11:00
parent 516344280a
commit dc22ba1051
9 changed files with 3778 additions and 120 deletions

View File

@@ -15,13 +15,14 @@ import org.session.libsession.messaging.jobs.JobQueue
import org.session.libsession.utilities.recipients.Recipient
import org.thoughtcrime.securesms.conversation.v2.utilities.BaseDialog
import org.thoughtcrime.securesms.database.SessionContactDatabase
import org.thoughtcrime.securesms.dependencies.DatabaseComponent
import javax.inject.Inject
/** Shown when receiving media from a contact for the first time, to confirm that
* they are to be trusted and files sent by them are to be downloaded. */
@AndroidEntryPoint
class DownloadDialog(private val recipient: Recipient) : BaseDialog() {
class DownloadDialog(private val recipient: Recipient,
private val
) : BaseDialog() {
@Inject lateinit var contactDB: SessionContactDatabase
@@ -43,10 +44,6 @@ class DownloadDialog(private val recipient: Recipient) : BaseDialog() {
}
private fun trust() {
val sessionID = recipient.address.toString()
val contact = contactDB.getContactWithSessionID(sessionID) ?: return
val threadID = DatabaseComponent.get(requireContext()).threadDatabase().getThreadIdIfExistsFor(recipient)
contactDB.setContactIsTrusted(contact, true, threadID)
JobQueue.shared.resumePendingJobs(AttachmentDownloadJob.KEY)
dismiss()
}

View File

@@ -6,20 +6,23 @@ import android.widget.LinearLayout
import androidx.annotation.ColorInt
import androidx.core.content.ContextCompat
import network.loki.messenger.R
import network.loki.messenger.databinding.ViewUntrustedAttachmentBinding
import network.loki.messenger.databinding.ViewPendingAttachmentBinding
import org.session.libsession.messaging.sending_receiving.attachments.AttachmentId
import org.session.libsession.utilities.recipients.Recipient
import org.thoughtcrime.securesms.conversation.v2.dialogs.DownloadDialog
import org.thoughtcrime.securesms.util.ActivityDispatcher
import java.util.Locale
class UntrustedAttachmentView: LinearLayout {
private val binding: ViewUntrustedAttachmentBinding by lazy { ViewUntrustedAttachmentBinding.bind(this) }
class PendingAttachmentView: LinearLayout {
private val binding by lazy { ViewPendingAttachmentBinding.bind(this) }
enum class AttachmentType {
AUDIO,
DOCUMENT,
MEDIA
}
private var attachmentId: AttachmentId? = null
// region Lifecycle
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
@@ -28,7 +31,7 @@ class UntrustedAttachmentView: LinearLayout {
// endregion
// region Updating
fun bind(attachmentType: AttachmentType, @ColorInt textColor: Int) {
fun bind(attachmentType: AttachmentType, @ColorInt textColor: Int, attachmentId: AttachmentId) {
val (iconRes, stringRes) = when (attachmentType) {
AttachmentType.AUDIO -> R.drawable.ic_microphone to R.string.Slide_audio
AttachmentType.DOCUMENT -> R.drawable.ic_document_large_light to R.string.document
@@ -40,12 +43,15 @@ class UntrustedAttachmentView: LinearLayout {
binding.untrustedAttachmentIcon.setImageDrawable(iconDrawable)
binding.untrustedAttachmentTitle.text = text
this.attachmentId = attachmentId
}
// endregion
// region Interaction
fun showTrustDialog(recipient: Recipient) {
ActivityDispatcher.get(context)?.showDialog(DownloadDialog(recipient))
fun showDownloadDialog(threadRecipient: Recipient) {
attachmentId?.let { attachmentId ->
ActivityDispatcher.get(context)?.showDialog(DownloadDialog(threadRecipient, attachmentId))
}
}
}

View File

@@ -40,7 +40,6 @@ import org.thoughtcrime.securesms.conversation.v2.utilities.ModalURLSpan
import org.thoughtcrime.securesms.conversation.v2.utilities.TextUtilities.getIntersectedModalSpans
import org.thoughtcrime.securesms.database.model.MessageRecord
import org.thoughtcrime.securesms.database.model.MmsMessageRecord
import org.thoughtcrime.securesms.database.model.SmsMessageRecord
import org.thoughtcrime.securesms.mms.GlideRequests
import org.thoughtcrime.securesms.util.SearchUtil
import org.thoughtcrime.securesms.util.getAccentColor
@@ -66,7 +65,7 @@ class VisibleMessageContentView : LinearLayout {
// region Updating
fun bind(message: MessageRecord, isStartOfMessageCluster: Boolean, isEndOfMessageCluster: Boolean,
glide: GlideRequests, thread: Recipient, searchQuery: String?, contactIsTrusted: Boolean) {
glide: GlideRequests, thread: Recipient, searchQuery: String?, autoDownloadAttachments: Boolean) {
// Background
val background = getBackground(message.isOutgoing)
val color = if (message.isOutgoing) context.getAccentColor()
@@ -75,8 +74,8 @@ class VisibleMessageContentView : LinearLayout {
background.colorFilter = filter
binding.contentParent.background = background
val onlyBodyMessage = message is SmsMessageRecord
val mediaThumbnailMessage = contactIsTrusted && message is MmsMessageRecord && message.slideDeck.thumbnailSlide != null
val mediaDownloaded = message is MmsMessageRecord && message.slideDeck.asAttachments().all { it.transferState == AttachmentTransferProgress.TRANSFER_PROGRESS_DONE }
val mediaThumbnailMessage = message is MmsMessageRecord && message.slideDeck.thumbnailSlide != null
// reset visibilities / containers
onContentClick.clear()
@@ -98,9 +97,9 @@ class VisibleMessageContentView : LinearLayout {
binding.linkPreviewView.isVisible = message is MmsMessageRecord && message.linkPreviews.isNotEmpty()
binding.untrustedView.root.isVisible = !contactIsTrusted && message is MmsMessageRecord && message.quote == null && message.linkPreviews.isEmpty()
binding.voiceMessageView.root.isVisible = contactIsTrusted && message is MmsMessageRecord && message.slideDeck.audioSlide != null
binding.documentView.root.isVisible = contactIsTrusted && message is MmsMessageRecord && message.slideDeck.documentSlide != null
binding.pendingAttachmentView.root.isVisible = !mediaDownloaded && message is MmsMessageRecord && message.quote == null && message.linkPreviews.isEmpty()
binding.voiceMessageView.root.isVisible = mediaDownloaded && message is MmsMessageRecord && message.slideDeck.audioSlide != null
binding.documentView.root.isVisible = mediaDownloaded && message is MmsMessageRecord && message.slideDeck.documentSlide != null
binding.albumThumbnailView.isVisible = mediaThumbnailMessage
binding.openGroupInvitationView.root.isVisible = message.isOpenGroupInvitation
@@ -124,7 +123,6 @@ class VisibleMessageContentView : LinearLayout {
delegate?.scrollToMessageIfPossible(quote.id)
}
}
val hasMedia = message.slideDeck.asAttachments().isNotEmpty()
}
if (message is MmsMessageRecord) {
@@ -156,7 +154,7 @@ class VisibleMessageContentView : LinearLayout {
message is MmsMessageRecord && message.slideDeck.audioSlide != null -> {
hideBody = true
// Audio attachment
if (contactIsTrusted || message.isOutgoing) {
if (mediaDownloaded || message.isOutgoing) {
binding.voiceMessageView.root.indexInAdapter = indexInAdapter
binding.voiceMessageView.root.delegate = context as? ConversationActivityV2
binding.voiceMessageView.root.bind(message, isStartOfMessageCluster, isEndOfMessageCluster)
@@ -165,26 +163,33 @@ class VisibleMessageContentView : LinearLayout {
onContentClick.add { binding.voiceMessageView.root.togglePlayback() }
onContentDoubleTap = { binding.voiceMessageView.root.handleDoubleTap() }
} else {
// TODO: move this out to its own area
binding.untrustedView.root.bind(UntrustedAttachmentView.AttachmentType.AUDIO, VisibleMessageContentView.getTextColor(context,message))
onContentClick.add { binding.untrustedView.root.showTrustDialog(message.individualRecipient) }
binding.pendingAttachmentView.root.bind(
PendingAttachmentView.AttachmentType.AUDIO,
getTextColor(context,message),
)
onContentClick.add { binding.pendingAttachmentView.root.showDownloadDialog(message.recipient) }
}
}
message is MmsMessageRecord && message.slideDeck.documentSlide != null -> {
hideBody = true
// Document attachment
if (contactIsTrusted || message.isOutgoing) {
binding.documentView.root.bind(message, VisibleMessageContentView.getTextColor(context, message))
if (mediaDownloaded || message.isOutgoing) {
binding.documentView.root.bind(message, getTextColor(context, message))
} else {
binding.untrustedView.root.bind(UntrustedAttachmentView.AttachmentType.DOCUMENT, VisibleMessageContentView.getTextColor(context,message))
onContentClick.add { binding.untrustedView.root.showTrustDialog(message.individualRecipient) }
binding.pendingAttachmentView.root.bind(
PendingAttachmentView.AttachmentType.DOCUMENT,
getTextColor(context,message),
)
onContentClick.add { binding.pendingAttachmentView.root.showDownloadDialog(message.recipient) }
}
}
message is MmsMessageRecord && message.slideDeck.asAttachments().isNotEmpty() -> {
/*
* Images / Video attachment
*/
if (contactIsTrusted || message.isOutgoing) {
if (mediaDownloaded || message.isOutgoing) {
// isStart and isEnd of cluster needed for calculating the mask for full bubble image groups
// bind after add view because views are inflated and calculated during bind
binding.albumThumbnailView.bind(
@@ -202,13 +207,17 @@ class VisibleMessageContentView : LinearLayout {
} else {
hideBody = true
binding.albumThumbnailView.clearViews()
binding.untrustedView.root.bind(UntrustedAttachmentView.AttachmentType.MEDIA, VisibleMessageContentView.getTextColor(context,message))
onContentClick.add { binding.untrustedView.root.showTrustDialog(message.individualRecipient) }
binding.pendingAttachmentView.root.bind(
PendingAttachmentView.AttachmentType.MEDIA,
getTextColor(context,message),
)
onContentClick.add { binding.pendingAttachmentView.root.showDownloadDialog(message.recipient) }
}
}
message.isOpenGroupInvitation -> {
hideBody = true
binding.openGroupInvitationView.root.bind(message, VisibleMessageContentView.getTextColor(context, message))
binding.openGroupInvitationView.root.bind(message, getTextColor(context, message))
onContentClick.add { binding.openGroupInvitationView.root.joinOpenGroup() }
}
}
@@ -243,7 +252,7 @@ class VisibleMessageContentView : LinearLayout {
fun recycle() {
arrayOf(
binding.deletedMessageView.root,
binding.untrustedView.root,
binding.pendingAttachmentView.root,
binding.voiceMessageView.root,
binding.openGroupInvitationView.root,
binding.documentView.root,

View File

@@ -685,9 +685,7 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
}
}
override fun shouldAutoDownloadAttachments(recipient: Recipient): Boolean {
TODO("Not yet implemented")
}
override fun shouldAutoDownloadAttachments(recipient: Recipient): Boolean = true
override fun setAutoDownloadAttachments(
recipient: Recipient,

View File

@@ -191,6 +191,9 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
executeStatements(db, GroupReceiptDatabase.CREATE_INDEXES);
executeStatements(db, ReactionDatabase.CREATE_REACTION_TRIGGERS);
db.execSQL(RecipientDatabase.getCreateAutoDownloadCommand());
db.execSQL(RecipientDatabase.getUpdateAutoDownloadValuesCommand());
}
@Override

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<org.thoughtcrime.securesms.conversation.v2.messages.UntrustedAttachmentView
<org.thoughtcrime.securesms.conversation.v2.messages.PendingAttachmentView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
@@ -27,4 +27,4 @@
android:maxLines="2"
android:ellipsize="end" />
</org.thoughtcrime.securesms.conversation.v2.messages.UntrustedAttachmentView>
</org.thoughtcrime.securesms.conversation.v2.messages.PendingAttachmentView>

View File

@@ -26,13 +26,13 @@
android:layout_height="wrap_content"
/>
<include layout="@layout/view_untrusted_attachment"
<include layout="@layout/view_pending_attachment"
tools:visibility="gone"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:visibility="gone"
android:id="@+id/untrustedView"
android:id="@+id/pending_attachment_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>

View File

@@ -119,6 +119,13 @@ message DataMessage {
required string name = 3;
}
message GroupMessage {
optional GroupDeleteMessage deleteMessage = 31;
optional GroupMemberLeftMessage memberLeftMessage = 32;
optional GroupInviteMessage inviteMessage = 33;
optional GroupPromoteMessage promoteMessage = 34;
}
message ClosedGroupControlMessage {
enum Type {
@@ -182,6 +189,34 @@ message DataMessage {
optional OpenGroupInvitation openGroupInvitation = 102;
optional ClosedGroupControlMessage closedGroupControlMessage = 104;
optional string syncTarget = 105;
optional GroupMessage groupMessage = 120;
}
message GroupDeleteMessage {
// @required
required bytes publicKey = 1; // the identity public key of the group to be deleted
// @required
required bytes lastEncryptionKey = 2; // used by members to make sure incoming admin action can be trusted
}
message GroupMemberLeftMessage {
// the pubkey of the member left is included as part of the closed group encryption logic (senderIdentity on desktop)
}
message GroupInviteMessage {
// @required
required bytes publicKey = 1; // this is the group public key
// @required
required string name = 2;
// @required
required bytes memberPrivateKey = 3;
}
message GroupPromoteMessage {
// @required
required bytes publicKey = 1; // this is the session id for the user that should be promoted
// @required
required bytes encryptedPrivateKey = 2; // this is the group admins key
}
message CallMessage {