diff --git a/common/ui/src/main/java/com/tangem/common/ui/expressStatus/state/ExpressTransactionsBlockState.kt b/common/ui/src/main/java/com/tangem/common/ui/expressStatus/state/ExpressTransactionsBlockState.kt new file mode 100644 index 0000000000..870d30bc07 --- /dev/null +++ b/common/ui/src/main/java/com/tangem/common/ui/expressStatus/state/ExpressTransactionsBlockState.kt @@ -0,0 +1,22 @@ +package com.tangem.common.ui.expressStatus.state + +import androidx.compose.runtime.Composable +import com.tangem.common.ui.tokendetails.TokenDetailsDialogConfig +import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig +import kotlinx.collections.immutable.PersistentList + +data class ExpressTransactionsBlockState( + val transactions: PersistentList, + val bottomSheetSlot: BottomSheetSlot?, + val dialogSlot: DialogSlot?, +) + +data class BottomSheetSlot( + val config: TangemBottomSheetConfig, + val content: @Composable () -> Unit, +) + +data class DialogSlot( + val config: TokenDetailsDialogConfig, + val content: @Composable () -> Unit, +) \ No newline at end of file diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/components/TokenDetailsDialogConfig.kt b/common/ui/src/main/java/com/tangem/common/ui/tokendetails/TokenDetailsDialogConfig.kt similarity index 95% rename from features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/components/TokenDetailsDialogConfig.kt rename to common/ui/src/main/java/com/tangem/common/ui/tokendetails/TokenDetailsDialogConfig.kt index 7df750dad1..8681f259a6 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/components/TokenDetailsDialogConfig.kt +++ b/common/ui/src/main/java/com/tangem/common/ui/tokendetails/TokenDetailsDialogConfig.kt @@ -1,9 +1,9 @@ -package com.tangem.feature.tokendetails.presentation.tokendetails.state.components +package com.tangem.common.ui.tokendetails +import com.tangem.core.ui.R import com.tangem.core.ui.extensions.TextReference import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.extensions.wrappedList -import com.tangem.features.tokendetails.impl.R /** * Wallet bottom sheet config @@ -12,7 +12,7 @@ import com.tangem.features.tokendetails.impl.R * @property onDismissRequest lambda be invoked when bottom sheet is dismissed * @property content content config */ -internal data class TokenDetailsDialogConfig( +data class TokenDetailsDialogConfig( val isShow: Boolean, val onDismissRequest: () -> Unit, val content: DialogContentConfig, @@ -28,7 +28,7 @@ internal data class TokenDetailsDialogConfig( data class ButtonConfig( val text: TextReference, val onClick: () -> Unit, - val warning: Boolean = false, + val hasWarning: Boolean = false, ) data class ConfirmHideConfig( @@ -51,7 +51,7 @@ internal data class TokenDetailsDialogConfig( override val confirmButtonConfig: ButtonConfig = ButtonConfig( text = TextReference.Res(R.string.token_details_hide_alert_hide), onClick = onConfirmClick, - warning = true, + hasWarning = true, ) } diff --git a/features/tangempay/details/impl/build.gradle.kts b/features/tangempay/details/impl/build.gradle.kts index 52a85dad6b..cc18ae7c58 100644 --- a/features/tangempay/details/impl/build.gradle.kts +++ b/features/tangempay/details/impl/build.gradle.kts @@ -29,6 +29,7 @@ dependencies { implementation(projects.features.tangempay.details.api) implementation(projects.features.tokenRecieve.api) implementation(projects.features.txhistory.api) + implementation(projects.features.tokendetails.api) /** Domain */ implementation(projects.domain.balanceHiding) diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/DefaultTangemPayDetailsContainerComponent.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/DefaultTangemPayDetailsContainerComponent.kt index 126f7124d8..baa27a447b 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/DefaultTangemPayDetailsContainerComponent.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/DefaultTangemPayDetailsContainerComponent.kt @@ -15,16 +15,18 @@ import com.tangem.core.decompose.context.AppComponentContext import com.tangem.core.decompose.context.childByContext import com.tangem.core.decompose.navigation.inner.InnerRouter import com.tangem.core.ui.decompose.ComposableContentComponent +import com.tangem.features.tangempay.components.express.ExpressTransactionsComponentProvider import com.tangem.features.tangempay.navigation.TangemPayDetailsInnerRoute import com.tangem.features.tokenreceive.TokenReceiveComponent import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject -class DefaultTangemPayDetailsContainerComponent @AssistedInject constructor( +internal class DefaultTangemPayDetailsContainerComponent @AssistedInject constructor( @Assisted private val appComponentContext: AppComponentContext, @Assisted private val params: TangemPayDetailsContainerComponent.Params, private val tokenReceiveComponentFactory: TokenReceiveComponent.Factory, + private val expressTransactionsComponentProvider: ExpressTransactionsComponentProvider, ) : AppComponentContext by appComponentContext, TangemPayDetailsContainerComponent { private val stackNavigation = StackNavigation() @@ -60,6 +62,7 @@ class DefaultTangemPayDetailsContainerComponent @AssistedInject constructor( appComponentContext = childByContext(componentContext = componentContext, router = innerRouter), params = params, tokenReceiveComponentFactory = tokenReceiveComponentFactory, + expressTransactionsComponentProvider = expressTransactionsComponentProvider, ) TangemPayDetailsInnerRoute.ChangePIN -> TangemPayChangePinComponent( appComponentContext = childByContext(componentContext = componentContext, router = innerRouter), diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/TangemPayDetailsComponent.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/TangemPayDetailsComponent.kt index fb099938ee..a4e44f025e 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/TangemPayDetailsComponent.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/TangemPayDetailsComponent.kt @@ -8,6 +8,7 @@ import com.arkivanov.decompose.ComponentContext import com.arkivanov.decompose.extensions.compose.subscribeAsState import com.arkivanov.decompose.router.slot.childSlot import com.arkivanov.decompose.router.slot.dismiss +import com.arkivanov.essenty.lifecycle.subscribe import com.tangem.core.decompose.context.AppComponentContext import com.tangem.core.decompose.context.child import com.tangem.core.decompose.context.childByContext @@ -17,6 +18,7 @@ import com.tangem.core.ui.decompose.ComposableBottomSheetComponent import com.tangem.core.ui.decompose.ComposableContentComponent import com.tangem.features.tangempay.components.cardDetails.DefaultTangemPayCardDetailsBlockComponent import com.tangem.features.tangempay.components.cardDetails.TangemPayCardDetailsBlockComponent +import com.tangem.features.tangempay.components.express.ExpressTransactionsComponentProvider import com.tangem.features.tangempay.components.txHistory.DefaultTangemPayTxHistoryComponent import com.tangem.features.tangempay.components.txHistory.TangemPayTxHistoryDetailsComponent import com.tangem.features.tangempay.entity.TangemPayDetailsNavigation @@ -28,6 +30,7 @@ internal class TangemPayDetailsComponent( private val appComponentContext: AppComponentContext, private val params: TangemPayDetailsContainerComponent.Params, private val tokenReceiveComponentFactory: TokenReceiveComponent.Factory, + private val expressTransactionsComponentProvider: ExpressTransactionsComponentProvider, ) : AppComponentContext by appComponentContext, ComposableContentComponent { private val model: TangemPayDetailsModel = getOrCreateModel(params = params) @@ -52,6 +55,21 @@ internal class TangemPayDetailsComponent( params = TangemPayCardDetailsBlockComponent.Params(params = params), ) + private val expressTransactionsComponent by lazy { + expressTransactionsComponentProvider.create( + appComponentContext = child("expressTransactionsComponent"), + userWalletId = params.userWalletId, + cryptoCurrency = model.cryptoCurrency, + ) + } + + init { + lifecycle.subscribe( + onPause = model::onPause, + onResume = model::onResume, + ) + } + @Composable override fun Content(modifier: Modifier) { val state by model.uiState.collectAsStateWithLifecycle() @@ -62,6 +80,7 @@ internal class TangemPayDetailsComponent( state = state, txHistoryComponent = txHistoryComponent, cardDetailsBlockComponent = cardDetailsBlockComponent, + expressTransactionsComponent = expressTransactionsComponent, modifier = modifier, ) bottomSheet.child?.instance?.BottomSheet() diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/express/EmptyExpressTransactionsComponent.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/express/EmptyExpressTransactionsComponent.kt new file mode 100644 index 0000000000..a06c8a9f4f --- /dev/null +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/express/EmptyExpressTransactionsComponent.kt @@ -0,0 +1,34 @@ +package com.tangem.features.tangempay.components.express + +import androidx.compose.foundation.lazy.LazyListScope +import androidx.compose.runtime.Stable +import androidx.compose.ui.Modifier +import com.tangem.common.ui.expressStatus.state.ExpressTransactionStateUM +import com.tangem.common.ui.expressStatus.state.ExpressTransactionsBlockState +import com.tangem.core.decompose.context.AppComponentContext +import com.tangem.features.tokendetails.ExpressTransactionsComponent +import kotlinx.collections.immutable.PersistentList +import kotlinx.collections.immutable.persistentListOf +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow + +@Stable +internal class EmptyExpressTransactionsComponent( + context: AppComponentContext, +) : AppComponentContext by context, ExpressTransactionsComponent { + + override val state: StateFlow = MutableStateFlow(getInitialState()) + + override fun LazyListScope.expressTransactionsContent( + state: PersistentList, + modifier: Modifier, + ) {} + + private fun getInitialState(): ExpressTransactionsBlockState { + return ExpressTransactionsBlockState( + transactions = persistentListOf(), + bottomSheetSlot = null, + dialogSlot = null, + ) + } +} \ No newline at end of file diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/express/ExpressTransactionsComponentProvider.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/express/ExpressTransactionsComponentProvider.kt new file mode 100644 index 0000000000..bcf6a91874 --- /dev/null +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/express/ExpressTransactionsComponentProvider.kt @@ -0,0 +1,25 @@ +package com.tangem.features.tangempay.components.express + +import com.tangem.core.decompose.context.AppComponentContext +import com.tangem.domain.models.currency.CryptoCurrency +import com.tangem.domain.models.wallet.UserWalletId +import com.tangem.features.tokendetails.ExpressTransactionsComponent +import javax.inject.Inject + +internal class ExpressTransactionsComponentProvider @Inject constructor( + private val expressTransactionsComponentFactory: ExpressTransactionsComponent.Factory, +) { + + fun create( + appComponentContext: AppComponentContext, + userWalletId: UserWalletId, + cryptoCurrency: CryptoCurrency?, + ): ExpressTransactionsComponent = if (cryptoCurrency != null) { + expressTransactionsComponentFactory.create( + context = appComponentContext, + params = ExpressTransactionsComponent.Params(userWalletId = userWalletId, currency = cryptoCurrency), + ) + } else { + EmptyExpressTransactionsComponent(context = appComponentContext) + } +} \ No newline at end of file diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/express/PreviewEmptyExpressTransactionsComponent.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/express/PreviewEmptyExpressTransactionsComponent.kt new file mode 100644 index 0000000000..23ead18dcf --- /dev/null +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/express/PreviewEmptyExpressTransactionsComponent.kt @@ -0,0 +1,32 @@ +package com.tangem.features.tangempay.components.express + +import androidx.compose.foundation.lazy.LazyListScope +import androidx.compose.ui.Modifier +import com.tangem.common.ui.expressStatus.state.ExpressTransactionStateUM +import com.tangem.common.ui.expressStatus.state.ExpressTransactionsBlockState +import com.tangem.features.tokendetails.ExpressTransactionsComponent +import kotlinx.collections.immutable.PersistentList +import kotlinx.collections.immutable.persistentListOf +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow + +/** Cannot really preview anything here since the UM implementation [ExchangeUM] is in token:details module + * For the actual preview @see [TokenDetailsScreen] + **/ +internal class PreviewEmptyExpressTransactionsComponent : ExpressTransactionsComponent { + + override val state: StateFlow = MutableStateFlow(getInitialState()) + + override fun LazyListScope.expressTransactionsContent( + state: PersistentList, + modifier: Modifier, + ) {} + + private fun getInitialState(): ExpressTransactionsBlockState { + return ExpressTransactionsBlockState( + transactions = persistentListOf(), + bottomSheetSlot = null, + dialogSlot = null, + ) + } +} \ No newline at end of file diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayDetailsModel.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayDetailsModel.kt index 2c2b69be13..bbdffbda81 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayDetailsModel.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayDetailsModel.kt @@ -21,6 +21,8 @@ import com.tangem.domain.feedback.SendFeedbackEmailUseCase import com.tangem.domain.feedback.models.FeedbackEmailType import com.tangem.domain.feedback.models.WalletMetaInfo import com.tangem.domain.models.TokenReceiveConfig +import com.tangem.domain.models.currency.CryptoCurrency +import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.pay.TangemPayCryptoCurrencyFactory import com.tangem.domain.pay.model.TangemPayCardBalance import com.tangem.domain.pay.model.TangemPayTopUpData @@ -47,6 +49,8 @@ import com.tangem.features.tangempay.utils.TangemPayDetailIntents import com.tangem.features.tangempay.utils.TangemPayMessagesFactory import com.tangem.features.tangempay.utils.TangemPayTxHistoryUiActions import com.tangem.features.tangempay.utils.TangemPayTxHistoryUpdateListener +import com.tangem.features.tokendetails.ExpressTransactionsEvent +import com.tangem.features.tokendetails.ExpressTransactionsEventListener import com.tangem.utils.coroutines.CoroutineDispatcherProvider import com.tangem.utils.coroutines.JobHolder import com.tangem.utils.coroutines.saveIn @@ -78,6 +82,7 @@ internal class TangemPayDetailsModel @Inject constructor( private val orderRepository: CustomerOrderRepository, private val getUserWalletUseCase: GetUserWalletUseCase, private val sendFeedbackEmailUseCase: SendFeedbackEmailUseCase, + private val expressTransactionsEventListener: ExpressTransactionsEventListener, ) : Model(), TangemPayTxHistoryUiActions, TangemPayDetailIntents, AddFundsListener, ViewPinListener { private val params: TangemPayDetailsContainerComponent.Params = paramsContainer.require() @@ -99,6 +104,11 @@ internal class TangemPayDetailsModel @Inject constructor( private var balance: TangemPayCardBalance? = null + private val userWallet: UserWallet? = getUserWalletUseCase(params.userWalletId).getOrNull() + val cryptoCurrency: CryptoCurrency? = userWallet?.let { wallet -> + tangemPayCryptoCurrencyFactory.create(userWallet = wallet, chainId = params.config.chainId).getOrNull() + } + val bottomSheetNavigation: SlotNavigation = SlotNavigation() init { @@ -109,6 +119,18 @@ internal class TangemPayDetailsModel @Inject constructor( subscribeToCardFrozenState() } + fun onResume() { + modelScope.launch { + expressTransactionsEventListener.send(ExpressTransactionsEvent.Update) + } + } + + fun onPause() { + modelScope.launch { + expressTransactionsEventListener.send(ExpressTransactionsEvent.Clear) + } + } + private fun subscribeToCardFrozenState() { cardDetailsRepository .cardFrozenState(params.config.cardId) @@ -252,8 +274,8 @@ internal class TangemPayDetailsModel @Inject constructor( if (hasActiveWithdrawal) { showBottomSheetError(TangemPayDetailsErrorType.WithdrawInProgress) } else { - val userWallet = getUserWalletUseCase(params.userWalletId).getOrNull() - val currency = userWallet?.let { + val userWallet = userWallet ?: getUserWalletUseCase(params.userWalletId).getOrNull() + val currency = cryptoCurrency ?: userWallet?.let { tangemPayCryptoCurrencyFactory.create(userWallet = userWallet, chainId = params.config.chainId) .getOrNull() } @@ -336,6 +358,7 @@ internal class TangemPayDetailsModel @Inject constructor( modelScope.launch { uiState.update(TangemPayDetailsRefreshTransformer(isRefreshing = refreshState.value)) cardDetailsEventListener.send(CardDetailsEvent.Hide) + expressTransactionsEventListener.send(ExpressTransactionsEvent.Update) txHistoryUpdateListener.triggerUpdate() fetchBalance().join() uiState.update(TangemPayDetailsRefreshTransformer(isRefreshing = false)) diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayDetailsScreen.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayDetailsScreen.kt index 255f5c37a5..91bd0656aa 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayDetailsScreen.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayDetailsScreen.kt @@ -34,17 +34,22 @@ import com.tangem.core.ui.components.dropdownmenu.TangemDropdownMenu import com.tangem.core.ui.components.notifications.Notification import com.tangem.core.ui.components.notifications.NotificationConfig import com.tangem.core.ui.components.text.applyBladeBrush -import com.tangem.core.ui.extensions.* +import com.tangem.core.ui.extensions.TextReference +import com.tangem.core.ui.extensions.orMaskWithStars +import com.tangem.core.ui.extensions.resourceReference +import com.tangem.core.ui.extensions.stringResourceSafe import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.res.TangemThemePreview import com.tangem.core.ui.test.TokenDetailsTopBarTestTags import com.tangem.domain.visa.model.TangemPayCardFrozenState import com.tangem.features.tangempay.components.cardDetails.PreviewTangemPayCardDetailsBlockComponent import com.tangem.features.tangempay.components.cardDetails.TangemPayCardDetailsBlockComponent +import com.tangem.features.tangempay.components.express.PreviewEmptyExpressTransactionsComponent import com.tangem.features.tangempay.components.txHistory.PreviewTangemPayTxHistoryComponent import com.tangem.features.tangempay.components.txHistory.TangemPayTxHistoryComponent import com.tangem.features.tangempay.details.impl.R import com.tangem.features.tangempay.entity.* +import com.tangem.features.tokendetails.ExpressTransactionsComponent import com.tangem.utils.StringsSigns.DASH_SIGN import kotlinx.collections.immutable.persistentListOf @@ -54,6 +59,7 @@ internal fun TangemPayDetailsScreen( state: TangemPayDetailsUM, txHistoryComponent: TangemPayTxHistoryComponent, cardDetailsBlockComponent: TangemPayCardDetailsBlockComponent, + expressTransactionsComponent: ExpressTransactionsComponent, modifier: Modifier = Modifier, ) { Scaffold( @@ -66,6 +72,9 @@ internal fun TangemPayDetailsScreen( val bottomBarHeight = with(LocalDensity.current) { WindowInsets.systemBars.getBottom(this).toDp() } val txHistoryState by txHistoryComponent.state.collectAsStateWithLifecycle() val cardDetailsState by cardDetailsBlockComponent.state.collectAsStateWithLifecycle() + val expressState by expressTransactionsComponent.state.collectAsStateWithLifecycle() + val expressTransactionsBottomSheetState = expressState.bottomSheetSlot + val expressTransactionsDialogState = expressState.dialogSlot TangemPullToRefreshContainer( config = state.pullToRefreshConfig, @@ -138,9 +147,19 @@ internal fun TangemPayDetailsScreen( ) }, ) + with(expressTransactionsComponent) { + expressTransactionsContent( + state = expressState.transactions, + modifier = modifier + .padding(start = 16.dp, end = 16.dp, top = 12.dp) + .fillMaxWidth(), + ) + } with(txHistoryComponent) { txHistoryContent(listState = listState, state = txHistoryState) } } } + expressTransactionsDialogState?.content() + expressTransactionsBottomSheetState?.content() } } @@ -292,6 +311,7 @@ private fun TangemPayDetailsScreenPreview( cardFrozenState = TangemPayCardFrozenState.Unfrozen, ), ), + expressTransactionsComponent = PreviewEmptyExpressTransactionsComponent(), ) } } @@ -370,6 +390,7 @@ private fun TangemPayDetailsTxHistoryScreenPreview( cardFrozenState = TangemPayCardFrozenState.Unfrozen, ), ), + expressTransactionsComponent = PreviewEmptyExpressTransactionsComponent(), ) } } diff --git a/features/tokendetails/api/build.gradle.kts b/features/tokendetails/api/build.gradle.kts index 0551d08f54..72eb80b695 100644 --- a/features/tokendetails/api/build.gradle.kts +++ b/features/tokendetails/api/build.gradle.kts @@ -14,6 +14,9 @@ dependencies { implementation(projects.core.decompose) implementation(projects.core.ui) + /** Common */ + implementation(projects.common.ui) + /** Domain models */ api(projects.domain.models) implementation(projects.domain.tokens.models) @@ -21,4 +24,9 @@ dependencies { /** Compose */ implementation(deps.compose.runtime) + implementation(deps.compose.ui) + implementation(deps.compose.foundation) + + /** Other */ + implementation(deps.kotlin.immutable.collections) } \ No newline at end of file diff --git a/features/tokendetails/api/src/main/kotlin/com/tangem/features/tokendetails/ExpressTransactionsComponent.kt b/features/tokendetails/api/src/main/kotlin/com/tangem/features/tokendetails/ExpressTransactionsComponent.kt new file mode 100644 index 0000000000..0ed67d34a6 --- /dev/null +++ b/features/tokendetails/api/src/main/kotlin/com/tangem/features/tokendetails/ExpressTransactionsComponent.kt @@ -0,0 +1,27 @@ +package com.tangem.features.tokendetails + +import androidx.compose.foundation.lazy.LazyListScope +import androidx.compose.runtime.Stable +import androidx.compose.ui.Modifier +import com.tangem.common.ui.expressStatus.state.ExpressTransactionStateUM +import com.tangem.common.ui.expressStatus.state.ExpressTransactionsBlockState +import com.tangem.core.decompose.factory.ComponentFactory +import com.tangem.domain.models.currency.CryptoCurrency +import com.tangem.domain.models.wallet.UserWalletId +import kotlinx.collections.immutable.PersistentList +import kotlinx.coroutines.flow.StateFlow + +@Stable +interface ExpressTransactionsComponent { + + val state: StateFlow + + fun LazyListScope.expressTransactionsContent(state: PersistentList, modifier: Modifier) + + data class Params( + val userWalletId: UserWalletId, + val currency: CryptoCurrency, + ) + + interface Factory : ComponentFactory +} \ No newline at end of file diff --git a/features/tokendetails/api/src/main/kotlin/com/tangem/features/tokendetails/ExpressTransactionsEventListener.kt b/features/tokendetails/api/src/main/kotlin/com/tangem/features/tokendetails/ExpressTransactionsEventListener.kt new file mode 100644 index 0000000000..bbe0d91105 --- /dev/null +++ b/features/tokendetails/api/src/main/kotlin/com/tangem/features/tokendetails/ExpressTransactionsEventListener.kt @@ -0,0 +1,14 @@ +package com.tangem.features.tokendetails + +import kotlinx.coroutines.flow.Flow + +interface ExpressTransactionsEventListener { + + val event: Flow + + suspend fun send(event: ExpressTransactionsEvent) +} + +enum class ExpressTransactionsEvent { + Update, Clear +} \ No newline at end of file diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/di/TokenDetailsModule.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/di/TokenDetailsModule.kt index 356a4c6fe4..18e5a4f513 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/di/TokenDetailsModule.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/di/TokenDetailsModule.kt @@ -4,9 +4,14 @@ import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.di.ModelComponent import com.tangem.core.decompose.model.Model import com.tangem.feature.tokendetails.DefaultTokenDetailsComponent +import com.tangem.feature.tokendetails.presentation.DefaultExpressTransactionsComponent import com.tangem.feature.tokendetails.presentation.router.DefaultTokenDetailsRouter import com.tangem.feature.tokendetails.presentation.router.InnerTokenDetailsRouter +import com.tangem.feature.tokendetails.presentation.tokendetails.model.ExpressTransactionsModel import com.tangem.feature.tokendetails.presentation.tokendetails.model.TokenDetailsModel +import com.tangem.feature.tokendetails.presentation.tokendetails.state.utils.DefaultExpressTransactionsEventListener +import com.tangem.features.tokendetails.ExpressTransactionsComponent +import com.tangem.features.tokendetails.ExpressTransactionsEventListener import com.tangem.features.tokendetails.TokenDetailsComponent import dagger.Binds import dagger.Module @@ -14,18 +19,35 @@ import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent import dagger.multibindings.ClassKey import dagger.multibindings.IntoMap +import javax.inject.Singleton @Module @InstallIn(SingletonComponent::class) internal interface TokenDetailsModule { @Binds - fun bindComponentFactory(factory: DefaultTokenDetailsComponent.Factory): TokenDetailsComponent.Factory + fun bindTokenDetailsComponentFactory(factory: DefaultTokenDetailsComponent.Factory): TokenDetailsComponent.Factory + + @Binds + fun bindExpressTransactionsComponent( + factory: DefaultExpressTransactionsComponent.Factory, + ): ExpressTransactionsComponent.Factory @Binds @IntoMap @ClassKey(TokenDetailsModel::class) - fun bindModel(model: TokenDetailsModel): Model + fun bindTokenDetailsModel(model: TokenDetailsModel): Model + + @Binds + @IntoMap + @ClassKey(ExpressTransactionsModel::class) + fun bindExpressTransactionsModel(model: ExpressTransactionsModel): Model + + @Binds + @Singleton + fun bindExpressTransactionsEventListener( + impl: DefaultExpressTransactionsEventListener, + ): ExpressTransactionsEventListener } @Module diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/DefaultExpressTransactionsComponent.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/DefaultExpressTransactionsComponent.kt new file mode 100644 index 0000000000..02b83cfe13 --- /dev/null +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/DefaultExpressTransactionsComponent.kt @@ -0,0 +1,42 @@ +package com.tangem.feature.tokendetails.presentation + +import androidx.compose.foundation.lazy.LazyListScope +import androidx.compose.runtime.Stable +import androidx.compose.ui.Modifier +import com.tangem.common.ui.expressStatus.expressTransactionsItems +import com.tangem.common.ui.expressStatus.state.ExpressTransactionStateUM +import com.tangem.common.ui.expressStatus.state.ExpressTransactionsBlockState +import com.tangem.core.decompose.context.AppComponentContext +import com.tangem.core.decompose.model.getOrCreateModel +import com.tangem.feature.tokendetails.presentation.tokendetails.model.ExpressTransactionsModel +import com.tangem.features.tokendetails.ExpressTransactionsComponent +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject +import kotlinx.collections.immutable.PersistentList +import kotlinx.coroutines.flow.StateFlow + +@Stable +internal class DefaultExpressTransactionsComponent @AssistedInject constructor( + @Assisted context: AppComponentContext, + @Assisted params: ExpressTransactionsComponent.Params, +) : AppComponentContext by context, ExpressTransactionsComponent { + + private val model: ExpressTransactionsModel = getOrCreateModel(params = params) + override val state: StateFlow = model.uiState + + override fun LazyListScope.expressTransactionsContent( + state: PersistentList, + modifier: Modifier, + ) { + expressTransactionsItems(expressTxs = state, modifier = modifier) + } + + @AssistedFactory + interface Factory : ExpressTransactionsComponent.Factory { + override fun create( + context: AppComponentContext, + params: ExpressTransactionsComponent.Params, + ): DefaultExpressTransactionsComponent + } +} \ No newline at end of file diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/model/ExpressTransactionsModel.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/model/ExpressTransactionsModel.kt new file mode 100644 index 0000000000..6d5210c3cf --- /dev/null +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/model/ExpressTransactionsModel.kt @@ -0,0 +1,306 @@ +package com.tangem.feature.tokendetails.presentation.tokendetails.model + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.Stable +import arrow.core.getOrElse +import arrow.core.right +import com.tangem.common.ui.expressStatus.ExpressStatusBottomSheetConfig +import com.tangem.common.ui.expressStatus.state.BottomSheetSlot +import com.tangem.common.ui.expressStatus.state.DialogSlot +import com.tangem.common.ui.expressStatus.state.ExpressTransactionStateUM +import com.tangem.common.ui.expressStatus.state.ExpressTransactionsBlockState +import com.tangem.common.ui.tokendetails.TokenDetailsDialogConfig +import com.tangem.core.decompose.di.ModelScoped +import com.tangem.core.decompose.model.Model +import com.tangem.core.decompose.model.ParamsContainer +import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig +import com.tangem.domain.account.featuretoggle.AccountsFeatureToggles +import com.tangem.domain.account.status.usecase.GetAccountCurrencyStatusUseCase +import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase +import com.tangem.domain.appcurrency.model.AppCurrency +import com.tangem.domain.card.common.util.cardTypesResolver +import com.tangem.domain.models.account.Account +import com.tangem.domain.models.currency.CryptoCurrency +import com.tangem.domain.models.currency.CryptoCurrencyStatus +import com.tangem.domain.models.wallet.UserWallet +import com.tangem.domain.models.wallet.UserWalletId +import com.tangem.domain.tokens.GetSingleCryptoCurrencyStatusUseCase +import com.tangem.domain.wallets.usecase.GetUserWalletUseCase +import com.tangem.domain.wallets.usecase.NetworkHasDerivationUseCase +import com.tangem.feature.tokendetails.presentation.router.InnerTokenDetailsRouter +import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState +import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.TokenDetailsStateFactory +import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.express.ExpressStatusFactory +import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.TokenDetailsDialogs +import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.express.ExpressStatusBottomSheet +import com.tangem.features.tokendetails.ExpressTransactionsComponent +import com.tangem.features.tokendetails.ExpressTransactionsEvent +import com.tangem.features.tokendetails.ExpressTransactionsEventListener +import com.tangem.features.yield.supply.api.YieldSupplyFeatureToggles +import com.tangem.utils.Provider +import com.tangem.utils.coroutines.* +import kotlinx.collections.immutable.PersistentList +import kotlinx.coroutines.flow.* +import kotlinx.coroutines.launch +import javax.inject.Inject +import kotlin.coroutines.cancellation.CancellationException + +@Suppress("LongParameterList", "PropertyUsedBeforeDeclaration") +@Stable +@ModelScoped +internal class ExpressTransactionsModel @Inject constructor( + override val dispatchers: CoroutineDispatcherProvider, + paramsContainer: ParamsContainer, + expressStatusFactory: ExpressStatusFactory.Factory, + getUserWalletUseCase: GetUserWalletUseCase, + private val getSingleCryptoCurrencyStatusUseCase: GetSingleCryptoCurrencyStatusUseCase, + private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase, + private val networkHasDerivationUseCase: NetworkHasDerivationUseCase, + private val router: InnerTokenDetailsRouter, + private val yieldSupplyFeatureToggles: YieldSupplyFeatureToggles, + private val accountsFeatureToggles: AccountsFeatureToggles, + private val getAccountCryptoCurrencyStatusUseCase: GetAccountCurrencyStatusUseCase, + private val expressTransactionsEventListener: ExpressTransactionsEventListener, +) : Model(), ExpressTransactionsClickIntents { + + private val params = paramsContainer.require() + private val userWalletId: UserWalletId = params.userWalletId + private val cryptoCurrency: CryptoCurrency = params.currency + + private val userWallet: UserWallet = getUserWalletUseCase(userWalletId).getOrNull() ?: error("UserWallet not found") + + private val marketPriceJobHolder = JobHolder() + private val expressTxJobHolder = JobHolder() + private val selectedAppCurrencyFlow: StateFlow = createSelectedAppCurrencyFlow() + + private var cryptoCurrencyStatus: CryptoCurrencyStatus? = null + private var account: Account.CryptoPortfolio? = null + private val expressTxStatusTaskScheduler = SingleTaskScheduler>() + + private val waitForFirstExpressStatusEmmit = MutableStateFlow(false) + + private val currentStateProvider: Provider = Provider { internalUiState.value } + + private val stateFactory by lazy(mode = LazyThreadSafetyMode.NONE) { + TokenDetailsStateFactory( + appCurrencyProvider = Provider(selectedAppCurrencyFlow::value), + currentStateProvider = currentStateProvider, + cryptoCurrencyStatusProvider = Provider { cryptoCurrencyStatus }, + tokenDetailsClickIntents = EmptyTokenDetailsClickIntents(), + expressTransactionsClickIntents = this, + networkHasDerivationUseCase = networkHasDerivationUseCase, + getUserWalletUseCase = getUserWalletUseCase, + userWalletId = userWalletId, + yieldSupplyFeatureToggles = yieldSupplyFeatureToggles, + ) + } + + private val expressStatusFactory by lazy(mode = LazyThreadSafetyMode.NONE) { + expressStatusFactory.create( + clickIntents = this, + appCurrencyProvider = Provider { selectedAppCurrencyFlow.value }, + currentStateProvider = currentStateProvider, + cryptoCurrencyStatusProvider = Provider { cryptoCurrencyStatus }, + userWallet = userWallet, + cryptoCurrency = cryptoCurrency, + ) + } + + private val internalUiState = MutableStateFlow(stateFactory.getInitialState(cryptoCurrency)) + + val uiState: StateFlow = internalUiState + .map(::mapInnerState) + .stateIn( + scope = modelScope, + started = SharingStarted.Eagerly, + initialValue = mapInnerState(internalUiState.value), + ) + + init { + subscribeOnExternalEvents() + subscribeOnCurrencyStatusUpdates() + subscribeOnExpressTransactionsUpdates() + } + + override fun onExpressTransactionClick(txId: String) { + val expressTxState = internalUiState.value.expressTxsToDisplay.firstOrNull { it.info.txId == txId } + ?: return + internalUiState.value = expressStatusFactory.getStateWithExpressStatusBottomSheet(expressTxState) + } + + override fun onGoToProviderClick(url: String) { + router.openUrl(url) + } + + override fun onGoToRefundedTokenClick(cryptoCurrency: CryptoCurrency) { + router.openTokenDetails(userWalletId, cryptoCurrency) + } + + override fun onOpenUrlClick(url: String) { + router.openUrl(url) + } + + override fun onConfirmDisposeExpressStatus() { + internalUiState.value = stateFactory.getStateWithConfirmHideExpressStatus() + } + + override fun onDisposeExpressStatus() { + val bottomSheetState = internalUiState.value.bottomSheetConfig?.content + if (bottomSheetState is ExpressStatusBottomSheetConfig) { + modelScope.launch { + expressStatusFactory.removeTransactionOnBottomSheetClosed( + expressState = bottomSheetState.value, + isForceDispose = true, + ) + } + } + internalUiState.value = stateFactory.getStateWithClosedBottomSheet() + } + + override fun onDismissBottomSheet() { + when (val bsContent = internalUiState.value.bottomSheetConfig?.content) { + is ExpressStatusBottomSheetConfig -> { + modelScope.launch(dispatchers.main) { + expressStatusFactory.removeTransactionOnBottomSheetClosed(bsContent.value) + } + } + } + internalUiState.value = stateFactory.getStateWithClosedBottomSheet() + } + + override fun onDismissDialog() { + internalUiState.value = stateFactory.getStateWithClosedDialog() + } + + override fun onDestroy() { + clear() + super.onDestroy() + } + + private fun mapInnerState(innerState: TokenDetailsState): ExpressTransactionsBlockState { + val bsContent = innerState.bottomSheetConfig?.content + return ExpressTransactionsBlockState( + transactions = innerState.expressTxsToDisplay, + bottomSheetSlot = if (bsContent != null && bsContent is ExpressStatusBottomSheetConfig) { + innerState.bottomSheetConfig.toBottomSheetSlot() + } else { + null + }, + dialogSlot = innerState.dialogConfig?.toDialogSlot(), + ) + } + + private fun TangemBottomSheetConfig.toBottomSheetSlot(): BottomSheetSlot { + val contentLambda: @Composable () -> Unit = { + when (this.content) { + is ExpressStatusBottomSheetConfig -> ExpressStatusBottomSheet(config = this) + } + } + return BottomSheetSlot(config = this, content = contentLambda) + } + + private fun TokenDetailsDialogConfig.toDialogSlot(): DialogSlot { + val contentLambda: @Composable () -> Unit = { + TokenDetailsDialogs(this) + } + return DialogSlot(config = this, content = contentLambda) + } + + private fun subscribeOnExternalEvents() { + modelScope.launch { + expressTransactionsEventListener.event.collect { event -> + when (event) { + ExpressTransactionsEvent.Update -> subscribeOnExpressTransactionsUpdates() + ExpressTransactionsEvent.Clear -> clear() + } + } + } + } + + private fun subscribeOnCurrencyStatusUpdates() { + if (accountsFeatureToggles.isFeatureEnabled) { + getAccountCryptoCurrencyStatusUseCase(userWalletId, cryptoCurrency) + .onEach { account = it.account } + .map { it.status.right() } + } else { + getSingleCryptoCurrencyStatusUseCase.invokeMultiWallet( + userWalletId = userWalletId, + currencyId = cryptoCurrency.id, + isSingleWalletWithTokens = userWallet is UserWallet.Cold && + userWallet.scanResponse.cardTypesResolver.isSingleWalletWithToken(), + ) + } + .distinctUntilChanged() + .onEach { maybeCurrencyStatus -> + internalUiState.value = stateFactory.getCurrencyLoadedBalanceState(maybeCurrencyStatus) + maybeCurrencyStatus.onRight { status -> + cryptoCurrencyStatus = status + } + } + .flowOn(dispatchers.main) + .launchIn(modelScope) + .saveIn(marketPriceJobHolder) + } + + private fun subscribeOnExpressTransactionsUpdates() { + expressTxStatusTaskScheduler.cancelTask() + expressStatusFactory.getExpressStatuses() + .distinctUntilChanged() + .onEach { waitForFirstExpressStatusEmmit.value = true } + .onEach { expressTxs -> + internalUiState.value = expressStatusFactory.getStateWithUpdatedExpressTxs( + expressTxs = expressTxs, + updateBalance = { /* no-op */ }, + ) + expressTxStatusTaskScheduler.scheduleTask( + scope = modelScope, + task = PeriodicTask( + isDelayFirst = false, + delay = EXPRESS_STATUS_UPDATE_DELAY, + task = { + try { + Result.success( + expressStatusFactory.getUpdatedExpressStatuses(internalUiState.value.expressTxs), + ) + } catch (exception: CancellationException) { + throw exception + } catch (exception: Exception) { + Result.failure(exception) + } + }, + onSuccess = { updatedTxs -> + internalUiState.value = expressStatusFactory.getStateWithUpdatedExpressTxs( + expressTxs = updatedTxs, + updateBalance = { /* no-op */ }, + ) + }, + onError = { /* no-op */ }, + ), + ) + } + .flowOn(dispatchers.main) + .launchIn(modelScope) + .saveIn(expressTxJobHolder) + } + + private fun createSelectedAppCurrencyFlow(): StateFlow { + return getSelectedAppCurrencyUseCase() + .map { maybeAppCurrency -> + maybeAppCurrency.getOrElse { AppCurrency.Default } + } + .stateIn( + scope = modelScope, + started = SharingStarted.Eagerly, + initialValue = AppCurrency.Default, + ) + } + + private fun clear() { + expressTxStatusTaskScheduler.cancelTask() + expressTxJobHolder.cancel() + } + + private companion object { + const val EXPRESS_STATUS_UPDATE_DELAY = 10_000L + } +} \ No newline at end of file diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/model/TokenDetailsClickIntents.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/model/TokenDetailsClickIntents.kt index 66d495e481..bf41cabfe1 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/model/TokenDetailsClickIntents.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/model/TokenDetailsClickIntents.kt @@ -24,8 +24,6 @@ interface TokenDetailsClickIntents { fun onSellClick(unavailabilityReason: ScenarioUnavailabilityReason) - fun onDismissDialog() - fun onHideClick() fun onHideConfirmed() @@ -42,14 +40,8 @@ interface TokenDetailsClickIntents { fun onAddressTypeSelected(addressModel: AddressModel) - fun onDismissBottomSheet() - fun onCloseRentInfoNotification() - fun onExpressTransactionClick(txId: String) - - fun onGoToProviderClick(url: String) - fun onSwapPromoDismiss(promoId: PromoId) fun onSwapPromoClick(promoId: PromoId) @@ -72,6 +64,15 @@ interface TokenDetailsClickIntents { fun onBalanceSelect(config: TokenBalanceSegmentedButtonConfig) + fun onYieldInfoClick() +} + +interface ExpressTransactionsClickIntents { + + fun onExpressTransactionClick(txId: String) + + fun onGoToProviderClick(url: String) + fun onGoToRefundedTokenClick(cryptoCurrency: CryptoCurrency) fun onOpenUrlClick(url: String) @@ -80,5 +81,69 @@ interface TokenDetailsClickIntents { fun onDisposeExpressStatus() - fun onYieldInfoClick() + fun onDismissBottomSheet() + + fun onDismissDialog() +} + +@Suppress("TooManyFunctions") +internal class EmptyTokenDetailsClickIntents : TokenDetailsClickIntents { + override fun onRefreshSwipe(isRefreshing: Boolean) { /* no op */ } + + override fun onBackClick() { /* no op */ } + + override fun onBuyClick(unavailabilityReason: ScenarioUnavailabilityReason) { /* no op */ } + + override fun onBuyCoinClick(cryptoCurrency: CryptoCurrency) { /* no op */ } + + override fun onStakeBannerClick() { /* no op */ } + + override fun onReloadClick() { /* no op */ } + + override fun onSendClick(unavailabilityReason: ScenarioUnavailabilityReason) { /* no op */ } + + override fun onReceiveClick(unavailabilityReason: ScenarioUnavailabilityReason) { /* no op */ } + + override fun onStakeClick(unavailabilityReason: ScenarioUnavailabilityReason) { /* no op */ } + + override fun onGenerateExtendedKey() { /* no op */ } + + override fun onSellClick(unavailabilityReason: ScenarioUnavailabilityReason) { /* no op */ } + + override fun onSwapClick(unavailabilityReason: ScenarioUnavailabilityReason) { /* no op */ } + + override fun onHideClick() { /* no op */ } + + override fun onHideConfirmed() { /* no op */ } + + override fun onExploreClick() { /* no op */ } + + override fun onAddressTypeSelected(addressModel: AddressModel) { /* no op */ } + + override fun onTransactionClick(txHash: String) { /* no op */ } + + override fun onCloseRentInfoNotification() { /* no op */ } + + override fun onSwapPromoDismiss(promoId: PromoId) { /* no op */ } + + override fun onSwapPromoClick(promoId: PromoId) { /* no op */ } + + override fun onRetryIncompleteTransactionClick() { /* no op */ } + + override fun onOpenTrustlineClick() { /* no op */ } + + override fun onDismissIncompleteTransactionClick() { /* no op */ } + + override fun onConfirmDismissIncompleteTransactionClick() { /* no op */ } + + override fun onAssociateClick() { /* no op */ } + + override fun onBalanceSelect(config: TokenBalanceSegmentedButtonConfig) { /* no op */ } + + override fun onYieldInfoClick() { /* no op */ } + + override fun onCopyAddress(): TextReference? { + /* no op */ + return null + } } \ No newline at end of file diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/model/TokenDetailsModel.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/model/TokenDetailsModel.kt index b660c09fdd..ba5ee42ad8 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/model/TokenDetailsModel.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/model/TokenDetailsModel.kt @@ -153,7 +153,10 @@ internal class TokenDetailsModel @Inject constructor( private val getAccountCryptoCurrencyStatusUseCase: GetAccountCurrencyStatusUseCase, private val manageCryptoCurrenciesUseCase: ManageCryptoCurrenciesUseCase, private val yieldSupplyGetRewardsBalanceUseCase: YieldSupplyGetRewardsBalanceUseCase, -) : Model(), TokenDetailsClickIntents, YieldSupplyDepositedWarningComponent.ModelCallback { +) : Model(), + TokenDetailsClickIntents, + ExpressTransactionsClickIntents, + YieldSupplyDepositedWarningComponent.ModelCallback { private val params = paramsContainer.require() private val userWalletId: UserWalletId = params.userWalletId @@ -184,7 +187,8 @@ internal class TokenDetailsModel @Inject constructor( currentStateProvider = Provider { uiState.value }, appCurrencyProvider = Provider(selectedAppCurrencyFlow::value), cryptoCurrencyStatusProvider = Provider { cryptoCurrencyStatus }, - clickIntents = this, + tokenDetailsClickIntents = this, + expressTransactionsClickIntents = this, networkHasDerivationUseCase = networkHasDerivationUseCase, getUserWalletUseCase = getUserWalletUseCase, userWalletId = userWalletId, diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/TokenDetailsState.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/TokenDetailsState.kt index 40805e48b9..ed8cf22b9f 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/TokenDetailsState.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/TokenDetailsState.kt @@ -1,10 +1,10 @@ package com.tangem.feature.tokendetails.presentation.tokendetails.state import com.tangem.common.ui.expressStatus.state.ExpressTransactionStateUM +import com.tangem.common.ui.tokendetails.TokenDetailsDialogConfig import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig import com.tangem.core.ui.components.containers.pullToRefresh.PullToRefreshConfig import com.tangem.core.ui.components.marketprice.MarketPriceBlockState -import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.TokenDetailsDialogConfig import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.TokenDetailsNotification import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.PersistentList diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsOnrampTransactionStateConverter.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsOnrampTransactionStateConverter.kt index 742e94dab2..52acac7843 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsOnrampTransactionStateConverter.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsOnrampTransactionStateConverter.kt @@ -20,14 +20,14 @@ import com.tangem.domain.models.currency.CryptoCurrencyStatus import com.tangem.domain.onramp.model.OnrampStatus import com.tangem.domain.onramp.model.cache.OnrampTransaction import com.tangem.domain.tokens.model.analytics.TokenOnrampAnalyticsEvent -import com.tangem.feature.tokendetails.presentation.tokendetails.model.TokenDetailsClickIntents +import com.tangem.feature.tokendetails.presentation.tokendetails.model.ExpressTransactionsClickIntents import com.tangem.features.tokendetails.impl.R import com.tangem.utils.Provider import com.tangem.utils.converter.Converter import kotlinx.collections.immutable.persistentListOf internal class TokenDetailsOnrampTransactionStateConverter( - private val clickIntents: TokenDetailsClickIntents, + private val clickIntents: ExpressTransactionsClickIntents, private val cryptoCurrency: CryptoCurrency, private val cryptoCurrencyStatusProvider: Provider, private val appCurrencyProvider: Provider, diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsStateFactory.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsStateFactory.kt index da13ce39ba..87552d058e 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsStateFactory.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsStateFactory.kt @@ -3,6 +3,7 @@ package com.tangem.feature.tokendetails.presentation.tokendetails.state.factory import arrow.core.Either import com.tangem.common.ui.bottomsheet.chooseaddress.ChooseAddressBottomSheetConfig import com.tangem.common.ui.bottomsheet.receive.TokenReceiveBottomSheetConfig +import com.tangem.common.ui.tokendetails.TokenDetailsDialogConfig import com.tangem.common.ui.tokens.getUnavailabilityReasonText import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig import com.tangem.core.ui.components.dropdownmenu.TangemDropdownMenuItem @@ -27,12 +28,12 @@ import com.tangem.domain.tokens.model.warnings.CryptoCurrencyWarning import com.tangem.domain.wallets.usecase.GetUserWalletUseCase import com.tangem.domain.wallets.usecase.NetworkHasDerivationUseCase import com.tangem.domain.yield.supply.models.YieldSupplyRewardBalance +import com.tangem.feature.tokendetails.presentation.tokendetails.model.ExpressTransactionsClickIntents import com.tangem.feature.tokendetails.presentation.tokendetails.model.TokenDetailsClickIntents import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenBalanceSegmentedButtonConfig import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsAppBarMenuConfig import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsBalanceBlockState import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState -import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.TokenDetailsDialogConfig import com.tangem.features.tokendetails.impl.R import com.tangem.features.yield.supply.api.YieldSupplyFeatureToggles import com.tangem.utils.Provider @@ -43,7 +44,8 @@ internal class TokenDetailsStateFactory( private val currentStateProvider: Provider, private val appCurrencyProvider: Provider, private val cryptoCurrencyStatusProvider: Provider, - private val clickIntents: TokenDetailsClickIntents, + private val tokenDetailsClickIntents: TokenDetailsClickIntents, + private val expressTransactionsClickIntents: ExpressTransactionsClickIntents, private val networkHasDerivationUseCase: NetworkHasDerivationUseCase, private val getUserWalletUseCase: GetUserWalletUseCase, private val userWalletId: UserWalletId, @@ -52,7 +54,7 @@ internal class TokenDetailsStateFactory( private val skeletonStateConverter by lazy { TokenDetailsSkeletonStateConverter( - clickIntents = clickIntents, + clickIntents = tokenDetailsClickIntents, networkHasDerivationUseCase = networkHasDerivationUseCase, getUserWalletUseCase = getUserWalletUseCase, userWalletId = userWalletId, @@ -64,7 +66,7 @@ internal class TokenDetailsStateFactory( TokenDetailsNotificationConverter( userWalletId = userWalletId, getUserWalletUseCase = getUserWalletUseCase, - clickIntents = clickIntents, + clickIntents = tokenDetailsClickIntents, ) } @@ -72,7 +74,7 @@ internal class TokenDetailsStateFactory( TokenDetailsLoadedBalanceConverter( currentStateProvider = currentStateProvider, appCurrencyProvider = appCurrencyProvider, - clickIntents = clickIntents, + clickIntents = tokenDetailsClickIntents, yieldSupplyFeatureToggles = yieldSupplyFeatureToggles, ) } @@ -80,7 +82,7 @@ internal class TokenDetailsStateFactory( private val tokenDetailsButtonsConverter by lazy { TokenDetailsActionButtonsConverter( currentStateProvider = currentStateProvider, - clickIntents = clickIntents, + clickIntents = tokenDetailsClickIntents, ) } @@ -117,7 +119,7 @@ internal class TokenDetailsStateFactory( return TokenDetailsStakingInfoConverter( currentState = state, cryptoCurrencyStatus = cryptoCurrencyStatus, - clickIntents = clickIntents, + clickIntents = tokenDetailsClickIntents, appCurrencyProvider = appCurrencyProvider, stakingEntryInfo = stakingEntryInfo, ).convert(stakingAvailability) @@ -136,11 +138,11 @@ internal class TokenDetailsStateFactory( return currentStateProvider().copy( dialogConfig = TokenDetailsDialogConfig( isShow = true, - onDismissRequest = clickIntents::onDismissDialog, + onDismissRequest = expressTransactionsClickIntents::onDismissDialog, content = TokenDetailsDialogConfig.DialogContentConfig.ConfirmHideConfig( currencyTitle = currency.name, - onConfirmClick = clickIntents::onHideConfirmed, - onCancelClick = clickIntents::onDismissDialog, + onConfirmClick = tokenDetailsClickIntents::onHideConfirmed, + onCancelClick = expressTransactionsClickIntents::onDismissDialog, ), ), ) @@ -150,12 +152,12 @@ internal class TokenDetailsStateFactory( return currentStateProvider().copy( dialogConfig = TokenDetailsDialogConfig( isShow = true, - onDismissRequest = clickIntents::onDismissDialog, + onDismissRequest = expressTransactionsClickIntents::onDismissDialog, content = TokenDetailsDialogConfig.DialogContentConfig.HasLinkedTokensConfig( currencyName = currency.name, currencySymbol = currency.symbol, networkName = currency.network.name, - onConfirmClick = clickIntents::onDismissDialog, + onConfirmClick = expressTransactionsClickIntents::onDismissDialog, ), ), ) @@ -165,10 +167,10 @@ internal class TokenDetailsStateFactory( return currentStateProvider().copy( dialogConfig = TokenDetailsDialogConfig( isShow = true, - onDismissRequest = clickIntents::onDismissDialog, + onDismissRequest = expressTransactionsClickIntents::onDismissDialog, content = TokenDetailsDialogConfig.DialogContentConfig.RemoveIncompleteTransactionConfirmDialogConfig( - onConfirmClick = clickIntents::onConfirmDismissIncompleteTransactionClick, - onCancelClick = clickIntents::onDismissDialog, + onConfirmClick = tokenDetailsClickIntents::onConfirmDismissIncompleteTransactionClick, + onCancelClick = expressTransactionsClickIntents::onDismissDialog, ), ), ) @@ -178,10 +180,10 @@ internal class TokenDetailsStateFactory( return currentStateProvider().copy( dialogConfig = TokenDetailsDialogConfig( isShow = true, - onDismissRequest = clickIntents::onDismissDialog, + onDismissRequest = expressTransactionsClickIntents::onDismissDialog, content = TokenDetailsDialogConfig.DialogContentConfig.DisabledButtonReasonDialogConfig( text = unavailabilityReason.getUnavailabilityReasonText(), - onConfirmClick = clickIntents::onDismissDialog, + onConfirmClick = expressTransactionsClickIntents::onDismissDialog, ), ), ) @@ -191,10 +193,10 @@ internal class TokenDetailsStateFactory( return currentStateProvider().copy( dialogConfig = TokenDetailsDialogConfig( isShow = true, - onDismissRequest = clickIntents::onDismissDialog, + onDismissRequest = expressTransactionsClickIntents::onDismissDialog, content = TokenDetailsDialogConfig.DialogContentConfig.ErrorDialogConfig( text = text, - onConfirmClick = clickIntents::onDismissDialog, + onConfirmClick = expressTransactionsClickIntents::onDismissDialog, ), ), ) @@ -217,7 +219,7 @@ internal class TokenDetailsStateFactory( return currentStateProvider().copy( bottomSheetConfig = TangemBottomSheetConfig( isShown = true, - onDismissRequest = clickIntents::onDismissBottomSheet, + onDismissRequest = expressTransactionsClickIntents::onDismissBottomSheet, content = TokenReceiveBottomSheetConfig( asset = TokenReceiveBottomSheetConfig.Asset.Currency( name = currency.name, @@ -240,7 +242,7 @@ internal class TokenDetailsStateFactory( return currentStateProvider().copy( bottomSheetConfig = TangemBottomSheetConfig( isShown = true, - onDismissRequest = clickIntents::onDismissBottomSheet, + onDismissRequest = expressTransactionsClickIntents::onDismissBottomSheet, content = ChooseAddressBottomSheetConfig( asset = TokenReceiveBottomSheetConfig.Asset.Currency( name = currency.name, @@ -248,7 +250,7 @@ internal class TokenDetailsStateFactory( ), network = currency.network, networkAddress = networkAddress, - onClick = clickIntents::onAddressTypeSelected, + onClick = tokenDetailsClickIntents::onAddressTypeSelected, ), ), ) @@ -338,13 +340,13 @@ internal class TokenDetailsStateFactory( return currentStateProvider().copy( dialogConfig = TokenDetailsDialogConfig( isShow = true, - onDismissRequest = clickIntents::onDismissDialog, + onDismissRequest = expressTransactionsClickIntents::onDismissDialog, content = TokenDetailsDialogConfig.DialogContentConfig.ConfirmExpressStatusHideDialogConfig( onConfirmClick = { - clickIntents.onDisposeExpressStatus() - clickIntents.onDismissDialog() + expressTransactionsClickIntents.onDisposeExpressStatus() + expressTransactionsClickIntents.onDismissDialog() }, - onCancelClick = clickIntents::onDismissDialog, + onCancelClick = expressTransactionsClickIntents::onDismissDialog, ), ), ) @@ -367,13 +369,13 @@ internal class TokenDetailsStateFactory( TangemDropdownMenuItem( title = resourceReference(R.string.token_details_generate_xpub), textColor = themedColor { TangemTheme.colors.text.primary1 }, - onClick = clickIntents::onGenerateExtendedKey, + onClick = tokenDetailsClickIntents::onGenerateExtendedKey, ).let(::add) } TangemDropdownMenuItem( title = TextReference.Res(id = R.string.token_details_hide_token), textColor = themedColor { TangemTheme.colors.text.warning }, - onClick = clickIntents::onHideClick, + onClick = tokenDetailsClickIntents::onHideClick, ).let(::add) }.toImmutableList(), ) 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 42e28102ef..c4204e04e1 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,7 +25,7 @@ import com.tangem.feature.swap.domain.models.domain.ExchangeStatus.Companion.isF import com.tangem.feature.swap.domain.models.domain.ExchangeStatusModel import com.tangem.feature.swap.domain.models.domain.SavedSwapTransactionListModel import com.tangem.feature.swap.domain.models.domain.SavedSwapTransactionModel -import com.tangem.feature.tokendetails.presentation.tokendetails.model.TokenDetailsClickIntents +import com.tangem.feature.tokendetails.presentation.tokendetails.model.ExpressTransactionsClickIntents import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.ExchangeStatusNotification import com.tangem.feature.tokendetails.presentation.tokendetails.state.express.ExchangeStatusState import com.tangem.feature.tokendetails.presentation.tokendetails.state.express.ExchangeUM @@ -43,7 +43,7 @@ import java.util.Locale // Fixme [REDACTED_JIRA] @Suppress("LargeClass") internal class TokenDetailsSwapTransactionsStateConverter( - private val clickIntents: TokenDetailsClickIntents, + private val clickIntents: ExpressTransactionsClickIntents, private val cryptoCurrency: CryptoCurrency, private val analyticsEventsHandler: AnalyticsEventHandler, appCurrencyProvider: Provider, diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/express/ExchangeStatusFactory.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/express/ExchangeStatusFactory.kt index 3aed5a00de..d2b9ffaddb 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/express/ExchangeStatusFactory.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/express/ExchangeStatusFactory.kt @@ -18,7 +18,7 @@ import com.tangem.domain.tokens.model.analytics.TokenExchangeAnalyticsEvent import com.tangem.feature.swap.domain.SwapTransactionRepository import com.tangem.feature.swap.domain.api.SwapRepository import com.tangem.feature.swap.domain.models.domain.* -import com.tangem.feature.tokendetails.presentation.tokendetails.model.TokenDetailsClickIntents +import com.tangem.feature.tokendetails.presentation.tokendetails.model.ExpressTransactionsClickIntents import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState import com.tangem.feature.tokendetails.presentation.tokendetails.state.express.ExchangeUM import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.TokenDetailsSwapTransactionsStateConverter @@ -44,7 +44,7 @@ internal class ExchangeStatusFactory @AssistedInject constructor( private val manageCryptoCurrenciesUseCase: ManageCryptoCurrenciesUseCase, private val swapTransactionStatusStore: SwapTransactionStatusStore, private val analyticsEventsHandler: AnalyticsEventHandler, - @Assisted private val clickIntents: TokenDetailsClickIntents, + @Assisted private val clickIntents: ExpressTransactionsClickIntents, @Assisted private val appCurrencyProvider: Provider, @Assisted private val currentStateProvider: Provider, @Assisted private val userWallet: UserWallet, @@ -257,7 +257,7 @@ internal class ExchangeStatusFactory @AssistedInject constructor( @AssistedFactory interface Factory { fun create( - clickIntents: TokenDetailsClickIntents, + clickIntents: ExpressTransactionsClickIntents, appCurrencyProvider: Provider, currentStateProvider: Provider, userWallet: UserWallet, diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/express/ExpressStatusFactory.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/express/ExpressStatusFactory.kt index 46a530ddbe..bb0dbbd4c4 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/express/ExpressStatusFactory.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/express/ExpressStatusFactory.kt @@ -12,7 +12,7 @@ import com.tangem.domain.tokens.model.analytics.TokenExchangeAnalyticsEvent import com.tangem.domain.tokens.model.analytics.TokenOnrampAnalyticsEvent import com.tangem.domain.tokens.model.analytics.TokenScreenAnalyticsEvent import com.tangem.feature.swap.domain.models.domain.ExchangeStatus -import com.tangem.feature.tokendetails.presentation.tokendetails.model.TokenDetailsClickIntents +import com.tangem.feature.tokendetails.presentation.tokendetails.model.ExpressTransactionsClickIntents import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.ExchangeStatusNotification import com.tangem.feature.tokendetails.presentation.tokendetails.state.express.ExchangeUM @@ -33,7 +33,7 @@ import kotlinx.coroutines.withContext @Suppress("LongParameterList") internal class ExpressStatusFactory @AssistedInject constructor( @Assisted private val currentStateProvider: Provider, - @Assisted private val clickIntents: TokenDetailsClickIntents, + @Assisted private val clickIntents: ExpressTransactionsClickIntents, @Assisted private val cryptoCurrency: CryptoCurrency, @Assisted appCurrencyProvider: Provider, @Assisted userWallet: UserWallet, @@ -205,7 +205,7 @@ internal class ExpressStatusFactory @AssistedInject constructor( interface Factory { @Suppress("LongParameterList") fun create( - clickIntents: TokenDetailsClickIntents, + clickIntents: ExpressTransactionsClickIntents, appCurrencyProvider: Provider, currentStateProvider: Provider, userWallet: UserWallet, diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/express/OnrampStatusFactory.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/express/OnrampStatusFactory.kt index 61a05030ba..4543119759 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/express/OnrampStatusFactory.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/express/OnrampStatusFactory.kt @@ -15,7 +15,7 @@ import com.tangem.domain.onramp.OnrampUpdateTransactionStatusUseCase import com.tangem.domain.onramp.model.OnrampStatus import com.tangem.domain.onramp.model.OnrampStatus.Status.* import com.tangem.domain.tokens.model.analytics.TokenOnrampAnalyticsEvent -import com.tangem.feature.tokendetails.presentation.tokendetails.model.TokenDetailsClickIntents +import com.tangem.feature.tokendetails.presentation.tokendetails.model.ExpressTransactionsClickIntents import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.TokenDetailsOnrampTransactionStateConverter import com.tangem.utils.Provider @@ -37,7 +37,7 @@ internal class OnrampStatusFactory @AssistedInject constructor( @Assisted private val currentStateProvider: Provider, @Assisted private val cryptoCurrencyStatusProvider: Provider, @Assisted private val appCurrencyProvider: Provider, - @Assisted private val clickIntents: TokenDetailsClickIntents, + @Assisted private val clickIntents: ExpressTransactionsClickIntents, @Assisted private val cryptoCurrency: CryptoCurrency, @Assisted private val userWallet: UserWallet, ) { @@ -157,7 +157,7 @@ internal class OnrampStatusFactory @AssistedInject constructor( currentStateProvider: Provider, cryptoCurrencyStatusProvider: Provider, appCurrencyProvider: Provider, - clickIntents: TokenDetailsClickIntents, + clickIntents: ExpressTransactionsClickIntents, cryptoCurrency: CryptoCurrency, userWallet: UserWallet, ): OnrampStatusFactory diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/utils/DefaultExpressTransactionsEventListener.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/utils/DefaultExpressTransactionsEventListener.kt new file mode 100644 index 0000000000..b6a5d1da32 --- /dev/null +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/utils/DefaultExpressTransactionsEventListener.kt @@ -0,0 +1,24 @@ +package com.tangem.feature.tokendetails.presentation.tokendetails.state.utils + +import com.tangem.features.tokendetails.ExpressTransactionsEvent +import com.tangem.features.tokendetails.ExpressTransactionsEventListener +import kotlinx.coroutines.channels.BufferOverflow +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableSharedFlow +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +internal class DefaultExpressTransactionsEventListener @Inject constructor() : ExpressTransactionsEventListener { + + private val _event = MutableSharedFlow( + replay = 1, + extraBufferCapacity = 0, + onBufferOverflow = BufferOverflow.DROP_OLDEST, + ) + override val event: Flow = _event + + override suspend fun send(event: ExpressTransactionsEvent) { + _event.emit(event) + } +} \ No newline at end of file diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/TokenDetailsScreen.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/TokenDetailsScreen.kt index f3466d9025..2e2ea39238 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/TokenDetailsScreen.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/TokenDetailsScreen.kt @@ -45,7 +45,7 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow // TODO: Split to blocks [REDACTED_JIRA] -@Suppress("LongMethod") +@Suppress("LongMethod", "CyclomaticComplexMethod") @Composable internal fun TokenDetailsScreen( state: TokenDetailsState, @@ -62,6 +62,7 @@ internal fun TokenDetailsScreen( ) { scaffoldPaddings -> val listState = rememberLazyListState() val txHistoryComponentState by txHistoryComponent.txHistoryState.collectAsStateWithLifecycle() + val dialogConfig = state.dialogConfig val betweenItemsPadding = TangemTheme.dimens.spacing12 val horizontalPadding = TangemTheme.dimens.spacing16 val itemModifier = Modifier @@ -162,7 +163,9 @@ internal fun TokenDetailsScreen( } } - TokenDetailsDialogs(state = state) + if (dialogConfig != null) { + TokenDetailsDialogs(dialogConfig = dialogConfig) + } state.bottomSheetConfig?.let { config -> when (config.content) { diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/TokenDetailsDialogs.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/TokenDetailsDialogs.kt index 3e57199b5a..5428e5d949 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/TokenDetailsDialogs.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/TokenDetailsDialogs.kt @@ -1,16 +1,14 @@ package com.tangem.feature.tokendetails.presentation.tokendetails.ui.components import androidx.compose.runtime.Composable +import com.tangem.common.ui.tokendetails.TokenDetailsDialogConfig import com.tangem.core.ui.components.BasicDialog import com.tangem.core.ui.components.DialogButtonUM import com.tangem.core.ui.extensions.resolveReference -import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState -import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.TokenDetailsDialogConfig @Composable -internal fun TokenDetailsDialogs(state: TokenDetailsState) { - val dialogConfig = state.dialogConfig - if (dialogConfig != null && dialogConfig.isShow) { +internal fun TokenDetailsDialogs(dialogConfig: TokenDetailsDialogConfig) { + if (dialogConfig.isShow) { TokenDetailsDialog(config = dialogConfig) } } @@ -21,7 +19,7 @@ private fun TokenDetailsDialog(config: TokenDetailsDialogConfig) { message = config.content.message.resolveReference(), confirmButton = DialogButtonUM( title = config.content.confirmButtonConfig.text.resolveReference(), - isWarning = config.content.confirmButtonConfig.warning, + isWarning = config.content.confirmButtonConfig.hasWarning, onClick = config.content.confirmButtonConfig.onClick, ), onDismissDialog = config.onDismissRequest, @@ -29,7 +27,7 @@ private fun TokenDetailsDialog(config: TokenDetailsDialogConfig) { dismissButton = config.content.cancelButtonConfig?.let { cancelButtonConfig -> DialogButtonUM( title = cancelButtonConfig.text.resolveReference(), - isWarning = cancelButtonConfig.warning, + isWarning = cancelButtonConfig.hasWarning, onClick = cancelButtonConfig.onClick, ) },