Updated on 2026-08-14

This commit is contained in:
Tangem 2023-11-13 16:22:16 +08:00
parent 2223f38cd9
commit fe8d2719a3
10 changed files with 94 additions and 42 deletions

View file

@ -9,6 +9,8 @@ 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.platform.LocalDensity
import androidx.compose.ui.unit.Dp
import coil.compose.SubcomposeAsyncImage
import coil.request.ImageRequest
import com.tangem.core.ui.components.currency.tokenicon.LoadingIcon
@ -19,16 +21,19 @@ import kotlinx.coroutines.launch
@Composable
internal inline fun DefaultCurrencyIcon(
iconData: Any,
size: Dp,
alpha: Float,
colorFilter: ColorFilter?,
crossinline errorIcon: @Composable () -> Unit,
modifier: Modifier = Modifier,
) {
var iconBackgroundColor by remember { mutableStateOf(Color.Transparent) }
var isBackgroundColorDefined by remember { mutableStateOf(false) }
val itemBackgroundColor = TangemTheme.colors.background.primary.toArgb()
val isDarkTheme = isSystemInDarkTheme()
val coroutineScope = rememberCoroutineScope()
val pixelsSize = with(LocalDensity.current) { size.roundToPx() }
SubcomposeAsyncImage(
modifier = modifier
.background(
@ -38,17 +43,21 @@ internal inline fun DefaultCurrencyIcon(
.clip(TangemTheme.shapes.roundedCorners8),
model = ImageRequest.Builder(context = LocalContext.current)
.data(iconData)
.size(size = pixelsSize)
.memoryCacheKey(key = iconData.toString() + pixelsSize)
.crossfade(enable = true)
.allowHardware(false)
.allowHardware(enable = false)
.listener(
onSuccess = { _, result ->
if (isDarkTheme) {
if (!isBackgroundColorDefined && isDarkTheme) {
coroutineScope.launch {
val color = ImageBackgroundContrastChecker(
drawable = result.drawable,
backgroundColor = itemBackgroundColor,
).getContrastColorIfNeeded(isDarkTheme)
size = pixelsSize,
).getContrastColor(isDarkTheme = true)
iconBackgroundColor = color
isBackgroundColorDefined = true
}
}
},

View file

@ -5,6 +5,7 @@ import androidx.compose.foundation.Image
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.Dp
import com.tangem.core.ui.R
import com.tangem.core.ui.components.currency.DefaultCurrencyIcon
@ -18,21 +19,23 @@ import com.tangem.core.ui.components.currency.DefaultCurrencyIcon
@Composable
fun FiatIcon(
url: String?,
size: Dp,
modifier: Modifier = Modifier,
@DrawableRes fallbackResId: Int = R.drawable.ic_shape_circle,
) {
val iconData: Any = if (url.isNullOrBlank()) fallbackResId else url
DefaultCurrencyIcon(
modifier = modifier,
iconData = iconData,
size = size,
alpha = 1f,
colorFilter = null,
errorIcon = {
Image(
painter = painterResource(id = fallbackResId),
contentDescription = null,
)
},
alpha = 1f,
colorFilter = null,
modifier = modifier,
)
}

View file

@ -14,6 +14,7 @@ import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.res.painterResource
import com.tangem.core.ui.R
import com.tangem.core.ui.components.currency.DefaultCurrencyIcon
import com.tangem.core.ui.res.TangemTheme
@Composable
internal fun ContentIcon(
@ -67,8 +68,10 @@ private fun CoinIcon(
val iconData: Any = if (url.isNullOrBlank()) fallbackResId else url
DefaultCurrencyIcon(
modifier = modifier,
iconData = iconData,
size = TangemTheme.dimens.size36,
alpha = alpha,
colorFilter = colorFilter,
errorIcon = {
Image(
painter = painterResource(id = fallbackResId),
@ -77,8 +80,7 @@ private fun CoinIcon(
contentDescription = null,
)
},
alpha = alpha,
colorFilter = colorFilter,
modifier = modifier,
)
}
@ -94,11 +96,12 @@ private fun TokenIcon(
errorIcon()
} else {
DefaultCurrencyIcon(
modifier = modifier,
iconData = url,
errorIcon = errorIcon,
size = TangemTheme.dimens.size36,
alpha = alpha,
colorFilter = colorFilter,
errorIcon = errorIcon,
modifier = modifier,
)
}
}

View file

@ -13,12 +13,12 @@ class ImageBackgroundContrastChecker(
private val image: Bitmap,
private val backgroundColor: Int,
) {
constructor(drawable: Drawable, backgroundColor: Int) : this(
image = drawable.toBitmap(),
constructor(drawable: Drawable, backgroundColor: Int, size: Int) : this(
image = drawable.toBitmap(width = size, height = size),
backgroundColor = backgroundColor,
)
suspend fun getContrastColorIfNeeded(isDarkTheme: Boolean): Color {
suspend fun getContrastColor(isDarkTheme: Boolean): Color {
return if (isLowContrast()) {
if (isDarkTheme) Color.White else Color.Black
} else {
@ -26,7 +26,7 @@ class ImageBackgroundContrastChecker(
}
}
suspend fun isLowContrast(): Boolean {
private suspend fun isLowContrast(): Boolean {
val palette = generatePaletteAsync(bitmap = image)
val color = palette.getDominantColor(backgroundColor)
val contrast = ColorUtils.calculateContrast(color, backgroundColor)