diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/buttons/segmentedbutton/SegmentedButton.kt b/core/ui/src/main/java/com/tangem/core/ui/components/buttons/segmentedbutton/SegmentedButton.kt index df18f78ab0..44d622f9eb 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/buttons/segmentedbutton/SegmentedButton.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/buttons/segmentedbutton/SegmentedButton.kt @@ -1,10 +1,16 @@ package com.tangem.core.ui.components.buttons.segmentedbutton +import androidx.compose.animation.animateColorAsState +import androidx.compose.animation.core.Spring +import androidx.compose.animation.core.spring import androidx.compose.foundation.LocalIndication import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.interaction.MutableInteractionSource -import androidx.compose.foundation.layout.* +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.padding import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Text import androidx.compose.runtime.* @@ -58,11 +64,16 @@ inline fun SegmentedButtons( val leftRadius = if (index == 0) TangemTheme.dimens.radius26 else TangemTheme.dimens.radius0 val rightRadius = if (index == config.lastIndex) TangemTheme.dimens.radius26 else TangemTheme.dimens.radius0 + val animateColor by animateColorAsState( + targetValue = if (index == selected) selectedColor else color, + label = "Segmented Button Selected Color Animation", + animationSpec = spring(stiffness = Spring.StiffnessMedium), + ) Box( modifier = Modifier .weight(1f) .background( - color = if (index == selected) selectedColor else color, + color = animateColor, shape = RoundedCornerShape( topStart = leftRadius, topEnd = rightRadius, diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/InputRowRecipient.kt b/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/InputRowRecipient.kt index e58a5bd0a8..c16d459a12 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/InputRowRecipient.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/InputRowRecipient.kt @@ -7,6 +7,7 @@ import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment.Companion.CenterEnd import androidx.compose.ui.Alignment.Companion.CenterVertically import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip @@ -16,6 +17,7 @@ import androidx.compose.ui.tooling.preview.PreviewParameterProvider import com.tangem.core.ui.R import com.tangem.core.ui.components.fields.SimpleTextField import com.tangem.core.ui.components.icons.identicon.IdentIcon +import com.tangem.core.ui.components.inputrow.inner.CrossIcon import com.tangem.core.ui.components.inputrow.inner.DividerContainer import com.tangem.core.ui.components.inputrow.inner.PasteButton import com.tangem.core.ui.extensions.TextReference @@ -73,44 +75,37 @@ fun InputRowRecipient( color = color, ) } - Row( + Box( modifier = Modifier .padding(top = TangemTheme.dimens.spacing8), ) { - AnimatedContent( - targetState = isLoading, - label = "Indicator Show Change", - modifier = Modifier - .align(CenterVertically) - .clip(RoundedCornerShape(TangemTheme.dimens.radius18)) - .size(TangemTheme.dimens.size36) - .background(TangemTheme.colors.background.tertiary), - ) { showIndicator -> - if (showIndicator) { - CircularProgressIndicator( - color = TangemTheme.colors.icon.informative, - modifier = Modifier - .padding(TangemTheme.dimens.spacing8), - ) - } else { - IdentIcon(address = value) - } + Row { + InputIcon( + isLoading = isLoading, + value = value, + ) + SimpleTextField( + value = value, + placeholder = placeholder, + onValueChange = onValueChange, + singleLine = singleLine, + modifier = Modifier + .padding(start = TangemTheme.dimens.spacing12) + .weight(1f) + .align(CenterVertically), + ) + CrossIcon( + onClick = onPasteClick, + modifier = Modifier + .align(CenterVertically) + .padding(start = TangemTheme.dimens.spacing8), + ) } - SimpleTextField( - value = value, - placeholder = placeholder, - onValueChange = onValueChange, - singleLine = singleLine, - modifier = Modifier - .padding(start = TangemTheme.dimens.spacing12) - .weight(1f) - .align(CenterVertically), - ) PasteButton( isPasteButtonVisible = value.isBlank(), onClick = onPasteClick, modifier = Modifier - .align(CenterVertically) + .align(CenterEnd) .padding(start = TangemTheme.dimens.spacing8), ) } @@ -118,6 +113,29 @@ fun InputRowRecipient( } } +@Composable +private fun RowScope.InputIcon(isLoading: Boolean, value: String) { + AnimatedContent( + targetState = isLoading, + label = "Indicator Show Change", + modifier = Modifier + .align(CenterVertically) + .clip(RoundedCornerShape(TangemTheme.dimens.radius18)) + .size(TangemTheme.dimens.size36) + .background(TangemTheme.colors.background.tertiary), + ) { showIndicator -> + if (showIndicator) { + CircularProgressIndicator( + color = TangemTheme.colors.icon.informative, + modifier = Modifier + .padding(TangemTheme.dimens.spacing8), + ) + } else { + IdentIcon(address = value) + } + } +} + //region preview @Preview @Composable diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/inner/PasteButton.kt b/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/inner/PasteButton.kt index 3e4642c061..1d7d0fab95 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/inner/PasteButton.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/inner/PasteButton.kt @@ -1,24 +1,28 @@ package com.tangem.core.ui.components.inputrow.inner +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.core.tween +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.interaction.MutableInteractionSource -import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.material.ripple.rememberRipple import androidx.compose.material3.Icon import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.remember +import androidx.compose.runtime.* import androidx.compose.ui.Modifier import androidx.compose.ui.hapticfeedback.HapticFeedbackType import androidx.compose.ui.platform.LocalClipboardManager import androidx.compose.ui.platform.LocalHapticFeedback import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview import com.tangem.core.ui.R import com.tangem.core.ui.res.TangemTheme +import com.tangem.core.ui.utils.DEFAULT_ANIMATION_DURATION /** * Paste button with cross icon. Retrieves text from clipboard. @@ -33,48 +37,67 @@ fun PasteButton(isPasteButtonVisible: Boolean, onClick: (String) -> Unit, modifi val clipboardManager = LocalClipboardManager.current val hapticFeedback = LocalHapticFeedback.current - if (isPasteButtonVisible) { - Box(modifier = modifier) { - Text( - text = "Paste", - style = TangemTheme.typography.button, - color = TangemTheme.colors.text.primary2, - modifier = Modifier - .background( - color = TangemTheme.colors.button.primary, - shape = TangemTheme.shapes.roundedCornersXMedium, - ) - .padding( - horizontal = TangemTheme.dimens.spacing10, - vertical = TangemTheme.dimens.spacing2, - ) - .clickable( - interactionSource = remember { MutableInteractionSource() }, - indication = rememberRipple(radius = TangemTheme.dimens.radius8), - onClick = { - hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress) - onClick( - clipboardManager - .getText() - ?.toString() - .orEmpty(), - ) - }, - ), - ) - } - } else { - Icon( - painter = painterResource(id = R.drawable.ic_close_24), - tint = TangemTheme.colors.icon.informative, - contentDescription = stringResource(R.string.common_close), - modifier = modifier - .size(TangemTheme.dimens.size20) + AnimatedVisibility( + visible = isPasteButtonVisible, + label = "Paste Button Visibility Animation", + enter = fadeIn(), + exit = fadeOut(animationSpec = tween(DEFAULT_ANIMATION_DURATION)), + modifier = modifier, + ) { + Text( + text = "Paste", + style = TangemTheme.typography.button, + color = TangemTheme.colors.text.primary2, + modifier = Modifier + .background( + color = TangemTheme.colors.button.primary, + shape = TangemTheme.shapes.roundedCornersXMedium, + ) + .padding( + horizontal = TangemTheme.dimens.spacing10, + vertical = TangemTheme.dimens.spacing2, + ) .clickable( interactionSource = remember { MutableInteractionSource() }, - indication = rememberRipple(radius = TangemTheme.dimens.radius10), - onClick = { onClick("") }, + indication = rememberRipple(radius = TangemTheme.dimens.radius8), + onClick = { + hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress) + onClick( + clipboardManager + .getText() + ?.toString() + .orEmpty(), + ) + }, ), ) } +} + +@Composable +fun CrossIcon(onClick: (String) -> Unit, modifier: Modifier = Modifier) { + Icon( + painter = painterResource(id = R.drawable.ic_close_24), + tint = TangemTheme.colors.icon.informative, + contentDescription = stringResource(R.string.common_close), + modifier = modifier + .size(TangemTheme.dimens.size20) + .clickable( + interactionSource = remember { MutableInteractionSource() }, + indication = rememberRipple(radius = TangemTheme.dimens.radius10), + onClick = { onClick("") }, + ), + ) +} + +@Preview +@Composable +private fun PasteButtonPreview() { + var isVisible by remember { mutableStateOf(true) } + TangemTheme { + PasteButton( + isPasteButtonVisible = isVisible, + onClick = { isVisible = !isVisible }, + ) + } } \ No newline at end of file diff --git a/core/ui/src/main/java/com/tangem/core/ui/utils/AnimationUtils.kt b/core/ui/src/main/java/com/tangem/core/ui/utils/AnimationUtils.kt new file mode 100644 index 0000000000..e43855563b --- /dev/null +++ b/core/ui/src/main/java/com/tangem/core/ui/utils/AnimationUtils.kt @@ -0,0 +1,3 @@ +package com.tangem.core.ui.utils + +const val DEFAULT_ANIMATION_DURATION = 300 \ No newline at end of file diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fields/SendAmountFieldMaxAmountConverter.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fields/SendAmountFieldMaxAmountConverter.kt index 6ca3cb3d93..1a9a4d6def 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fields/SendAmountFieldMaxAmountConverter.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fields/SendAmountFieldMaxAmountConverter.kt @@ -5,6 +5,7 @@ import com.tangem.domain.tokens.model.CryptoCurrencyStatus import com.tangem.features.send.impl.presentation.state.SendUiState import com.tangem.utils.Provider import com.tangem.utils.converter.Converter +import com.tangem.utils.isNullOrZero internal class SendAmountFieldMaxAmountConverter( private val currentStateProvider: Provider, @@ -23,6 +24,8 @@ internal class SendAmountFieldMaxAmountConverter( val decimalCryptoValue = cryptoCurrencyStatus.value.amount val decimalFiatValue = cryptoCurrencyStatus.value.fiatAmount + if (decimalCryptoValue.isNullOrZero()) return state + val cryptoValue = decimalCryptoValue?.parseBigDecimal(cryptoDecimals).orEmpty() val fiatValue = decimalFiatValue?.parseBigDecimal(fiatDecimals).orEmpty() return state.copy( diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/SendNavigationButtons.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/SendNavigationButtons.kt index fb4fa79a9f..b0462ca18f 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/SendNavigationButtons.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/SendNavigationButtons.kt @@ -3,6 +3,8 @@ package com.tangem.features.send.impl.presentation.ui import androidx.annotation.StringRes import androidx.compose.animation.AnimatedContent import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.expandHorizontally +import androidx.compose.animation.shrinkHorizontally import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Column @@ -14,6 +16,7 @@ import androidx.compose.material3.Icon import androidx.compose.runtime.Composable import androidx.compose.runtime.State import androidx.compose.runtime.collectAsState +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.hapticfeedback.HapticFeedbackType @@ -54,6 +57,8 @@ private fun SendSecondaryNavigationButton(uiState: SendUiState) { val isCorrectScreen = currentState.value == SendUiStateType.Amount || currentState.value == SendUiStateType.Fee AnimatedVisibility( visible = !isEditingDisabled && isCorrectScreen, + enter = expandHorizontally(expandFrom = Alignment.End), + exit = shrinkHorizontally(shrinkTowards = Alignment.End), ) { Icon( modifier = Modifier diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/amount/SendAmountContent.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/amount/SendAmountContent.kt index 39e83215dc..fa0a7445eb 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/amount/SendAmountContent.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/amount/SendAmountContent.kt @@ -46,6 +46,7 @@ internal fun SendAmountContent( .weight(1f) .height(TangemTheme.dimens.size40), config = amountState.segmentedButtonConfig, + showIndication = false, onClick = { clickIntents.onCurrencyChangeClick(it.isFiat) }, ) { SendAmountCurrencyButton(it) diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/recipient/TextFieldWithPaste.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/recipient/TextFieldWithPaste.kt index c3a49b8da6..6109c5ff50 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/recipient/TextFieldWithPaste.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/recipient/TextFieldWithPaste.kt @@ -1,15 +1,14 @@ package com.tangem.features.send.impl.presentation.ui.recipient 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.* import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment.Companion.CenterEnd import androidx.compose.ui.Alignment.Companion.CenterVertically import androidx.compose.ui.Modifier import com.tangem.core.ui.components.fields.SimpleTextField +import com.tangem.core.ui.components.inputrow.inner.CrossIcon import com.tangem.core.ui.components.inputrow.inner.PasteButton import com.tangem.core.ui.extensions.TextReference import com.tangem.core.ui.extensions.resolveReference @@ -35,40 +34,46 @@ internal fun TextFieldWithPaste( else -> label to TangemTheme.colors.text.secondary } FooterContainer(modifier, footer) { - Row( + Box( modifier = Modifier .background( color = TangemTheme.colors.background.action, shape = TangemTheme.shapes.roundedCornersXMedium, - ), - ) { - Column( - modifier = Modifier - .weight(1f) - .padding(TangemTheme.dimens.spacing12), - ) { - Text( - text = title.resolveReference(), - style = TangemTheme.typography.body2, - color = color, ) - SimpleTextField( - value = value, - placeholder = placeholder, - onValueChange = onValueChange, - readOnly = isReadOnly, + .padding(end = TangemTheme.dimens.spacing16), + ) { + Row { + Column( modifier = Modifier - .fillMaxWidth() - .padding(top = TangemTheme.dimens.spacing6), + .weight(1f) + .padding(TangemTheme.dimens.spacing12), + ) { + Text( + text = title.resolveReference(), + style = TangemTheme.typography.body2, + color = color, + ) + SimpleTextField( + value = value, + placeholder = placeholder, + onValueChange = onValueChange, + readOnly = isReadOnly, + modifier = Modifier + .fillMaxWidth() + .padding(top = TangemTheme.dimens.spacing6), + ) + } + CrossIcon( + onClick = onPasteClick, + modifier = Modifier + .align(CenterVertically), ) } if (!isReadOnly) { PasteButton( isPasteButtonVisible = value.isBlank(), onClick = onPasteClick, - modifier = Modifier - .align(CenterVertically) - .padding(end = TangemTheme.dimens.spacing16), + modifier = Modifier.align(CenterEnd), ) } }