Updated on 2026-08-14
This commit is contained in:
parent
9a14c11e33
commit
c55e5745e9
11 changed files with 90 additions and 86 deletions
|
|
@ -91,9 +91,12 @@ dependencies {
|
|||
// Camera
|
||||
implementation 'com.otaliastudios:cameraview:2.6.3'
|
||||
|
||||
// Image Loading - Picasso
|
||||
implementation 'com.squareup.picasso:picasso:2.71828'
|
||||
|
||||
testImplementation 'junit:junit:4.13'
|
||||
testImplementation "com.google.truth:truth:1.0.1"
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
|
||||
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.tap
|
||||
|
||||
import android.app.Application
|
||||
import com.tangem.tap.common.images.PicassoHelper
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.common.redux.appReducer
|
||||
import com.tangem.tap.network.NetworkConnectivity
|
||||
|
|
@ -24,5 +25,6 @@ class TapApplication : Application() {
|
|||
}
|
||||
NetworkConnectivity.createInstance(store, this)
|
||||
preferencesStorage = PreferencesStorage(this)
|
||||
PicassoHelper.initPicassoWithCaching(this)
|
||||
}
|
||||
}
|
||||
39
app/src/main/java/com/tangem/tap/common/images/Picasso.kt
Normal file
39
app/src/main/java/com/tangem/tap/common/images/Picasso.kt
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
package com.tangem.tap.common.images
|
||||
|
||||
import android.app.Application
|
||||
import com.squareup.picasso.OkHttp3Downloader
|
||||
import com.squareup.picasso.Picasso
|
||||
import okhttp3.Cache
|
||||
import okhttp3.CacheControl
|
||||
import okhttp3.OkHttpClient
|
||||
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.setSingletonInstance(picasso)
|
||||
}
|
||||
|
||||
private fun getOkHttpForPicasso(application: Application): OkHttpClient {
|
||||
val okHttpBuilder = OkHttpClient.Builder()
|
||||
okHttpBuilder.cache(Cache(File(application.filesDir, "artworks"), Long.MAX_VALUE))
|
||||
okHttpBuilder.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)
|
||||
}
|
||||
return okHttpBuilder.build()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,17 +2,14 @@ package com.tangem.tap.domain
|
|||
|
||||
import com.tangem.blockchain.common.Wallet
|
||||
import com.tangem.blockchain.common.WalletManager
|
||||
import com.tangem.commands.Card
|
||||
import com.tangem.commands.CardStatus
|
||||
import com.tangem.commands.common.network.Result
|
||||
import com.tangem.commands.common.network.TangemService
|
||||
import com.tangem.common.extensions.toHexString
|
||||
import com.tangem.tap.TapConfig
|
||||
import com.tangem.tap.common.redux.global.CryptoCurrencyName
|
||||
import com.tangem.tap.common.redux.global.FiatCurrencyName
|
||||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
import com.tangem.tap.domain.tasks.ScanNoteResponse
|
||||
import com.tangem.tap.features.wallet.redux.Artwork
|
||||
import com.tangem.tap.features.wallet.redux.PayIdState
|
||||
import com.tangem.tap.features.wallet.redux.WalletAction
|
||||
import com.tangem.tap.network.NetworkConnectivity
|
||||
|
|
@ -26,7 +23,6 @@ import java.math.BigDecimal
|
|||
class TapWalletManager {
|
||||
private val payIdManager = PayIdManager()
|
||||
private val coinMarketCapService = CoinMarketCapService()
|
||||
private val tangemService = TangemService()
|
||||
|
||||
suspend fun loadWalletData() {
|
||||
val walletManager = store.state.globalState.scanNoteResponse?.walletManager
|
||||
|
|
@ -37,21 +33,6 @@ class TapWalletManager {
|
|||
updateWallet(walletManager)
|
||||
}
|
||||
|
||||
suspend fun loadArtwork(card: Card, artworkId: String) {
|
||||
val result =
|
||||
tangemService.getArtwork(card.cardId, card.cardPublicKey!!.toHexString(), artworkId)
|
||||
withContext(Dispatchers.Main) {
|
||||
when (result) {
|
||||
is Result.Success -> {
|
||||
store.dispatch(WalletAction.LoadArtwork.Success(
|
||||
Artwork(artworkId, result.data.byteStream().readBytes())
|
||||
))
|
||||
}
|
||||
is Result.Failure -> store.dispatch(WalletAction.LoadArtwork.Failure)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun loadPayId() {
|
||||
val result = loadPayIdIfNeeded()
|
||||
result?.let { handlePayIdResult(it) }
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ import com.tangem.tap.network.NetworkStateChanged
|
|||
import com.tangem.tap.scope
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.tap.tangemSdkManager
|
||||
import com.tangem.wallet.R
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
|
@ -46,21 +45,6 @@ val walletMiddleware: Middleware<AppState> = { dispatch, state ->
|
|||
store.state.globalState.tapWalletManager.loadFiatRate(store.state.globalState.appCurrency)
|
||||
}
|
||||
}
|
||||
is WalletAction.LoadArtwork -> {
|
||||
if (action.artworkId != null) {
|
||||
scope.launch {
|
||||
store.state.globalState.tapWalletManager.loadArtwork(
|
||||
action.card, action.artworkId
|
||||
)
|
||||
}
|
||||
} else {
|
||||
val artworkRes = R.drawable.card_default
|
||||
store.dispatch(WalletAction.LoadArtwork.Success(Artwork(
|
||||
artworkId = artworkRes.toString(), artworkResId = artworkRes
|
||||
)))
|
||||
}
|
||||
|
||||
}
|
||||
is WalletAction.CreateWallet -> {
|
||||
scope.launch {
|
||||
val result = tangemSdkManager.createWallet(
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.tangem.tap.features.wallet.redux
|
|||
|
||||
import com.tangem.blockchain.common.AmountType
|
||||
import com.tangem.common.extensions.isZero
|
||||
import com.tangem.common.extensions.toHexString
|
||||
import com.tangem.tap.common.extensions.toFiatString
|
||||
import com.tangem.tap.common.extensions.toFormattedCurrencyString
|
||||
import com.tangem.tap.common.extensions.toFormattedString
|
||||
|
|
@ -12,6 +13,8 @@ import com.tangem.tap.features.wallet.models.toPendingTransactions
|
|||
import com.tangem.tap.features.wallet.ui.BalanceStatus
|
||||
import com.tangem.tap.features.wallet.ui.BalanceWidgetData
|
||||
import com.tangem.tap.features.wallet.ui.TokenData
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
import org.rekotlin.Action
|
||||
|
||||
class WalletReducer {
|
||||
|
|
@ -165,8 +168,18 @@ private fun internalReduce(action: Action, state: AppState): WalletState {
|
|||
token = newState.currencyData.token?.copy(fiatAmount = tokenFiatAmount)
|
||||
))
|
||||
}
|
||||
is WalletAction.LoadArtwork.Success -> {
|
||||
newState = newState.copy(cardImage = action.artwork)
|
||||
is WalletAction.LoadArtwork -> {
|
||||
// TODO: form URL in Card SDK
|
||||
var artworkAddress = "https://verify.tangem.com/card/artwork"
|
||||
artworkAddress += "?artworkId=${action.artworkId}"
|
||||
artworkAddress += "&CID=${store.state.globalState.scanNoteResponse?.card?.cardId}"
|
||||
artworkAddress += "&publicKey=${store.state.globalState.scanNoteResponse?.card?.cardPublicKey?.toHexString()}"
|
||||
val artwork = if (action.artworkId != null) {
|
||||
Artwork(artworkId = artworkAddress)
|
||||
} else {
|
||||
Artwork(artworkResId = R.drawable.card_default)
|
||||
}
|
||||
newState = newState.copy(cardImage = artwork)
|
||||
}
|
||||
is WalletAction.ShowQrCode -> {
|
||||
newState = newState.copy(
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ data class AddressData(
|
|||
)
|
||||
|
||||
data class Artwork(
|
||||
val artworkId: String,
|
||||
val artworkId: String? = null,
|
||||
val artwork: Bitmap? = null,
|
||||
val artworkResId: Int? = null
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -85,6 +85,7 @@ class BalanceWidget(
|
|||
fragment.tv_status_error_message.text = data.errorMessage
|
||||
|
||||
showStatus(R.id.group_error)
|
||||
fragment.tv_status_error_message.show(!data.errorMessage.isNullOrBlank())
|
||||
}
|
||||
BalanceStatus.EmptyCard -> {
|
||||
fragment.l_balance.hide()
|
||||
|
|
|
|||
|
|
@ -35,7 +35,6 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), StoreSubscriber<Walle
|
|||
|
||||
private var dialog: Dialog? = null
|
||||
private var snackbar: Snackbar? = null
|
||||
private var artworkId: String? = null
|
||||
|
||||
private lateinit var viewAdapter: PendingTransactionsAdapter
|
||||
|
||||
|
|
@ -187,25 +186,15 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), StoreSubscriber<Walle
|
|||
}
|
||||
|
||||
private fun setupCardImage(cardImage: Artwork?) {
|
||||
if (cardImage?.artwork != null) {
|
||||
if (cardImage.artworkId != this.artworkId) {
|
||||
prepareShowingCardImage(cardImage.artworkId)
|
||||
iv_card.setImageBitmap(cardImage.artwork)
|
||||
}
|
||||
} else if (cardImage?.artworkResId != null) {
|
||||
if (cardImage.artworkId != this.artworkId) {
|
||||
prepareShowingCardImage(cardImage.artworkId)
|
||||
iv_card.setImageDrawable(getDrawable(cardImage.artworkResId))
|
||||
}
|
||||
val address = cardImage?.artworkId ?: cardImage?.artworkResId
|
||||
val picassoRequest = when (address) {
|
||||
is String -> Picasso.get().load(address)
|
||||
is Int -> Picasso.get().load(address)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
private fun prepareShowingCardImage(artworkId: String) {
|
||||
this.artworkId = artworkId
|
||||
val fadeInAnimation: Animation = AlphaAnimation(0.0f, 1.0f)
|
||||
fadeInAnimation.duration = 400
|
||||
iv_card.startAnimation(fadeInAnimation)
|
||||
iv_card_tangem_logo.hide()
|
||||
picassoRequest?.placeholder(R.drawable.card_placeholder)
|
||||
?.error(R.drawable.card_placeholder)
|
||||
?.into(iv_card)
|
||||
}
|
||||
|
||||
private fun handleDialogs(walletDialog: WalletDialog?) {
|
||||
|
|
|
|||
|
|
@ -1,19 +1,22 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle"
|
||||
>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item>
|
||||
<shape android:shape="rectangle">
|
||||
|
||||
<corners
|
||||
android:radius="12dp"
|
||||
/>
|
||||
<size
|
||||
android:height="174dp"
|
||||
android:width="328dp"/>
|
||||
<gradient
|
||||
android:startColor="#FFFFFF"
|
||||
android:endColor="#FFFFFF"
|
||||
/>
|
||||
|
||||
|
||||
</shape>
|
||||
<corners android:radius="12dp" />
|
||||
<size
|
||||
android:width="328dp"
|
||||
android:height="174dp" />
|
||||
<gradient
|
||||
android:endColor="#FFFFFF"
|
||||
android:startColor="#FFFFFF" />
|
||||
</shape>
|
||||
</item>
|
||||
<item
|
||||
android:drawable="@drawable/ic_tangem_pale"
|
||||
android:gravity="center">
|
||||
<size
|
||||
android:width="85dp"
|
||||
android:height="23dp" />
|
||||
</item>
|
||||
</layer-list>
|
||||
|
|
|
|||
|
|
@ -60,17 +60,6 @@
|
|||
android:scaleType="fitCenter"
|
||||
android:src="@drawable/card_placeholder"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_card_tangem_logo"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/ic_tangem_pale"
|
||||
app:layout_constraintStart_toStartOf="@id/iv_card"
|
||||
app:layout_constraintEnd_toEndOf="@id/iv_card"
|
||||
app:layout_constraintTop_toTopOf="@id/iv_card"
|
||||
app:layout_constraintBottom_toBottomOf="@id/iv_card"
|
||||
android:elevation="6dp"/>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/rv_pending_transaction"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue