diff --git a/app/src/main/java/com/tangem/tap/features/main/MainViewModel.kt b/app/src/main/java/com/tangem/tap/features/main/MainViewModel.kt index 6f5d289dd9..d61c7ffebf 100644 --- a/app/src/main/java/com/tangem/tap/features/main/MainViewModel.kt +++ b/app/src/main/java/com/tangem/tap/features/main/MainViewModel.kt @@ -11,6 +11,7 @@ import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase import com.tangem.domain.balancehiding.ListenToFlipsUseCase import com.tangem.domain.balancehiding.UpdateBalanceHidingSettingsUseCase import com.tangem.domain.settings.DeleteDeprecatedLogsUseCase +import com.tangem.features.send.api.featuretoggles.SendFeatureToggles import com.tangem.tap.features.main.model.MainScreenState import com.tangem.utils.coroutines.CoroutineDispatcherProvider import dagger.hilt.android.lifecycle.HiltViewModel @@ -26,6 +27,7 @@ internal class MainViewModel @Inject constructor( private val reduxNavController: ReduxNavController, private val fetchAppCurrenciesUseCase: FetchAppCurrenciesUseCase, private val deleteDeprecatedLogsUseCase: DeleteDeprecatedLogsUseCase, + private val sendFeatureToggles: SendFeatureToggles, private val dispatchers: CoroutineDispatcherProvider, getBalanceHidingSettingsUseCase: GetBalanceHidingSettingsUseCase, ) : ViewModel(), MainIntents { @@ -41,6 +43,7 @@ internal class MainViewModel @Inject constructor( init { updateAppCurrencies() + updateSendFeatureToggle() observeFlips() displayBalancesHidingStatusToast() displayHiddenBalancesModalNotification() @@ -56,6 +59,12 @@ internal class MainViewModel @Inject constructor( } } + private fun updateSendFeatureToggle() { + viewModelScope.launch(dispatchers.main) { + sendFeatureToggles.fetchNewSendEnabled() + } + } + private fun observeFlips() { listenToFlipsUseCase().launchIn(viewModelScope) } diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/TangemTechApi.kt b/core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/TangemTechApi.kt index 63e632438e..38e872886c 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/TangemTechApi.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/TangemTechApi.kt @@ -82,4 +82,7 @@ interface TangemTechApi { @Header("card_id") cardId: String, @Body body: CreateUserNetworkAccountBody, ): ApiResponse + + @GET("features") + suspend fun getFeatures(): ApiResponse } \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/models/FeaturesResponse.kt b/core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/models/FeaturesResponse.kt new file mode 100644 index 0000000000..2d72021cd0 --- /dev/null +++ b/core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/models/FeaturesResponse.kt @@ -0,0 +1,7 @@ +package com.tangem.datasource.api.tangemTech.models + +import com.squareup.moshi.Json + +data class FeaturesResponse( + @Json(name = "send") val isNewSendEnabled: Boolean, +) \ No newline at end of file diff --git a/core/featuretoggles/src/main/assets/configs/feature_toggles_config.json b/core/featuretoggles/src/main/assets/configs/feature_toggles_config.json index cf1fb0dc1d..644ced90b9 100644 --- a/core/featuretoggles/src/main/assets/configs/feature_toggles_config.json +++ b/core/featuretoggles/src/main/assets/configs/feature_toggles_config.json @@ -17,7 +17,7 @@ }, { "name": "LOCAL_USER_LOGS_ENABLED", - "version": "5.10.0" + "version": "5.11.0" }, { "name": "GENERATE_XPUB_ENABLED", diff --git a/core/res/src/main/res/values-ru/strings.xml b/core/res/src/main/res/values-ru/strings.xml index 8be4d56fef..7b010115ba 100644 --- a/core/res/src/main/res/values-ru/strings.xml +++ b/core/res/src/main/res/values-ru/strings.xml @@ -477,7 +477,7 @@ Покрытие сетевой комиссии Недостаточно средств для перевода, так как сумма комиссии и сумма перевода в совокупности больше имеющегося баланса Недостаточно средств - Оставить %s + Оставить %s Аккаунт будет удален из блокчейна, если баланс упадет ниже экзистенциального депозита. Пожалуйста, оставьте %s на балансе. Экзистенциальный депозит Сумма комиссии в %s раз превышает рекомендованную. Убедитесь, что указанная комиссия верна. @@ -490,7 +490,6 @@ Адрес получателя не активирован. \nПожалуйста, измените сумму отправки, чтобы продолжить. Сумма отправки не может быть менее %s Уменьшить на %s - Уменьшить до %s Обратите внимание, что при определенных параметрах комиссии возможны задержки по вашей транзакции Возможны задержки по транзакции Из-за ограничений %1$s в одну транзакцию может поместиться только %2$s UTXO. Это означает, что вы можете отправить только %3$s или меньше. Вам нужно уменьшить сумму. diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml index 50421fa1b7..2e840caeb5 100644 --- a/core/res/src/main/res/values/strings.xml +++ b/core/res/src/main/res/values/strings.xml @@ -474,7 +474,6 @@ Network fee coverage Insufficient funds for the transfer, as the total of the fee and transfer amount exceeds the existing balance Total exceeds balance - Leave %s The account will be wiped from the blockchain if a balance goes below the existential deposit. Please leave %s on your balance. Existential deposit The commission amount is %s times the recommended amount. Make sure that the custom settings are correct. @@ -486,8 +485,8 @@ The minimum sending amount is %1$s. Please ensure that the remaining balance after sending will not be less than %2$s. Target account is not created. Please change the amount to send. The amount to send must be at least %s + Leave %s Reduce by %s - Reduce to %s Kindly be aware that your transaction may experience delays under specific fee settings Transaction delays are possible Due to %1$s limitations only %2$s UTXOs can fit in a single transaction. This means you can only send %3$s or less. You need to reduce the amount. diff --git a/features/send/api/src/main/kotlin/com/tangem/features/send/api/featuretoggles/SendFeatureToggles.kt b/features/send/api/src/main/kotlin/com/tangem/features/send/api/featuretoggles/SendFeatureToggles.kt index d80f08cf56..453a79b60c 100644 --- a/features/send/api/src/main/kotlin/com/tangem/features/send/api/featuretoggles/SendFeatureToggles.kt +++ b/features/send/api/src/main/kotlin/com/tangem/features/send/api/featuretoggles/SendFeatureToggles.kt @@ -7,4 +7,7 @@ interface SendFeatureToggles { /** Availability of redesigned send screen */ val isRedesignedSendEnabled: Boolean + + /** Updates remote toggle */ + suspend fun fetchNewSendEnabled() } \ No newline at end of file diff --git a/features/send/impl/build.gradle.kts b/features/send/impl/build.gradle.kts index 587cb6d67c..4d0d072624 100644 --- a/features/send/impl/build.gradle.kts +++ b/features/send/impl/build.gradle.kts @@ -48,6 +48,7 @@ dependencies { implementation(projects.core.navigation) implementation(projects.core.analytics) implementation(projects.core.analytics.models) + implementation(projects.core.datasource) /** Common */ implementation(projects.common) diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/di/SendFeatureTogglesModule.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/di/SendFeatureTogglesModule.kt index 6b1465762c..60c8b2822c 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/di/SendFeatureTogglesModule.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/di/SendFeatureTogglesModule.kt @@ -1,8 +1,10 @@ package com.tangem.features.send.impl.di import com.tangem.core.featuretoggle.manager.FeatureTogglesManager +import com.tangem.datasource.api.tangemTech.TangemTechApi import com.tangem.features.send.api.featuretoggles.SendFeatureToggles import com.tangem.features.send.impl.featuretoggles.DefaultSendFeatureToggles +import com.tangem.utils.coroutines.CoroutineDispatcherProvider import dagger.Module import dagger.Provides import dagger.hilt.InstallIn @@ -18,7 +20,15 @@ internal object SendFeatureTogglesModule { @Provides @Singleton - fun provideSendFeatureToggles(featureTogglesManager: FeatureTogglesManager): SendFeatureToggles { - return DefaultSendFeatureToggles(featureTogglesManager = featureTogglesManager) + fun provideSendFeatureToggles( + featureTogglesManager: FeatureTogglesManager, + tangemTechApi: TangemTechApi, + dispatchers: CoroutineDispatcherProvider, + ): SendFeatureToggles { + return DefaultSendFeatureToggles( + featureTogglesManager = featureTogglesManager, + tangemTechApi = tangemTechApi, + dispatchers = dispatchers, + ) } } \ No newline at end of file diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/featuretoggles/DefaultSendFeatureToggles.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/featuretoggles/DefaultSendFeatureToggles.kt index 71f11c480d..b36cba4cbd 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/featuretoggles/DefaultSendFeatureToggles.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/featuretoggles/DefaultSendFeatureToggles.kt @@ -1,16 +1,41 @@ package com.tangem.features.send.impl.featuretoggles import com.tangem.core.featuretoggle.manager.FeatureTogglesManager +import com.tangem.datasource.api.common.response.getOrThrow +import com.tangem.datasource.api.tangemTech.TangemTechApi import com.tangem.features.send.api.featuretoggles.SendFeatureToggles +import com.tangem.utils.coroutines.CoroutineDispatcherProvider +import com.tangem.utils.coroutines.runCatching +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.update +import timber.log.Timber /** * Default implementation of Send feature toggles * * @property featureTogglesManager manager for getting information about the availability of feature toggles + * @property tangemTechApi api to get remote feature toggle for send + * @property dispatchers coroutine dispatchers */ internal class DefaultSendFeatureToggles( private val featureTogglesManager: FeatureTogglesManager, + private val tangemTechApi: TangemTechApi, + private val dispatchers: CoroutineDispatcherProvider, ) : SendFeatureToggles { + + private val remoteSendEnabled: MutableStateFlow = MutableStateFlow(true) + override val isRedesignedSendEnabled: Boolean - get() = featureTogglesManager.isFeatureEnabled(name = "REDESIGNED_SEND_SCREEN_ENABLED") + get() = featureTogglesManager.isFeatureEnabled(name = "REDESIGNED_SEND_SCREEN_ENABLED") && + remoteSendEnabled.value + + override suspend fun fetchNewSendEnabled() { + runCatching(dispatchers.io) { + tangemTechApi.getFeatures().getOrThrow() + }.onSuccess { response -> + remoteSendEnabled.update { response.isNewSendEnabled } + }.onFailure { + Timber.e(it.localizedMessage, "Unable to fetch new send toggle") + } + } } \ No newline at end of file diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/domain/AvailableWallet.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/domain/AvailableWallet.kt index 69e56bfc62..8a7d5e7f3a 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/domain/AvailableWallet.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/domain/AvailableWallet.kt @@ -1,15 +1,18 @@ package com.tangem.features.send.impl.presentation.domain import androidx.compose.runtime.Immutable +import com.tangem.domain.wallets.models.UserWalletId /** * Available wallet to send * * @property name wallet name + * @property userWalletId wallet id * @property address blockchain address */ @Immutable data class AvailableWallet( val name: String, + val userWalletId: UserWalletId, val address: String, ) \ No newline at end of file diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendNotification.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendNotification.kt index c59c030f46..fcd33d986f 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendNotification.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendNotification.kt @@ -54,7 +54,7 @@ internal sealed class SendNotification(val config: NotificationConfig) { wrappedList(cryptoCurrency, utxoLimit, amountLimit), ), buttonState = NotificationConfig.ButtonsState.PrimaryButtonConfig( - text = resourceReference(R.string.send_notification_reduce_to, wrappedList(amountLimit)), + text = resourceReference(R.string.send_notification_leave_button, wrappedList(amountLimit)), onClick = onConfirmClick, ), ) @@ -98,7 +98,7 @@ internal sealed class SendNotification(val config: NotificationConfig) { title = resourceReference(R.string.send_notification_existential_deposit_title), subtitle = resourceReference(R.string.send_notification_existential_deposit_text, wrappedList(deposit)), buttonState = NotificationConfig.ButtonsState.PrimaryButtonConfig( - text = resourceReference(R.string.send_notification_existential_deposit_button, wrappedList(deposit)), + text = resourceReference(R.string.send_notification_leave_button, wrappedList(deposit)), onClick = onConfirmClick, ), ) 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 916388ae26..ad764dbb71 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 @@ -66,11 +66,12 @@ internal class SendNotificationFactory( amountValue = amountValue, feeValue = feeValue, ) - val sendingAmount = calculateSubtractedAmount( - isFeeCoverage = isFeeCoverage, + val sendingAmount = checkAndCalculateSubtractedAmount( + isAmountSubtractAvailable = isFeeCoverage, cryptoCurrencyStatus = cryptoCurrencyStatusProvider(), amountValue = amountValue, feeValue = feeValue, + reduceAmountBy = sendState.reduceAmountBy, ) buildList { // errors @@ -194,7 +195,7 @@ internal class SendNotificationFactory( val spendingAmount = if (cryptoCurrency is CryptoCurrency.Token) { feeAmount } else { - feeAmount + receivedAmount + receivedAmount } val currencyDeposit = currencyChecksRepository.getExistentialDeposit( userWalletId, diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/FeeCalculation.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/FeeCalculation.kt index b06d42a23d..a8a93bcd32 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/FeeCalculation.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/FeeCalculation.kt @@ -54,7 +54,7 @@ internal fun checkFeeCoverage( /** * Calculates subtracted amount */ -internal fun calculateSubtractedAmount( +private fun calculateSubtractedAmount( isFeeCoverage: Boolean, cryptoCurrencyStatus: CryptoCurrencyStatus, amountValue: BigDecimal, diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/viewmodel/SendViewModel.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/viewmodel/SendViewModel.kt index 1a42abca89..540968febf 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/viewmodel/SendViewModel.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/viewmodel/SendViewModel.kt @@ -95,6 +95,7 @@ internal class SendViewModel @Inject constructor( private val neverShowTapHelpUseCase: NeverShowTapHelpUseCase, private val getExplorerTransactionUrlUseCase: GetExplorerTransactionUrlUseCase, private val listenToQrScanningUseCase: ListenToQrScanningUseCase, + private val addCryptoCurrenciesUseCase: AddCryptoCurrenciesUseCase, currencyChecksRepository: CurrencyChecksRepository, isFeeApproximateUseCase: IsFeeApproximateUseCase, validateWalletMemoUseCase: ValidateWalletMemoUseCase, @@ -189,6 +190,7 @@ internal class SendViewModel @Inject constructor( private set private var userWallet: UserWallet by Delegates.notNull() + private var userWallets: List = emptyList() private var isAmountSubtractAvailable: Boolean = false private var isTapHelpPreviewEnabled: Boolean = false private var coinCryptoCurrencyStatus: CryptoCurrencyStatus by Delegates.notNull() @@ -408,7 +410,10 @@ internal class SendViewModel @Inject constructor( .orEmpty() }.onSuccess { result -> combine(*result.toTypedArray()) { it } - .onEach { uiState = stateFactory.onLoadedWalletsList(wallets = it.toList()) } + .onEach { + userWallets = it.filterNotNull().toList() + uiState = stateFactory.onLoadedWalletsList(wallets = userWallets) + } .flowOn(dispatchers.main) .launchIn(viewModelScope) }.onFailure { @@ -417,7 +422,7 @@ internal class SendViewModel @Inject constructor( } } - private suspend fun List.toAvailableWallets(): List> = + private suspend fun List.toAvailableWallets(): List> = filterNot { it.walletId == userWalletId || it.isLocked } .mapNotNull { wallet -> val status = if (!wallet.isMultiCurrency) { @@ -435,6 +440,7 @@ internal class SendViewModel @Inject constructor( AvailableWallet( name = wallet.name, address = address, + userWalletId = wallet.walletId, ) } } @@ -863,11 +869,25 @@ internal class SendViewModel @Inject constructor( uiState = stateFactory.getSendingStateUpdate(isSending = false) updateTransactionStatus(txData) scheduleBalanceUpdate() + addTokenToWalletIfNeeded() sendScreenAnalyticSender.sendTransaction() }, ) } + private fun addTokenToWalletIfNeeded() { + if (cryptoCurrency !is CryptoCurrency.Token) return + + val recipientState = uiState.getRecipientState(stateRouter.isEditState) ?: return + val destinationAddress = recipientState.addressTextField.value + + val maybeUserWallet = userWallets.firstOrNull { it.address == destinationAddress } ?: return + + viewModelScope.launch(dispatchers.io) { + addCryptoCurrenciesUseCase(userWalletId = maybeUserWallet.userWalletId, currency = cryptoCurrency) + } + } + private suspend fun updateTransactionStatus(txData: TransactionData) { val txUrl = getExplorerTransactionUrlUseCase( userWalletId = userWalletId, diff --git a/gradle/dependencies.toml b/gradle/dependencies.toml index af0d8874b0..954d918b05 100644 --- a/gradle/dependencies.toml +++ b/gradle/dependencies.toml @@ -86,7 +86,7 @@ markdown = "0.7.2" # endregion Other libraries # region Tangem -tangemBlockchainSdk = "release-app_5.10-618" +tangemBlockchainSdk = "release-app_5.10-630" #tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds tangemCardSdk = "release-app_5.10-353" #tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^