diff --git a/app/build.gradle b/app/build.gradle index 51067545d6..a2c501010a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -118,8 +118,9 @@ dependencies { // Camera implementation 'com.otaliastudios:cameraview:2.6.3' - // Image Loading - Picasso - implementation 'com.squareup.picasso:picasso:2.71828' + // Image Loading + implementation 'io.coil-kt:coil:2.1.0' + implementation 'io.coil-kt:coil-compose:2.1.0' // Firebase implementation platform('com.google.firebase:firebase-bom:26.0.0') @@ -172,9 +173,6 @@ dependencies { implementation "com.github.skydoves:androidveil:1.1.2" - implementation("io.coil-kt:coil:2.0.0-rc01") - implementation("io.coil-kt:coil-compose:2.0.0-rc01") - implementation 'com.github.kirich1409:viewbindingpropertydelegate-noreflection:1.5.6' testImplementation 'junit:junit:4.13.2' diff --git a/app/src/main/assets/tangem-app-config b/app/src/main/assets/tangem-app-config index 985642c135..7f058ec409 160000 --- a/app/src/main/assets/tangem-app-config +++ b/app/src/main/assets/tangem-app-config @@ -1 +1 @@ -Subproject commit 985642c135606ba1f59fd739127aec03024da79b +Subproject commit 7f058ec409b4eaaf8688ecd4bf944ef8d58d3564 diff --git a/app/src/main/java/com/tangem/tap/TapApplication.kt b/app/src/main/java/com/tangem/tap/TapApplication.kt index b58485ab88..2e6c7b534b 100644 --- a/app/src/main/java/com/tangem/tap/TapApplication.kt +++ b/app/src/main/java/com/tangem/tap/TapApplication.kt @@ -1,6 +1,8 @@ package com.tangem.tap import android.app.Application +import coil.ImageLoader +import coil.ImageLoaderFactory import com.appsflyer.AppsFlyerLib import com.google.firebase.ktx.Firebase import com.google.firebase.remoteconfig.ktx.remoteConfig @@ -10,7 +12,7 @@ import com.tangem.blockchain.network.BlockchainSdkRetrofitBuilder import com.tangem.domain.DomainLayer import com.tangem.network.common.MoshiConverter import com.tangem.tap.common.analytics.GlobalAnalyticsHandler -import com.tangem.tap.common.images.PicassoHelper +import com.tangem.tap.common.images.createCoilImageLoader import com.tangem.tap.common.redux.AppState import com.tangem.tap.common.redux.appReducer import com.tangem.tap.common.redux.global.GlobalAction @@ -43,7 +45,7 @@ lateinit var currenciesRepository: CurrenciesRepository lateinit var walletConnectRepository: WalletConnectRepository lateinit var shopService: TangemShopService -class TapApplication : Application() { +class TapApplication : Application(), ImageLoaderFactory { override fun onCreate() { super.onCreate() @@ -61,7 +63,6 @@ class TapApplication : Application() { NetworkConnectivity.createInstance(store, this) preferencesStorage = PreferencesStorage(this) - PicassoHelper.initPicassoWithCaching(this) currenciesRepository = CurrenciesRepository( this, store.state.domainNetworks.tangemTechService ) @@ -75,6 +76,10 @@ class TapApplication : Application() { initAppsFlyer() } + override fun newImageLoader(): ImageLoader { + return createCoilImageLoader(context = this) + } + private fun loadConfigs() { val moshi = MoshiConverter.defaultMoshi() val localLoader = FeaturesLocalLoader(this, moshi) @@ -108,11 +113,6 @@ class TapApplication : Application() { } data class LogConfig( - // disables both [internal, http] - val picasso: Boolean = BuildConfig.DEBUG, - val picassoInternal: Boolean = true, - val picassoHttp: Boolean = true, - + val coil: Boolean = BuildConfig.DEBUG, val storeAction: Boolean = BuildConfig.DEBUG, - ) \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/extensions/Picasso.kt b/app/src/main/java/com/tangem/tap/common/extensions/Picasso.kt deleted file mode 100644 index dbeefadbe8..0000000000 --- a/app/src/main/java/com/tangem/tap/common/extensions/Picasso.kt +++ /dev/null @@ -1,135 +0,0 @@ -package com.tangem.tap.common.extensions - -import android.graphics.* -import android.widget.TextView -import androidx.constraintlayout.utils.widget.ImageFilterView -import com.squareup.picasso.Callback -import com.squareup.picasso.Picasso -import com.squareup.picasso.Transformation -import com.tangem.blockchain.common.Blockchain -import com.tangem.blockchain.common.IconsUtil -import com.tangem.blockchain.common.Token -import com.tangem.domain.common.extensions.toNetworkId -import com.tangem.tap.domain.extensions.getCustomIconUrl -import com.tangem.tap.domain.tokens.getIconUrl -import com.tangem.wallet.R - -fun Picasso.loadCurrenciesIcon( - imageView: ImageFilterView, - textView: TextView, - token: Token? = null, - blockchain: Blockchain, -) { - - val url: String? = if (token != null) { - token.id?.let { getIconUrl(it) } ?: token.getCustomIconUrl() - ?: IconsUtil.getTokenIconUri(blockchain, token)?.toString() - } else { - getIconUrl(blockchain.toNetworkId()) - } - - imageView.setImageDrawable(null) - imageView.colorFilter = null - textView.text = null - - when { - token?.symbol == QCX -> { - this.load(R.drawable.ic_qcx)?.into(imageView) - } - token?.symbol == VOYR -> { - this.load(R.drawable.ic_voyr)?.into(imageView) - } - url != null -> { - if (token != null) { - setTokenImage(imageView, textView, token, blockchain) - } - this.load(url) - .transform(RoundedCornersTransform()) - .noPlaceholder() - ?.into(imageView, - object : Callback { - override fun onError(e: Exception?) { - setOfflineCurrencyImage(imageView, textView, token, blockchain) - } - - override fun onSuccess() { - if (token != null) { - imageView.colorFilter = null - textView.text = null - } - if (blockchain.isTestnet()) imageView.saturation = 0f - } - }) - } - else -> { - setOfflineCurrencyImage(imageView, textView, token, blockchain) - } - } -} - -private const val QCX = "QCX" -private const val VOYR = "VOYRME" - -private fun setOfflineCurrencyImage( - imageView: ImageFilterView, - textView: TextView, - token: Token?, - blockchain: Blockchain, -) { - when (token) { - null -> setBlockchainImage(imageView, textView, blockchain) - else -> setTokenImage(imageView, textView, token, blockchain) - } -} - -private fun setBlockchainImage( - imageView: ImageFilterView, - textView: TextView, - blockchain: Blockchain, -) { - imageView.setImageResource(blockchain.getRoundIconRes()) - imageView.colorFilter = null - if (blockchain.isTestnet()) imageView.saturation = 0f - textView.text = null -} - -private fun setTokenImage( - imageView: ImageFilterView, - textView: TextView, - token: Token, - tokenBlockchain: Blockchain -) { - imageView.setImageResource(R.drawable.shape_circle) - if (tokenBlockchain.isTestnet()) { - imageView.saturation = 0f - } else { - imageView.setColorFilter(token.getColor()) - } - textView.text = token.symbol.take(1) -} - -private class RoundedCornersTransform : Transformation { - - override fun transform(source: Bitmap): Bitmap { - val size = source.width.coerceAtMost(source.height) - val x = (source.width - size) / 2 - val y = (source.height - size) / 2 - val squaredBitmap = Bitmap.createBitmap(source, x, y, size, size) - if (squaredBitmap != source) source.recycle() - - val paint = Paint().apply { - shader = BitmapShader(squaredBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP) - isAntiAlias = true - } - - val rectF = RectF(0f, 0f, source.width.toFloat(), source.height.toFloat()) - val radius = size / 8f - val bitmap = Bitmap.createBitmap(size, size, source.config) - Canvas(bitmap).drawRoundRect(rectF, radius, radius, paint) - squaredBitmap.recycle() - - return bitmap - } - - override fun key(): String = "rounded_corners" -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/extensions/Specific.kt b/app/src/main/java/com/tangem/tap/common/extensions/Specific.kt index b431b780ad..219e9339da 100644 --- a/app/src/main/java/com/tangem/tap/common/extensions/Specific.kt +++ b/app/src/main/java/com/tangem/tap/common/extensions/Specific.kt @@ -53,8 +53,7 @@ fun BigDecimal.toFiatString( fiatCurrencyName: String, formatWithSpaces: Boolean = false ): String { - var fiatValue = rateValue.multiply(this) - fiatValue = fiatValue.setScale(2, RoundingMode.HALF_UP) + val fiatValue = rateValue.multiply(this) return fiatValue.toFormattedFiatValue(fiatCurrencyName, formatWithSpaces) } @@ -67,7 +66,8 @@ fun BigDecimal.toFormattedFiatValue( fiatCurrencyName: String, formatWithSpaces: Boolean = false ): String { - val fiatValue = if (formatWithSpaces) this.formatWithSpaces() else this + val fiatValue = this.setScale(2, RoundingMode.HALF_UP) + .let { if (formatWithSpaces) it.formatWithSpaces() else it } return " ${fiatValue}  $fiatCurrencyName" } diff --git a/app/src/main/java/com/tangem/tap/common/extensions/Token.kt b/app/src/main/java/com/tangem/tap/common/extensions/Token.kt index fdfb83ef77..10897bc069 100644 --- a/app/src/main/java/com/tangem/tap/common/extensions/Token.kt +++ b/app/src/main/java/com/tangem/tap/common/extensions/Token.kt @@ -1,6 +1,8 @@ package com.tangem.tap.common.extensions +import android.graphics.Color import androidx.annotation.ColorInt +import androidx.core.graphics.luminance import androidx.core.graphics.toColorInt import com.tangem.blockchain.common.Token import com.tangem.wallet.R @@ -9,8 +11,13 @@ import com.tangem.wallet.R fun Token.getColor(): Int { return try { ("#" + this.contractAddress.subSequence(2..7).toString()) - .toColorInt() + .toColorInt() } catch (exception: Exception) { R.color.lightGray4 } +} + +@ColorInt +fun Token.getTextColor(): Int { + return if (this.getColor().luminance > 0.5) Color.BLACK else Color.WHITE } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/images/Coil.kt b/app/src/main/java/com/tangem/tap/common/images/Coil.kt new file mode 100644 index 0000000000..64b7b76734 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/common/images/Coil.kt @@ -0,0 +1,50 @@ +package com.tangem.tap.common.images + +import android.content.Context +import android.util.Log +import coil.ImageLoader +import coil.util.Logger +import com.tangem.tap.logConfig +import okhttp3.OkHttpClient +import okhttp3.logging.HttpLoggingInterceptor +import timber.log.Timber + +private const val COIL_LOG_TAG = "COIL" + +fun createCoilImageLoader( + context: Context +): ImageLoader { + return ImageLoader.Builder(context) + .apply { + if (!logConfig.coil) return@apply + + logger(CoilTimberLogger()) + okHttpClient { + OkHttpClient.Builder() + .addNetworkInterceptor( + HttpLoggingInterceptor { message -> + Timber.tag(COIL_LOG_TAG).d(message) + } + .apply { + level = HttpLoggingInterceptor.Level.BODY + } + ) + .build() + + } + } + .build() +} + + +private class CoilTimberLogger : Logger { + + override var level: Int = Log.DEBUG + + override fun log(tag: String, priority: Int, message: String?, throwable: Throwable?) { + with(Timber.tag(COIL_LOG_TAG)) { + throwable?.let { e -> e(e, message) } + message?.let { msg -> d(msg) } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/images/Picasso.kt b/app/src/main/java/com/tangem/tap/common/images/Picasso.kt deleted file mode 100644 index 81c52ca693..0000000000 --- a/app/src/main/java/com/tangem/tap/common/images/Picasso.kt +++ /dev/null @@ -1,68 +0,0 @@ -package com.tangem.tap.common.images - -import android.app.Application -import com.squareup.picasso.OkHttp3Downloader -import com.squareup.picasso.Picasso -import com.tangem.tap.logConfig -import com.tangem.wallet.BuildConfig -import okhttp3.Cache -import okhttp3.CacheControl -import okhttp3.OkHttpClient -import okhttp3.logging.HttpLoggingInterceptor -import timber.log.Timber -import java.io.File -import java.util.concurrent.TimeUnit - -class PicassoHelper { - companion object { - private const val KEEP_CACHE_MAX_DAYS = 7 - - fun initPicassoWithCaching(application: Application) { - val picasso = Picasso.Builder(application) - .downloader(OkHttp3Downloader(getOkHttpForPicasso(application))) - .build() - picasso.isLoggingEnabled = logIsEnabled() - picasso.setIndicatorsEnabled(BuildConfig.DEBUG) - Picasso.setSingletonInstance(picasso) - } - - private fun getOkHttpForPicasso(application: Application): OkHttpClient { - return OkHttpClient.Builder().apply { - cache(Cache(File(application.filesDir, "artworks"), Long.MAX_VALUE)) - callTimeout(15000, TimeUnit.MILLISECONDS) - - if (logIsEnabled()) { - addDebugInterceptors(this) - } - - addInterceptor { chain -> - val cacheControl = CacheControl.Builder() - .maxStale(KEEP_CACHE_MAX_DAYS, TimeUnit.DAYS) - .build() - val origRequest = chain.request() - val neverExpireRequest = origRequest.newBuilder() - .cacheControl(cacheControl) - .build() - chain.proceed(neverExpireRequest) - } - }.build() - - } - - private fun addDebugInterceptors(okHttpBuilder: OkHttpClient.Builder) { - val picassoInterceptor = HttpLoggingInterceptor(PicassoOkHttpLogger()).apply { - level = HttpLoggingInterceptor.Level.BODY - } - okHttpBuilder.addInterceptor(picassoInterceptor) - } - - private fun logIsEnabled(): Boolean = BuildConfig.DEBUG && logConfig.picasso - - } -} - -private class PicassoOkHttpLogger : HttpLoggingInterceptor.Logger { - override fun log(message: String) { - Timber.d(message) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/UrlBitmapLoader.kt b/app/src/main/java/com/tangem/tap/domain/UrlBitmapLoader.kt deleted file mode 100644 index c06d9b0001..0000000000 --- a/app/src/main/java/com/tangem/tap/domain/UrlBitmapLoader.kt +++ /dev/null @@ -1,49 +0,0 @@ -package com.tangem.tap.domain - -import android.graphics.Bitmap -import android.graphics.drawable.Drawable -import android.os.Handler -import android.os.Looper -import com.squareup.picasso.Picasso -import com.squareup.picasso.Target -import com.tangem.common.services.Result - -/** -[REDACTED_AUTHOR] - */ -class UrlBitmapLoader { - private val mainHandler = Handler(Looper.getMainLooper()) - - fun loadBitmap(url: String, callback: (Result) -> Unit) { - val target = DownloadTarget(callback) - protectedFromGarbageCollectorTargets.add(target) - mainHandler.post { Picasso.get().load(url).into(target) } - } - - fun loadBitmap(url: String, target: DownloadTarget) { - protectedFromGarbageCollectorTargets.add(target) - Picasso.get().load(url).into(target) - } - -} - -private val protectedFromGarbageCollectorTargets = mutableListOf() - -// It adds the ability to trigger multiple downloads with a unique callback. -open class DownloadTarget( - val callback: (Result) -> Unit, -) : Target { - - override fun onBitmapLoaded(bitmap: Bitmap, from: Picasso.LoadedFrom) { - callback(Result.Success(bitmap)) - protectedFromGarbageCollectorTargets.remove(this) - } - - override fun onBitmapFailed(e: Exception?, errorDrawable: Drawable?) { - callback.invoke(Result.Failure(e ?: Exception("Unknown exception"))) - protectedFromGarbageCollectorTargets.remove(this) - } - - override fun onPrepareLoad(placeHolderDrawable: Drawable?) { - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/OnboardingNoteFragment.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/note/OnboardingNoteFragment.kt index 3125784ba9..b31dd02832 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/OnboardingNoteFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/note/OnboardingNoteFragment.kt @@ -10,7 +10,7 @@ import androidx.annotation.LayoutRes import androidx.constraintlayout.widget.ConstraintSet import androidx.core.view.isVisible import androidx.transition.TransitionManager -import com.squareup.picasso.Picasso +import coil.load import com.tangem.blockchain.common.Blockchain import com.tangem.tangem_sdk_new.extensions.fadeIn import com.tangem.tangem_sdk_new.extensions.fadeOut @@ -67,11 +67,11 @@ class OnboardingNoteFragment : BaseOnboardingFragment() { override fun newState(state: OnboardingNoteState) { if (activity == null || view == null) return - Picasso.get() - .load(state.cardArtworkUrl) - .error(R.drawable.card_placeholder_black) - .placeholder(R.drawable.card_placeholder_black) - ?.into(binding.onboardingTopContainer.imvFrontCard) + binding.onboardingTopContainer.imvFrontCard.load(state.cardArtworkUrl) { + placeholder(R.drawable.card_placeholder_black) + error(R.drawable.card_placeholder_black) + fallback(R.drawable.card_placeholder_black) + } pbBinding.pbState.max = state.steps.size - 1 pbBinding.pbState.progress = state.progress diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/OnboardingOtherCardsFragment.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/OnboardingOtherCardsFragment.kt index 996fdd67fe..e2b1e015c4 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/OnboardingOtherCardsFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/OnboardingOtherCardsFragment.kt @@ -7,7 +7,7 @@ import androidx.annotation.LayoutRes import androidx.constraintlayout.widget.ConstraintSet import androidx.core.view.isVisible import androidx.transition.TransitionManager -import com.squareup.picasso.Picasso +import coil.load import com.tangem.tap.common.extensions.getDrawableCompat import com.tangem.tap.common.redux.navigation.ShareElement import com.tangem.tap.common.transitions.InternalNoteLayoutTransition @@ -54,11 +54,11 @@ class OnboardingOtherCardsFragment : BaseOnboardingFragment() { resources.getValue(R.dimen.device_scale_factor_for_twins_welcome, typedValue, true) val deviceScaleFactorForWelcomeState = typedValue.float - twinsWidget = TwinsCardWidget(LeapfrogWidget(binding.onboardingTopContainer.cardsContainer), deviceScaleFactorForWelcomeState) { + twinsWidget = TwinsCardWidget( + LeapfrogWidget(binding.onboardingTopContainer.cardsContainer), + deviceScaleFactorForWelcomeState + ) { 285f * deviceScaleFactorForWelcomeState } - btnRefreshBalanceWidget = RefreshBalanceWidget(binding.onboardingTopContainer.onboardingMainContainer) + btnRefreshBalanceWidget = + RefreshBalanceWidget(binding.onboardingTopContainer.onboardingMainContainer) binding.toolbar.title = getText(R.string.twins_recreate_toolbar) - Picasso.get() - .load(Artwork.TWIN_CARD_1) - .error(R.drawable.card_placeholder_black) - .placeholder(R.drawable.card_placeholder_black) - ?.into(binding.onboardingTopContainer.imvTwinFrontCard) + binding.onboardingTopContainer.imvTwinFrontCard.load(Artwork.TWIN_CARD_1) { + placeholder(R.drawable.card_placeholder_black) + error(R.drawable.card_placeholder_black) + fallback(R.drawable.card_placeholder_black) + } - Picasso.get() - .load(Artwork.TWIN_CARD_2) - .error(R.drawable.card_placeholder_white) - .placeholder(R.drawable.card_placeholder_white) - ?.into(binding.onboardingTopContainer.imvTwinBackCard) + binding.onboardingTopContainer.imvTwinBackCard.load(Artwork.TWIN_CARD_2) { + placeholder(R.drawable.card_placeholder_white) + error(R.drawable.card_placeholder_white) + fallback(R.drawable.card_placeholder_white) + } } private fun reconfigureLayoutForTwins(containerBinding: LayoutOnboardingContainerTopBinding) = diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/OnboardingWalletFragment.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/OnboardingWalletFragment.kt index b9691488c5..056d5a28bb 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/OnboardingWalletFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/OnboardingWalletFragment.kt @@ -11,9 +11,9 @@ import androidx.fragment.app.Fragment import androidx.transition.TransitionInflater import androidx.transition.TransitionManager import by.kirich1409.viewbindingdelegate.viewBinding +import coil.load import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.tabs.TabLayoutMediator -import com.squareup.picasso.Picasso import com.tangem.common.CardIdFormatter import com.tangem.common.core.CardIdDisplayFormat import com.tangem.tangem_sdk_new.ui.widget.leapfrogWidget.LeapfrogWidget @@ -22,7 +22,12 @@ import com.tangem.tap.common.extensions.hide import com.tangem.tap.common.extensions.show import com.tangem.tap.features.FragmentOnBackPressedHandler import com.tangem.tap.features.addBackPressHandler -import com.tangem.tap.features.onboarding.products.wallet.redux.* +import com.tangem.tap.features.onboarding.products.wallet.redux.BackupAction +import com.tangem.tap.features.onboarding.products.wallet.redux.BackupState +import com.tangem.tap.features.onboarding.products.wallet.redux.BackupStep +import com.tangem.tap.features.onboarding.products.wallet.redux.OnboardingWalletAction +import com.tangem.tap.features.onboarding.products.wallet.redux.OnboardingWalletState +import com.tangem.tap.features.onboarding.products.wallet.redux.OnboardingWalletStep import com.tangem.tap.features.onboarding.products.wallet.ui.dialogs.AccessCodeDialog import com.tangem.tap.store import com.tangem.wallet.R @@ -124,11 +129,11 @@ class OnboardingWalletFragment : Fragment(R.layout.fragment_onboarding_wallet), } private fun loadImageIntoImageView(url: String?, view: ImageView) { - Picasso.get() - .load(url) - .error(R.drawable.card_placeholder_black) - .placeholder(R.drawable.card_placeholder_black) - ?.into(view) + view.load(url) { + placeholder(R.drawable.card_placeholder_black) + error(R.drawable.card_placeholder_black) + fallback(R.drawable.card_placeholder_black) + } } private fun setupCreateWalletState() = with(binding) { diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/WalletReducer.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/WalletReducer.kt index fe7213d361..04fec99524 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/WalletReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/WalletReducer.kt @@ -217,8 +217,8 @@ private fun internalReduce(action: Action, state: AppState): WalletState { currency = walletBlockchain.currency, ), fiatAmount = fiatAmount, - fiatAmountFormatted = fiatAmount.toFiatRateString( - fiatCurrencyName = store.state.globalState.appCurrency.symbol + fiatAmountFormatted = fiatAmount.toFormattedFiatValue( + fiatCurrencyName = state.globalState.appCurrency.symbol ), amountToCreateAccount = action.amountToCreateAccount, ) @@ -439,7 +439,7 @@ private fun setMultiWalletFiatRate( wallet?.getTokenAmount(currency.token)?.value?.toFiatValue(rate) } if (currencyData.status == BalanceStatus.NoAccount && fiatAmount == null) { - fiatAmount = BigDecimal.ZERO + fiatAmount = BigDecimal.ZERO.setScale(2) } val fiatAmountFormatted = fiatAmount?.toFormattedFiatValue(appCurrency.symbol) diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletDetailsFragment.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletDetailsFragment.kt index 00b0fb8d78..997c042f15 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletDetailsFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletDetailsFragment.kt @@ -1,7 +1,11 @@ package com.tangem.tap.features.wallet.ui import android.os.Bundle -import android.view.* +import android.view.Menu +import android.view.MenuInflater +import android.view.MenuItem +import android.view.View +import android.view.ViewGroup import android.widget.TextView import androidx.activity.OnBackPressedCallback import androidx.annotation.ColorRes @@ -11,20 +15,32 @@ import androidx.fragment.app.Fragment import androidx.recyclerview.widget.LinearLayoutManager import androidx.transition.TransitionInflater import by.kirich1409.viewbindingdelegate.viewBinding -import com.squareup.picasso.Picasso import com.tangem.tangem_sdk_new.extensions.dpToPx import com.tangem.tap.common.SnackbarHandler import com.tangem.tap.common.TestActions -import com.tangem.tap.common.extensions.* +import com.tangem.tap.common.extensions.appendIfNotNull +import com.tangem.tap.common.extensions.beginDelayedTransition +import com.tangem.tap.common.extensions.fitChipsByGroupWidth +import com.tangem.tap.common.extensions.getColor +import com.tangem.tap.common.extensions.getString +import com.tangem.tap.common.extensions.hide +import com.tangem.tap.common.extensions.show +import com.tangem.tap.common.extensions.toQrCode import com.tangem.tap.common.recyclerView.SpaceItemDecoration import com.tangem.tap.common.redux.navigation.NavigationAction import com.tangem.tap.domain.tokens.models.BlockchainNetwork import com.tangem.tap.features.onboarding.getQRReceiveMessage import com.tangem.tap.features.wallet.models.PendingTransaction -import com.tangem.tap.features.wallet.redux.* +import com.tangem.tap.features.wallet.redux.Currency +import com.tangem.tap.features.wallet.redux.ErrorType +import com.tangem.tap.features.wallet.redux.ProgressState +import com.tangem.tap.features.wallet.redux.WalletAction +import com.tangem.tap.features.wallet.redux.WalletData +import com.tangem.tap.features.wallet.redux.WalletState import com.tangem.tap.features.wallet.redux.WalletState.Companion.UNKNOWN_AMOUNT_SIGN import com.tangem.tap.features.wallet.ui.adapters.PendingTransactionsAdapter import com.tangem.tap.features.wallet.ui.adapters.WalletDetailWarningMessagesAdapter +import com.tangem.tap.features.wallet.ui.images.loadCurrencyIcon import com.tangem.tap.features.wallet.ui.test.TestWalletDetails import com.tangem.tap.store import com.tangem.wallet.R @@ -199,9 +215,9 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), } private fun handleCurrencyIcon(wallet: WalletData) = with(binding.lWalletDetails.lBalance) { - Picasso.get().loadCurrenciesIcon( - imageView = ivCurrency, - textView = tvTokenLetter, + loadCurrencyIcon( + currencyImageView = ivCurrency, + currencyTextView = tvTokenLetter, blockchain = wallet.currency.blockchain, token = (wallet.currency as? Currency.Token)?.token ) diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt index 6a113fb7a8..176fa48a14 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt @@ -12,7 +12,7 @@ import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import androidx.transition.TransitionInflater import by.kirich1409.viewbindingdelegate.viewBinding -import com.squareup.picasso.Picasso +import coil.load import com.tangem.tap.MainActivity import com.tangem.tap.common.extensions.show import com.tangem.tap.common.recyclerView.SpaceItemDecoration @@ -165,11 +165,11 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), StoreSubscriber currencyImageView.loadIcon( + iconUrl = getIconUrl(blockchain.toNetworkId()), + placeholderRes = blockchain.getRoundIconRes(), + onStart = { + if (blockchain.isTestnet()) { + currencyImageView.saturation = 0f + } else { + currencyImageView.colorFilter = null + } + } + ) + token.symbol == QCX -> currencyImageView.load(R.drawable.ic_qcx) + token.symbol == VOYR -> currencyImageView.load(R.drawable.ic_voyr) + else -> currencyImageView.loadIcon( + iconUrl = getTokenIconUrl(token, blockchain), + placeholderRes = R.drawable.shape_circle, + onStart = { + currencyTextView.text = token.symbol.take(1) + currencyTextView.setTextColor(token.getTextColor()) + + if (blockchain.isTestnet()) { + currencyImageView.saturation = 0f + } + }, + onError = { + currencyImageView.colorFilter = PorterDuffColorFilter( + /* color = */ + token.getColor(), + /* mode = */ + PorterDuff.Mode.SRC_ATOP, + ) + }, + onSuccess = { + if (!blockchain.isTestnet()) { + currencyImageView.colorFilter = null + } + } + ) + } +} + +private inline fun ImageView.loadIcon( + iconUrl: String?, + placeholderRes: Int, + crossinline onStart: () -> Unit = {}, + crossinline onSuccess: () -> Unit = {}, + crossinline onError: () -> Unit = {}, +) { + ImageRequest.Builder(context) + .data(iconUrl) + .placeholder(placeholderRes) + .error(placeholderRes) + .fallback(placeholderRes) + .transformations( + RoundedCornersTransformation( + topLeft = 32f, + topRight = 32f, + bottomLeft = 32f, + bottomRight = 32f + ) + ) + .listener( + onStart = { onStart() }, + onSuccess = { _, _ -> onSuccess() }, + onError = { _, _ -> onError() } + ) + .target(imageView = this) + .build() + .also(context.imageLoader::enqueue) +} + +private fun getTokenIconUrl(token: Token, blockchain: Blockchain): String? { + return token.id?.let(::getIconUrl) + ?: token.getCustomIconUrl() + ?: IconsUtil.getTokenIconUri(blockchain, token) + ?.toString() +} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 8f60b3bd0b..52a563ad69 100644 --- a/gradle.properties +++ b/gradle.properties @@ -13,4 +13,4 @@ org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryErro org.gradle.parallel=true org.gradle.daemon=true android.useAndroidX=true -android.enableJetifier=true \ No newline at end of file +android.enableJetifier=true