fix: downloads now don't automatically queue for untrusted contacts and UI to handle re-downloading failed attachments

This commit is contained in:
jubb 2021-07-08 17:14:53 +10:00
parent 176456c253
commit bc4f660fb0
8 changed files with 53 additions and 12 deletions

View File

@ -60,9 +60,9 @@ class DatabaseAttachmentProvider(context: Context, helper: SQLCipherOpenHelper)
return databaseAttachment.toSignalAttachmentPointer() return databaseAttachment.toSignalAttachmentPointer()
} }
override fun setAttachmentState(attachmentState: AttachmentState, attachmentId: Long, messageID: Long) { override fun setAttachmentState(attachmentState: AttachmentState, attachmentId: AttachmentId, messageID: Long) {
val attachmentDatabase = DatabaseFactory.getAttachmentDatabase(context) val attachmentDatabase = DatabaseFactory.getAttachmentDatabase(context)
attachmentDatabase.setTransferState(messageID, AttachmentId(attachmentId, 0), attachmentState.value) attachmentDatabase.setTransferState(messageID, attachmentId, attachmentState.value)
} }
override fun getMessageForQuote(timestamp: Long, author: Address): Pair<Long, Boolean>? { override fun getMessageForQuote(timestamp: Long, author: Address): Pair<Long, Boolean>? {

View File

@ -13,6 +13,9 @@ import androidx.core.view.children
import androidx.core.view.isVisible import androidx.core.view.isVisible
import kotlinx.android.synthetic.main.album_thumbnail_view.view.* import kotlinx.android.synthetic.main.album_thumbnail_view.view.*
import network.loki.messenger.R import network.loki.messenger.R
import org.session.libsession.messaging.jobs.AttachmentDownloadJob
import org.session.libsession.messaging.jobs.JobQueue
import org.session.libsession.messaging.sending_receiving.attachments.DatabaseAttachment
import org.session.libsession.utilities.ViewUtil import org.session.libsession.utilities.ViewUtil
import org.session.libsession.utilities.recipients.Recipient import org.session.libsession.utilities.recipients.Recipient
import org.thoughtcrime.securesms.MediaPreviewActivity import org.thoughtcrime.securesms.MediaPreviewActivity
@ -23,6 +26,7 @@ import org.thoughtcrime.securesms.loki.utilities.ActivityDispatcher
import org.thoughtcrime.securesms.longmessage.LongMessageActivity import org.thoughtcrime.securesms.longmessage.LongMessageActivity
import org.thoughtcrime.securesms.mms.GlideRequests import org.thoughtcrime.securesms.mms.GlideRequests
import org.thoughtcrime.securesms.mms.Slide import org.thoughtcrime.securesms.mms.Slide
import org.thoughtcrime.securesms.video.exo.AttachmentDataSource
import kotlin.math.roundToInt import kotlin.math.roundToInt
class AlbumThumbnailView : FrameLayout { class AlbumThumbnailView : FrameLayout {
@ -82,6 +86,13 @@ class AlbumThumbnailView : FrameLayout {
// hit intersects with this particular child // hit intersects with this particular child
val slide = slides.getOrNull(index) ?: return val slide = slides.getOrNull(index) ?: return
// only open to downloaded images // only open to downloaded images
if (slide.isPendingDownload) {
// restart download here
(slide.asAttachment() as? DatabaseAttachment)?.let { attachment ->
val attachmentId = attachment.attachmentId.rowId
JobQueue.shared.add(AttachmentDownloadJob(attachmentId, mms.getId()))
}
}
if (slide.isInProgress) return if (slide.isInProgress) return
ActivityDispatcher.get(context)?.dispatchIntent { context -> ActivityDispatcher.get(context)?.dispatchIntent { context ->

View File

@ -40,6 +40,7 @@ open class KThumbnailView: FrameLayout {
private val image by lazy { thumbnail_image } private val image by lazy { thumbnail_image }
private val playOverlay by lazy { play_overlay } private val playOverlay by lazy { play_overlay }
val loadIndicator: View by lazy { thumbnail_load_indicator } val loadIndicator: View by lazy { thumbnail_load_indicator }
val downloadIndicator: View by lazy { thumbnail_download_icon }
private val dimensDelegate = ThumbnailDimensDelegate() private val dimensDelegate = ThumbnailDimensDelegate()
@ -108,7 +109,8 @@ open class KThumbnailView: FrameLayout {
this.slide = slide this.slide = slide
loadIndicator.isVisible = slide.isInProgress && !mms.isFailed loadIndicator.isVisible = slide.isInProgress && !slide.isPendingDownload
downloadIndicator.isVisible = slide.isPendingDownload
dimensDelegate.setDimens(naturalWidth, naturalHeight) dimensDelegate.setDimens(naturalWidth, naturalHeight)
invalidate() invalidate()

View File

@ -47,6 +47,14 @@ class SessionContactDatabase(context: Context, helper: SQLCipherOpenHelper) : Da
}.toSet() }.toSet()
} }
fun setContactIsTrusted(contact: Contact, isTrusted: Boolean) {
val database = databaseHelper.writableDatabase
val contentValues = ContentValues(1)
contentValues.put(Companion.isTrusted, if (isTrusted) 1 else 0)
database.insertOrUpdate(sessionContactTable, contentValues, "$sessionID = ?", arrayOf( contact.sessionID ))
notifyConversationListListeners()
}
fun setContact(contact: Contact) { fun setContact(contact: Contact) {
val database = databaseHelper.writableDatabase val database = databaseHelper.writableDatabase
val contentValues = ContentValues(8) val contentValues = ContentValues(8)

View File

@ -22,6 +22,15 @@
android:visibility="gone" android:visibility="gone"
tools:visibility="visible" /> tools:visibility="visible" />
<ImageView
android:src="@drawable/ic_download_circle_filled_48"
android:id="@+id/thumbnail_download_icon"
android:layout_width="@dimen/medium_button_height"
android:layout_height="@dimen/medium_button_height"
android:layout_gravity="center"
android:visibility="gone"
/>
<FrameLayout <FrameLayout
android:id="@+id/play_overlay" android:id="@+id/play_overlay"
android:layout_width="48dp" android:layout_width="48dp"
@ -29,8 +38,7 @@
android:background="@drawable/circle_white" android:background="@drawable/circle_white"
android:layout_gravity="center" android:layout_gravity="center"
android:longClickable="false" android:longClickable="false"
android:visibility="gone" android:visibility="gone">
tools:visibility="visible">
<ImageView <ImageView
android:layout_width="19dp" android:layout_width="19dp"

View File

@ -18,7 +18,7 @@ interface MessageDataProvider {
fun getSignalAttachmentStream(attachmentId: Long): SignalServiceAttachmentStream? fun getSignalAttachmentStream(attachmentId: Long): SignalServiceAttachmentStream?
fun getScaledSignalAttachmentStream(attachmentId: Long): SignalServiceAttachmentStream? fun getScaledSignalAttachmentStream(attachmentId: Long): SignalServiceAttachmentStream?
fun getSignalAttachmentPointer(attachmentId: Long): SignalServiceAttachmentPointer? fun getSignalAttachmentPointer(attachmentId: Long): SignalServiceAttachmentPointer?
fun setAttachmentState(attachmentState: AttachmentState, attachmentId: Long, messageID: Long) fun setAttachmentState(attachmentState: AttachmentState, attachmentId: AttachmentId, messageID: Long)
fun insertAttachment(messageId: Long, attachmentId: AttachmentId, stream : InputStream) fun insertAttachment(messageId: Long, attachmentId: AttachmentId, stream : InputStream)
fun updateAudioAttachmentDuration(attachmentId: AttachmentId, durationMs: Long, threadId: Long) fun updateAudioAttachmentDuration(attachmentId: AttachmentId, durationMs: Long, threadId: Long)
fun isOutgoingMessage(timestamp: Long): Boolean fun isOutgoingMessage(timestamp: Long): Boolean

View File

@ -3,6 +3,7 @@ package org.session.libsession.messaging.jobs
import okhttp3.HttpUrl import okhttp3.HttpUrl
import org.session.libsession.messaging.MessagingModuleConfiguration import org.session.libsession.messaging.MessagingModuleConfiguration
import org.session.libsession.messaging.open_groups.OpenGroupAPIV2 import org.session.libsession.messaging.open_groups.OpenGroupAPIV2
import org.session.libsession.messaging.sending_receiving.attachments.AttachmentId
import org.session.libsession.messaging.sending_receiving.attachments.AttachmentState import org.session.libsession.messaging.sending_receiving.attachments.AttachmentState
import org.session.libsession.messaging.sending_receiving.attachments.DatabaseAttachment import org.session.libsession.messaging.sending_receiving.attachments.DatabaseAttachment
import org.session.libsession.messaging.utilities.Data import org.session.libsession.messaging.utilities.Data
@ -41,10 +42,14 @@ class AttachmentDownloadJob(val attachmentID: Long, val databaseMessageID: Long)
override fun execute() { override fun execute() {
val storage = MessagingModuleConfiguration.shared.storage val storage = MessagingModuleConfiguration.shared.storage
val messageDataProvider = MessagingModuleConfiguration.shared.messageDataProvider val messageDataProvider = MessagingModuleConfiguration.shared.messageDataProvider
val handleFailure: (java.lang.Exception) -> Unit = { exception -> val handleFailure: (java.lang.Exception, attachmentId: AttachmentId?) -> Unit = { exception, attachment ->
if (exception == Error.NoAttachment if (exception == Error.NoAttachment
|| (exception is OnionRequestAPI.HTTPRequestFailedAtDestinationException && exception.statusCode == 400)) { || (exception is OnionRequestAPI.HTTPRequestFailedAtDestinationException && exception.statusCode == 400)) {
messageDataProvider.setAttachmentState(AttachmentState.FAILED, attachmentID, databaseMessageID) attachment?.let { id ->
messageDataProvider.setAttachmentState(AttachmentState.FAILED, id, databaseMessageID)
} ?: run {
messageDataProvider.setAttachmentState(AttachmentState.FAILED, AttachmentId(attachmentID,0), databaseMessageID)
}
this.handlePermanentFailure(exception) this.handlePermanentFailure(exception)
} else { } else {
this.handleFailure(exception) this.handleFailure(exception)
@ -53,8 +58,8 @@ class AttachmentDownloadJob(val attachmentID: Long, val databaseMessageID: Long)
var tempFile: File? = null var tempFile: File? = null
try { try {
val attachment = messageDataProvider.getDatabaseAttachment(attachmentID) val attachment = messageDataProvider.getDatabaseAttachment(attachmentID)
?: return handleFailure(Error.NoAttachment) ?: return handleFailure(Error.NoAttachment, null)
messageDataProvider.setAttachmentState(AttachmentState.STARTED, attachmentID, this.databaseMessageID) messageDataProvider.setAttachmentState(AttachmentState.STARTED, attachment.attachmentId, this.databaseMessageID)
tempFile = createTempFile() tempFile = createTempFile()
val threadID = storage.getThreadIdForMms(databaseMessageID) val threadID = storage.getThreadIdForMms(databaseMessageID)
val openGroupV2 = storage.getV2OpenGroup(threadID) val openGroupV2 = storage.getV2OpenGroup(threadID)

View File

@ -221,10 +221,17 @@ fun MessageReceiver.handleVisibleMessage(message: VisibleMessage, proto: SignalS
val messageID = storage.persist(message, quoteModel, linkPreviews, message.groupPublicKey, openGroupID, attachments) ?: throw MessageReceiver.Error.DuplicateMessage val messageID = storage.persist(message, quoteModel, linkPreviews, message.groupPublicKey, openGroupID, attachments) ?: throw MessageReceiver.Error.DuplicateMessage
// Parse & persist attachments // Parse & persist attachments
// Start attachment downloads if needed // Start attachment downloads if needed
val contact = message.sender?.let { address -> storage.getContactWithSessionID(address) }
storage.getAttachmentsForMessage(messageID).forEach { attachment -> storage.getAttachmentsForMessage(messageID).forEach { attachment ->
attachment.attachmentId?.let { id -> attachment.attachmentId?.let { id ->
val downloadJob = AttachmentDownloadJob(id.rowId, messageID) // if open group or self-send, then always download attachment
JobQueue.shared.add(downloadJob) val immediatelyDownload = !openGroupID.isNullOrEmpty() // open group
|| userPublicKey == message.sender // self-send
|| contact?.isTrusted == true // trusted contact
if (immediatelyDownload) {
val downloadJob = AttachmentDownloadJob(id.rowId, messageID)
JobQueue.shared.add(downloadJob)
}
} }
} }
val openGroupServerID = message.openGroupServerMessageID val openGroupServerID = message.openGroupServerMessageID