diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 23d6214b10..e3e96fb28d 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -95,7 +95,6 @@ dependencies { implementation(deps.lifecycle.common.java8) implementation(deps.lifecycle.viewModel.ktx) implementation(deps.lifecycle.compose) - implementation(deps.androidx.palette) /** Compose libraries */ implementation(deps.compose.constraintLayout) diff --git a/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/ui/BriefNetworksList.kt b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/ui/BriefNetworksList.kt index 4d6738f03d..ea2c77ed2a 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/ui/BriefNetworksList.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/ui/BriefNetworksList.kt @@ -3,19 +3,20 @@ package com.tangem.tap.features.tokens.impl.presentation.ui import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut -import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material.Icon import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.key import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource import com.tangem.core.ui.res.TangemTheme import com.tangem.tap.features.tokens.impl.presentation.states.NetworkItemState @@ -69,11 +70,21 @@ internal fun BriefNetworksList( */ @Composable internal fun BriefNetworkItem(model: NetworkItemState, modifier: Modifier = Modifier) { + val isAdded = model is NetworkItemState.ManageContent && model.isAdded.value Box(modifier = modifier.size(size = TangemTheme.dimens.size20)) { - Image( + if (!isAdded) { + Box( + modifier = Modifier + .size(TangemTheme.dimens.size20) + .clip(CircleShape) + .background(TangemTheme.colors.control.unchecked), + ) + } + Icon( painter = painterResource(id = model.iconResId.value), contentDescription = null, modifier = Modifier.size(size = TangemTheme.dimens.size20), + tint = if (isAdded) Color.Unspecified else TangemTheme.colors.text.tertiary, ) if (model.isMainNetwork) { diff --git a/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/ui/TokenItem.kt b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/ui/TokenItem.kt index 42577a5372..862b0c874f 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/ui/TokenItem.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/ui/TokenItem.kt @@ -1,6 +1,5 @@ package com.tangem.tap.features.tokens.impl.presentation.ui -import android.graphics.drawable.Drawable import androidx.compose.animation.* import androidx.compose.foundation.background import androidx.compose.foundation.isSystemInDarkTheme @@ -20,16 +19,15 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.constraintlayout.compose.ConstraintLayout import androidx.constraintlayout.compose.Dimension -import androidx.core.graphics.ColorUtils -import androidx.core.graphics.drawable.toBitmap -import androidx.palette.graphics.Palette import coil.compose.SubcomposeAsyncImage import coil.request.ImageRequest import com.tangem.core.ui.components.CurrencyPlaceholderIcon import com.tangem.core.ui.res.TangemTheme +import com.tangem.core.ui.utils.ImageBackgroundContrastChecker import com.tangem.tap.common.compose.extensions.toPx import com.tangem.tap.features.tokens.impl.presentation.states.TokenItemState import com.tangem.wallet.R +import kotlinx.coroutines.launch /** [REDACTED_AUTHOR] @@ -130,6 +128,7 @@ private fun Icon(name: String, iconUrl: String, onContrastCalculate: (Color) -> val iconModifier = modifier.size(size = TangemTheme.dimens.size46) val screenBackgroundColor = TangemTheme.colors.background.primary.toArgb() val isDarkTheme = isSystemInDarkTheme() + val coroutineScope = rememberCoroutineScope() SubcomposeAsyncImage( modifier = iconModifier, @@ -141,11 +140,13 @@ private fun Icon(name: String, iconUrl: String, onContrastCalculate: (Color) -> .listener( onSuccess = { _, result -> if (isDarkTheme) { - setContrastBackgroundIfNeeded( - drawable = result.drawable, - screenBackgroundColor = screenBackgroundColor, - onContrastCalculate = onContrastCalculate, - ) + coroutineScope.launch { + val color = ImageBackgroundContrastChecker( + drawable = result.drawable, + backgroundColor = screenBackgroundColor, + ).getContrastColorIfNeeded(isDarkTheme) + onContrastCalculate(color) + } } }, ) @@ -156,26 +157,6 @@ private fun Icon(name: String, iconUrl: String, onContrastCalculate: (Color) -> ) } -private fun setContrastBackgroundIfNeeded( - drawable: Drawable, - screenBackgroundColor: Int, - onContrastCalculate: (Color) -> Unit, -) { - Palette.Builder(drawable.toBitmap()).generate { palette -> - val color = palette?.getDominantColor(screenBackgroundColor) ?: screenBackgroundColor - val contrast = ColorUtils.calculateContrast(color, screenBackgroundColor) - val colorToSet = if (contrast > LOW_CONTRAST_RATIO) { - Color.Transparent - } else { - Color.White - } - onContrastCalculate(colorToSet) - } -} - -// https://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef -private const val LOW_CONTRAST_RATIO = 1.5f - @Composable private fun Title(title: String, modifier: Modifier = Modifier) { Text( diff --git a/app/src/main/res/drawable/bg_half_transparent_overlay.xml b/app/src/main/res/drawable/bg_half_transparent_overlay.xml index 4b5937d793..1e819d64aa 100644 --- a/app/src/main/res/drawable/bg_half_transparent_overlay.xml +++ b/app/src/main/res/drawable/bg_half_transparent_overlay.xml @@ -2,8 +2,8 @@ \ No newline at end of file diff --git a/app/src/main/res/values-night/colors.xml b/app/src/main/res/values-night/colors.xml index 1b1466a874..29535c674f 100644 --- a/app/src/main/res/values-night/colors.xml +++ b/app/src/main/res/values-night/colors.xml @@ -51,4 +51,8 @@ #333333 + + #000000 + #0F0000 + #19000000 \ No newline at end of file diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 5d49d88d30..7d26f9c9d0 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -80,6 +80,10 @@ #000000 #00000000 - + d #1B1D1C + + #FFFFFF + #F0FFFF + #19FFFFFF \ No newline at end of file diff --git a/core/ui/build.gradle.kts b/core/ui/build.gradle.kts index 4f39028ae4..3a09e91308 100644 --- a/core/ui/build.gradle.kts +++ b/core/ui/build.gradle.kts @@ -18,6 +18,7 @@ dependencies { /** AndroidX libraries */ implementation(deps.androidx.fragment.ktx) implementation(deps.androidx.paging.runtime) + implementation(deps.androidx.palette) /** Compose */ implementation(deps.compose.constraintLayout) diff --git a/core/ui/src/main/java/com/tangem/core/ui/utils/ImageBackgroundContrastChecker.kt b/core/ui/src/main/java/com/tangem/core/ui/utils/ImageBackgroundContrastChecker.kt new file mode 100644 index 0000000000..5fab6c4856 --- /dev/null +++ b/core/ui/src/main/java/com/tangem/core/ui/utils/ImageBackgroundContrastChecker.kt @@ -0,0 +1,44 @@ +package com.tangem.core.ui.utils + +import android.graphics.Bitmap +import android.graphics.drawable.Drawable +import androidx.compose.ui.graphics.Color +import androidx.core.graphics.ColorUtils +import androidx.core.graphics.drawable.toBitmap +import androidx.palette.graphics.Palette +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext + +class ImageBackgroundContrastChecker( + private val image: Bitmap, + private val backgroundColor: Int, +) { + constructor(drawable: Drawable, backgroundColor: Int) : this( + image = drawable.toBitmap(), + backgroundColor = backgroundColor, + ) + + suspend fun getContrastColorIfNeeded(isDarkTheme: Boolean): Color { + return if (isLowContrast()) { + if (isDarkTheme) Color.White else Color.Black + } else { + Color.Transparent + } + } + + suspend fun isLowContrast(): Boolean { + val palette = generatePaletteAsync(bitmap = image) + val color = palette.getDominantColor(backgroundColor) + val contrast = ColorUtils.calculateContrast(color, backgroundColor) + return contrast <= LOW_CONTRAST_RATIO + } + + private suspend fun generatePaletteAsync(bitmap: Bitmap): Palette = withContext(Dispatchers.Default) { + return@withContext Palette.Builder(bitmap).generate() + } + + private companion object { + // https://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef + private const val LOW_CONTRAST_RATIO = 1.5f + } +} \ No newline at end of file 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 23647ff1d8..ea3a63e8dd 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 @@ -5,17 +5,20 @@ import androidx.annotation.StringRes import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.background import androidx.compose.foundation.clickable +import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.material.Divider import androidx.compose.material.Scaffold import androidx.compose.material.Text -import androidx.compose.runtime.Composable +import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.ColorFilter import androidx.compose.ui.graphics.ColorMatrix +import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource @@ -29,11 +32,13 @@ import com.tangem.core.ui.components.SpacerW2 import com.tangem.core.ui.components.appbar.ExpandableSearchView import com.tangem.core.ui.extensions.getActiveIconRes import com.tangem.core.ui.res.TangemTheme +import com.tangem.core.ui.utils.ImageBackgroundContrastChecker import com.tangem.feature.swap.models.Network import com.tangem.feature.swap.models.SwapSelectTokenStateHolder import com.tangem.feature.swap.models.TokenBalanceData import com.tangem.feature.swap.models.TokenToSelect import com.tangem.feature.swap.presentation.R +import kotlinx.coroutines.launch @Composable fun SwapSelectTokenScreen( @@ -66,9 +71,10 @@ fun SwapSelectTokenScreen( @OptIn(ExperimentalFoundationApi::class) @Composable private fun ListOfTokens(state: SwapSelectTokenStateHolder, modifier: Modifier = Modifier) { + val screenBackgroundColor = TangemTheme.colors.background.secondary LazyColumn( modifier = modifier - .background(color = TangemTheme.colors.background.secondary) + .background(color = screenBackgroundColor) .fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally, ) { @@ -77,7 +83,15 @@ private fun ListOfTokens(state: SwapSelectTokenStateHolder, modifier: Modifier = } itemsIndexed(items = state.addedTokens) { index, item -> - TokenItem(token = item, network = state.network, onTokenClick = { state.onTokenSelected(item.id) }) + TokenItem( + token = item, + network = state.network, + screenBackgroundColor = screenBackgroundColor, + onTokenClick = { + state + .onTokenSelected(item.id) + }, + ) if (index != state.addedTokens.lastIndex) { Divider( @@ -92,7 +106,12 @@ private fun ListOfTokens(state: SwapSelectTokenStateHolder, modifier: Modifier = } itemsIndexed(items = state.otherTokens) { index, item -> - TokenItem(token = item, network = state.network, onTokenClick = { state.onTokenSelected(item.id) }) + TokenItem( + token = item, + network = state.network, + screenBackgroundColor = screenBackgroundColor, + onTokenClick = { state.onTokenSelected(item.id) }, + ) if (index != state.otherTokens.lastIndex) { Divider( color = TangemTheme.colors.stroke.primary, @@ -121,7 +140,7 @@ private fun Header(@StringRes title: Int) { @Suppress("LongMethod") @Composable -private fun TokenItem(token: TokenToSelect, network: Network, onTokenClick: () -> Unit) { +private fun TokenItem(token: TokenToSelect, network: Network, screenBackgroundColor: Color, onTokenClick: () -> Unit) { Row( modifier = Modifier .fillMaxWidth() @@ -134,6 +153,7 @@ private fun TokenItem(token: TokenToSelect, network: Network, onTokenClick: () - ) { TokenIcon( token = token, + screenBackgroundColor = screenBackgroundColor, iconPlaceholder = if (token.isNative) getActiveIconRes(network.blockchainId) else null, ) @@ -187,13 +207,21 @@ private fun TokenItem(token: TokenToSelect, network: Network, onTokenClick: () - @Suppress("MagicNumber") @Composable -private fun TokenIcon(token: TokenToSelect, @DrawableRes iconPlaceholder: Int?) { +private fun TokenIcon(token: TokenToSelect, screenBackgroundColor: Color, @DrawableRes iconPlaceholder: Int?) { + var iconBackgroundColor by remember { mutableStateOf(Color.Transparent) } + val isDarkTheme = isSystemInDarkTheme() + val coroutineScope = rememberCoroutineScope() + val data = token.iconUrl.ifEmpty { iconPlaceholder } Box( modifier = Modifier - .padding(end = TangemTheme.dimens.spacing12), + .padding(end = TangemTheme.dimens.spacing12) + .background( + color = iconBackgroundColor, + shape = TangemTheme.shapes.roundedCorners8, + ), ) { val iconModifier = Modifier .size(TangemTheme.dimens.size40) @@ -208,7 +236,20 @@ private fun TokenIcon(token: TokenToSelect, @DrawableRes iconPlaceholder: Int?) model = ImageRequest.Builder(LocalContext.current) .data(data) .crossfade(true) - .build(), + .allowHardware(false) + .listener( + onSuccess = { _, result -> + if (isDarkTheme) { + coroutineScope.launch { + val color = ImageBackgroundContrastChecker( + drawable = result.drawable, + backgroundColor = screenBackgroundColor.toArgb(), + ).getContrastColorIfNeeded(isDarkTheme) + iconBackgroundColor = color + } + } + }, + ).build(), contentDescription = token.id, loading = { CircleShimmer(modifier = iconModifier) }, error = { CurrencyPlaceholderIcon(modifier = iconModifier, id = token.id) }, 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 be8d01441a..bd57a551b1 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 @@ -5,6 +5,7 @@ import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.* import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape @@ -13,11 +14,11 @@ import androidx.compose.material.Icon import androidx.compose.material.MaterialTheme import androidx.compose.material.Text import androidx.compose.material.ripple.rememberRipple -import androidx.compose.runtime.Composable -import androidx.compose.runtime.remember +import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource @@ -27,15 +28,16 @@ import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import coil.compose.SubcomposeAsyncImage import coil.request.ImageRequest import com.tangem.core.ui.R import com.tangem.core.ui.components.* import com.tangem.core.ui.res.TangemTheme +import com.tangem.core.ui.utils.ImageBackgroundContrastChecker import com.tangem.feature.swap.models.SwapWarning import com.tangem.feature.swap.models.TransactionCardType +import kotlinx.coroutines.launch @Suppress("LongParameterList") @Composable @@ -265,47 +267,13 @@ fun Token( verticalArrangement = Arrangement.Bottom, horizontalAlignment = Alignment.End, ) { - Box( - modifier = Modifier - .padding(end = TangemTheme.dimens.spacing16) - .size(TangemTheme.dimens.size42), - ) { - val tokenImageModifier = Modifier - .align(Alignment.BottomStart) - .size(TangemTheme.dimens.size36) - - val data = tokenIconUrl.ifEmpty { - iconPlaceholder - } - SubcomposeAsyncImage( - modifier = tokenImageModifier, - model = ImageRequest.Builder(LocalContext.current) - .data(data) - .crossfade(true) - .build(), - loading = { CircleShimmer(modifier = tokenImageModifier) }, - contentDescription = tokenCurrency, - ) - - if (networkIconRes != null) { - Box( - modifier = Modifier - .align(Alignment.TopEnd) - .size(TangemTheme.dimens.size18) - .background(color = Color.White, shape = CircleShape), - contentAlignment = Alignment.Center, - ) { - Image( - modifier = Modifier.padding(all = 0.5.dp), - painter = painterResource(id = networkIconRes), - contentDescription = null, - ) - } - } - } - + TokenIcon( + tokenIconUrl = tokenIconUrl, + tokenCurrency = tokenCurrency, + iconPlaceholder = iconPlaceholder, + networkIconRes = networkIconRes, + ) SpacerH4() - Text( text = tokenCurrency, color = TangemTheme.colors.text.primary1, @@ -317,6 +285,75 @@ fun Token( } } +@Composable +private fun TokenIcon( + tokenIconUrl: String, + tokenCurrency: String, + @DrawableRes iconPlaceholder: Int? = null, + @DrawableRes networkIconRes: Int? = null, +) { + val itemBackgroundColor = TangemTheme.colors.background.primary.toArgb() + var iconBackgroundColor by remember { mutableStateOf(Color.Transparent) } + val isDarkTheme = isSystemInDarkTheme() + val coroutineScope = rememberCoroutineScope() + + Box( + modifier = Modifier + .padding(end = TangemTheme.dimens.spacing16) + .size(TangemTheme.dimens.size42), + ) { + val tokenImageModifier = Modifier + .align(Alignment.BottomStart) + .size(TangemTheme.dimens.size36) + .background( + color = iconBackgroundColor, + shape = TangemTheme.shapes.roundedCorners8, + ) + + val data = tokenIconUrl.ifEmpty { + iconPlaceholder + } + SubcomposeAsyncImage( + modifier = tokenImageModifier, + model = ImageRequest.Builder(LocalContext.current) + .data(data) + .crossfade(true) + .allowHardware(false) + .listener( + onSuccess = { _, result -> + if (isDarkTheme) { + coroutineScope.launch { + val color = ImageBackgroundContrastChecker( + drawable = result.drawable, + backgroundColor = itemBackgroundColor, + ).getContrastColorIfNeeded(isDarkTheme) + iconBackgroundColor = color + } + } + }, + ).build(), + loading = { CircleShimmer(modifier = tokenImageModifier) }, + contentDescription = tokenCurrency, + ) + + if (networkIconRes != null) { + Box( + modifier = Modifier + .align(Alignment.TopEnd) + .size(TangemTheme.dimens.size18) + .background(color = TangemTheme.colors.background.primary, shape = CircleShape), + contentAlignment = Alignment.Center, + ) { + Image( + modifier = Modifier.padding(all = TangemTheme.dimens.spacing0_5), + painter = painterResource(id = networkIconRes), + contentDescription = null, + ) + } + } + } +} + @Composable fun ChangeTokenSelector() { Box( diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/TokenIcon.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/TokenIcon.kt index a210927b5b..2a11731a45 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/TokenIcon.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/TokenIcon.kt @@ -3,21 +3,26 @@ package com.tangem.feature.tokendetails.presentation.tokendetails.ui.components import androidx.annotation.DrawableRes import androidx.compose.foundation.Image import androidx.compose.foundation.background +import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.Box import androidx.compose.foundation.shape.CircleShape import androidx.compose.material3.Icon -import androidx.compose.runtime.Composable +import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.ColorFilter +import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import coil.compose.SubcomposeAsyncImage import coil.request.ImageRequest import com.tangem.core.ui.components.CircleShimmer +import com.tangem.core.ui.res.TangemTheme +import com.tangem.core.ui.utils.ImageBackgroundContrastChecker import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenInfoBlockState import com.tangem.features.tokendetails.impl.R +import kotlinx.coroutines.launch @Composable internal fun CurrencyIcon( @@ -131,12 +136,34 @@ private inline fun DefaultCurrencyIcon( crossinline errorIcon: @Composable () -> Unit, modifier: Modifier = Modifier, ) { + val itemBackgroundColor = TangemTheme.colors.background.primary.toArgb() + var iconBackgroundColor by remember { mutableStateOf(Color.Transparent) } + val isDarkTheme = isSystemInDarkTheme() + val coroutineScope = rememberCoroutineScope() + SubcomposeAsyncImage( - modifier = modifier, + modifier = modifier + .background( + color = iconBackgroundColor, + shape = TangemTheme.shapes.roundedCorners8, + ), model = ImageRequest.Builder(context = LocalContext.current) .data(iconData) .crossfade(enable = true) - .build(), + .allowHardware(false) + .listener( + onSuccess = { _, result -> + if (isDarkTheme) { + coroutineScope.launch { + val color = ImageBackgroundContrastChecker( + drawable = result.drawable, + backgroundColor = itemBackgroundColor, + ).getContrastColorIfNeeded(isDarkTheme) + iconBackgroundColor = color + } + } + }, + ).build(), loading = { CircleShimmer() }, error = { errorIcon() }, alpha = alpha, diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/component/token/icon/ContentIcon.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/component/token/icon/ContentIcon.kt index 9f29cbd72b..dd1be11f5a 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/component/token/icon/ContentIcon.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/component/token/icon/ContentIcon.kt @@ -3,20 +3,25 @@ package com.tangem.feature.wallet.presentation.common.component.token.icon import androidx.annotation.DrawableRes import androidx.compose.foundation.Image import androidx.compose.foundation.background +import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.Box import androidx.compose.foundation.shape.CircleShape import androidx.compose.material3.Icon -import androidx.compose.runtime.Composable +import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.ColorFilter +import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import coil.compose.SubcomposeAsyncImage import coil.request.ImageRequest +import com.tangem.core.ui.res.TangemTheme +import com.tangem.core.ui.utils.ImageBackgroundContrastChecker import com.tangem.feature.wallet.impl.R import com.tangem.feature.wallet.presentation.common.state.TokenItemState +import kotlinx.coroutines.launch @Composable internal fun ContentIcon( @@ -133,12 +138,34 @@ private inline fun DefaultCurrencyIcon( crossinline errorIcon: @Composable () -> Unit, modifier: Modifier = Modifier, ) { + var iconBackgroundColor by remember { mutableStateOf(Color.Transparent) } + val itemBackgroundColor = TangemTheme.colors.background.primary.toArgb() + val isDarkTheme = isSystemInDarkTheme() + val coroutineScope = rememberCoroutineScope() + SubcomposeAsyncImage( - modifier = modifier, + modifier = modifier + .background( + color = iconBackgroundColor, + shape = TangemTheme.shapes.roundedCorners8, + ), model = ImageRequest.Builder(context = LocalContext.current) .data(iconData) .crossfade(enable = true) - .build(), + .allowHardware(false) + .listener( + onSuccess = { _, result -> + if (isDarkTheme) { + coroutineScope.launch { + val color = ImageBackgroundContrastChecker( + drawable = result.drawable, + backgroundColor = itemBackgroundColor, + ).getContrastColorIfNeeded(isDarkTheme) + iconBackgroundColor = color + } + } + }, + ).build(), loading = { LoadingIcon() }, error = { errorIcon() }, alpha = alpha,