mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-03-02 15:36:32 +00:00
Sticker management v2 - Display available and installed stickers.
This commit is contained in:
committed by
Cody Henthorne
parent
e442c27555
commit
3d1895500c
@@ -123,7 +123,7 @@ public final class StickerManagementActivity extends PassphraseRequiredActivity
|
||||
}
|
||||
|
||||
private void initViewModel() {
|
||||
StickerManagementRepository repository = new StickerManagementRepository(this);
|
||||
StickerManagementRepository repository = new StickerManagementRepository();
|
||||
viewModel = new ViewModelProvider(this, new StickerManagementViewModel.Factory(getApplication(), repository)).get(StickerManagementViewModel.class);
|
||||
|
||||
viewModel.init();
|
||||
|
||||
@@ -10,9 +10,13 @@ import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.wrapContentHeight
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.pager.HorizontalPager
|
||||
import androidx.compose.foundation.pager.rememberPagerState
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
@@ -31,16 +35,22 @@ import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import kotlinx.coroutines.launch
|
||||
import org.signal.core.ui.compose.Dividers
|
||||
import org.signal.core.ui.compose.Previews
|
||||
import org.signal.core.ui.compose.Scaffolds
|
||||
import org.signal.core.ui.compose.SignalPreview
|
||||
import org.signal.core.ui.compose.theme.SignalTheme
|
||||
import org.thoughtcrime.securesms.PassphraseRequiredActivity
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.stickers.AvailableStickerPack.DownloadStatus
|
||||
import org.thoughtcrime.securesms.util.viewModel
|
||||
|
||||
/**
|
||||
* Displays all of the available and installed sticker packs, enabling installation, uninstallation, and sorting.
|
||||
*/
|
||||
class StickerManagementActivityV2 : PassphraseRequiredActivity() {
|
||||
companion object {
|
||||
@JvmStatic
|
||||
@@ -84,7 +94,7 @@ private fun StickerManagementScreen(
|
||||
val pages = listOf(
|
||||
Page(
|
||||
title = stringResource(R.string.StickerManagement_available_tab_label),
|
||||
getContent = { AvailableStickersContent(uiState.availablePacks) }
|
||||
getContent = { AvailableStickersContent(blessedPacks = uiState.availableBlessedPacks, availablePacks = uiState.availablePacks) }
|
||||
),
|
||||
Page(
|
||||
title = stringResource(R.string.StickerManagement_installed_tab_label),
|
||||
@@ -164,23 +174,64 @@ private fun PagerTab(
|
||||
|
||||
@Composable
|
||||
private fun AvailableStickersContent(
|
||||
packs: List<AvailableStickerPack>
|
||||
blessedPacks: List<AvailableStickerPack>,
|
||||
availablePacks: List<AvailableStickerPack>,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
if (packs.isEmpty()) {
|
||||
if (blessedPacks.isEmpty() && availablePacks.isEmpty()) {
|
||||
EmptyView(text = stringResource(R.string.StickerManagement_available_tab_empty_text))
|
||||
} else {
|
||||
// TODO show available stickers list
|
||||
LazyColumn(
|
||||
contentPadding = PaddingValues(top = 8.dp),
|
||||
modifier = modifier.fillMaxHeight()
|
||||
) {
|
||||
if (blessedPacks.isNotEmpty()) {
|
||||
item { StickerPackSectionHeader(text = stringResource(R.string.StickerManagement_signal_artist_series_header)) }
|
||||
items(
|
||||
items = blessedPacks,
|
||||
key = { it.record.packId }
|
||||
) {
|
||||
AvailableStickerPackRow(it)
|
||||
}
|
||||
}
|
||||
|
||||
if (blessedPacks.isNotEmpty() && availablePacks.isNotEmpty()) {
|
||||
item { Dividers.Default() }
|
||||
}
|
||||
|
||||
if (availablePacks.isNotEmpty()) {
|
||||
item { StickerPackSectionHeader(text = stringResource(R.string.StickerManagement_stickers_you_received_header)) }
|
||||
items(
|
||||
items = availablePacks,
|
||||
key = { it.record.packId }
|
||||
) {
|
||||
AvailableStickerPackRow(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun InstalledStickersContent(
|
||||
packs: List<InstalledStickerPack>
|
||||
packs: List<InstalledStickerPack>,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
if (packs.isEmpty()) {
|
||||
EmptyView(text = stringResource(R.string.StickerManagement_installed_tab_empty_text))
|
||||
} else {
|
||||
// TODO show installed stickers list
|
||||
LazyColumn(
|
||||
contentPadding = PaddingValues(top = 8.dp),
|
||||
modifier = modifier.fillMaxHeight()
|
||||
) {
|
||||
item { StickerPackSectionHeader(text = stringResource(R.string.StickerManagement_installed_stickers_header)) }
|
||||
items(
|
||||
items = packs,
|
||||
key = { it.record.packId }
|
||||
) {
|
||||
InstalledStickerPackRow(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -210,3 +261,58 @@ private fun StickerManagementScreenEmptyStatePreview() {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@SignalPreview
|
||||
@Composable
|
||||
private fun AvailableStickersContentPreview() {
|
||||
Previews.Preview {
|
||||
AvailableStickersContent(
|
||||
blessedPacks = listOf(
|
||||
StickerPreviewDataFactory.availablePack(
|
||||
title = "Swoon / Faces",
|
||||
author = "Swoon",
|
||||
isBlessed = true
|
||||
)
|
||||
),
|
||||
availablePacks = listOf(
|
||||
StickerPreviewDataFactory.availablePack(
|
||||
title = "Bandit the Cat",
|
||||
author = "Agnes Lee",
|
||||
isBlessed = false,
|
||||
downloadStatus = DownloadStatus.InProgress(progressPercent = 22.0)
|
||||
),
|
||||
StickerPreviewDataFactory.availablePack(
|
||||
title = "Day by Day",
|
||||
author = "Miguel Ángel Camprubí",
|
||||
isBlessed = false,
|
||||
downloadStatus = DownloadStatus.Downloaded
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@SignalPreview
|
||||
@Composable
|
||||
private fun InstalledStickersContentPreview() {
|
||||
Previews.Preview {
|
||||
InstalledStickersContent(
|
||||
packs = listOf(
|
||||
StickerPreviewDataFactory.installedPack(
|
||||
title = "Swoon / Faces",
|
||||
author = "Swoon",
|
||||
isBlessed = true
|
||||
),
|
||||
StickerPreviewDataFactory.installedPack(
|
||||
title = "Bandit the Cat",
|
||||
author = "Agnes Lee",
|
||||
isBlessed = true
|
||||
),
|
||||
StickerPreviewDataFactory.installedPack(
|
||||
title = "Day by Day",
|
||||
author = "Miguel Ángel Camprubí"
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,12 +46,12 @@ final class StickerManagementAdapter extends SectionedRecyclerViewAdapter<String
|
||||
|
||||
private final List<StickerSection> sections = new ArrayList<StickerSection>(3) {{
|
||||
StickerSection yourStickers = new StickerSection(TAG_YOUR_STICKERS,
|
||||
R.string.StickerManagementAdapter_installed_stickers,
|
||||
R.string.StickerManagement_installed_stickers_header,
|
||||
R.string.StickerManagementAdapter_no_stickers_installed,
|
||||
new ArrayList<>(),
|
||||
0);
|
||||
StickerSection messageStickers = new StickerSection(TAG_MESSAGE_STICKERS,
|
||||
R.string.StickerManagementAdapter_stickers_you_received,
|
||||
R.string.StickerManagement_stickers_you_received_header,
|
||||
R.string.StickerManagementAdapter_stickers_from_incoming_messages_will_appear_here,
|
||||
new ArrayList<>(),
|
||||
yourStickers.size());
|
||||
@@ -127,17 +127,17 @@ final class StickerManagementAdapter extends SectionedRecyclerViewAdapter<String
|
||||
@NonNull List<StickerPackRecord> blessedPacks)
|
||||
{
|
||||
StickerSection yourStickers = new StickerSection(TAG_YOUR_STICKERS,
|
||||
R.string.StickerManagementAdapter_installed_stickers,
|
||||
R.string.StickerManagement_installed_stickers_header,
|
||||
R.string.StickerManagementAdapter_no_stickers_installed,
|
||||
installedPacks,
|
||||
0);
|
||||
StickerSection blessedStickers = new StickerSection(TAG_BLESSED_STICKERS,
|
||||
R.string.StickerManagementAdapter_signal_artist_series,
|
||||
R.string.StickerManagement_signal_artist_series_header,
|
||||
0,
|
||||
blessedPacks,
|
||||
yourStickers.size());
|
||||
StickerSection messageStickers = new StickerSection(TAG_MESSAGE_STICKERS,
|
||||
R.string.StickerManagementAdapter_stickers_you_received,
|
||||
R.string.StickerManagement_stickers_you_received_header,
|
||||
R.string.StickerManagementAdapter_stickers_from_incoming_messages_will_appear_here,
|
||||
availablePacks,
|
||||
yourStickers.size() + (blessedPacks.isEmpty() ? 0 : blessedStickers.size()));
|
||||
@@ -270,7 +270,7 @@ final class StickerManagementAdapter extends SectionedRecyclerViewAdapter<String
|
||||
}
|
||||
|
||||
title.setText(titleBuilder);
|
||||
author.setText(stickerPack.authorOptional.orElse(itemView.getResources().getString(R.string.StickerManagementAdapter_unknown)));
|
||||
author.setText(stickerPack.authorOptional.orElse(itemView.getResources().getString(R.string.StickerManagement_author_unknown)));
|
||||
divider.setVisibility(lastInList ? View.GONE : View.VISIBLE);
|
||||
|
||||
requestManager.load(new DecryptableUri(stickerPack.cover.uri))
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package org.thoughtcrime.securesms.stickers;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
@@ -16,19 +15,16 @@ import org.thoughtcrime.securesms.jobmanager.JobManager;
|
||||
import org.thoughtcrime.securesms.jobs.MultiDeviceStickerPackOperationJob;
|
||||
import org.thoughtcrime.securesms.jobs.StickerPackDownloadJob;
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
final class StickerManagementRepository {
|
||||
|
||||
private final Context context;
|
||||
private final StickerTable stickerDatabase;
|
||||
private final AttachmentTable attachmentDatabase;
|
||||
|
||||
StickerManagementRepository(@NonNull Context context) {
|
||||
this.context = context.getApplicationContext();
|
||||
StickerManagementRepository() {
|
||||
this.stickerDatabase = SignalDatabase.stickers();
|
||||
this.attachmentDatabase = SignalDatabase.attachments();
|
||||
}
|
||||
|
||||
@@ -10,13 +10,36 @@ import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import org.thoughtcrime.securesms.database.model.StickerPackRecord
|
||||
import org.thoughtcrime.securesms.stickers.AvailableStickerPack.DownloadStatus
|
||||
|
||||
class StickerManagementViewModelV2 : ViewModel() {
|
||||
private val stickerManagementRepo = StickerManagementRepository()
|
||||
|
||||
private val _uiState = MutableStateFlow(StickerManagementUiState())
|
||||
val uiState: StateFlow<StickerManagementUiState> = _uiState.asStateFlow()
|
||||
|
||||
init {
|
||||
stickerManagementRepo.deleteOrphanedStickerPacks()
|
||||
stickerManagementRepo.fetchUnretrievedReferencePacks()
|
||||
loadStickerPacks()
|
||||
}
|
||||
|
||||
private fun loadStickerPacks() {
|
||||
stickerManagementRepo.getStickerPacks { result ->
|
||||
_uiState.value = _uiState.value.copy(
|
||||
availableBlessedPacks = result.blessedPacks
|
||||
.map { AvailableStickerPack(record = it, isBlessed = true, downloadStatus = DownloadStatus.NotDownloaded) },
|
||||
availablePacks = result.availablePacks
|
||||
.map { AvailableStickerPack(record = it, isBlessed = false, downloadStatus = DownloadStatus.NotDownloaded) },
|
||||
installedPacks = result.installedPacks
|
||||
.mapIndexed { index, record -> InstalledStickerPack(record = record, isBlessed = BlessedPacks.contains(record.packId), sortOrder = index) }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class StickerManagementUiState(
|
||||
val availableBlessedPacks: List<AvailableStickerPack> = emptyList(),
|
||||
val availablePacks: List<AvailableStickerPack> = emptyList(),
|
||||
val installedPacks: List<InstalledStickerPack> = emptyList(),
|
||||
val isMultiSelectMode: Boolean = false
|
||||
@@ -35,7 +58,8 @@ data class AvailableStickerPack(
|
||||
}
|
||||
|
||||
data class InstalledStickerPack(
|
||||
private val record: StickerPackRecord,
|
||||
val record: StickerPackRecord,
|
||||
val isBlessed: Boolean,
|
||||
val sortOrder: Int,
|
||||
val isSelected: Boolean
|
||||
val isSelected: Boolean = false
|
||||
)
|
||||
|
||||
@@ -0,0 +1,260 @@
|
||||
/*
|
||||
* Copyright 2025 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.thoughtcrime.securesms.stickers
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material3.Checkbox
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.ColorFilter
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import org.signal.core.ui.compose.IconButtons
|
||||
import org.signal.core.ui.compose.SignalPreview
|
||||
import org.signal.core.ui.compose.theme.SignalTheme
|
||||
import org.signal.core.util.nullIfBlank
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.compose.GlideImage
|
||||
import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader.DecryptableUri
|
||||
import org.thoughtcrime.securesms.stickers.AvailableStickerPack.DownloadStatus
|
||||
|
||||
@Composable
|
||||
fun StickerPackSectionHeader(
|
||||
text: String,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
Text(
|
||||
text = text,
|
||||
style = MaterialTheme.typography.titleSmall,
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.background(MaterialTheme.colorScheme.surface)
|
||||
.padding(horizontal = 24.dp, vertical = 12.dp)
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun AvailableStickerPackRow(
|
||||
pack: AvailableStickerPack,
|
||||
onStartDownloadClick: () -> Unit = {},
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = modifier
|
||||
.background(MaterialTheme.colorScheme.surface)
|
||||
.padding(start = 24.dp, top = 12.dp, end = 12.dp, bottom = 12.dp)
|
||||
) {
|
||||
StickerPackInfo(
|
||||
coverImageUri = DecryptableUri(pack.record.cover.uri),
|
||||
title = pack.record.title,
|
||||
author = pack.record.author.nullIfBlank(),
|
||||
showOfficialBadge = pack.isBlessed,
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
|
||||
// TODO show TransferProgressIndicator based on download state
|
||||
IconButtons.IconButton(
|
||||
size = 48.dp,
|
||||
onClick = onStartDownloadClick,
|
||||
content = {
|
||||
Image(
|
||||
imageVector = ImageVector.vectorResource(id = R.drawable.symbol_arrow_circle_down_24),
|
||||
colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onSurface),
|
||||
contentDescription = stringResource(R.string.StickerManagement_accessibility_download_pack, pack.record.title)
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun InstalledStickerPackRow(
|
||||
pack: InstalledStickerPack,
|
||||
multiSelectModeEnabled: Boolean = false,
|
||||
checked: Boolean = false,
|
||||
onCheckedChange: (Boolean) -> Unit = {},
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = modifier
|
||||
.background(MaterialTheme.colorScheme.surface)
|
||||
.padding(12.dp)
|
||||
) {
|
||||
if (multiSelectModeEnabled) {
|
||||
Checkbox(
|
||||
checked = checked,
|
||||
onCheckedChange = onCheckedChange,
|
||||
modifier = Modifier.padding(end = 8.dp)
|
||||
)
|
||||
}
|
||||
|
||||
StickerPackInfo(
|
||||
coverImageUri = DecryptableUri(pack.record.cover.uri),
|
||||
title = pack.record.title,
|
||||
author = pack.record.author.nullIfBlank(),
|
||||
showOfficialBadge = pack.isBlessed,
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
|
||||
Icon(
|
||||
imageVector = ImageVector.vectorResource(id = R.drawable.ic_drag_handle),
|
||||
contentDescription = stringResource(R.string.StickerManagement_accessibility_drag_handle),
|
||||
tint = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
modifier = modifier
|
||||
.padding(horizontal = 12.dp)
|
||||
.size(24.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun StickerPackInfo(
|
||||
coverImageUri: DecryptableUri,
|
||||
title: String,
|
||||
author: String?,
|
||||
showOfficialBadge: Boolean,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
Row(
|
||||
modifier = modifier.fillMaxWidth()
|
||||
) {
|
||||
GlideImage(
|
||||
model = coverImageUri,
|
||||
modifier = Modifier
|
||||
.padding(end = 16.dp)
|
||||
.size(56.dp)
|
||||
)
|
||||
|
||||
Column(
|
||||
modifier = Modifier.align(Alignment.CenterVertically)
|
||||
) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Text(
|
||||
text = title,
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
color = MaterialTheme.colorScheme.onSurface
|
||||
)
|
||||
|
||||
if (showOfficialBadge) {
|
||||
Image(
|
||||
imageVector = ImageVector.vectorResource(id = R.drawable.ic_official_20),
|
||||
contentDescription = null,
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 4.dp)
|
||||
.size(16.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
Text(
|
||||
text = author ?: stringResource(R.string.StickerManagement_author_unknown),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SignalPreview
|
||||
@Composable
|
||||
private fun StickerPackSectionHeaderPreview() = SignalTheme {
|
||||
StickerPackSectionHeader(
|
||||
text = "Signal artist series"
|
||||
)
|
||||
}
|
||||
|
||||
@SignalPreview
|
||||
@Composable
|
||||
private fun AvailableStickerPackRowPreviewBlessed() = SignalTheme {
|
||||
AvailableStickerPackRow(
|
||||
pack = StickerPreviewDataFactory.availablePack(
|
||||
title = "Swoon / Faces",
|
||||
author = "Swoon",
|
||||
isBlessed = true
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@SignalPreview
|
||||
@Composable
|
||||
private fun AvailableStickerPackRowPreviewNotBlessed() = SignalTheme {
|
||||
AvailableStickerPackRow(
|
||||
pack = StickerPreviewDataFactory.availablePack(
|
||||
title = "Day by Day",
|
||||
author = "Miguel Ángel Camprubí",
|
||||
isBlessed = false,
|
||||
downloadStatus = DownloadStatus.NotDownloaded
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@SignalPreview
|
||||
@Composable
|
||||
private fun AvailableStickerPackRowPreviewDownloading() = SignalTheme {
|
||||
AvailableStickerPackRow(
|
||||
pack = StickerPreviewDataFactory.availablePack(
|
||||
title = "Bandit the Cat",
|
||||
author = "Agnes Lee",
|
||||
isBlessed = false,
|
||||
downloadStatus = DownloadStatus.InProgress(progressPercent = 22.0)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@SignalPreview
|
||||
@Composable
|
||||
private fun AvailableStickerPackRowPreviewDownloaded() = SignalTheme {
|
||||
AvailableStickerPackRow(
|
||||
pack = StickerPreviewDataFactory.availablePack(
|
||||
title = "Bandit the Cat",
|
||||
author = "Agnes Lee",
|
||||
isBlessed = false,
|
||||
downloadStatus = DownloadStatus.Downloaded
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@SignalPreview
|
||||
@Composable
|
||||
private fun InstalledStickerPackRowPreview() = SignalTheme {
|
||||
InstalledStickerPackRow(
|
||||
multiSelectModeEnabled = false,
|
||||
pack = StickerPreviewDataFactory.installedPack(
|
||||
title = "Bandit the Cat",
|
||||
author = "Agnes Lee",
|
||||
isBlessed = true
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@SignalPreview
|
||||
@Composable
|
||||
private fun InstalledStickerPackRowSelectModePreview() = SignalTheme {
|
||||
InstalledStickerPackRow(
|
||||
multiSelectModeEnabled = true,
|
||||
pack = StickerPreviewDataFactory.installedPack(
|
||||
title = "Bandit the Cat",
|
||||
author = "Agnes Lee",
|
||||
isBlessed = true
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -177,7 +177,7 @@ public final class StickerPackPreviewActivity extends PassphraseRequiredActivity
|
||||
private void initViewModel(@NonNull String packId, @NonNull String packKey) {
|
||||
viewModel = new ViewModelProvider(this, new StickerPackPreviewViewModel.Factory(getApplication(),
|
||||
new StickerPackPreviewRepository(this),
|
||||
new StickerManagementRepository(this))
|
||||
new StickerManagementRepository())
|
||||
).get(StickerPackPreviewViewModel.class);
|
||||
|
||||
viewModel.getStickerManifest(packId, packKey).observe(this, manifest -> {
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright 2025 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.thoughtcrime.securesms.stickers
|
||||
|
||||
import org.thoughtcrime.securesms.database.model.StickerPackRecord
|
||||
import org.thoughtcrime.securesms.database.model.StickerRecord
|
||||
import java.util.UUID
|
||||
|
||||
/**
|
||||
* Generates sample sticker data to use in compose UI previews.
|
||||
*/
|
||||
object StickerPreviewDataFactory {
|
||||
fun availablePack(
|
||||
packId: String = UUID.randomUUID().toString(),
|
||||
title: String,
|
||||
author: String,
|
||||
isBlessed: Boolean = false,
|
||||
downloadStatus: AvailableStickerPack.DownloadStatus = AvailableStickerPack.DownloadStatus.NotDownloaded
|
||||
): AvailableStickerPack = AvailableStickerPack(
|
||||
record = StickerPackRecord(
|
||||
packId = packId,
|
||||
packKey = "packKey",
|
||||
title = title,
|
||||
author = author,
|
||||
cover = StickerRecord(
|
||||
rowId = 11,
|
||||
packId = packId,
|
||||
packKey = "packKey",
|
||||
stickerId = 111,
|
||||
emoji = "",
|
||||
contentType = "image/webp",
|
||||
size = 1111,
|
||||
isCover = true
|
||||
),
|
||||
isInstalled = false
|
||||
),
|
||||
isBlessed = isBlessed,
|
||||
downloadStatus = downloadStatus
|
||||
)
|
||||
|
||||
fun installedPack(
|
||||
packId: String = UUID.randomUUID().toString(),
|
||||
title: String,
|
||||
author: String,
|
||||
isBlessed: Boolean = false
|
||||
): InstalledStickerPack = InstalledStickerPack(
|
||||
record = StickerPackRecord(
|
||||
packId = packId,
|
||||
packKey = "packKey",
|
||||
title = title,
|
||||
author = author,
|
||||
cover = StickerRecord(
|
||||
rowId = 11,
|
||||
packId = packId,
|
||||
packKey = "packKey",
|
||||
stickerId = 111,
|
||||
emoji = "",
|
||||
contentType = "image/webp",
|
||||
size = 1111,
|
||||
isCover = true
|
||||
),
|
||||
isInstalled = true
|
||||
),
|
||||
isBlessed = isBlessed,
|
||||
sortOrder = 0
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user