diff --git a/app/build.gradle.kts b/app/build.gradle.kts index ea77304740..89ca7c3734 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -22,6 +22,7 @@ dependencies { implementation(project(":core:utils")) implementation(project(":libs:crypto")) implementation(project(":libs:auth")) + implementation(project(":data:source:preferences")) /** Features */ implementation(project(":features:onboarding")) diff --git a/app/src/main/java/com/tangem/tap/TapApplication.kt b/app/src/main/java/com/tangem/tap/TapApplication.kt index 58a834e134..ad51eea81f 100644 --- a/app/src/main/java/com/tangem/tap/TapApplication.kt +++ b/app/src/main/java/com/tangem/tap/TapApplication.kt @@ -20,6 +20,7 @@ import com.tangem.datasource.config.models.Config import com.tangem.datasource.connection.NetworkConnectionManager import com.tangem.domain.DomainLayer import com.tangem.domain.common.LogConfig +import com.tangem.data.source.preferences.PreferencesDataSource import com.tangem.tap.common.IntentHandler import com.tangem.tap.common.analytics.AnalyticsFactory import com.tangem.tap.common.analytics.api.AnalyticsHandlerBuilder @@ -51,7 +52,6 @@ import com.tangem.tap.domain.walletStores.repository.di.provideDefaultImplementa import com.tangem.tap.domain.walletconnect.WalletConnectRepository import com.tangem.tap.features.customtoken.api.featuretoggles.CustomTokenFeatureToggles import com.tangem.tap.features.tokens.api.featuretoggles.TokensListFeatureToggles -import com.tangem.tap.persistence.PreferencesStorage import com.tangem.tap.proxy.AppStateHolder import com.tangem.tap.proxy.redux.DaggerGraphState import com.tangem.wallet.BuildConfig @@ -66,7 +66,7 @@ lateinit var store: Store lateinit var foregroundActivityObserver: ForegroundActivityObserver lateinit var activityResultCaller: ActivityResultCaller -lateinit var preferencesStorage: PreferencesStorage +lateinit var preferencesStorage: PreferencesDataSource lateinit var walletConnectRepository: WalletConnectRepository lateinit var shopService: TangemShopService lateinit var userTokensRepository: UserTokensRepository @@ -134,6 +134,9 @@ class TapApplication : Application(), ImageLoaderFactory { @Inject lateinit var customTokenFeatureToggles: CustomTokenFeatureToggles + @Inject + lateinit var preferencesDataSource: PreferencesDataSource + override fun onCreate() { super.onCreate() @@ -161,7 +164,7 @@ class TapApplication : Application(), ImageLoaderFactory { registerActivityLifecycleCallbacks(foregroundActivityObserver.callbacks) DomainLayer.init() - preferencesStorage = PreferencesStorage(this) + preferencesStorage = preferencesDataSource walletConnectRepository = WalletConnectRepository(this) val configLoader = FeaturesLocalLoader(assetReader, MoshiConverter.sdkMoshi, BuildConfig.ENVIRONMENT) @@ -246,7 +249,7 @@ class TapApplication : Application(), ImageLoaderFactory { private fun initFeedbackManager( context: Context, - preferencesStorage: PreferencesStorage, + preferencesStorage: PreferencesDataSource, foregroundActivityObserver: ForegroundActivityObserver, store: Store, ) { diff --git a/app/src/main/java/com/tangem/tap/common/analytics/topup/TopUpController.kt b/app/src/main/java/com/tangem/tap/common/analytics/topup/TopUpController.kt index 30caf9f355..97edaae4c1 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/topup/TopUpController.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/topup/TopUpController.kt @@ -3,9 +3,11 @@ package com.tangem.tap.common.analytics.topup import com.tangem.common.extensions.guard import com.tangem.common.extensions.isZero import com.tangem.core.analytics.Analytics +import com.tangem.data.source.preferences.model.DataSourceTopupInfo +import com.tangem.data.source.preferences.storage.ToppedUpWalletStorage import com.tangem.domain.common.CardTypesResolver -import com.tangem.domain.common.util.cardTypesResolver import com.tangem.domain.common.util.UserWalletId +import com.tangem.domain.common.util.cardTypesResolver import com.tangem.domain.models.scan.ScanResponse import com.tangem.tap.common.analytics.converters.TopUpEventConverter import com.tangem.tap.common.analytics.events.AnalyticsParam @@ -19,7 +21,6 @@ import com.tangem.tap.domain.tokens.models.BlockchainNetwork import com.tangem.tap.domain.walletCurrencies.WalletCurrenciesManager import com.tangem.tap.domain.walletStores.WalletStoresManager import com.tangem.tap.features.wallet.models.Currency -import com.tangem.tap.persistence.ToppedUpWalletStorage import com.tangem.tap.scope import kotlinx.coroutines.launch import java.math.BigDecimal @@ -90,9 +91,9 @@ class TopUpController( val isToppedUpInPast = findToppedUpCurrenciesInPast(walletDataModels).isNotEmpty() if (isToppedUpInPast) { - val newWalletInfo = ToppedUpWalletStorage.TopupInfo( + val newWalletInfo = DataSourceTopupInfo( walletId = userWalletId.stringValue, - cardBalanceState = AnalyticsParam.CardBalanceState.Full, + cardBalanceState = DataSourceTopupInfo.CardBalanceState.Full, ) topupWalletStorage.save(newWalletInfo) return@launch @@ -109,9 +110,9 @@ class TopUpController( fun registerEmptyWallet(scanResponse: ScanResponse) { UserWalletIdBuilder.scanResponse(scanResponse).build()?.let { topupWalletStorage.save( - ToppedUpWalletStorage.TopupInfo( + DataSourceTopupInfo( walletId = it.stringValue, - cardBalanceState = AnalyticsParam.CardBalanceState.Empty, + cardBalanceState = DataSourceTopupInfo.CardBalanceState.Empty, ), ) } @@ -129,17 +130,28 @@ class TopUpController( cardTypesResolver: CardTypesResolver, ) { val topupInfo = topupWalletStorage.restore(userWalletId.stringValue).guard { - val topupInfo = ToppedUpWalletStorage.TopupInfo( + val topupInfo = DataSourceTopupInfo( walletId = userWalletId.stringValue, - cardBalanceState = cardBalanceState, + cardBalanceState = when (cardBalanceState) { + AnalyticsParam.CardBalanceState.BlockchainError -> + DataSourceTopupInfo.CardBalanceState.BlockchainError + AnalyticsParam.CardBalanceState.CustomToken -> + DataSourceTopupInfo.CardBalanceState.CustomToken + AnalyticsParam.CardBalanceState.Empty -> + DataSourceTopupInfo.CardBalanceState.Empty + AnalyticsParam.CardBalanceState.Full -> + DataSourceTopupInfo.CardBalanceState.Full + }, ) topupWalletStorage.save(topupInfo) return } - if (topupInfo.isToppedUp) return - if (!topupInfo.isToppedUp && cardBalanceState.isToppedUp()) { - topupWalletStorage.save(topupInfo.copy(cardBalanceState = AnalyticsParam.CardBalanceState.Full)) + val isToppedUp = topupInfo.cardBalanceState == DataSourceTopupInfo.CardBalanceState.Full + if (isToppedUp) return + + if (cardBalanceState.isToppedUp()) { + topupWalletStorage.save(topupInfo.copy(cardBalanceState = DataSourceTopupInfo.CardBalanceState.Full)) TopUpEventConverter().convert(cardTypesResolver)?.let { Analytics.send(it) } diff --git a/app/src/main/java/com/tangem/tap/common/chat/ChatManager.kt b/app/src/main/java/com/tangem/tap/common/chat/ChatManager.kt index bc69217fa1..182aa7350b 100644 --- a/app/src/main/java/com/tangem/tap/common/chat/ChatManager.kt +++ b/app/src/main/java/com/tangem/tap/common/chat/ChatManager.kt @@ -2,19 +2,19 @@ package com.tangem.tap.common.chat import android.content.Context import android.os.Build -import com.tangem.tap.ForegroundActivityObserver import com.tangem.datasource.config.models.ChatConfig -import com.tangem.tap.common.chat.opener.ChatOpener import com.tangem.datasource.config.models.SprinklrConfig import com.tangem.datasource.config.models.ZendeskConfig +import com.tangem.data.source.preferences.PreferencesDataSource +import com.tangem.tap.ForegroundActivityObserver +import com.tangem.tap.common.chat.opener.ChatOpener import com.tangem.tap.common.chat.opener.implementation.SprinklrChatOpener import com.tangem.tap.common.chat.opener.implementation.ZendeskChatOpener import com.tangem.tap.common.redux.AppState -import com.tangem.tap.persistence.PreferencesStorage import org.rekotlin.Store class ChatManager( - private val preferencesStorage: PreferencesStorage, + private val preferencesStorage: PreferencesDataSource, private val foregroundActivityObserver: ForegroundActivityObserver, private val store: Store, ) { diff --git a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalMiddleware.kt b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalMiddleware.kt index 39d29a451f..01d00c9a82 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalMiddleware.kt @@ -5,11 +5,12 @@ import com.tangem.common.core.TangemSdkError import com.tangem.common.extensions.guard import com.tangem.datasource.config.models.Config import com.tangem.domain.common.LogConfig -import com.tangem.domain.common.util.cardTypesResolver import com.tangem.domain.common.extensions.withMainContext +import com.tangem.domain.common.util.cardTypesResolver import com.tangem.domain.models.scan.CardDTO import com.tangem.domain.models.scan.ProductType import com.tangem.domain.models.scan.ScanResponse +import com.tangem.tap.common.entities.FiatCurrency import com.tangem.tap.common.extensions.dispatchDebugErrorNotification import com.tangem.tap.common.extensions.dispatchDialogShow import com.tangem.tap.common.extensions.dispatchOnMain @@ -75,7 +76,9 @@ private fun handleAction(action: Action, appState: () -> AppState?, dispatch: Di is GlobalAction.RestoreAppCurrency -> { store.dispatch( GlobalAction.RestoreAppCurrency.Success( - preferencesStorage.fiatCurrenciesPrefStorage.getAppCurrency(), + preferencesStorage.fiatCurrenciesPrefStorage.getAppCurrency() + ?.run { FiatCurrency(code, name, symbol) } + ?: FiatCurrency.Default, ), ) } diff --git a/app/src/main/java/com/tangem/tap/domain/tasks/product/ScanProductTask.kt b/app/src/main/java/com/tangem/tap/domain/tasks/product/ScanProductTask.kt index 8f7fe94bac..86c7ecc477 100644 --- a/app/src/main/java/com/tangem/tap/domain/tasks/product/ScanProductTask.kt +++ b/app/src/main/java/com/tangem/tap/domain/tasks/product/ScanProductTask.kt @@ -19,9 +19,6 @@ import com.tangem.common.tlv.Tlv import com.tangem.common.tlv.TlvDecoder import com.tangem.crypto.CryptoUtils import com.tangem.crypto.hdWallet.DerivationPath -import com.tangem.domain.models.scan.CardDTO -import com.tangem.domain.models.scan.ProductType -import com.tangem.domain.models.scan.ScanResponse import com.tangem.domain.common.TapWorkarounds.isExcluded import com.tangem.domain.common.TapWorkarounds.isNotSupportedInThatRelease import com.tangem.domain.common.TapWorkarounds.isSaltPay @@ -29,6 +26,9 @@ import com.tangem.domain.common.TapWorkarounds.isStart2Coin import com.tangem.domain.common.TapWorkarounds.isTangemTwins import com.tangem.domain.common.TapWorkarounds.useOldStyleDerivation import com.tangem.domain.common.TwinsHelper +import com.tangem.domain.models.scan.CardDTO +import com.tangem.domain.models.scan.ProductType +import com.tangem.domain.models.scan.ScanResponse import com.tangem.operations.PreflightReadMode import com.tangem.operations.PreflightReadTask import com.tangem.operations.ScanTask diff --git a/app/src/main/java/com/tangem/tap/features/disclaimer/DisclaimerDataProvider.kt b/app/src/main/java/com/tangem/tap/features/disclaimer/DisclaimerDataProvider.kt index 0097f34142..9d3b4aeda6 100644 --- a/app/src/main/java/com/tangem/tap/features/disclaimer/DisclaimerDataProvider.kt +++ b/app/src/main/java/com/tangem/tap/features/disclaimer/DisclaimerDataProvider.kt @@ -1,6 +1,6 @@ package com.tangem.tap.features.disclaimer -import com.tangem.tap.persistence.DisclaimerPrefStorage +import com.tangem.data.source.preferences.storage.DisclaimerPrefStorage /** [REDACTED_AUTHOR] diff --git a/app/src/main/java/com/tangem/tap/features/disclaimer/DisclaimerType.kt b/app/src/main/java/com/tangem/tap/features/disclaimer/DisclaimerType.kt index 30b3f43d1c..56519de4ff 100644 --- a/app/src/main/java/com/tangem/tap/features/disclaimer/DisclaimerType.kt +++ b/app/src/main/java/com/tangem/tap/features/disclaimer/DisclaimerType.kt @@ -1,11 +1,11 @@ package com.tangem.tap.features.disclaimer -import com.tangem.domain.models.scan.CardDTO import com.tangem.domain.common.TapWorkarounds.isSaltPay import com.tangem.domain.common.TapWorkarounds.isStart2Coin -import com.tangem.tap.persistence.DisclaimerPrefStorage +import com.tangem.domain.models.scan.CardDTO +import com.tangem.data.source.preferences.storage.DisclaimerPrefStorage import com.tangem.tap.preferencesStorage -import java.util.* +import java.util.Locale /** [REDACTED_AUTHOR] diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingManager.kt b/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingManager.kt index e35aa85d7a..bf80a5b458 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingManager.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingManager.kt @@ -15,7 +15,7 @@ import com.tangem.tap.domain.extensions.getOrLoadCardArtworkUrl import com.tangem.tap.features.wallet.models.Currency import com.tangem.tap.features.wallet.models.hasPendingTransactions import com.tangem.tap.features.wallet.redux.ProgressState -import com.tangem.tap.persistence.UsedCardsPrefStorage +import com.tangem.data.source.preferences.storage.UsedCardsPrefStorage import timber.log.Timber import java.math.BigDecimal diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/AppCurrencyMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/AppCurrencyMiddleware.kt index cabb464853..bc5e960649 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/AppCurrencyMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/AppCurrencyMiddleware.kt @@ -2,7 +2,9 @@ package com.tangem.tap.features.wallet.redux.middlewares import com.tangem.common.extensions.guard import com.tangem.core.analytics.Analytics -import com.tangem.datasource.api.tangemTech.models.CurrenciesResponse +import com.tangem.data.source.preferences.model.DataSourceCurrency +import com.tangem.data.source.preferences.model.DataSourceFiatCurrency +import com.tangem.data.source.preferences.storage.FiatCurrenciesPrefStorage import com.tangem.tap.common.analytics.events.AnalyticsParam import com.tangem.tap.common.analytics.events.MainScreen import com.tangem.tap.common.entities.FiatCurrency @@ -14,7 +16,6 @@ import com.tangem.tap.features.wallet.domain.WalletRepository import com.tangem.tap.features.wallet.redux.WalletAction import com.tangem.tap.features.wallet.redux.models.WalletDialog import com.tangem.tap.features.walletSelector.redux.WalletSelectorAction -import com.tangem.tap.persistence.FiatCurrenciesPrefStorage import com.tangem.tap.scope import com.tangem.tap.store import com.tangem.tap.userWalletsListManager @@ -47,8 +48,10 @@ class AppCurrencyMiddleware( scope.launch { runCatching { walletRepository.getCurrencyList() } - .onSuccess { - val currenciesList = it.currencies + .onSuccess { response -> + val currenciesList = response.currencies + .map { with(it) { DataSourceCurrency(id, code, name, rateBTC, unit, type) } } + if (currenciesList.isNotEmpty() && currenciesList.toSet() != storedFiatCurrencies.toSet()) { fiatCurrenciesPrefStorage.save(currenciesList) store.dispatchDialogShow( @@ -64,7 +67,9 @@ class AppCurrencyMiddleware( private fun selectCurrency(action: WalletAction.AppCurrencyAction.SelectAppCurrency) { Analytics.send(MainScreen.MainCurrencyChanged(AnalyticsParam.CurrencyType.FiatCurrency(action.fiatCurrency))) - fiatCurrenciesPrefStorage.saveAppCurrency(action.fiatCurrency) + fiatCurrenciesPrefStorage.saveAppCurrency( + with(action.fiatCurrency) { DataSourceFiatCurrency(code, name, symbol) }, + ) store.dispatch(GlobalAction.ChangeAppCurrency(action.fiatCurrency)) store.dispatch(DetailsAction.ChangeAppCurrency(action.fiatCurrency)) store.dispatch(WalletSelectorAction.ChangeAppCurrency(action.fiatCurrency)) @@ -77,7 +82,7 @@ class AppCurrencyMiddleware( } } - private fun List.mapToUiModel(): List { + private fun List.mapToUiModel(): List { return this.map { FiatCurrency( code = it.code, diff --git a/app/src/main/java/com/tangem/tap/persistence/CardBalanceStateAdapter.kt b/app/src/main/java/com/tangem/tap/persistence/CardBalanceStateAdapter.kt deleted file mode 100644 index 0385071ff3..0000000000 --- a/app/src/main/java/com/tangem/tap/persistence/CardBalanceStateAdapter.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.tangem.tap.persistence - -import com.squareup.moshi.FromJson -import com.squareup.moshi.ToJson -import com.tangem.tap.common.analytics.events.AnalyticsParam - -class CardBalanceStateAdapter { - - @ToJson - fun toJson(src: AnalyticsParam.CardBalanceState): String = src.value - - @FromJson - fun fromJson(json: String): AnalyticsParam.CardBalanceState { - return when (json) { - AnalyticsParam.CardBalanceState.Empty.value -> AnalyticsParam.CardBalanceState.Empty - AnalyticsParam.CardBalanceState.Full.value -> AnalyticsParam.CardBalanceState.Full - else -> error("CardBalanceState not found") - } - } -} \ No newline at end of file diff --git a/data/source/preferences/.gitignore b/data/source/preferences/.gitignore new file mode 100644 index 0000000000..796b96d1c4 --- /dev/null +++ b/data/source/preferences/.gitignore @@ -0,0 +1 @@ +/build diff --git a/data/source/preferences/build.gradle.kts b/data/source/preferences/build.gradle.kts new file mode 100644 index 0000000000..7cd9e54515 --- /dev/null +++ b/data/source/preferences/build.gradle.kts @@ -0,0 +1,17 @@ +plugins { + alias(deps.plugins.kotlin.android) + alias(deps.plugins.kotlin.kapt) + alias(deps.plugins.android.library) + id("configuration") +} + +dependencies { + implementation(deps.androidx.core.ktx) + implementation(deps.moshi) + implementation(deps.moshi.kotlin) + implementation(deps.hilt.android) + kapt(deps.hilt.kapt) + + // For MoshiJsonConverter + implementation(deps.tangem.card.core) +} \ No newline at end of file diff --git a/data/source/preferences/src/main/AndroidManifest.xml b/data/source/preferences/src/main/AndroidManifest.xml new file mode 100644 index 0000000000..67568f1b9e --- /dev/null +++ b/data/source/preferences/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + + diff --git a/data/source/preferences/src/main/kotlin/com/tangem/data/source/preferences/AppRatingLaunchObserver.kt b/data/source/preferences/src/main/kotlin/com/tangem/data/source/preferences/AppRatingLaunchObserver.kt new file mode 100644 index 0000000000..d65eb3813b --- /dev/null +++ b/data/source/preferences/src/main/kotlin/com/tangem/data/source/preferences/AppRatingLaunchObserver.kt @@ -0,0 +1,73 @@ +package com.tangem.data.source.preferences + +import android.content.SharedPreferences +import androidx.core.content.edit +import java.util.* + +@Deprecated("Create repository instead") +class AppRatingLaunchObserver internal constructor( + private val preferences: SharedPreferences, + private val launchCounts: Int, +) { + + private val deferShowing = 20 + private val firstShowing = 3 + private var fundsFoundDate: Calendar? = null + + init { + val msWhenFundsWasFound = preferences.getLong(K_FUNDS_FOUND_DATE, FUNDS_FOUND_DATE_UNDEFINED) + if (msWhenFundsWasFound != FUNDS_FOUND_DATE_UNDEFINED) { + fundsFoundDate = Calendar.getInstance().apply { timeInMillis = msWhenFundsWasFound } + } + } + + fun foundWalletWithFunds() { + if (fundsFoundDate != null) return + + fundsFoundDate = Calendar.getInstance() + preferences.edit(true) { + putLong(K_FUNDS_FOUND_DATE, fundsFoundDate!!.timeInMillis).apply() + putInt(K_SHOW_RATING_AT_LAUNCH_COUNT, launchCounts + firstShowing) + } + } + + fun isReadyToShow(): Boolean { + val fundsDate = fundsFoundDate ?: return false + + if (!userWasInteractWithRating()) { + val diff = Calendar.getInstance().timeInMillis - fundsDate.timeInMillis + val diffInDays = diff / DAY_MILLIS + return launchCounts >= getCounterOfNextShowing() && diffInDays >= firstShowing + } + + val nextShowing = getCounterOfNextShowing() + return launchCounts >= nextShowing + } + + fun applyDelayedShowing() { + updateNextShowing(launchCounts + deferShowing) + } + + fun setNeverToShow() { + updateNextShowing(Int.MAX_VALUE) + } + + private fun updateNextShowing(at: Int) { + val editor = preferences.edit() + editor.putInt(K_SHOW_RATING_AT_LAUNCH_COUNT, at) + editor.putBoolean(K_USER_WAS_INTERACT_WITH_RATING, true) + editor.apply() + } + + private fun userWasInteractWithRating(): Boolean = preferences.getBoolean(K_USER_WAS_INTERACT_WITH_RATING, false) + + private fun getCounterOfNextShowing(): Int = preferences.getInt(K_SHOW_RATING_AT_LAUNCH_COUNT, firstShowing) + + companion object { + private const val K_SHOW_RATING_AT_LAUNCH_COUNT = "showRatingDialogAtLaunchCount" + private const val K_FUNDS_FOUND_DATE = "fundsFoundDate" + private const val K_USER_WAS_INTERACT_WITH_RATING = "userWasInteractWithRating" + private const val FUNDS_FOUND_DATE_UNDEFINED = -1L + private const val DAY_MILLIS = 1000 * 60 * 60 * 24 + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/persistence/PreferencesStorage.kt b/data/source/preferences/src/main/kotlin/com/tangem/data/source/preferences/PreferencesDataSource.kt similarity index 60% rename from app/src/main/java/com/tangem/tap/persistence/PreferencesStorage.kt rename to data/source/preferences/src/main/kotlin/com/tangem/data/source/preferences/PreferencesDataSource.kt index 5a2fddd325..ec8b43876b 100644 --- a/app/src/main/java/com/tangem/tap/persistence/PreferencesStorage.kt +++ b/data/source/preferences/src/main/kotlin/com/tangem/data/source/preferences/PreferencesDataSource.kt @@ -1,14 +1,21 @@ -package com.tangem.tap.persistence +package com.tangem.data.source.preferences -import android.app.Application import android.content.Context import android.content.SharedPreferences import androidx.core.content.edit import com.tangem.common.json.MoshiJsonConverter -import com.tangem.datasource.api.common.BigDecimalAdapter -import java.util.* +import com.tangem.data.source.preferences.adapters.BigDecimalAdapter +import com.tangem.data.source.preferences.adapters.CardBalanceStateAdapter +import com.tangem.data.source.preferences.storage.DisclaimerPrefStorage +import com.tangem.data.source.preferences.storage.FiatCurrenciesPrefStorage +import com.tangem.data.source.preferences.storage.ToppedUpWalletStorage +import com.tangem.data.source.preferences.storage.UsedCardsPrefStorage +import javax.inject.Inject -class PreferencesStorage(applicationContext: Application) { +// 🔥FIXME: Only logic to work with preferences must be here, must be separated to repositories +// TODO: Replace shared preferences with DataStore +@Deprecated("Create repository instead") +class PreferencesDataSource @Inject internal constructor(applicationContext: Context) { val appRatingLaunchObserver: AppRatingLaunchObserver val usedCardsPrefStorage: UsedCardsPrefStorage @@ -73,8 +80,6 @@ class PreferencesStorage(applicationContext: Application) { putBoolean(OPEN_WELCOME_ON_RESUME_KEY, value) } - fun getCountOfLaunches(): Int = preferences.getInt(APP_LAUNCH_COUNT_KEY, 1) - fun saveTwinsOnboardingShown() { preferences.edit { putBoolean(TWINS_ONBOARDING_SHOWN_KEY, true) } } @@ -83,6 +88,8 @@ class PreferencesStorage(applicationContext: Application) { return preferences.getBoolean(TWINS_ONBOARDING_SHOWN_KEY, false) } + private fun getCountOfLaunches(): Int = preferences.getInt(APP_LAUNCH_COUNT_KEY, 1) + private fun incrementLaunchCounter() { var count = preferences.getInt(APP_LAUNCH_COUNT_KEY, 0) preferences.edit { putInt(APP_LAUNCH_COUNT_KEY, ++count) } @@ -100,72 +107,4 @@ class PreferencesStorage(applicationContext: Application) { private const val APPLICATION_STOPPED_KEY = "applicationStopped" private const val OPEN_WELCOME_ON_RESUME_KEY = "openWelcomeOnResume" } -} - -class AppRatingLaunchObserver( - private val preferences: SharedPreferences, - private val launchCounts: Int, -) { - - private val deferShowing = 20 - private val firstShowing = 3 - private var fundsFoundDate: Calendar? = null - - init { - val msWhenFundsWasFound = preferences.getLong(K_FUNDS_FOUND_DATE, FUNDS_FOUND_DATE_UNDEFINED) - if (msWhenFundsWasFound != FUNDS_FOUND_DATE_UNDEFINED) { - fundsFoundDate = Calendar.getInstance().apply { timeInMillis = msWhenFundsWasFound } - } - } - - fun foundWalletWithFunds() { - if (fundsFoundDate != null) return - - fundsFoundDate = Calendar.getInstance() - preferences.edit(true) { - putLong(K_FUNDS_FOUND_DATE, fundsFoundDate!!.timeInMillis).apply() - putInt(K_SHOW_RATING_AT_LAUNCH_COUNT, launchCounts + firstShowing) - } - } - - @Suppress("MagicNumber") - fun isReadyToShow(): Boolean { - val fundsDate = fundsFoundDate ?: return false - - if (!userWasInteractWithRating()) { - val diff = Calendar.getInstance().timeInMillis - fundsDate.timeInMillis - val diffInDays = diff / (1000 * 60 * 60 * 24) - return launchCounts >= getCounterOfNextShowing() && diffInDays >= firstShowing - } - - val nextShowing = getCounterOfNextShowing() - return launchCounts >= nextShowing - } - - fun applyDelayedShowing() { - updateNextShowing(launchCounts + deferShowing) - } - - @Suppress("MagicNumber") - fun setNeverToShow() { - updateNextShowing(999999999) - } - - private fun updateNextShowing(at: Int) { - val editor = preferences.edit() - editor.putInt(K_SHOW_RATING_AT_LAUNCH_COUNT, at) - editor.putBoolean(K_USER_WAS_INTERACT_WITH_RATING, true) - editor.apply() - } - - private fun userWasInteractWithRating(): Boolean = preferences.getBoolean(K_USER_WAS_INTERACT_WITH_RATING, false) - - private fun getCounterOfNextShowing(): Int = preferences.getInt(K_SHOW_RATING_AT_LAUNCH_COUNT, firstShowing) - - companion object { - private const val K_SHOW_RATING_AT_LAUNCH_COUNT = "showRatingDialogAtLaunchCount" - private const val K_FUNDS_FOUND_DATE = "fundsFoundDate" - private const val K_USER_WAS_INTERACT_WITH_RATING = "userWasInteractWithRating" - private const val FUNDS_FOUND_DATE_UNDEFINED = -1L - } } \ No newline at end of file diff --git a/data/source/preferences/src/main/kotlin/com/tangem/data/source/preferences/adapters/BigDecimalAdapter.kt b/data/source/preferences/src/main/kotlin/com/tangem/data/source/preferences/adapters/BigDecimalAdapter.kt new file mode 100644 index 0000000000..d2adc38e1d --- /dev/null +++ b/data/source/preferences/src/main/kotlin/com/tangem/data/source/preferences/adapters/BigDecimalAdapter.kt @@ -0,0 +1,13 @@ +package com.tangem.data.source.preferences.adapters + +import com.squareup.moshi.FromJson +import com.squareup.moshi.ToJson +import java.math.BigDecimal + +class BigDecimalAdapter { + @FromJson + fun fromJson(value: String) = BigDecimal(value) + + @ToJson + fun toJson(value: BigDecimal) = value.toString() +} \ No newline at end of file diff --git a/data/source/preferences/src/main/kotlin/com/tangem/data/source/preferences/adapters/CardBalanceStateAdapter.kt b/data/source/preferences/src/main/kotlin/com/tangem/data/source/preferences/adapters/CardBalanceStateAdapter.kt new file mode 100644 index 0000000000..6f9ca6f810 --- /dev/null +++ b/data/source/preferences/src/main/kotlin/com/tangem/data/source/preferences/adapters/CardBalanceStateAdapter.kt @@ -0,0 +1,20 @@ +package com.tangem.data.source.preferences.adapters + +import com.squareup.moshi.FromJson +import com.squareup.moshi.ToJson +import com.tangem.data.source.preferences.model.DataSourceTopupInfo + +class CardBalanceStateAdapter { + + @ToJson + fun toJson(src: DataSourceTopupInfo.CardBalanceState): String = src.serializedName + + @FromJson + fun fromJson(json: String): DataSourceTopupInfo.CardBalanceState { + return when (json) { + DataSourceTopupInfo.CardBalanceState.Empty.serializedName -> DataSourceTopupInfo.CardBalanceState.Empty + DataSourceTopupInfo.CardBalanceState.Full.serializedName -> DataSourceTopupInfo.CardBalanceState.Full + else -> error("CardBalanceState not found") + } + } +} \ No newline at end of file diff --git a/data/source/preferences/src/main/kotlin/com/tangem/data/source/preferences/di/PreferencesStoreModule.kt b/data/source/preferences/src/main/kotlin/com/tangem/data/source/preferences/di/PreferencesStoreModule.kt new file mode 100644 index 0000000000..5961efde84 --- /dev/null +++ b/data/source/preferences/src/main/kotlin/com/tangem/data/source/preferences/di/PreferencesStoreModule.kt @@ -0,0 +1,19 @@ +package com.tangem.data.source.preferences.di + +import android.content.Context +import com.tangem.data.source.preferences.PreferencesDataSource +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.android.qualifiers.ApplicationContext +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +internal object PreferencesStoreModule { + + @Provides + @Singleton + fun providePreferencesStore(@ApplicationContext context: Context) = PreferencesDataSource(context) +} \ No newline at end of file diff --git a/data/source/preferences/src/main/kotlin/com/tangem/data/source/preferences/model/DataSourceCurrency.kt b/data/source/preferences/src/main/kotlin/com/tangem/data/source/preferences/model/DataSourceCurrency.kt new file mode 100644 index 0000000000..3a2efbcd50 --- /dev/null +++ b/data/source/preferences/src/main/kotlin/com/tangem/data/source/preferences/model/DataSourceCurrency.kt @@ -0,0 +1,10 @@ +package com.tangem.data.source.preferences.model + +data class DataSourceCurrency( + val id: String, + val code: String, + val name: String, + val rateBTC: String, + val unit: String, + val type: String, +) \ No newline at end of file diff --git a/data/source/preferences/src/main/kotlin/com/tangem/data/source/preferences/model/DataSourceFiatCurrency.kt b/data/source/preferences/src/main/kotlin/com/tangem/data/source/preferences/model/DataSourceFiatCurrency.kt new file mode 100644 index 0000000000..9497c85988 --- /dev/null +++ b/data/source/preferences/src/main/kotlin/com/tangem/data/source/preferences/model/DataSourceFiatCurrency.kt @@ -0,0 +1,7 @@ +package com.tangem.data.source.preferences.model + +data class DataSourceFiatCurrency( + val code: String, + val name: String, + val symbol: String, +) \ No newline at end of file diff --git a/data/source/preferences/src/main/kotlin/com/tangem/data/source/preferences/model/DataSourceTopupInfo.kt b/data/source/preferences/src/main/kotlin/com/tangem/data/source/preferences/model/DataSourceTopupInfo.kt new file mode 100644 index 0000000000..0088d25b3e --- /dev/null +++ b/data/source/preferences/src/main/kotlin/com/tangem/data/source/preferences/model/DataSourceTopupInfo.kt @@ -0,0 +1,13 @@ +package com.tangem.data.source.preferences.model + +data class DataSourceTopupInfo( + val walletId: String, + val cardBalanceState: CardBalanceState, +) { + enum class CardBalanceState(val serializedName: String) { + Empty(serializedName = "Empty"), + Full(serializedName = "Full"), + CustomToken(serializedName = "Custom token"), + BlockchainError(serializedName = "Blockchain error"), + } +} \ No newline at end of file diff --git a/data/source/preferences/src/main/kotlin/com/tangem/data/source/preferences/model/DataSourceUsedCardInfo.kt b/data/source/preferences/src/main/kotlin/com/tangem/data/source/preferences/model/DataSourceUsedCardInfo.kt new file mode 100644 index 0000000000..d05eadc7ca --- /dev/null +++ b/data/source/preferences/src/main/kotlin/com/tangem/data/source/preferences/model/DataSourceUsedCardInfo.kt @@ -0,0 +1,8 @@ +package com.tangem.data.source.preferences.model + +internal data class DataSourceUsedCardInfo( + val cardId: String, + val isScanned: Boolean = false, + val isActivationStarted: Boolean = false, + val isActivationFinished: Boolean = false, +) \ No newline at end of file diff --git a/data/source/preferences/src/main/kotlin/com/tangem/data/source/preferences/model/DataSourceUsedCardInfoOld.kt b/data/source/preferences/src/main/kotlin/com/tangem/data/source/preferences/model/DataSourceUsedCardInfoOld.kt new file mode 100644 index 0000000000..ee01e6752a --- /dev/null +++ b/data/source/preferences/src/main/kotlin/com/tangem/data/source/preferences/model/DataSourceUsedCardInfoOld.kt @@ -0,0 +1,7 @@ +package com.tangem.data.source.preferences.model + +internal data class DataSourceUsedCardInfoOld( + val cardId: String, + val isScanned: Boolean = false, + val isActivationStarted: Boolean = false, +) \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/persistence/DisclaimerPrefStorage.kt b/data/source/preferences/src/main/kotlin/com/tangem/data/source/preferences/storage/DisclaimerPrefStorage.kt similarity index 73% rename from app/src/main/java/com/tangem/tap/persistence/DisclaimerPrefStorage.kt rename to data/source/preferences/src/main/kotlin/com/tangem/data/source/preferences/storage/DisclaimerPrefStorage.kt index 34dbf530a3..e91fb9e27c 100644 --- a/app/src/main/java/com/tangem/tap/persistence/DisclaimerPrefStorage.kt +++ b/data/source/preferences/src/main/kotlin/com/tangem/data/source/preferences/storage/DisclaimerPrefStorage.kt @@ -1,4 +1,4 @@ -package com.tangem.tap.persistence +package com.tangem.data.source.preferences.storage import android.content.SharedPreferences import androidx.core.content.edit @@ -6,7 +6,8 @@ import androidx.core.content.edit /** [REDACTED_AUTHOR] */ -class DisclaimerPrefStorage( +@Deprecated("Create repository instead") +class DisclaimerPrefStorage internal constructor( private val preferences: SharedPreferences, ) { diff --git a/app/src/main/java/com/tangem/tap/persistence/FiatCurrenciesPrefStorage.kt b/data/source/preferences/src/main/kotlin/com/tangem/data/source/preferences/storage/FiatCurrenciesPrefStorage.kt similarity index 65% rename from app/src/main/java/com/tangem/tap/persistence/FiatCurrenciesPrefStorage.kt rename to data/source/preferences/src/main/kotlin/com/tangem/data/source/preferences/storage/FiatCurrenciesPrefStorage.kt index a52f38f854..e30fdbbe48 100644 --- a/app/src/main/java/com/tangem/tap/persistence/FiatCurrenciesPrefStorage.kt +++ b/data/source/preferences/src/main/kotlin/com/tangem/data/source/preferences/storage/FiatCurrenciesPrefStorage.kt @@ -1,15 +1,16 @@ -package com.tangem.tap.persistence +package com.tangem.data.source.preferences.storage import android.content.SharedPreferences import androidx.core.content.edit import com.tangem.common.json.MoshiJsonConverter -import com.tangem.datasource.api.tangemTech.models.CurrenciesResponse -import com.tangem.tap.common.entities.FiatCurrency +import com.tangem.data.source.preferences.model.DataSourceCurrency +import com.tangem.data.source.preferences.model.DataSourceFiatCurrency /** [REDACTED_AUTHOR] */ -class FiatCurrenciesPrefStorage( +@Deprecated("Create repository instead") +class FiatCurrenciesPrefStorage internal constructor( private val preferences: SharedPreferences, private val converter: MoshiJsonConverter, ) { @@ -20,26 +21,26 @@ class FiatCurrenciesPrefStorage( } } - fun getAppCurrency(): FiatCurrency { + fun getAppCurrency(): DataSourceFiatCurrency? { val json = preferences.getString(APP_CURRENCY_KEY, "") - if (json.isNullOrBlank()) return FiatCurrency.Default + if (json.isNullOrBlank()) return null - return converter.fromJson(json) ?: FiatCurrency.Default + return converter.fromJson(json) } - fun saveAppCurrency(fiatCurrency: FiatCurrency) { + fun saveAppCurrency(fiatCurrency: DataSourceFiatCurrency) { val json = converter.toJson(fiatCurrency) preferences.edit { putString(APP_CURRENCY_KEY, json) } } - fun save(currencies: List) { + fun save(currencies: List) { val json: String = converter.toJson(currencies) return preferences.edit().putString(FIAT_CURRENCIES_KEY, json).apply() } - fun restore(): List { + fun restore(): List { val json = preferences.getString(FIAT_CURRENCIES_KEY, "") - val type = converter.typedList(CurrenciesResponse.Currency::class.java) + val type = converter.typedList(DataSourceCurrency::class.java) if (json.isNullOrBlank()) return emptyList() return converter.fromJson(json, type) ?: emptyList() diff --git a/data/source/preferences/src/main/kotlin/com/tangem/data/source/preferences/storage/Migration.kt b/data/source/preferences/src/main/kotlin/com/tangem/data/source/preferences/storage/Migration.kt new file mode 100644 index 0000000000..e1cc25e4ba --- /dev/null +++ b/data/source/preferences/src/main/kotlin/com/tangem/data/source/preferences/storage/Migration.kt @@ -0,0 +1,5 @@ +package com.tangem.data.source.preferences.storage + +internal interface Migration { + fun migrate() +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/persistence/ToppedUpWalletStorage.kt b/data/source/preferences/src/main/kotlin/com/tangem/data/source/preferences/storage/ToppedUpWalletStorage.kt similarity index 56% rename from app/src/main/java/com/tangem/tap/persistence/ToppedUpWalletStorage.kt rename to data/source/preferences/src/main/kotlin/com/tangem/data/source/preferences/storage/ToppedUpWalletStorage.kt index 892b1a2370..14b1e77b7f 100644 --- a/app/src/main/java/com/tangem/tap/persistence/ToppedUpWalletStorage.kt +++ b/data/source/preferences/src/main/kotlin/com/tangem/data/source/preferences/storage/ToppedUpWalletStorage.kt @@ -1,51 +1,50 @@ -package com.tangem.tap.persistence +package com.tangem.data.source.preferences.storage import android.content.SharedPreferences import androidx.core.content.edit import com.tangem.common.json.MoshiJsonConverter -import com.tangem.tap.common.analytics.events.AnalyticsParam -import timber.log.Timber +import com.tangem.data.source.preferences.model.DataSourceTopupInfo /** [REDACTED_AUTHOR] */ -class ToppedUpWalletStorage( +@Deprecated("Create repository instead") +class ToppedUpWalletStorage internal constructor( private val preferences: SharedPreferences, private val jsonConverter: MoshiJsonConverter, ) { - private val walletList: MutableSet = mutableSetOf() + private val walletList: MutableSet = mutableSetOf() init { walletList.addAll(restore()) } - fun save(userWalletInfo: TopupInfo): Boolean { + fun save(userWalletInfo: DataSourceTopupInfo): Boolean { walletList.removeAll { it.walletId == userWalletInfo.walletId } walletList.add(userWalletInfo) return save(walletList) } - fun restore(walletId: String): TopupInfo? { + fun restore(walletId: String): DataSourceTopupInfo? { return walletList.firstOrNull { it.walletId == walletId } } - private fun save(userWallets: MutableSet): Boolean { + private fun save(userWallets: MutableSet): Boolean { return try { val json = jsonConverter.toJson(userWallets) preferences.edit(true) { putString(KEY, json) } true } catch (ex: Exception) { - Timber.e(ex) false } } - private fun restore(): MutableSet { + private fun restore(): MutableSet { val json = preferences.getString(KEY, null) ?: return mutableSetOf() return try { - val typedList = jsonConverter.typedList(TopupInfo::class.java) - val listData = jsonConverter.fromJson>(json, typedList)!! + val typedList = jsonConverter.typedList(DataSourceTopupInfo::class.java) + val listData = jsonConverter.fromJson>(json, typedList)!! listData.toMutableSet() } catch (ex: Exception) { preferences.edit(true) { remove(KEY) } @@ -53,13 +52,6 @@ class ToppedUpWalletStorage( } } - data class TopupInfo( - val walletId: String, - val cardBalanceState: AnalyticsParam.CardBalanceState, - ) { - val isToppedUp: Boolean = cardBalanceState == AnalyticsParam.CardBalanceState.Full - } - companion object { private const val KEY = "userWalletsInfo" } diff --git a/app/src/main/java/com/tangem/tap/persistence/UsedCardsPrefStorage.kt b/data/source/preferences/src/main/kotlin/com/tangem/data/source/preferences/storage/UsedCardsPrefStorage.kt similarity index 67% rename from app/src/main/java/com/tangem/tap/persistence/UsedCardsPrefStorage.kt rename to data/source/preferences/src/main/kotlin/com/tangem/data/source/preferences/storage/UsedCardsPrefStorage.kt index f814eb7e16..b1fbf61361 100644 --- a/app/src/main/java/com/tangem/tap/persistence/UsedCardsPrefStorage.kt +++ b/data/source/preferences/src/main/kotlin/com/tangem/data/source/preferences/storage/UsedCardsPrefStorage.kt @@ -1,15 +1,16 @@ -package com.tangem.tap.persistence +package com.tangem.data.source.preferences.storage import android.content.SharedPreferences import androidx.core.content.edit import com.tangem.common.json.MoshiJsonConverter -import com.tangem.tap.common.extensions.replaceByOrAdd -import timber.log.Timber +import com.tangem.data.source.preferences.model.DataSourceUsedCardInfo +import com.tangem.data.source.preferences.model.DataSourceUsedCardInfoOld /** [REDACTED_AUTHOR] */ -class UsedCardsPrefStorage( +@Deprecated("Create repository instead") +class UsedCardsPrefStorage internal constructor( private val preferences: SharedPreferences, private val jsonConverter: MoshiJsonConverter, ) { @@ -26,7 +27,7 @@ class UsedCardsPrefStorage( fun scanned(cardId: String) { val restoredList = restore() val foundItem = findCardInfo(cardId, restoredList)?.copy(isScanned = true) - ?: UsedCardInfo(cardId, true) + ?: DataSourceUsedCardInfo(cardId, true) save(foundItem, restoredList) } @@ -38,14 +39,14 @@ class UsedCardsPrefStorage( fun activationStarted(cardId: String) { val restoredList = restore() val foundItem = findCardInfo(cardId, restoredList)?.copy(isActivationStarted = true) - ?: UsedCardInfo(cardId, isActivationStarted = true) + ?: DataSourceUsedCardInfo(cardId, isActivationStarted = true) save(foundItem, restoredList) } fun activationFinished(cardId: String) { val restoredList = restore() - var foundItem = findCardInfo(cardId, restoredList) ?: UsedCardInfo(cardId) + var foundItem = findCardInfo(cardId, restoredList) ?: DataSourceUsedCardInfo(cardId) foundItem = foundItem.copy( isActivationStarted = true, isActivationFinished = true, @@ -67,33 +68,38 @@ class UsedCardsPrefStorage( return cardInfo.isActivationStarted && !cardInfo.isActivationFinished } - private fun findCardInfo(cardId: String, list: MutableList? = null): UsedCardInfo? { + private fun findCardInfo( + cardId: String, + list: MutableList? = null, + ): DataSourceUsedCardInfo? { val findInList = list ?: restore() return findInList.firstOrNull { it.cardId == cardId } } - private fun save(usedCardInfo: UsedCardInfo?, usedCardsInfo: MutableList) { + private fun save(usedCardInfo: DataSourceUsedCardInfo?, usedCardsInfo: MutableList) { val info = usedCardInfo ?: return - usedCardsInfo.replaceByOrAdd(info) { it.cardId == info.cardId } + with(usedCardsInfo) { + val index = indexOfFirst { it.cardId == info.cardId } + if (index == -1) { + add(info) + } else { + set(index, info) + } + } + save(usedCardsInfo) } - private fun save(list: MutableList): Boolean { - return try { - val json = jsonConverter.toJson(list) - preferences.edit { putString(USED_CARDS_INFO_V2, json) } - true - } catch (ex: Exception) { - Timber.e(ex) - false - } + private fun save(list: MutableList) { + val json = jsonConverter.toJson(list) + preferences.edit { putString(USED_CARDS_INFO_V2, json) } } - private fun restore(): MutableList { + private fun restore(): MutableList { val json = preferences.getString(USED_CARDS_INFO_V2, null) ?: return mutableListOf() return try { - jsonConverter.fromJson(json, jsonConverter.typedList(UsedCardInfo::class.java))!! + jsonConverter.fromJson(json, jsonConverter.typedList(DataSourceUsedCardInfo::class.java))!! } catch (ex: Exception) { preferences.edit(true) { remove(USED_CARDS_INFO_V2) } mutableListOf() @@ -113,7 +119,7 @@ class UsedCardsPrefStorage( if (restoredCardsInfo.isEmpty()) return val newCardsInfo = restoredCardsInfo.map { cardInfo -> - UsedCardInfo( + DataSourceUsedCardInfo( cardId = cardInfo.cardId, isScanned = cardInfo.isScanned, isActivationStarted = true, @@ -123,10 +129,13 @@ class UsedCardsPrefStorage( storage.save(newCardsInfo) } - private fun restore(): MutableList { + private fun restore(): MutableList { val json = storage.preferences.getString(USED_CARDS_INFO, null) ?: return mutableListOf() return try { - storage.jsonConverter.fromJson(json, storage.jsonConverter.typedList(UsedCardInfoOld::class.java))!! + storage.jsonConverter.fromJson( + json, + storage.jsonConverter.typedList(DataSourceUsedCardInfoOld::class.java), + )!! } catch (ex: Exception) { mutableListOf() } finally { @@ -134,21 +143,4 @@ class UsedCardsPrefStorage( } } } - - private data class UsedCardInfo( - val cardId: String, - val isScanned: Boolean = false, - val isActivationStarted: Boolean = false, - val isActivationFinished: Boolean = false, - ) - - private data class UsedCardInfoOld( - val cardId: String, - val isScanned: Boolean = false, - val isActivationStarted: Boolean = false, - ) -} - -private interface Migration { - fun migrate() } \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 2c4e5ecbcc..3928077a46 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -69,4 +69,8 @@ include(":domain:legacy") include(":domain:core") include(":domain:card") -// endregion Domain modules \ No newline at end of file +// endregion Domain modules + +// region Data modules +include(":data:source:preferences") +// endregion Data modules \ No newline at end of file