diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/ResizableText.kt b/core/ui/src/main/java/com/tangem/core/ui/components/ResizableText.kt index 0c4c0c3610..d4d1abb476 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/ResizableText.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/ResizableText.kt @@ -1,14 +1,15 @@ package com.tangem.core.ui.components +import androidx.annotation.FloatRange import androidx.compose.material.LocalTextStyle import androidx.compose.material.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember +import androidx.compose.runtime.* import androidx.compose.ui.Modifier import androidx.compose.ui.draw.drawWithContent import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.TextUnit import androidx.compose.ui.unit.sp @@ -54,6 +55,63 @@ fun ResizableText( ) } +/** + * A Composable function that displays text which can be resized based on its content's overflow. + * + * This function draws text on the screen and checks if it overflows. If the text overflows, + * its font size is reduced recursively until it either fits the available space or reaches a + * specified minimum font size. + */ +@Composable +fun ResizableText( + text: String, + modifier: Modifier = Modifier, + color: Color = Color.Unspecified, + textAlign: TextAlign? = null, + overflow: TextOverflow = TextOverflow.Clip, + softWrap: Boolean = true, + maxLines: Int = Int.MAX_VALUE, + style: TextStyle = LocalTextStyle.current, + minFontSize: TextUnit = TextUnit.Unspecified, + @FloatRange(from = 0.0, to = 1.0, fromInclusive = false, toInclusive = false) + reduceFactor: Double = 0.9, +) { + var fontSize by remember { mutableStateOf(style.fontSize) } + var readyToDraw by remember { mutableStateOf(value = false) } + + Text( + modifier = modifier.drawWithContent { + if (readyToDraw) drawContent() + }, + text = text, + color = color, + fontSize = fontSize, + textAlign = textAlign, + overflow = overflow, + softWrap = softWrap, + maxLines = maxLines, + style = style, + onTextLayout = { result -> + fun reduceFontSize() { + val reducedFontSize = fontSize * reduceFactor + + if (minFontSize != TextUnit.Unspecified && reducedFontSize <= minFontSize) { + fontSize = minFontSize + readyToDraw = true + } else { + fontSize = reducedFontSize + } + } + + if (result.hasVisualOverflow) { + reduceFontSize() + } else { + readyToDraw = true + } + }, + ) +} + data class FontSizeRange( val min: TextUnit, val max: TextUnit, diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/buttons/common/TangemButton.kt b/core/ui/src/main/java/com/tangem/core/ui/components/buttons/common/TangemButton.kt index 6560c617e0..fc114059fe 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/buttons/common/TangemButton.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/buttons/common/TangemButton.kt @@ -1,20 +1,19 @@ package com.tangem.core.ui.components.buttons.common -import androidx.compose.foundation.layout.RowScope -import androidx.compose.foundation.layout.heightIn -import androidx.compose.foundation.layout.requiredSizeIn +import androidx.compose.foundation.layout.* import androidx.compose.material.* import androidx.compose.runtime.Composable -import androidx.compose.runtime.remember +import androidx.compose.runtime.ReadOnlyComposable import androidx.compose.ui.Modifier import androidx.compose.ui.composed +import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.Dp -import androidx.compose.ui.unit.dp -import com.tangem.core.ui.components.SpacerW +import androidx.compose.ui.unit.sp +import com.tangem.core.ui.components.ResizableText import com.tangem.core.ui.res.TangemTheme @Suppress("LongParameterList") @@ -40,31 +39,35 @@ fun TangemButton( colors = colors, contentPadding = size.toContentPadding(icon = icon), ) { + val maxContentSize = getMaxButtonContentSize(buttonTextStyle = textStyle) + ButtonContentContainer( buttonIcon = icon, iconPadding = size.toIconPadding(), showProgress = showProgress, progressIndicator = { CircularProgressIndicator( - modifier = Modifier.buttonContentSize(textStyle), + modifier = Modifier.buttonContentSize(maxContentSize), color = colors.contentColor(enabled = enabled).value, - strokeWidth = TangemTheme.dimens.size4, ) }, text = { - Text( - modifier = Modifier.alignByBaseline(), + ResizableText( + modifier = Modifier + .weight(1f, fill = false) + .heightIn(MinButtonContentSize, maxContentSize), text = text, style = textStyle, color = colors.contentColor(enabled = enabled).value, textAlign = TextAlign.Center, maxLines = 1, overflow = TextOverflow.Ellipsis, + minFontSize = 12.sp, ) }, icon = { iconResId -> Icon( - modifier = Modifier.buttonContentSize(textStyle), + modifier = Modifier.buttonContentSize(maxContentSize), painter = painterResource(id = iconResId), tint = colors.contentColor(enabled = enabled).value, contentDescription = null, @@ -89,26 +92,36 @@ private inline fun RowScope.ButtonContentContainer( } else { if (buttonIcon is TangemButtonIconPosition.Start) { icon(buttonIcon.iconResId) - SpacerW(width = iconPadding) + Spacer(modifier = Modifier.requiredWidth(iconPadding)) } text() if (buttonIcon is TangemButtonIconPosition.End) { - SpacerW(width = iconPadding) + Spacer(modifier = Modifier.requiredWidth(iconPadding)) icon(buttonIcon.iconResId) } } } -private fun Modifier.buttonContentSize(buttonTextStyle: TextStyle): Modifier = composed { - val minContentElementSize = TangemTheme.dimens.size20 - val maxContentElementSize = remember(key1 = buttonTextStyle.lineHeight) { - buttonTextStyle.lineHeight.value.dp + 4.dp +private val MinButtonContentSize: Dp + @Composable + @ReadOnlyComposable + get() = TangemTheme.dimens.size20 + +@Composable +@ReadOnlyComposable +private fun getMaxButtonContentSize(buttonTextStyle: TextStyle): Dp { + val buttonLineHeight = with(LocalDensity.current) { + buttonTextStyle.lineHeight.toDp() } + return buttonLineHeight.coerceAtLeast(MinButtonContentSize) +} + +private fun Modifier.buttonContentSize(maxSize: Dp): Modifier = composed { this.requiredSizeIn( - minWidth = minContentElementSize, - minHeight = minContentElementSize, - maxWidth = maxContentElementSize, - maxHeight = maxContentElementSize, + minWidth = MinButtonContentSize, + minHeight = MinButtonContentSize, + maxWidth = maxSize, + maxHeight = maxSize, ) } \ No newline at end of file