Updated on 2026-08-14
This commit is contained in:
parent
563d95d75e
commit
1b25b81caf
12 changed files with 100 additions and 4 deletions
|
|
@ -56,15 +56,19 @@ inline fun <reified T : StoryConfig> 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<StoryConfigPreviewProviderData>
|
||||
|
||||
private data class StoryConfigPreviewProviderData(
|
||||
|
|
|
|||
|
|
@ -80,6 +80,7 @@ fun StoriesProgressBar(
|
|||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier
|
||||
.statusBarsPadding()
|
||||
.padding(
|
||||
start = 16.dp,
|
||||
end = 16.dp,
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import kotlinx.collections.immutable.ImmutableList
|
|||
interface StoriesContentConfig<T : StoryConfig> {
|
||||
val stories: ImmutableList<T>
|
||||
val isRestartable: Boolean
|
||||
val onClose: () -> Unit
|
||||
}
|
||||
|
||||
interface StoryConfig {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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<SwapStoryConfig>,
|
||||
override val onClose: () -> Unit,
|
||||
) : StoriesContentConfig<SwapStoryConfig> {
|
||||
override val isRestartable: Boolean = false
|
||||
}
|
||||
|
||||
data class SwapStoryConfig(
|
||||
@DrawableRes val imageRes: Int,
|
||||
) : StoryConfig {
|
||||
override val duration: Int = 2000
|
||||
}
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -67,5 +67,5 @@ internal class SwapRouter(
|
|||
}
|
||||
|
||||
enum class SwapNavScreen {
|
||||
Main, Success, SelectToken
|
||||
Main, Success, SelectToken, PromoStories
|
||||
}
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue