diff --git a/features/approval/api/src/main/java/com/tangem/features/approval/api/GiveApprovalComponent.kt b/features/approval/api/src/main/java/com/tangem/features/approval/api/GiveApprovalComponent.kt index b680b9470b..e2345bbc2d 100644 --- a/features/approval/api/src/main/java/com/tangem/features/approval/api/GiveApprovalComponent.kt +++ b/features/approval/api/src/main/java/com/tangem/features/approval/api/GiveApprovalComponent.kt @@ -4,12 +4,12 @@ import com.tangem.core.decompose.context.AppComponentContext import com.tangem.core.ui.decompose.ComposableBottomSheetComponent import com.tangem.core.ui.extensions.TextReference import com.tangem.domain.models.currency.CryptoCurrencyStatus -import com.tangem.domain.models.wallet.UserWallet +import com.tangem.domain.models.wallet.UserWalletId interface GiveApprovalComponent : ComposableBottomSheetComponent { data class Params( - val userWallet: UserWallet, + val userWalletId: UserWalletId, val cryptoCurrencyStatus: CryptoCurrencyStatus, val feeCryptoCurrencyStatus: CryptoCurrencyStatus, val amount: String, @@ -19,6 +19,7 @@ interface GiveApprovalComponent : ComposableBottomSheetComponent { ) interface Callback { + fun onApproveClick() fun onApproveDone() fun onApproveFailed() fun onCancelClick() diff --git a/features/approval/impl/build.gradle.kts b/features/approval/impl/build.gradle.kts index 01c43ad67f..e15b2662cd 100644 --- a/features/approval/impl/build.gradle.kts +++ b/features/approval/impl/build.gradle.kts @@ -22,6 +22,8 @@ dependencies { implementation(projects.core.navigation) implementation(projects.core.ui) implementation(projects.core.utils) + implementation(projects.core.analytics) + implementation(projects.core.analytics.models) /** Common */ implementation(projects.common.ui) @@ -33,6 +35,7 @@ dependencies { /** Domain */ implementation(projects.domain.models) + implementation(projects.domain.wallets) implementation(projects.domain.wallets.models) implementation(projects.domain.transaction.models) implementation(projects.domain.transaction) diff --git a/features/approval/impl/src/main/java/com/tangem/features/approval/impl/DefaultGiveApprovalComponent.kt b/features/approval/impl/src/main/java/com/tangem/features/approval/impl/DefaultGiveApprovalComponent.kt index 51c2fe3986..c0102d54a6 100644 --- a/features/approval/impl/src/main/java/com/tangem/features/approval/impl/DefaultGiveApprovalComponent.kt +++ b/features/approval/impl/src/main/java/com/tangem/features/approval/impl/DefaultGiveApprovalComponent.kt @@ -4,7 +4,6 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.tangem.common.ui.userwallet.ext.walletInterationIcon import com.tangem.core.decompose.context.AppComponentContext import com.tangem.core.decompose.context.child import com.tangem.core.decompose.model.getOrCreateModel @@ -46,7 +45,7 @@ internal class DefaultGiveApprovalComponent @AssistedInject constructor( feeDisplaySource = FeeSelectorParams.FeeDisplaySource.Screen, analyticsCategoryName = CommonSendAnalyticEvents.APPROVE_CATEGORY, analyticsSendSource = CommonSendAnalyticEvents.CommonSendSource.Approve, - userWalletId = params.userWallet.walletId, + userWalletId = params.userWalletId, ), onResult = model::onFeeResult, ) @@ -84,7 +83,7 @@ internal class DefaultGiveApprovalComponent @AssistedInject constructor( approveType = uiState.approveType, approveItems = uiState.approveItems, onChangeApproveType = model::onChangeApproveType, - walletInteractionIcon = walletInterationIcon(params.userWallet), + walletInteractionIcon = uiState.walletInteractionIcon, isApproveEnabled = uiState.isApproveButtonEnabled, isApproveLoading = uiState.isApproveLoading, onApproveClick = model::onApproveClick, diff --git a/features/approval/impl/src/main/java/com/tangem/features/approval/impl/DefaultGiveApprovalFeatureToggles.kt b/features/approval/impl/src/main/java/com/tangem/features/approval/impl/DefaultGiveApprovalFeatureToggles.kt index 07867cc6a6..b135009ed6 100644 --- a/features/approval/impl/src/main/java/com/tangem/features/approval/impl/DefaultGiveApprovalFeatureToggles.kt +++ b/features/approval/impl/src/main/java/com/tangem/features/approval/impl/DefaultGiveApprovalFeatureToggles.kt @@ -2,8 +2,9 @@ package com.tangem.features.approval.impl import com.tangem.core.configtoggle.feature.FeatureTogglesManager import com.tangem.features.approval.api.GiveApprovalFeatureToggles +import javax.inject.Inject -internal class DefaultGiveApprovalFeatureToggles( +internal class DefaultGiveApprovalFeatureToggles @Inject constructor( private val featureToggles: FeatureTogglesManager, ) : GiveApprovalFeatureToggles { diff --git a/features/approval/impl/src/main/java/com/tangem/features/approval/impl/di/GiveApprovalBindsModule.kt b/features/approval/impl/src/main/java/com/tangem/features/approval/impl/di/GiveApprovalBindsModule.kt index 94d432e9b9..3f6fdce55a 100644 --- a/features/approval/impl/src/main/java/com/tangem/features/approval/impl/di/GiveApprovalBindsModule.kt +++ b/features/approval/impl/src/main/java/com/tangem/features/approval/impl/di/GiveApprovalBindsModule.kt @@ -3,7 +3,9 @@ package com.tangem.features.approval.impl.di import com.tangem.core.decompose.di.ModelComponent import com.tangem.core.decompose.model.Model import com.tangem.features.approval.api.GiveApprovalComponent +import com.tangem.features.approval.api.GiveApprovalFeatureToggles import com.tangem.features.approval.impl.DefaultGiveApprovalComponent +import com.tangem.features.approval.impl.DefaultGiveApprovalFeatureToggles import com.tangem.features.approval.impl.model.GiveApprovalModel import dagger.Binds import dagger.Module @@ -17,6 +19,10 @@ import javax.inject.Singleton @Module internal interface GiveApprovalFeatureModule { + @Singleton + @Binds + fun bindGiveApprovalFeatureToggle(toggles: DefaultGiveApprovalFeatureToggles): GiveApprovalFeatureToggles + @Binds @Singleton fun bindComponentFactory(factory: DefaultGiveApprovalComponent.Factory): GiveApprovalComponent.Factory diff --git a/features/approval/impl/src/main/java/com/tangem/features/approval/impl/model/GiveApprovalModel.kt b/features/approval/impl/src/main/java/com/tangem/features/approval/impl/model/GiveApprovalModel.kt index 2b3fb3fa8f..87882d24ce 100644 --- a/features/approval/impl/src/main/java/com/tangem/features/approval/impl/model/GiveApprovalModel.kt +++ b/features/approval/impl/src/main/java/com/tangem/features/approval/impl/model/GiveApprovalModel.kt @@ -8,6 +8,9 @@ import com.tangem.blockchain.common.TransactionData import com.tangem.blockchain.common.transaction.Fee import com.tangem.blockchain.common.transaction.TransactionFee import com.tangem.common.ui.bottomsheet.permission.state.ApproveType +import com.tangem.core.analytics.api.AnalyticsEventHandler +import com.tangem.core.analytics.models.AnalyticsParam +import com.tangem.core.analytics.models.Basic import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer @@ -28,6 +31,8 @@ import com.tangem.features.approval.api.GiveApprovalComponent import com.tangem.features.send.v2.api.callbacks.FeeSelectorModelCallback import com.tangem.features.send.v2.api.entity.FeeSelectorUM import com.tangem.core.navigation.url.UrlOpener +import com.tangem.common.ui.userwallet.ext.walletInterationIcon +import com.tangem.domain.wallets.usecase.GetUserWalletUseCase import com.tangem.utils.TangemBlogUrlBuilder.RESOURCE_TO_LEARN_ABOUT_APPROVING_IN_SWAP import com.tangem.utils.coroutines.CoroutineDispatcherProvider import kotlinx.coroutines.flow.MutableStateFlow @@ -52,14 +57,23 @@ internal class GiveApprovalModel @Inject constructor( private val createAndSendGaslessTransactionUseCase: CreateAndSendGaslessTransactionUseCase, private val uiMessageSender: UiMessageSender, private val urlOpener: UrlOpener, + private val getUserWalletUseCase: GetUserWalletUseCase, + private val analyticsEventHandler: AnalyticsEventHandler, ) : Model(), FeeSelectorModelCallback { private val params: GiveApprovalComponent.Params = paramsContainer.require() + private val userWallet by lazy { + requireNotNull( + getUserWalletUseCase(params.userWalletId).getOrNull(), + ) { "No wallet found for id: $params.userWalletId" } + } + val uiState: StateFlow field = MutableStateFlow( GiveApprovalUM( approveType = ApproveType.LIMITED, + walletInteractionIcon = walletInterationIcon(userWallet), isApproveButtonEnabled = false, isApproveLoading = false, ), @@ -73,6 +87,7 @@ internal class GiveApprovalModel @Inject constructor( } fun onApproveClick() { + params.callback.onApproveClick() uiState.update { it.copy(isApproveLoading = true) } modelScope.launch(dispatchers.main) { val isSuccess = sendApprovalTransaction() @@ -113,7 +128,7 @@ internal class GiveApprovalModel @Inject constructor( return createApprovalTransactionUseCase( cryptoCurrencyStatus = cryptoCurrencyStatus, - userWalletId = params.userWallet.walletId, + userWalletId = params.userWalletId, amount = getApprovalAmount(), contractAddress = tokenCurrency.contractAddress, spenderAddress = params.spenderAddress, @@ -126,7 +141,7 @@ internal class GiveApprovalModel @Inject constructor( return getFeeUseCase( transactionData = approvalTransaction, - userWallet = params.userWallet, + userWallet = userWallet, network = params.cryptoCurrencyStatus.currency.network, ) } @@ -138,13 +153,13 @@ internal class GiveApprovalModel @Inject constructor( return if (maybeToken == null) { getFeeForGaslessUseCase( transactionData = approvalTransaction, - userWallet = params.userWallet, + userWallet = userWallet, network = params.cryptoCurrencyStatus.currency.network, ) } else { getFeeForTokenUseCase( transactionData = approvalTransaction, - userWallet = params.userWallet, + userWallet = userWallet, token = maybeToken.currency, ) } @@ -162,7 +177,7 @@ internal class GiveApprovalModel @Inject constructor( val transactionData = createApprovalTransactionUseCase( cryptoCurrencyStatus = cryptoCurrencyStatus, - userWalletId = params.userWallet.walletId, + userWalletId = params.userWalletId, amount = getApprovalAmount(), fee = selectedFee, contractAddress = tokenCurrency.contractAddress, @@ -174,14 +189,14 @@ internal class GiveApprovalModel @Inject constructor( return if (isFeeInTokenCurrency) { createAndSendGaslessTransactionUseCase( - userWallet = params.userWallet, + userWallet = userWallet, transactionData = transactionData, fee = feeExtended, ) } else { sendTransactionUseCase( txData = transactionData, - userWallet = params.userWallet, + userWallet = userWallet, network = tokenCurrency.network, ) }.fold( @@ -189,7 +204,32 @@ internal class GiveApprovalModel @Inject constructor( Timber.e("Failed to send approval transaction: $error") false }, - ifRight = { true }, + ifRight = { + sendApproveSuccessAnalytics(feeContent) + true + }, + ) + } + + private fun sendApproveSuccessAnalytics(feeContent: FeeSelectorUM.Content) { + val currency = params.cryptoCurrencyStatus.currency + val feeToken = feeContent.feeExtraInfo.feeCryptoCurrencyStatus.currency.symbol + val permissionType = when (uiState.value.approveType) { + ApproveType.LIMITED -> "Current transaction" + ApproveType.UNLIMITED -> "Unlimited" + } + val event = AnalyticsParam.TxSentFrom.Approve( + blockchain = currency.network.name, + token = currency.symbol, + feeType = feeContent.toAnalyticType(), + feeToken = feeToken, + permissionType = permissionType, + ) + analyticsEventHandler.send( + Basic.TransactionSent( + sentFrom = event, + memoType = Basic.TransactionSent.MemoType.Null, + ), ) } diff --git a/features/approval/impl/src/main/java/com/tangem/features/approval/impl/model/GiveApprovalUM.kt b/features/approval/impl/src/main/java/com/tangem/features/approval/impl/model/GiveApprovalUM.kt index 83bf60054d..96fc768b88 100644 --- a/features/approval/impl/src/main/java/com/tangem/features/approval/impl/model/GiveApprovalUM.kt +++ b/features/approval/impl/src/main/java/com/tangem/features/approval/impl/model/GiveApprovalUM.kt @@ -1,5 +1,6 @@ package com.tangem.features.approval.impl.model +import androidx.annotation.DrawableRes import com.tangem.common.ui.bottomsheet.permission.state.ApproveType import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList @@ -7,6 +8,7 @@ import kotlinx.collections.immutable.toImmutableList internal data class GiveApprovalUM( val approveType: ApproveType, val approveItems: ImmutableList = ApproveType.entries.toImmutableList(), + @DrawableRes val walletInteractionIcon: Int?, val isApproveButtonEnabled: Boolean, val isApproveLoading: Boolean, ) \ No newline at end of file diff --git a/features/swap/impl/build.gradle.kts b/features/swap/impl/build.gradle.kts index 5b8d84540a..8a54dbba3d 100644 --- a/features/swap/impl/build.gradle.kts +++ b/features/swap/impl/build.gradle.kts @@ -84,6 +84,7 @@ dependencies { /** Api */ implementation(projects.features.swap.api) implementation(projects.features.tokendetails.api) + implementation(projects.features.approval.api) /** Libs */ implementation(projects.libs.crypto) diff --git a/features/swap/impl/src/main/java/com/tangem/feature/swap/DefaultSwapComponent.kt b/features/swap/impl/src/main/java/com/tangem/feature/swap/DefaultSwapComponent.kt index 6a88017cb4..b3b291e98f 100644 --- a/features/swap/impl/src/main/java/com/tangem/feature/swap/DefaultSwapComponent.kt +++ b/features/swap/impl/src/main/java/com/tangem/feature/swap/DefaultSwapComponent.kt @@ -12,11 +12,15 @@ import com.arkivanov.decompose.router.slot.activate import com.arkivanov.decompose.router.slot.childSlot import com.arkivanov.decompose.router.slot.dismiss import com.arkivanov.essenty.lifecycle.subscribe +import com.tangem.common.ui.bottomsheet.permission.state.GiveTxPermissionState import com.tangem.common.ui.swapStoriesScreen.SwapStoriesScreen import com.tangem.core.decompose.context.AppComponentContext import com.tangem.core.decompose.context.childByContext import com.tangem.core.decompose.model.getOrCreateModel +import com.tangem.core.ui.R import com.tangem.core.ui.decompose.ComposableBottomSheetComponent +import com.tangem.core.ui.extensions.resourceReference +import com.tangem.core.ui.extensions.wrappedList import com.tangem.core.ui.res.TangemTheme import com.tangem.domain.models.currency.CryptoCurrencyStatus import com.tangem.feature.swap.component.SwapFeeSelectorBlockComponent @@ -26,6 +30,7 @@ import com.tangem.feature.swap.router.SwapNavScreen import com.tangem.feature.swap.ui.SwapScreen import com.tangem.feature.swap.ui.SwapSelectTokenScreen import com.tangem.feature.swap.ui.SwapSuccessScreen +import com.tangem.features.approval.api.GiveApprovalComponent import com.tangem.features.feed.components.market.details.portfolio.add.AddToPortfolioComponent import com.tangem.features.send.v2.api.SendFeatureToggles import com.tangem.features.send.v2.api.analytics.CommonSendAnalyticEvents @@ -43,6 +48,7 @@ internal class DefaultSwapComponent @AssistedInject constructor( private val swapFeeSelectorBlockComponentFactory: SwapFeeSelectorBlockComponent.Factory, private val sendFeatureToggles: SendFeatureToggles, private val addToPortfolioComponentFactory: AddToPortfolioComponent.Factory, + private val giveApprovalComponentFactory: GiveApprovalComponent.Factory, ) : SwapComponent, AppComponentContext by appComponentContext { private val model: SwapModel = getOrCreateModel(params) @@ -55,6 +61,21 @@ internal class DefaultSwapComponent @AssistedInject constructor( childFactory = { configuration, context -> bottomSheetChild(context) }, ) + private val approvalSlot = childSlot( + key = APPROVAL_SLOT_KEY, + source = model.approvalSlotNavigation, + serializer = null, + handleBackButton = true, + childFactory = { _, factoryContext -> + val approvalParams = getApprovalParams() + ?: error("Approval params are not available") + giveApprovalComponentFactory.create( + context = childByContext(factoryContext), + params = approvalParams, + ) + }, + ) + init { lifecycle.subscribe( onStart = model::onStart, @@ -191,6 +212,9 @@ internal class DefaultSwapComponent @AssistedInject constructor( } bottomSheet.child?.instance?.BottomSheet() + + val approvalSlotState by approvalSlot.subscribeAsState() + approvalSlotState.child?.instance?.BottomSheet() } @Suppress("UnsafeCallOnNullableType") @@ -205,6 +229,27 @@ internal class DefaultSwapComponent @AssistedInject constructor( ) } + fun getApprovalParams(): GiveApprovalComponent.Params? { + val permissionState = model.uiState.permissionState as? GiveTxPermissionState.ReadyForRequest + ?: return null + val fromCryptoCurrency = model.dataState.fromCryptoCurrency ?: return null + val feeCryptoCurrency = model.dataState.feePaidCryptoCurrency ?: return null + val providerName = model.dataState.selectedProvider?.name.orEmpty() + + return GiveApprovalComponent.Params( + userWalletId = params.userWalletId, + cryptoCurrencyStatus = fromCryptoCurrency, + feeCryptoCurrencyStatus = feeCryptoCurrency, + amount = permissionState.amount, + spenderAddress = requireNotNull(model.dataState.approveDataModel).spenderAddress, + subtitle = resourceReference( + id = R.string.give_permission_swap_subtitle, + formatArgs = wrappedList(providerName, permissionState.currency), + ), + callback = model.approvalCallback, + ) + } + private fun toBigDecimalOrZero(bigDecimalString: String?): BigDecimal { return bigDecimalString?.replace(",", ".")?.toBigDecimalOrNull() ?: BigDecimal.ZERO } @@ -217,5 +262,6 @@ internal class DefaultSwapComponent @AssistedInject constructor( private companion object { const val BOTTOM_SHEET_SLOT_KEY = "bottomSheetSlot" const val FEE_SELECTOR_SLOT_KEY = "feeSelectorSlot" + const val APPROVAL_SLOT_KEY = "approvalSlot" } } \ No newline at end of file diff --git a/features/swap/impl/src/main/java/com/tangem/feature/swap/model/SwapModel.kt b/features/swap/impl/src/main/java/com/tangem/feature/swap/model/SwapModel.kt index 20ebd990d5..3eb20abc33 100644 --- a/features/swap/impl/src/main/java/com/tangem/feature/swap/model/SwapModel.kt +++ b/features/swap/impl/src/main/java/com/tangem/feature/swap/model/SwapModel.kt @@ -14,6 +14,8 @@ import com.tangem.blockchainsdk.utils.ExcludedBlockchains import com.tangem.common.routing.AppRouter import com.tangem.common.ui.bottomsheet.permission.state.ApproveType import com.tangem.common.ui.bottomsheet.permission.state.GiveTxPermissionState.InProgress.getApproveTypeOrNull +import com.tangem.features.approval.api.GiveApprovalComponent +import com.tangem.features.approval.api.GiveApprovalFeatureToggles import com.tangem.common.ui.markets.models.MarketsListItemUM import com.tangem.core.analytics.api.AnalyticsErrorHandler import com.tangem.core.analytics.api.AnalyticsEventHandler @@ -31,9 +33,9 @@ import com.tangem.core.ui.R import com.tangem.core.ui.extensions.TextReference import com.tangem.core.ui.extensions.combinedReference import com.tangem.core.ui.extensions.resourceReference +import com.tangem.core.ui.extensions.wrappedList import com.tangem.core.ui.extensions.stringReference import com.tangem.core.ui.extensions.toWrappedList -import com.tangem.core.ui.extensions.wrappedList import com.tangem.core.ui.message.DialogMessage import com.tangem.core.ui.message.EventMessageAction import com.tangem.core.ui.utils.InputNumberFormatter @@ -118,6 +120,8 @@ import com.tangem.utils.Provider import com.tangem.utils.TangemBlogUrlBuilder.RESOURCE_TO_LEARN_ABOUT_APPROVING_IN_SWAP import com.tangem.utils.coroutines.* import com.tangem.utils.isNullOrZero +import kotlinx.coroutines.NonCancellable +import kotlinx.coroutines.delay import kotlinx.coroutines.* import kotlinx.coroutines.flow.* import timber.log.Timber @@ -173,6 +177,7 @@ internal class SwapModel @Inject constructor( private val appsFlyerStore: AppsFlyerStore, private val holdToConfirmButtonFeatureToggles: HoldToConfirmButtonFeatureToggles, private val messageSender: UiMessageSender, + giveApprovalFeatureToggles: GiveApprovalFeatureToggles, ) : Model() { private val params = paramsContainer.require() @@ -301,6 +306,33 @@ internal class SwapModel @Inject constructor( get() = swapRouter.currentScreen val bottomSheetNavigation: SlotNavigation = SlotNavigation() + val approvalSlotNavigation = SlotNavigation() + private val shouldUseGaslessApproval: Boolean = giveApprovalFeatureToggles.isGaslessApprovalEnabled + + val approvalCallback = object : GiveApprovalComponent.Callback { + override fun onApproveClick() { + sendPermissionApproveClickedEvent() + } + + override fun onApproveDone() { + approvalSlotNavigation.dismiss() + updateWalletBalance() + uiState = stateBuilder.loadingPermissionState(uiState) + startLoadingQuotesFromLastState(isSilent = true) + } + + override fun onApproveFailed() { + approvalSlotNavigation.dismiss() + showAlert() + } + + override fun onCancelClick() { + approvalSlotNavigation.dismiss() + startLoadingQuotesFromLastState(isSilent = true) + analyticsEventHandler.send(SwapEvents.ButtonPermissionCancelClicked()) + } + } + val addToPortfolioCallback = object : AddToPortfolioComponent.Callback { override fun onDismiss() = bottomSheetNavigation.dismiss() @@ -1224,7 +1256,7 @@ internal class SwapModel @Inject constructor( fromTokenStatus = fromCryptoCurrency, approveType = approveType, txFee = feeForPermission, - spenderAddress = approveDataModel.spenderAddress, + spenderAddress = requireNotNull(dataState.approveDataModel).spenderAddress, ), ) }.onSuccess { swapTransactionState -> @@ -1785,10 +1817,14 @@ internal class SwapModel @Inject constructor( openPermissionBottomSheet = { singleTaskScheduler.cancelTask() sendGivePermissionClickedEvent() - uiState = stateBuilder.showPermissionBottomSheet(uiState) { - startLoadingQuotesFromLastState(isSilent = true) - analyticsEventHandler.send(SwapEvents.ButtonPermissionCancelClicked()) - uiState = stateBuilder.dismissBottomSheet(uiState) + if (shouldUseGaslessApproval) { + approvalSlotNavigation.activate(Unit) + } else { + uiState = stateBuilder.showPermissionBottomSheet(uiState) { + startLoadingQuotesFromLastState(isSilent = true) + analyticsEventHandler.send(SwapEvents.ButtonPermissionCancelClicked()) + uiState = stateBuilder.dismissBottomSheet(uiState) + } } }, onAmountSelected = { onAmountSelected(it) }, diff --git a/features/swap/impl/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt b/features/swap/impl/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt index 2a61151dde..3b0249e51b 100644 --- a/features/swap/impl/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt +++ b/features/swap/impl/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt @@ -711,6 +711,9 @@ internal class StateBuilder( fun createSilentLoadState(uiState: SwapStateHolder): SwapStateHolder { return uiState.copy( changeCardsButtonState = ChangeCardsButtonState.UPDATE_IN_PROGRESS, + notifications = uiState.notifications + .filterNot { it is SwapNotificationUM.Info.PermissionNeeded } + .toImmutableList(), ) }