Sticker management v2 – Improve list animations and state transitions.

- Uninstall selected packs in a single database transaction to avoid UI flickering.
- Add section header keys to prevent them from animating wildly while scrolling.
This commit is contained in:
Jeffrey Starke
2025-05-14 17:10:41 -04:00
committed by GitHub
parent 8b828677de
commit f3a475d0c8
5 changed files with 38 additions and 18 deletions

View File

@@ -412,7 +412,13 @@ private fun AvailableStickersContent(
modifier = modifier.fillMaxHeight()
) {
if (blessedPacks.isNotEmpty()) {
item { StickerPackSectionHeader(text = stringResource(R.string.StickerManagement_signal_artist_series_header)) }
item(key = "blessed_section_header") {
StickerPackSectionHeader(
text = stringResource(R.string.StickerManagement_signal_artist_series_header),
modifier = Modifier.animateItem()
)
}
items(
items = blessedPacks,
key = { it.id.value }
@@ -442,7 +448,12 @@ private fun AvailableStickersContent(
}
if (notBlessedPacks.isNotEmpty()) {
item { StickerPackSectionHeader(text = stringResource(R.string.StickerManagement_stickers_you_received_header)) }
item(key = "not_blessed_section_header") {
StickerPackSectionHeader(
text = stringResource(R.string.StickerManagement_stickers_you_received_header),
modifier = Modifier.animateItem()
)
}
items(
items = notBlessedPacks,
key = { it.id.value }
@@ -508,9 +519,12 @@ private fun InstalledStickersContent(
rightDpOffset = if (isRtl) 56.dp else screenWidth
)
) {
item {
item(key = "installed_section_header") {
DraggableItem(dragDropState, 0) {
StickerPackSectionHeader(text = stringResource(R.string.StickerManagement_installed_stickers_header))
StickerPackSectionHeader(
text = stringResource(R.string.StickerManagement_installed_stickers_header),
modifier = Modifier.animateItem()
)
}
}

View File

@@ -118,15 +118,17 @@ object StickerManagementRepository {
@Discouraged("For Java use only. In Kotlin, use uninstallStickerPack() instead.")
fun uninstallStickerPackAsync(packId: String, packKey: String) {
coroutineScope.launch {
uninstallStickerPack(StickerPackId(packId), StickerPackKey(packKey))
uninstallStickerPacks(mapOf(StickerPackId(packId) to StickerPackKey(packKey)))
}
}
suspend fun uninstallStickerPack(packId: StickerPackId, packKey: StickerPackKey) = withContext(Dispatchers.IO) {
stickersDbTable.uninstallPack(packId.value)
suspend fun uninstallStickerPacks(packKeysById: Map<StickerPackId, StickerPackKey>) = withContext(Dispatchers.IO) {
stickersDbTable.uninstallPacks(packIds = packKeysById.keys)
if (SignalStore.account.hasLinkedDevices) {
AppDependencies.jobManager.add(MultiDeviceStickerPackOperationJob(packId.value, packKey.value, MultiDeviceStickerPackOperationJob.Type.REMOVE))
packKeysById.forEach { (packId, packKey) ->
AppDependencies.jobManager.add(MultiDeviceStickerPackOperationJob(packId.value, packKey.value, MultiDeviceStickerPackOperationJob.Type.REMOVE))
}
}
}

View File

@@ -133,12 +133,7 @@ class StickerManagementViewModel : ViewModel() {
private fun uninstallStickerPacks(packIds: Set<StickerPackId>) {
val packsToUninstall = _uiState.value.installedPacks.filter { packIds.contains(it.id) }
viewModelScope.launch {
packsToUninstall.forEach { pack ->
StickerManagementRepository.uninstallStickerPack(packId = pack.id, packKey = pack.key)
_uiState.update { previousState ->
previousState.copy(selectedPackIds = previousState.selectedPackIds.minus(pack.id))
}
}
StickerManagementRepository.uninstallStickerPacks(packsToUninstall.associate { it.id to it.key })
_uiState.update { previousState ->
previousState.copy(
@@ -146,7 +141,8 @@ class StickerManagementViewModel : ViewModel() {
StickerManagementConfirmation.UninstalledPack(packsToUninstall.single().record.title)
} else {
StickerManagementConfirmation.UninstalledPacks(packsToUninstall.size)
}
},
selectedPackIds = previousState.selectedPackIds.minus(packIds)
)
}
}