diff --git a/app/src/main/res/layout/view_wallet_details_buttons_row.xml b/app/src/main/res/layout/view_wallet_details_buttons_row.xml index 9644db6849..7db53ce591 100644 --- a/app/src/main/res/layout/view_wallet_details_buttons_row.xml +++ b/app/src/main/res/layout/view_wallet_details_buttons_row.xml @@ -17,7 +17,7 @@ diff --git a/core/res/src/main/res/values-de/strings.xml b/core/res/src/main/res/values-de/strings.xml index 606fc12069..fd9e93d29e 100644 --- a/core/res/src/main/res/values-de/strings.xml +++ b/core/res/src/main/res/values-de/strings.xml @@ -237,6 +237,7 @@ Abbrechen Akzeptieren Sie haben keinen Zugang zur Kamera erteilt, bitte passen Sie Ihre Datenschutzeinstellungen an + Actions Absenden ein Wallet erstellen Tangem diff --git a/core/res/src/main/res/values-fr/strings.xml b/core/res/src/main/res/values-fr/strings.xml index f4973b4b18..d7669b19de 100644 --- a/core/res/src/main/res/values-fr/strings.xml +++ b/core/res/src/main/res/values-fr/strings.xml @@ -237,6 +237,7 @@ Annuler J\'accepte Vous n\'avez pas octroyé l\'accès à votre caméra, veuillez modifier vos paramètres de confidentialité + Actions Envoyer Créer un portefeuille Tangem diff --git a/core/res/src/main/res/values-it/strings.xml b/core/res/src/main/res/values-it/strings.xml index 216dc84c8b..585f284053 100644 --- a/core/res/src/main/res/values-it/strings.xml +++ b/core/res/src/main/res/values-it/strings.xml @@ -237,6 +237,7 @@ Annulla Accetta Non hai fornito l\'accesso alla tua videocamera, modifica le tue impostazioni sulla privacy + Actions Invia Crea portafoglio Tangem diff --git a/core/res/src/main/res/values-ru/strings.xml b/core/res/src/main/res/values-ru/strings.xml index b27bc3b7f7..5cbbf731a8 100644 --- a/core/res/src/main/res/values-ru/strings.xml +++ b/core/res/src/main/res/values-ru/strings.xml @@ -237,6 +237,7 @@ Отмена Принять Вы не предоставили доступ к камере, пожалуйста, измените настройки конфиденциальности. + Действия Отправить Создать кошелек Tangem diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml index 9614432e50..fc5c6b65d6 100644 --- a/core/res/src/main/res/values/strings.xml +++ b/core/res/src/main/res/values/strings.xml @@ -237,6 +237,7 @@ Cancel Accept You have not given access to your camera, please adjust your privacy settings + Actions Send Create wallet Tangem diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/Warnings.kt b/core/ui/src/main/java/com/tangem/core/ui/components/Warnings.kt index a959f0a897..d8293a9868 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/Warnings.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/Warnings.kt @@ -136,7 +136,7 @@ private fun WarningCardSurface( shape = RoundedCornerShape(TangemTheme.dimens.size12), backgroundColor = TangemTheme.colors.background.primary, elevation = TangemTheme.dimens.elevation2, - onClick = { onClick ?: Unit }, + onClick = onClick ?: {}, enabled = onClick != null, ) { content() diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/converters/TokensDataConverter.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/converters/TokensDataConverter.kt index 4e5deed03d..bc67135496 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/converters/TokensDataConverter.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/converters/TokensDataConverter.kt @@ -14,7 +14,8 @@ class TokensDataConverter( override fun convert(value: FoundTokensState): SwapSelectTokenStateHolder { return SwapSelectTokenStateHolder( - tokens = (value.tokensInWallet + value.loadedTokens).map { tokenWithBalanceToTokenToSelect(it) }, + addedTokens = value.tokensInWallet.map { tokenWithBalanceToTokenToSelect(it) }, + otherTokens = value.loadedTokens.map { tokenWithBalanceToTokenToSelect(it) }, onSearchEntered = onSearchEntered, onTokenSelected = onTokenSelected, ) diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/SwapSelectTokenStateHolder.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/SwapSelectTokenStateHolder.kt index cf80940a59..be315efabf 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/SwapSelectTokenStateHolder.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/SwapSelectTokenStateHolder.kt @@ -1,7 +1,8 @@ package com.tangem.feature.swap.models data class SwapSelectTokenStateHolder( - val tokens: List, + val addedTokens: List, + val otherTokens: List, val onSearchEntered: (String) -> Unit, val onTokenSelected: (String) -> Unit, ) diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/SwapStateHolder.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/SwapStateHolder.kt index 1dc5412e8c..aedfd886dd 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/SwapStateHolder.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/SwapStateHolder.kt @@ -9,6 +9,7 @@ data class SwapStateHolder( val fee: FeeState = FeeState.Empty, val warnings: List = emptyList(), val alert: SwapWarning.GenericWarning? = null, + val updateInProgress: Boolean = false, val permissionState: SwapPermissionState = SwapPermissionState.Empty, val successState: SwapSuccessStateHolder? = null, diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapScreenContent.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapScreenContent.kt index 06d84f65c5..6660e36e01 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapScreenContent.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapScreenContent.kt @@ -78,7 +78,7 @@ internal fun SwapScreenContent(state: SwapStateHolder, onPermissionWarningClick: if (state.warnings.isNotEmpty()) { SwapWarnings( warnings = state.warnings, - onApproveWarningClick = onPermissionWarningClick, + onPermissionWarningClick = onPermissionWarningClick, ) } @@ -119,8 +119,7 @@ internal fun SwapScreenContent(state: SwapStateHolder, onPermissionWarningClick: AnimatedVisibility( visible = keyboard is Keyboard.Opened, - modifier = Modifier - .align(Alignment.BottomCenter), + modifier = Modifier.align(Alignment.BottomCenter), ) { Text( text = stringResource(id = R.string.send_max_amount_label), @@ -147,12 +146,10 @@ internal fun SwapScreenContent(state: SwapStateHolder, onPermissionWarningClick: } } -@OptIn(ExperimentalMaterialApi::class) @Composable private fun MainInfo(state: SwapStateHolder) { Box( - modifier = Modifier - .fillMaxWidth(), + modifier = Modifier.fillMaxWidth(), contentAlignment = Alignment.Center, ) { Column { @@ -182,21 +179,36 @@ private fun MainInfo(state: SwapStateHolder) { }, ) } - Card( - elevation = TangemTheme.dimens.elevation3, - shape = CircleShape, - backgroundColor = TangemTheme.colors.background.plain, - contentColor = TangemTheme.colors.text.primary1, - modifier = Modifier - .size(TangemTheme.dimens.size48), - onClick = state.onChangeCardsClicked, - ) { + SwapButton() + } +} + +@OptIn(ExperimentalMaterialApi::class) +@Composable +private fun SwapButton() { + Card( + elevation = TangemTheme.dimens.elevation3, + shape = CircleShape, + backgroundColor = TangemTheme.colors.background.plain, + contentColor = TangemTheme.colors.text.primary1, + modifier = Modifier.size(TangemTheme.dimens.size48), + onClick = state.onChangeCardsClicked, + enabled = !state.updateInProgress, + ) { + if (state.updateInProgress) { + CircularProgressIndicator( + modifier = Modifier + .size(TangemTheme.dimens.size16) + .padding(TangemTheme.dimens.spacing14), + color = TangemTheme.colors.icon.primary1, + strokeWidth = TangemTheme.dimens.size2, + ) + } else { Icon( - painter = painterResource(id = com.tangem.core.ui.R.drawable.ic_exchange_vertical_24), + painter = painterResource(id = R.drawable.ic_exchange_vertical_24), contentDescription = null, tint = TangemTheme.colors.text.primary1, - modifier = Modifier - .padding(TangemTheme.dimens.spacing12), + modifier = Modifier.padding(TangemTheme.dimens.spacing12), ) } } @@ -226,7 +238,7 @@ private fun FeeItem(feeState: FeeState, currency: String) { @Composable private fun SwapWarnings( warnings: List, - onApproveWarningClick: () -> Unit, + onPermissionWarningClick: () -> Unit, ) { Column( modifier = Modifier @@ -252,7 +264,7 @@ private fun SwapWarnings( modifier = Modifier.size(TangemTheme.dimens.size20), ) }, - onClick = onApproveWarningClick, + onClick = onPermissionWarningClick, ) } is SwapWarning.GenericWarning -> { diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapSelectTokenScreen.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapSelectTokenScreen.kt index 43095f4132..30dca38d3a 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapSelectTokenScreen.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapSelectTokenScreen.kt @@ -1,5 +1,7 @@ package com.tangem.feature.swap.ui +import androidx.annotation.StringRes +import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement @@ -23,6 +25,7 @@ import androidx.compose.ui.graphics.ColorFilter import androidx.compose.ui.graphics.ColorMatrix import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import coil.compose.SubcomposeAsyncImage import coil.request.ImageRequest @@ -57,6 +60,7 @@ fun SwapSelectTokenScreen(state: SwapSelectTokenStateHolder, onBack: () -> Unit) } } +@OptIn(ExperimentalFoundationApi::class) @Composable private fun ListOfTokens(state: SwapSelectTokenStateHolder, modifier: Modifier = Modifier) { LazyColumn( @@ -64,12 +68,25 @@ private fun ListOfTokens(state: SwapSelectTokenStateHolder, modifier: Modifier = .background(color = TangemTheme.colors.background.secondary) .fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally, - ) { - itemsIndexed(items = state.tokens) { index, item -> + stickyHeader { Header(title = R.string.swapping_token_list_your_tokens) } + + itemsIndexed(items = state.addedTokens) { index, item -> TokenItem(token = item, onTokenClick = { state.onTokenSelected(item.id) }) - if (index != state.tokens.lastIndex) { + if (index != state.addedTokens.lastIndex) { + Divider( + color = TangemTheme.colors.stroke.primary, + startIndent = TangemTheme.dimens.spacing54, + ) + } + } + + stickyHeader { Header(title = R.string.swapping_token_list_other_tokens) } + + itemsIndexed(items = state.otherTokens) { index, item -> + TokenItem(token = item, onTokenClick = { state.onTokenSelected(item.id) }) + if (index != state.otherTokens.lastIndex) { Divider( color = TangemTheme.colors.stroke.primary, startIndent = TangemTheme.dimens.spacing54, @@ -79,6 +96,22 @@ private fun ListOfTokens(state: SwapSelectTokenStateHolder, modifier: Modifier = } } +@Composable +private fun Header(@StringRes title: Int) { + Text( + text = stringResource(id = title).uppercase(), + style = TangemTheme.typography.overline, + color = TangemTheme.colors.text.tertiary, + modifier = Modifier + .fillMaxWidth() + .padding( + vertical = TangemTheme.dimens.spacing6, + horizontal = TangemTheme.dimens.spacing16, + ), + textAlign = TextAlign.Start, + ) +} + @Composable private fun TokenItem(token: TokenToSelect, onTokenClick: () -> Unit) { Row( @@ -199,14 +232,13 @@ private val token = TokenToSelect( ), ) -private val tokenNotAvailable = token.copy(available = false) - @Preview @Composable private fun TokenScreenPreview() { SwapSelectTokenScreen( state = SwapSelectTokenStateHolder( - tokens = listOf(token, tokenNotAvailable, token), + addedTokens = listOf(token, token, token), + otherTokens = listOf(token, token, token), onSearchEntered = {}, onTokenSelected = {}, ), diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/TransactionCard.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/TransactionCard.kt index 9a64b57259..878165b841 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/TransactionCard.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/TransactionCard.kt @@ -44,7 +44,6 @@ import androidx.compose.ui.graphics.SolidColor import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalFocusManager -import androidx.compose.ui.res.dimensionResource import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.ParagraphIntrinsics @@ -61,6 +60,7 @@ import com.tangem.core.ui.R import com.tangem.core.ui.components.FontSizeRange import com.tangem.core.ui.components.ResizableText import com.tangem.core.ui.components.SpacerH4 +import com.tangem.core.ui.components.SpacerWMax import com.tangem.core.ui.res.TangemTheme import com.tangem.feature.swap.models.TransactionCardType import com.valentinilk.shimmer.shimmer @@ -136,7 +136,8 @@ private fun Header( modifier = modifier .fillMaxWidth() .padding( - bottom = dimensionResource(id = R.dimen.spacing8), + bottom = TangemTheme.dimens.spacing8, + top = TangemTheme.dimens.spacing12, start = TangemTheme.dimens.spacing16, end = TangemTheme.dimens.spacing16, ), @@ -152,15 +153,26 @@ private fun Header( color = TangemTheme.colors.text.tertiary, maxLines = 1, style = MaterialTheme.typography.subtitle2, - modifier = Modifier.padding(top = TangemTheme.dimens.spacing12), - ) - Text( - text = stringResource(R.string.common_balance, balance), - color = TangemTheme.colors.text.tertiary, - maxLines = 1, - style = MaterialTheme.typography.body2, - modifier = Modifier.padding(top = TangemTheme.dimens.spacing12), ) + SpacerWMax(Modifier.defaultMinSize(minWidth = TangemTheme.dimens.spacing16)) + if (balance.isNotBlank()) { + Text( + text = stringResource(R.string.common_balance, balance), + color = TangemTheme.colors.text.tertiary, + maxLines = 1, + style = MaterialTheme.typography.body2, + ) + } else { + Box( + modifier = Modifier + .size(width = TangemTheme.dimens.size80, height = TangemTheme.dimens.size12) + .shimmer() + .background( + color = TangemTheme.colors.button.secondary, + shape = RoundedCornerShape(TangemTheme.dimens.radius3), + ), + ) + } } } @@ -196,8 +208,7 @@ private fun Content( text = amount, color = TangemTheme.colors.text.primary1, style = TangemTheme.typography.h2, - fontSizeRange = - FontSizeRange(min = 16.sp, max = TangemTheme.typography.h2.fontSize), + fontSizeRange = FontSizeRange(min = 16.sp, max = TangemTheme.typography.h2.fontSize), ) } else { Box( @@ -213,7 +224,7 @@ private fun Content( } is TransactionCardType.SendCard -> { AutoSizeTextField( - amount = amount ?: "1", + amount = amount ?: "", onAmountChange = { type.onAmountChanged(it) }, ) } @@ -279,9 +290,7 @@ private fun AutoSizeTextField(amount: String, onAmountChange: (String) -> Unit) handleColor = Transparent, backgroundColor = TangemTheme.colors.text.secondary.copy(alpha = 0.4f), ) - CompositionLocalProvider( - LocalTextSelectionColors provides customTextSelectionColors, - ) { + CompositionLocalProvider(LocalTextSelectionColors provides customTextSelectionColors) { BasicTextField( value = amount, onValueChange = onAmountChange, @@ -293,11 +302,17 @@ private fun AutoSizeTextField(amount: String, onAmountChange: (String) -> Unit) imeAction = ImeAction.Done, keyboardType = KeyboardType.Decimal, ), - keyboardActions = KeyboardActions( - onDone = { - focusManager.clearFocus() - }, - ), + keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }), + decorationBox = { innerTextField -> + if (amount.isBlank()) { + Text( + text = "0", + color = TangemTheme.colors.text.disabled, + style = TangemTheme.typography.h2, + ) + } + innerTextField() + }, textStyle = TangemTheme.typography.h2.copy( color = TangemTheme.colors.text.primary1, fontSize = shrunkFontSize,