Sticker management v2 - Implement multi-delete.

This commit is contained in:
Jeffrey Starke
2025-05-01 17:14:54 -04:00
committed by Cody Henthorne
parent 7c9bab421a
commit 3c77a3d7aa
3 changed files with 78 additions and 9 deletions

View File

@@ -60,6 +60,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import kotlinx.coroutines.launch
import org.signal.core.ui.compose.Dialogs
import org.signal.core.ui.compose.Dividers
import org.signal.core.ui.compose.DropdownMenus
import org.signal.core.ui.compose.Previews
@@ -117,7 +118,9 @@ class StickerManagementActivityV2 : PassphraseRequiredActivity() {
},
installedTabCallbacks = object : InstalledStickersContentCallbacks {
override fun onForwardClick(pack: InstalledStickerPack) = openShareSheet(pack.id, pack.key)
override fun onRemoveClick(pack: InstalledStickerPack) = viewModel.uninstallStickerPack(pack)
override fun onRemoveClick(packIds: Set<StickerPackId>) = viewModel.onUninstallStickerPacksRequested(packIds)
override fun onRemoveStickerPacksConfirmed(packIds: Set<StickerPackId>) = viewModel.onUninstallStickerPacksConfirmed(packIds)
override fun onRemoveStickerPacksCanceled() = viewModel.onUninstallStickerPacksCanceled()
override fun onSelectionToggle(pack: InstalledStickerPack) = viewModel.toggleSelection(pack)
override fun onSelectAllToggle() = viewModel.toggleSelectAll()
override fun onDragAndDropEvent(event: DragAndDropEvent) {
@@ -165,14 +168,18 @@ interface AvailableStickersContentCallbacks {
interface InstalledStickersContentCallbacks {
fun onForwardClick(pack: InstalledStickerPack)
fun onRemoveClick(pack: InstalledStickerPack)
fun onRemoveClick(packIds: Set<StickerPackId>)
fun onRemoveStickerPacksConfirmed(packIds: Set<StickerPackId>)
fun onRemoveStickerPacksCanceled()
fun onSelectionToggle(pack: InstalledStickerPack)
fun onSelectAllToggle()
fun onDragAndDropEvent(event: DragAndDropEvent)
object Empty : InstalledStickersContentCallbacks {
override fun onForwardClick(pack: InstalledStickerPack) = Unit
override fun onRemoveClick(pack: InstalledStickerPack) = Unit
override fun onRemoveClick(packIds: Set<StickerPackId>) = Unit
override fun onRemoveStickerPacksConfirmed(packIds: Set<StickerPackId>) = Unit
override fun onRemoveStickerPacksCanceled() = Unit
override fun onSelectionToggle(pack: InstalledStickerPack) = Unit
override fun onSelectAllToggle() = Unit
override fun onDragAndDropEvent(event: DragAndDropEvent) = Unit
@@ -207,6 +214,7 @@ private fun StickerManagementScreen(
packs = uiState.installedPacks,
multiSelectEnabled = uiState.multiSelectEnabled,
selectedPackIds = uiState.selectedPackIds,
dialogState = uiState.userPrompt,
callbacks = installedTabCallbacks
)
}
@@ -393,6 +401,7 @@ private fun InstalledStickersContent(
packs: List<InstalledStickerPack>,
multiSelectEnabled: Boolean,
selectedPackIds: Set<StickerPackId>,
dialogState: ConfirmRemoveStickerPacksPrompt? = null,
callbacks: InstalledStickersContentCallbacks = InstalledStickersContentCallbacks.Empty,
modifier: Modifier = Modifier
) {
@@ -448,7 +457,7 @@ private fun InstalledStickersContent(
menuController = menuController,
onForwardClick = { callbacks.onForwardClick(pack) },
onSelectionToggle = { callbacks.onSelectionToggle(pack) },
onRemoveClick = { callbacks.onRemoveClick(pack) },
onRemoveClick = { callbacks.onRemoveClick(setOf(pack.id)) },
modifier = Modifier
.shadow(if (isDragging) 1.dp else 0.dp)
.combinedClickable(
@@ -470,6 +479,22 @@ private fun InstalledStickersContent(
}
}
if (dialogState != null) {
Dialogs.SimpleAlertDialog(
title = Dialogs.NoTitle,
body = pluralStringResource(
R.plurals.StickerManagement_delete_n_packs_confirmation,
dialogState.numItemsToDelete,
NumberFormat.getInstance().format(dialogState.numItemsToDelete)
),
confirm = stringResource(R.string.StickerManagement_menu_remove_pack),
dismiss = stringResource(android.R.string.cancel),
onConfirm = { callbacks.onRemoveStickerPacksConfirmed(selectedPackIds) },
onDeny = callbacks::onRemoveStickerPacksCanceled,
onDismiss = callbacks::onRemoveStickerPacksCanceled
)
}
SignalBottomActionBar(
visible = multiSelectEnabled,
items = listOf(
@@ -485,7 +510,7 @@ private fun InstalledStickersContent(
ActionItem(
iconRes = R.drawable.symbol_trash_24,
title = stringResource(R.string.StickerManagement_action_delete_selected),
action = { /* TODO implement multi-delete */ }
action = { callbacks.onRemoveClick(selectedPackIds) }
)
),
modifier = Modifier

View File

@@ -72,7 +72,8 @@ class StickerManagementViewModelV2 : ViewModel() {
previousState.copy(
availableBlessedPacks = availableBlessedPacks,
availableNotBlessedPacks = availableNotBlessedPacks,
installedPacks = installedPacks
installedPacks = installedPacks,
multiSelectEnabled = if (installedPacks.isEmpty()) false else previousState.multiSelectEnabled
)
}
}
@@ -98,9 +99,42 @@ class StickerManagementViewModelV2 : ViewModel() {
}
}
fun uninstallStickerPack(pack: InstalledStickerPack) {
fun onUninstallStickerPacksRequested(packIds: Set<StickerPackId>) {
if (packIds.isEmpty()) {
return
}
if (_uiState.value.multiSelectEnabled) {
_uiState.update { previousState ->
previousState.copy(
userPrompt = ConfirmRemoveStickerPacksPrompt(numItemsToDelete = packIds.size)
)
}
} else {
uninstallStickerPacks(packIds)
}
}
fun onUninstallStickerPacksConfirmed(packIds: Set<StickerPackId>) {
_uiState.update { previousState -> previousState.copy(userPrompt = null) }
uninstallStickerPacks(packIds)
}
fun onUninstallStickerPacksCanceled() {
_uiState.update { previousState -> previousState.copy(userPrompt = null) }
}
private fun uninstallStickerPacks(packIds: Set<StickerPackId>) {
viewModelScope.launch {
StickerManagementRepository.uninstallStickerPack(packId = pack.id, packKey = pack.key)
_uiState.value.installedPacks
.filter { packIds.contains(it.id) }
.forEach { pack -> StickerManagementRepository.uninstallStickerPack(packId = pack.id, packKey = pack.key) }
_uiState.update { previousState ->
previousState.copy(
selectedPackIds = previousState.selectedPackIds.minus(packIds)
)
}
}
}
@@ -152,7 +186,12 @@ data class StickerManagementUiState(
val availableNotBlessedPacks: List<AvailableStickerPack> = emptyList(),
val installedPacks: List<InstalledStickerPack> = emptyList(),
val multiSelectEnabled: Boolean = false,
val selectedPackIds: Set<StickerPackId> = emptySet()
val selectedPackIds: Set<StickerPackId> = emptySet(),
val userPrompt: ConfirmRemoveStickerPacksPrompt? = null
)
data class ConfirmRemoveStickerPacksPrompt(
val numItemsToDelete: Int
)
data class AvailableStickerPack(