Updated on 2026-08-14
This commit is contained in:
parent
cf1f3c8b30
commit
8459eb743b
8 changed files with 30 additions and 54 deletions
|
|
@ -29,6 +29,7 @@ import com.tangem.domain.settings.IncrementAppLaunchCounterUseCase
|
||||||
import com.tangem.domain.settings.usercountry.FetchUserCountryUseCase
|
import com.tangem.domain.settings.usercountry.FetchUserCountryUseCase
|
||||||
import com.tangem.domain.staking.FetchStakingTokensUseCase
|
import com.tangem.domain.staking.FetchStakingTokensUseCase
|
||||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||||
|
import com.tangem.feature.swap.analytics.StoriesEvents
|
||||||
import com.tangem.features.onramp.OnrampFeatureToggles
|
import com.tangem.features.onramp.OnrampFeatureToggles
|
||||||
import com.tangem.features.swap.SwapFeatureToggles
|
import com.tangem.features.swap.SwapFeatureToggles
|
||||||
import com.tangem.tap.common.extensions.setContext
|
import com.tangem.tap.common.extensions.setContext
|
||||||
|
|
@ -300,19 +301,32 @@ internal class MainViewModel @Inject constructor(
|
||||||
private fun preloadImages() {
|
private fun preloadImages() {
|
||||||
try {
|
try {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
val swapStories = if (swapFeatureToggles.isPromoStoriesEnabled) {
|
if (swapFeatureToggles.isPromoStoriesEnabled) {
|
||||||
getStoryContentUseCase.invokeSync(StoryContentIds.STORY_FIRST_TIME_SWAP.id)
|
val swapStories = getStoryContentUseCase.invokeSync(
|
||||||
.getOrNull()
|
id = StoryContentIds.STORY_FIRST_TIME_SWAP.id,
|
||||||
} else {
|
refresh = true,
|
||||||
null
|
).getOrNull()
|
||||||
}
|
|
||||||
|
|
||||||
val storiesImages = swapStories?.getImageUrls()
|
if (swapStories == null) {
|
||||||
// try to preload images for stories
|
analyticsEventHandler.send(
|
||||||
storiesImages?.forEach(imagePreloader::preload)
|
StoriesEvents.Error(
|
||||||
|
type = StoryContentIds.STORY_FIRST_TIME_SWAP.analyticType,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
val storiesImages = swapStories.getImageUrls()
|
||||||
|
// try to preload images for stories
|
||||||
|
storiesImages.forEach(imagePreloader::preload)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (ex: Exception) {
|
} catch (ex: Exception) {
|
||||||
Timber.e(ex.message)
|
Timber.e(ex.message)
|
||||||
|
analyticsEventHandler.send(
|
||||||
|
StoriesEvents.Error(
|
||||||
|
type = StoryContentIds.STORY_FIRST_TIME_SWAP.analyticType,
|
||||||
|
),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -44,15 +44,15 @@ internal class DefaultPromoRepository(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getStoryById(id: String): Flow<StoryContent?> = isReadyToShowStories(id).mapLatest {
|
override fun getStoryById(id: String): Flow<StoryContent?> = isReadyToShowStories(id).mapLatest {
|
||||||
getStoryByIdSync(id)
|
getStoryByIdSync(id = id, refresh = false)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getStoryByIdSync(id: String): StoryContent? = withContext(dispatchers.io) {
|
override suspend fun getStoryByIdSync(id: String, refresh: Boolean): StoryContent? = withContext(dispatchers.io) {
|
||||||
if (!isReadyToShowStoriesSync(id)) return@withContext null
|
if (!isReadyToShowStoriesSync(id)) return@withContext null
|
||||||
|
|
||||||
val storedPromo = promoStoriesStore.getSyncOrNull(storyId = id)
|
val storedPromo = promoStoriesStore.getSyncOrNull(storyId = id)
|
||||||
// Get last stored promo by id if possible or get from network
|
// Get last stored promo by id if possible or get from network
|
||||||
val story = if (storedPromo == null) {
|
val story = if (storedPromo == null && refresh) {
|
||||||
val storyContent = runCatching {
|
val storyContent = runCatching {
|
||||||
// Important to return
|
// Important to return
|
||||||
withTimeoutOrNull(STORIES_LOAD_DELAY) {
|
withTimeoutOrNull(STORIES_LOAD_DELAY) {
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ class GetStoryContentUseCase(
|
||||||
.catch { emit(it.left()) }
|
.catch { emit(it.left()) }
|
||||||
.onEmpty { emit(null.right()) }
|
.onEmpty { emit(null.right()) }
|
||||||
|
|
||||||
suspend fun invokeSync(id: String): Either<Throwable, StoryContent?> = Either.catch {
|
suspend fun invokeSync(id: String, refresh: Boolean = false): Either<Throwable, StoryContent?> = Either.catch {
|
||||||
promoRepository.getStoryByIdSync(id)
|
promoRepository.getStoryByIdSync(id, refresh)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -18,7 +18,7 @@ interface PromoRepository {
|
||||||
// region Stories
|
// region Stories
|
||||||
fun getStoryById(id: String): Flow<StoryContent?>
|
fun getStoryById(id: String): Flow<StoryContent?>
|
||||||
|
|
||||||
suspend fun getStoryByIdSync(id: String): StoryContent?
|
suspend fun getStoryByIdSync(id: String, refresh: Boolean): StoryContent?
|
||||||
|
|
||||||
fun isReadyToShowStories(storyId: String): Flow<Boolean>
|
fun isReadyToShowStories(storyId: String): Flow<Boolean>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,15 +19,4 @@ sealed class StoriesEvents(
|
||||||
WATCHED to watchCount,
|
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,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
@ -53,22 +53,10 @@ internal class StoriesModel @Inject constructor(
|
||||||
getStoryContentUseCase.invokeSync(params.storyId).fold(
|
getStoryContentUseCase.invokeSync(params.storyId).fold(
|
||||||
ifLeft = {
|
ifLeft = {
|
||||||
Timber.e("Unable to load stories for ${StoryContentIds.STORY_FIRST_TIME_SWAP.id}")
|
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
|
openScreen(hideStories = false) // Fallback to target screen
|
||||||
},
|
},
|
||||||
ifRight = { swapStory ->
|
ifRight = { swapStory ->
|
||||||
if (swapStory == null) {
|
if (swapStory == null) {
|
||||||
analyticsEventHandler.send(
|
|
||||||
StoriesEvents.Error(
|
|
||||||
source = params.screenSource,
|
|
||||||
type = StoryContentIds.STORY_FIRST_TIME_SWAP.analyticType,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
openScreen(hideStories = false) // Fallback to target screen
|
openScreen(hideStories = false) // Fallback to target screen
|
||||||
} else {
|
} else {
|
||||||
_state.update {
|
_state.update {
|
||||||
|
|
|
||||||
|
|
@ -21,12 +21,10 @@ sealed class StoriesEvents(
|
||||||
)
|
)
|
||||||
|
|
||||||
data class Error(
|
data class Error(
|
||||||
val source: String,
|
|
||||||
val type: String,
|
val type: String,
|
||||||
) : StoriesEvents(
|
) : StoriesEvents(
|
||||||
event = "Error",
|
event = "Error",
|
||||||
params = mapOf(
|
params = mapOf(
|
||||||
AnalyticsParam.SOURCE to source,
|
|
||||||
AnalyticsParam.TYPE to type,
|
AnalyticsParam.TYPE to type,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -82,7 +82,6 @@ internal class SwapModel @Inject constructor(
|
||||||
override val dispatchers: CoroutineDispatcherProvider,
|
override val dispatchers: CoroutineDispatcherProvider,
|
||||||
private val blockchainInteractor: BlockchainInteractor,
|
private val blockchainInteractor: BlockchainInteractor,
|
||||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||||
private val getBalanceHidingSettingsUseCase: GetBalanceHidingSettingsUseCase,
|
|
||||||
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
|
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
|
||||||
private val getCryptoCurrencyStatusUseCase: GetCryptoCurrencyStatusSyncUseCase,
|
private val getCryptoCurrencyStatusUseCase: GetCryptoCurrencyStatusSyncUseCase,
|
||||||
private val updateDelayedCurrencyStatusUseCase: UpdateDelayedNetworkStatusUseCase,
|
private val updateDelayedCurrencyStatusUseCase: UpdateDelayedNetworkStatusUseCase,
|
||||||
|
|
@ -96,6 +95,7 @@ internal class SwapModel @Inject constructor(
|
||||||
private val shouldShowStoriesUseCase: ShouldShowStoriesUseCase,
|
private val shouldShowStoriesUseCase: ShouldShowStoriesUseCase,
|
||||||
private val getStoryContentUseCase: GetStoryContentUseCase,
|
private val getStoryContentUseCase: GetStoryContentUseCase,
|
||||||
private val featureToggles: SwapFeatureToggles,
|
private val featureToggles: SwapFeatureToggles,
|
||||||
|
getBalanceHidingSettingsUseCase: GetBalanceHidingSettingsUseCase,
|
||||||
swapInteractorFactory: SwapInteractor.Factory,
|
swapInteractorFactory: SwapInteractor.Factory,
|
||||||
private val urlOpener: UrlOpener,
|
private val urlOpener: UrlOpener,
|
||||||
router: AppRouter,
|
router: AppRouter,
|
||||||
|
|
@ -278,23 +278,10 @@ internal class SwapModel @Inject constructor(
|
||||||
getStoryContentUseCase.invokeSync(StoryContentIds.STORY_FIRST_TIME_SWAP.id).fold(
|
getStoryContentUseCase.invokeSync(StoryContentIds.STORY_FIRST_TIME_SWAP.id).fold(
|
||||||
ifLeft = {
|
ifLeft = {
|
||||||
Timber.e("Unable to load stories for ${StoryContentIds.STORY_FIRST_TIME_SWAP.id}")
|
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 ->
|
ifRight = { story ->
|
||||||
if (story != null) {
|
if (story != null) {
|
||||||
uiState = stateBuilder.createStoriesState(uiState, story)
|
uiState = stateBuilder.createStoriesState(uiState, story)
|
||||||
} else {
|
|
||||||
analyticsEventHandler.send(
|
|
||||||
StoriesEvents.Error(
|
|
||||||
source = params.screenSource,
|
|
||||||
type = StoryContentIds.STORY_FIRST_TIME_SWAP.analyticType,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue