mirror of
https://github.com/signalapp/Signal-Android.git
synced 2025-12-25 21:48:17 +00:00
Add TransferProgressIndicator composable.
Adds a composable version of `TransferProgressView`.
This commit is contained in:
committed by
Cody Henthorne
parent
3d1895500c
commit
48d26beb77
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright 2025 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.thoughtcrime.securesms.components.transfercontrols
|
||||
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.StrokeCap
|
||||
import androidx.compose.ui.graphics.painter.Painter
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.semantics.clearAndSetSemantics
|
||||
import androidx.compose.ui.semantics.contentDescription
|
||||
import androidx.compose.ui.unit.dp
|
||||
import org.signal.core.ui.compose.clickableContainer
|
||||
import org.thoughtcrime.securesms.R
|
||||
|
||||
/**
|
||||
* A button that can be used to start, cancel, show progress, and show completion of a data transfer.
|
||||
*/
|
||||
@Composable
|
||||
fun TransferProgressIndicator(
|
||||
state: TransferProgressState,
|
||||
modifier: Modifier = Modifier.size(48.dp)
|
||||
) {
|
||||
when (state) {
|
||||
is TransferProgressState.Ready -> StartTransferButton(state, modifier)
|
||||
is TransferProgressState.InProgress -> ProgressIndicator(state, modifier)
|
||||
is TransferProgressState.Complete -> CompleteIcon(state, modifier)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun StartTransferButton(
|
||||
state: TransferProgressState.Ready,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
Box(
|
||||
modifier = modifier
|
||||
.clickableContainer(
|
||||
contentDescription = state.startButtonContentDesc,
|
||||
onClickLabel = state.startButtonOnClickLabel,
|
||||
onClick = state.onStartClick
|
||||
)
|
||||
) {
|
||||
Icon(
|
||||
painter = state.iconPainter,
|
||||
tint = MaterialTheme.colorScheme.onSurface,
|
||||
contentDescription = null,
|
||||
modifier = Modifier
|
||||
.matchParentSize()
|
||||
.padding(12.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ProgressIndicator(
|
||||
state: TransferProgressState.InProgress,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
Box(
|
||||
modifier = modifier
|
||||
.clickableContainer(
|
||||
contentDescription = null,
|
||||
onClickLabel = state.cancelButtonOnClickLabel,
|
||||
onClick = state.onCancelClick
|
||||
)
|
||||
.padding(8.dp)
|
||||
) {
|
||||
Icon(
|
||||
painter = painterResource(R.drawable.symbol_stop_24),
|
||||
tint = MaterialTheme.colorScheme.onSurface,
|
||||
contentDescription = null,
|
||||
modifier = Modifier
|
||||
.matchParentSize()
|
||||
.padding(6.dp)
|
||||
)
|
||||
|
||||
CircularProgressIndicator(
|
||||
progress = { state.progress },
|
||||
strokeWidth = 2.dp,
|
||||
strokeCap = StrokeCap.Round,
|
||||
trackColor = MaterialTheme.colorScheme.surfaceContainerHighest,
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
modifier = Modifier
|
||||
.matchParentSize()
|
||||
.clearAndSetSemantics {
|
||||
contentDescription = state.cancelButtonContentDesc
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun CompleteIcon(
|
||||
state: TransferProgressState.Complete,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
Icon(
|
||||
painter = state.iconPainter,
|
||||
tint = MaterialTheme.colorScheme.onSurface,
|
||||
contentDescription = state.iconContentDesc,
|
||||
modifier = modifier.padding(12.dp)
|
||||
)
|
||||
}
|
||||
|
||||
sealed interface TransferProgressState {
|
||||
data class Ready(
|
||||
val iconPainter: Painter,
|
||||
val startButtonContentDesc: String,
|
||||
val startButtonOnClickLabel: String,
|
||||
val onStartClick: () -> Unit
|
||||
) : TransferProgressState
|
||||
|
||||
data class InProgress(
|
||||
val progress: Float,
|
||||
val cancelButtonContentDesc: String,
|
||||
val cancelButtonOnClickLabel: String,
|
||||
val onCancelClick: () -> Unit = {}
|
||||
) : TransferProgressState
|
||||
|
||||
data class Complete(
|
||||
val iconPainter: Painter,
|
||||
val iconContentDesc: String
|
||||
) : TransferProgressState
|
||||
}
|
||||
@@ -15,6 +15,7 @@ import android.graphics.RectF
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.util.AttributeSet
|
||||
import android.view.View
|
||||
import androidx.annotation.Discouraged
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.graphics.withTranslation
|
||||
import org.signal.core.util.logging.Log
|
||||
@@ -24,6 +25,7 @@ import kotlin.math.roundToInt
|
||||
/**
|
||||
* This displays a circular progress around an icon. The icon is either an upload arrow, a download arrow, or a rectangular stop button.
|
||||
*/
|
||||
@Discouraged("Use TransferProgressIndicator instead.")
|
||||
class TransferProgressView @JvmOverloads constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null,
|
||||
|
||||
@@ -279,7 +279,7 @@ private fun AvailableStickersContentPreview() {
|
||||
title = "Bandit the Cat",
|
||||
author = "Agnes Lee",
|
||||
isBlessed = false,
|
||||
downloadStatus = DownloadStatus.InProgress(progressPercent = 22.0)
|
||||
downloadStatus = DownloadStatus.InProgress(progress = 0.37f)
|
||||
),
|
||||
StickerPreviewDataFactory.availablePack(
|
||||
title = "Day by Day",
|
||||
|
||||
@@ -52,7 +52,7 @@ data class AvailableStickerPack(
|
||||
) {
|
||||
sealed class DownloadStatus {
|
||||
data object NotDownloaded : DownloadStatus()
|
||||
data class InProgress(val progressPercent: Double) : DownloadStatus()
|
||||
data class InProgress(val progress: Float) : DownloadStatus()
|
||||
data object Downloaded : DownloadStatus()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,16 +19,17 @@ 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.painterResource
|
||||
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.components.transfercontrols.TransferProgressIndicator
|
||||
import org.thoughtcrime.securesms.components.transfercontrols.TransferProgressState
|
||||
import org.thoughtcrime.securesms.compose.GlideImage
|
||||
import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader.DecryptableUri
|
||||
import org.thoughtcrime.securesms.stickers.AvailableStickerPack.DownloadStatus
|
||||
@@ -53,6 +54,7 @@ fun StickerPackSectionHeader(
|
||||
fun AvailableStickerPackRow(
|
||||
pack: AvailableStickerPack,
|
||||
onStartDownloadClick: () -> Unit = {},
|
||||
onCancelDownloadClick: () -> Unit = {},
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
Row(
|
||||
@@ -69,15 +71,25 @@ fun AvailableStickerPackRow(
|
||||
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)
|
||||
TransferProgressIndicator(
|
||||
state = when (pack.downloadStatus) {
|
||||
DownloadStatus.NotDownloaded -> TransferProgressState.Ready(
|
||||
iconPainter = painterResource(id = R.drawable.symbol_arrow_circle_down_24),
|
||||
startButtonContentDesc = stringResource(R.string.StickerManagement_accessibility_download),
|
||||
startButtonOnClickLabel = stringResource(R.string.StickerManagement_accessibility_download_pack, pack.record.title),
|
||||
onStartClick = onStartDownloadClick
|
||||
)
|
||||
|
||||
is DownloadStatus.InProgress -> TransferProgressState.InProgress(
|
||||
progress = pack.downloadStatus.progress,
|
||||
cancelButtonContentDesc = stringResource(R.string.StickerManagement_accessibility_cancel),
|
||||
cancelButtonOnClickLabel = stringResource(R.string.StickerManagement_accessibility_cancel_downloading_pack, pack.record.title),
|
||||
onCancelClick = onCancelDownloadClick
|
||||
)
|
||||
|
||||
DownloadStatus.Downloaded -> TransferProgressState.Complete(
|
||||
iconPainter = painterResource(id = R.drawable.symbol_check_24),
|
||||
iconContentDesc = stringResource(R.string.StickerManagement_accessibility_downloaded_checkmark, pack.record.title)
|
||||
)
|
||||
}
|
||||
)
|
||||
@@ -215,7 +227,7 @@ private fun AvailableStickerPackRowPreviewDownloading() = SignalTheme {
|
||||
title = "Bandit the Cat",
|
||||
author = "Agnes Lee",
|
||||
isBlessed = false,
|
||||
downloadStatus = DownloadStatus.InProgress(progressPercent = 22.0)
|
||||
downloadStatus = DownloadStatus.InProgress(progress = 0.37f)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user