Skip to content

Commit fffb999

Browse files
authored
feat: Delete group option on Leaving it WPB-14938 (#3809)
1 parent 59d4513 commit fffb999

File tree

11 files changed

+108
-42
lines changed

11 files changed

+108
-42
lines changed

app/src/main/kotlin/com/wire/android/ui/common/bottomsheet/conversation/ConversationSheetContent.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import com.wire.android.ui.home.conversations.folder.ConversationFoldersNavArgs
2929
import com.wire.android.ui.home.conversationslist.model.BlockingState
3030
import com.wire.android.ui.home.conversationslist.model.DialogState
3131
import com.wire.android.ui.home.conversationslist.model.GroupDialogState
32+
import com.wire.android.ui.home.conversationslist.model.LeaveGroupDialogState
3233
import com.wire.kalium.logic.data.conversation.Conversation
3334
import com.wire.kalium.logic.data.conversation.ConversationFolder
3435
import com.wire.kalium.logic.data.conversation.MutedConversationStatus
@@ -46,7 +47,7 @@ fun ConversationSheetContent(
4647
clearConversationContent: (DialogState) -> Unit,
4748
blockUser: (BlockUserDialogState) -> Unit,
4849
unblockUser: (UnblockUserDialogState) -> Unit,
49-
leaveGroup: (GroupDialogState) -> Unit,
50+
leaveGroup: (LeaveGroupDialogState) -> Unit,
5051
deleteGroup: (GroupDialogState) -> Unit,
5152
deleteGroupLocally: (GroupDialogState) -> Unit,
5253
isBottomSheetVisible: () -> Boolean = { true }

app/src/main/kotlin/com/wire/android/ui/common/bottomsheet/conversation/HomeSheetContent.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ import com.wire.android.ui.home.conversationslist.common.GroupConversationAvatar
4848
import com.wire.android.ui.home.conversationslist.model.BlockingState
4949
import com.wire.android.ui.home.conversationslist.model.DialogState
5050
import com.wire.android.ui.home.conversationslist.model.GroupDialogState
51+
import com.wire.android.ui.home.conversationslist.model.LeaveGroupDialogState
5152
import com.wire.android.ui.home.conversationslist.model.getMutedStatusTextResource
5253
import com.wire.android.ui.theme.wireColorScheme
5354
import com.wire.android.ui.theme.wireTypography
@@ -68,7 +69,7 @@ internal fun ConversationMainSheetContent(
6869
clearConversationContent: (DialogState) -> Unit,
6970
blockUserClick: (BlockUserDialogState) -> Unit,
7071
unblockUserClick: (UnblockUserDialogState) -> Unit,
71-
leaveGroup: (GroupDialogState) -> Unit,
72+
leaveGroup: (LeaveGroupDialogState) -> Unit,
7273
deleteGroup: (GroupDialogState) -> Unit,
7374
deleteGroupLocally: (GroupDialogState) -> Unit,
7475
navigateToNotification: () -> Unit
@@ -294,7 +295,7 @@ internal fun ConversationMainSheetContent(
294295
title = stringResource(R.string.label_leave_group),
295296
onItemClick = {
296297
leaveGroup(
297-
GroupDialogState(
298+
LeaveGroupDialogState(
298299
conversationSheetContent.conversationId,
299300
conversationSheetContent.title
300301
)

app/src/main/kotlin/com/wire/android/ui/home/conversations/details/GroupConversationDetailsScreen.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ import com.wire.android.ui.home.conversations.folder.RemoveConversationFromFolde
119119
import com.wire.android.ui.home.conversations.folder.RemoveConversationFromFolderVMImpl
120120
import com.wire.android.ui.home.conversationslist.model.DialogState
121121
import com.wire.android.ui.home.conversationslist.model.GroupDialogState
122+
import com.wire.android.ui.home.conversationslist.model.LeaveGroupDialogState
122123
import com.wire.android.ui.legalhold.dialog.subject.LegalHoldSubjectConversationDialog
123124
import com.wire.android.ui.theme.WireTheme
124125
import com.wire.android.ui.theme.wireColorScheme
@@ -310,7 +311,7 @@ private fun GroupConversationDetailsContent(
310311
onEditGuestAccess: () -> Unit,
311312
onEditSelfDeletingMessages: () -> Unit,
312313
onEditGroupName: () -> Unit,
313-
onLeaveGroup: (GroupDialogState) -> Unit,
314+
onLeaveGroup: (LeaveGroupDialogState) -> Unit,
314315
onDeleteGroup: (GroupDialogState) -> Unit,
315316
groupParticipantsState: GroupConversationParticipantsState,
316317
isLoading: Boolean,
@@ -348,7 +349,7 @@ private fun GroupConversationDetailsContent(
348349
val getBottomSheetVisibility: () -> Boolean = remember(sheetState) { { sheetState.isVisible } }
349350

350351
val deleteGroupDialogState = rememberVisibilityState<GroupDialogState>()
351-
val leaveGroupDialogState = rememberVisibilityState<GroupDialogState>()
352+
val leaveGroupDialogState = rememberVisibilityState<LeaveGroupDialogState>()
352353
val clearConversationDialogState = rememberVisibilityState<DialogState>()
353354
val archiveConversationDialogState = rememberVisibilityState<DialogState>()
354355
val legalHoldSubjectDialogState = rememberVisibilityState<Unit>()

app/src/main/kotlin/com/wire/android/ui/home/conversations/details/GroupConversationDetailsViewModel.kt

Lines changed: 45 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import androidx.compose.runtime.mutableStateOf
2323
import androidx.compose.runtime.setValue
2424
import androidx.lifecycle.SavedStateHandle
2525
import androidx.lifecycle.viewModelScope
26+
import androidx.work.WorkManager
2627
import com.wire.android.R
2728
import com.wire.android.appLogger
2829
import com.wire.android.ui.common.bottomsheet.conversation.ConversationSheetContent
@@ -33,11 +34,14 @@ import com.wire.android.ui.home.conversations.details.participants.GroupConversa
3334
import com.wire.android.ui.home.conversations.details.participants.usecase.ObserveParticipantsForConversationUseCase
3435
import com.wire.android.ui.home.conversationslist.model.DialogState
3536
import com.wire.android.ui.home.conversationslist.model.GroupDialogState
37+
import com.wire.android.ui.home.conversationslist.model.LeaveGroupDialogState
3638
import com.wire.android.ui.home.conversationslist.showLegalHoldIndicator
3739
import com.wire.android.ui.navArgs
3840
import com.wire.android.util.dispatchers.DispatcherProvider
3941
import com.wire.android.util.ui.UIText
4042
import com.wire.android.util.uiText
43+
import com.wire.android.workmanager.worker.ConversationDeletionLocallyStatus
44+
import com.wire.android.workmanager.worker.enqueueConversationDeletionLocally
4145
import com.wire.kalium.logic.CoreFailure
4246
import com.wire.kalium.logic.data.conversation.Conversation
4347
import com.wire.kalium.logic.data.conversation.ConversationDetails
@@ -62,7 +66,7 @@ import com.wire.kalium.logic.feature.team.DeleteTeamConversationUseCase
6266
import com.wire.kalium.logic.feature.team.GetUpdatedSelfTeamUseCase
6367
import com.wire.kalium.logic.feature.team.Result
6468
import com.wire.kalium.logic.feature.user.GetDefaultProtocolUseCase
65-
import com.wire.kalium.logic.feature.user.ObserveSelfUserUseCase
69+
import com.wire.kalium.logic.feature.user.GetSelfUserUseCase
6670
import com.wire.kalium.logic.feature.user.IsMLSEnabledUseCase
6771
import com.wire.kalium.logic.functional.getOrNull
6872
import dagger.hilt.android.lifecycle.HiltViewModel
@@ -73,8 +77,6 @@ import kotlinx.coroutines.flow.StateFlow
7377
import kotlinx.coroutines.flow.combine
7478
import kotlinx.coroutines.flow.distinctUntilChanged
7579
import kotlinx.coroutines.flow.filterIsInstance
76-
import kotlinx.coroutines.flow.first
77-
import kotlinx.coroutines.flow.firstOrNull
7880
import kotlinx.coroutines.flow.flowOn
7981
import kotlinx.coroutines.flow.map
8082
import kotlinx.coroutines.flow.shareIn
@@ -91,7 +93,7 @@ class GroupConversationDetailsViewModel @Inject constructor(
9193
private val observeConversationMembers: ObserveParticipantsForConversationUseCase,
9294
private val updateConversationAccessRole: UpdateConversationAccessRoleUseCase,
9395
private val getSelfTeam: GetUpdatedSelfTeamUseCase,
94-
private val observerSelfUser: ObserveSelfUserUseCase,
96+
private val getSelfUser: GetSelfUserUseCase,
9597
private val deleteTeamConversation: DeleteTeamConversationUseCase,
9698
private val removeMemberFromConversation: RemoveMemberFromConversationUseCase,
9799
private val updateConversationMutedStatus: UpdateConversationMutedStatusUseCase,
@@ -102,6 +104,7 @@ class GroupConversationDetailsViewModel @Inject constructor(
102104
override val savedStateHandle: SavedStateHandle,
103105
private val isMLSEnabled: IsMLSEnabledUseCase,
104106
private val getDefaultProtocol: GetDefaultProtocolUseCase,
107+
private val workManager: WorkManager,
105108
refreshUsersWithoutMetadata: RefreshUsersWithoutMetadataUseCase,
106109
) : GroupConversationParticipantsViewModel(
107110
savedStateHandle, observeConversationMembers, refreshUsersWithoutMetadata
@@ -136,15 +139,15 @@ class GroupConversationDetailsViewModel @Inject constructor(
136139
.shareIn(this, SharingStarted.WhileSubscribed(), 1)
137140

138141
val selfTeam = getSelfTeam().getOrNull()
139-
val selfUser = observerSelfUser().first()
142+
val selfUser = getSelfUser()
140143
val isMLSTeam = getDefaultProtocol() == SupportedProtocol.MLS
141144

142145
combine(
143146
groupDetailsFlow,
144147
observeSelfDeletionTimerSettingsForConversation(conversationId, considerSelfUserSettings = false),
145148
) { groupDetails, selfDeletionTimer ->
146149
val isSelfInOwnerTeam = selfTeam?.id != null && selfTeam.id == groupDetails.conversation.teamId?.value
147-
val isSelfExternalMember = selfUser.userType == UserType.EXTERNAL
150+
val isSelfExternalMember = selfUser?.userType == UserType.EXTERNAL
148151
val isSelfAnAdmin = groupDetails.selfRole == Conversation.Member.Role.Admin
149152
val isMLSConversation = groupDetails.conversation.protocol is Conversation.ProtocolInfo.MLS
150153

@@ -154,7 +157,7 @@ class GroupConversationDetailsViewModel @Inject constructor(
154157
mutingConversationState = groupDetails.conversation.mutedStatus,
155158
conversationTypeDetail = ConversationTypeDetail.Group(
156159
conversationId = conversationId,
157-
isFromTheSameTeam = groupDetails.conversation.teamId == observerSelfUser().firstOrNull()?.teamId
160+
isFromTheSameTeam = groupDetails.conversation.teamId == getSelfUser()?.teamId
158161
),
159162
isTeamConversation = groupDetails.conversation.teamId?.value != null,
160163
selfRole = groupDetails.selfRole,
@@ -190,21 +193,27 @@ class GroupConversationDetailsViewModel @Inject constructor(
190193
}
191194

192195
fun leaveGroup(
193-
leaveGroupState: GroupDialogState,
196+
leaveGroupState: LeaveGroupDialogState,
194197
onSuccess: () -> Unit,
195198
onFailure: (UIText) -> Unit
196199
) {
197200
viewModelScope.launch {
198201
requestInProgress = true
199202
val response = withContext(dispatcher.io()) {
200-
val selfUser = observerSelfUser().first()
201-
removeMemberFromConversation(
202-
leaveGroupState.conversationId, selfUser.id
203-
)
203+
getSelfUser()?.let { selfUser ->
204+
removeMemberFromConversation(leaveGroupState.conversationId, selfUser.id)
205+
}
204206
}
205207
when (response) {
206208
is RemoveMemberFromConversationUseCase.Result.Failure -> onFailure(response.cause.uiText())
207-
RemoveMemberFromConversationUseCase.Result.Success -> onSuccess()
209+
RemoveMemberFromConversationUseCase.Result.Success -> {
210+
if (leaveGroupState.shouldDelete) {
211+
deleteGroupLocally(leaveGroupState, onSuccess, onFailure)
212+
} else {
213+
onSuccess()
214+
}
215+
}
216+
null -> {}
208217
}
209218
requestInProgress = false
210219
}
@@ -226,6 +235,29 @@ class GroupConversationDetailsViewModel @Inject constructor(
226235
}
227236
}
228237

238+
fun deleteGroupLocally(
239+
groupDialogState: GroupDialogState,
240+
onSuccess: () -> Unit,
241+
onFailure: (UIText) -> Unit
242+
) {
243+
viewModelScope.launch {
244+
workManager.enqueueConversationDeletionLocally(groupDialogState.conversationId)
245+
.collect { status ->
246+
when (status) {
247+
ConversationDeletionLocallyStatus.SUCCEEDED -> onSuccess()
248+
249+
ConversationDeletionLocallyStatus.FAILED ->
250+
onFailure(UIText.StringResource(R.string.delete_group_conversation_error))
251+
252+
ConversationDeletionLocallyStatus.RUNNING,
253+
ConversationDeletionLocallyStatus.IDLE -> {
254+
// nop
255+
}
256+
}
257+
}
258+
}
259+
}
260+
229261
fun onServicesUpdate(enableServices: Boolean) {
230262
updateState(groupOptionsState.value.copy(loadingServicesOption = true, isServicesAllowed = enableServices))
231263
when (enableServices) {

app/src/main/kotlin/com/wire/android/ui/home/conversations/details/menu/LeaveConversationGroupDialog.kt

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,26 +18,31 @@
1818

1919
package com.wire.android.ui.home.conversations.details.menu
2020

21+
import androidx.compose.foundation.layout.Arrangement
22+
import androidx.compose.foundation.layout.fillMaxWidth
2123
import androidx.compose.runtime.Composable
24+
import androidx.compose.runtime.remember
25+
import androidx.compose.ui.Modifier
2226
import androidx.compose.ui.res.stringResource
2327
import com.wire.android.R
2428
import com.wire.android.ui.common.VisibilityState
2529
import com.wire.android.ui.common.WireDialog
2630
import com.wire.android.ui.common.WireDialogButtonProperties
2731
import com.wire.android.ui.common.WireDialogButtonType
32+
import com.wire.android.ui.common.WireLabelledCheckbox
2833
import com.wire.android.ui.common.button.WireButtonState
2934
import com.wire.android.ui.common.visbility.VisibilityState
30-
import com.wire.android.ui.home.conversationslist.model.GroupDialogState
35+
import com.wire.android.ui.home.conversationslist.model.LeaveGroupDialogState
3136

3237
@Composable
3338
internal fun LeaveConversationGroupDialog(
34-
dialogState: VisibilityState<GroupDialogState>,
39+
dialogState: VisibilityState<LeaveGroupDialogState>,
3540
isLoading: Boolean,
36-
onLeaveGroup: (GroupDialogState) -> Unit,
41+
onLeaveGroup: (LeaveGroupDialogState) -> Unit,
3742
) {
38-
VisibilityState(dialogState) {
43+
VisibilityState(dialogState) { state ->
3944
WireDialog(
40-
title = stringResource(id = R.string.leave_group_conversation_dialog_title, it.conversationName),
45+
title = stringResource(id = R.string.leave_group_conversation_dialog_title, state.conversationName),
4146
text = stringResource(id = R.string.leave_group_conversation_dialog_description),
4247
buttonsHorizontalAlignment = true,
4348
onDismiss = dialogState::dismiss,
@@ -47,7 +52,7 @@ internal fun LeaveConversationGroupDialog(
4752
state = WireButtonState.Default
4853
),
4954
optionButton1Properties = WireDialogButtonProperties(
50-
onClick = { onLeaveGroup(it) },
55+
onClick = { onLeaveGroup(state) },
5156
text = stringResource(id = R.string.label_leave),
5257
type = WireDialogButtonType.Primary,
5358
state =
@@ -57,6 +62,14 @@ internal fun LeaveConversationGroupDialog(
5762
WireButtonState.Error,
5863
loading = isLoading
5964
)
60-
)
65+
) {
66+
WireLabelledCheckbox(
67+
label = stringResource(R.string.leave_group_conversation_dialog_delete_fully_check),
68+
checked = state.shouldDelete,
69+
onCheckClicked = remember { { dialogState.show(state.copy(shouldDelete = it)) } },
70+
horizontalArrangement = Arrangement.Center,
71+
modifier = Modifier.fillMaxWidth()
72+
)
73+
}
6174
}
6275
}

app/src/main/kotlin/com/wire/android/ui/home/conversationslist/ConversationListViewModel.kt

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ import com.wire.android.ui.home.conversationslist.model.ConversationItem
4848
import com.wire.android.ui.home.conversationslist.model.ConversationsSource
4949
import com.wire.android.ui.home.conversationslist.model.DialogState
5050
import com.wire.android.ui.home.conversationslist.model.GroupDialogState
51+
import com.wire.android.ui.home.conversationslist.model.LeaveGroupDialogState
5152
import com.wire.android.util.dispatchers.DispatcherProvider
5253
import com.wire.android.workmanager.worker.ConversationDeletionLocallyStatus
5354
import com.wire.android.workmanager.worker.enqueueConversationDeletionLocally
@@ -117,7 +118,7 @@ interface ConversationListViewModel {
117118
fun deleteGroup(groupDialogState: GroupDialogState) {}
118119
fun deleteGroupLocally(groupDialogState: GroupDialogState) {}
119120
fun observeIsDeletingConversationLocally(conversationId: ConversationId): Flow<Boolean>
120-
fun leaveGroup(leaveGroupState: GroupDialogState) {}
121+
fun leaveGroup(leaveGroupState: LeaveGroupDialogState) {}
121122
fun clearConversationContent(dialogState: DialogState) {}
122123
fun muteConversation(conversationId: ConversationId?, mutedConversationStatus: MutedConversationStatus) {}
123124
fun moveConversationToFolder() {}
@@ -374,7 +375,7 @@ class ConversationListViewModelImpl @AssistedInject constructor(
374375
}
375376
}
376377

377-
override fun leaveGroup(leaveGroupState: GroupDialogState) {
378+
override fun leaveGroup(leaveGroupState: LeaveGroupDialogState) {
378379
viewModelScope.launch {
379380
_requestInProgress = true
380381
val response = leaveConversation(leaveGroupState.conversationId)
@@ -383,7 +384,11 @@ class ConversationListViewModelImpl @AssistedInject constructor(
383384
_infoMessage.emit(HomeSnackBarMessage.LeaveConversationError)
384385

385386
RemoveMemberFromConversationUseCase.Result.Success -> {
386-
_infoMessage.emit(HomeSnackBarMessage.LeftConversationSuccess)
387+
if (leaveGroupState.shouldDelete) {
388+
deleteGroupLocally(leaveGroupState)
389+
} else {
390+
_infoMessage.emit(HomeSnackBarMessage.LeftConversationSuccess)
391+
}
387392
}
388393
}
389394
_requestInProgress = false

app/src/main/kotlin/com/wire/android/ui/home/conversationslist/ConversationsDialogsState.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,11 @@ import com.wire.android.ui.common.visbility.VisibilityState
2929
import com.wire.android.ui.common.visbility.rememberVisibilityState
3030
import com.wire.android.ui.home.conversationslist.model.DialogState
3131
import com.wire.android.ui.home.conversationslist.model.GroupDialogState
32+
import com.wire.android.ui.home.conversationslist.model.LeaveGroupDialogState
3233

3334
@Suppress("LongParameterList")
3435
class ConversationsDialogsState(
35-
val leaveGroupDialogState: VisibilityState<GroupDialogState>,
36+
val leaveGroupDialogState: VisibilityState<LeaveGroupDialogState>,
3637
val deleteGroupDialogState: VisibilityState<GroupDialogState>,
3738
val deleteGroupLocallyDialogState: VisibilityState<GroupDialogState>,
3839
val blockUserDialogState: VisibilityState<BlockUserDialogState>,
@@ -47,7 +48,7 @@ class ConversationsDialogsState(
4748
@Composable
4849
fun rememberConversationsDialogsState(requestInProgress: Boolean): ConversationsDialogsState {
4950

50-
val leaveGroupDialogState = rememberVisibilityState<GroupDialogState>()
51+
val leaveGroupDialogState = rememberVisibilityState<LeaveGroupDialogState>()
5152
val deleteGroupDialogState = rememberVisibilityState<GroupDialogState>()
5253
val deleteGroupLocallyDialogState = rememberVisibilityState<GroupDialogState>()
5354
val blockUserDialogState = rememberVisibilityState<BlockUserDialogState>()

app/src/main/kotlin/com/wire/android/ui/home/conversationslist/model/GroupDialogState.kt

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@ package com.wire.android.ui.home.conversationslist.model
2121
import com.wire.android.ui.common.bottomsheet.conversation.ConversationTypeDetail
2222
import com.wire.kalium.logic.data.id.ConversationId
2323

24-
data class GroupDialogState(
25-
val conversationId: ConversationId,
26-
val conversationName: String
24+
open class GroupDialogState(
25+
open val conversationId: ConversationId,
26+
open val conversationName: String
2727
)
2828

2929
data class DialogState(
@@ -33,3 +33,9 @@ data class DialogState(
3333
val isArchived: Boolean,
3434
val isMember: Boolean
3535
)
36+
37+
data class LeaveGroupDialogState(
38+
override val conversationId: ConversationId,
39+
override val conversationName: String,
40+
val shouldDelete: Boolean = false
41+
) : GroupDialogState(conversationId, conversationName)

app/src/main/res/values/strings.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -571,6 +571,7 @@
571571
<string name="leave_group_conversation_menu_item">Leave Group…</string>
572572
<string name="leave_group_conversation_dialog_title">Leave “%s”?</string>
573573
<string name="leave_group_conversation_dialog_description">You will then no longer be able to send or read messages in this group on any device.</string>
574+
<string name="leave_group_conversation_dialog_delete_fully_check">Delete the group and its content for me on all my devices</string>
574575
<string name="delete_group_conversation_menu_item">Delete Group…</string>
575576
<string name="delete_group_conversation_dialog_title">Remove “%s”?</string>
576577
<string name="delete_group_conversation_dialog_description">The group will be removed from your conversations list on all devices. You will no longer be able to access the group and its content.</string>

0 commit comments

Comments
 (0)