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,