diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/stories/StoriesContainer.kt b/core/ui/src/main/java/com/tangem/core/ui/components/stories/StoriesContainer.kt index f1cd043fd6..0bcf8ace95 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/stories/StoriesContainer.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/stories/StoriesContainer.kt @@ -56,15 +56,19 @@ inline fun StoriesContainer( onNextStory = storyState::nextStory, ) + currentStoryContent(storyState.currentStory, isPaused) + StoriesProgressBar( steps = storyState.steps, currentStep = storyState.currentIndex.intValue, stepDuration = storyState.currentStory.duration, paused = isPaused, - onStepFinish = storyState::nextStory, + onStepFinish = { + if (storyState.nextStory()) { + config.onClose() + } + }, ) - - currentStoryContent(storyState.currentStory, isPaused) } } @@ -97,6 +101,7 @@ private data class StoryContainerPreviewProviderData( StoryConfigPreviewProviderData(title = "Wallet"), ), override val isRestartable: Boolean = true, + override val onClose: () -> Unit = {}, ) : StoriesContentConfig private data class StoryConfigPreviewProviderData( diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/stories/inner/StoriesProgressBar.kt b/core/ui/src/main/java/com/tangem/core/ui/components/stories/inner/StoriesProgressBar.kt index f2c504316e..5f009d8569 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/stories/inner/StoriesProgressBar.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/stories/inner/StoriesProgressBar.kt @@ -80,6 +80,7 @@ fun StoriesProgressBar( Row( verticalAlignment = Alignment.CenterVertically, modifier = Modifier + .statusBarsPadding() .padding( start = 16.dp, end = 16.dp, diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/stories/model/StoriesContentConfig.kt b/core/ui/src/main/java/com/tangem/core/ui/components/stories/model/StoriesContentConfig.kt index 68cc624895..f5e569292a 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/stories/model/StoriesContentConfig.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/stories/model/StoriesContentConfig.kt @@ -11,6 +11,7 @@ import kotlinx.collections.immutable.ImmutableList interface StoriesContentConfig { val stories: ImmutableList val isRestartable: Boolean + val onClose: () -> Unit } interface StoryConfig { diff --git a/features/swap/presentation/build.gradle.kts b/features/swap/presentation/build.gradle.kts index dfd97b9d99..3049182a5f 100644 --- a/features/swap/presentation/build.gradle.kts +++ b/features/swap/presentation/build.gradle.kts @@ -38,6 +38,7 @@ dependencies { implementation(projects.domain.settings) implementation(projects.domain.staking) implementation(projects.domain.feedback) + implementation(projects.domain.promo) /** Feature modules */ implementation(projects.features.swap.domain) diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/SwapStateHolder.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/SwapStateHolder.kt index 542c5974cb..d4498bf83c 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/SwapStateHolder.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/SwapStateHolder.kt @@ -34,6 +34,7 @@ internal data class SwapStateHolder( val successState: SwapSuccessStateHolder? = null, val selectTokenState: SwapSelectTokenStateHolder? = null, val bottomSheetConfig: TangemBottomSheetConfig? = null, + val storiesConfig: SwapStoriesContentConfig? = null, val swapButton: SwapButton, val shouldShowMaxAmount: Boolean, diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/SwapStoriesContentConfig.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/SwapStoriesContentConfig.kt new file mode 100644 index 0000000000..625eecdb62 --- /dev/null +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/SwapStoriesContentConfig.kt @@ -0,0 +1,19 @@ +package com.tangem.feature.swap.models + +import androidx.annotation.DrawableRes +import com.tangem.core.ui.components.stories.model.StoriesContentConfig +import com.tangem.core.ui.components.stories.model.StoryConfig +import kotlinx.collections.immutable.ImmutableList + +data class SwapStoriesContentConfig( + override val stories: ImmutableList, + override val onClose: () -> Unit, +) : StoriesContentConfig { + override val isRestartable: Boolean = false +} + +data class SwapStoryConfig( + @DrawableRes val imageRes: Int, +) : StoryConfig { + override val duration: Int = 2000 +} \ No newline at end of file diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/UiActions.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/UiActions.kt index 0075bcca6e..4c7a41a979 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/UiActions.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/UiActions.kt @@ -21,6 +21,7 @@ data class UiActions( val openPermissionBottomSheet: () -> Unit, val onChangeApproveType: (ApproveType) -> Unit, // region new actions + val onStoriesClose: () -> Unit, val onRetryClick: () -> Unit, val onClickFee: () -> Unit, val onSelectFeeType: (TxFee) -> Unit, diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/presentation/SwapFragment.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/presentation/SwapFragment.kt index d6389ac181..86c77dd6e8 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/presentation/SwapFragment.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/presentation/SwapFragment.kt @@ -13,6 +13,7 @@ import com.tangem.core.ui.screen.ComposeFragment 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.SwapStoriesScreen import com.tangem.feature.swap.ui.SwapSuccessScreen import com.tangem.feature.swap.viewmodels.SwapViewModel import dagger.hilt.android.AndroidEntryPoint @@ -46,6 +47,14 @@ class SwapFragment : ComposeFragment() { label = "", ) { screen -> when (screen) { + SwapNavScreen.PromoStories -> { + val storiesConfig = viewModel.uiState.storiesConfig + if (storiesConfig != null) { + SwapStoriesScreen(config = storiesConfig) + } else { + SwapScreen(stateHolder = viewModel.uiState) + } + } SwapNavScreen.Main -> SwapScreen(stateHolder = viewModel.uiState) SwapNavScreen.Success -> { val successState = viewModel.uiState.successState diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/router/SwapRouter.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/router/SwapRouter.kt index 98ceb6e3d4..48bdde9475 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/router/SwapRouter.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/router/SwapRouter.kt @@ -67,5 +67,5 @@ internal class SwapRouter( } enum class SwapNavScreen { - Main, Success, SelectToken + Main, Success, SelectToken, PromoStories } \ No newline at end of file diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt index c932040053..219efa3a97 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt @@ -125,6 +125,26 @@ internal class StateBuilder( ) } + fun createStoriesState(uiStateHolder: SwapStateHolder): SwapStateHolder { + return uiStateHolder.copy( + // todo stories [REDACTED_TASK_KEY] fix when design is ready + storiesConfig = SwapStoriesContentConfig( + stories = persistentListOf( + SwapStoryConfig( + imageRes = R.drawable.img_card_with_ring, + ), + SwapStoryConfig( + imageRes = R.drawable.ill_businessman_3d, + ), + SwapStoryConfig( + imageRes = R.drawable.ill_one_inch_powered, + ), + ), + onClose = actions.onStoriesClose, + ), + ) + } + fun createNoAvailableTokensToSwapState( uiStateHolder: SwapStateHolder, fromToken: CryptoCurrencyStatus, diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapStoriesScreen.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapStoriesScreen.kt new file mode 100644 index 0000000000..edb6c2d5b6 --- /dev/null +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapStoriesScreen.kt @@ -0,0 +1,20 @@ +package com.tangem.feature.swap.ui + +import androidx.compose.foundation.Image +import androidx.compose.runtime.Composable +import androidx.compose.ui.res.painterResource +import com.tangem.core.ui.components.stories.StoriesContainer +import com.tangem.feature.swap.models.SwapStoriesContentConfig + +@Composable +internal fun SwapStoriesScreen(config: SwapStoriesContentConfig) { + StoriesContainer( + config = config, + ) { current, _ -> + // todo stories [REDACTED_TASK_KEY] fix when design is ready + Image( + painter = painterResource(current.imageRes), + contentDescription = null, + ) + } +} \ No newline at end of file diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt index ae4b5ef4d6..40de9a3c95 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt @@ -27,6 +27,7 @@ import com.tangem.domain.feedback.SaveBlockchainErrorUseCase import com.tangem.domain.feedback.SendFeedbackEmailUseCase import com.tangem.domain.feedback.models.BlockchainErrorInfo import com.tangem.domain.feedback.models.FeedbackEmailType +import com.tangem.domain.promo.ShouldShowSwapStoriesUseCase import com.tangem.domain.tokens.* import com.tangem.domain.tokens.model.CryptoCurrency import com.tangem.domain.tokens.model.CryptoCurrencyStatus @@ -50,6 +51,7 @@ import com.tangem.feature.swap.router.SwapNavScreen import com.tangem.feature.swap.router.SwapRouter import com.tangem.feature.swap.ui.StateBuilder import com.tangem.feature.swap.utils.formatToUIRepresentation +import com.tangem.features.swap.SwapFeatureToggles import com.tangem.utils.Provider import com.tangem.utils.coroutines.* import com.tangem.utils.isNullOrZero @@ -86,6 +88,8 @@ internal class SwapViewModel @Inject constructor( private val saveBlockchainErrorUseCase: SaveBlockchainErrorUseCase, private val sendFeedbackEmailUseCase: SendFeedbackEmailUseCase, private val getMinimumTransactionAmountSyncUseCase: GetMinimumTransactionAmountSyncUseCase, + private val shouldShowSwapStoriesUseCase: ShouldShowSwapStoriesUseCase, + private val featureToggles: SwapFeatureToggles, swapInteractorFactory: SwapInteractor.Factory, private val savedStateHandle: SavedStateHandle, private val urlOpener: UrlOpener, @@ -168,6 +172,13 @@ internal class SwapViewModel @Inject constructor( val fromStatus = getCryptoCurrencyStatusUseCase(userWalletId, initialCurrencyFrom.id).getOrNull() val toStatus = initialCurrencyTo?.let { getCryptoCurrencyStatusUseCase(userWalletId, it.id).getOrNull() } val wallet = getUserWalletUseCase(userWalletId).getOrNull() + val isShowPromoStories = shouldShowSwapStoriesUseCase.invokeSync() && featureToggles.isPromoStoriesEnabled + + if (isShowPromoStories) { + initStories() + swapRouter.openScreen(SwapNavScreen.PromoStories) + } + if (fromStatus == null || wallet == null) { uiState = stateBuilder.addAlert(uiState = uiState, onDismiss = swapRouter::back) } else { @@ -271,6 +282,10 @@ internal class SwapViewModel @Inject constructor( } } + private fun initStories() { + uiState = stateBuilder.createStoriesState(uiState) + } + private fun applyInitialTokenChoice( state: TokensDataStateExpress, selectedCurrency: CryptoCurrencyStatus?, @@ -1115,6 +1130,9 @@ internal class SwapViewModel @Inject constructor( onSuccess = { swapRouter.openScreen(SwapNavScreen.Success) }, + onStoriesClose = { + swapRouter.openScreen(SwapNavScreen.Main) + }, ) }