diff --git a/app/src/main/assets/tangem-app-config b/app/src/main/assets/tangem-app-config index d52c8382e9..cf01c91626 160000 --- a/app/src/main/assets/tangem-app-config +++ b/app/src/main/assets/tangem-app-config @@ -1 +1 @@ -Subproject commit d52c8382e9e94b2b44ceecd7cb7bd897e091073c +Subproject commit cf01c91626bf58bdf6895c59a706b83c37a9e345 diff --git a/core/datasource/build.gradle.kts b/core/datasource/build.gradle.kts index 0a236d6e5a..494f2c12e6 100644 --- a/core/datasource/build.gradle.kts +++ b/core/datasource/build.gradle.kts @@ -50,7 +50,6 @@ dependencies { implementation(deps.okHttp.prettyLogging) implementation(deps.retrofit) implementation(deps.retrofit.moshi) - implementation(deps.reactive.network) /** Time */ implementation(deps.jodatime) diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/express/models/response/ExchangeStatusResponse.kt b/core/datasource/src/main/java/com/tangem/datasource/api/express/models/response/ExchangeStatusResponse.kt index 7682c70d4f..a56308d255 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/api/express/models/response/ExchangeStatusResponse.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/express/models/response/ExchangeStatusResponse.kt @@ -64,6 +64,9 @@ enum class ExchangeStatus { @Json(name = "tx-failed") TxFailed, + @Json(name = "paused") + Paused, + @Json(name = "unknown") Unknown, } diff --git a/core/datasource/src/main/java/com/tangem/datasource/connection/AndroidNetworkConnectionManager.kt b/core/datasource/src/main/java/com/tangem/datasource/connection/AndroidNetworkConnectionManager.kt new file mode 100644 index 0000000000..3e91a7016f --- /dev/null +++ b/core/datasource/src/main/java/com/tangem/datasource/connection/AndroidNetworkConnectionManager.kt @@ -0,0 +1,26 @@ +package com.tangem.datasource.connection + +import android.content.Context +import android.net.ConnectivityManager +import android.net.Network +import android.net.NetworkCapabilities +import androidx.core.content.ContextCompat + +internal class AndroidNetworkConnectionManager( + private val applicationContext: Context, +) : NetworkConnectionManager { + + override val isOnline: Boolean + get() = isNetworkAvailable() + + private fun isNetworkAvailable(): Boolean { + val connectivityManager = ContextCompat.getSystemService(applicationContext, ConnectivityManager::class.java) + + // Network that is currently in use (several networks can be presented at the same time) + val defaultNetwork: Network = connectivityManager?.activeNetwork ?: return false + val networkCapabilities: NetworkCapabilities = + connectivityManager.getNetworkCapabilities(defaultNetwork) ?: return false + + return networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + } +} \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/connection/NetworkConnectionManager.kt b/core/datasource/src/main/java/com/tangem/datasource/connection/NetworkConnectionManager.kt index dc1c3e9051..fa6faca57d 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/connection/NetworkConnectionManager.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/connection/NetworkConnectionManager.kt @@ -1,13 +1,8 @@ package com.tangem.datasource.connection -import kotlinx.coroutines.flow.StateFlow - /** Network connection manager */ interface NetworkConnectionManager { /** Connection status */ val isOnline: Boolean - - /** Connection status flow */ - val isOnlineFlow: StateFlow } \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/connection/RealInternetConnectionManager.kt b/core/datasource/src/main/java/com/tangem/datasource/connection/RealInternetConnectionManager.kt deleted file mode 100644 index 7a3279d188..0000000000 --- a/core/datasource/src/main/java/com/tangem/datasource/connection/RealInternetConnectionManager.kt +++ /dev/null @@ -1,53 +0,0 @@ -package com.tangem.datasource.connection - -import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork -import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings -import com.tangem.utils.coroutines.FeatureCoroutineExceptionHandler -import io.reactivex.BackpressureStrategy -import io.reactivex.schedulers.Schedulers -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.SupervisorJob -import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.stateIn -import kotlinx.coroutines.reactive.asFlow - -private const val PING_SERVER = "https://clients3.google.com/generate_204" -private const val PING_INTERVAL = 5_000 - -internal class RealInternetConnectionManager : NetworkConnectionManager { - - private val scope = - CoroutineScope( - SupervisorJob() + Dispatchers.IO + FeatureCoroutineExceptionHandler.create("RealInternetConnectionManager"), - ) - - private val initialNetworkResult: Boolean by lazy { - ReactiveNetwork - .checkInternetConnectivity( - InternetObservingSettings.builder() - .host(PING_SERVER) - .port(443) - .build(), - ) - .subscribeOn(Schedulers.io()) - .observeOn(Schedulers.io()) - .blockingGet() - } - - override val isOnlineFlow: StateFlow = ReactiveNetwork - .observeInternetConnectivity( - InternetObservingSettings.builder() - .host(PING_SERVER) - .port(443) - .interval(PING_INTERVAL) - .build(), - ) - .toFlowable(BackpressureStrategy.LATEST) - .asFlow() - .stateIn(scope, SharingStarted.Lazily, initialValue = initialNetworkResult) - - override val isOnline: Boolean - get() = isOnlineFlow.value -} \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/di/NetworkConnectionModule.kt b/core/datasource/src/main/java/com/tangem/datasource/di/NetworkConnectionModule.kt index b3eca89707..f698c5144d 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/di/NetworkConnectionModule.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/di/NetworkConnectionModule.kt @@ -1,10 +1,12 @@ package com.tangem.datasource.di +import android.content.Context +import com.tangem.datasource.connection.AndroidNetworkConnectionManager import com.tangem.datasource.connection.NetworkConnectionManager -import com.tangem.datasource.connection.RealInternetConnectionManager import dagger.Module import dagger.Provides import dagger.hilt.InstallIn +import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.components.SingletonComponent import javax.inject.Singleton @@ -14,7 +16,7 @@ internal class NetworkConnectionModule { @Provides @Singleton - fun provideNetworkConnectionManager(): NetworkConnectionManager { - return RealInternetConnectionManager() + fun provideNetworkConnectionManager(@ApplicationContext applicationContext: Context): NetworkConnectionManager { + return AndroidNetworkConnectionManager(applicationContext = applicationContext) } } \ No newline at end of file diff --git a/data/manage-tokens/src/main/kotlin/com/tangem/data/managetokens/DefaultManageTokensRepository.kt b/data/manage-tokens/src/main/kotlin/com/tangem/data/managetokens/DefaultManageTokensRepository.kt index a62a1be508..70c7c69396 100644 --- a/data/manage-tokens/src/main/kotlin/com/tangem/data/managetokens/DefaultManageTokensRepository.kt +++ b/data/manage-tokens/src/main/kotlin/com/tangem/data/managetokens/DefaultManageTokensRepository.kt @@ -99,6 +99,7 @@ internal class DefaultManageTokensRepository( loadUserTokensFromRemote: Boolean, ): BatchFetchResult.Success> { val supportedBlockchains = getSupportedBlockchains(userWallet) + val query = request.params.searchText.takeUnless(String?::isNullOrBlank) val call = suspend { tangemTechApi.getCoins( @@ -107,7 +108,7 @@ internal class DefaultManageTokensRepository( transform = Blockchain::toNetworkId, ), active = true, - searchText = request.params.searchText, + searchText = query, offset = request.offset * request.limit, limit = request.limit, ).getOrThrow() @@ -135,7 +136,7 @@ internal class DefaultManageTokensRepository( val items = if (isFirstBatchFetching && tokensResponse != null && userWallet != null && - request.params.searchText.isNullOrBlank() + query == null ) { managedCryptoCurrencyFactory.createWithCustomTokens( coinsResponse = updatedCoinsResponse, diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/confirm/SendNotificationFactory.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/confirm/SendNotificationFactory.kt index 1bf9b9ed01..23f483ef38 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/confirm/SendNotificationFactory.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/confirm/SendNotificationFactory.kt @@ -93,7 +93,7 @@ internal class SendNotificationFactory constructor( val currencyCheck = getCurrencyCheckUseCase( userWalletId = userWalletId, currencyStatus = cryptoCurrencyStatus, - amount = amountValue, + amount = sendingAmount, fee = feeValue, ) buildList { diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/custom/EthereumCustomFeeConverter.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/custom/EthereumCustomFeeConverter.kt index 0757bdfc78..b65735aeb2 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/custom/EthereumCustomFeeConverter.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/custom/EthereumCustomFeeConverter.kt @@ -128,4 +128,8 @@ internal class EthereumCustomFeeConverter( const val GAS_DECIMALS = 0 const val FEE_AMOUNT = 0 } +} + +internal fun MutableList.setEmpty(index: Int) { + set(index, this[index].copy(value = "")) } \ No newline at end of file diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/custom/EthereumEIPCustomFeeConverter.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/custom/EthereumEIPCustomFeeConverter.kt index 397af3dbf4..a3d874d526 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/custom/EthereumEIPCustomFeeConverter.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/custom/EthereumEIPCustomFeeConverter.kt @@ -12,6 +12,7 @@ import com.tangem.core.ui.utils.parseToBigDecimal import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.tokens.model.CryptoCurrencyStatus import com.tangem.features.send.impl.R +import com.tangem.features.send.impl.presentation.state.fee.checkExceedBalance import com.tangem.features.send.impl.presentation.state.fee.custom.EthereumCustomFeeConverter.Companion.ETHEREUM_GAS_UNIT import com.tangem.features.send.impl.presentation.state.fee.custom.EthereumCustomFeeConverter.Companion.FEE_AMOUNT import com.tangem.features.send.impl.presentation.state.fee.custom.EthereumCustomFeeConverter.Companion.GAS_DECIMALS @@ -85,15 +86,12 @@ internal class EthereumEIPCustomFeeConverter( when (index) { FEE_AMOUNT -> setOnAmountChange(value, index) MAX_FEE -> setOnMaxFeeChange(value, index) + GAS_LIMIT -> setOnGasLimitChange(value, index) else -> set(index, this[index].copy(value = value)) } }.toImmutableList() } - private fun MutableList.setEmpty(index: Int) { - set(index, this[index].copy(value = "")) - } - private fun MutableList.setOnAmountChange(value: String, index: Int) { val gasLimit = this[GAS_LIMIT].value.parseToBigDecimal(this[GAS_LIMIT].decimals) if (value.isBlank()) { @@ -148,6 +146,48 @@ internal class EthereumEIPCustomFeeConverter( } } + private fun MutableList.setOnGasLimitChange(value: String, index: Int) { + if (value.isBlank()) { + setEmpty(FEE_AMOUNT) + setEmpty(GAS_LIMIT) + } else { + val newGasLimit = value.parseToBigDecimal(this[GAS_LIMIT].decimals) + + val maxFee = this[MAX_FEE].value.parseToBigDecimal(this[MAX_FEE].decimals) + .movePointLeft(this[MAX_FEE].decimals) // from GWEI to ETH + + val newFeeAmount = newGasLimit * maxFee + + set( + index = FEE_AMOUNT, + element = this[FEE_AMOUNT].copy( + value = newFeeAmount.parseBigDecimal(this[FEE_AMOUNT].decimals), + label = getFiatReference( + rate = feeCryptoCurrencyStatusProvider()?.value?.fiatRate, + value = newFeeAmount, + appCurrency = appCurrencyProvider(), + ), + ), + ) + + val isNotExceedBalance = checkExceedBalance( + feeBalance = feeCryptoCurrencyStatusProvider()?.value?.amount, + feeAmount = newFeeAmount, + ) + + set( + index = index, + element = this[index].copy( + value = value, + keyboardOptions = KeyboardOptions( + imeAction = if (!isNotExceedBalance) ImeAction.None else ImeAction.Done, + keyboardType = KeyboardType.Number, + ), + ), + ) + } + } + private companion object { const val MAX_FEE = 1 const val PRIORITY_FEE = 2 diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/custom/EthereumLegacyCustomFeeConverter.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/custom/EthereumLegacyCustomFeeConverter.kt index 4783cd62c4..b4058dd76d 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/custom/EthereumLegacyCustomFeeConverter.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/custom/EthereumLegacyCustomFeeConverter.kt @@ -12,6 +12,7 @@ import com.tangem.core.ui.utils.parseToBigDecimal import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.tokens.model.CryptoCurrencyStatus import com.tangem.features.send.impl.R +import com.tangem.features.send.impl.presentation.state.fee.checkExceedBalance import com.tangem.features.send.impl.presentation.state.fee.custom.EthereumCustomFeeConverter.Companion.ETHEREUM_GAS_UNIT import com.tangem.features.send.impl.presentation.state.fee.custom.EthereumCustomFeeConverter.Companion.FEE_AMOUNT import com.tangem.features.send.impl.presentation.state.fee.custom.EthereumCustomFeeConverter.Companion.GAS_DECIMALS @@ -76,15 +77,12 @@ internal class EthereumLegacyCustomFeeConverter( when (index) { FEE_AMOUNT -> setOnAmountChange(value, index) GAS_PRICE -> setOnGasPriceChange(value, index) + GAS_LIMIT -> setOnGasLimitChange(value, index) else -> set(index, this[index].copy(value = value)) } }.toImmutableList() } - private fun MutableList.setEmpty(index: Int) { - set(index, this[index].copy(value = "")) - } - private fun MutableList.setOnAmountChange(value: String, index: Int) { val gasLimit = this[GAS_LIMIT].value.parseToBigDecimal(this[GAS_LIMIT].decimals) if (value.isBlank()) { @@ -133,6 +131,47 @@ internal class EthereumLegacyCustomFeeConverter( } } + private fun MutableList.setOnGasLimitChange(value: String, index: Int) { + if (value.isBlank()) { + setEmpty(FEE_AMOUNT) + setEmpty(GAS_LIMIT) + } else { + val newGasLimit = value.parseToBigDecimal(this[GAS_LIMIT].decimals) + val gasPrice = this[GAS_PRICE].value.parseToBigDecimal(this[GAS_PRICE].decimals) + .movePointLeft(this[GAS_PRICE].decimals) // from GWEI to ETH + + val newFeeAmount = newGasLimit * gasPrice + + set( + index = FEE_AMOUNT, + element = this[FEE_AMOUNT].copy( + value = newFeeAmount.parseBigDecimal(this[FEE_AMOUNT].decimals), + label = getFiatReference( + rate = feeCryptoCurrencyStatusProvider()?.value?.fiatRate, + value = newFeeAmount, + appCurrency = appCurrencyProvider(), + ), + ), + ) + + val isNotExceedBalance = checkExceedBalance( + feeBalance = feeCryptoCurrencyStatusProvider()?.value?.amount, + feeAmount = newFeeAmount, + ) + + set( + index = index, + element = this[index].copy( + value = value, + keyboardOptions = KeyboardOptions( + imeAction = if (!isNotExceedBalance) ImeAction.None else ImeAction.Done, + keyboardType = KeyboardType.Number, + ), + ), + ) + } + } + private companion object { const val GAS_PRICE = 1 const val GAS_LIMIT = 2 diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/converters/YieldBalancesConverter.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/converters/YieldBalancesConverter.kt index 61bd335e65..fc1f5aa7b3 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/converters/YieldBalancesConverter.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/converters/YieldBalancesConverter.kt @@ -72,7 +72,7 @@ internal class YieldBalancesConverter( val rewards = yieldBalance?.balance?.items ?.filter { it.type == BalanceType.REWARDS && !it.amount.isZero() } - val isActionable = rewards?.all { it.pendingActions.isNotEmpty() } == true + val isActionable = rewards?.any { it.pendingActions.isNotEmpty() } == true val isRewardsClaimable = rewards?.isNotEmpty() == true val isSolana = isSolana(cryptoCurrencyStatus.currency.network.id.value) diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingClaimRewardsValidatorContent.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingClaimRewardsValidatorContent.kt index fecd9f9cb6..2068357514 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingClaimRewardsValidatorContent.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingClaimRewardsValidatorContent.kt @@ -57,6 +57,7 @@ internal fun StakingClaimRewardsValidatorContent( .roundedShapeItemDecoration(index, state.rewards.lastIndex, false) .background(TangemTheme.colors.background.action) .clickable( + enabled = item.pendingActions.isNotEmpty(), onClick = { clickIntents.onActiveStake(item) }, diff --git a/features/swap/data/src/main/java/com/tangem/feature/swap/DefaultSwapRepository.kt b/features/swap/data/src/main/java/com/tangem/feature/swap/DefaultSwapRepository.kt index bf614cd4a1..0548a65ea7 100644 --- a/features/swap/data/src/main/java/com/tangem/feature/swap/DefaultSwapRepository.kt +++ b/features/swap/data/src/main/java/com/tangem/feature/swap/DefaultSwapRepository.kt @@ -169,14 +169,15 @@ internal class DefaultSwapRepository( return withContext(coroutineDispatcher.io) { either { catch( - { + block = { exchangeStatusConverter.convert( tangemExpressApi .getExchangeStatus(txId) .getOrThrow(), ) }, - { + catch = { + Timber.e("getExchangeStatus error: $it") raise(UnknownError(it.message)) }, ) diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/TokenDetailsPreviewData.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/TokenDetailsPreviewData.kt index 747cf08519..3f49fe9fb2 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/TokenDetailsPreviewData.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/TokenDetailsPreviewData.kt @@ -155,7 +155,7 @@ internal object TokenDetailsPreviewData { onStakeClicked = {}, ) - val stakedBlock = StakingBlockUM.Staked( + val stakingBalanceBlock = StakingBlockUM.Staked( cryptoValue = stringReference("5 SOL"), fiatValue = stringReference("456.34 $"), rewardValue = resourceReference(R.string.staking_details_no_rewards_to_claim, wrappedList("0.43 $")), @@ -351,6 +351,6 @@ internal object TokenDetailsPreviewData { value = PagingData.from(txHistoryItems), ), ), - stakingBlocksState = stakedBlock, + stakingBlocksState = stakingBalanceBlock, ) } \ No newline at end of file diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/StakingBlockUM.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/StakingBlockUM.kt index 55ba3c6fcc..0072e90707 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/StakingBlockUM.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/StakingBlockUM.kt @@ -1,10 +1,10 @@ package com.tangem.feature.tokendetails.presentation.tokendetails.state -import androidx.compose.runtime.Stable +import androidx.compose.runtime.Immutable import com.tangem.core.ui.extensions.TextReference import java.math.BigDecimal -@Stable +@Immutable internal sealed interface StakingBlockUM { data object TemporaryUnavailable : StakingBlockUM diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsSwapTransactionsStateConverter.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsSwapTransactionsStateConverter.kt index c5db7b099d..57de8e0000 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsSwapTransactionsStateConverter.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsSwapTransactionsStateConverter.kt @@ -25,6 +25,7 @@ import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.PersistentList import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toPersistentList +import timber.log.Timber import java.math.BigDecimal import java.util.Locale @@ -115,7 +116,10 @@ internal class TokenDetailsSwapTransactionsStateConverter( refundToken: CryptoCurrency?, isRefundTerminalStatus: Boolean, ): SwapTransactionsState { - if (statusModel == null || tx.activeStatus == statusModel.status) return tx + if (statusModel == null || tx.activeStatus == statusModel.status) { + Timber.e("UpdateTxStatus isn't required. Current status isn't changed") + return tx + } val hasFailed = tx.hasFailed || statusModel.status == ExchangeStatus.Failed val notifications = getNotification(statusModel.status, statusModel.txExternalUrl, refundToken) val showProviderLink = getShowProviderLink(notifications, statusModel) @@ -217,13 +221,15 @@ internal class TokenDetailsSwapTransactionsStateConverter( isPaused = isPaused, ), ) - add( - sendStep( - isSending = isSending, - isSendingDone = isSendingDone, - isRefunded = isRefunded, - ), - ) + if (!isPaused) { + add( + sendStep( + isSending = isSending, + isSendingDone = isSendingDone, + isRefunded = isRefunded, + ), + ) + } } } }.toPersistentList() diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/staking/StakingBalanceBlock.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/staking/StakingBalanceBlock.kt index 1107eba6ae..76bc8386d6 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/staking/StakingBalanceBlock.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/staking/StakingBalanceBlock.kt @@ -1,18 +1,12 @@ package com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.staking import android.content.res.Configuration -import androidx.compose.foundation.background -import androidx.compose.foundation.clickable -import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.* import androidx.compose.material3.Icon import androidx.compose.material3.Text -import androidx.compose.material3.ripple import androidx.compose.runtime.Composable -import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview @@ -23,7 +17,7 @@ import com.tangem.core.ui.extensions.orMaskWithStars import com.tangem.core.ui.extensions.resolveReference import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.res.TangemThemePreview -import com.tangem.feature.tokendetails.presentation.tokendetails.TokenDetailsPreviewData.stakedBlock +import com.tangem.feature.tokendetails.presentation.tokendetails.TokenDetailsPreviewData.stakingBalanceBlock import com.tangem.feature.tokendetails.presentation.tokendetails.state.StakingBlockUM import com.tangem.features.tokendetails.impl.R import com.tangem.utils.StringsSigns @@ -36,16 +30,7 @@ internal fun StakingBalanceBlock( ) { Row( verticalAlignment = Alignment.CenterVertically, - modifier = modifier - .fillMaxWidth() - .clip(TangemTheme.shapes.roundedCornersXMedium) - .background(TangemTheme.colors.background.primary) - .clickable( - interactionSource = remember { MutableInteractionSource() }, - indication = ripple(), - onClick = state.onStakeClicked, - ) - .padding(TangemTheme.dimens.spacing12), + modifier = modifier.fillMaxWidth(), ) { Column( verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing4), @@ -108,6 +93,6 @@ private fun StakingBalanceBlock_Preview( private class StakingBalanceBlockPreviewProvider : PreviewParameterProvider { override val values: Sequence - get() = sequenceOf(stakedBlock) + get() = sequenceOf(stakingBalanceBlock) } // endregion \ No newline at end of file diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/staking/StakingUnavailableBlock.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/staking/StakingUnavailableBlock.kt index 2341b0cab8..2047a1f09f 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/staking/StakingUnavailableBlock.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/staking/StakingUnavailableBlock.kt @@ -1,12 +1,10 @@ package com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.staking import android.content.res.Configuration -import androidx.compose.foundation.background import androidx.compose.foundation.layout.* import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import com.tangem.core.ui.res.TangemTheme @@ -17,11 +15,7 @@ import com.tangem.features.tokendetails.impl.R internal fun StakingTemporaryUnavailableBlock(modifier: Modifier = Modifier) { Column( verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing4), - modifier = modifier - .fillMaxWidth() - .clip(TangemTheme.shapes.roundedCornersXMedium) - .background(TangemTheme.colors.background.primary) - .padding(TangemTheme.dimens.spacing12), + modifier = modifier.fillMaxWidth(), ) { Text( text = stringResource(R.string.staking_native), diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/staking/TokenStakingBlock.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/staking/TokenStakingBlock.kt index a4db00c78a..a8ba9f84c2 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/staking/TokenStakingBlock.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/staking/TokenStakingBlock.kt @@ -3,8 +3,11 @@ package com.tangem.feature.tokendetails.presentation.tokendetails.ui.components. import android.content.res.Configuration import androidx.compose.animation.AnimatedContent import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.* import androidx.compose.material3.Text +import androidx.compose.material3.ripple import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.Alignment @@ -14,18 +17,15 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider -import com.tangem.core.ui.components.RectangleShimmer -import com.tangem.core.ui.components.SecondaryButton -import com.tangem.core.ui.components.SpacerW8 -import com.tangem.core.ui.extensions.TextReference +import com.tangem.core.ui.components.* import com.tangem.core.ui.extensions.resolveReference import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.res.TangemThemePreview import com.tangem.core.ui.utils.getGreyScaleColorFilter +import com.tangem.feature.tokendetails.presentation.tokendetails.TokenDetailsPreviewData.stakingBalanceBlock import com.tangem.feature.tokendetails.presentation.tokendetails.TokenDetailsPreviewData.stakingAvailableBlock import com.tangem.feature.tokendetails.presentation.tokendetails.TokenDetailsPreviewData.stakingLoadingBlock import com.tangem.feature.tokendetails.presentation.tokendetails.TokenDetailsPreviewData.stakingTemporaryUnavailableBlock -import com.tangem.feature.tokendetails.presentation.tokendetails.state.IconState import com.tangem.feature.tokendetails.presentation.tokendetails.state.StakingBlockUM import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.CurrencyIcon import com.tangem.features.tokendetails.impl.R @@ -39,26 +39,35 @@ import com.tangem.features.tokendetails.impl.R */ @Composable internal fun TokenStakingBlock(state: StakingBlockUM, isBalanceHidden: Boolean, modifier: Modifier = Modifier) { - AnimatedContent( - targetState = state, - contentAlignment = Alignment.CenterStart, - label = "Staking block animation", + Column( + modifier = modifier + .clip(TangemTheme.shapes.roundedCornersXMedium) + .background(TangemTheme.colors.background.primary) + .clickable( + enabled = state is StakingBlockUM.Staked, + interactionSource = remember { MutableInteractionSource() }, + indication = ripple(), + onClick = { (state as? StakingBlockUM.Staked)?.onStakeClicked?.invoke() }, + ) + .fillMaxWidth() + .padding(all = TangemTheme.dimens.spacing12), ) { - when (it) { - is StakingBlockUM.TemporaryUnavailable -> StakingTemporaryUnavailableBlock(modifier) - is StakingBlockUM.Loading -> StakingLoading( - iconState = it.iconState, - modifier = modifier, - ) - is StakingBlockUM.Staked -> StakingBalanceBlock( - state = it, - isBalanceHidden = isBalanceHidden, - modifier = modifier, - ) - is StakingBlockUM.StakeAvailable -> StakingAvailableContent( - state = it, - modifier = modifier, - ) + AnimatedContent( + targetState = state, + contentAlignment = Alignment.CenterStart, + label = "Staking block animation", + ) { + when (it) { + is StakingBlockUM.TemporaryUnavailable -> StakingTemporaryUnavailableBlock() + is StakingBlockUM.Loading -> StakingLoading() + is StakingBlockUM.Staked -> StakingBalanceBlock( + state = it, + isBalanceHidden = isBalanceHidden, + ) + is StakingBlockUM.StakeAvailable -> StakingAvailableContent( + state = it, + ) + } } } } @@ -66,13 +75,7 @@ internal fun TokenStakingBlock(state: StakingBlockUM, isBalanceHidden: Boolean, @Composable private fun StakingAvailableContent(state: StakingBlockUM.StakeAvailable, modifier: Modifier = Modifier) { Column( - modifier = modifier - .background( - color = TangemTheme.colors.background.primary, - shape = TangemTheme.shapes.roundedCornersXMedium, - ) - .fillMaxWidth() - .padding(all = TangemTheme.dimens.spacing12), + modifier = modifier.fillMaxWidth(), ) { Row { val (alpha, colorFilter) = remember(state.iconState.isGrayscale) { @@ -115,52 +118,30 @@ private fun StakingAvailableContent(state: StakingBlockUM.StakeAvailable, modifi } @Composable -private fun StakingLoading(iconState: IconState, modifier: Modifier = Modifier) { +private fun StakingLoading(modifier: Modifier = Modifier) { Column( - modifier = modifier - .background( - color = TangemTheme.colors.background.primary, - shape = TangemTheme.shapes.roundedCornersXMedium, - ) - .fillMaxWidth() - .heightIn(min = TangemTheme.dimens.size72) - .padding(all = TangemTheme.dimens.spacing12), - + modifier = modifier.fillMaxWidth(), ) { Row { - val (alpha, colorFilter) = remember(iconState.isGrayscale) { - getGreyScaleColorFilter(iconState.isGrayscale) - } - CurrencyIcon( - modifier = Modifier - .size(TangemTheme.dimens.size20) - .clip(TangemTheme.shapes.roundedCorners8) - .align(Alignment.CenterVertically), - icon = iconState, - alpha = alpha, - colorFilter = colorFilter, - ) - SpacerW8() Column { RectangleShimmer( modifier = Modifier .fillMaxWidth() .height(TangemTheme.dimens.size20), ) - Spacer(modifier = Modifier.size(TangemTheme.dimens.size4)) + Spacer(modifier = Modifier.size(TangemTheme.dimens.size8)) RectangleShimmer( modifier = Modifier .fillMaxWidth() - .height(TangemTheme.dimens.size20), + .height(TangemTheme.dimens.size36), ) Spacer(modifier = Modifier.size(TangemTheme.dimens.size8)) } } - SecondaryButton( - modifier = Modifier.fillMaxWidth(), - showProgress = true, - text = TextReference.EMPTY.resolveReference(), - onClick = { /* no-op */ }, + RectangleShimmer( + modifier = Modifier + .fillMaxWidth() + .height(TangemTheme.dimens.size48), ) } } @@ -186,6 +167,7 @@ private class StakingBlockStateProvider : CollectionPreviewParameterProvider + items(items = wallets, contentType = { it.id.stringValue }) { state -> WalletCard( state = state, isBalanceHidden = isBalanceHidden, - modifier = Modifier - .animateItemPlacement() - .width(itemWidth), + modifier = Modifier.width(itemWidth), ) } } diff --git a/gradle/dependencies.toml b/gradle/dependencies.toml index a939b22dfe..87e70174f7 100644 --- a/gradle/dependencies.toml +++ b/gradle/dependencies.toml @@ -69,7 +69,6 @@ zxingQrCode = "3.5.1" mviCore = "1.3.1" kotlinSerialization = "1.4.1" arrow = "1.2.3" -reactiveNetwork = "3.0.8" walletConnectCore = "1.18.0" walletConnectWeb3 = "1.11.0" prettyLogger = "2.2.0" @@ -89,7 +88,7 @@ markdownComposeView = "0.5.4" # endregion Other libraries # region Tangem -tangemBlockchainSdk = "release-app_5.17-828" +tangemBlockchainSdk = "release-app_5.17-830" #tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds tangemCardSdk = "release-app_5.17-392" #tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^ @@ -252,7 +251,6 @@ mviCore-watcher = { module = "com.github.badoo.mvicore:mvicore-diff", version.re kotlin-serialization = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinSerialization" } arrow-core = { module = "io.arrow-kt:arrow-core", version.ref = "arrow" } arrow-fx = { module = "io.arrow-kt:arrow-fx-coroutines", version.ref = "arrow" } -reactive-network = { module = "com.github.pwittchen:reactivenetwork-rx2", version.ref = "reactiveNetwork" } walletConnectCore = { module = "com.walletconnect:android-core", version.ref = "walletConnectCore" } walletConnectWeb3 = { module = "com.walletconnect:web3wallet", version.ref = "walletConnectWeb3" } prettyLogger = { module = "com.orhanobut:logger", version.ref = "prettyLogger" }