Updated on 2026-08-14
This commit is contained in:
parent
054a7f982f
commit
a7ab7abbfb
23 changed files with 165 additions and 30 deletions
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.features.markets.portfolio.impl.model
|
||||
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.core.analytics.models.AnalyticsParam
|
||||
import com.tangem.core.decompose.di.ComponentScoped
|
||||
import com.tangem.core.decompose.navigation.Router
|
||||
import com.tangem.core.decompose.ui.UiMessageSender
|
||||
|
|
@ -155,6 +156,7 @@ internal class TokenActionsHandler @AssistedInject constructor(
|
|||
currencyFrom = cryptoCurrencyData.status.currency,
|
||||
userWalletId = cryptoCurrencyData.userWallet.walletId,
|
||||
isInitialReverseOrder = true,
|
||||
screenSource = AnalyticsParam.ScreensSources.Markets.value,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -94,6 +94,7 @@ internal class SwapSelectTokensModel @Inject constructor(
|
|||
currencyFrom = requireNotNull(fromCurrencyStatus.value).currency,
|
||||
currencyTo = status.currency,
|
||||
userWalletId = params.userWalletId,
|
||||
screenSource = AnalyticsParam.ScreensSources.Main.value,
|
||||
),
|
||||
onComplete = {
|
||||
modelScope.launch {
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ interface StoriesComponent : ComposableContentComponent {
|
|||
data class Params(
|
||||
val storyId: String,
|
||||
val nextScreen: AppRoute,
|
||||
val screenSource: String,
|
||||
)
|
||||
|
||||
interface Factory : ComponentFactory<Params, StoriesComponent>
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ dependencies {
|
|||
implementation(projects.core.decompose)
|
||||
implementation(projects.core.navigation)
|
||||
implementation(projects.core.ui)
|
||||
implementation(projects.core.analytics)
|
||||
|
||||
/** AndroidX */
|
||||
implementation(deps.androidx.activity.compose)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
package com.tangem.feature.stories.impl.analytics
|
||||
|
||||
import com.tangem.core.analytics.models.AnalyticsEvent
|
||||
import com.tangem.core.analytics.models.AnalyticsParam
|
||||
import com.tangem.core.analytics.models.AnalyticsParam.Key.WATCHED
|
||||
|
||||
sealed class StoriesEvents(
|
||||
event: String,
|
||||
params: Map<String, String> = mapOf(),
|
||||
) : AnalyticsEvent("Stories", event, params) {
|
||||
|
||||
data class SwapStories(
|
||||
val source: String,
|
||||
val watchCount: String,
|
||||
) : StoriesEvents(
|
||||
event = "Swap Stories",
|
||||
params = mapOf(
|
||||
AnalyticsParam.SOURCE to source,
|
||||
WATCHED to watchCount,
|
||||
),
|
||||
)
|
||||
|
||||
data class Error(
|
||||
val source: String,
|
||||
val type: String,
|
||||
) : StoriesEvents(
|
||||
event = "Error",
|
||||
params = mapOf(
|
||||
AnalyticsParam.SOURCE to source,
|
||||
AnalyticsParam.TYPE to type,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ package com.tangem.feature.stories.impl.model
|
|||
|
||||
import com.tangem.common.ui.swapStoriesScreen.SwapStoriesFactory
|
||||
import com.tangem.common.ui.swapStoriesScreen.SwapStoriesUM
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
import com.tangem.core.decompose.navigation.Router
|
||||
|
|
@ -9,6 +10,7 @@ import com.tangem.domain.promo.GetStoryContentUseCase
|
|||
import com.tangem.domain.promo.ShouldShowStoriesUseCase
|
||||
import com.tangem.domain.promo.models.StoryContentIds
|
||||
import com.tangem.feature.stories.api.StoriesComponent
|
||||
import com.tangem.feature.stories.impl.analytics.StoriesEvents
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
|
@ -23,6 +25,7 @@ internal class StoriesModel @Inject constructor(
|
|||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
private val getStoryContentUseCase: GetStoryContentUseCase,
|
||||
private val shouldShowStoriesUseCase: ShouldShowStoriesUseCase,
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
) : Model() {
|
||||
val state: StateFlow<SwapStoriesUM> get() = _state
|
||||
|
||||
|
|
@ -50,16 +53,36 @@ internal class StoriesModel @Inject constructor(
|
|||
getStoryContentUseCase.invokeSync(params.storyId).fold(
|
||||
ifLeft = {
|
||||
Timber.e("Unable to load stories for ${StoryContentIds.STORY_FIRST_TIME_SWAP.id}")
|
||||
analyticsEventHandler.send(
|
||||
StoriesEvents.Error(
|
||||
source = params.screenSource,
|
||||
type = StoryContentIds.STORY_FIRST_TIME_SWAP.analyticType,
|
||||
),
|
||||
)
|
||||
openScreen(hideStories = false) // Fallback to target screen
|
||||
},
|
||||
ifRight = { swapStory ->
|
||||
if (swapStory == null) {
|
||||
analyticsEventHandler.send(
|
||||
StoriesEvents.Error(
|
||||
source = params.screenSource,
|
||||
type = StoryContentIds.STORY_FIRST_TIME_SWAP.analyticType,
|
||||
),
|
||||
)
|
||||
openScreen(hideStories = false) // Fallback to target screen
|
||||
} else {
|
||||
_state.update {
|
||||
SwapStoriesFactory.createStoriesState(
|
||||
swapStory = swapStory,
|
||||
onStoriesClose = ::openScreen,
|
||||
onStoriesClose = { watchCount ->
|
||||
analyticsEventHandler.send(
|
||||
StoriesEvents.SwapStories(
|
||||
source = params.screenSource,
|
||||
watchCount = watchCount.toString(),
|
||||
),
|
||||
)
|
||||
openScreen()
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ interface SwapComponent : ComposableContentComponent {
|
|||
val currencyTo: CryptoCurrency? = null,
|
||||
val userWalletId: UserWalletId,
|
||||
val isInitialReverseOrder: Boolean = false,
|
||||
val screenSource: String,
|
||||
)
|
||||
|
||||
interface Factory : ComponentFactory<Params, SwapComponent>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
package com.tangem.feature.swap.analytics
|
||||
|
||||
import com.tangem.core.analytics.models.AnalyticsEvent
|
||||
import com.tangem.core.analytics.models.AnalyticsParam
|
||||
import com.tangem.core.analytics.models.AnalyticsParam.Key.WATCHED
|
||||
|
||||
sealed class StoriesEvents(
|
||||
event: String,
|
||||
params: Map<String, String> = mapOf(),
|
||||
) : AnalyticsEvent("Stories", event, params) {
|
||||
|
||||
data class SwapStories(
|
||||
val source: String,
|
||||
val watchCount: String,
|
||||
) : StoriesEvents(
|
||||
event = "Swap Stories",
|
||||
params = mapOf(
|
||||
AnalyticsParam.SOURCE to source,
|
||||
WATCHED to watchCount,
|
||||
),
|
||||
)
|
||||
|
||||
data class Error(
|
||||
val source: String,
|
||||
val type: String,
|
||||
) : StoriesEvents(
|
||||
event = "Error",
|
||||
params = mapOf(
|
||||
AnalyticsParam.SOURCE to source,
|
||||
AnalyticsParam.TYPE to type,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -37,6 +37,7 @@ import com.tangem.domain.tokens.model.Network
|
|||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
|
||||
import com.tangem.feature.swap.analytics.StoriesEvents
|
||||
import com.tangem.feature.swap.analytics.SwapEvents
|
||||
import com.tangem.feature.swap.domain.BlockchainInteractor
|
||||
import com.tangem.feature.swap.domain.SwapInteractor
|
||||
|
|
@ -277,10 +278,23 @@ internal class SwapModel @Inject constructor(
|
|||
getStoryContentUseCase.invokeSync(StoryContentIds.STORY_FIRST_TIME_SWAP.id).fold(
|
||||
ifLeft = {
|
||||
Timber.e("Unable to load stories for ${StoryContentIds.STORY_FIRST_TIME_SWAP.id}")
|
||||
analyticsEventHandler.send(
|
||||
StoriesEvents.Error(
|
||||
source = params.screenSource,
|
||||
type = StoryContentIds.STORY_FIRST_TIME_SWAP.analyticType,
|
||||
),
|
||||
)
|
||||
},
|
||||
ifRight = { story ->
|
||||
story?.let {
|
||||
if (story != null) {
|
||||
uiState = stateBuilder.createStoriesState(uiState, story)
|
||||
} else {
|
||||
analyticsEventHandler.send(
|
||||
StoriesEvents.Error(
|
||||
source = params.screenSource,
|
||||
type = StoryContentIds.STORY_FIRST_TIME_SWAP.analyticType,
|
||||
),
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
|
|
@ -1131,7 +1145,13 @@ internal class SwapModel @Inject constructor(
|
|||
onSuccess = {
|
||||
swapRouter.openScreen(SwapNavScreen.Success)
|
||||
},
|
||||
onStoriesClose = {
|
||||
onStoriesClose = { watchCount ->
|
||||
analyticsEventHandler.send(
|
||||
StoriesEvents.SwapStories(
|
||||
source = params.screenSource,
|
||||
watchCount = watchCount.toString(),
|
||||
),
|
||||
)
|
||||
modelScope.launch { shouldShowStoriesUseCase.neverToShow(StoryContentIds.STORY_FIRST_TIME_SWAP.id) }
|
||||
swapRouter.openScreen(SwapNavScreen.Main)
|
||||
},
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ data class UiActions(
|
|||
val openPermissionBottomSheet: () -> Unit,
|
||||
val onChangeApproveType: (ApproveType) -> Unit,
|
||||
// region new actions
|
||||
val onStoriesClose: () -> Unit,
|
||||
val onStoriesClose: (Int) -> Unit,
|
||||
val onRetryClick: () -> Unit,
|
||||
val onClickFee: () -> Unit,
|
||||
val onSelectFeeType: (TxFee) -> Unit,
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ import com.tangem.domain.card.NetworkHasDerivationUseCase
|
|||
import com.tangem.domain.common.util.cardTypesResolver
|
||||
import com.tangem.domain.demo.IsDemoCardUseCase
|
||||
import com.tangem.domain.onramp.model.OnrampSource
|
||||
import com.tangem.domain.promo.ShouldShowSwapPromoTokenUseCase
|
||||
import com.tangem.domain.redux.ReduxStateHolder
|
||||
import com.tangem.domain.staking.GetStakingAvailabilityUseCase
|
||||
import com.tangem.domain.staking.GetStakingEntryInfoUseCase
|
||||
|
|
@ -73,7 +74,6 @@ import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenBala
|
|||
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.domain.promo.ShouldShowSwapPromoTokenUseCase
|
||||
import com.tangem.features.onramp.OnrampFeatureToggles
|
||||
import com.tangem.features.tokendetails.impl.R
|
||||
import com.tangem.utils.Provider
|
||||
|
|
@ -645,7 +645,13 @@ internal class TokenDetailsViewModel @Inject constructor(
|
|||
return
|
||||
}
|
||||
|
||||
appRouter.push(AppRoute.Swap(currencyFrom = cryptoCurrency, userWalletId = userWalletId))
|
||||
appRouter.push(
|
||||
AppRoute.Swap(
|
||||
currencyFrom = cryptoCurrency,
|
||||
userWalletId = userWalletId,
|
||||
screenSource = AnalyticsParam.ScreensSources.Token.value,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
override fun onDismissDialog() {
|
||||
|
|
|
|||
|
|
@ -358,6 +358,7 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor(
|
|||
AppRoute.Swap(
|
||||
currencyFrom = cryptoCurrencyStatus.currency,
|
||||
userWalletId = userWalletId,
|
||||
screenSource = AnalyticsParam.ScreensSources.LongTap.value,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -617,6 +618,7 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor(
|
|||
AppRoute.Stories(
|
||||
storyId = StoryContentIds.STORY_FIRST_TIME_SWAP.id,
|
||||
nextScreen = targetRoute,
|
||||
screenSource = AnalyticsParam.ScreensSources.Main.value,
|
||||
)
|
||||
} else {
|
||||
targetRoute
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue