diff --git a/app/src/main/java/org/thoughtcrime/securesms/repository/ConversationRepository.kt b/app/src/main/java/org/thoughtcrime/securesms/repository/ConversationRepository.kt index 2a00440dda..7f10b1eb20 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/repository/ConversationRepository.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/repository/ConversationRepository.kt @@ -8,7 +8,6 @@ import app.cash.copper.Query import app.cash.copper.flow.observeQuery import dagger.hilt.android.qualifiers.ApplicationContext import kotlin.coroutines.resume -import kotlin.coroutines.resumeWithException import kotlin.coroutines.suspendCoroutine import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map @@ -59,15 +58,15 @@ interface ConversationRepository { fun deleteLocally(recipient: Recipient, message: MessageRecord) fun deleteAllLocalMessagesInThreadFromSenderOfMessage(messageRecord: MessageRecord) fun setApproved(recipient: Recipient, isApproved: Boolean) - suspend fun deleteForEveryone(threadId: Long, recipient: Recipient, message: MessageRecord): ResultOf + suspend fun deleteForEveryone(threadId: Long, recipient: Recipient, message: MessageRecord): Result fun buildUnsendRequest(recipient: Recipient, message: MessageRecord): UnsendRequest? - suspend fun deleteMessageWithoutUnsendRequest(threadId: Long, messages: Set): ResultOf - suspend fun banUser(threadId: Long, recipient: Recipient): ResultOf - suspend fun banAndDeleteAll(threadId: Long, recipient: Recipient): ResultOf - suspend fun deleteThread(threadId: Long): ResultOf - suspend fun deleteMessageRequest(thread: ThreadRecord): ResultOf - suspend fun clearAllMessageRequests(block: Boolean): ResultOf - suspend fun acceptMessageRequest(threadId: Long, recipient: Recipient): ResultOf + suspend fun deleteMessageWithoutUnsendRequest(threadId: Long, messages: Set): Result + suspend fun banUser(threadId: Long, recipient: Recipient): Result + suspend fun banAndDeleteAll(threadId: Long, recipient: Recipient): Result + suspend fun deleteThread(threadId: Long): Result + suspend fun deleteMessageRequest(thread: ThreadRecord): Result + suspend fun clearAllMessageRequests(block: Boolean): Result + suspend fun acceptMessageRequest(threadId: Long, recipient: Recipient): Result fun declineMessageRequest(threadId: Long) fun hasReceived(threadId: Long): Boolean } @@ -185,7 +184,7 @@ class DefaultConversationRepository @Inject constructor( threadId: Long, recipient: Recipient, message: MessageRecord - ): ResultOf = suspendCoroutine { continuation -> + ): Result = suspendCoroutine { continuation -> buildUnsendRequest(recipient, message)?.let { unsendRequest -> MessageSender.send(unsendRequest, recipient.address) } @@ -196,10 +195,10 @@ class DefaultConversationRepository @Inject constructor( OpenGroupApi.deleteMessage(messageServerID, openGroup.room, openGroup.server) .success { messageDataProvider.deleteMessage(message.id, !message.isMms) - continuation.resume(ResultOf.Success(Unit)) + continuation.resume(Result.success(Unit)) }.fail { error -> Log.w("TAG", "Call to OpenGroupApi.deleteForEveryone failed - attempting to resume..") - continuation.resumeWithException(error) + continuation.resume(Result.failure(error)) } } @@ -229,10 +228,10 @@ class DefaultConversationRepository @Inject constructor( } SnodeAPI.deleteMessage(publicKey, listOf(serverHash)) .success { - continuation.resume(ResultOf.Success(Unit)) + continuation.resume(Result.success(Unit)) }.fail { error -> Log.w("ConversationRepository", "Call to SnodeAPI.deleteMessage failed - attempting to resume..") - continuation.resumeWithException(error) + continuation.resume(Result.failure(error)) } } } @@ -250,7 +249,7 @@ class DefaultConversationRepository @Inject constructor( override suspend fun deleteMessageWithoutUnsendRequest( threadId: Long, messages: Set - ): ResultOf = suspendCoroutine { continuation -> + ): Result = suspendCoroutine { continuation -> val openGroup = lokiThreadDb.getOpenGroupChat(threadId) if (openGroup != null) { val messageServerIDs = mutableMapOf() @@ -264,7 +263,7 @@ class DefaultConversationRepository @Inject constructor( .success { messageDataProvider.deleteMessage(message.id, !message.isMms) }.fail { error -> - continuation.resumeWithException(error) + continuation.resume(Result.failure(error)) } } } else { @@ -276,22 +275,22 @@ class DefaultConversationRepository @Inject constructor( } } } - continuation.resume(ResultOf.Success(Unit)) + continuation.resume(Result.success(Unit)) } - override suspend fun banUser(threadId: Long, recipient: Recipient): ResultOf = + override suspend fun banUser(threadId: Long, recipient: Recipient): Result = suspendCoroutine { continuation -> val accountID = recipient.address.toString() val openGroup = lokiThreadDb.getOpenGroupChat(threadId)!! OpenGroupApi.ban(accountID, openGroup.room, openGroup.server) .success { - continuation.resume(ResultOf.Success(Unit)) + continuation.resume(Result.success(Unit)) }.fail { error -> - continuation.resumeWithException(error) + continuation.resume(Result.failure(error)) } } - override suspend fun banAndDeleteAll(threadId: Long, recipient: Recipient): ResultOf = + override suspend fun banAndDeleteAll(threadId: Long, recipient: Recipient): Result = suspendCoroutine { continuation -> // Note: This accountId could be the blinded Id val accountID = recipient.address.toString() @@ -299,25 +298,25 @@ class DefaultConversationRepository @Inject constructor( OpenGroupApi.banAndDeleteAll(accountID, openGroup.room, openGroup.server) .success { - continuation.resume(ResultOf.Success(Unit)) + continuation.resume(Result.success(Unit)) }.fail { error -> - continuation.resumeWithException(error) + continuation.resume(Result.failure(error)) } } - override suspend fun deleteThread(threadId: Long): ResultOf { + override suspend fun deleteThread(threadId: Long): Result { sessionJobDb.cancelPendingMessageSendJobs(threadId) storage.deleteConversation(threadId) - return ResultOf.Success(Unit) + return Result.success(Unit) } - override suspend fun deleteMessageRequest(thread: ThreadRecord): ResultOf { + override suspend fun deleteMessageRequest(thread: ThreadRecord): Result { sessionJobDb.cancelPendingMessageSendJobs(thread.threadId) storage.deleteConversation(thread.threadId) - return ResultOf.Success(Unit) + return Result.success(Unit) } - override suspend fun clearAllMessageRequests(block: Boolean): ResultOf { + override suspend fun clearAllMessageRequests(block: Boolean): Result { threadDb.readerFor(threadDb.unapprovedConversationList).use { reader -> while (reader.next != null) { deleteMessageRequest(reader.current) @@ -325,18 +324,18 @@ class DefaultConversationRepository @Inject constructor( if (block) { setBlocked(recipient, true) } } } - return ResultOf.Success(Unit) + return Result.success(Unit) } - override suspend fun acceptMessageRequest(threadId: Long, recipient: Recipient): ResultOf = suspendCoroutine { continuation -> + override suspend fun acceptMessageRequest(threadId: Long, recipient: Recipient): Result = suspendCoroutine { continuation -> storage.setRecipientApproved(recipient, true) val message = MessageRequestResponse(true) MessageSender.send(message, Destination.from(recipient.address), isSyncMessage = recipient.isLocalNumber) .success { threadDb.setHasSent(threadId, true) - continuation.resume(ResultOf.Success(Unit)) + continuation.resume(Result.success(Unit)) }.fail { error -> - continuation.resumeWithException(error) + continuation.resume(Result.failure(error)) } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/repository/ResultOf.kt b/app/src/main/java/org/thoughtcrime/securesms/repository/ResultOf.kt deleted file mode 100644 index 96ae97e510..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/repository/ResultOf.kt +++ /dev/null @@ -1,43 +0,0 @@ -package org.thoughtcrime.securesms.repository - -import kotlinx.coroutines.CancellationException - -sealed class ResultOf { - - data class Success(val value: R) : ResultOf() - - data class Failure(val throwable: Throwable) : ResultOf() - - inline fun onFailure(block: (throwable: Throwable) -> Unit) = this.also { - if (this is Failure) { - block(throwable) - } - } - - inline fun onSuccess(block: (value: T) -> Unit) = this.also { - if (this is Success) { - block(value) - } - } - - inline fun flatMap(mapper: (T) -> R): ResultOf = when (this) { - is Success -> wrap { mapper(value) } - is Failure -> Failure(throwable) - } - - fun getOrThrow(): T = when (this) { - is Success -> value - is Failure -> throw throwable - } - - companion object { - inline fun wrap(block: () -> T): ResultOf = - try { - Success(block()) - } catch (e: CancellationException) { - throw e - } catch (e: Exception) { - Failure(e) - } - } -} diff --git a/app/src/test/java/org/thoughtcrime/securesms/conversation/v2/ConversationViewModelTest.kt b/app/src/test/java/org/thoughtcrime/securesms/conversation/v2/ConversationViewModelTest.kt index 7f4db828e4..1bd6a63c7f 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/conversation/v2/ConversationViewModelTest.kt +++ b/app/src/test/java/org/thoughtcrime/securesms/conversation/v2/ConversationViewModelTest.kt @@ -3,14 +3,12 @@ package org.thoughtcrime.securesms.conversation.v2 import com.goterl.lazysodium.utils.KeyPair import kotlinx.coroutines.flow.emptyFlow import kotlinx.coroutines.flow.first -import kotlinx.coroutines.runBlocking import org.hamcrest.CoreMatchers.endsWith import org.hamcrest.CoreMatchers.equalTo import org.hamcrest.CoreMatchers.notNullValue import org.hamcrest.CoreMatchers.nullValue import org.hamcrest.MatcherAssert.assertThat import org.junit.Before -import org.junit.BeforeClass import org.junit.Test import org.mockito.Mockito import org.mockito.Mockito.anyLong @@ -20,14 +18,11 @@ import org.mockito.kotlin.any import org.mockito.kotlin.mock import org.mockito.kotlin.whenever import org.session.libsession.utilities.recipients.Recipient -import org.session.libsignal.utilities.Log import org.thoughtcrime.securesms.BaseViewModelTest -import org.thoughtcrime.securesms.NoOpLogger import org.thoughtcrime.securesms.database.MmsDatabase import org.thoughtcrime.securesms.database.Storage import org.thoughtcrime.securesms.database.model.MessageRecord import org.thoughtcrime.securesms.repository.ConversationRepository -import org.thoughtcrime.securesms.repository.ResultOf class ConversationViewModelTest: BaseViewModelTest() { @@ -107,7 +102,7 @@ class ConversationViewModelTest: BaseViewModelTest() { val message = mock() val error = Throwable() whenever(repository.deleteForEveryone(anyLong(), any(), any())) - .thenReturn(ResultOf.Failure(error)) + .thenReturn(Result.failure(error)) viewModel.deleteForEveryone(message) @@ -120,7 +115,7 @@ class ConversationViewModelTest: BaseViewModelTest() { val message = mock() val error = Throwable() whenever(repository.deleteMessageWithoutUnsendRequest(anyLong(), anySet())) - .thenReturn(ResultOf.Failure(error)) + .thenReturn(Result.failure(error)) viewModel.deleteMessagesWithoutUnsendRequest(setOf(message)) @@ -130,7 +125,7 @@ class ConversationViewModelTest: BaseViewModelTest() { @Test fun `should emit error message on ban user failure`() = runBlockingTest { val error = Throwable() - whenever(repository.banUser(anyLong(), any())).thenReturn(ResultOf.Failure(error)) + whenever(repository.banUser(anyLong(), any())).thenReturn(Result.failure(error)) viewModel.banUser(recipient) @@ -139,7 +134,7 @@ class ConversationViewModelTest: BaseViewModelTest() { @Test fun `should emit a message on ban user success`() = runBlockingTest { - whenever(repository.banUser(anyLong(), any())).thenReturn(ResultOf.Success(Unit)) + whenever(repository.banUser(anyLong(), any())).thenReturn(Result.success(Unit)) viewModel.banUser(recipient) @@ -152,7 +147,7 @@ class ConversationViewModelTest: BaseViewModelTest() { @Test fun `should emit error message on ban user and delete all failure`() = runBlockingTest { val error = Throwable() - whenever(repository.banAndDeleteAll(anyLong(), any())).thenReturn(ResultOf.Failure(error)) + whenever(repository.banAndDeleteAll(anyLong(), any())).thenReturn(Result.failure(error)) viewModel.banAndDeleteAll(messageRecord) @@ -161,7 +156,7 @@ class ConversationViewModelTest: BaseViewModelTest() { @Test fun `should emit a message on ban user and delete all success`() = runBlockingTest { - whenever(repository.banAndDeleteAll(anyLong(), any())).thenReturn(ResultOf.Success(Unit)) + whenever(repository.banAndDeleteAll(anyLong(), any())).thenReturn(Result.success(Unit)) viewModel.banAndDeleteAll(messageRecord) @@ -188,7 +183,7 @@ class ConversationViewModelTest: BaseViewModelTest() { @Test fun `should remove shown message`() = runBlockingTest { // Given that a message is generated - whenever(repository.banUser(anyLong(), any())).thenReturn(ResultOf.Success(Unit)) + whenever(repository.banUser(anyLong(), any())).thenReturn(Result.success(Unit)) viewModel.banUser(recipient) assertThat(viewModel.uiState.value.uiMessages.size, equalTo(1)) // When the message is shown