From 3114c26fc8768d3b54ce3ff91994b967f05496b1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 26 Sep 2023 11:49:04 +0200 Subject: [PATCH 1/3] chore(deps): bump amannn/action-semantic-pull-request from 5.2.0 to 5.3.0 (#2271) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/semantic-commit-lint.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/semantic-commit-lint.yml b/.github/workflows/semantic-commit-lint.yml index 350eb46d0be..606f95a45c2 100644 --- a/.github/workflows/semantic-commit-lint.yml +++ b/.github/workflows/semantic-commit-lint.yml @@ -15,7 +15,7 @@ jobs: # Please look up the latest version from # https://github.com/amannn/action-semantic-pull-request/releases - name: Run Semantic Commint Linter - uses: amannn/action-semantic-pull-request@v5.2.0 + uses: amannn/action-semantic-pull-request@v5.3.0 with: # Configure which types are allowed. # Default: https://github.com/commitizen/conventional-commit-types From 68655d0d03270070bfd649324ecac71f8ad01ee0 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 26 Sep 2023 10:55:12 +0000 Subject: [PATCH 2/3] fix: ignore mention with negative index [WPB-4854] (#2272) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jakub Żerko Co-authored-by: Tommaso Piazza <196761+tmspzz@users.noreply.github.com> --- .../home/conversations/model/MessageTypes.kt | 23 +++-- .../conversations/model/MessageTypesTest.kt | 96 +++++++++++++++++++ 2 files changed, 109 insertions(+), 10 deletions(-) create mode 100644 app/src/test/kotlin/com/wire/android/ui/home/conversations/model/MessageTypesTest.kt diff --git a/app/src/main/kotlin/com/wire/android/ui/home/conversations/model/MessageTypes.kt b/app/src/main/kotlin/com/wire/android/ui/home/conversations/model/MessageTypes.kt index da8b392a4ef..79a4c009b10 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/conversations/model/MessageTypes.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/conversations/model/MessageTypes.kt @@ -233,20 +233,23 @@ internal fun MessageGenericAsset( * @param resources: Resources - To be able to get String out of UIText message * @return Pair, String> */ -private fun mapToDisplayMentions(uiText: UIText, resources: Resources): Pair, String> { +fun mapToDisplayMentions(uiText: UIText, resources: Resources): Pair, String> { return if (uiText is UIText.DynamicString) { val stringBuilder: StringBuilder = StringBuilder(uiText.value) - val mentions = uiText.mentions.sortedBy { it.start }.reversed() - val mentionList = mentions.mapNotNull { + val mentions = uiText.mentions + .filter { it.start >= 0 && it.length > 0 } + .sortedBy { it.start } + .reversed() + val mentionList = mentions.mapNotNull { mention -> // secured crash for mentions caused by web when text without mentions contains mention data - if (it.start + it.length <= uiText.value.length && uiText.value.elementAt(it.start) == '@') { - val mentionName = uiText.value.substring(it.start, it.start + it.length) - stringBuilder.insert(it.start + it.length, MENTION_MARK) - stringBuilder.insert(it.start, MENTION_MARK) + if (mention.start + mention.length <= uiText.value.length && uiText.value.elementAt(mention.start) == '@') { + val mentionName = uiText.value.substring(mention.start, mention.start + mention.length) + stringBuilder.insert(mention.start + mention.length, MENTION_MARK) + stringBuilder.insert(mention.start, MENTION_MARK) DisplayMention( - it.userId, - it.length, - it.isSelfMention, + mention.userId, + mention.length, + mention.isSelfMention, mentionName ) } else { diff --git a/app/src/test/kotlin/com/wire/android/ui/home/conversations/model/MessageTypesTest.kt b/app/src/test/kotlin/com/wire/android/ui/home/conversations/model/MessageTypesTest.kt new file mode 100644 index 00000000000..f56e3b25ad0 --- /dev/null +++ b/app/src/test/kotlin/com/wire/android/ui/home/conversations/model/MessageTypesTest.kt @@ -0,0 +1,96 @@ +/* + * Wire + * Copyright (C) 2023 Wire Swiss GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + */ +package com.wire.android.ui.home.conversations.model + +import android.content.res.Resources +import com.wire.android.framework.TestUser +import com.wire.android.ui.markdown.MarkdownConstants +import com.wire.android.util.ui.UIText +import com.wire.kalium.logic.data.message.mention.MessageMention +import io.mockk.MockKAnnotations +import io.mockk.every +import io.mockk.impl.annotations.MockK +import org.amshove.kluent.internal.assertEquals +import org.junit.jupiter.api.Assertions.assertTrue +import org.junit.jupiter.api.Test + +class MessageTypesTest { + + @MockK + lateinit var mockResources: Resources + + init { + MockKAnnotations.init(this, relaxUnitFun = true) + + every { mockResources.getString(any()) } returns "mockedString" + } + + @Test + fun `Given message with no mentions when mapping then no mentions should be returned`() { + val uiText = UIText.DynamicString("Hello world") + val result = mapToDisplayMentions(uiText, mockResources) + assertTrue(result.first.isEmpty()) + assertEquals("Hello world", result.second) + } + + @Test + fun `Given message with a valid mention when mapping then the mention should be returned with markers`() { + val mention = MessageMention(0, 6, TestUser.USER_ID, isSelfMention = false) + val uiText = UIText.DynamicString("@Hello world", listOf(mention)) + val result = mapToDisplayMentions(uiText, mockResources) + assertEquals(1, result.first.size) + assertEquals("@Hello", result.first.first().mentionUserName) + assertEquals("${MarkdownConstants.MENTION_MARK}@Hello${MarkdownConstants.MENTION_MARK} world", result.second) + } + + @Test + fun `Given message with a negative start mention when mapping then no mentions should be returned`() { + val mention = MessageMention(-1, 5, TestUser.USER_ID, isSelfMention = false) + val uiText = UIText.DynamicString("Hello world", listOf(mention)) + val result = mapToDisplayMentions(uiText, mockResources) + assertTrue(result.first.isEmpty()) + assertEquals("Hello world", result.second) + } + + @Test + fun `Given message with a mention exceeding string length when mapping then no mentions should be returned`() { + val mention = MessageMention(10, 20, TestUser.USER_ID, isSelfMention = false) + val uiText = UIText.DynamicString("Hello world", listOf(mention)) + val result = mapToDisplayMentions(uiText, mockResources) + assertTrue(result.first.isEmpty()) + assertEquals("Hello world", result.second) + } + + @Test + fun `Given message where mention's start position doesn't have '@' character when mapping then no mentions should be returned`() { + val mention = MessageMention(6, 5, TestUser.USER_ID, isSelfMention = false) + val uiText = UIText.DynamicString("Hello world", listOf(mention)) + val result = mapToDisplayMentions(uiText, mockResources) + assertTrue(result.first.isEmpty()) + assertEquals("Hello world", result.second) + } + + @Test + fun `Given message with multiple mentions when mapping then only valid mentions should be returned`() { + val validMention = MessageMention(6, 5, TestUser.USER_ID, isSelfMention = false) + val invalidMention = MessageMention(50, 5, TestUser.OTHER_USER.id, isSelfMention = false) + val uiText = UIText.DynamicString("Hello @world", listOf(validMention, invalidMention)) + val result = mapToDisplayMentions(uiText, mockResources) + assertEquals(1, result.first.size) + } +} From 596009fd135b0e1055663b5da200278d00bd894c Mon Sep 17 00:00:00 2001 From: Gonzo Date: Tue, 26 Sep 2023 13:36:01 +0200 Subject: [PATCH 3/3] feat: Adding option on bottom sheet to archive use cases (#2262) --- .../di/accountScoped/ConversationModule.kt | 6 ++ .../conversation/ConversationSheetContent.kt | 4 +- .../conversation/HomeSheetContent.kt | 36 ++++---- .../com/wire/android/ui/home/HomeScreen.kt | 3 + .../wire/android/ui/home/HomeSnackbarState.kt | 2 + .../details/GroupConversationDetailsScreen.kt | 22 +++-- .../GroupConversationDetailsViewModel.kt | 21 ++++- ...ersationDetailsBottomSheetEventsHandler.kt | 22 ++++- .../ConversationListViewModel.kt | 30 +++++-- .../conversationslist/ConversationRouter.kt | 8 +- .../ImportMediaAuthenticatedViewModel.kt | 2 +- .../other/OtherUserProfileEventsHandlers.kt | 4 +- .../other/OtherUserProfileInfoMessageType.kt | 6 +- .../other/OtherUserProfileScreenViewModel.kt | 20 ++++- .../OtherUserProfileBottomSheet.kt | 2 +- app/src/main/res/values/strings.xml | 2 + .../GroupConversationDetailsViewModelTest.kt | 84 +++++++++++++++++++ .../ConversationListViewModelTest.kt | 40 ++++++++- .../OtherUserProfileViewModelArrangement.kt | 7 ++ kalium | 2 +- 20 files changed, 276 insertions(+), 47 deletions(-) diff --git a/app/src/main/kotlin/com/wire/android/di/accountScoped/ConversationModule.kt b/app/src/main/kotlin/com/wire/android/di/accountScoped/ConversationModule.kt index f5b53dfec95..9ad64cdad76 100644 --- a/app/src/main/kotlin/com/wire/android/di/accountScoped/ConversationModule.kt +++ b/app/src/main/kotlin/com/wire/android/di/accountScoped/ConversationModule.kt @@ -42,6 +42,7 @@ import com.wire.kalium.logic.feature.conversation.RefreshConversationsWithoutMet import com.wire.kalium.logic.feature.conversation.RemoveMemberFromConversationUseCase import com.wire.kalium.logic.feature.conversation.RenameConversationUseCase import com.wire.kalium.logic.feature.conversation.UpdateConversationAccessRoleUseCase +import com.wire.kalium.logic.feature.conversation.UpdateConversationArchivedStatusUseCase import com.wire.kalium.logic.feature.conversation.UpdateConversationMutedStatusUseCase import com.wire.kalium.logic.feature.conversation.UpdateConversationReadDateUseCase import com.wire.kalium.logic.feature.conversation.UpdateConversationReceiptModeUseCase @@ -216,4 +217,9 @@ class ConversationModule { @Provides fun provideClearConversationContentUseCase(conversationScope: ConversationScope): ClearConversationContentUseCase = conversationScope.clearConversationContent + + @ViewModelScoped + @Provides + fun provideUpdateConversationArchivedStatusUseCase(conversationScope: ConversationScope): UpdateConversationArchivedStatusUseCase = + conversationScope.updateConversationArchivedStatus } diff --git a/app/src/main/kotlin/com/wire/android/ui/common/bottomsheet/conversation/ConversationSheetContent.kt b/app/src/main/kotlin/com/wire/android/ui/common/bottomsheet/conversation/ConversationSheetContent.kt index 21c9a8eeda0..f268710d81b 100644 --- a/app/src/main/kotlin/com/wire/android/ui/common/bottomsheet/conversation/ConversationSheetContent.kt +++ b/app/src/main/kotlin/com/wire/android/ui/common/bottomsheet/conversation/ConversationSheetContent.kt @@ -41,7 +41,7 @@ fun ConversationSheetContent( onMutingConversationStatusChange: () -> Unit, addConversationToFavourites: () -> Unit, moveConversationToFolder: () -> Unit, - moveConversationToArchive: () -> Unit, + moveConversationToArchive: (DialogState) -> Unit, clearConversationContent: (DialogState) -> Unit, blockUser: (BlockUserDialogState) -> Unit, unblockUser: (UnblockUserDialogState) -> Unit, @@ -61,7 +61,7 @@ fun ConversationSheetContent( // // addConversationToFavourites = addConversationToFavourites, // moveConversationToFolder = moveConversationToFolder, -// moveConversationToArchive = moveConversationToArchive, + moveConversationToArchive = moveConversationToArchive, clearConversationContent = clearConversationContent, blockUserClick = blockUser, unblockUserClick = unblockUser, diff --git a/app/src/main/kotlin/com/wire/android/ui/common/bottomsheet/conversation/HomeSheetContent.kt b/app/src/main/kotlin/com/wire/android/ui/common/bottomsheet/conversation/HomeSheetContent.kt index ae20cfd006b..b2f5e9562cc 100644 --- a/app/src/main/kotlin/com/wire/android/ui/common/bottomsheet/conversation/HomeSheetContent.kt +++ b/app/src/main/kotlin/com/wire/android/ui/common/bottomsheet/conversation/HomeSheetContent.kt @@ -58,10 +58,9 @@ import com.wire.kalium.logic.data.user.ConnectionState internal fun ConversationMainSheetContent( conversationSheetContent: ConversationSheetContent, // TODO(profile): enable when implemented -// // addConversationToFavourites: () -> Unit, // moveConversationToFolder: () -> Unit, -// moveConversationToArchive: () -> Unit, + moveConversationToArchive: (DialogState) -> Unit, clearConversationContent: (DialogState) -> Unit, blockUserClick: (BlockUserDialogState) -> Unit, unblockUserClick: (UnblockUserDialogState) -> Unit, @@ -135,18 +134,27 @@ internal fun ConversationMainSheetContent( // onItemClick = moveConversationToFolder // ) // } -// add { -// MenuBottomSheetItem( -// icon = { -// MenuItemIcon( -// id = R.drawable.ic_archive, -// contentDescription = stringResource(R.string.content_description_move_to_archive), -// ) -// }, -// title = stringResource(R.string.label_move_to_archive), -// onItemClick = moveConversationToArchive -// ) -// } + add { + MenuBottomSheetItem( + icon = { + MenuItemIcon( + id = R.drawable.ic_archive, + contentDescription = stringResource(R.string.content_description_move_to_archive), + ) + }, + title = stringResource(R.string.label_move_to_archive), + onItemClick = { + with(conversationSheetContent) { + moveConversationToArchive( + DialogState( + conversationId, + title, + conversationTypeDetail + ) + ) + } + }) + } add { MenuBottomSheetItem( icon = { diff --git a/app/src/main/kotlin/com/wire/android/ui/home/HomeScreen.kt b/app/src/main/kotlin/com/wire/android/ui/home/HomeScreen.kt index a3937541753..fa2c4ce80d0 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/HomeScreen.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/HomeScreen.kt @@ -362,6 +362,9 @@ private fun handleSnackBarMessage( is HomeSnackbarState.ClearConversationContentSuccess -> stringResource( if (messageType.isGroup) R.string.group_content_deleted else R.string.conversation_content_deleted ) + + HomeSnackbarState.ArchivingConversationError -> stringResource(id = R.string.error_archiving_conversation) + HomeSnackbarState.ArchivingConversationSuccess -> stringResource(id = R.string.success_archiving_conversation) } LaunchedEffect(messageType) { diff --git a/app/src/main/kotlin/com/wire/android/ui/home/HomeSnackbarState.kt b/app/src/main/kotlin/com/wire/android/ui/home/HomeSnackbarState.kt index c94adf91293..15ccf7e134d 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/HomeSnackbarState.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/HomeSnackbarState.kt @@ -35,4 +35,6 @@ sealed class HomeSnackbarState { object DeleteConversationGroupError : HomeSnackbarState() object LeftConversationSuccess : HomeSnackbarState() object LeaveConversationError : HomeSnackbarState() + object ArchivingConversationSuccess : HomeSnackbarState() + object ArchivingConversationError : HomeSnackbarState() } diff --git a/app/src/main/kotlin/com/wire/android/ui/home/conversations/details/GroupConversationDetailsScreen.kt b/app/src/main/kotlin/com/wire/android/ui/home/conversations/details/GroupConversationDetailsScreen.kt index 2772040cc3e..6b0b6d5e0e1 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/conversations/details/GroupConversationDetailsScreen.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/conversations/details/GroupConversationDetailsScreen.kt @@ -350,15 +350,25 @@ private fun GroupConversationDetailsContent( isBottomSheetVisible = getBottomSheetVisibility, conversationSheetState = conversationSheetState, onMutingConversationStatusChange = { - bottomSheetEventsHandler.onMutingConversationStatusChange( - conversationSheetState.conversationId, - conversationSheetState.conversationSheetContent!!.mutingConversationState, - closeBottomSheetAndShowSnackbarMessage - ) + conversationSheetContent?.let { + bottomSheetEventsHandler.onMutingConversationStatusChange( + conversationSheetState.conversationId, + it.mutingConversationState, + closeBottomSheetAndShowSnackbarMessage + ) + } }, addConversationToFavourites = bottomSheetEventsHandler::onAddConversationToFavourites, moveConversationToFolder = bottomSheetEventsHandler::onMoveConversationToFolder, - moveConversationToArchive = bottomSheetEventsHandler::onMoveConversationToArchive, + moveConversationToArchive = { + conversationSheetContent?.let { + bottomSheetEventsHandler.onMoveConversationToArchive( + conversationId = it.conversationId, + shouldArchive = true, + onMessage = closeBottomSheetAndShowSnackbarMessage + ) + } + }, clearConversationContent = clearConversationDialogState::show, blockUser = {}, unblockUser = {}, diff --git a/app/src/main/kotlin/com/wire/android/ui/home/conversations/details/GroupConversationDetailsViewModel.kt b/app/src/main/kotlin/com/wire/android/ui/home/conversations/details/GroupConversationDetailsViewModel.kt index afdfdff645d..44c29dbd7da 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/conversations/details/GroupConversationDetailsViewModel.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/conversations/details/GroupConversationDetailsViewModel.kt @@ -45,12 +45,14 @@ import com.wire.kalium.logic.data.conversation.ConversationDetails import com.wire.kalium.logic.data.conversation.MutedConversationStatus import com.wire.kalium.logic.data.id.ConversationId import com.wire.kalium.logic.data.id.QualifiedID +import com.wire.kalium.logic.feature.conversation.ArchiveStatusUpdateResult import com.wire.kalium.logic.feature.conversation.ClearConversationContentUseCase import com.wire.kalium.logic.feature.conversation.ConversationUpdateReceiptModeResult import com.wire.kalium.logic.feature.conversation.ConversationUpdateStatusResult import com.wire.kalium.logic.feature.conversation.ObserveConversationDetailsUseCase import com.wire.kalium.logic.feature.conversation.RemoveMemberFromConversationUseCase import com.wire.kalium.logic.feature.conversation.UpdateConversationAccessRoleUseCase +import com.wire.kalium.logic.feature.conversation.UpdateConversationArchivedStatusUseCase import com.wire.kalium.logic.feature.conversation.UpdateConversationMutedStatusUseCase import com.wire.kalium.logic.feature.conversation.UpdateConversationReceiptModeUseCase import com.wire.kalium.logic.feature.publicuser.RefreshUsersWithoutMetadataUseCase @@ -91,6 +93,7 @@ class GroupConversationDetailsViewModel @Inject constructor( private val clearConversationContent: ClearConversationContentUseCase, private val updateConversationReceiptMode: UpdateConversationReceiptModeUseCase, private val observeSelfDeletionTimerSettingsForConversation: ObserveSelfDeletionTimerSettingsForConversationUseCase, + private val updateConversationArchivedStatus: UpdateConversationArchivedStatusUseCase, override val savedStateHandle: SavedStateHandle, private val isMLSEnabled: IsMLSEnabledUseCase, refreshUsersWithoutMetadata: RefreshUsersWithoutMetadataUseCase, @@ -375,8 +378,22 @@ class GroupConversationDetailsViewModel @Inject constructor( override fun onMoveConversationToFolder(conversationId: ConversationId?) { } - @Suppress("EmptyFunctionBlock") - override fun onMoveConversationToArchive(conversationId: ConversationId?) { + override fun onMoveConversationToArchive( + conversationId: ConversationId, + shouldArchive: Boolean, + timestamp: Long, + onMessage: (UIText) -> Unit + ) { + viewModelScope.launch { + requestInProgress = true + val result = + withContext(dispatcher.io()) { updateConversationArchivedStatus(conversationId, shouldArchive, timestamp) } + requestInProgress = false + when (result) { + ArchiveStatusUpdateResult.Failure -> onMessage(UIText.StringResource(R.string.error_archiving_conversation)) + ArchiveStatusUpdateResult.Success -> onMessage(UIText.StringResource(R.string.success_archiving_conversation)) + } + } } companion object { diff --git a/app/src/main/kotlin/com/wire/android/ui/home/conversations/details/menu/GroupConversationDetailsBottomSheetEventsHandler.kt b/app/src/main/kotlin/com/wire/android/ui/home/conversations/details/menu/GroupConversationDetailsBottomSheetEventsHandler.kt index 928bba67336..25c8465d323 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/conversations/details/menu/GroupConversationDetailsBottomSheetEventsHandler.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/conversations/details/menu/GroupConversationDetailsBottomSheetEventsHandler.kt @@ -24,13 +24,20 @@ import com.wire.android.ui.home.conversationslist.model.DialogState import com.wire.android.util.ui.UIText import com.wire.kalium.logic.data.conversation.MutedConversationStatus import com.wire.kalium.logic.data.id.ConversationId +import com.wire.kalium.util.DateTimeUtil @Suppress("TooManyFunctions") interface GroupConversationDetailsBottomSheetEventsHandler { fun onMutingConversationStatusChange(conversationId: ConversationId?, status: MutedConversationStatus, onMessage: (UIText) -> Unit) fun onAddConversationToFavourites(conversationId: ConversationId? = null) fun onMoveConversationToFolder(conversationId: ConversationId? = null) - fun onMoveConversationToArchive(conversationId: ConversationId? = null) + fun onMoveConversationToArchive( + conversationId: ConversationId, + shouldArchive: Boolean, + timestamp: Long = DateTimeUtil.currentInstant().toEpochMilliseconds(), + onMessage: (UIText) -> Unit + ) + fun onClearConversationContent(dialogState: DialogState, onMessage: (UIText) -> Unit) companion object { @@ -40,10 +47,19 @@ interface GroupConversationDetailsBottomSheetEventsHandler { conversationId: ConversationId?, status: MutedConversationStatus, onMessage: (UIText) -> Unit - ) {} + ) { + } + override fun onAddConversationToFavourites(conversationId: ConversationId?) {} override fun onMoveConversationToFolder(conversationId: ConversationId?) {} - override fun onMoveConversationToArchive(conversationId: ConversationId?) {} + override fun onMoveConversationToArchive( + conversationId: ConversationId, + shouldArchive: Boolean, + timestamp: Long, + onMessage: (UIText) -> Unit + ) { + } + override fun onClearConversationContent(dialogState: DialogState, onMessage: (UIText) -> Unit) {} } } diff --git a/app/src/main/kotlin/com/wire/android/ui/home/conversationslist/ConversationListViewModel.kt b/app/src/main/kotlin/com/wire/android/ui/home/conversationslist/ConversationListViewModel.kt index da76577eb6b..fde5aca9bd4 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/conversationslist/ConversationListViewModel.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/conversationslist/ConversationListViewModel.kt @@ -66,17 +66,20 @@ import com.wire.kalium.logic.feature.connection.BlockUserResult import com.wire.kalium.logic.feature.connection.BlockUserUseCase import com.wire.kalium.logic.feature.connection.UnblockUserResult import com.wire.kalium.logic.feature.connection.UnblockUserUseCase +import com.wire.kalium.logic.feature.conversation.ArchiveStatusUpdateResult import com.wire.kalium.logic.feature.conversation.ClearConversationContentUseCase import com.wire.kalium.logic.feature.conversation.ConversationUpdateStatusResult import com.wire.kalium.logic.feature.conversation.LeaveConversationUseCase import com.wire.kalium.logic.feature.conversation.ObserveConversationListDetailsUseCase import com.wire.kalium.logic.feature.conversation.RefreshConversationsWithoutMetadataUseCase import com.wire.kalium.logic.feature.conversation.RemoveMemberFromConversationUseCase +import com.wire.kalium.logic.feature.conversation.UpdateConversationArchivedStatusUseCase import com.wire.kalium.logic.feature.conversation.UpdateConversationMutedStatusUseCase import com.wire.kalium.logic.feature.publicuser.RefreshUsersWithoutMetadataUseCase import com.wire.kalium.logic.feature.team.DeleteTeamConversationUseCase import com.wire.kalium.logic.feature.team.Result import com.wire.kalium.logic.functional.combine +import com.wire.kalium.util.DateTimeUtil import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.collections.immutable.toImmutableMap import kotlinx.coroutines.delay @@ -108,7 +111,8 @@ class ConversationListViewModel @Inject constructor( private val userTypeMapper: UserTypeMapper, private val endCall: EndCallUseCase, private val refreshUsersWithoutMetadata: RefreshUsersWithoutMetadataUseCase, - private val refreshConversationsWithoutMetadata: RefreshConversationsWithoutMetadataUseCase + private val refreshConversationsWithoutMetadata: RefreshConversationsWithoutMetadataUseCase, + private val updateConversationArchivedStatus: UpdateConversationArchivedStatusUseCase, ) : ViewModel() { var conversationListState by mutableStateOf(ConversationListState()) @@ -148,7 +152,7 @@ class ConversationListViewModel @Inject constructor( } viewModelScope.launch { searchQueryFlow.combine( - observeConversationListDetails() + observeConversationListDetails(includeArchived = false) .map { it.map { conversationDetails -> conversationDetails.toConversationItem( @@ -417,9 +421,25 @@ class ConversationListViewModel @Inject constructor( fun moveConversationToFolder(id: String = "") { } - // TODO: needs to be implemented - @Suppress("EmptyFunctionBlock") - fun moveConversationToArchive(id: String = "") { + fun moveConversationToArchive( + conversationId: ConversationId, + isArchiving: Boolean, + timestamp: Long = DateTimeUtil.currentInstant().toEpochMilliseconds() + ) { + viewModelScope.launch { + requestInProgress = true + val result = withContext(dispatcher.io()) { updateConversationArchivedStatus(conversationId, isArchiving, timestamp) } + requestInProgress = false + when (result) { + is ArchiveStatusUpdateResult.Failure -> { + homeSnackBarState.emit(HomeSnackbarState.ArchivingConversationError) + } + + is ArchiveStatusUpdateResult.Success -> { + homeSnackBarState.emit(HomeSnackbarState.ArchivingConversationSuccess) + } + } + } } fun clearConversationContent(dialogState: DialogState) { diff --git a/app/src/main/kotlin/com/wire/android/ui/home/conversationslist/ConversationRouter.kt b/app/src/main/kotlin/com/wire/android/ui/home/conversationslist/ConversationRouter.kt index 1f8010ef5d6..b9870c88202 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/conversationslist/ConversationRouter.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/conversationslist/ConversationRouter.kt @@ -149,7 +149,13 @@ fun ConversationRouterHomeBridge( }, addConversationToFavourites = viewModel::addConversationToFavourites, moveConversationToFolder = viewModel::moveConversationToFolder, - moveConversationToArchive = viewModel::moveConversationToArchive, + moveConversationToArchive = { + viewModel.moveConversationToArchive( + conversationId = it.conversationId, + isArchiving = true // All conversations at this point are not archived + ) + onCloseBottomSheet() + }, clearConversationContent = clearContentDialogState::show, blockUser = blockUserDialogState::show, unblockUser = unblockUserDialogState::show, diff --git a/app/src/main/kotlin/com/wire/android/ui/sharing/ImportMediaAuthenticatedViewModel.kt b/app/src/main/kotlin/com/wire/android/ui/sharing/ImportMediaAuthenticatedViewModel.kt index e902fa38bdf..68183813bcc 100644 --- a/app/src/main/kotlin/com/wire/android/ui/sharing/ImportMediaAuthenticatedViewModel.kt +++ b/app/src/main/kotlin/com/wire/android/ui/sharing/ImportMediaAuthenticatedViewModel.kt @@ -119,7 +119,7 @@ class ImportMediaAuthenticatedViewModel @Inject constructor( @OptIn(ExperimentalCoroutinesApi::class) private suspend fun observeConversationWithSearch() = viewModelScope.launch { searchQueryFlow.mapLatest { searchQuery -> - val conversations = observeConversationListDetails().first() + val conversations = observeConversationListDetails(includeArchived = false).first() .mapNotNull { conversationDetails -> conversationDetails.toConversationItem( wireSessionImageLoader, diff --git a/app/src/main/kotlin/com/wire/android/ui/userprofile/other/OtherUserProfileEventsHandlers.kt b/app/src/main/kotlin/com/wire/android/ui/userprofile/other/OtherUserProfileEventsHandlers.kt index 9b4473edef3..67ad451915d 100644 --- a/app/src/main/kotlin/com/wire/android/ui/userprofile/other/OtherUserProfileEventsHandlers.kt +++ b/app/src/main/kotlin/com/wire/android/ui/userprofile/other/OtherUserProfileEventsHandlers.kt @@ -71,7 +71,7 @@ interface OtherUserProfileBottomSheetEventsHandler { fun onMutingConversationStatusChange(conversationId: ConversationId?, status: MutedConversationStatus) fun onAddConversationToFavourites(conversationId: ConversationId? = null) fun onMoveConversationToFolder(conversationId: ConversationId? = null) - fun onMoveConversationToArchive(conversationId: ConversationId? = null) + fun onMoveConversationToArchive(conversationId: ConversationId, shouldArchiveConversation: Boolean) fun onClearConversationContent(dialogState: DialogState) companion object { @@ -81,7 +81,7 @@ interface OtherUserProfileBottomSheetEventsHandler { override fun onMutingConversationStatusChange(conversationId: ConversationId?, status: MutedConversationStatus) {} override fun onAddConversationToFavourites(conversationId: ConversationId?) {} override fun onMoveConversationToFolder(conversationId: ConversationId?) {} - override fun onMoveConversationToArchive(conversationId: ConversationId?) {} + override fun onMoveConversationToArchive(conversationId: ConversationId, shouldArchiveConversation: Boolean) {} override fun onClearConversationContent(dialogState: DialogState) {} } } diff --git a/app/src/main/kotlin/com/wire/android/ui/userprofile/other/OtherUserProfileInfoMessageType.kt b/app/src/main/kotlin/com/wire/android/ui/userprofile/other/OtherUserProfileInfoMessageType.kt index ff82d061134..3c2348d3edf 100644 --- a/app/src/main/kotlin/com/wire/android/ui/userprofile/other/OtherUserProfileInfoMessageType.kt +++ b/app/src/main/kotlin/com/wire/android/ui/userprofile/other/OtherUserProfileInfoMessageType.kt @@ -50,12 +50,12 @@ sealed class OtherUserProfileInfoMessageType(override val uiText: UIText) : Snac OtherUserProfileInfoMessageType(UIText.StringResource(R.string.blocking_user_success, name)) object MutingOperationError : OtherUserProfileInfoMessageType(UIText.StringResource(R.string.error_updating_muting_setting)) - object UnblockingUserOperationError : OtherUserProfileInfoMessageType(UIText.StringResource(R.string.error_unblocking_user)) - object ConversationContentDeleted : OtherUserProfileInfoMessageType(UIText.StringResource(R.string.conversation_content_deleted)) - object ConversationContentDeleteFailure : OtherUserProfileInfoMessageType(UIText.StringResource(R.string.conversation_content_delete_failure)) + object ArchiveConversationError : OtherUserProfileInfoMessageType(UIText.StringResource(R.string.error_archiving_conversation)) + object ArchiveConversationSuccess : OtherUserProfileInfoMessageType(UIText.StringResource(R.string.success_archiving_conversation)) + } diff --git a/app/src/main/kotlin/com/wire/android/ui/userprofile/other/OtherUserProfileScreenViewModel.kt b/app/src/main/kotlin/com/wire/android/ui/userprofile/other/OtherUserProfileScreenViewModel.kt index d58439fe151..33a27987c69 100644 --- a/app/src/main/kotlin/com/wire/android/ui/userprofile/other/OtherUserProfileScreenViewModel.kt +++ b/app/src/main/kotlin/com/wire/android/ui/userprofile/other/OtherUserProfileScreenViewModel.kt @@ -61,10 +61,12 @@ import com.wire.kalium.logic.feature.connection.BlockUserResult import com.wire.kalium.logic.feature.connection.BlockUserUseCase import com.wire.kalium.logic.feature.connection.UnblockUserResult import com.wire.kalium.logic.feature.connection.UnblockUserUseCase +import com.wire.kalium.logic.feature.conversation.ArchiveStatusUpdateResult import com.wire.kalium.logic.feature.conversation.ClearConversationContentUseCase import com.wire.kalium.logic.feature.conversation.ConversationUpdateStatusResult import com.wire.kalium.logic.feature.conversation.GetOneToOneConversationUseCase import com.wire.kalium.logic.feature.conversation.RemoveMemberFromConversationUseCase +import com.wire.kalium.logic.feature.conversation.UpdateConversationArchivedStatusUseCase import com.wire.kalium.logic.feature.conversation.UpdateConversationMemberRoleResult import com.wire.kalium.logic.feature.conversation.UpdateConversationMemberRoleUseCase import com.wire.kalium.logic.feature.conversation.UpdateConversationMutedStatusUseCase @@ -100,6 +102,7 @@ class OtherUserProfileScreenViewModel @Inject constructor( private val observeClientList: ObserveClientsByUserIdUseCase, private val persistOtherUserClients: PersistOtherUserClientsUseCase, private val clearConversationContentUseCase: ClearConversationContentUseCase, + private val updateConversationArchivedStatus: UpdateConversationArchivedStatusUseCase, savedStateHandle: SavedStateHandle ) : ViewModel(), OtherUserProfileEventsHandler, OtherUserProfileBottomSheetEventsHandler { @@ -292,8 +295,21 @@ class OtherUserProfileScreenViewModel @Inject constructor( override fun onMoveConversationToFolder(conversationId: ConversationId?) { } - @Suppress("EmptyFunctionBlock") - override fun onMoveConversationToArchive(conversationId: ConversationId?) { + override fun onMoveConversationToArchive(conversationId: ConversationId, shouldArchiveConversation: Boolean) { + viewModelScope.launch { + requestInProgress = true + val result = withContext(dispatchers.io()) { updateConversationArchivedStatus(conversationId, shouldArchiveConversation) } + requestInProgress = false + when (result) { + ArchiveStatusUpdateResult.Failure -> { + closeBottomSheetAndShowInfoMessage(OtherUserProfileInfoMessageType.ArchiveConversationError) + } + + ArchiveStatusUpdateResult.Success -> { + closeBottomSheetAndShowInfoMessage(OtherUserProfileInfoMessageType.ArchiveConversationSuccess) + } + } + } } override fun onClearConversationContent(dialogState: DialogState) { diff --git a/app/src/main/kotlin/com/wire/android/ui/userprofile/other/bottomsheet/OtherUserProfileBottomSheet.kt b/app/src/main/kotlin/com/wire/android/ui/userprofile/other/bottomsheet/OtherUserProfileBottomSheet.kt index 109956057fb..293ff54525b 100644 --- a/app/src/main/kotlin/com/wire/android/ui/userprofile/other/bottomsheet/OtherUserProfileBottomSheet.kt +++ b/app/src/main/kotlin/com/wire/android/ui/userprofile/other/bottomsheet/OtherUserProfileBottomSheet.kt @@ -53,7 +53,7 @@ fun OtherUserProfileBottomSheetContent( }, addConversationToFavourites = eventsHandler::onAddConversationToFavourites, moveConversationToFolder = eventsHandler::onMoveConversationToFolder, - moveConversationToArchive = eventsHandler::onMoveConversationToArchive, + moveConversationToArchive = { eventsHandler.onMoveConversationToArchive(it.conversationId, true) }, clearConversationContent = clearContent, blockUser = blockUser, unblockUser = unblockUser, diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index e8ea877302e..bc70bf6995e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -714,6 +714,8 @@ User could not be unblocked There was an error while deleting conversation You can only send up to 20 files at once + Conversation was archived + Conversation could not be archived MessageComposeInputState transition Collapse button rotation degree transition diff --git a/app/src/test/kotlin/com/wire/android/ui/home/conversations/details/GroupConversationDetailsViewModelTest.kt b/app/src/test/kotlin/com/wire/android/ui/home/conversations/details/GroupConversationDetailsViewModelTest.kt index 024603d2a50..b8958f8ba77 100644 --- a/app/src/test/kotlin/com/wire/android/ui/home/conversations/details/GroupConversationDetailsViewModelTest.kt +++ b/app/src/test/kotlin/com/wire/android/ui/home/conversations/details/GroupConversationDetailsViewModelTest.kt @@ -39,12 +39,14 @@ import com.wire.kalium.logic.data.conversation.MutedConversationStatus import com.wire.kalium.logic.data.id.ConversationId import com.wire.kalium.logic.data.id.TeamId import com.wire.kalium.logic.data.team.Team +import com.wire.kalium.logic.feature.conversation.ArchiveStatusUpdateResult import com.wire.kalium.logic.feature.conversation.ClearConversationContentUseCase import com.wire.kalium.logic.feature.conversation.ConversationUpdateReceiptModeResult import com.wire.kalium.logic.feature.conversation.ConversationUpdateStatusResult import com.wire.kalium.logic.feature.conversation.ObserveConversationDetailsUseCase import com.wire.kalium.logic.feature.conversation.RemoveMemberFromConversationUseCase import com.wire.kalium.logic.feature.conversation.UpdateConversationAccessRoleUseCase +import com.wire.kalium.logic.feature.conversation.UpdateConversationArchivedStatusUseCase import com.wire.kalium.logic.feature.conversation.UpdateConversationMutedStatusUseCase import com.wire.kalium.logic.feature.conversation.UpdateConversationReceiptModeUseCase import com.wire.kalium.logic.feature.publicuser.RefreshUsersWithoutMetadataUseCase @@ -123,6 +125,78 @@ class GroupConversationDetailsViewModelTest { assertEquals(details2.conversation.name, viewModel.groupOptionsState.value.groupName) } + @Test + fun `given some conversation details, when archiving that conversation, then the use case is invoked`() = runTest { + // Given + val members = buildList { + for (i in 1..5) { + add(testUIParticipant(i)) + } + } + val archivingEventTimestamp = 123456789L + val conversationParticipantsData = ConversationParticipantsData( + participants = members.take(GroupConversationDetailsViewModel.MAX_NUMBER_OF_PARTICIPANTS), + allParticipantsCount = members.size + ) + + val conversationDetails = testGroup.copy(conversation = testGroup.conversation.copy(name = "Group name 1")) + val (arrangement, viewModel) = GroupConversationDetailsViewModelArrangement() + .withConversationDetailUpdate(conversationDetails) + .withConversationMembersUpdate(conversationParticipantsData) + .withUpdateArchivedStatus(ArchiveStatusUpdateResult.Success) + .arrange() + + // When + viewModel.onMoveConversationToArchive( + conversationId = viewModel.conversationId, + shouldArchive = true, + timestamp = archivingEventTimestamp + ) {} + + // Then + coVerify(exactly = 1) { + arrangement.updateConversationArchivedStatus( + conversationId = viewModel.conversationId, + shouldArchiveConversation = true, + archivedStatusTimestamp = archivingEventTimestamp + ) + } + } + + @Test + fun `given some conversation details, when un-archiving that conversation, then the use case is invoked`() = runTest { + // Given + val members = buildList { + for (i in 1..5) { + add(testUIParticipant(i)) + } + } + val archivingEventTimestamp = 123456789L + val conversationParticipantsData = ConversationParticipantsData( + participants = members.take(GroupConversationDetailsViewModel.MAX_NUMBER_OF_PARTICIPANTS), + allParticipantsCount = members.size + ) + + val conversationDetails = testGroup.copy(conversation = testGroup.conversation.copy(name = "Group name 1")) + val (arrangement, viewModel) = GroupConversationDetailsViewModelArrangement() + .withConversationDetailUpdate(conversationDetails) + .withConversationMembersUpdate(conversationParticipantsData) + .withUpdateArchivedStatus(ArchiveStatusUpdateResult.Success) + .arrange() + + // When + viewModel.onMoveConversationToArchive(viewModel.conversationId, false, archivingEventTimestamp) {} + + // Then + coVerify(exactly = 1) { + arrangement.updateConversationArchivedStatus( + conversationId = viewModel.conversationId, + shouldArchiveConversation = false, + archivedStatusTimestamp = archivingEventTimestamp + ) + } + } + @Test fun `given a group conversation, when solving the state, then the state is correct`() = runTest { // Given @@ -541,6 +615,9 @@ internal class GroupConversationDetailsViewModelArrangement { @MockK lateinit var observeSelfDeletionTimerSettingsForConversation: ObserveSelfDeletionTimerSettingsForConversationUseCase + @MockK + lateinit var updateConversationArchivedStatus: UpdateConversationArchivedStatusUseCase + private val conversationDetailsChannel = Channel(capacity = Channel.UNLIMITED) private val observeParticipantsForConversationChannel = Channel(capacity = Channel.UNLIMITED) @@ -565,6 +642,7 @@ internal class GroupConversationDetailsViewModelArrangement { isMLSEnabled = isMLSEnabledUseCase, observeSelfDeletionTimerSettingsForConversation = observeSelfDeletionTimerSettingsForConversation, refreshUsersWithoutMetadata = refreshUsersWithoutMetadata, + updateConversationArchivedStatus = updateConversationArchivedStatus ) } @@ -590,6 +668,7 @@ internal class GroupConversationDetailsViewModelArrangement { coEvery { isMLSEnabledUseCase() } returns true coEvery { updateConversationMutedStatus(any(), any(), any()) } returns ConversationUpdateStatusResult.Success coEvery { observeSelfDeletionTimerSettingsForConversation(any(), any()) } returns flowOf(SelfDeletionTimer.Disabled) + coEvery { updateConversationArchivedStatus(any(), any()) } returns ArchiveStatusUpdateResult.Success } suspend fun withConversationDetailUpdate(conversationDetails: ConversationDetails) = apply { @@ -615,5 +694,10 @@ internal class GroupConversationDetailsViewModelArrangement { coEvery { updateConversationReceiptMode(any(), any()) } returns ConversationUpdateReceiptModeResult.Success } + suspend fun withUpdateArchivedStatus(result: ArchiveStatusUpdateResult) = apply { + coEvery { updateConversationArchivedStatus(any(), any()) } returns result + coEvery { updateConversationArchivedStatus(any(), any(), any()) } returns result + } + fun arrange() = this to viewModel } diff --git a/app/src/test/kotlin/com/wire/android/ui/home/conversationslist/ConversationListViewModelTest.kt b/app/src/test/kotlin/com/wire/android/ui/home/conversationslist/ConversationListViewModelTest.kt index 2e5b97cf801..7b5abe7d804 100644 --- a/app/src/test/kotlin/com/wire/android/ui/home/conversationslist/ConversationListViewModelTest.kt +++ b/app/src/test/kotlin/com/wire/android/ui/home/conversationslist/ConversationListViewModelTest.kt @@ -20,12 +20,14 @@ package com.wire.android.ui.home.conversationslist +import app.cash.turbine.test import com.wire.android.config.CoroutineTestExtension import com.wire.android.config.TestDispatcherProvider import com.wire.android.config.mockUri import com.wire.android.mapper.UserTypeMapper import com.wire.android.model.UserAvatarData import com.wire.android.ui.common.dialogs.BlockUserDialogState +import com.wire.android.ui.home.HomeSnackbarState import com.wire.android.ui.home.conversations.model.UILastMessageContent import com.wire.android.ui.home.conversationslist.model.BadgeEventType import com.wire.android.ui.home.conversationslist.model.BlockingState @@ -43,11 +45,13 @@ import com.wire.kalium.logic.feature.connection.BlockUserResult import com.wire.kalium.logic.feature.connection.BlockUserUseCase import com.wire.kalium.logic.feature.connection.UnblockUserResult import com.wire.kalium.logic.feature.connection.UnblockUserUseCase +import com.wire.kalium.logic.feature.conversation.ArchiveStatusUpdateResult import com.wire.kalium.logic.feature.conversation.ClearConversationContentUseCase import com.wire.kalium.logic.feature.conversation.ConversationUpdateStatusResult import com.wire.kalium.logic.feature.conversation.LeaveConversationUseCase import com.wire.kalium.logic.feature.conversation.ObserveConversationListDetailsUseCase import com.wire.kalium.logic.feature.conversation.RefreshConversationsWithoutMetadataUseCase +import com.wire.kalium.logic.feature.conversation.UpdateConversationArchivedStatusUseCase import com.wire.kalium.logic.feature.conversation.UpdateConversationMutedStatusUseCase import com.wire.kalium.logic.feature.publicuser.RefreshUsersWithoutMetadataUseCase import com.wire.kalium.logic.feature.team.DeleteTeamConversationUseCase @@ -58,9 +62,9 @@ import io.mockk.impl.annotations.MockK import io.mockk.verify import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.emptyFlow -import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.test.runTest import org.amshove.kluent.internal.assertEquals +import org.amshove.kluent.shouldBeEqualTo import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith @@ -111,6 +115,9 @@ class ConversationListViewModelTest { @MockK private lateinit var refreshConversationsWithoutMetadata: RefreshConversationsWithoutMetadataUseCase + @MockK + private lateinit var updateConversationArchivedStatus: UpdateConversationArchivedStatusUseCase + @MockK(relaxed = true) private lateinit var onJoined: (ConversationId) -> Unit @@ -119,7 +126,7 @@ class ConversationListViewModelTest { MockKAnnotations.init(this, relaxUnitFun = true) coEvery { observeEstablishedCalls.invoke() } returns emptyFlow() - coEvery { observeConversationListDetailsUseCase.invoke() } returns emptyFlow() + coEvery { observeConversationListDetailsUseCase.invoke(any()) } returns emptyFlow() mockUri() conversationListViewModel = @@ -139,9 +146,8 @@ class ConversationListViewModelTest { refreshUsersWithoutMetadata = refreshUsersWithoutMetadata, refreshConversationsWithoutMetadata = refreshConversationsWithoutMetadata, userTypeMapper = UserTypeMapper(), + updateConversationArchivedStatus = updateConversationArchivedStatus ) - - coEvery { observeConversationListDetailsUseCase() } returns flowOf(listOf()) } @Test @@ -248,6 +254,32 @@ class ConversationListViewModelTest { assertEquals(false, conversationListViewModel.conversationListState.shouldShowCallingPermissionDialog) } + @Test + fun `given a valid conversation state, when archiving it correctly, then the right success message is shown`() = runTest { + val isArchiving = true + val archivingTimestamp = 123456789L + + coEvery { updateConversationArchivedStatus(any(), any(), any()) } returns ArchiveStatusUpdateResult.Success + + conversationListViewModel.homeSnackBarState.test { + conversationListViewModel.moveConversationToArchive(conversationId, isArchiving, archivingTimestamp) + expectMostRecentItem() shouldBeEqualTo HomeSnackbarState.ArchivingConversationSuccess + } + } + + @Test + fun `given a valid conversation state, when archiving it with an error, then the right failure message is shown`() = runTest { + val isArchiving = true + val archivingTimestamp = 123456789L + + coEvery { updateConversationArchivedStatus(any(), any(), any()) } returns ArchiveStatusUpdateResult.Failure + + conversationListViewModel.homeSnackBarState.test { + conversationListViewModel.moveConversationToArchive(conversationId, isArchiving, archivingTimestamp) + expectMostRecentItem() shouldBeEqualTo HomeSnackbarState.ArchivingConversationError + } + } + companion object { private val conversationId = ConversationId("some_id", "some_domain") private val userId: UserId = UserId("someUser", "some_domain") diff --git a/app/src/test/kotlin/com/wire/android/ui/userprofile/other/OtherUserProfileViewModelArrangement.kt b/app/src/test/kotlin/com/wire/android/ui/userprofile/other/OtherUserProfileViewModelArrangement.kt index 24dfd47b05c..39f2fb89b0d 100644 --- a/app/src/test/kotlin/com/wire/android/ui/userprofile/other/OtherUserProfileViewModelArrangement.kt +++ b/app/src/test/kotlin/com/wire/android/ui/userprofile/other/OtherUserProfileViewModelArrangement.kt @@ -37,9 +37,11 @@ import com.wire.kalium.logic.feature.client.PersistOtherUserClientsUseCase import com.wire.kalium.logic.feature.connection.BlockUserResult import com.wire.kalium.logic.feature.connection.BlockUserUseCase import com.wire.kalium.logic.feature.connection.UnblockUserUseCase +import com.wire.kalium.logic.feature.conversation.ArchiveStatusUpdateResult import com.wire.kalium.logic.feature.conversation.ClearConversationContentUseCase import com.wire.kalium.logic.feature.conversation.GetOneToOneConversationUseCase import com.wire.kalium.logic.feature.conversation.RemoveMemberFromConversationUseCase +import com.wire.kalium.logic.feature.conversation.UpdateConversationArchivedStatusUseCase import com.wire.kalium.logic.feature.conversation.UpdateConversationMemberRoleResult import com.wire.kalium.logic.feature.conversation.UpdateConversationMemberRoleUseCase import com.wire.kalium.logic.feature.conversation.UpdateConversationMutedStatusUseCase @@ -99,6 +101,9 @@ internal class OtherUserProfileViewModelArrangement { @MockK lateinit var clearConversationContent: ClearConversationContentUseCase + @MockK + lateinit var updateConversationArchivedStatus: UpdateConversationArchivedStatusUseCase + private val viewModel by lazy { OtherUserProfileScreenViewModel( TestDispatcherProvider(), @@ -115,6 +120,7 @@ internal class OtherUserProfileViewModelArrangement { observeClientList, persistOtherUserClientsUseCase, clearConversationContent, + updateConversationArchivedStatus, savedStateHandle ) } @@ -138,6 +144,7 @@ internal class OtherUserProfileViewModelArrangement { ) ) coEvery { observeSelfUser() } returns flowOf(TestUser.SELF_USER) + coEvery { updateConversationArchivedStatus(any(), any()) } returns ArchiveStatusUpdateResult.Success every { userTypeMapper.toMembership(any()) } returns Membership.None coEvery { getOneToOneConversation(USER_ID) } returns flowOf( GetOneToOneConversationUseCase.Result.Success(OtherUserProfileScreenViewModelTest.CONVERSATION) diff --git a/kalium b/kalium index 00d151f4189..45b6707e7a0 160000 --- a/kalium +++ b/kalium @@ -1 +1 @@ -Subproject commit 00d151f4189c5d7123fb9d6b57c5587e62900ddf +Subproject commit 45b6707e7a0f29bd9b1647a7780fe04425404015