Updated on 2026-08-14
This commit is contained in:
commit
13ced5bd3a
31 changed files with 318 additions and 227 deletions
|
|
@ -80,8 +80,8 @@ dependencies {
|
|||
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
|
||||
|
||||
implementation 'com.tangem:blockchain:develop-65'
|
||||
implementation 'com.tangem.tangem-sdk-kotlin:core:develop-139'
|
||||
implementation 'com.tangem.tangem-sdk-kotlin:android:develop-139'
|
||||
implementation 'com.tangem.tangem-sdk-kotlin:core:develop-140'
|
||||
implementation 'com.tangem.tangem-sdk-kotlin:android:develop-140'
|
||||
|
||||
// WebView
|
||||
implementation "androidx.browser:browser:1.3.0"
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit b3fb1483a37bf1fb7d9da3f9bd9424f693c0ec5b
|
||||
Subproject commit 64ae04d2086e5a605dd4da3cba4af32a60d46c79
|
||||
|
|
@ -35,6 +35,8 @@ val store = Store(
|
|||
middleware = AppState.getMiddleware(),
|
||||
state = AppState()
|
||||
)
|
||||
val logConfig = LogConfig()
|
||||
|
||||
lateinit var preferencesStorage: PreferencesStorage
|
||||
lateinit var currenciesRepository: CurrenciesRepository
|
||||
lateinit var walletConnectRepository: WalletConnectRepository
|
||||
|
|
@ -99,4 +101,14 @@ class TapApplication : Application() {
|
|||
val analyticsHandler = GlobalAnalyticsHandler.createDefaultAnalyticHandlers(this)
|
||||
store.dispatch(GlobalAction.SetAnanlyticHandlers(analyticsHandler))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class LogConfig(
|
||||
// disables both [internal, http]
|
||||
val picasso: Boolean = BuildConfig.DEBUG,
|
||||
val picassoInternal: Boolean = true,
|
||||
val picassoHttp: Boolean = true,
|
||||
|
||||
val storeAction: Boolean = BuildConfig.DEBUG,
|
||||
|
||||
)
|
||||
64
app/src/main/java/com/tangem/tap/common/Throttling.kt
Normal file
64
app/src/main/java/com/tangem/tap/common/Throttling.kt
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
package com.tangem.tap.common
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
open class Throttler<T>(
|
||||
private val duration: Long,
|
||||
) : Throttle<T> {
|
||||
|
||||
private val items: MutableMap<T, Long> = mutableMapOf()
|
||||
|
||||
override fun isStillThrottled(item: T): Boolean {
|
||||
val inThrottlingUpTo = items[item] ?: return false
|
||||
val diff = System.currentTimeMillis() - inThrottlingUpTo
|
||||
return diff < 0
|
||||
}
|
||||
|
||||
override fun updateThrottlingTo(item: T): T {
|
||||
val now = System.currentTimeMillis()
|
||||
val throttledUpTo = items[item] ?: 0L
|
||||
if (throttledUpTo == 0L || throttledUpTo < now) {
|
||||
val newTime = now + duration
|
||||
items[item] = newTime
|
||||
}
|
||||
return item
|
||||
}
|
||||
|
||||
open fun clear() {
|
||||
items.clear()
|
||||
}
|
||||
}
|
||||
|
||||
class ThrottlerWithValues<T, V>(
|
||||
duration: Long
|
||||
) : Throttler<T>(duration), ValuesHolder<T, V> {
|
||||
|
||||
private val valuesHolder: MutableMap<T, V?> = mutableMapOf()
|
||||
|
||||
override fun setValue(item: T, value: V) {
|
||||
valuesHolder[item] = value
|
||||
}
|
||||
|
||||
override fun geValue(item: T): V? = valuesHolder[item]
|
||||
|
||||
override fun remove(item: T) {
|
||||
valuesHolder.remove(item)
|
||||
}
|
||||
|
||||
override fun clear() {
|
||||
valuesHolder.clear()
|
||||
super.clear()
|
||||
}
|
||||
}
|
||||
|
||||
interface Throttle<T> {
|
||||
fun isStillThrottled(item: T): Boolean
|
||||
fun updateThrottlingTo(item: T): T
|
||||
}
|
||||
|
||||
interface ValuesHolder<K, V> {
|
||||
fun setValue(item: K, value: V)
|
||||
fun geValue(item: K): V?
|
||||
fun remove(item: K)
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@ enum class AnalyticsEvent(val event: String) {
|
|||
CARD_IS_SCANNED("card_is_scanned"),
|
||||
TRANSACTION_IS_SENT("transaction_is_sent"),
|
||||
READY_TO_SCAN("ready_to_scan"),
|
||||
DEMO_MODE_ACTIVATED("demo_mode_activated"),
|
||||
|
||||
APP_RATING_DISPLAYED("rate_app_warning_displayed"),
|
||||
APP_RATING_DISMISS("dismiss_rate_app_warning"),
|
||||
|
|
@ -20,6 +21,7 @@ enum class AnalyticsEvent(val event: String) {
|
|||
|
||||
enum class AnalyticsParam(val param: String) {
|
||||
BLOCKCHAIN("blockchain"),
|
||||
CARD_ID("cardId"),
|
||||
BATCH_ID("batch_id"),
|
||||
FIRMWARE("firmware"),
|
||||
ACTION("action"),
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ class GlobalAnalyticsHandler(val analyticsHandlers: List<AnalyticsHandler>) :
|
|||
blockchain: String?,
|
||||
params: Map<String, String>
|
||||
) {
|
||||
analyticsHandlers.forEach { it.triggerEvent(event, card, blockchain) }
|
||||
analyticsHandlers.forEach { it.triggerEvent(event, card, blockchain, params) }
|
||||
}
|
||||
|
||||
override fun triggerEvent(event: String, params: Map<String, String>) {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ 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
|
||||
|
|
@ -18,42 +19,45 @@ class PicassoHelper {
|
|||
|
||||
fun initPicassoWithCaching(application: Application) {
|
||||
val picasso = Picasso.Builder(application)
|
||||
.downloader(OkHttp3Downloader(getOkHttpForPicasso(application)))
|
||||
.build()
|
||||
picasso.isLoggingEnabled = BuildConfig.DEBUG
|
||||
.downloader(OkHttp3Downloader(getOkHttpForPicasso(application)))
|
||||
.build()
|
||||
picasso.isLoggingEnabled = logIsEnabled()
|
||||
picasso.setIndicatorsEnabled(BuildConfig.DEBUG)
|
||||
Picasso.setSingletonInstance(picasso)
|
||||
}
|
||||
|
||||
private fun getOkHttpForPicasso(application: Application): OkHttpClient {
|
||||
val okHttpBuilder = OkHttpClient.Builder()
|
||||
okHttpBuilder.cache(Cache(File(application.filesDir, "artworks"), Long.MAX_VALUE))
|
||||
okHttpBuilder.callTimeout(15000, TimeUnit.MILLISECONDS)
|
||||
return OkHttpClient.Builder().apply {
|
||||
cache(Cache(File(application.filesDir, "artworks"), Long.MAX_VALUE))
|
||||
callTimeout(15000, TimeUnit.MILLISECONDS)
|
||||
|
||||
okHttpBuilder.addInterceptor { chain ->
|
||||
val cacheControl = CacheControl.Builder()
|
||||
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()
|
||||
val origRequest = chain.request()
|
||||
val neverExpireRequest = origRequest.newBuilder()
|
||||
.cacheControl(cacheControl)
|
||||
.build()
|
||||
chain.proceed(neverExpireRequest)
|
||||
}
|
||||
addDebugInterceptors(okHttpBuilder)
|
||||
chain.proceed(neverExpireRequest)
|
||||
}
|
||||
}.build()
|
||||
|
||||
return okHttpBuilder.build()
|
||||
}
|
||||
|
||||
private fun addDebugInterceptors(okHttpBuilder: OkHttpClient.Builder) {
|
||||
if (!BuildConfig.DEBUG) return
|
||||
|
||||
val picassoInterceptor = HttpLoggingInterceptor(PicassoOkHttpLogger()).apply {
|
||||
level = HttpLoggingInterceptor.Level.BODY
|
||||
}
|
||||
okHttpBuilder.addInterceptor(picassoInterceptor)
|
||||
}
|
||||
|
||||
private fun logIsEnabled(): Boolean = BuildConfig.DEBUG && logConfig.picasso
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.tap.common.redux
|
||||
|
||||
import com.tangem.tap.logConfig
|
||||
import org.rekotlin.Middleware
|
||||
import timber.log.Timber
|
||||
|
||||
|
|
@ -9,7 +10,7 @@ import timber.log.Timber
|
|||
val logMiddleware: Middleware<AppState> = { dispatch, appState ->
|
||||
{ nextDispatch ->
|
||||
{ action ->
|
||||
Timber.d("Dispatch action: $action")
|
||||
if (logConfig.storeAction) Timber.d("Dispatch action: $action")
|
||||
nextDispatch(action)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
package com.tangem.tap.common.shop.shopify
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class ShopifyShop(
|
||||
val domain: String,
|
||||
@Json(name = "storefrontApiKeyAndroid")
|
||||
val storefrontApiKey: String,
|
||||
val merchantID: String,
|
||||
)
|
||||
|
|
@ -26,11 +26,13 @@ import com.tangem.operations.pins.SetUserCodeCommand
|
|||
import com.tangem.tap.common.analytics.Analytics
|
||||
import com.tangem.tap.common.analytics.AnalyticsEvent
|
||||
import com.tangem.tap.common.analytics.AnalyticsHandler
|
||||
import com.tangem.tap.common.analytics.AnalyticsParam
|
||||
import com.tangem.tap.domain.tasks.CreateWalletAndRescanTask
|
||||
import com.tangem.tap.domain.tasks.product.ResetToFactorySettingsTask
|
||||
import com.tangem.tap.domain.tasks.product.ScanProductTask
|
||||
import com.tangem.tap.domain.tasks.product.ScanResponse
|
||||
import com.tangem.tap.domain.tokens.CurrenciesRepository
|
||||
import com.tangem.tap.features.demo.DemoHelper
|
||||
import com.tangem.wallet.R
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.isActive
|
||||
|
|
@ -70,12 +72,21 @@ class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Co
|
|||
result: CompletionResult<ScanResponse>
|
||||
) {
|
||||
when (result) {
|
||||
is CompletionResult.Success ->
|
||||
is CompletionResult.Success -> {
|
||||
analyticsHandler?.triggerEvent(
|
||||
event = AnalyticsEvent.CARD_IS_SCANNED,
|
||||
card = result.data.card,
|
||||
blockchain = result.data.walletData?.blockchain
|
||||
)
|
||||
if (DemoHelper.isDemoCard(result.data)) {
|
||||
analyticsHandler?.triggerEvent(
|
||||
event = AnalyticsEvent.DEMO_MODE_ACTIVATED,
|
||||
card = result.data.card,
|
||||
blockchain = result.data.walletData?.blockchain,
|
||||
params = mapOf(AnalyticsParam.CARD_ID.param to result.data.card.cardId)
|
||||
)
|
||||
}
|
||||
}
|
||||
is CompletionResult.Failure ->
|
||||
(result.error as? TangemSdkError)?.let { error ->
|
||||
analyticsHandler?.logCardSdkError(
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package com.tangem.tap.domain
|
|||
import com.tangem.blockchain.blockchains.solana.RentProvider
|
||||
import com.tangem.blockchain.common.*
|
||||
import com.tangem.common.services.Result
|
||||
import com.tangem.tap.common.ThrottlerWithValues
|
||||
import com.tangem.tap.common.extensions.dispatchDebugErrorNotification
|
||||
import com.tangem.tap.common.extensions.dispatchOnMain
|
||||
import com.tangem.tap.common.extensions.safeUpdate
|
||||
|
|
@ -27,26 +28,47 @@ import com.tangem.tap.network.coinmarketcap.CoinMarketCapService
|
|||
import com.tangem.tap.scope
|
||||
import com.tangem.tap.store
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.math.BigDecimal
|
||||
|
||||
|
||||
class TapWalletManager {
|
||||
private val coinMarketCapService = CoinMarketCapService()
|
||||
|
||||
private val blockchainSdkConfig by lazy {
|
||||
store.state.globalState.configManager?.config?.blockchainSdkConfig ?: BlockchainSdkConfig()
|
||||
}
|
||||
val walletManagerFactory: WalletManagerFactory
|
||||
by lazy { WalletManagerFactory(blockchainSdkConfig) }
|
||||
|
||||
suspend fun loadWalletData(walletManager: WalletManager) {
|
||||
handleUpdateWalletResult(walletManager.safeUpdate(), walletManager)
|
||||
private val coinMarketCapService = CoinMarketCapService()
|
||||
private val blockchainSdkConfig by lazy {
|
||||
store.state.globalState.configManager?.config?.blockchainSdkConfig ?: BlockchainSdkConfig()
|
||||
}
|
||||
|
||||
suspend fun updateWallet(walletManager: WalletManager) {
|
||||
val result = walletManager.safeUpdate()
|
||||
private val walletManagersThrottler = ThrottlerWithValues<Blockchain, Result<Wallet>>(10000)
|
||||
private val fiatRatesThrottler = ThrottlerWithValues<Currency, Result<BigDecimal>?>(60000)
|
||||
|
||||
suspend fun loadWalletData(walletManager: WalletManager) {
|
||||
val blockchain = walletManager.wallet.blockchain
|
||||
val result = if (walletManagersThrottler.isStillThrottled(blockchain)) {
|
||||
delay(500)
|
||||
walletManagersThrottler.geValue(blockchain)!!
|
||||
} else {
|
||||
updateThrottlingForWalletManager(walletManager)
|
||||
}
|
||||
handleUpdateWalletResult(result, walletManager)
|
||||
}
|
||||
|
||||
suspend fun updateWallet(walletManager: WalletManager, force: Boolean) {
|
||||
val result = if (force) {
|
||||
updateThrottlingForWalletManager(walletManager)
|
||||
} else {
|
||||
val blockchain = walletManager.wallet.blockchain
|
||||
if (walletManagersThrottler.isStillThrottled(blockchain)) {
|
||||
delay(500)
|
||||
walletManagersThrottler.geValue(blockchain)!!
|
||||
} else {
|
||||
updateThrottlingForWalletManager(walletManager)
|
||||
}
|
||||
}
|
||||
withContext(Dispatchers.Main) {
|
||||
when (result) {
|
||||
is Result.Success ->
|
||||
|
|
@ -55,7 +77,14 @@ class TapWalletManager {
|
|||
store.dispatch(WalletAction.UpdateWallet.Failure(result.error.localizedMessage))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun updateThrottlingForWalletManager(walletManager: WalletManager): Result<Wallet> {
|
||||
val newResult = walletManager.safeUpdate()
|
||||
val blockchain = walletManager.wallet.blockchain
|
||||
walletManagersThrottler.updateThrottlingTo(blockchain)
|
||||
walletManagersThrottler.setValue(blockchain, newResult)
|
||||
return newResult
|
||||
}
|
||||
|
||||
suspend fun loadFiatRate(fiatCurrency: FiatCurrencyName, wallet: Wallet) {
|
||||
|
|
@ -65,20 +94,27 @@ class TapWalletManager {
|
|||
loadFiatRate(fiatCurrency, currencies)
|
||||
}
|
||||
|
||||
suspend fun loadFiatRate(fiatCurrency: FiatCurrencyName, currency: Currency) {
|
||||
val currencies = listOf(currency)
|
||||
loadFiatRate(fiatCurrency, currencies)
|
||||
}
|
||||
|
||||
suspend fun loadFiatRate(fiatCurrency: FiatCurrencyName, currencies: List<Currency>) {
|
||||
val results = mutableListOf<Pair<Currency, Result<BigDecimal>?>>()
|
||||
currencies.forEach {
|
||||
results.add(it to coinMarketCapService.getRate(it.currencySymbol, fiatCurrency))
|
||||
// get and submit previous result of equivalents.
|
||||
val throttledResult = currencies.filter { fiatRatesThrottler.isStillThrottled(it) }.map {
|
||||
Pair(it, fiatRatesThrottler.geValue(it))
|
||||
}
|
||||
if (throttledResult.isNotEmpty()) handleFiatRatesResult(throttledResult)
|
||||
|
||||
val toUpdate = currencies.filter { !fiatRatesThrottler.isStillThrottled(it) }
|
||||
toUpdate.forEach {
|
||||
val result = coinMarketCapService.getRate(it.currencySymbol, fiatCurrency)
|
||||
if (result is Result.Success) {
|
||||
fiatRatesThrottler.updateThrottlingTo(it)
|
||||
fiatRatesThrottler.setValue(it, result)
|
||||
}
|
||||
handleFiatRatesResult(listOf(it to result))
|
||||
}
|
||||
handleFiatRatesResult(results)
|
||||
}
|
||||
|
||||
suspend fun onCardScanned(data: ScanResponse) {
|
||||
walletManagersThrottler.clear()
|
||||
// fiatRatesThrottler.clear()
|
||||
store.state.globalState.feedbackManager?.infoHolder?.setCardInfo(data.card)
|
||||
updateConfigManager(data)
|
||||
|
||||
|
|
@ -295,8 +331,7 @@ class TapWalletManager {
|
|||
store.dispatch(WalletAction.LoadFiatRate.Success(rate))
|
||||
}
|
||||
is Result.Failure -> store.dispatch(WalletAction.LoadFiatRate.Failure)
|
||||
null -> {
|
||||
}
|
||||
null -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
package com.tangem.tap.features.demo
|
||||
|
||||
import com.tangem.blockchain.common.Wallet
|
||||
import com.tangem.blockchain.common.WalletManager
|
||||
import com.tangem.tap.domain.tasks.product.ScanResponse
|
||||
|
||||
|
|
@ -8,5 +7,4 @@ import com.tangem.tap.domain.tasks.product.ScanResponse
|
|||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
fun ScanResponse.isDemoCard(): Boolean = DemoHelper.isDemoCardId(card.cardId)
|
||||
fun WalletManager.isDemoWallet(): Boolean = DemoHelper.isDemoCardId(wallet.cardId)
|
||||
fun Wallet.isDemoWallet(): Boolean = DemoHelper.isDemoCardId(cardId)
|
||||
fun WalletManager.isDemoWallet(): Boolean = DemoHelper.isDemoCardId(wallet.cardId)
|
||||
|
|
@ -29,17 +29,25 @@ class HomeFragment : Fragment(R.layout.fragment_home), StoreSubscriber<HomeState
|
|||
|
||||
store.dispatch(BackupAction.CheckForUnfinishedBackup)
|
||||
|
||||
|
||||
getView()?.findViewById<ComposeView>(R.id.cv_stories)?.setContent {
|
||||
AppCompatTheme {
|
||||
StoriesScreen(
|
||||
homeState,
|
||||
onScanButtonClick = { store.dispatch(HomeAction.ReadCard) },
|
||||
onShopButtonClick = { store.dispatch(HomeAction.GoToShop) }
|
||||
onShopButtonClick = { store.dispatch(HomeAction.GoToShop(getRegionProvider())) }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getRegionProvider(): RegionProvider = RegionService(
|
||||
listOf(
|
||||
// TelephonyManagerRegionProvider(requireContext()),
|
||||
LocaleRegionProvider()
|
||||
)
|
||||
)
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
store.subscribe(this) { state ->
|
||||
|
|
|
|||
|
|
@ -0,0 +1,48 @@
|
|||
package com.tangem.tap.features.home
|
||||
|
||||
import android.content.Context
|
||||
import android.telephony.TelephonyManager
|
||||
import android.telephony.TelephonyManager.PHONE_TYPE_CDMA
|
||||
import androidx.compose.ui.text.intl.Locale
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
interface RegionProvider {
|
||||
fun getRegion(): String?
|
||||
}
|
||||
|
||||
class RegionService(
|
||||
private val providers: List<RegionProvider>
|
||||
) : RegionProvider {
|
||||
override fun getRegion(): String? {
|
||||
for (provider in providers) {
|
||||
val region = provider.getRegion()
|
||||
if (region != null) return region
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
class TelephonyManagerRegionProvider(context: Context) : RegionProvider {
|
||||
|
||||
private val wContext: WeakReference<Context> = WeakReference(context)
|
||||
|
||||
override fun getRegion(): String? {
|
||||
val tm = wContext.get()?.getSystemService(Context.TELEPHONY_SERVICE) as? TelephonyManager ?: return null
|
||||
|
||||
val region = when (tm.phoneType) {
|
||||
PHONE_TYPE_CDMA -> {
|
||||
// Result may be unreliable
|
||||
tm.networkCountryIso
|
||||
}
|
||||
else -> tm.networkCountryIso
|
||||
}
|
||||
return region.ifEmpty { return null }
|
||||
}
|
||||
}
|
||||
|
||||
class LocaleRegionProvider : RegionProvider {
|
||||
override fun getRegion(): String? = Locale.current.region
|
||||
}
|
||||
|
|
@ -1,12 +1,13 @@
|
|||
package com.tangem.tap.features.home.redux
|
||||
|
||||
import com.tangem.tap.common.entities.IndeterminateProgressButton
|
||||
import com.tangem.tap.features.home.RegionProvider
|
||||
import org.rekotlin.Action
|
||||
|
||||
sealed class HomeAction : Action {
|
||||
// from ui
|
||||
object ReadCard : HomeAction()
|
||||
object GoToShop : HomeAction()
|
||||
data class GoToShop(val regionProvider: RegionProvider) : HomeAction()
|
||||
|
||||
// internal
|
||||
data class ShouldScanCardOnResume(val shouldScanCard: Boolean) : HomeAction()
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import com.tangem.tap.common.analytics.AnalyticsEvent
|
|||
import com.tangem.tap.common.analytics.AnalyticsParam
|
||||
import com.tangem.tap.common.analytics.GetCardSourceParams
|
||||
import com.tangem.tap.common.entities.IndeterminateProgressButton
|
||||
import com.tangem.tap.common.extensions.dispatchOpenUrl
|
||||
import com.tangem.tap.common.extensions.onCardScanned
|
||||
import com.tangem.tap.common.extensions.withMainContext
|
||||
import com.tangem.tap.common.post
|
||||
|
|
@ -14,6 +15,7 @@ import com.tangem.tap.common.redux.navigation.AppScreen
|
|||
import com.tangem.tap.common.redux.navigation.FragmentShareTransition
|
||||
import com.tangem.tap.common.redux.navigation.NavigationAction
|
||||
import com.tangem.tap.domain.DELAY_SDK_DIALOG_CLOSE
|
||||
import com.tangem.tap.features.home.redux.HomeMiddleware.Companion.BUY_WALLET_URL
|
||||
import com.tangem.tap.features.onboarding.OnboardingHelper
|
||||
import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsAction
|
||||
import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsStep
|
||||
|
|
@ -29,6 +31,7 @@ class HomeMiddleware {
|
|||
val handler = homeMiddleware
|
||||
|
||||
const val CARD_SHOP_URI = "http://cards.tangem.com/"
|
||||
const val BUY_WALLET_URL = "https://mv.tangem.com/"
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -49,7 +52,10 @@ private val homeMiddleware: Middleware<AppState> = { dispatch, state ->
|
|||
}
|
||||
is HomeAction.ReadCard -> handleReadCard()
|
||||
is HomeAction.GoToShop -> {
|
||||
store.dispatch(NavigationAction.NavigateTo(AppScreen.Shop))
|
||||
when (action.regionProvider.getRegion()?.toLowerCase()) {
|
||||
"ru" -> store.dispatchOpenUrl(BUY_WALLET_URL)
|
||||
else -> store.dispatch(NavigationAction.NavigateTo(AppScreen.Shop))
|
||||
}
|
||||
store.state.globalState.analyticsHandlers?.triggerEvent(
|
||||
event = AnalyticsEvent.GET_CARD,
|
||||
params = mapOf(AnalyticsParam.SOURCE.param to GetCardSourceParams.WELCOME.param)
|
||||
|
|
@ -66,7 +72,7 @@ private fun handleReadCard() {
|
|||
store.dispatch(NavigationAction.NavigateTo(AppScreen.Disclaimer))
|
||||
} else {
|
||||
changeButtonState(ButtonState.PROGRESS)
|
||||
store.dispatch(GlobalAction.ScanCard( onSuccess = { scanResponse ->
|
||||
store.dispatch(GlobalAction.ScanCard(onSuccess = { scanResponse ->
|
||||
store.state.globalState.tapWalletManager.updateConfigManager(scanResponse)
|
||||
store.dispatch(TwinCardsAction.IfTwinsPrepareState(scanResponse))
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ sealed class OnboardingWalletAction : Action {
|
|||
sealed class BackupAction : Action {
|
||||
|
||||
object DetermineBackupStep : BackupAction()
|
||||
data class IntroduceBackup(val buyCardsUrl: String? = null) : BackupAction()
|
||||
object StartBackup : BackupAction()
|
||||
object DismissBackup : BackupAction()
|
||||
|
||||
|
|
@ -42,7 +41,6 @@ sealed class BackupAction : Action {
|
|||
data class Success(val cardId: CardId, val artwork: Bitmap)
|
||||
}
|
||||
|
||||
object GoToShop : BackupAction()
|
||||
object FinishAddingBackupCards : BackupAction()
|
||||
|
||||
object ShowAccessCodeInfoScreen : BackupAction()
|
||||
|
|
@ -58,7 +56,7 @@ sealed class BackupAction : Action {
|
|||
data class WriteBackupCard(val cardNumber: Int) : BackupAction()
|
||||
|
||||
object PrepareToWritePrimaryCard : BackupAction()
|
||||
object WritePrimaryCard: BackupAction()
|
||||
object WritePrimaryCard : BackupAction()
|
||||
|
||||
object FinishBackup : BackupAction()
|
||||
object DiscardBackup : BackupAction()
|
||||
|
|
|
|||
|
|
@ -4,9 +4,6 @@ import com.tangem.common.CompletionResult
|
|||
import com.tangem.common.card.Card
|
||||
import com.tangem.operations.backup.BackupService
|
||||
import com.tangem.tap.*
|
||||
import com.tangem.tap.common.analytics.AnalyticsEvent
|
||||
import com.tangem.tap.common.analytics.AnalyticsParam
|
||||
import com.tangem.tap.common.analytics.GetCardSourceParams
|
||||
import com.tangem.tap.common.extensions.dispatchOnMain
|
||||
import com.tangem.tap.common.extensions.withMainContext
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
|
|
@ -17,7 +14,6 @@ import com.tangem.tap.domain.extensions.hasWallets
|
|||
import com.tangem.tap.domain.tasks.product.ScanResponse
|
||||
import com.tangem.tap.features.demo.DemoHelper
|
||||
import com.tangem.tap.features.home.redux.HomeAction
|
||||
import com.tangem.tap.features.onboarding.products.wallet.redux.OnboardingWalletMiddleware.Companion.BUY_WALLET_URL
|
||||
import com.tangem.tap.features.wallet.redux.Artwork
|
||||
import kotlinx.coroutines.launch
|
||||
import org.rekotlin.Action
|
||||
|
|
@ -26,8 +22,6 @@ import org.rekotlin.Middleware
|
|||
class OnboardingWalletMiddleware {
|
||||
companion object {
|
||||
val handler = onboardingWalletMiddleware
|
||||
|
||||
const val BUY_WALLET_URL = "https://wallet.tangem.com/"
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -116,21 +110,8 @@ private fun handleWalletAction(action: Action) {
|
|||
OnboardingWalletAction.ProceedBackup -> {
|
||||
val newAction = when (val backupState = backupService.currentState) {
|
||||
BackupService.State.FinalizingPrimaryCard -> BackupAction.PrepareToWritePrimaryCard
|
||||
is BackupService.State.FinalizingBackupCard ->
|
||||
BackupAction.PrepareToWriteBackupCard(backupState.index)
|
||||
else -> {
|
||||
val url = if (card?.issuer?.name?.lowercase()?.contains("tangem") == true) {
|
||||
BUY_WALLET_URL
|
||||
} else {
|
||||
null
|
||||
}
|
||||
if (walletState.backupState.backupStep == BackupStep.InitBackup ||
|
||||
walletState.backupState.backupStep == BackupStep.Finished) {
|
||||
BackupAction.IntroduceBackup(url)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
is BackupService.State.FinalizingBackupCard -> BackupAction.PrepareToWriteBackupCard(backupState.index)
|
||||
else -> null
|
||||
}
|
||||
newAction?.let { store.dispatch(it) }
|
||||
}
|
||||
|
|
@ -221,13 +202,6 @@ private fun handleBackupAction(appState: () -> AppState?, action: BackupAction)
|
|||
}
|
||||
}
|
||||
}
|
||||
is BackupAction.GoToShop -> {
|
||||
store.dispatch(NavigationAction.NavigateTo(AppScreen.Shop))
|
||||
store.state.globalState.analyticsHandlers?.triggerEvent(
|
||||
event = AnalyticsEvent.GET_CARD,
|
||||
params = mapOf(AnalyticsParam.SOURCE.param to GetCardSourceParams.ONBOARDING.param)
|
||||
)
|
||||
}
|
||||
is BackupAction.FinishAddingBackupCards -> {
|
||||
if (backupService.addedBackupCardsCount == 1) {
|
||||
store.dispatchOnMain(GlobalAction.ShowDialog(BackupDialog.AddMoreBackupCards))
|
||||
|
|
|
|||
|
|
@ -39,14 +39,7 @@ class BackupReducer {
|
|||
): BackupState {
|
||||
|
||||
return when (action) {
|
||||
is BackupAction.IntroduceBackup -> BackupState(
|
||||
backupStep = BackupStep.InitBackup,
|
||||
canSkipBackup = state.canSkipBackup,
|
||||
buyAdditionalCardsUrl = action.buyCardsUrl
|
||||
)
|
||||
|
||||
BackupAction.StartAddingPrimaryCard -> state.copy(backupStep = BackupStep.ScanOriginCard)
|
||||
|
||||
BackupAction.StartAddingBackupCards -> {
|
||||
state.copy(backupStep = BackupStep.AddBackupCards)
|
||||
}
|
||||
|
|
@ -122,7 +115,6 @@ class BackupReducer {
|
|||
BackupAction.DismissBackup -> state
|
||||
is BackupAction.LoadBackupCardArtwork -> state
|
||||
is BackupAction.CheckAccessCode -> state
|
||||
BackupAction.GoToShop -> state
|
||||
BackupAction.DetermineBackupStep -> state
|
||||
BackupAction.CheckForUnfinishedBackup -> state
|
||||
BackupAction.DiscardBackup -> state
|
||||
|
|
|
|||
|
|
@ -52,7 +52,6 @@ data class BackupState(
|
|||
val backupStep: BackupStep = BackupStep.InitBackup,
|
||||
val maxBackupCards: Int = 2,
|
||||
val canSkipBackup: Boolean = true,
|
||||
val buyAdditionalCardsUrl: String? = null
|
||||
)
|
||||
|
||||
enum class AccessCodeError {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,9 @@ package com.tangem.tap.features.onboarding.products.wallet.ui
|
|||
|
||||
import android.os.Bundle
|
||||
import android.util.TypedValue
|
||||
import android.view.*
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.WindowManager
|
||||
import android.widget.ImageView
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.fragment.app.Fragment
|
||||
|
|
@ -387,28 +389,6 @@ class OnboardingWalletFragment : Fragment(R.layout.fragment_onboarding_wallet),
|
|||
}
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
return when (item.itemId) {
|
||||
R.id.shop_menu -> {
|
||||
store.dispatch(BackupAction.GoToShop)
|
||||
true
|
||||
}
|
||||
else -> super.onOptionsItemSelected(item)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||
inflater.inflate(R.menu.shop, menu)
|
||||
|
||||
val backupState = store.state.onboardingWalletState.backupState
|
||||
val backupStep = backupState.backupStep
|
||||
|
||||
val shopMenuShouldBeVisible =
|
||||
(backupStep == BackupStep.ScanOriginCard || backupStep == BackupStep.AddBackupCards) &&
|
||||
backupState.buyAdditionalCardsUrl != null
|
||||
menu.getItem(0).isVisible = shopMenuShouldBeVisible
|
||||
}
|
||||
|
||||
override fun handleOnBackPressed() {
|
||||
store.dispatch(OnboardingWalletAction.OnBackPressed)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -204,7 +204,7 @@ private fun sendTransaction(
|
|||
withContext(Dispatchers.Main) {
|
||||
dispatch(WalletAction.UpdateWallet(walletManager.wallet.blockchain))
|
||||
}
|
||||
delay(10000)
|
||||
delay(11000) // more than 10000 to avoid throttling
|
||||
withContext(Dispatchers.Main) {
|
||||
dispatch(WalletAction.UpdateWallet(walletManager.wallet.blockchain))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import com.tangem.common.extensions.toMapKey
|
|||
import com.tangem.common.hdWallet.DerivationPath
|
||||
import com.tangem.operations.derivation.ExtendedPublicKeysMap
|
||||
import com.tangem.tap.common.extensions.dispatchErrorNotification
|
||||
import com.tangem.tap.common.extensions.dispatchOnMain
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
import com.tangem.tap.common.redux.navigation.NavigationAction
|
||||
|
|
@ -106,11 +107,11 @@ class TokensMiddleware {
|
|||
val updatedScanResponse = scanResponse.copy(
|
||||
derivedKeys = updatedDerivedKeys
|
||||
)
|
||||
store.dispatch(GlobalAction.SaveScanNoteResponse(updatedScanResponse))
|
||||
store.dispatchOnMain(GlobalAction.SaveScanNoteResponse(updatedScanResponse))
|
||||
submitAdd(blockchains, tokens)
|
||||
|
||||
delay(DELAY_SDK_DIALOG_CLOSE)
|
||||
store.dispatch(NavigationAction.PopBackTo())
|
||||
store.dispatchOnMain(NavigationAction.PopBackTo())
|
||||
}
|
||||
is CompletionResult.Failure -> {
|
||||
store.dispatchErrorNotification(TapError.CustomError("Error adding tokens"))
|
||||
|
|
@ -155,6 +156,6 @@ class TokensMiddleware {
|
|||
WalletAction.MultiWallet.AddBlockchain(it)
|
||||
} + tokens.map {
|
||||
WalletAction.MultiWallet.AddToken(it)
|
||||
}).forEach { store.dispatch(it) }
|
||||
}).forEach { store.dispatchOnMain(it) }
|
||||
}
|
||||
}
|
||||
|
|
@ -74,14 +74,14 @@ sealed class WalletAction : Action {
|
|||
class CheckRemainingSignatures(val remainingSignatures: Int?) : Warnings()
|
||||
}
|
||||
|
||||
data class UpdateWallet(val blockchain: Blockchain? = null) : WalletAction() {
|
||||
data class UpdateWallet(val blockchain: Blockchain? = null, val force: Boolean = true) : WalletAction() {
|
||||
object ScheduleUpdatingWallet : WalletAction()
|
||||
data class Success(val wallet: Wallet) : WalletAction()
|
||||
data class Failure(val errorMessage: String? = null) : WalletAction()
|
||||
}
|
||||
|
||||
data class LoadFiatRate(
|
||||
val wallet: Wallet? = null, val currency: Currency? = null,
|
||||
val wallet: Wallet? = null, val currencyList: List<Currency>? = null,
|
||||
) : WalletAction() {
|
||||
data class Success(val fiatRate: Pair<Currency, BigDecimal?>) : WalletAction()
|
||||
object Failure : WalletAction()
|
||||
|
|
|
|||
|
|
@ -54,8 +54,8 @@ data class WalletState(
|
|||
val primaryWallet = if (wallets.isNotEmpty()) wallets[0] else null
|
||||
|
||||
val shouldShowDetails: Boolean =
|
||||
primaryWallet?.currencyData?.status != BalanceStatus.EmptyCard &&
|
||||
primaryWallet?.currencyData?.status != BalanceStatus.UnknownBlockchain
|
||||
primaryWallet?.currencyData?.status != BalanceStatus.EmptyCard &&
|
||||
primaryWallet?.currencyData?.status != BalanceStatus.UnknownBlockchain
|
||||
|
||||
val blockchains: List<Blockchain>
|
||||
get() = walletManagers.map { it.wallet.blockchain }
|
||||
|
|
@ -101,10 +101,10 @@ data class WalletState(
|
|||
|
||||
if (!isPrimaryCurrency(walletData)) {
|
||||
val walletManager = getWalletManager(walletData.currency)
|
||||
?: return true
|
||||
?: return true
|
||||
|
||||
if (walletData.currency is Currency.Blockchain &&
|
||||
walletManager.cardTokens.isNotEmpty()
|
||||
walletManager.cardTokens.isNotEmpty()
|
||||
) {
|
||||
return false
|
||||
}
|
||||
|
|
@ -113,22 +113,22 @@ data class WalletState(
|
|||
|
||||
if (walletData.currency is Currency.Blockchain) {
|
||||
return wallet.recentTransactions.toPendingTransactions(wallet.address).isEmpty() &&
|
||||
wallet.amounts.toSendableAmounts().isEmpty()
|
||||
wallet.amounts.toSendableAmounts().isEmpty()
|
||||
} else if (walletData.currency is Currency.Token) (
|
||||
return wallet.recentTransactions.toPendingTransactionsForToken(
|
||||
walletData.currency.token, wallet.address).isEmpty()
|
||||
&& wallet.amounts[AmountType.Token(token = walletData.currency.token)]
|
||||
?.isAboveZero() != true
|
||||
)
|
||||
return wallet.recentTransactions.toPendingTransactionsForToken(
|
||||
walletData.currency.token, wallet.address).isEmpty()
|
||||
&& wallet.amounts[AmountType.Token(token = walletData.currency.token)]
|
||||
?.isAboveZero() != true
|
||||
)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun isPrimaryCurrency(walletData: WalletData): Boolean {
|
||||
return (walletData.currency is Currency.Blockchain &&
|
||||
walletData.currency.blockchain == store.state.walletState.primaryBlockchain)
|
||||
|| (walletData.currency is Currency.Token &&
|
||||
walletData.currency.token == store.state.walletState.primaryToken)
|
||||
walletData.currency.blockchain == store.state.walletState.primaryBlockchain)
|
||||
|| (walletData.currency is Currency.Token &&
|
||||
walletData.currency.token == store.state.walletState.primaryToken)
|
||||
}
|
||||
|
||||
fun replaceWalletInWallets(walletData: WalletData?): List<WalletData> {
|
||||
|
|
@ -149,7 +149,7 @@ data class WalletState(
|
|||
val remainingWallets: MutableList<WalletData> = newWallets.toMutableList()
|
||||
val updatedWallets = wallets.map { wallet ->
|
||||
val newWallet = newWallets
|
||||
.firstOrNull { wallet.currency == it.currency }
|
||||
.firstOrNull { wallet.currency == it.currency }
|
||||
if (newWallet == null) {
|
||||
wallet
|
||||
} else {
|
||||
|
|
@ -176,7 +176,7 @@ data class WalletState(
|
|||
|
||||
fun addWalletManagers(newWalletManagers: List<WalletManager>): WalletState {
|
||||
val updatedWalletManagers = this.walletManagers +
|
||||
newWalletManagers.filterNot { this.blockchains.contains(it.wallet.blockchain) }
|
||||
newWalletManagers.filterNot { this.blockchains.contains(it.wallet.blockchain) }
|
||||
return copy(walletManagers = updatedWalletManagers)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ package com.tangem.tap.features.wallet.redux.middlewares
|
|||
import com.tangem.blockchain.common.*
|
||||
import com.tangem.blockchain.extensions.Result
|
||||
import com.tangem.common.extensions.isZero
|
||||
import com.tangem.tap.common.extensions.dispatchOnMain
|
||||
import com.tangem.tap.common.extensions.safeUpdate
|
||||
import com.tangem.tap.common.redux.global.GlobalState
|
||||
import com.tangem.tap.common.redux.navigation.AppScreen
|
||||
|
|
@ -47,7 +46,7 @@ class MultiWalletMiddleware {
|
|||
globalState.scanResponse?.card?.cardId?.let {
|
||||
currenciesRepository.saveAddedToken(it, action.token)
|
||||
}
|
||||
addToken(action.token, walletState, globalState)
|
||||
addTokens(listOf(action.token), walletState, globalState)
|
||||
}
|
||||
is WalletAction.MultiWallet.AddTokens -> {
|
||||
addTokens(action.tokens, walletState, globalState)
|
||||
|
|
@ -62,7 +61,9 @@ class MultiWalletMiddleware {
|
|||
}
|
||||
}
|
||||
}
|
||||
store.dispatch(WalletAction.LoadFiatRate(currency = Currency.Blockchain(action.blockchain)))
|
||||
store.dispatch(WalletAction.LoadFiatRate(
|
||||
currencyList = listOf(Currency.Blockchain(action.blockchain)))
|
||||
)
|
||||
store.dispatch(WalletAction.LoadWallet(action.blockchain)
|
||||
)
|
||||
}
|
||||
|
|
@ -172,80 +173,41 @@ class MultiWalletMiddleware {
|
|||
}
|
||||
}
|
||||
|
||||
private fun addToken(token: Token, walletState: WalletState?, globalState: GlobalState?) {
|
||||
private fun addTokens(tokens: List<Token>, walletState: WalletState?, globalState: GlobalState?) {
|
||||
val scanResponse = globalState?.scanResponse ?: return
|
||||
val wmFactory = globalState.tapWalletManager.walletManagerFactory
|
||||
|
||||
val walletManager = walletState?.getWalletManager(token)
|
||||
?: globalState.tapWalletManager.walletManagerFactory.makeWalletManagerForApp(
|
||||
scanResponse,
|
||||
token.blockchain
|
||||
)?.also { walletManager ->
|
||||
store.dispatch(WalletAction.MultiWallet.AddWalletManagers(walletManager))
|
||||
store.dispatch(WalletAction.MultiWallet.AddBlockchain(walletManager.wallet.blockchain))
|
||||
}
|
||||
|
||||
store.dispatch(WalletAction.LoadFiatRate(currency = Currency.Token(token)))
|
||||
|
||||
scope.launch {
|
||||
when (val result = walletManager?.addToken(token)) {
|
||||
is Result.Success -> {
|
||||
store.dispatchOnMain(WalletAction.MultiWallet.TokenLoaded(result.data, token))
|
||||
val groupedTokens = tokens.groupBy { it.blockchain }
|
||||
val walletManagers = groupedTokens.mapNotNull { entry ->
|
||||
val blockchain = entry.key
|
||||
val tokensList = entry.value
|
||||
val walletManager = walletState?.getWalletManager(blockchain)
|
||||
?: wmFactory.makeWalletManagerForApp(scanResponse, blockchain)?.also {
|
||||
store.dispatch(WalletAction.MultiWallet.AddWalletManagers(it))
|
||||
store.dispatch(WalletAction.MultiWallet.AddBlockchain(blockchain))
|
||||
}
|
||||
is Result.Failure -> {
|
||||
when (val result = walletManager.safeUpdate()) {
|
||||
is com.tangem.common.services.Result.Success -> {
|
||||
val tokenAmount = result.data.getTokenAmount(token) ?: return@launch
|
||||
store.dispatchOnMain(WalletAction.MultiWallet.TokenLoaded(tokenAmount, token))
|
||||
}
|
||||
is com.tangem.common.services.Result.Failure -> {
|
||||
}
|
||||
store.dispatch(WalletAction.LoadFiatRate(currencyList = tokensList.map { Currency.Token(it) }))
|
||||
walletManager?.apply {
|
||||
scope.launch { async { addTokens(tokensList) }.await() }
|
||||
}
|
||||
}
|
||||
scope.launch {
|
||||
walletManagers.forEach { walletManager ->
|
||||
when (val result = walletManager.safeUpdate()) {
|
||||
is com.tangem.common.services.Result.Success -> {
|
||||
val wallet = result.data
|
||||
wallet.getTokens()
|
||||
.filter { tokens.contains(it) }
|
||||
.mapNotNull { token -> wallet.getTokenAmount(token)?.let { Pair(token, it) } }
|
||||
.forEach {
|
||||
withContext(Dispatchers.Main) {
|
||||
store.dispatch(WalletAction.MultiWallet.TokenLoaded(it.second, it.first))
|
||||
}
|
||||
}
|
||||
}
|
||||
is com.tangem.common.services.Result.Failure -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun addTokens(
|
||||
tokens: List<Token>,
|
||||
walletState: WalletState?,
|
||||
globalState: GlobalState?,
|
||||
) {
|
||||
val scanResponse = globalState?.scanResponse ?: return
|
||||
|
||||
val tokensWithManagers = tokens.map { token ->
|
||||
val walletManager = walletState?.getWalletManager(token)
|
||||
?: globalState.tapWalletManager.walletManagerFactory.makeWalletManagerForApp(
|
||||
scanResponse,
|
||||
token.blockchain
|
||||
)?.also { walletManager ->
|
||||
store.dispatch(WalletAction.MultiWallet.AddWalletManagers(walletManager))
|
||||
store.dispatch(WalletAction.MultiWallet.AddBlockchain(walletManager.wallet.blockchain))
|
||||
}
|
||||
store.dispatch(
|
||||
WalletAction.LoadFiatRate(currency = Currency.Token(token))
|
||||
)
|
||||
TokenWithManager(token, walletManager)
|
||||
}
|
||||
scope.launch {
|
||||
tokensWithManagers.forEach {
|
||||
when (val result = it.walletManager?.addToken(it.token)) {
|
||||
is Result.Success -> {
|
||||
store.dispatchOnMain(WalletAction.MultiWallet.TokenLoaded(result.data, it.token))
|
||||
}
|
||||
is Result.Failure -> {
|
||||
when (val result = it.walletManager.safeUpdate()) {
|
||||
is com.tangem.common.services.Result.Success -> {
|
||||
val tokenAmount = result.data.getTokenAmount(it.token) ?: return@launch
|
||||
store.dispatchOnMain(WalletAction.MultiWallet.TokenLoaded(tokenAmount, it.token))
|
||||
}
|
||||
is com.tangem.common.services.Result.Failure -> {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private data class TokenWithManager(val token: Token, val walletManager: WalletManager?)
|
||||
}
|
||||
|
|
@ -63,9 +63,9 @@ class WalletMiddleware {
|
|||
is WalletAction.LoadWallet -> {
|
||||
scope.launch {
|
||||
if (action.blockchain == null) {
|
||||
walletState.walletManagers.map { walletManager ->
|
||||
async { globalState.tapWalletManager.loadWalletData(walletManager) }
|
||||
}.awaitAll()
|
||||
walletState.walletManagers.map { walletManager ->
|
||||
async { globalState.tapWalletManager.loadWalletData(walletManager) }
|
||||
}.awaitAll()
|
||||
} else {
|
||||
val walletManager = walletState.getWalletManager(action.blockchain)
|
||||
walletManager?.let { globalState.tapWalletManager.loadWalletData(it) }
|
||||
|
|
@ -88,18 +88,20 @@ class WalletMiddleware {
|
|||
when {
|
||||
action.wallet != null -> {
|
||||
globalState.tapWalletManager.loadFiatRate(
|
||||
globalState.appCurrency, action.wallet
|
||||
fiatCurrency = globalState.appCurrency,
|
||||
wallet = action.wallet,
|
||||
)
|
||||
}
|
||||
action.currency != null -> {
|
||||
action.currencyList != null -> {
|
||||
globalState.tapWalletManager.loadFiatRate(
|
||||
globalState.appCurrency, action.currency
|
||||
fiatCurrency = globalState.appCurrency,
|
||||
currencies = action.currencyList,
|
||||
)
|
||||
}
|
||||
else -> {
|
||||
globalState.tapWalletManager.loadFiatRate(
|
||||
fiatCurrency = globalState.appCurrency,
|
||||
currencies = walletState.wallets.mapNotNull { it.currency }
|
||||
currencies = walletState.wallets.map { it.currency },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -131,13 +133,13 @@ class WalletMiddleware {
|
|||
if (action.blockchain != null) {
|
||||
scope.launch {
|
||||
val walletManager = walletState.getWalletManager(action.blockchain)
|
||||
walletManager?.let { globalState.tapWalletManager.updateWallet(it) }
|
||||
walletManager?.let { globalState.tapWalletManager.updateWallet(it, action.force) }
|
||||
}
|
||||
} else {
|
||||
scope.launch {
|
||||
if (walletState.state == ProgressState.Done) {
|
||||
walletState.walletManagers.map { walletManager ->
|
||||
globalState.tapWalletManager.updateWallet(walletManager)
|
||||
globalState.tapWalletManager.updateWallet(walletManager, action.force)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -163,6 +165,7 @@ class WalletMiddleware {
|
|||
)
|
||||
withMainContext { actionList.forEach { store.dispatch(it) } }
|
||||
}
|
||||
is Result.Failure -> {}
|
||||
}
|
||||
store.dispatchOnMain(WalletAction.Warnings.CheckIfNeeded)
|
||||
}
|
||||
|
|
@ -230,12 +233,12 @@ class WalletMiddleware {
|
|||
when (currency) {
|
||||
is Currency.Blockchain -> {
|
||||
val amountToSend = amounts?.find { it.currencySymbol == currency.blockchain.currency }
|
||||
?: return WalletAction.Send.ChooseCurrency(amounts)
|
||||
?: return WalletAction.Send.ChooseCurrency(amounts)
|
||||
PrepareSendScreen(amountToSend, selectedWalletData.fiatRate, walletManager)
|
||||
}
|
||||
is Currency.Token -> {
|
||||
val amountToSend = amounts?.find { it.currencySymbol == currency.token.symbol }
|
||||
?: return WalletAction.Send.ChooseCurrency(amounts)
|
||||
?: return WalletAction.Send.ChooseCurrency(amounts)
|
||||
prepareSendActionForToken(amountToSend, state, selectedWalletData, wallet, walletManager)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -95,7 +95,6 @@ private fun internalReduce(action: Action, state: AppState): WalletState {
|
|||
is WalletAction.LoadWallet -> {
|
||||
if (action.blockchain == null) {
|
||||
val wallets = newState.wallets.map { wallet ->
|
||||
|
||||
wallet.copy(
|
||||
currencyData = wallet.currencyData.copy(
|
||||
status = BalanceStatus.Loading,
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), StoreSubscriber<Walle
|
|||
}.select { it.walletState }
|
||||
}
|
||||
walletView.setFragment(this, binding)
|
||||
store.dispatch(WalletAction.UpdateWallet())
|
||||
store.dispatch(WalletAction.UpdateWallet(force = false))
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@
|
|||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
app:menu="@menu/shop"
|
||||
app:navigationIcon="@drawable/ic_baseline_arrow_back_24"
|
||||
app:title="@string/onboarding_getting_started" />
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<item
|
||||
android:id="@+id/shop_menu"
|
||||
android:title="@string/home_button_shop"
|
||||
app:showAsAction="always" />
|
||||
</menu>
|
||||
Loading…
Add table
Add a link
Reference in a new issue