Extracted EmbedeedImage mapper to AttachmentsHelper.
MAILAND-1337
This commit is contained in:
parent
ab4f5a5de4
commit
6df695a9a9
|
@ -37,6 +37,7 @@ import me.proton.core.util.kotlin.DispatcherProvider
|
|||
import org.jsoup.Jsoup
|
||||
import org.jsoup.nodes.Document
|
||||
import org.jsoup.select.Elements
|
||||
import timber.log.Timber
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.File
|
||||
import javax.inject.Inject
|
||||
|
@ -128,7 +129,7 @@ internal class MessageRenderer(
|
|||
if (!file.exists() || file.length() == 0L) continue
|
||||
|
||||
val size = (MAX_IMAGES_TOTAL_SIZE / embeddedImages.size)
|
||||
.coerceAtMost(MAX_IMAGE_SINGLE_SIZE)
|
||||
.coerceAtMost(MAX_IMAGE_SINGLE_SIZE)
|
||||
|
||||
val compressed = try {
|
||||
ByteArrayOutputStream().also {
|
||||
|
@ -139,6 +140,7 @@ internal class MessageRenderer(
|
|||
bitmap.compress(Bitmap.CompressFormat.WEBP, 80, it)
|
||||
}
|
||||
} catch (t: Throwable) {
|
||||
Timber.i(t, "Skip the image")
|
||||
// Skip the image
|
||||
continue
|
||||
}
|
||||
|
@ -183,7 +185,7 @@ internal class MessageRenderer(
|
|||
val contentType = embeddedImage.contentType.formatContentType()
|
||||
|
||||
document.findImageElements(contentId)
|
||||
?.attr("src", "data:$contentType;$encoding,$image64")
|
||||
?.attr("src", "data:$contentType;$encoding,$image64")
|
||||
}
|
||||
documentStringifier.send(Unit) // Deliver after all the elements for now
|
||||
}
|
||||
|
@ -244,7 +246,7 @@ private const val ID_PLACEHOLDER = "%id"
|
|||
|
||||
/** [Array] of html attributes that could contain an image */
|
||||
private val IMAGE_ATTRIBUTES =
|
||||
arrayOf("img[src=$ID_PLACEHOLDER]", "img[src=cid:$ID_PLACEHOLDER]", "img[rel=$ID_PLACEHOLDER]")
|
||||
arrayOf("img[src=$ID_PLACEHOLDER]", "img[src=cid:$ID_PLACEHOLDER]", "img[rel=$ID_PLACEHOLDER]")
|
||||
// endregion
|
||||
|
||||
// region typealiases
|
||||
|
@ -256,8 +258,8 @@ private typealias ImageString = Pair<EmbeddedImage, String>
|
|||
private fun String.formatEncoding() = toLowerCase()
|
||||
private fun String.formatContentId() = trimStart('<').trimEnd('>')
|
||||
private fun String.formatContentType() = toLowerCase()
|
||||
.replace("\r", "").replace("\n", "")
|
||||
.replaceFirst(";.*$".toRegex(), "")
|
||||
.replace("\r", "").replace("\n", "")
|
||||
.replaceFirst(";.*$".toRegex(), "")
|
||||
|
||||
/**
|
||||
* Flatten the receiver [Document] by removing the indentation and disabling prettyPrint.
|
||||
|
@ -268,12 +270,12 @@ private fun Document.flatten() = apply { outputSettings().indentAmount(0).pretty
|
|||
/** @return [Elements] matching the image attribute for the given [id] */
|
||||
private fun Document.findImageElements(id: String): Elements? {
|
||||
return IMAGE_ATTRIBUTES
|
||||
.map { attr -> attr.replace(ID_PLACEHOLDER, id) }
|
||||
// with `asSequence` iteration will stop when the first usable element
|
||||
// is found and so avoid to make too many calls to document.select
|
||||
.asSequence()
|
||||
.map { select(it) }
|
||||
.find { it.isNotEmpty() }
|
||||
.map { attr -> attr.replace(ID_PLACEHOLDER, id) }
|
||||
// with `asSequence` iteration will stop when the first usable element
|
||||
// is found and so avoid to make too many calls to document.select
|
||||
.asSequence()
|
||||
.map { select(it) }
|
||||
.find { it.isNotEmpty() }
|
||||
}
|
||||
// endregion
|
||||
|
||||
|
|
|
@ -43,6 +43,7 @@ import ch.protonmail.android.api.models.room.messages.Attachment
|
|||
import ch.protonmail.android.api.models.room.messages.Label
|
||||
import ch.protonmail.android.api.models.room.messages.Message
|
||||
import ch.protonmail.android.api.models.room.pendingActions.PendingSend
|
||||
import ch.protonmail.android.attachments.AttachmentsHelper
|
||||
import ch.protonmail.android.attachments.DownloadEmbeddedAttachmentsWorker
|
||||
import ch.protonmail.android.core.BigContentHolder
|
||||
import ch.protonmail.android.core.Constants
|
||||
|
@ -87,6 +88,7 @@ internal class MessageDetailsViewModel @ViewModelInject constructor(
|
|||
private val fetchVerificationKeys: FetchVerificationKeys,
|
||||
private val attachmentsWorker: DownloadEmbeddedAttachmentsWorker.Enqueuer,
|
||||
private val dispatchers: DispatcherProvider,
|
||||
private val attachmentsHelper: AttachmentsHelper,
|
||||
messageRendererFactory: MessageRenderer.Factory,
|
||||
verifyConnection: VerifyConnection,
|
||||
networkConfigurator: NetworkConfigurator
|
||||
|
@ -253,20 +255,22 @@ internal class MessageDetailsViewModel @ViewModelInject constructor(
|
|||
|
||||
val attachmentMetadataList = attachmentMetadataDatabase.getAllAttachmentsForMessage(messageId)
|
||||
val embeddedImages = _embeddedImagesAttachments.mapNotNull {
|
||||
EmbeddedImage.fromAttachment(
|
||||
attachmentsHelper.fromAttachmentToEmbededImage(
|
||||
it, decryptedMessageData.value!!.embeddedImagesArray.toList()
|
||||
)
|
||||
}
|
||||
|
||||
val embeddedImagesWithLocalFiles = mutableListOf<EmbeddedImage>()
|
||||
embeddedImages.forEach { embeddedImage ->
|
||||
attachmentMetadataList.find { it.id == embeddedImage.attachmentId }?.let {
|
||||
embeddedImage.localFileName = it.localLocation.substringAfterLast("/")
|
||||
embeddedImagesWithLocalFiles.add(
|
||||
embeddedImage.copy(localFileName = it.localLocation.substringAfterLast("/"))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// don't download embedded images, if we already have them in local storage
|
||||
if (embeddedImages.all { it.localFileName != null }) {
|
||||
AppUtil.postEventOnUi(DownloadEmbeddedImagesEvent(Status.SUCCESS, embeddedImages))
|
||||
if (embeddedImagesWithLocalFiles.all { it.localFileName != null }) {
|
||||
AppUtil.postEventOnUi(DownloadEmbeddedImagesEvent(Status.SUCCESS, embeddedImagesWithLocalFiles))
|
||||
} else {
|
||||
messageDetailsRepository.startDownloadEmbeddedImages(messageId, userManager.username)
|
||||
}
|
||||
|
@ -510,8 +514,8 @@ internal class MessageDetailsViewModel @ViewModelInject constructor(
|
|||
val embeddedImagesToFetch = ArrayList<EmbeddedImage>()
|
||||
val embeddedImagesAttachments = ArrayList<Attachment>()
|
||||
for (attachment in attachments) {
|
||||
val embeddedImage = EmbeddedImage
|
||||
.fromAttachment(attachment, message.embeddedImagesArray.toList()) ?: continue
|
||||
val embeddedImage = attachmentsHelper
|
||||
.fromAttachmentToEmbededImage(attachment, message.embeddedImagesArray.toList()) ?: continue
|
||||
embeddedImagesToFetch.add(embeddedImage)
|
||||
embeddedImagesAttachments.add(attachment)
|
||||
}
|
||||
|
|
|
@ -77,6 +77,7 @@ public class AttachmentHeaders implements Serializable {
|
|||
return contentDisposition;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getContentId() {
|
||||
if (contentId != null && !contentId.isEmpty()) {
|
||||
return contentId.get(0);
|
||||
|
|
|
@ -33,22 +33,19 @@ const val COLUMN_ATTACHMENT_FOLDER_LOCATION = "folder_location"
|
|||
const val COLUMN_ATTACHMENT_DOWNLOAD_TIMESTAMP = "download_timestamp"
|
||||
// endregion
|
||||
|
||||
/**
|
||||
* Created by dino on 4/20/18.
|
||||
*/
|
||||
|
||||
@Entity(tableName = TABLE_ATTACHMENT_METADATA)
|
||||
class AttachmentMetadata constructor(
|
||||
@ColumnInfo(name = COLUMN_ATTACHMENT_ID)
|
||||
@PrimaryKey
|
||||
val id: String,
|
||||
@ColumnInfo(name = COLUMN_ATTACHMENT_NAME)
|
||||
val name: String,
|
||||
@ColumnInfo(name = COLUMN_ATTACHMENT_FILE_SIZE)
|
||||
val size: Long,
|
||||
@ColumnInfo(name = COLUMN_ATTACHMENT_LOCAL_LOCATION)
|
||||
val localLocation: String,
|
||||
@ColumnInfo(name = COLUMN_ATTACHMENT_FOLDER_LOCATION)
|
||||
val folderLocation: String,
|
||||
@ColumnInfo(name = COLUMN_ATTACHMENT_DOWNLOAD_TIMESTAMP)
|
||||
val downloadTimestamp: Long): Serializable
|
||||
@ColumnInfo(name = COLUMN_ATTACHMENT_ID)
|
||||
@PrimaryKey
|
||||
val id: String,
|
||||
@ColumnInfo(name = COLUMN_ATTACHMENT_NAME)
|
||||
val name: String,
|
||||
@ColumnInfo(name = COLUMN_ATTACHMENT_FILE_SIZE)
|
||||
val size: Long,
|
||||
@ColumnInfo(name = COLUMN_ATTACHMENT_LOCAL_LOCATION)
|
||||
val localLocation: String,
|
||||
@ColumnInfo(name = COLUMN_ATTACHMENT_FOLDER_LOCATION)
|
||||
val folderLocation: String,
|
||||
@ColumnInfo(name = COLUMN_ATTACHMENT_DOWNLOAD_TIMESTAMP)
|
||||
val downloadTimestamp: Long
|
||||
) : Serializable
|
||||
|
|
|
@ -126,13 +126,12 @@ data class Attachment @JvmOverloads constructor(
|
|||
private fun isInline(embeddedImagesArray: List<String>): Boolean {
|
||||
val headers = headers ?: return false
|
||||
val contentDisposition = headers.contentDisposition
|
||||
var contentId = headers.contentId
|
||||
if (TextUtils.isEmpty(contentId)) {
|
||||
contentId = headers.contentLocation
|
||||
}
|
||||
if (contentId.isNotEmpty()) {
|
||||
contentId = contentId.removeSurrounding("<", ">")
|
||||
var contentId = if (headers.contentId.isNullOrEmpty()) {
|
||||
headers.contentLocation
|
||||
} else {
|
||||
headers.contentId
|
||||
}
|
||||
contentId = contentId?.removeSurrounding("<", ">")
|
||||
val embeddedMimeTypes = listOf("image/gif", "image/jpeg", "image/png", "image/bmp")
|
||||
var containsInline = false
|
||||
for (element in contentDisposition) {
|
||||
|
@ -143,7 +142,7 @@ data class Attachment @JvmOverloads constructor(
|
|||
}
|
||||
|
||||
return contentDisposition != null &&
|
||||
(containsInline || embeddedImagesArray.contains(contentId.removeSurrounding("<", ">"))) &&
|
||||
(containsInline || embeddedImagesArray.contains(contentId?.removeSurrounding("<", ">"))) &&
|
||||
embeddedMimeTypes.contains(mimeType)
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ import ch.protonmail.android.R
|
|||
import ch.protonmail.android.api.ProgressListener
|
||||
import ch.protonmail.android.api.ProtonMailApiManager
|
||||
import ch.protonmail.android.api.models.room.attachmentMetadata.AttachmentMetadataDatabase
|
||||
import ch.protonmail.android.api.models.room.messages.Attachment
|
||||
import ch.protonmail.android.crypto.AddressCrypto
|
||||
import ch.protonmail.android.crypto.CipherText
|
||||
import ch.protonmail.android.events.DownloadEmbeddedImagesEvent
|
||||
|
@ -39,12 +40,14 @@ import timber.log.Timber
|
|||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.util.Date
|
||||
import java.util.Locale
|
||||
import javax.inject.Inject
|
||||
|
||||
private const val NOTIFICATION_ID = 213_412
|
||||
private const val FULL_PROGRESS = 100
|
||||
private const val BASE_64 = "base64"
|
||||
|
||||
class DownloadAttachmentsHelper @Inject constructor(
|
||||
class AttachmentsHelper @Inject constructor(
|
||||
private val context: Context,
|
||||
private val api: ProtonMailApiManager,
|
||||
private val notificationManager: NotificationManager
|
||||
|
@ -63,14 +66,17 @@ class DownloadAttachmentsHelper @Inject constructor(
|
|||
val attachmentMetadataList = attachmentMetadataDatabase.getAllAttachmentsForMessage(messageId)
|
||||
attachmentMetadataList.size
|
||||
|
||||
val embeddedImagesWithLocalFiles = mutableListOf<EmbeddedImage>()
|
||||
embeddedImages.forEach { embeddedImage ->
|
||||
attachmentMetadataList.find { it.id == embeddedImage.attachmentId }?.let {
|
||||
embeddedImage.localFileName = it.localLocation.substringAfterLast("/")
|
||||
embeddedImagesWithLocalFiles.add(
|
||||
embeddedImage.copy(localFileName = it.localLocation.substringAfterLast("/"))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// all embedded images are in the local filestorage already
|
||||
if (embeddedImages.all { it.localFileName != null }) return true
|
||||
if (embeddedImagesWithLocalFiles.all { it.localFileName != null }) return true
|
||||
}
|
||||
|
||||
return false
|
||||
|
@ -195,4 +201,65 @@ class DownloadAttachmentsHelper @Inject constructor(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun fromAttachmentToEmbededImage(
|
||||
attachment: Attachment,
|
||||
embeddedImagesArray: List<String>
|
||||
): EmbeddedImage? {
|
||||
val headers = attachment.headers ?: return null
|
||||
val contentDisposition = headers.contentDisposition
|
||||
var contentId = if (headers.contentId.isNullOrEmpty()) {
|
||||
headers.contentLocation
|
||||
} else {
|
||||
headers.contentId
|
||||
}
|
||||
contentId = contentId?.removeSurrounding("<", ">")
|
||||
if (contentDisposition != null) {
|
||||
if (contentDisposition.isEmpty()) {
|
||||
return null
|
||||
} else {
|
||||
var containsInlineMarker = false
|
||||
|
||||
for (element in contentDisposition) {
|
||||
if (!element.isNullOrEmpty() && element.contains("inline")) {
|
||||
containsInlineMarker = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if (!containsInlineMarker && !embeddedImagesArray.contains(contentId)) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (attachment.attachmentId.isNullOrEmpty()) {
|
||||
return null
|
||||
}
|
||||
val fileName = attachment.fileName
|
||||
if (fileName.isNullOrEmpty()) {
|
||||
return null
|
||||
}
|
||||
val encoding = headers.contentTransferEncoding
|
||||
val contentType = headers.contentType
|
||||
val mimeData = attachment.mimeData
|
||||
val embeddedMimeTypes = listOf("image/gif", "image/jpeg", "image/png", "image/bmp")
|
||||
return if (!embeddedMimeTypes.contains(attachment.mimeTypeFirstValue?.toLowerCase(Locale.ENGLISH))) {
|
||||
null
|
||||
} else EmbeddedImage(
|
||||
attachment.attachmentId ?: "",
|
||||
fileName,
|
||||
attachment.keyPackets ?: "",
|
||||
if (contentType.isEmpty()) {
|
||||
attachment.mimeType ?: ""
|
||||
} else {
|
||||
contentType
|
||||
},
|
||||
if (encoding.isEmpty()) BASE_64 else encoding,
|
||||
contentId ?: headers.contentLocation,
|
||||
mimeData,
|
||||
attachment.fileSize,
|
||||
attachment.messageId,
|
||||
null
|
||||
)
|
||||
}
|
||||
}
|
|
@ -136,7 +136,7 @@ class AttachmentsRepository @Inject constructor(
|
|||
}
|
||||
|
||||
private fun contentIdFormatted(headers: AttachmentHeaders): String {
|
||||
val contentId = headers.contentId
|
||||
val contentId = requireNotNull(headers.contentId)
|
||||
val parts = contentId.split("<").dropLastWhile { it.isEmpty() }.toTypedArray()
|
||||
if (parts.size > 1) {
|
||||
return parts[1].replace(">", "")
|
||||
|
|
|
@ -76,7 +76,7 @@ class DownloadEmbeddedAttachmentsWorker @WorkerInject constructor(
|
|||
private val userManager: UserManager,
|
||||
private val messageDetailsRepository: MessageDetailsRepository,
|
||||
private val attachmentMetadataDatabase: AttachmentMetadataDatabase,
|
||||
private val downloadHelper: DownloadAttachmentsHelper
|
||||
private val downloadHelper: AttachmentsHelper
|
||||
) : Worker(context, params) {
|
||||
|
||||
override fun doWork(): Result {
|
||||
|
@ -111,7 +111,9 @@ class DownloadEmbeddedAttachmentsWorker @WorkerInject constructor(
|
|||
attachments = message.Attachments
|
||||
}
|
||||
|
||||
val embeddedImages = attachments.mapNotNull { EmbeddedImage.fromAttachment(it, message.embeddedImagesArray) }
|
||||
val embeddedImages = attachments.mapNotNull {
|
||||
downloadHelper.fromAttachmentToEmbededImage(it, message.embeddedImagesArray)
|
||||
}
|
||||
val otherAttachments = attachments.filter { attachment ->
|
||||
embeddedImages.find { attachment.attachmentId == it.attachmentId } == null
|
||||
}
|
||||
|
@ -232,7 +234,7 @@ class DownloadEmbeddedAttachmentsWorker @WorkerInject constructor(
|
|||
var failure = false
|
||||
embeddedImages.forEachIndexed { index, embeddedImage ->
|
||||
|
||||
val filename = downloadHelper.calculateFilename(embeddedImage.fileName!!, index)
|
||||
val filename = downloadHelper.calculateFilename(embeddedImage.fileNameFormatted!!, index)
|
||||
val attachmentFile = File(attachmentsDirectoryFile, filename)
|
||||
|
||||
try {
|
||||
|
@ -247,12 +249,12 @@ class DownloadEmbeddedAttachmentsWorker @WorkerInject constructor(
|
|||
it.write(decryptedByteArray)
|
||||
}
|
||||
|
||||
embeddedImage.localFileName = filename
|
||||
val embeddedImageWithFile = embeddedImage.copy(localFileName = filename)
|
||||
val attachmentMetadata = AttachmentMetadata(
|
||||
embeddedImage.attachmentId,
|
||||
embeddedImage.fileName!!, embeddedImage.size,
|
||||
embeddedImage.messageId + "/" + filename,
|
||||
embeddedImage.messageId, System.currentTimeMillis()
|
||||
embeddedImageWithFile.attachmentId,
|
||||
embeddedImageWithFile.fileNameFormatted!!, embeddedImageWithFile.size,
|
||||
embeddedImageWithFile.messageId + "/" + filename,
|
||||
embeddedImageWithFile.messageId, System.currentTimeMillis()
|
||||
)
|
||||
attachmentMetadataDatabase.insertAttachmentMetadata(attachmentMetadata)
|
||||
|
||||
|
|
|
@ -18,92 +18,17 @@
|
|||
*/
|
||||
package ch.protonmail.android.jobs.helper
|
||||
|
||||
import android.text.TextUtils
|
||||
import ch.protonmail.android.api.models.room.messages.Attachment
|
||||
import java.util.*
|
||||
|
||||
// region constants
|
||||
private const val BASE_64 = "base64"
|
||||
// endregion
|
||||
|
||||
/**
|
||||
* Created by dkadrikj on 7/16/16.
|
||||
*/
|
||||
|
||||
class EmbeddedImage private constructor(
|
||||
val attachmentId: String,
|
||||
fileName: String,
|
||||
val key: String,
|
||||
val contentType: String,
|
||||
val encoding: String,
|
||||
val contentId: String,
|
||||
val mimeData: ByteArray?,
|
||||
val size: Long,
|
||||
val messageId: String,
|
||||
var localFileName: String?) {
|
||||
var fileName: String? = null
|
||||
|
||||
init {
|
||||
this.fileName = fileName.replace(" ", "_")
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
fun fromAttachment(attachment: Attachment, embeddedImagesArray: List<String>): EmbeddedImage? {
|
||||
val headers = attachment.headers ?: return null
|
||||
val contentDisposition = headers.contentDisposition
|
||||
var contentId = headers.contentId
|
||||
if (TextUtils.isEmpty(contentId)) {
|
||||
contentId = headers.contentLocation
|
||||
}
|
||||
if (!TextUtils.isEmpty(contentId)) {
|
||||
contentId = contentId.removeSurrounding("<", ">")
|
||||
}
|
||||
if (contentDisposition != null) {
|
||||
if (contentDisposition.isEmpty()) {
|
||||
return null
|
||||
} else {
|
||||
var containsInlineMarker = false
|
||||
|
||||
for (element in contentDisposition) {
|
||||
if (!element.isNullOrEmpty() && element.contains("inline")) {
|
||||
containsInlineMarker = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if (!containsInlineMarker && !embeddedImagesArray.contains(contentId)) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (TextUtils.isEmpty(attachment.attachmentId)) {
|
||||
return null
|
||||
}
|
||||
val fileName = attachment.fileName
|
||||
if (TextUtils.isEmpty(fileName)) {
|
||||
return null
|
||||
}
|
||||
val encoding = headers.contentTransferEncoding
|
||||
val contentType = headers.contentType
|
||||
val mimeData = attachment.mimeData
|
||||
val embeddedMimeTypes = Arrays.asList("image/gif", "image/jpeg", "image/png", "image/bmp")
|
||||
return if (!embeddedMimeTypes.contains(attachment.mimeTypeFirstValue?.toLowerCase())) {
|
||||
null
|
||||
} else EmbeddedImage(attachment.attachmentId ?: "",
|
||||
fileName!!,
|
||||
attachment.keyPackets ?: "",
|
||||
if (TextUtils.isEmpty(contentType)) {
|
||||
attachment.mimeType ?: ""
|
||||
} else {
|
||||
contentType
|
||||
},
|
||||
if (TextUtils.isEmpty(encoding)) BASE_64 else encoding,
|
||||
contentId,
|
||||
mimeData,
|
||||
attachment.fileSize,
|
||||
attachment.messageId,
|
||||
null)
|
||||
}
|
||||
}
|
||||
data class EmbeddedImage constructor(
|
||||
val attachmentId: String,
|
||||
val fileName: String,
|
||||
val key: String,
|
||||
val contentType: String,
|
||||
val encoding: String,
|
||||
val contentId: String,
|
||||
val mimeData: ByteArray?,
|
||||
val size: Long,
|
||||
val messageId: String,
|
||||
val localFileName: String?
|
||||
) {
|
||||
var fileNameFormatted: String? = fileName.replace(" ", "_")
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ import ch.protonmail.android.activities.messageDetails.MessageRenderer
|
|||
import ch.protonmail.android.activities.messageDetails.repository.MessageDetailsRepository
|
||||
import ch.protonmail.android.api.NetworkConfigurator
|
||||
import ch.protonmail.android.api.models.room.attachmentMetadata.AttachmentMetadataDatabase
|
||||
import ch.protonmail.android.attachments.AttachmentsHelper
|
||||
import ch.protonmail.android.attachments.DownloadEmbeddedAttachmentsWorker
|
||||
import ch.protonmail.android.core.UserManager
|
||||
import ch.protonmail.android.data.ContactsRepository
|
||||
|
@ -59,6 +60,9 @@ class MessageDetailsViewModelTest : ArchTest, CoroutinesTest {
|
|||
@RelaxedMockK
|
||||
private lateinit var contactsRepository: ContactsRepository
|
||||
|
||||
@RelaxedMockK
|
||||
private lateinit var attachmentsHelper: AttachmentsHelper
|
||||
|
||||
@RelaxedMockK
|
||||
private lateinit var attachmentMetadataDatabase: AttachmentMetadataDatabase
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ package ch.protonmail.android.attachments
|
|||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
|
||||
class DownloadAttachmentsHelperTest {
|
||||
class AttachmentsHelperTest {
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
Loading…
Reference in New Issue