Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Verified Commit 5784a2ec authored by Saalim Quadri's avatar Saalim Quadri
Browse files

feat: Use progressButton fill

parent d4f98835
Loading
Loading
Loading
Loading
Loading
+42 −41
Original line number Diff line number Diff line
@@ -19,13 +19,14 @@ package foundation.e.apps.ui.compose.components

import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.animateColorAsState
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.tween
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.togetherWith
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Arrangement
@@ -33,6 +34,7 @@ import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
@@ -42,8 +44,6 @@ import androidx.compose.foundation.layout.widthIn
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.Star
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
@@ -277,19 +277,18 @@ private fun PrimaryActionArea(
    val accentColor = MaterialTheme.colorScheme.tertiary
    val outlineColor = MaterialTheme.colorScheme.onBackground.copy(alpha = 0.25f)
    val animationDuration = 250
    val hasProgress = uiState.progressFraction > 0f

    val targetContainerColor = when {
        hasProgress -> accentColor.copy(alpha = 0.12f)
        uiState.isFilledStyle && uiState.enabled -> accentColor
        uiState.isFilledStyle -> accentColor.copy(alpha = 0.12f)
        else -> Color.Transparent
    }

    val targetBorderColor = when {
        uiState.isFilledStyle -> Color.Transparent
        else -> outlineColor
    }

    val targetTextColor = when {
        hasProgress && uiState.progressFraction >= 0.5f -> MaterialTheme.colorScheme.onPrimary
        hasProgress -> accentColor
        uiState.isFilledStyle -> MaterialTheme.colorScheme.onPrimary
        else -> accentColor
    }
@@ -300,41 +299,51 @@ private fun PrimaryActionArea(
        label = "containerColor"
    )

    val animatedBorderColor = animateColorAsState(
        targetValue = targetBorderColor,
        animationSpec = tween(durationMillis = animationDuration),
        label = "borderColor"
    )

    val animatedTextColor = animateColorAsState(
        targetValue = targetTextColor,
        animationSpec = tween(durationMillis = animationDuration),
        label = "textColor"
    )

    val animatedProgress = animateFloatAsState(
        targetValue = uiState.progressFraction.coerceIn(0f, 1f),
        animationSpec = tween(durationMillis = animationDuration),
        label = "progressFraction"
    )

    Column(horizontalAlignment = Alignment.End) {
        Button(
            onClick = onPrimaryClick,
            enabled = uiState.enabled,
        val buttonShape = RoundedCornerShape(4.dp)
        val showBorder = !hasProgress && !uiState.isFilledStyle
        val borderColor = outlineColor
        Box(
            modifier = Modifier
                .widthIn(min = 88.dp)
                .height(40.dp),
            shape = RoundedCornerShape(4.dp),
            colors = ButtonDefaults.buttonColors(
                containerColor = animatedContainerColor.value,
                contentColor = animatedTextColor.value,
                disabledContainerColor = animatedContainerColor.value,
                disabledContentColor = animatedTextColor.value.copy(alpha = 0.38f),
            ),
            border = BorderStroke(1.dp, animatedBorderColor.value),
            contentPadding = ButtonDefaults.ContentPadding,
                .then(
                    if (hasProgress) Modifier.width(88.dp)
                    else Modifier.widthIn(min = 88.dp)
                )
                .height(40.dp)
                .clip(buttonShape)
                .background(animatedContainerColor.value)
                .then(
                    if (showBorder) Modifier.border(1.dp, borderColor, buttonShape)
                    else Modifier
                )
                .clickable(enabled = uiState.enabled, onClick = onPrimaryClick),
            contentAlignment = Alignment.Center,
        ) {
            if (hasProgress) {
                Box(
                    modifier = Modifier
                        .fillMaxHeight()
                        .fillMaxWidth(animatedProgress.value.coerceIn(0f, 1f))
                        .align(Alignment.CenterStart)
                        .background(accentColor)
                )
            }

            val showSpinner = uiState.isInProgress && uiState.label.isBlank()
            val isProgressLabel = uiState.label.endsWith("%")
            // Stable keys here
            val animationKey = when {
                showSpinner -> "spinner"
                isProgressLabel -> "progress"
                else -> uiState.label
            }
            AnimatedContent(
@@ -354,16 +363,6 @@ private fun PrimaryActionArea(
                        )
                    }

                    "progress" -> {
                        Text(
                            text = uiState.label,
                            maxLines = 1,
                            overflow = TextOverflow.Clip,
                            color = animatedTextColor.value,
                            style = MaterialTheme.typography.labelLarge,
                        )
                    }

                    else -> {
                        Text(
                            text = targetKey,
@@ -371,6 +370,7 @@ private fun PrimaryActionArea(
                            overflow = TextOverflow.Clip,
                            color = animatedTextColor.value,
                            style = MaterialTheme.typography.labelLarge,
                            modifier = Modifier.padding(horizontal = 16.dp),
                        )
                    }
                }
@@ -423,6 +423,7 @@ data class PrimaryActionUiState(
    val isFilledStyle: Boolean,
    val showMore: Boolean = false,
    val actionIntent: InstallButtonAction = InstallButtonAction.NoOp,
    val progressFraction: Float = 0f,
)

// --- Previews ---
+1 −1
Original line number Diff line number Diff line
@@ -625,7 +625,6 @@ private fun Application.toSearchResultUiState(buttonState: InstallButtonState):
        isPrivacyLoading = false,
        primaryAction = PrimaryActionUiState(
            label = buttonState.label.text
                ?: buttonState.progressPercentText
                ?: buttonState.label.resId?.let { stringResource(id = it) }
                ?: "",
            enabled = buttonState.enabled,
@@ -633,6 +632,7 @@ private fun Application.toSearchResultUiState(buttonState: InstallButtonState):
            isFilledStyle = buttonState.style == InstallButtonStyle.AccentFill,
            showMore = false,
            actionIntent = buttonState.actionIntent,
            progressFraction = buttonState.progressFraction,
        ),
        iconUrl = iconUrl,
        placeholderResId = null,
+3 −1
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ data class InstallButtonState(
    val style: InstallButtonStyle = InstallButtonStyle.AccentOutline,
    val showProgressBar: Boolean = false,
    val progressPercentText: String? = null,
    val progressFraction: Float = 0f,
    val actionIntent: InstallButtonAction = InstallButtonAction.NoOp,
    @StringRes val snackbarMessageId: Int? = null,
    val dialogType: InstallDialogType? = null,
@@ -222,8 +223,9 @@ fun mapAppToInstallState(
        )

        Status.DOWNLOADING, Status.DOWNLOADED -> InstallButtonState(
            label = ButtonLabel(resId = if (percentLabel == null) R.string.cancel else null, text = percentLabel),
            label = ButtonLabel(resId = R.string.cancel),
            progressPercentText = percentLabel,
            progressFraction = progressPercent?.coerceIn(0, 100)?.div(100f) ?: 0f,
            enabled = true,
            style = styleFor(status, enabled = true),
            actionIntent = InstallButtonAction.CancelDownload,