Updated on 2026-08-14

This commit is contained in:
Tangem 2026-05-14 13:35:52 +03:00
parent f58a422765
commit c2e8cb82a7
39 changed files with 105 additions and 105 deletions

View file

@ -155,8 +155,8 @@ dependencies {
implementation(projects.domain.nft.models)
implementation(projects.domain.offramp)
implementation(projects.domain.onramp)
implementation(projects.domain.promo)
implementation(projects.domain.promo.models)
implementation(projects.domain.stories)
implementation(projects.domain.stories.models)
implementation(projects.domain.networks)
implementation(projects.domain.quotes)
implementation(projects.domain.notifications)
@ -207,7 +207,7 @@ dependencies {
implementation(projects.data.analytics)
implementation(projects.data.transaction)
implementation(projects.data.visa)
implementation(projects.data.promo)
implementation(projects.data.stories)
implementation(projects.data.onboarding)
implementation(projects.data.dynamicAddresses)
implementation(projects.data.feedback)

View file

@ -1,8 +1,8 @@
package com.tangem.tap.di.domain
import com.tangem.domain.promo.GetStoryContentUseCase
import com.tangem.domain.promo.PromoRepository
import com.tangem.domain.promo.ShouldShowStoriesUseCase
import com.tangem.domain.stories.GetStoryContentUseCase
import com.tangem.domain.stories.StoriesRepository
import com.tangem.domain.stories.ShouldShowStoriesUseCase
import com.tangem.domain.settings.repositories.SettingsRepository
import dagger.Module
import dagger.Provides
@ -12,20 +12,20 @@ import javax.inject.Singleton
@Module
@InstallIn(SingletonComponent::class)
internal object PromoDomainModule {
internal object StoriesDomainModule {
@Provides
@Singleton
fun provideShouldShowSwapStoriesUseCase(promoRepository: PromoRepository): ShouldShowStoriesUseCase {
return ShouldShowStoriesUseCase(promoRepository)
fun provideShouldShowStoriesUseCase(storiesRepository: StoriesRepository): ShouldShowStoriesUseCase {
return ShouldShowStoriesUseCase(storiesRepository)
}
@Provides
@Singleton
fun provideGetStoryContentUseCase(
promoRepository: PromoRepository,
storiesRepository: StoriesRepository,
settingsRepository: SettingsRepository,
): GetStoryContentUseCase {
return GetStoryContentUseCase(promoRepository, settingsRepository)
return GetStoryContentUseCase(storiesRepository, settingsRepository)
}
}

View file

@ -10,7 +10,7 @@ import com.tangem.domain.networks.multi.MultiNetworkStatusFetcher
import com.tangem.domain.networks.repository.NetworksRepository
import com.tangem.domain.networks.single.SingleNetworkStatusFetcher
import com.tangem.domain.pay.flow.PaymentAccountStatusFetcher
import com.tangem.domain.promo.PromoRepository
import com.tangem.domain.stories.StoriesRepository
import com.tangem.domain.quotes.multi.MultiQuoteStatusFetcher
import com.tangem.domain.staking.StakingIdFactory
import com.tangem.domain.staking.multi.MultiStakingBalanceFetcher
@ -55,14 +55,14 @@ internal object TokensDomainModule {
rampStateManager: RampStateManager,
walletManagersFacade: WalletManagersFacade,
stakingRepository: StakingRepository,
promoRepository: PromoRepository,
storiesRepository: StoriesRepository,
dispatchers: CoroutineDispatcherProvider,
): GetCryptoCurrencyActionsUseCase {
return GetCryptoCurrencyActionsUseCase(
rampManager = rampStateManager,
walletManagersFacade = walletManagersFacade,
stakingRepository = stakingRepository,
promoRepository = promoRepository,
storiesRepository = storiesRepository,
dispatchers = dispatchers,
)
}

View file

@ -27,8 +27,8 @@ import com.tangem.domain.notifications.SendPushTokenUseCase
import com.tangem.domain.notifications.models.ApplicationId
import com.tangem.domain.notifications.models.NotificationsError
import com.tangem.domain.onramp.FetchHotCryptoUseCase
import com.tangem.domain.promo.GetStoryContentUseCase
import com.tangem.domain.promo.models.StoryContentIds
import com.tangem.domain.stories.GetStoryContentUseCase
import com.tangem.domain.stories.models.StoryContentIds
import com.tangem.domain.quotes.multi.MultiQuoteUpdater
import com.tangem.domain.settings.DeleteDeprecatedLogsUseCase
import com.tangem.domain.settings.IncrementAppLaunchCounterUseCase

View file

@ -1,4 +1,4 @@
package com.tangem.datasource.api.promotion.models
package com.tangem.datasource.api.stories.models
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass

View file

@ -1,7 +1,7 @@
package com.tangem.datasource.api.tangemTech
import com.tangem.datasource.api.common.response.ApiResponse
import com.tangem.datasource.api.promotion.models.StoryContentResponse
import com.tangem.datasource.api.stories.models.StoryContentResponse
import com.tangem.datasource.api.tangemTech.models.*
import com.tangem.datasource.api.tangemTech.models.promobanners.PromoBannerDisplaysResponse
import com.tangem.datasource.api.tangemTech.models.promobanners.DismissPromoBannerRequest

View file

@ -1,8 +1,8 @@
package com.tangem.datasource.di
import com.tangem.datasource.local.datastore.RuntimeDataStore
import com.tangem.datasource.local.promo.DefaultPromoStoriesStore
import com.tangem.datasource.local.promo.PromoStoriesStore
import com.tangem.datasource.local.stories.DefaultStoriesStore
import com.tangem.datasource.local.stories.StoriesStore
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
@ -11,11 +11,11 @@ import javax.inject.Singleton
@Module
@InstallIn(SingletonComponent::class)
object PromoStoreModule {
object StoriesStoreModule {
@Provides
@Singleton
fun providePromoStoriesStore(): PromoStoriesStore {
return DefaultPromoStoriesStore(dataStore = RuntimeDataStore())
fun provideStoriesStore(): StoriesStore {
return DefaultStoriesStore(dataStore = RuntimeDataStore())
}
}

View file

@ -1,12 +1,12 @@
package com.tangem.datasource.local.promo
package com.tangem.datasource.local.stories
import com.tangem.datasource.api.promotion.models.StoryContentResponse
import com.tangem.datasource.api.stories.models.StoryContentResponse
import com.tangem.datasource.local.datastore.core.StringKeyDataStore
import kotlinx.coroutines.flow.Flow
internal class DefaultPromoStoriesStore(
internal class DefaultStoriesStore(
private val dataStore: StringKeyDataStore<StoryContentResponse>,
) : PromoStoriesStore {
) : StoriesStore {
override suspend fun getSyncOrNull(storyId: String): StoryContentResponse? {
return dataStore.getSyncOrNull(storyId)
}

View file

@ -1,9 +1,9 @@
package com.tangem.datasource.local.promo
package com.tangem.datasource.local.stories
import com.tangem.datasource.api.promotion.models.StoryContentResponse
import com.tangem.datasource.api.stories.models.StoryContentResponse
import kotlinx.coroutines.flow.Flow
interface PromoStoriesStore {
interface StoriesStore {
suspend fun getSyncOrNull(storyId: String): StoryContentResponse?
fun get(storyId: String): Flow<StoryContentResponse?>

View file

@ -7,7 +7,7 @@ plugins {
}
android {
namespace = "com.tangem.data.promo"
namespace = "com.tangem.data.stories"
}
dependencies {
@ -16,8 +16,8 @@ dependencies {
implementation(deps.hilt.android)
kapt(deps.hilt.kapt)
implementation(projects.domain.promo)
implementation(projects.domain.promo.models)
implementation(projects.domain.stories)
implementation(projects.domain.stories.models)
api(projects.domain.models)
implementation(projects.domain.wallets.models)
implementation(projects.features.referral.domain)

View file

@ -1,6 +1,6 @@
package com.tangem.data.promo
package com.tangem.data.stories
import com.tangem.data.promo.converters.StoryContentResponseConverter
import com.tangem.data.stories.converters.StoryContentResponseConverter
import com.tangem.datasource.api.common.response.getOrThrow
import com.tangem.datasource.api.tangemTech.TangemTechApi
import com.tangem.datasource.local.preferences.AppPreferencesStore
@ -8,21 +8,21 @@ import com.tangem.datasource.local.preferences.PreferencesKeys
import com.tangem.datasource.local.preferences.utils.get
import com.tangem.datasource.local.preferences.utils.getSyncOrDefault
import com.tangem.datasource.local.preferences.utils.store
import com.tangem.datasource.local.promo.PromoStoriesStore
import com.tangem.domain.promo.PromoRepository
import com.tangem.domain.promo.models.StoryContent
import com.tangem.datasource.local.stories.StoriesStore
import com.tangem.domain.stories.StoriesRepository
import com.tangem.domain.stories.models.StoryContent
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import com.tangem.utils.coroutines.runSuspendCatching
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.withContext
import kotlinx.coroutines.withTimeoutOrNull
internal class DefaultPromoRepository(
internal class DefaultStoriesRepository(
private val tangemApi: TangemTechApi,
private val appPreferencesStore: AppPreferencesStore,
private val promoStoriesStore: PromoStoriesStore,
private val promoStoriesStore: StoriesStore,
private val dispatchers: CoroutineDispatcherProvider,
) : PromoRepository {
) : StoriesRepository {
private val storyContentConverter = StoryContentResponseConverter()

View file

@ -1,7 +1,7 @@
package com.tangem.data.promo.converters
package com.tangem.data.stories.converters
import com.tangem.datasource.api.promotion.models.StoryContentResponse
import com.tangem.domain.promo.models.StoryContent
import com.tangem.datasource.api.stories.models.StoryContentResponse
import com.tangem.domain.stories.models.StoryContent
import com.tangem.utils.converter.Converter
internal class StoryContentResponseConverter : Converter<StoryContentResponse, StoryContent> {

View file

@ -1,10 +1,10 @@
package com.tangem.data.promo.di
package com.tangem.data.stories.di
import com.tangem.data.promo.DefaultPromoRepository
import com.tangem.data.stories.DefaultStoriesRepository
import com.tangem.datasource.api.tangemTech.TangemTechApi
import com.tangem.datasource.local.preferences.AppPreferencesStore
import com.tangem.datasource.local.promo.PromoStoriesStore
import com.tangem.domain.promo.PromoRepository
import com.tangem.datasource.local.stories.StoriesStore
import com.tangem.domain.stories.StoriesRepository
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import dagger.Module
import dagger.Provides
@ -14,17 +14,17 @@ import javax.inject.Singleton
@Module
@InstallIn(SingletonComponent::class)
internal object PromoDataModule {
internal object StoriesDataModule {
@Provides
@Singleton
fun providePromoRepository(
fun provideStoriesRepository(
tangemTechApi: TangemTechApi,
appPreferencesStore: AppPreferencesStore,
promoStoriesStore: PromoStoriesStore,
promoStoriesStore: StoriesStore,
dispatchers: CoroutineDispatcherProvider,
): PromoRepository {
return DefaultPromoRepository(
): StoriesRepository {
return DefaultStoriesRepository(
tangemApi = tangemTechApi,
appPreferencesStore = appPreferencesStore,
promoStoriesStore = promoStoriesStore,

View file

@ -24,7 +24,7 @@ dependencies {
api(projects.domain.walletManager)
api(projects.domain.wallets)
api(projects.domain.wallets.models)
api(projects.domain.promo)
api(projects.domain.stories)
implementation(projects.domain.tokens.models)
implementation(projects.domain.tokens)

View file

@ -19,7 +19,7 @@ dependencies {
api(projects.domain.core)
api(projects.domain.settings)
implementation(deps.kotlin.serialization)
implementation(projects.domain.promo)
implementation(projects.domain.stories)
/** Tests */
testImplementation(deps.test.coroutine)

View file

@ -1,10 +0,0 @@
package com.tangem.domain.promo
import kotlinx.coroutines.flow.Flow
class ShouldShowStoriesUseCase(private val promoRepository: PromoRepository) {
operator fun invoke(storyId: String): Flow<Boolean> = promoRepository.isReadyToShowStories(storyId)
suspend fun invokeSync(storyId: String): Boolean = promoRepository.isReadyToShowStoriesSync(storyId)
suspend fun neverToShow(storyId: String) = promoRepository.setNeverToShowStories(storyId)
}

View file

@ -5,7 +5,7 @@ plugins {
dependencies {
implementation(projects.domain.models)
implementation(projects.domain.promo.models)
implementation(projects.domain.stories.models)
implementation(projects.domain.settings)
implementation(projects.domain.wallets.models)

View file

@ -1,4 +1,4 @@
package com.tangem.domain.promo.models
package com.tangem.domain.stories.models
data class StoryContent(
val imageHost: String,

View file

@ -1,10 +1,10 @@
package com.tangem.domain.promo
package com.tangem.domain.stories
import arrow.core.Either
import arrow.core.left
import arrow.core.right
import com.tangem.domain.promo.models.StoryContent
import com.tangem.domain.promo.models.StoryContentIds
import com.tangem.domain.stories.models.StoryContent
import com.tangem.domain.stories.models.StoryContentIds
import com.tangem.domain.settings.repositories.SettingsRepository
import com.tangem.domain.settings.usercountry.models.needApplyFCARestrictions
import kotlinx.coroutines.FlowPreview
@ -12,7 +12,7 @@ import kotlinx.coroutines.flow.*
import kotlin.time.Duration.Companion.seconds
class GetStoryContentUseCase(
private val promoRepository: PromoRepository,
private val storiesRepository: StoriesRepository,
private val settingsRepository: SettingsRepository,
) {
@ -20,7 +20,7 @@ class GetStoryContentUseCase(
return isFCAAllowed(id).transform { isAllowed ->
if (isAllowed) {
emitAll(
promoRepository.getStoryById(id)
storiesRepository.getStoryById(id)
.map<StoryContent?, Either<Throwable, StoryContent?>> { it.right() }
.catch { emit(it.left()) }
.onEmpty { emit(null.right()) },
@ -34,7 +34,7 @@ class GetStoryContentUseCase(
suspend fun invokeSync(id: String, refresh: Boolean = false): Either<Throwable, StoryContent?> = Either.catch {
val isFCAAllowed = isFCAAllowed(id).firstOrNull() ?: false
return@catch if (isFCAAllowed) {
promoRepository.getStoryByIdSync(id, refresh)
storiesRepository.getStoryByIdSync(id, refresh)
} else {
null
}

View file

@ -0,0 +1,10 @@
package com.tangem.domain.stories
import kotlinx.coroutines.flow.Flow
class ShouldShowStoriesUseCase(private val storiesRepository: StoriesRepository) {
operator fun invoke(storyId: String): Flow<Boolean> = storiesRepository.isReadyToShowStories(storyId)
suspend fun invokeSync(storyId: String): Boolean = storiesRepository.isReadyToShowStoriesSync(storyId)
suspend fun neverToShow(storyId: String) = storiesRepository.setNeverToShowStories(storyId)
}

View file

@ -1,9 +1,9 @@
package com.tangem.domain.promo
package com.tangem.domain.stories
import com.tangem.domain.promo.models.StoryContent
import com.tangem.domain.stories.models.StoryContent
import kotlinx.coroutines.flow.Flow
interface PromoRepository {
interface StoriesRepository {
// region Stories
fun getStoryById(id: String): Flow<StoryContent?>

View file

@ -34,8 +34,8 @@ dependencies {
implementation(projects.domain.settings)
implementation(projects.features.swap.domain.api)
implementation(projects.features.swap.domain.models)
implementation(projects.domain.promo.models)
implementation(projects.domain.promo)
implementation(projects.domain.stories.models)
implementation(projects.domain.stories)
implementation(projects.domain.networks)
implementation(projects.domain.quotes)
implementation(projects.domain.yieldSupply.models)

View file

@ -12,7 +12,7 @@ dependencies {
implementation(projects.domain.models)
implementation(projects.domain.txhistory.models)
implementation(projects.domain.staking.models)
implementation(projects.domain.promo.models)
implementation(projects.domain.stories.models)
/** Other dependencies */
implementation(deps.kotlin.serialization)

View file

@ -6,9 +6,9 @@ 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.promo.PromoRepository
import com.tangem.domain.promo.models.StoryContent
import com.tangem.domain.promo.models.StoryContentIds
import com.tangem.domain.stories.StoriesRepository
import com.tangem.domain.stories.models.StoryContent
import com.tangem.domain.stories.models.StoryContentIds
import com.tangem.domain.staking.model.StakingAvailability
import com.tangem.domain.staking.repositories.StakingRepository
import com.tangem.domain.tokens.actions.CommonActionsFactory
@ -28,14 +28,14 @@ import kotlinx.coroutines.flow.*
* @param rampManager the manager for handling ramp state operations
* @param walletManagersFacade the facade for managing wallet operations
* @property stakingRepository the repository for staking-related data
* @property promoRepository the repository for promotional content
* @property storiesRepository the repository for stories content
* @property dispatchers the coroutine dispatcher provider for managing concurrency
*/
class GetCryptoCurrencyActionsUseCase(
rampManager: RampStateManager,
walletManagersFacade: WalletManagersFacade,
private val stakingRepository: StakingRepository,
private val promoRepository: PromoRepository,
private val storiesRepository: StoriesRepository,
private val dispatchers: CoroutineDispatcherProvider,
) {
@ -127,7 +127,7 @@ class GetCryptoCurrencyActionsUseCase(
}
private fun getSwapStoryContent(): Flow<StoryContent?> {
return promoRepository.getStoryById(StoryContentIds.STORY_FIRST_TIME_SWAP.id)
return storiesRepository.getStoryById(StoryContentIds.STORY_FIRST_TIME_SWAP.id)
.conflate()
.distinctUntilChanged()
}

View file

@ -14,8 +14,8 @@ dependencies {
/** Feature modules */
implementation(projects.features.stories.api)
/** Domain modules */
implementation(projects.domain.promo)
implementation(projects.domain.promo.models)
implementation(projects.domain.stories)
implementation(projects.domain.stories.models)
/** Project - Common */
implementation(projects.common.routing)

View file

@ -1,6 +1,6 @@
package com.tangem.feature.stories.impl
import com.tangem.domain.promo.models.StoryContentIds
import com.tangem.domain.stories.models.StoryContentIds
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf

View file

@ -5,8 +5,8 @@ import com.tangem.core.decompose.model.Model
import com.tangem.core.decompose.model.ParamsContainer
import com.tangem.core.decompose.navigation.Router
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.domain.promo.GetStoryContentUseCase
import com.tangem.domain.promo.ShouldShowStoriesUseCase
import com.tangem.domain.stories.GetStoryContentUseCase
import com.tangem.domain.stories.ShouldShowStoriesUseCase
import com.tangem.feature.stories.api.StoriesComponent
import com.tangem.feature.stories.api.StoriesUM
import com.tangem.feature.stories.impl.StoriesSlideConfigs

View file

@ -54,8 +54,8 @@ dependencies {
implementation(projects.domain.staking)
implementation(projects.domain.feedback)
implementation(projects.domain.feedback.models)
implementation(projects.domain.promo)
implementation(projects.domain.promo.models)
implementation(projects.domain.stories)
implementation(projects.domain.stories.models)
implementation(projects.domain.txhistory)
implementation(projects.domain.txhistory.models)
implementation(projects.domain.express.models)

View file

@ -54,8 +54,8 @@ import com.tangem.domain.models.network.Network
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.domain.pay.WithdrawalResult
import com.tangem.domain.pay.usecase.GetPaymentAccountCryptoCurrencyStatusUseCase
import com.tangem.domain.promo.ShouldShowStoriesUseCase
import com.tangem.domain.promo.models.StoryContentIds
import com.tangem.domain.stories.ShouldShowStoriesUseCase
import com.tangem.domain.stories.models.StoryContentIds
import com.tangem.domain.settings.usercountry.GetUserCountryUseCase
import com.tangem.domain.settings.usercountry.models.UserCountry
import com.tangem.domain.settings.usercountry.models.needApplyFCARestrictions

View file

@ -78,8 +78,8 @@ dependencies {
implementation(projects.domain.offramp)
implementation(projects.domain.onramp)
implementation(projects.domain.onramp.models)
implementation(projects.domain.promo)
implementation(projects.domain.promo.models)
implementation(projects.domain.stories)
implementation(projects.domain.stories.models)
implementation(projects.domain.quotes)
implementation(projects.domain.settings)
implementation(projects.domain.staking)

View file

@ -105,8 +105,8 @@ dependencies {
implementation(projects.domain.offramp)
implementation(projects.domain.onramp)
implementation(projects.domain.onramp.models)
implementation(projects.domain.promo)
implementation(projects.domain.promo.models)
implementation(projects.domain.stories)
implementation(projects.domain.stories.models)
implementation(projects.domain.quotes)
implementation(projects.domain.settings)
implementation(projects.domain.staking)

View file

@ -41,8 +41,8 @@ import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.domain.offramp.GetOfframpUrlUseCase
import com.tangem.domain.onramp.model.OnrampSource
import com.tangem.domain.promo.GetStoryContentUseCase
import com.tangem.domain.promo.models.StoryContentIds
import com.tangem.domain.stories.GetStoryContentUseCase
import com.tangem.domain.stories.models.StoryContentIds
import com.tangem.domain.staking.model.StakingOption
import com.tangem.domain.tokens.NeedShowYieldSupplyDepositedWarningUseCase
import com.tangem.domain.tokens.SaveViewedTokenReceiveWarningUseCase

View file

@ -1,8 +1,8 @@
package com.tangem.feature.wallet.presentation.wallet.subscribers
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.promo.GetStoryContentUseCase
import com.tangem.domain.promo.models.StoryContentIds
import com.tangem.domain.stories.GetStoryContentUseCase
import com.tangem.domain.stories.models.StoryContentIds
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
import com.tangem.feature.wallet.presentation.wallet.state.transformers.UpdateMultiWalletActionButtonBadgeTransformer
import dagger.assisted.Assisted

View file

@ -379,8 +379,8 @@ include(":domain:manage-tokens:models")
include(":domain:onramp")
include(":domain:onramp:models")
include(":domain:offramp")
include(":domain:promo")
include(":domain:promo:models")
include(":domain:stories")
include(":domain:stories:models")
include(":domain:nft")
include(":domain:nft:models")
include(":domain:hot-wallet")
@ -421,7 +421,7 @@ include(":data:transaction")
include(":data:visa")
include(":data:payment")
include(":data:virtual-account")
include(":data:promo")
include(":data:stories")
include(":data:onboarding")
include(":data:dynamic-addresses")
include(":data:feedback")