Updated on 2026-08-14

This commit is contained in:
Tangem 2023-09-25 13:16:47 +03:00
parent cf308447a8
commit 74ae074402
7 changed files with 110 additions and 14 deletions

View file

@ -0,0 +1,30 @@
package com.tangem.core.ui.extensions
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
import androidx.compose.ui.platform.LocalHapticFeedback
private typealias Action = () -> Unit
/**
* Returns action with Haptic Feedback
*
* @param state of the content
* @param hapticType haptic effect
* @param onAction action that needs haptic feedback
*/
@Composable
fun rememberHapticFeedback(
state: Any,
onAction: () -> Unit,
hapticType: HapticFeedbackType = HapticFeedbackType.LongPress,
): Action {
val hapticFeedback = LocalHapticFeedback.current
return remember(state) {
{
hapticFeedback.performHapticFeedback(hapticType)
onAction.invoke()
}
}
}

View file

@ -182,6 +182,17 @@ internal object WalletPreviewData {
id = UUID.randomUUID().toString(),
icon = tokenIconState,
name = "Polygon",
onItemClick = {},
onItemLongClick = {},
)
}
val tokenItemNoAddressState by lazy {
TokenItemState.NoAddress(
id = UUID.randomUUID().toString(),
icon = tokenIconState,
name = "Polygon",
onItemLongClick = {},
)
}

View file

@ -9,11 +9,8 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.composed
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
import androidx.compose.ui.platform.LocalHapticFeedback
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
@ -21,6 +18,7 @@ import androidx.constraintlayout.compose.ConstrainedLayoutReference
import androidx.constraintlayout.compose.ConstraintLayout
import androidx.constraintlayout.compose.ConstraintLayoutScope
import androidx.constraintlayout.compose.Dimension
import com.tangem.core.ui.extensions.rememberHapticFeedback
import com.tangem.core.ui.res.TangemTheme
import com.tangem.feature.wallet.presentation.common.WalletPreviewData
import com.tangem.feature.wallet.presentation.common.component.token.TokenCryptoInfoBlock
@ -102,21 +100,36 @@ private fun Modifier.constrainAsOptionsItem(scope: ConstraintLayoutScope, ref: C
private fun Modifier.tokenClickable(state: TokenItemState): Modifier = composed {
when (state) {
is TokenItemState.Content -> {
val hapticFeedback = LocalHapticFeedback.current
val onLongClick = remember(state) {
{
hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
state.onItemLongClick()
}
}
val onLongClick = rememberHapticFeedback(
state = state,
onAction = state.onItemLongClick,
)
this.combinedClickable(
onClick = state.onItemClick,
onLongClick = onLongClick,
)
}
is TokenItemState.Unreachable -> {
val onLongClick = rememberHapticFeedback(
state = state,
onAction = state.onItemLongClick,
)
this.combinedClickable(
onClick = state.onItemClick,
onLongClick = onLongClick,
)
}
is TokenItemState.NoAddress -> {
val onLongClick = rememberHapticFeedback(
state = state,
onAction = state.onItemLongClick,
)
this.combinedClickable(
onClick = {},
onLongClick = onLongClick,
)
}
is TokenItemState.Draggable,
is TokenItemState.Unreachable,
is TokenItemState.Loading,
is TokenItemState.Locked,
-> this
@ -144,6 +157,7 @@ private class TokenConfigProvider : CollectionPreviewParameterProvider<TokenItem
collection = listOf(
WalletPreviewData.tokenItemVisibleState,
WalletPreviewData.tokenItemUnreachableState,
WalletPreviewData.tokenItemNoAddressState,
WalletPreviewData.tokenItemDragState,
WalletPreviewData.tokenItemHiddenState,
WalletPreviewData.loadingTokenItemState,

View file

@ -41,7 +41,9 @@ private fun ContentBlock(state: TokenItemState.ContentState, modifier: Modifier
amount = when (state) {
is TokenItemState.Content -> if (state.tokenOptions.isBalanceHidden) STARS else state.amount
is TokenItemState.Draggable -> state.info.resolveReference()
is TokenItemState.Unreachable -> null
is TokenItemState.Unreachable,
is TokenItemState.NoAddress,
-> null
},
)
}

View file

@ -38,6 +38,7 @@ internal fun TokenFiatInfoBlock(
)
}
is TokenItemState.Unreachable -> UnreachableBlock(modifier = modifier)
is TokenItemState.NoAddress -> NoAddressBlock(modifier = modifier)
is TokenItemState.Loading -> LoadingBlock(modifier = modifier)
is TokenItemState.Locked -> LockedBlock(modifier = modifier)
}
@ -154,6 +155,16 @@ private fun UnreachableBlock(modifier: Modifier = Modifier) {
)
}
@Composable
private fun NoAddressBlock(modifier: Modifier = Modifier) {
Text(
modifier = modifier,
text = stringResource(id = R.string.common_no_address),
style = TangemTypography.body2,
color = TangemTheme.colors.text.tertiary,
)
}
@Composable
private fun LoadingBlock(modifier: Modifier = Modifier) {
NonContentContainer(modifier = modifier) {

View file

@ -71,11 +71,30 @@ internal sealed interface TokenItemState {
* @property id token id
* @property icon token icon state
* @property name token name
* @property onItemClick callback which will be called when an item is clicked
* @property onItemLongClick callback which will be called when an item is long clicked
*/
data class Unreachable(
override val id: String,
override val icon: IconState,
override val name: String,
val onItemClick: () -> Unit,
val onItemLongClick: () -> Unit,
) : ContentState()
/**
* No derivation address state
*
* @property id token id
* @property icon token icon state
* @property name token name
* @property onItemLongClick callback which will be called when an item is long clicked
*/
data class NoAddress(
override val id: String,
override val icon: IconState,
override val name: String,
val onItemLongClick: () -> Unit,
) : ContentState()
/**

View file

@ -27,8 +27,8 @@ internal class CryptoCurrencyStatusToTokenItemConverter(
is CryptoCurrencyStatus.NoQuote,
is CryptoCurrencyStatus.NoAccount,
-> value.mapToTokenItemState()
is CryptoCurrencyStatus.MissedDerivation -> value.mapToNoAddressTokenItemState()
// TODO: Add other token item states, currently not designed
is CryptoCurrencyStatus.MissedDerivation,
is CryptoCurrencyStatus.Unreachable,
is CryptoCurrencyStatus.NoAmount,
-> value.mapToUnreachableTokenItemState()
@ -69,6 +69,15 @@ internal class CryptoCurrencyStatusToTokenItemConverter(
id = currency.id.value,
name = currency.name,
icon = iconStateConverter.convert(value = this),
onItemClick = { clickIntents.onTokenItemClick(currency) },
onItemLongClick = { clickIntents.onTokenItemLongClick(cryptoCurrencyStatus = this) },
)
private fun CryptoCurrencyStatus.mapToNoAddressTokenItemState() = TokenItemState.NoAddress(
id = currency.id.value,
name = currency.name,
icon = iconStateConverter.convert(this),
onItemLongClick = { clickIntents.onTokenItemLongClick(cryptoCurrencyStatus = this) },
)
private fun CryptoCurrencyStatus.getPriceChangeConfig(): PriceChangeConfig {