Bug 1856957 - Translations UI Download Cycle Spinner.

fenix/121.0
iorgamgabriel 9 months ago committed by mergify[bot]
parent e8eb5de884
commit 6894cee460

@ -36,7 +36,10 @@ const val DEFAULT_MAX_LINES = 2
* @param textColor [Color] to apply to the button text.
* @param backgroundColor The background [Color] of the button.
* @param modifier [Modifier] to be applied to the layout.
* @param enabled Controls the enabled state of the button.
* When false, this button will not be clickable.
* @param icon Optional [Painter] used to display a [Icon] before the button text.
* @param iconModifier [Modifier] to be applied to the icon.
* @param tint Tint [Color] to be applied to the icon.
* @param onClick Invoked when the user clicks on the button.
*/
@ -46,7 +49,9 @@ private fun Button(
textColor: Color,
backgroundColor: Color,
modifier: Modifier = Modifier,
enabled: Boolean = true,
icon: Painter? = null,
iconModifier: Modifier = Modifier,
tint: Color,
onClick: () -> Unit,
) {
@ -56,6 +61,7 @@ private fun Button(
androidx.compose.material.Button(
onClick = onClick,
modifier = modifier,
enabled = enabled,
contentPadding = PaddingValues(horizontal = 16.dp, vertical = 12.dp),
elevation = ButtonDefaults.elevation(defaultElevation = 0.dp, pressedElevation = 0.dp),
colors = ButtonDefaults.outlinedButtonColors(
@ -66,6 +72,7 @@ private fun Button(
Icon(
painter = painter,
contentDescription = null,
modifier = iconModifier,
tint = tint,
)
@ -87,18 +94,23 @@ private fun Button(
*
* @param text The button text to be displayed.
* @param modifier [Modifier] to be applied to the layout.
* @param enabled Controls the enabled state of the button.
* When false, this button will not be clickable
* @param textColor [Color] to apply to the button text.
* @param backgroundColor The background [Color] of the button.
* @param icon Optional [Painter] used to display an [Icon] before the button text.
* @param iconModifier [Modifier] to be applied to the icon.
* @param onClick Invoked when the user clicks on the button.
*/
@Composable
fun PrimaryButton(
text: String,
modifier: Modifier = Modifier.fillMaxWidth(),
enabled: Boolean = true,
textColor: Color = FirefoxTheme.colors.textActionPrimary,
backgroundColor: Color = FirefoxTheme.colors.actionPrimary,
icon: Painter? = null,
iconModifier: Modifier = Modifier,
onClick: () -> Unit,
) {
Button(
@ -106,7 +118,9 @@ fun PrimaryButton(
textColor = textColor,
backgroundColor = backgroundColor,
modifier = modifier,
enabled = enabled,
icon = icon,
iconModifier = iconModifier,
tint = FirefoxTheme.colors.iconActionPrimary,
onClick = onClick,
)
@ -117,18 +131,23 @@ fun PrimaryButton(
*
* @param text The button text to be displayed.
* @param modifier [Modifier] to be applied to the layout.
* @param enabled Controls the enabled state of the button.
* When false, this button will not be clickable
* @param textColor [Color] to apply to the button text.
* @param backgroundColor The background [Color] of the button.
* @param icon Optional [Painter] used to display an [Icon] before the button text.
* @param iconModifier [Modifier] to be applied to the icon.
* @param onClick Invoked when the user clicks on the button.
*/
@Composable
fun SecondaryButton(
text: String,
modifier: Modifier = Modifier.fillMaxWidth(),
enabled: Boolean = true,
textColor: Color = FirefoxTheme.colors.textActionSecondary,
backgroundColor: Color = FirefoxTheme.colors.actionSecondary,
icon: Painter? = null,
iconModifier: Modifier = Modifier,
onClick: () -> Unit,
) {
Button(
@ -136,7 +155,9 @@ fun SecondaryButton(
textColor = textColor,
backgroundColor = backgroundColor,
modifier = modifier,
enabled = enabled,
icon = icon,
iconModifier = iconModifier,
tint = FirefoxTheme.colors.iconActionSecondary,
onClick = onClick,
)
@ -147,18 +168,23 @@ fun SecondaryButton(
*
* @param text The button text to be displayed.
* @param modifier [Modifier] to be applied to the layout.
* @param enabled Controls the enabled state of the button.
* When false, this button will not be clickable
* @param textColor [Color] to apply to the button text.
* @param backgroundColor The background [Color] of the button.
* @param icon Optional [Painter] used to display an [Icon] before the button text.
* @param iconModifier [Modifier] to be applied to the icon.
* @param onClick Invoked when the user clicks on the button.
*/
@Composable
fun TertiaryButton(
text: String,
modifier: Modifier = Modifier.fillMaxWidth(),
enabled: Boolean = true,
textColor: Color = FirefoxTheme.colors.textActionTertiary,
backgroundColor: Color = FirefoxTheme.colors.actionTertiary,
icon: Painter? = null,
iconModifier: Modifier = Modifier,
onClick: () -> Unit,
) {
Button(
@ -166,7 +192,9 @@ fun TertiaryButton(
textColor = textColor,
backgroundColor = backgroundColor,
modifier = modifier,
enabled = enabled,
icon = icon,
iconModifier = iconModifier,
tint = FirefoxTheme.colors.iconActionTertiary,
onClick = onClick,
)
@ -177,18 +205,23 @@ fun TertiaryButton(
*
* @param text The button text to be displayed.
* @param modifier [Modifier] to be applied to the layout.
* @param enabled Controls the enabled state of the button.
* When false, this button will not be clickable
* @param textColor [Color] to apply to the button text.
* @param backgroundColor The background [Color] of the button.
* @param icon Optional [Painter] used to display an [Icon] before the button text.
* @param iconModifier [Modifier] to be applied to the icon.
* @param onClick Invoked when the user clicks on the button.
*/
@Composable
fun DestructiveButton(
text: String,
modifier: Modifier = Modifier.fillMaxWidth(),
enabled: Boolean = true,
textColor: Color = FirefoxTheme.colors.textWarningButton,
backgroundColor: Color = FirefoxTheme.colors.actionSecondary,
icon: Painter? = null,
iconModifier: Modifier = Modifier,
onClick: () -> Unit,
) {
Button(
@ -196,7 +229,9 @@ fun DestructiveButton(
textColor = textColor,
backgroundColor = backgroundColor,
modifier = modifier,
enabled = enabled,
icon = icon,
iconModifier = iconModifier,
tint = FirefoxTheme.colors.iconWarningButton,
onClick = onClick,
)

@ -0,0 +1,157 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.fenix.translations
import androidx.compose.animation.core.LinearEasing
import androidx.compose.animation.core.RepeatMode
import androidx.compose.animation.core.animateFloat
import androidx.compose.animation.core.infiniteRepeatable
import androidx.compose.animation.core.rememberInfiniteTransition
import androidx.compose.animation.core.tween
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.material.Icon
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.rotate
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.semantics.clearAndSetSemantics
import androidx.compose.ui.semantics.contentDescription
import androidx.compose.ui.semantics.disabled
import androidx.compose.ui.semantics.role
import androidx.compose.ui.unit.dp
import org.mozilla.fenix.R
import org.mozilla.fenix.compose.annotation.LightDarkPreview
import org.mozilla.fenix.compose.button.PrimaryButton
import org.mozilla.fenix.theme.FirefoxTheme
/**
* Animation duration in milliseconds.
* If it is set to a low number, the speed of the rotation will be higher.
*/
private const val ANIMATION_DURATION_MS = 2000
/**
* Icon for Download indicator.
*
* @param icon [Painter] used to be displayed.
* @param modifier [Modifier] to be applied to the icon layout.
* @param tint Tint [Color] to be applied to the icon.
* @param contentDescription Optional content description for the icon.
*/
@Composable
fun DownloadIconIndicator(
icon: Painter,
modifier: Modifier = Modifier,
tint: Color = FirefoxTheme.colors.iconPrimary,
contentDescription: String? = null,
) {
Icon(
painter = icon,
modifier = modifier.then(
Modifier
.rotate(rotationAnimation()),
),
contentDescription = contentDescription,
tint = tint,
)
}
/**
* Download indicator for translations screens.
* It indicates that the download of the language file is in progress.
*
* @param text The button text to be displayed.
* @param modifier [Modifier] to be applied to the layout.
* @param contentDescription Content description to be applied to the button.
* @param icon Optional [Painter] used to display an [Icon] before the button text.
*/
@Composable
fun DownloadIndicator(
text: String,
modifier: Modifier = Modifier,
contentDescription: String? = null,
icon: Painter? = null,
) {
PrimaryButton(
text = text,
modifier = modifier.then(
Modifier
.clearAndSetSemantics {
disabled()
role = Role.Button
contentDescription?.let { this.contentDescription = contentDescription }
},
),
enabled = false,
icon = icon,
iconModifier = Modifier
.rotate(rotationAnimation()),
onClick = {},
)
}
@Composable
private fun rotationAnimation(): Float {
val infiniteTransition = rememberInfiniteTransition()
val angle by infiniteTransition.animateFloat(
initialValue = 0f,
targetValue = 360f,
animationSpec = infiniteRepeatable(
animation = tween(ANIMATION_DURATION_MS, easing = LinearEasing),
repeatMode = RepeatMode.Restart,
),
)
return angle
}
@Composable
@LightDarkPreview
private fun DownloadIconIndicatorPreview() {
FirefoxTheme {
Column(
modifier = Modifier
.background(FirefoxTheme.colors.layer1)
.padding(16.dp),
verticalArrangement = Arrangement.spacedBy(16.dp),
) {
DownloadIconIndicator(
icon = painterResource(id = R.drawable.mozac_ic_sync_24),
contentDescription = stringResource(
id = R.string.translations_bottom_sheet_translating_in_progress,
),
)
}
}
}
@Composable
@LightDarkPreview
private fun DownloadIndicatorPreview() {
FirefoxTheme {
Column(
modifier = Modifier
.background(FirefoxTheme.colors.layer1)
.padding(16.dp),
verticalArrangement = Arrangement.spacedBy(16.dp),
) {
DownloadIndicator(
modifier = Modifier.padding(horizontal = 16.dp, vertical = 12.dp),
text = stringResource(id = R.string.translations_bottom_sheet_translating_in_progress),
contentDescription = stringResource(
id = R.string.translations_bottom_sheet_translating_in_progress_content_description,
),
icon = painterResource(id = R.drawable.mozac_ic_sync_24),
)
}
}
}

@ -124,4 +124,7 @@
<string name="translations_bottom_sheet_translate_to">Translate to</string>
<string name="translations_bottom_sheet_negative_button">Not now</string>
<string name="translations_bottom_sheet_positive_button">Translate</string>
<string name="translations_bottom_sheet_translating_in_progress">In progress</string>
<string name="translations_bottom_sheet_translating_in_progress_content_description">Translating in Progress</string>
</resources>

Loading…
Cancel
Save