Updated on 2026-08-14
This commit is contained in:
parent
67a80fc097
commit
8ee78ad042
8 changed files with 169 additions and 100 deletions
|
|
@ -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 <reified T> 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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
package com.tangem.core.ui.utils
|
||||
|
||||
const val DEFAULT_ANIMATION_DURATION = 300
|
||||
|
|
@ -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<SendUiState>,
|
||||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue