Moved some labels and message related logic for action sheet from MessageDetailsRepository to MessageRepository.
MAILAND-1401
This commit is contained in:
parent
514f83e1bd
commit
36beb44829
|
@ -45,11 +45,8 @@ import ch.protonmail.android.domain.entity.Id
|
|||
import ch.protonmail.android.jobs.ApplyLabelJob
|
||||
import ch.protonmail.android.jobs.FetchMessageDetailJob
|
||||
import ch.protonmail.android.jobs.PostReadJob
|
||||
import ch.protonmail.android.jobs.PostStarJob
|
||||
import ch.protonmail.android.jobs.PostUnreadJob
|
||||
import ch.protonmail.android.jobs.PostUnstarJob
|
||||
import ch.protonmail.android.jobs.RemoveLabelJob
|
||||
import ch.protonmail.android.jobs.ReportPhishingJob
|
||||
import ch.protonmail.android.utils.MessageUtils
|
||||
import ch.protonmail.android.utils.extensions.asyncMap
|
||||
import com.birbit.android.jobqueue.Job
|
||||
|
@ -124,12 +121,6 @@ class MessageDetailsRepository @Inject constructor(
|
|||
fun findMessageById(messageId: String): Flow<Message?> =
|
||||
messagesDao.findMessageById(messageId).map { readMessageBodyFromFileIfNeeded(it) }
|
||||
|
||||
suspend fun findMessageByIdOnce(messageId: String): Message =
|
||||
messagesDao.findMessageByIdOnce(messageId).apply { readMessageBodyFromFileIfNeeded(this) }
|
||||
|
||||
fun findSearchMessageByIdBlocking(messageId: String): Message? =
|
||||
searchDatabaseDao.findMessageByIdBlocking(messageId)?.apply { readMessageBodyFromFileIfNeeded(this) }
|
||||
|
||||
fun findSearchMessageById(messageId: String): Flow<Message?> =
|
||||
searchDatabaseDao.findMessageById(messageId).map { readMessageBodyFromFileIfNeeded(it) }
|
||||
|
||||
|
@ -552,33 +543,22 @@ class MessageDetailsRepository @Inject constructor(
|
|||
attachmentsWorker.enqueue(messageId, userId, "")
|
||||
}
|
||||
|
||||
@Deprecated("Use a method from [MessageRepository]")
|
||||
fun markRead(messageIds: List<String>) {
|
||||
jobManager.addJobInBackground(PostReadJob(messageIds))
|
||||
}
|
||||
|
||||
@Deprecated("Use a method from [MessageRepository]")
|
||||
fun markUnRead(messageIds: List<String>) {
|
||||
jobManager.addJobInBackground(PostUnreadJob(messageIds))
|
||||
}
|
||||
|
||||
fun starMessages(messageIds: List<String>) {
|
||||
jobManager.addJobInBackground(PostStarJob(messageIds))
|
||||
}
|
||||
|
||||
fun unStarMessages(messageIds: List<String>) {
|
||||
jobManager.addJobInBackground(PostUnstarJob(messageIds))
|
||||
}
|
||||
|
||||
fun findAllPendingSendsAsync(): LiveData<List<PendingSend>> =
|
||||
pendingActionDao.findAllPendingSendsAsync()
|
||||
|
||||
fun findAllPendingUploadsAsync(): LiveData<List<PendingUpload>> =
|
||||
pendingActionDao.findAllPendingUploadsAsync()
|
||||
|
||||
suspend fun reportPhishing(messageId: String) {
|
||||
val message = findMessageByIdOnce(messageId)
|
||||
jobManager.addJobInBackground(ReportPhishingJob(message))
|
||||
}
|
||||
|
||||
@AssistedInject.Factory
|
||||
interface AssistedFactory {
|
||||
|
||||
|
|
|
@ -126,10 +126,6 @@ abstract class MessageDao {
|
|||
message.Attachments = message.attachments(this)
|
||||
}
|
||||
|
||||
suspend fun findMessageByIdOnce(messageId: String): Message = findMessageInfoByIdOnce(messageId).also { message ->
|
||||
message.Attachments = message.attachmentsBlocking(this)
|
||||
}
|
||||
|
||||
@Deprecated("Use Flow variant", ReplaceWith("findMessageById(messageId).first()"))
|
||||
fun findMessageByIdBlocking(messageId: String): Message? = findMessageInfoByIdBlocking(messageId)
|
||||
?.also { message ->
|
||||
|
@ -182,7 +178,7 @@ abstract class MessageDao {
|
|||
protected abstract fun findMessageInfoById(messageId: String): Flow<Message?>
|
||||
|
||||
@Query("SELECT * FROM $TABLE_MESSAGES WHERE $COLUMN_MESSAGE_ID = :messageId")
|
||||
protected abstract suspend fun findMessageInfoByIdOnce(messageId: String): Message
|
||||
protected abstract suspend fun findMessageInfoByIdOnce(messageId: String): Message?
|
||||
|
||||
@Deprecated("Use Flow variant", ReplaceWith("findMessageInfoById(messageId).first()"))
|
||||
@Query("SELECT * FROM $TABLE_MESSAGES WHERE $COLUMN_MESSAGE_ID = :messageId")
|
||||
|
|
|
@ -20,11 +20,13 @@
|
|||
package ch.protonmail.android.labels.domain.usecase
|
||||
|
||||
import ch.protonmail.android.activities.messageDetails.repository.MessageDetailsRepository
|
||||
import ch.protonmail.android.repository.MessageRepository
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
class UpdateLabels @Inject constructor(
|
||||
private val messageDetailsRepository: MessageDetailsRepository
|
||||
private val messageDetailsRepository: MessageDetailsRepository, // TODO: Replace it with future LabelsRepository
|
||||
private val messageRepository: MessageRepository
|
||||
) {
|
||||
|
||||
suspend operator fun invoke(
|
||||
|
@ -32,7 +34,7 @@ class UpdateLabels @Inject constructor(
|
|||
checkedLabelIds: List<String>,
|
||||
isTransient: Boolean = false
|
||||
) {
|
||||
val message = messageDetailsRepository.findMessageByIdOnce(messageId)
|
||||
val message = requireNotNull(messageRepository.findMessageById(messageId))
|
||||
val existingLabels = messageDetailsRepository.getAllLabels()
|
||||
.filter { it.id in message.labelIDsNotIncludingLocations }
|
||||
Timber.v("UpdateLabels checkedLabelIds: $checkedLabelIds")
|
||||
|
|
|
@ -28,17 +28,24 @@ import ch.protonmail.android.domain.entity.Id
|
|||
import ch.protonmail.android.jobs.MoveToFolderJob
|
||||
import ch.protonmail.android.jobs.PostArchiveJob
|
||||
import ch.protonmail.android.jobs.PostInboxJob
|
||||
import ch.protonmail.android.jobs.PostReadJob
|
||||
import ch.protonmail.android.jobs.PostSpamJob
|
||||
import ch.protonmail.android.jobs.PostStarJob
|
||||
import ch.protonmail.android.jobs.PostTrashJobV2
|
||||
import ch.protonmail.android.jobs.PostUnreadJob
|
||||
import ch.protonmail.android.jobs.PostUnstarJob
|
||||
import ch.protonmail.android.utils.MessageBodyFileManager
|
||||
import com.birbit.android.jobqueue.JobManager
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.withContext
|
||||
import me.proton.core.util.kotlin.DispatcherProvider
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
const val MAX_BODY_SIZE_IN_DB = 900 * 1024 // 900 KB
|
||||
|
||||
private const val FILE_PREFIX = "file://"
|
||||
|
||||
/**
|
||||
* A repository for getting and saving messages.
|
||||
*/
|
||||
|
@ -57,12 +64,22 @@ class MessageRepository @Inject constructor(
|
|||
val messageDao = databaseProvider.provideMessageDao(userId)
|
||||
return@withContext messageDao.findMessageById(messageId).first()?.apply {
|
||||
messageBody?.let {
|
||||
if (it.startsWith("file://"))
|
||||
if (it.startsWith(FILE_PREFIX))
|
||||
messageBody = messageBodyFileManager.readMessageBodyFromFile(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun findMessageById(messageId: String): Message? {
|
||||
val currentUser = userManager.currentUserId
|
||||
return if (currentUser != null) {
|
||||
findMessage(currentUser, messageId)
|
||||
} else {
|
||||
Timber.w("Cannot find message for null user id")
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun saveMessage(userId: Id, message: Message): Long =
|
||||
withContext(dispatcherProvider.Io) {
|
||||
val messageToBeSaved = message.apply {
|
||||
|
@ -166,4 +183,21 @@ class MessageRepository @Inject constructor(
|
|||
MoveToFolderJob(messageIds, newFolderLocationId)
|
||||
)
|
||||
}
|
||||
|
||||
fun starMessages(messageIds: List<String>) {
|
||||
jobManager.addJobInBackground(PostStarJob(messageIds))
|
||||
}
|
||||
|
||||
fun unStarMessages(messageIds: List<String>) {
|
||||
jobManager.addJobInBackground(PostUnstarJob(messageIds))
|
||||
}
|
||||
|
||||
fun markRead(messageIds: List<String>) {
|
||||
jobManager.addJobInBackground(PostReadJob(messageIds))
|
||||
}
|
||||
|
||||
fun markUnRead(messageIds: List<String>) {
|
||||
jobManager.addJobInBackground(PostUnreadJob(messageIds))
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -69,7 +69,7 @@ class MessageActionSheet : BottomSheetDialogFragment() {
|
|||
val binding = FragmentMessageDetailsActionSheetBinding.inflate(inflater)
|
||||
|
||||
setupHeaderBindings(binding.actionSheetHeaderDetailsActions, arguments)
|
||||
setupMessageReplyActionsBindings(binding.includeLayoutActionSheetButtons, originatorId)
|
||||
setupReplyActionsBindings(binding.includeLayoutActionSheetButtons, originatorId)
|
||||
setupManageSectionBindings(binding, viewModel, originatorId, messageIds, messageLocation)
|
||||
setupMoveSectionBindings(binding, viewModel, messageIds, messageLocation)
|
||||
setupMoreSectionBindings(binding, originatorId, messageIds)
|
||||
|
@ -142,7 +142,7 @@ class MessageActionSheet : BottomSheetDialogFragment() {
|
|||
}
|
||||
}
|
||||
|
||||
private fun setupMessageReplyActionsBindings(
|
||||
private fun setupReplyActionsBindings(
|
||||
binding: LayoutMessageDetailsActionsSheetButtonsBinding,
|
||||
originatorId: Int
|
||||
) = with(binding) {
|
||||
|
|
|
@ -21,23 +21,24 @@ package ch.protonmail.android.ui.dialog
|
|||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import ch.protonmail.android.activities.messageDetails.repository.MessageDetailsRepository
|
||||
import ch.protonmail.android.core.Constants
|
||||
import ch.protonmail.android.labels.domain.usecase.MoveMessagesToFolder
|
||||
import ch.protonmail.android.labels.presentation.ui.ManageLabelsActionSheet
|
||||
import ch.protonmail.android.repository.MessageRepository
|
||||
import ch.protonmail.android.usecase.delete.DeleteMessage
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import me.proton.core.util.kotlin.EMPTY_STRING
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class MessageActionSheetViewModel @Inject constructor(
|
||||
private val deleteMessage: DeleteMessage,
|
||||
private val moveMessagesToFolder: MoveMessagesToFolder,
|
||||
private val messageDetailsRepository: MessageDetailsRepository
|
||||
private val messageRepository: MessageRepository
|
||||
) : ViewModel() {
|
||||
|
||||
private val actionsMutableFlow = MutableStateFlow<MessageActionSheetAction>(MessageActionSheetAction.Default)
|
||||
|
@ -65,8 +66,11 @@ class MessageActionSheetViewModel @Inject constructor(
|
|||
): List<String> {
|
||||
val checkedLabels = mutableListOf<String>()
|
||||
messageIds.forEach { messageId ->
|
||||
val message = messageDetailsRepository.findMessageByIdOnce(messageId)
|
||||
checkedLabels.addAll(message.labelIDsNotIncludingLocations)
|
||||
val message = messageRepository.findMessageById(messageId)
|
||||
Timber.v("Checking message labels: ${message?.labelIDsNotIncludingLocations}")
|
||||
message?.labelIDsNotIncludingLocations?.let {
|
||||
checkedLabels.addAll(it)
|
||||
}
|
||||
}
|
||||
return checkedLabels
|
||||
}
|
||||
|
@ -112,19 +116,19 @@ class MessageActionSheetViewModel @Inject constructor(
|
|||
)
|
||||
|
||||
fun starMessage(messageId: List<String>) =
|
||||
messageDetailsRepository.starMessages(messageId)
|
||||
messageRepository.starMessages(messageId)
|
||||
|
||||
fun unStarMessage(messageId: List<String>) =
|
||||
messageDetailsRepository.unStarMessages(messageId)
|
||||
messageRepository.unStarMessages(messageId)
|
||||
|
||||
fun markUnread(messageIds: List<String>) = messageDetailsRepository.markUnRead(messageIds)
|
||||
fun markUnread(messageIds: List<String>) = messageRepository.markUnRead(messageIds)
|
||||
|
||||
fun markRead(messageIds: List<String>) = messageDetailsRepository.markRead(messageIds)
|
||||
fun markRead(messageIds: List<String>) = messageRepository.markRead(messageIds)
|
||||
|
||||
fun showMessageHeaders(messageId: String) {
|
||||
viewModelScope.launch {
|
||||
val message = messageDetailsRepository.findMessageByIdOnce(messageId)
|
||||
actionsMutableFlow.value = MessageActionSheetAction.ShowMessageHeaders(message.header ?: EMPTY_STRING)
|
||||
val message = messageRepository.findMessageById(messageId)
|
||||
actionsMutableFlow.value = MessageActionSheetAction.ShowMessageHeaders(message?.header ?: EMPTY_STRING)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ import me.proton.core.util.kotlin.DispatcherProvider
|
|||
import okio.buffer
|
||||
import okio.sink
|
||||
import okio.source
|
||||
import timber.log.Timber
|
||||
import java.io.File
|
||||
import java.io.FileInputStream
|
||||
import java.io.FileOutputStream
|
||||
|
@ -48,7 +49,10 @@ class FileHelper @Inject constructor(
|
|||
FileInputStream(file)
|
||||
.bufferedReader()
|
||||
.use { it.readText() }
|
||||
}.getOrNull()
|
||||
}
|
||||
.onFailure { Timber.i(it, "Unable to read file") }
|
||||
.onSuccess { Timber.v("File ${file.path} read success") }
|
||||
.getOrNull()
|
||||
}
|
||||
|
||||
suspend fun writeToFile(file: File, text: String): Boolean = withContext(dispatcherProvider.Io) {
|
||||
|
|
|
@ -22,6 +22,7 @@ package ch.protonmail.android.labels.domain.usecase
|
|||
import ch.protonmail.android.activities.messageDetails.repository.MessageDetailsRepository
|
||||
import ch.protonmail.android.data.local.model.Label
|
||||
import ch.protonmail.android.data.local.model.Message
|
||||
import ch.protonmail.android.repository.MessageRepository
|
||||
import io.mockk.MockKAnnotations
|
||||
import io.mockk.Runs
|
||||
import io.mockk.coEvery
|
||||
|
@ -39,12 +40,15 @@ class UpdateLabelsTest {
|
|||
@MockK
|
||||
private lateinit var repository: MessageDetailsRepository
|
||||
|
||||
@MockK
|
||||
private lateinit var newRepository: MessageRepository
|
||||
|
||||
private lateinit var useCase: UpdateLabels
|
||||
|
||||
@BeforeTest
|
||||
fun setUp() {
|
||||
MockKAnnotations.init(this)
|
||||
useCase = UpdateLabels(repository)
|
||||
useCase = UpdateLabels(repository, newRepository)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -61,7 +65,7 @@ class UpdateLabelsTest {
|
|||
val label = mockk<Label> {
|
||||
every { id } returns testLabelId1
|
||||
}
|
||||
coEvery { repository.findMessageByIdOnce(testMessageId) } returns message
|
||||
coEvery { newRepository.findMessageById(testMessageId) } returns message
|
||||
val existingLabels = listOf(label)
|
||||
coEvery { repository.getAllLabels() } returns existingLabels
|
||||
val checkedLabelIds = listOf(testLabelId1)
|
||||
|
|
|
@ -19,11 +19,11 @@
|
|||
|
||||
package ch.protonmail.android.ui.dialog
|
||||
|
||||
import ch.protonmail.android.activities.messageDetails.repository.MessageDetailsRepository
|
||||
import ch.protonmail.android.core.Constants
|
||||
import ch.protonmail.android.data.local.model.Message
|
||||
import ch.protonmail.android.labels.domain.usecase.MoveMessagesToFolder
|
||||
import ch.protonmail.android.labels.presentation.ui.ManageLabelsActionSheet
|
||||
import ch.protonmail.android.repository.MessageRepository
|
||||
import ch.protonmail.android.usecase.delete.DeleteMessage
|
||||
import io.mockk.MockKAnnotations
|
||||
import io.mockk.coEvery
|
||||
|
@ -46,7 +46,7 @@ class MessageActionSheetViewModelTest : ArchTest, CoroutinesTest {
|
|||
private lateinit var moveMessagesToFolder: MoveMessagesToFolder
|
||||
|
||||
@MockK
|
||||
private lateinit var repository: MessageDetailsRepository
|
||||
private lateinit var repository: MessageRepository
|
||||
private lateinit var viewModel: MessageActionSheetViewModel
|
||||
|
||||
@BeforeTest
|
||||
|
@ -85,8 +85,8 @@ class MessageActionSheetViewModelTest : ArchTest, CoroutinesTest {
|
|||
every { messageId } returns messageId2
|
||||
every { labelIDsNotIncludingLocations } returns listOf(labelId2)
|
||||
}
|
||||
coEvery { repository.findMessageByIdOnce(messageId1) } returns message1
|
||||
coEvery { repository.findMessageByIdOnce(messageId2) } returns message2
|
||||
coEvery { repository.findMessageById(messageId1) } returns message1
|
||||
coEvery { repository.findMessageById(messageId2) } returns message2
|
||||
|
||||
// when
|
||||
viewModel.showLabelsManager(messageIds, currentLocation)
|
||||
|
@ -121,8 +121,8 @@ class MessageActionSheetViewModelTest : ArchTest, CoroutinesTest {
|
|||
every { messageId } returns messageId2
|
||||
every { labelIDsNotIncludingLocations } returns listOf(labelId2)
|
||||
}
|
||||
coEvery { repository.findMessageByIdOnce(messageId1) } returns message1
|
||||
coEvery { repository.findMessageByIdOnce(messageId2) } returns message2
|
||||
coEvery { repository.findMessageById(messageId1) } returns message1
|
||||
coEvery { repository.findMessageById(messageId2) } returns message2
|
||||
|
||||
// when
|
||||
viewModel.showLabelsManager(messageIds, currentLocation, ManageLabelsActionSheet.Type.FOLDER)
|
||||
|
@ -141,7 +141,7 @@ class MessageActionSheetViewModelTest : ArchTest, CoroutinesTest {
|
|||
every { messageId } returns messageId1
|
||||
every { header } returns messageHeader
|
||||
}
|
||||
coEvery { repository.findMessageByIdOnce(messageId1) } returns message1
|
||||
coEvery { repository.findMessageById(messageId1) } returns message1
|
||||
val expected = MessageActionSheetAction.ShowMessageHeaders(messageHeader)
|
||||
|
||||
// when
|
||||
|
|
|
@ -160,7 +160,7 @@ class DeleteMessageTest {
|
|||
every { db.findPendingUploadByMessageId(any()) } returns null
|
||||
every { db.findPendingSendByMessageId(any()) } returns pendingSend
|
||||
every { repository.findMessageByIdBlocking(messId) } returns null
|
||||
every { repository.findSearchMessageByIdBlocking(messId) } returns message
|
||||
every { repository.findSearchMessageById(messId) } returns flowOf(message)
|
||||
coEvery { repository.saveMessage(message) } returns 1L
|
||||
coEvery { repository.saveSearchMessage(message) } returns 0L
|
||||
coEvery { repository.saveMessagesInOneTransaction(any()) } returns Unit
|
||||
|
|
Loading…
Reference in New Issue