Updated on 2026-08-14
This commit is contained in:
parent
0d2f6e2410
commit
17ba4a88e3
14 changed files with 127 additions and 215 deletions
|
|
@ -17,6 +17,7 @@ import com.tangem.datasource.asset.AssetReader
|
|||
import com.tangem.datasource.config.ConfigManager
|
||||
import com.tangem.datasource.config.FeaturesLocalLoader
|
||||
import com.tangem.datasource.config.models.Config
|
||||
import com.tangem.datasource.connection.NetworkConnectionManager
|
||||
import com.tangem.domain.DomainLayer
|
||||
import com.tangem.domain.common.LogConfig
|
||||
import com.tangem.tap.common.IntentHandler
|
||||
|
|
@ -49,7 +50,6 @@ import com.tangem.tap.domain.walletStores.repository.WalletManagersRepository
|
|||
import com.tangem.tap.domain.walletStores.repository.WalletStoresRepository
|
||||
import com.tangem.tap.domain.walletStores.repository.di.provideDefaultImplementation
|
||||
import com.tangem.tap.domain.walletconnect.WalletConnectRepository
|
||||
import com.tangem.tap.network.NetworkConnectivity
|
||||
import com.tangem.tap.persistence.PreferencesStorage
|
||||
import com.tangem.tap.proxy.AppStateHolder
|
||||
import com.tangem.tap.proxy.redux.DaggerGraphAction
|
||||
|
|
@ -124,6 +124,9 @@ class TapApplication : Application(), ImageLoaderFactory {
|
|||
@Inject
|
||||
lateinit var featureTogglesManager: FeatureTogglesManager
|
||||
|
||||
@Inject
|
||||
lateinit var networkConnectionManager: NetworkConnectionManager
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
|
||||
|
|
@ -144,7 +147,6 @@ class TapApplication : Application(), ImageLoaderFactory {
|
|||
registerActivityLifecycleCallbacks(foregroundActivityObserver.callbacks)
|
||||
|
||||
DomainLayer.init()
|
||||
NetworkConnectivity.createInstance(store, this)
|
||||
preferencesStorage = PreferencesStorage(this)
|
||||
walletConnectRepository = WalletConnectRepository(this)
|
||||
|
||||
|
|
@ -161,12 +163,18 @@ class TapApplication : Application(), ImageLoaderFactory {
|
|||
userTokensRepository = UserTokensRepository.init(
|
||||
context = this,
|
||||
tangemTechService = store.state.domainNetworks.tangemTechService,
|
||||
networkConnectionManager = networkConnectionManager,
|
||||
)
|
||||
appStateHolder.mainStore = store
|
||||
appStateHolder.userTokensRepository = userTokensRepository
|
||||
appStateHolder.walletStoresManager = walletStoresManager
|
||||
|
||||
store.dispatch(DaggerGraphAction.SetApplicationDependencies(assetReader))
|
||||
store.dispatch(
|
||||
action = DaggerGraphAction.SetApplicationDependencies(
|
||||
assetReader = assetReader,
|
||||
networkConnectionManager = networkConnectionManager,
|
||||
),
|
||||
)
|
||||
|
||||
scope.launch {
|
||||
featureTogglesManager.init()
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@ import com.tangem.tap.features.demo.isDemoCard
|
|||
import com.tangem.tap.features.wallet.models.Currency
|
||||
import com.tangem.tap.features.wallet.redux.AddressData
|
||||
import com.tangem.tap.features.wallet.redux.reducers.createAddressesData
|
||||
import com.tangem.tap.network.NetworkConnectivity
|
||||
import com.tangem.tap.network.exchangeServices.CurrencyExchangeManager
|
||||
import com.tangem.tap.proxy.redux.DaggerGraphState
|
||||
import com.tangem.tap.store
|
||||
import kotlinx.coroutines.delay
|
||||
import timber.log.Timber
|
||||
|
|
@ -47,7 +47,8 @@ suspend fun WalletManager.safeUpdate(): Result<Wallet> = try {
|
|||
} catch (exception: Exception) {
|
||||
Timber.e(exception)
|
||||
|
||||
if (!NetworkConnectivity.getInstance().isOnlineOrConnecting()) {
|
||||
val networkConnectionManager = store.state.daggerGraphState.get(DaggerGraphState::networkConnectionManager)
|
||||
if (!networkConnectionManager.isOnline) {
|
||||
Result.Failure(TapError.NoInternetConnection)
|
||||
} else {
|
||||
val blockchain = wallet.blockchain
|
||||
|
|
@ -87,8 +88,6 @@ fun WalletManager?.getAddressData(): AddressData? {
|
|||
return if (addressDataList.isEmpty()) null else addressDataList[0]
|
||||
}
|
||||
|
||||
fun WalletManager.getTxHistory(currency: Currency): List<TransactionData> = wallet.getTxHistory(currency)
|
||||
|
||||
fun WalletManager.getBlockchainTxHistory(): List<TransactionData> = wallet.getBlockchainTxHistory()
|
||||
|
||||
fun WalletManager.getTokenTxHistory(token: Token): List<TransactionData> = wallet.getTokenTxHistory(token)
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import com.tangem.common.core.TangemSdkError
|
|||
import com.tangem.datasource.api.tangemTech.TangemTechApi
|
||||
import com.tangem.datasource.api.tangemTech.TangemTechService
|
||||
import com.tangem.datasource.api.tangemTech.models.UserTokensResponse
|
||||
import com.tangem.datasource.connection.NetworkConnectionManager
|
||||
import com.tangem.domain.common.CardDTO
|
||||
import com.tangem.tap.common.AndroidFileReader
|
||||
import com.tangem.tap.domain.model.builders.UserWalletIdBuilder
|
||||
|
|
@ -15,7 +16,6 @@ import com.tangem.tap.features.demo.DemoHelper
|
|||
import com.tangem.tap.features.wallet.models.Currency
|
||||
import com.tangem.tap.features.wallet.models.toBlockchainNetworks
|
||||
import com.tangem.tap.features.wallet.models.toCurrencies
|
||||
import com.tangem.tap.network.NetworkConnectivity
|
||||
import com.tangem.utils.coroutines.AppCoroutineDispatcherProvider
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.withContext
|
||||
|
|
@ -25,6 +25,7 @@ class UserTokensRepository(
|
|||
private val storageService: UserTokensStorageService,
|
||||
private val tangemTechApi: TangemTechApi,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
private val networkConnectionManager: NetworkConnectionManager,
|
||||
) {
|
||||
|
||||
// TODO("After adding DI") replace with CoroutineDispatcherProvider
|
||||
|
|
@ -34,7 +35,7 @@ class UserTokensRepository(
|
|||
return@withContext loadTokensOffline(card, userId).ifEmpty(::loadDemoCurrencies)
|
||||
}
|
||||
|
||||
if (!NetworkConnectivity.getInstance().isOnlineOrConnecting()) {
|
||||
if (!networkConnectionManager.isOnline) {
|
||||
return@withContext loadTokensOffline(card, userId)
|
||||
}
|
||||
|
||||
|
|
@ -131,7 +132,11 @@ class UserTokensRepository(
|
|||
private const val NOT_FOUND_HTTP_CODE = "404"
|
||||
|
||||
// TODO("After adding DI") get dependencies by DI
|
||||
fun init(context: Context, tangemTechService: TangemTechService): UserTokensRepository {
|
||||
fun init(
|
||||
context: Context,
|
||||
tangemTechService: TangemTechService,
|
||||
networkConnectionManager: NetworkConnectionManager,
|
||||
): UserTokensRepository {
|
||||
val fileReader = AndroidFileReader(context)
|
||||
val dispatchers = AppCoroutineDispatcherProvider()
|
||||
|
||||
|
|
@ -149,6 +154,7 @@ class UserTokensRepository(
|
|||
storageService = storageService,
|
||||
tangemTechApi = tangemTechService.api,
|
||||
dispatchers = dispatchers,
|
||||
networkConnectionManager = networkConnectionManager,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,7 +44,8 @@ import com.tangem.tap.features.wallet.models.Currency
|
|||
import com.tangem.tap.features.wallet.models.PendingTransactionType
|
||||
import com.tangem.tap.features.wallet.models.filterByCoin
|
||||
import com.tangem.tap.features.wallet.models.getPendingTransactions
|
||||
import com.tangem.tap.network.NetworkConnectivity
|
||||
import com.tangem.tap.proxy.redux.DaggerGraphState
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.async
|
||||
|
|
@ -62,8 +63,6 @@ internal class DefaultWalletAmountsRepository(
|
|||
private val tangemTechApi: TangemTechApi,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
) : WalletAmountsRepository {
|
||||
private val walletStoresStorage = WalletStoresStorage
|
||||
private val walletManagersStorage = WalletManagerStorage
|
||||
|
||||
override suspend fun updateAmountsForUserWallets(
|
||||
userWallets: List<UserWallet>,
|
||||
|
|
@ -76,8 +75,7 @@ internal class DefaultWalletAmountsRepository(
|
|||
awaitAll(
|
||||
async { fetchAmountsForUserWallets(userWallets) },
|
||||
async { fetchFiatRates(userWallets, walletStores = null, fiatCurrency) },
|
||||
)
|
||||
.fold()
|
||||
).fold()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -104,8 +102,7 @@ internal class DefaultWalletAmountsRepository(
|
|||
awaitAll(
|
||||
async { fetchAmountForWalletStores(userWalletId, scanResponse, walletStores) },
|
||||
async { fetchFiatRates(listOf(userWallet), walletStores, fiatCurrency) },
|
||||
)
|
||||
.fold()
|
||||
).fold()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -123,41 +120,41 @@ internal class DefaultWalletAmountsRepository(
|
|||
walletStores: List<WalletStoreModel>?,
|
||||
fiatCurrency: FiatCurrency,
|
||||
): CompletionResult<Unit> {
|
||||
// FIXME: Use NetworkConnectionManager when it is added to DI
|
||||
if (!NetworkConnectivity.getInstance().isOnlineOrConnecting()) {
|
||||
val networkConnectionManager = store.state.daggerGraphState.get(DaggerGraphState::networkConnectionManager)
|
||||
if (!networkConnectionManager.isOnline) {
|
||||
return CompletionResult.Failure(WalletStoresError.NoInternetConnection)
|
||||
}
|
||||
|
||||
val walletStoresInternal = walletStores ?: getWalletStores(userWallets)
|
||||
val currencies = walletStoresInternal
|
||||
.asSequence()
|
||||
.flatMap { it.walletsData }
|
||||
.map { it.currency }
|
||||
val currencies = walletStoresInternal.asSequence().flatMap { it.walletsData }.map { it.currency }
|
||||
|
||||
val coinsIds = currencies.mapNotNull { it.coinId }.distinct().toList()
|
||||
|
||||
return withContext(dispatchers.io) {
|
||||
runCatching { tangemTechApi.getRates(fiatCurrency.code.lowercase(), coinsIds.joinToString(",")) }
|
||||
.onSuccess {
|
||||
updateWalletStoresWithFiatRates(walletStores = walletStoresInternal, fiatRates = it.rates)
|
||||
return@withContext CompletionResult.Success(Unit)
|
||||
}
|
||||
.onFailure {
|
||||
val error = WalletStoresError.FetchFiatRatesError(
|
||||
currencies = currencies.map(Currency::currencySymbol).toList(),
|
||||
cause = it,
|
||||
)
|
||||
runCatching {
|
||||
tangemTechApi.getRates(
|
||||
fiatCurrency.code.lowercase(),
|
||||
coinsIds.joinToString(","),
|
||||
)
|
||||
}.onSuccess {
|
||||
updateWalletStoresWithFiatRates(walletStores = walletStoresInternal, fiatRates = it.rates)
|
||||
return@withContext CompletionResult.Success(Unit)
|
||||
}.onFailure {
|
||||
val error = WalletStoresError.FetchFiatRatesError(
|
||||
currencies = currencies.map(Currency::currencySymbol).toList(),
|
||||
cause = it,
|
||||
)
|
||||
|
||||
Timber.e(
|
||||
error,
|
||||
"""
|
||||
Timber.e(
|
||||
error,
|
||||
"""
|
||||
Unable to fetch fiat rates
|
||||
|- Coins ids: $coinsIds
|
||||
""".trimIndent(),
|
||||
)
|
||||
""".trimIndent(),
|
||||
)
|
||||
|
||||
return@withContext CompletionResult.Failure(error)
|
||||
}
|
||||
return@withContext CompletionResult.Failure(error)
|
||||
}
|
||||
|
||||
error("Unreachable code because runCatching must return result")
|
||||
}
|
||||
|
|
@ -166,9 +163,7 @@ internal class DefaultWalletAmountsRepository(
|
|||
private suspend fun fetchAmountsForUserWallets(
|
||||
userWallets: List<UserWallet>,
|
||||
): CompletionResult<Unit> = withContext(Dispatchers.Default) {
|
||||
userWallets.map { async { fetchAmountsForUserWallet(it) } }
|
||||
.awaitAll()
|
||||
.fold()
|
||||
userWallets.map { async { fetchAmountsForUserWallet(it) } }.awaitAll().fold()
|
||||
}
|
||||
|
||||
private suspend fun fetchAmountsForUserWallet(
|
||||
|
|
@ -186,8 +181,8 @@ internal class DefaultWalletAmountsRepository(
|
|||
scanResponse: ScanResponse,
|
||||
walletStores: List<WalletStoreModel>,
|
||||
): CompletionResult<Unit> = coroutineScope {
|
||||
// FIXME: Use NetworkConnectionManager when it is added to DI
|
||||
if (!NetworkConnectivity.getInstance().isOnlineOrConnecting()) {
|
||||
val networkConnectionManager = store.state.daggerGraphState.get(DaggerGraphState::networkConnectionManager)
|
||||
if (!networkConnectionManager.isOnline) {
|
||||
walletStores.forEach {
|
||||
updateWalletStoreWithUnreachable(it)
|
||||
}
|
||||
|
|
@ -200,9 +195,7 @@ internal class DefaultWalletAmountsRepository(
|
|||
val walletManager = walletStore.walletManager
|
||||
fetchAmountsForWalletStore(userWalletId, scanResponse, walletStore, walletManager)
|
||||
}
|
||||
}
|
||||
.awaitAll()
|
||||
.fold()
|
||||
}.awaitAll().fold()
|
||||
}
|
||||
|
||||
private suspend fun fetchAmountsForWalletStore(
|
||||
|
|
@ -223,24 +216,25 @@ internal class DefaultWalletAmountsRepository(
|
|||
updateWalletStoreWithUnreachable(walletStore)
|
||||
}
|
||||
else -> {
|
||||
updateWalletManager(scanResponse, walletManager)
|
||||
.map { updateWalletManagerInStorage(userWalletId, walletManager) }
|
||||
.flatMap {
|
||||
updateWalletStoreWithAmounts(
|
||||
walletStore = walletStore,
|
||||
updatedWallet = walletManager.wallet,
|
||||
// FIXME: move DemoHelper to Demo core module maybe
|
||||
isDemo = DemoHelper.isDemoCardId(scanResponse.card.cardId),
|
||||
)
|
||||
}
|
||||
.flatMap { fetchWalletStoreRentIfNeeded(walletStore, walletManager) }
|
||||
.flatMapOnFailure { error ->
|
||||
updateWalletStoreWithError(
|
||||
walletStore = walletStore,
|
||||
wallet = walletManager.wallet,
|
||||
error = error,
|
||||
)
|
||||
}
|
||||
updateWalletManager(scanResponse, walletManager).map {
|
||||
updateWalletManagerInStorage(
|
||||
userWalletId,
|
||||
walletManager,
|
||||
)
|
||||
}.flatMap {
|
||||
updateWalletStoreWithAmounts(
|
||||
walletStore = walletStore,
|
||||
updatedWallet = walletManager.wallet,
|
||||
// FIXME: move DemoHelper to Demo core module maybe
|
||||
isDemo = DemoHelper.isDemoCardId(scanResponse.card.cardId),
|
||||
)
|
||||
}.flatMap { fetchWalletStoreRentIfNeeded(walletStore, walletManager) }.flatMapOnFailure { error ->
|
||||
updateWalletStoreWithError(
|
||||
walletStore = walletStore,
|
||||
wallet = walletManager.wallet,
|
||||
error = error,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -267,8 +261,7 @@ internal class DefaultWalletAmountsRepository(
|
|||
walletStore: WalletStoreModel,
|
||||
walletManager: WalletManager,
|
||||
): CompletionResult<Unit> {
|
||||
val rentProvider = walletManager as? RentProvider
|
||||
?: return CompletionResult.Success(Unit)
|
||||
val rentProvider = walletManager as? RentProvider ?: return CompletionResult.Success(Unit)
|
||||
|
||||
when (val result = rentProvider.minimalBalanceForRentExemption()) {
|
||||
is Success -> {
|
||||
|
|
@ -318,7 +311,7 @@ internal class DefaultWalletAmountsRepository(
|
|||
)
|
||||
|
||||
if (error is BlockchainSdkError) {
|
||||
walletStoresStorage.update { prevState ->
|
||||
WalletStoresStorage.update { prevState ->
|
||||
prevState.replaceWalletStore(
|
||||
walletStoreToUpdate = walletStore,
|
||||
update = {
|
||||
|
|
@ -350,7 +343,7 @@ internal class DefaultWalletAmountsRepository(
|
|||
""".trimIndent(),
|
||||
)
|
||||
|
||||
walletStoresStorage.update { prevState ->
|
||||
WalletStoresStorage.update { prevState ->
|
||||
prevState.replaceWalletStore(
|
||||
walletStoreToUpdate = walletStore,
|
||||
update = {
|
||||
|
|
@ -378,7 +371,7 @@ internal class DefaultWalletAmountsRepository(
|
|||
""".trimIndent(),
|
||||
)
|
||||
|
||||
walletStoresStorage.update { prevState ->
|
||||
WalletStoresStorage.update { prevState ->
|
||||
prevState.replaceWalletStore(
|
||||
walletStoreToUpdate = walletStore,
|
||||
update = {
|
||||
|
|
@ -402,7 +395,7 @@ internal class DefaultWalletAmountsRepository(
|
|||
""".trimIndent(),
|
||||
)
|
||||
|
||||
walletStoresStorage.update { prevState ->
|
||||
WalletStoresStorage.update { prevState ->
|
||||
prevState.replaceWalletStore(
|
||||
walletStoreToUpdate = walletStore,
|
||||
update = {
|
||||
|
|
@ -425,7 +418,7 @@ internal class DefaultWalletAmountsRepository(
|
|||
""".trimIndent(),
|
||||
)
|
||||
|
||||
walletStoresStorage.update { prevState ->
|
||||
WalletStoresStorage.update { prevState ->
|
||||
prevState.replaceWalletStores(
|
||||
walletStoresToUpdate = walletStores,
|
||||
update = {
|
||||
|
|
@ -450,7 +443,7 @@ internal class DefaultWalletAmountsRepository(
|
|||
)
|
||||
|
||||
if (rent != walletStore.walletRent) {
|
||||
walletStoresStorage.update { prevState ->
|
||||
WalletStoresStorage.update { prevState ->
|
||||
prevState.replaceWalletStore(
|
||||
walletStoreToUpdate = walletStore,
|
||||
update = {
|
||||
|
|
@ -465,14 +458,12 @@ internal class DefaultWalletAmountsRepository(
|
|||
userWalletId: UserWalletId,
|
||||
walletManager: WalletManager,
|
||||
) = withContext(Dispatchers.Default) {
|
||||
walletManagersStorage.update { prevManagers ->
|
||||
val newManagersForUserWallet = prevManagers[userWalletId].orEmpty()
|
||||
.toMutableList()
|
||||
.apply {
|
||||
replaceByOrAdd(walletManager) {
|
||||
it.wallet.blockchain == walletManager.wallet.blockchain
|
||||
}
|
||||
WalletManagerStorage.update { prevManagers ->
|
||||
val newManagersForUserWallet = prevManagers[userWalletId].orEmpty().toMutableList().apply {
|
||||
replaceByOrAdd(walletManager) {
|
||||
it.wallet.blockchain == walletManager.wallet.blockchain
|
||||
}
|
||||
}
|
||||
|
||||
prevManagers.apply {
|
||||
set(userWalletId, newManagersForUserWallet)
|
||||
|
|
@ -481,13 +472,8 @@ internal class DefaultWalletAmountsRepository(
|
|||
}
|
||||
|
||||
private suspend fun getWalletStores(userWallets: List<UserWallet>): List<WalletStoreModel> {
|
||||
return userWallets
|
||||
.map { it.walletId }
|
||||
.flatMap { userWalletId ->
|
||||
walletStoresStorage.getAll()
|
||||
.firstOrNull()
|
||||
?.get(userWalletId)
|
||||
.orEmpty()
|
||||
}
|
||||
return userWallets.map { it.walletId }.flatMap { userWalletId ->
|
||||
WalletStoresStorage.getAll().firstOrNull()?.get(userWalletId).orEmpty()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -31,6 +31,7 @@ import com.tangem.tap.common.redux.navigation.NavigationAction
|
|||
import com.tangem.tap.domain.TapError
|
||||
import com.tangem.tap.domain.tokens.LoadAvailableCoinsService
|
||||
import com.tangem.tap.features.wallet.models.Currency
|
||||
import com.tangem.tap.proxy.redux.DaggerGraphState
|
||||
import com.tangem.tap.scope
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.tap.tangemSdkManager
|
||||
|
|
@ -84,7 +85,7 @@ class TokensMiddleware {
|
|||
val loadCoinsService = LoadAvailableCoinsService(
|
||||
tangemTechApi = store.state.domainNetworks.tangemTechService.api,
|
||||
dispatchers = AppCoroutineDispatcherProvider(),
|
||||
assetReader = requireNotNull(store.state.daggerGraphState.assetReader) { "Asset reader is null" },
|
||||
assetReader = store.state.daggerGraphState.get(DaggerGraphState::assetReader),
|
||||
)
|
||||
|
||||
scope.launch {
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import com.tangem.blockchain.common.AmountType
|
|||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.common.extensions.guard
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.datasource.connection.NetworkConnectionManager
|
||||
import com.tangem.tap.common.analytics.converters.BasicEventsPreChecker
|
||||
import com.tangem.tap.common.analytics.converters.BasicEventsSourceData
|
||||
import com.tangem.tap.common.analytics.events.AnalyticsParam
|
||||
|
|
@ -37,15 +38,13 @@ import com.tangem.tap.features.wallet.redux.WalletData
|
|||
import com.tangem.tap.features.wallet.redux.WalletState
|
||||
import com.tangem.tap.features.wallet.redux.WalletStore
|
||||
import com.tangem.tap.features.wallet.redux.reducers.findSelectedCurrency
|
||||
import com.tangem.tap.network.NetworkConnectivity
|
||||
import com.tangem.tap.network.NetworkStateChanged
|
||||
import com.tangem.tap.preferencesStorage
|
||||
import com.tangem.tap.proxy.redux.DaggerGraphState
|
||||
import com.tangem.tap.scope
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.tap.tangemSdkManager
|
||||
import com.tangem.tap.totalFiatBalanceCalculator
|
||||
import com.tangem.tap.userWalletsListManager
|
||||
import com.tangem.tap.userWalletsListManagerSafe
|
||||
import com.tangem.tap.walletStoresManager
|
||||
import com.tangem.wallet.R
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
|
|
@ -72,6 +71,9 @@ class WalletMiddleware {
|
|||
)
|
||||
}
|
||||
|
||||
private val networkConnectionManager: NetworkConnectionManager
|
||||
get() = store.state.daggerGraphState.get(DaggerGraphState::networkConnectionManager)
|
||||
|
||||
val walletMiddleware: Middleware<AppState> = { _, state ->
|
||||
{ next ->
|
||||
{ action ->
|
||||
|
|
@ -135,16 +137,6 @@ class WalletMiddleware {
|
|||
)
|
||||
}
|
||||
}
|
||||
is NetworkStateChanged -> {
|
||||
store.dispatch(WalletAction.Warnings.CheckHashesCount.CheckHashesCountOnline)
|
||||
if (!action.isOnline) return
|
||||
|
||||
val selectedUserWallet = userWalletsListManagerSafe?.selectedUserWalletSync.guard {
|
||||
Timber.e("Unable to proceed with changed network state, no user wallet selected")
|
||||
return
|
||||
}
|
||||
scope.launch { globalState.tapWalletManager.loadData(selectedUserWallet, refresh = true) }
|
||||
}
|
||||
is WalletAction.CopyAddress -> {
|
||||
Analytics.send(Token.Receive.ButtonCopyAddress())
|
||||
action.context.copyToClipboard(action.address)
|
||||
|
|
@ -159,7 +151,7 @@ class WalletMiddleware {
|
|||
store.dispatchOpenUrl(action.exploreUrl)
|
||||
}
|
||||
is WalletAction.Send -> {
|
||||
if (!NetworkConnectivity.getInstance().isOnlineOrConnecting()) {
|
||||
if (!networkConnectionManager.isOnline) {
|
||||
store.dispatchErrorNotification(TapError.NoInternetConnection)
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,29 +2,26 @@ package com.tangem.tap.features.wallet.redux.middlewares
|
|||
|
||||
import com.tangem.blockchain.common.BlockchainSdkError
|
||||
import com.tangem.blockchain.common.SignatureCountValidator
|
||||
import com.tangem.blockchain.common.Wallet
|
||||
import com.tangem.blockchain.extensions.SimpleResult
|
||||
import com.tangem.common.card.FirmwareVersion
|
||||
import com.tangem.domain.common.CardDTO
|
||||
import com.tangem.domain.common.ScanResponse
|
||||
import com.tangem.domain.common.TapWorkarounds.isTestCard
|
||||
import com.tangem.tap.common.extensions.dispatchOnMain
|
||||
import com.tangem.tap.common.extensions.isGreaterThan
|
||||
import com.tangem.tap.common.redux.global.GlobalState
|
||||
import com.tangem.tap.domain.configurable.warningMessage.WarningMessage
|
||||
import com.tangem.tap.domain.configurable.warningMessage.WarningMessagesManager
|
||||
import com.tangem.tap.domain.extensions.hasSignedHashes
|
||||
import com.tangem.tap.features.demo.isDemoCard
|
||||
import com.tangem.tap.features.wallet.redux.WalletAction
|
||||
import com.tangem.tap.network.NetworkConnectivity
|
||||
import com.tangem.tap.preferencesStorage
|
||||
import com.tangem.tap.proxy.redux.DaggerGraphState
|
||||
import com.tangem.tap.scope
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.math.BigDecimal
|
||||
|
||||
class WarningsMiddleware {
|
||||
fun handle(action: WalletAction.Warnings, globalState: GlobalState?) {
|
||||
|
|
@ -75,13 +72,6 @@ class WarningsMiddleware {
|
|||
}
|
||||
}
|
||||
|
||||
fun tryToShowAppRatingWarning(wallet: Wallet) {
|
||||
val nonZeroWalletsCount = wallet.amounts.filter {
|
||||
it.value.value?.isGreaterThan(BigDecimal.ZERO) ?: false
|
||||
}.size
|
||||
tryToShowAppRatingWarning(hasNonZeroWallets = nonZeroWalletsCount > 0)
|
||||
}
|
||||
|
||||
private fun showCardWarningsIfNeeded(globalState: GlobalState?) {
|
||||
globalState?.scanResponse?.let { scanResponse ->
|
||||
val card = scanResponse.card
|
||||
|
|
@ -147,7 +137,9 @@ class WarningsMiddleware {
|
|||
|
||||
private fun checkHashesCountOnline() {
|
||||
if (store.state.walletState.hashesCountVerified != false) return
|
||||
if (!NetworkConnectivity.getInstance().isOnlineOrConnecting()) return
|
||||
|
||||
val networkConnectionManager = store.state.daggerGraphState.get(DaggerGraphState::networkConnectionManager)
|
||||
if (!networkConnectionManager.isOnline) return
|
||||
|
||||
val scanResponse = store.state.globalState.scanResponse
|
||||
val card = scanResponse?.card
|
||||
|
|
|
|||
|
|
@ -1,71 +0,0 @@
|
|||
package com.tangem.tap.network
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.net.ConnectivityManager
|
||||
import android.net.NetworkCapabilities
|
||||
import android.os.Build
|
||||
import org.rekotlin.Action
|
||||
import org.rekotlin.Store
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
@Deprecated("Use com.tangem.datasource.connection.NetworkConnectionManager")
|
||||
class NetworkConnectivity(
|
||||
private val store: Store<*>,
|
||||
context: Context,
|
||||
) {
|
||||
|
||||
private val wContext: WeakReference<Context> = WeakReference(context)
|
||||
|
||||
private val receiver = object : BroadcastReceiver() {
|
||||
override fun onReceive(c: Context?, intent: Intent?) {
|
||||
store.dispatch(NetworkStateChanged(isOnlineOrConnecting()))
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
val intentFilter = IntentFilter()
|
||||
intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION)
|
||||
wContext.get()?.registerReceiver(receiver, intentFilter)
|
||||
store.dispatch(NetworkStateChanged(isOnlineOrConnecting()))
|
||||
}
|
||||
|
||||
fun isOnlineOrConnecting(): Boolean {
|
||||
val connectivityManager = getConnectivityManager() ?: return false
|
||||
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
val capabilities = connectivityManager.getNetworkCapabilities(connectivityManager.activeNetwork)
|
||||
capabilities != null &&
|
||||
(capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) ||
|
||||
capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) ||
|
||||
capabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN) ||
|
||||
capabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET))
|
||||
} else {
|
||||
val networkInfo = connectivityManager.activeNetworkInfo
|
||||
networkInfo != null && networkInfo.isConnectedOrConnecting
|
||||
}
|
||||
}
|
||||
|
||||
private fun getConnectivityManager(): ConnectivityManager? {
|
||||
return wContext.get()?.applicationContext
|
||||
?.getSystemService(Context.CONNECTIVITY_SERVICE) as? ConnectivityManager
|
||||
}
|
||||
|
||||
companion object {
|
||||
private lateinit var instance: NetworkConnectivity
|
||||
|
||||
fun createInstance(store: Store<*>, context: Context): NetworkConnectivity {
|
||||
instance = NetworkConnectivity(store, context)
|
||||
return instance
|
||||
}
|
||||
|
||||
fun getInstance(): NetworkConnectivity = instance
|
||||
}
|
||||
}
|
||||
|
||||
data class NetworkStateChanged(val isOnline: Boolean) : Action
|
||||
|
|
@ -1,12 +1,16 @@
|
|||
package com.tangem.tap.proxy.redux
|
||||
|
||||
import com.tangem.datasource.asset.AssetReader
|
||||
import com.tangem.datasource.connection.NetworkConnectionManager
|
||||
import com.tangem.features.tester.api.TesterRouter
|
||||
import org.rekotlin.Action
|
||||
|
||||
sealed interface DaggerGraphAction : Action {
|
||||
|
||||
data class SetApplicationDependencies(val assetReader: AssetReader) : DaggerGraphAction
|
||||
data class SetApplicationDependencies(
|
||||
val assetReader: AssetReader,
|
||||
val networkConnectionManager: NetworkConnectionManager,
|
||||
) : DaggerGraphAction
|
||||
|
||||
data class SetActivityDependencies(val testerRouter: TesterRouter) : DaggerGraphAction
|
||||
}
|
||||
|
|
@ -13,10 +13,11 @@ object DaggerGraphReducer {
|
|||
private fun internalReduce(action: DaggerGraphAction, state: AppState): DaggerGraphState {
|
||||
return when (action) {
|
||||
is DaggerGraphAction.SetApplicationDependencies -> state.daggerGraphState.copy(
|
||||
assetReader = action.assetReader
|
||||
assetReader = action.assetReader,
|
||||
networkConnectionManager = action.networkConnectionManager,
|
||||
)
|
||||
is DaggerGraphAction.SetActivityDependencies -> state.daggerGraphState.copy(
|
||||
testerRouter = action.testerRouter
|
||||
testerRouter = action.testerRouter,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,19 @@
|
|||
package com.tangem.tap.proxy.redux
|
||||
|
||||
import com.tangem.datasource.asset.AssetReader
|
||||
import com.tangem.datasource.connection.NetworkConnectionManager
|
||||
import com.tangem.features.tester.api.TesterRouter
|
||||
import org.rekotlin.StateType
|
||||
|
||||
data class DaggerGraphState(
|
||||
val assetReader: AssetReader? = null,
|
||||
val testerRouter: TesterRouter? = null,
|
||||
) : StateType
|
||||
val networkConnectionManager: NetworkConnectionManager? = null,
|
||||
) : StateType {
|
||||
|
||||
inline fun <reified T> get(getDependency: DaggerGraphState.() -> T?): T {
|
||||
return requireNotNull(getDependency()) {
|
||||
"${T::class.simpleName} isn't initialized "
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -15,7 +15,6 @@ import dagger.hilt.android.qualifiers.ApplicationContext
|
|||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
|
@ -36,9 +35,9 @@ internal class AndroidNetworkConnectionManager @Inject constructor(
|
|||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
) : NetworkConnectionManager {
|
||||
|
||||
override val connectionStatus: StateFlow<ConnectionStatus> get() = _connectionStatus
|
||||
override val isOnline: Boolean get() = _isOnline.value
|
||||
|
||||
private val _connectionStatus = MutableStateFlow(ConnectionStatus.OFFLINE)
|
||||
private val _isOnline = MutableStateFlow(value = false)
|
||||
private val callbacks = NetworkConnectionManagerCallbacks()
|
||||
private val receiver = NetworkConnectionBroadcastReceiver()
|
||||
|
||||
|
|
@ -78,28 +77,26 @@ internal class AndroidNetworkConnectionManager @Inject constructor(
|
|||
|
||||
CoroutineScope(SupervisorJob()).launch(dispatchers.io) {
|
||||
try {
|
||||
val status = getCurrentStatus()
|
||||
val status = isConnected()
|
||||
|
||||
_connectionStatus.emit(value = status)
|
||||
Timber.i("Status changed to $status")
|
||||
_isOnline.emit(value = status)
|
||||
Timber.i("Connection status is ${if (status) "ONLINE" else "OFFLINE"}")
|
||||
} finally {
|
||||
pendingResult.finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getCurrentStatus(): ConnectionStatus {
|
||||
connectivityManager ?: return ConnectionStatus.OFFLINE
|
||||
private fun isConnected(): Boolean {
|
||||
connectivityManager ?: return false
|
||||
|
||||
val isConnected = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
val capabilities = connectivityManager.getNetworkCapabilities(connectivityManager.activeNetwork)
|
||||
capabilities != null && capabilities.hasNetworkTransport()
|
||||
} else {
|
||||
val networkInfo = connectivityManager.activeNetworkInfo
|
||||
networkInfo != null && networkInfo.isConnectedOrConnecting
|
||||
}
|
||||
|
||||
return if (isConnected) ConnectionStatus.ONLINE else ConnectionStatus.OFFLINE
|
||||
}
|
||||
|
||||
private fun NetworkCapabilities.hasNetworkTransport(): Boolean {
|
||||
|
|
|
|||
|
|
@ -1,10 +0,0 @@
|
|||
package com.tangem.datasource.connection
|
||||
|
||||
/**
|
||||
* Network connection status
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
enum class ConnectionStatus {
|
||||
ONLINE, OFFLINE
|
||||
}
|
||||
|
|
@ -1,10 +1,8 @@
|
|||
package com.tangem.datasource.connection
|
||||
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
/** Network connection manager */
|
||||
interface NetworkConnectionManager {
|
||||
|
||||
/** Connection status */
|
||||
val connectionStatus: StateFlow<ConnectionStatus>
|
||||
val isOnline: Boolean
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue