diff --git a/app/src/main/java/com/tangem/tap/TapApplication.kt b/app/src/main/java/com/tangem/tap/TapApplication.kt index c67f289238..420a6ff091 100644 --- a/app/src/main/java/com/tangem/tap/TapApplication.kt +++ b/app/src/main/java/com/tangem/tap/TapApplication.kt @@ -30,7 +30,6 @@ import com.tangem.domain.apptheme.repository.AppThemeModeRepository import com.tangem.domain.balancehiding.repositories.BalanceHidingRepository import com.tangem.domain.card.ScanCardProcessor import com.tangem.domain.common.LogConfig -import com.tangem.domain.settings.repositories.AppRatingRepository import com.tangem.domain.tokens.repository.CurrenciesRepository import com.tangem.domain.tokens.repository.NetworksRepository import com.tangem.domain.walletmanager.WalletManagersFacade @@ -209,9 +208,6 @@ internal class TapApplication : Application(), ImageLoaderFactory { @Inject lateinit var userTokensStore: UserTokensStore - @Inject - lateinit var appRatingRepository: AppRatingRepository - @Inject lateinit var getAppThemeModeUseCase: GetAppThemeModeUseCase @@ -248,10 +244,8 @@ internal class TapApplication : Application(), ImageLoaderFactory { // TODO: Try to performance and user experience. // [REDACTED_JIRA] runBlocking { - walletsRepository.initialize() initUserWalletsListManager() featureTogglesManager.init() - appRatingRepository.initialize() // learn2earnInteractor.init() } diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TradeCryptoMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TradeCryptoMiddleware.kt index 66027e8a6b..80f84ebf33 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TradeCryptoMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TradeCryptoMiddleware.kt @@ -36,8 +36,6 @@ import com.tangem.tap.proxy.redux.DaggerGraphState import com.tangem.tap.scope import com.tangem.tap.store import kotlinx.coroutines.launch -import kotlinx.serialization.encodeToString -import kotlinx.serialization.json.Json @Suppress("LargeClass") class TradeCryptoMiddleware { @@ -259,7 +257,7 @@ class TradeCryptoMiddleware { private fun openSwap(currency: CryptoCurrency) { val bundle = bundleOf( - SwapFragment.CURRENCY_BUNDLE_KEY to currency + SwapFragment.CURRENCY_BUNDLE_KEY to currency, ) store.dispatchOnMain(NavigationAction.NavigateTo(screen = AppScreen.Swap, bundle = bundle)) diff --git a/core/datasource/src/main/java/com/tangem/datasource/di/AppCurrencyDataModule.kt b/core/datasource/src/main/java/com/tangem/datasource/di/AppCurrencyDataModule.kt index e25e15471b..fade673123 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/di/AppCurrencyDataModule.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/di/AppCurrencyDataModule.kt @@ -1,18 +1,11 @@ package com.tangem.datasource.di -import android.content.Context -import com.squareup.moshi.Moshi -import com.tangem.datasource.api.tangemTech.models.CurrenciesResponse import com.tangem.datasource.local.appcurrency.AvailableAppCurrenciesStore -import com.tangem.datasource.local.appcurrency.SelectedAppCurrencyStore import com.tangem.datasource.local.appcurrency.implementation.DefaultAvailableAppCurrenciesStore -import com.tangem.datasource.local.appcurrency.implementation.DefaultSelectedAppCurrencyStore -import com.tangem.datasource.local.datastore.JsonSharedPreferencesDataStore import com.tangem.datasource.local.datastore.RuntimeDataStore 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 @@ -23,23 +16,6 @@ internal object AppCurrencyDataModule { @Provides @Singleton fun provideAvailableAppCurrenciesStore(): AvailableAppCurrenciesStore { - return DefaultAvailableAppCurrenciesStore( - dataStore = RuntimeDataStore(), - ) - } - - @Provides - @Singleton - fun provideSelectedAppCurrencyStore( - @ApplicationContext context: Context, - @NetworkMoshi moshi: Moshi, - ): SelectedAppCurrencyStore { - return DefaultSelectedAppCurrencyStore( - dataStore = JsonSharedPreferencesDataStore( - preferencesName = "selected_app_currency", - context = context, - adapter = moshi.adapter(CurrenciesResponse.Currency::class.java), - ), - ) + return DefaultAvailableAppCurrenciesStore(dataStore = RuntimeDataStore()) } } \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/di/AppThemeModeDataModule.kt b/core/datasource/src/main/java/com/tangem/datasource/di/AppThemeModeDataModule.kt deleted file mode 100644 index a6e8020146..0000000000 --- a/core/datasource/src/main/java/com/tangem/datasource/di/AppThemeModeDataModule.kt +++ /dev/null @@ -1,29 +0,0 @@ -package com.tangem.datasource.di - -import android.content.Context -import com.squareup.moshi.Moshi -import com.tangem.datasource.local.apptheme.AppThemeModeStore -import com.tangem.datasource.local.apptheme.DefaultAppThemeModeStore -import com.tangem.datasource.local.datastore.JsonSharedPreferencesDataStore -import com.tangem.domain.apptheme.model.AppThemeMode -import dagger.Module -import dagger.Provides -import dagger.hilt.InstallIn -import dagger.hilt.android.qualifiers.ApplicationContext -import dagger.hilt.components.SingletonComponent - -@Module -@InstallIn(SingletonComponent::class) -internal object AppThemeModeDataModule { - - @Provides - fun provideAppThemeModeStore(@ApplicationContext context: Context, @NetworkMoshi moshi: Moshi): AppThemeModeStore { - return DefaultAppThemeModeStore( - dataStore = JsonSharedPreferencesDataStore( - preferencesName = "app_theme", - context = context, - adapter = moshi.adapter(AppThemeMode::class.java), - ), - ) - } -} \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/di/CardDataModule.kt b/core/datasource/src/main/java/com/tangem/datasource/di/CardDataModule.kt deleted file mode 100644 index f06e5ac8e5..0000000000 --- a/core/datasource/src/main/java/com/tangem/datasource/di/CardDataModule.kt +++ /dev/null @@ -1,34 +0,0 @@ -package com.tangem.datasource.di - -import android.content.Context -import com.squareup.moshi.Moshi -import com.squareup.moshi.Types -import com.tangem.datasource.local.card.DefaultUsedCardsStore -import com.tangem.datasource.local.card.UsedCardInfo -import com.tangem.datasource.local.card.UsedCardsStore -import com.tangem.datasource.local.datastore.JsonSharedPreferencesDataStore -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 CardDataModule { - - @Provides - @Singleton - fun provideUsedCardsStore(@ApplicationContext context: Context, @NetworkMoshi moshi: Moshi): UsedCardsStore { - return DefaultUsedCardsStore( - store = JsonSharedPreferencesDataStore( - preferencesName = "tapPrefs", - context = context, - adapter = moshi.adapter( - Types.newParameterizedType(List::class.java, UsedCardInfo::class.java), - ), - ), - ) - } -} \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/di/HiddenBalanceDataModule.kt b/core/datasource/src/main/java/com/tangem/datasource/di/HiddenBalanceDataModule.kt deleted file mode 100644 index 9b59f30477..0000000000 --- a/core/datasource/src/main/java/com/tangem/datasource/di/HiddenBalanceDataModule.kt +++ /dev/null @@ -1,32 +0,0 @@ -package com.tangem.datasource.di - -import android.content.Context -import com.squareup.moshi.Moshi -import com.tangem.datasource.local.appcurrency.BalanceHidingSettingsStore -import com.tangem.datasource.local.appcurrency.implementation.BalanceStateHidingSettingsStore -import com.tangem.datasource.local.datastore.JsonSharedPreferencesDataStore -import com.tangem.domain.balancehiding.BalanceHidingSettings -import dagger.Module -import dagger.Provides -import dagger.hilt.InstallIn -import dagger.hilt.android.qualifiers.ApplicationContext -import dagger.hilt.components.SingletonComponent - -@Module -@InstallIn(SingletonComponent::class) -internal object HiddenBalanceDataModule { - - @Provides - fun provideHiddenBalanceStateStore( - @ApplicationContext context: Context, - @NetworkMoshi moshi: Moshi, - ): BalanceHidingSettingsStore { - return BalanceStateHidingSettingsStore( - dataStore = JsonSharedPreferencesDataStore( - preferencesName = "balance_hiding_settings", - context = context, - adapter = moshi.adapter(BalanceHidingSettings::class.java), - ), - ) - } -} \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/di/SettingsDataModule.kt b/core/datasource/src/main/java/com/tangem/datasource/di/SettingsDataModule.kt deleted file mode 100644 index ba757806d6..0000000000 --- a/core/datasource/src/main/java/com/tangem/datasource/di/SettingsDataModule.kt +++ /dev/null @@ -1,50 +0,0 @@ -package com.tangem.datasource.di - -import android.content.Context -import com.tangem.datasource.local.datastore.BooleanSharedPreferencesDataStore -import com.tangem.datasource.local.datastore.IntSharedPreferencesDataStore -import com.tangem.datasource.local.datastore.LongSharedPreferencesDataStore -import com.tangem.datasource.local.settings.* -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 SettingsDataModule { - - @Provides - @Singleton - fun provideAppLaunchCountStore(@ApplicationContext context: Context): AppLaunchCountStore { - return DefaultAppLaunchCountStore( - store = IntSharedPreferencesDataStore(preferencesName = "tapPrefs", context = context), - ) - } - - @Provides - @Singleton - fun provideAppRatingShowingCountStore(@ApplicationContext context: Context): AppRatingShowingCountStore { - return DefaultAppRatingShowingCountStore( - store = IntSharedPreferencesDataStore(preferencesName = "tapPrefs", context = context), - ) - } - - @Provides - @Singleton - fun provideFundsFoundDateInMillisStore(@ApplicationContext context: Context): FundsFoundDateInMillisStore { - return DefaultFundsFoundDateInMillisStore( - store = LongSharedPreferencesDataStore(preferencesName = "tapPrefs", context = context), - ) - } - - @Provides - @Singleton - fun provideUserInteractingStatusStore(@ApplicationContext context: Context): UserInteractingStatusStore { - return DefaultUserInteractingStatusStore( - store = BooleanSharedPreferencesDataStore(preferencesName = "tapPrefs", context = context), - ) - } -} \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/di/WalletsDataModule.kt b/core/datasource/src/main/java/com/tangem/datasource/di/WalletsDataModule.kt deleted file mode 100644 index 61cdcacad3..0000000000 --- a/core/datasource/src/main/java/com/tangem/datasource/di/WalletsDataModule.kt +++ /dev/null @@ -1,26 +0,0 @@ -package com.tangem.datasource.di - -import android.content.Context -import com.tangem.datasource.local.datastore.BooleanSharedPreferencesDataStore -import com.tangem.datasource.local.settings.* -import com.tangem.datasource.local.userwallet.DefaultShouldSaveUserWalletStore -import com.tangem.datasource.local.userwallet.ShouldSaveUserWalletStore -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 WalletsDataModule { - - @Provides - @Singleton - fun provideShouldSaveUserWalletsStore(@ApplicationContext context: Context): ShouldSaveUserWalletStore { - return DefaultShouldSaveUserWalletStore( - store = BooleanSharedPreferencesDataStore(preferencesName = "tapPrefs", context = context), - ) - } -} \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/AppPreferenceStorage.kt b/core/datasource/src/main/java/com/tangem/datasource/local/AppPreferenceStorage.kt index 3e30c7344b..d56ca29fa0 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/local/AppPreferenceStorage.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/local/AppPreferenceStorage.kt @@ -5,6 +5,7 @@ package com.tangem.datasource.local * [REDACTED_AUTHOR] */ +@Deprecated(message = "Use AppPreferencesStore", level = DeprecationLevel.WARNING) interface AppPreferenceStorage { /** Json config with feature toggles 'ToggleName: String - Availability: Boolean' */ diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/appcurrency/BalanceHidingSettingsStore.kt b/core/datasource/src/main/java/com/tangem/datasource/local/appcurrency/BalanceHidingSettingsStore.kt deleted file mode 100644 index a29714251b..0000000000 --- a/core/datasource/src/main/java/com/tangem/datasource/local/appcurrency/BalanceHidingSettingsStore.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.tangem.datasource.local.appcurrency - -import com.tangem.domain.balancehiding.BalanceHidingSettings -import kotlinx.coroutines.flow.Flow - -interface BalanceHidingSettingsStore { - - fun get(): Flow - - suspend fun getSyncOrDefault(): BalanceHidingSettings - - suspend fun store(settings: BalanceHidingSettings) -} \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/appcurrency/SelectedAppCurrencyStore.kt b/core/datasource/src/main/java/com/tangem/datasource/local/appcurrency/SelectedAppCurrencyStore.kt deleted file mode 100644 index e732ce8415..0000000000 --- a/core/datasource/src/main/java/com/tangem/datasource/local/appcurrency/SelectedAppCurrencyStore.kt +++ /dev/null @@ -1,15 +0,0 @@ -package com.tangem.datasource.local.appcurrency - -import com.tangem.datasource.api.tangemTech.models.CurrenciesResponse -import kotlinx.coroutines.flow.Flow - -interface SelectedAppCurrencyStore { - - fun get(): Flow - - suspend fun getSyncOrNull(): CurrenciesResponse.Currency? - - suspend fun store(item: CurrenciesResponse.Currency) - - suspend fun isEmpty(): Boolean -} \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/appcurrency/implementation/BalanceStateHidingSettingsStore.kt b/core/datasource/src/main/java/com/tangem/datasource/local/appcurrency/implementation/BalanceStateHidingSettingsStore.kt deleted file mode 100644 index 0314d6549d..0000000000 --- a/core/datasource/src/main/java/com/tangem/datasource/local/appcurrency/implementation/BalanceStateHidingSettingsStore.kt +++ /dev/null @@ -1,19 +0,0 @@ -package com.tangem.datasource.local.appcurrency.implementation - -import com.tangem.datasource.local.appcurrency.BalanceHidingSettingsStore -import com.tangem.datasource.local.datastore.core.KeylessDataStoreDecorator -import com.tangem.datasource.local.datastore.core.StringKeyDataStore -import com.tangem.domain.balancehiding.BalanceHidingSettings - -internal class BalanceStateHidingSettingsStore( - dataStore: StringKeyDataStore, -) : BalanceHidingSettingsStore, KeylessDataStoreDecorator(dataStore) { - - override suspend fun getSyncOrDefault(): BalanceHidingSettings { - return getSyncOrNull() ?: BalanceHidingSettings( - isHidingEnabledInSettings = false, - isBalanceHidden = false, - isBalanceHidingNotificationEnabled = true, - ) - } -} \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/appcurrency/implementation/DefaultSelectedAppCurrencyStore.kt b/core/datasource/src/main/java/com/tangem/datasource/local/appcurrency/implementation/DefaultSelectedAppCurrencyStore.kt deleted file mode 100644 index c79bf3045b..0000000000 --- a/core/datasource/src/main/java/com/tangem/datasource/local/appcurrency/implementation/DefaultSelectedAppCurrencyStore.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.tangem.datasource.local.appcurrency.implementation - -import com.tangem.datasource.api.tangemTech.models.CurrenciesResponse -import com.tangem.datasource.local.appcurrency.SelectedAppCurrencyStore -import com.tangem.datasource.local.datastore.core.KeylessDataStoreDecorator -import com.tangem.datasource.local.datastore.core.StringKeyDataStore - -internal class DefaultSelectedAppCurrencyStore( - dataStore: StringKeyDataStore, -) : SelectedAppCurrencyStore, KeylessDataStoreDecorator(dataStore) \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/apptheme/AppThemeModeStore.kt b/core/datasource/src/main/java/com/tangem/datasource/local/apptheme/AppThemeModeStore.kt deleted file mode 100644 index 78e1fd514c..0000000000 --- a/core/datasource/src/main/java/com/tangem/datasource/local/apptheme/AppThemeModeStore.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.tangem.datasource.local.apptheme - -import com.tangem.domain.apptheme.model.AppThemeMode -import kotlinx.coroutines.flow.Flow - -interface AppThemeModeStore { - - fun get(): Flow - - suspend fun store(item: AppThemeMode) - - suspend fun isEmpty(): Boolean -} \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/apptheme/DefaultAppThemeModeStore.kt b/core/datasource/src/main/java/com/tangem/datasource/local/apptheme/DefaultAppThemeModeStore.kt deleted file mode 100644 index 483bf4b525..0000000000 --- a/core/datasource/src/main/java/com/tangem/datasource/local/apptheme/DefaultAppThemeModeStore.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.tangem.datasource.local.apptheme - -import com.tangem.datasource.local.datastore.core.KeylessDataStoreDecorator -import com.tangem.datasource.local.datastore.core.StringKeyDataStore -import com.tangem.domain.apptheme.model.AppThemeMode - -internal class DefaultAppThemeModeStore( - dataStore: StringKeyDataStore, -) : AppThemeModeStore, KeylessDataStoreDecorator(dataStore) \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/card/UsedCardsStore.kt b/core/datasource/src/main/java/com/tangem/datasource/local/card/UsedCardsStore.kt deleted file mode 100644 index 0d54995dbb..0000000000 --- a/core/datasource/src/main/java/com/tangem/datasource/local/card/UsedCardsStore.kt +++ /dev/null @@ -1,21 +0,0 @@ -package com.tangem.datasource.local.card - -import com.tangem.datasource.local.datastore.SharedPreferencesDataStore -import com.tangem.datasource.local.datastore.core.KeylessDataStoreDecorator -import kotlinx.coroutines.flow.Flow - -interface UsedCardsStore { - - fun get(): Flow> - - suspend fun getSyncOrNull(): List? - - suspend fun store(item: List) -} - -internal class DefaultUsedCardsStore( - store: SharedPreferencesDataStore>, -) : UsedCardsStore, KeylessDataStoreDecorator>( - wrappedDataStore = store, - key = "usedCardsInfo_v2", -) \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/datastore/BooleanSharedPreferencesDataStore.kt b/core/datasource/src/main/java/com/tangem/datasource/local/datastore/BooleanSharedPreferencesDataStore.kt deleted file mode 100644 index 36141207c0..0000000000 --- a/core/datasource/src/main/java/com/tangem/datasource/local/datastore/BooleanSharedPreferencesDataStore.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.tangem.datasource.local.datastore - -import android.content.Context -import androidx.core.content.edit - -internal class BooleanSharedPreferencesDataStore( - preferencesName: String, - context: Context, -) : SharedPreferencesDataStore(preferencesName, context) { - - override fun getByKey(key: String): Boolean = sharedPreferences.getBoolean(key, false) - - override fun storeByKey(key: String, value: Boolean) { - sharedPreferences.edit { putBoolean(key, value) } - } -} \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/datastore/IntSharedPreferencesDataStore.kt b/core/datasource/src/main/java/com/tangem/datasource/local/datastore/IntSharedPreferencesDataStore.kt deleted file mode 100644 index 7ef0f70fa6..0000000000 --- a/core/datasource/src/main/java/com/tangem/datasource/local/datastore/IntSharedPreferencesDataStore.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.tangem.datasource.local.datastore - -import android.content.Context -import androidx.core.content.edit - -internal class IntSharedPreferencesDataStore( - preferencesName: String, - context: Context, -) : SharedPreferencesDataStore(preferencesName, context) { - - override fun getByKey(key: String): Int = sharedPreferences.getInt(key, 0) - - override fun storeByKey(key: String, value: Int) { - sharedPreferences.edit { putInt(key, value) } - } -} \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/datastore/JsonSharedPreferencesDataStore.kt b/core/datasource/src/main/java/com/tangem/datasource/local/datastore/JsonSharedPreferencesDataStore.kt deleted file mode 100644 index 5e47ee8114..0000000000 --- a/core/datasource/src/main/java/com/tangem/datasource/local/datastore/JsonSharedPreferencesDataStore.kt +++ /dev/null @@ -1,24 +0,0 @@ -package com.tangem.datasource.local.datastore - -import android.content.Context -import androidx.core.content.edit -import com.squareup.moshi.JsonAdapter - -internal class JsonSharedPreferencesDataStore( - preferencesName: String, - context: Context, - private val adapter: JsonAdapter, -) : SharedPreferencesDataStore(preferencesName, context) { - - override fun getByKey(key: String): Value? { - val json = sharedPreferences.getString(key, null) ?: return null - - return adapter.fromJson(json) - } - - override fun storeByKey(key: String, value: Value) { - val json = adapter.toJson(value) - - sharedPreferences.edit { putString(key, json) } - } -} \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/datastore/LongSharedPreferencesDataStore.kt b/core/datasource/src/main/java/com/tangem/datasource/local/datastore/LongSharedPreferencesDataStore.kt deleted file mode 100644 index b1bb00e4e1..0000000000 --- a/core/datasource/src/main/java/com/tangem/datasource/local/datastore/LongSharedPreferencesDataStore.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.tangem.datasource.local.datastore - -import android.content.Context -import androidx.core.content.edit - -internal class LongSharedPreferencesDataStore( - preferencesName: String, - context: Context, -) : SharedPreferencesDataStore(preferencesName, context) { - - override fun getByKey(key: String): Long = sharedPreferences.getLong(key, 0) - - override fun storeByKey(key: String, value: Long) { - sharedPreferences.edit { putLong(key, value) } - } -} \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/datastore/SharedPreferencesDataStore.kt b/core/datasource/src/main/java/com/tangem/datasource/local/datastore/SharedPreferencesDataStore.kt deleted file mode 100644 index 417b4e9ac4..0000000000 --- a/core/datasource/src/main/java/com/tangem/datasource/local/datastore/SharedPreferencesDataStore.kt +++ /dev/null @@ -1,98 +0,0 @@ -package com.tangem.datasource.local.datastore - -import android.content.Context -import android.content.Context.MODE_PRIVATE -import android.content.SharedPreferences -import androidx.core.content.edit -import com.tangem.datasource.local.datastore.core.StringKeyDataStore -import com.tangem.datasource.local.datastore.utils.Trigger -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.distinctUntilChanged -import kotlinx.coroutines.flow.mapNotNull -import timber.log.Timber - -internal abstract class SharedPreferencesDataStore( - preferencesName: String, - context: Context, -) : StringKeyDataStore { - - protected val sharedPreferences: SharedPreferences by lazy { - context.getSharedPreferences(preferencesName, MODE_PRIVATE) - } - - private val writeTrigger = Trigger() - - abstract fun getByKey(key: String): Value? - - abstract fun storeByKey(key: String, value: Value) - - override suspend fun isEmpty(): Boolean { - return sharedPreferences.all.isEmpty() - } - - override suspend fun contains(key: String): Boolean { - return sharedPreferences.contains(key) - } - - override fun get(key: String): Flow { - return writeTrigger - .mapNotNull { getInternal(key) } - .distinctUntilChanged() - } - - override fun getAll(): Flow> { - throw UnsupportedOperationException("Unknown key") - } - - override suspend fun getSyncOrNull(key: String): Value? = getInternal(key) - - override suspend fun getAllSyncOrNull(): List { - throw UnsupportedOperationException("Unknown key") - } - - override suspend fun store(key: String, value: Value) { - try { - storeByKey(key, value) - writeTrigger.trigger() - } catch (e: Throwable) { - Timber.e(e, "Unable to edit preferences: $key") - } - } - - override suspend fun store(values: Map) { - values.forEach { (key, item) -> - store(key, item) - } - } - - override suspend fun remove(key: String) { - sharedPreferences.edit { remove(key) } - writeTrigger.trigger() - } - - override suspend fun remove(keys: Collection) { - sharedPreferences.edit { - keys.forEach { key -> - remove(key) - } - } - - writeTrigger.trigger() - } - - override suspend fun clear() { - sharedPreferences.edit { clear() } - writeTrigger.trigger() - } - - private fun getInternal(key: String): Value? { - if (!sharedPreferences.contains(key)) return null - - return try { - getByKey(key) - } catch (e: Throwable) { - Timber.e(e, "Unable to get value from preferences: $key") - null - } - } -} \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/preferences/PreferencesDataStore.kt b/core/datasource/src/main/java/com/tangem/datasource/local/preferences/PreferencesDataStore.kt index 7d0d6ba94a..9e9b278b7e 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/local/preferences/PreferencesDataStore.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/local/preferences/PreferencesDataStore.kt @@ -4,11 +4,13 @@ import android.content.Context import androidx.datastore.core.DataMigration import androidx.datastore.core.DataStore import androidx.datastore.core.handlers.ReplaceFileCorruptionHandler +import androidx.datastore.preferences.SharedPreferencesMigration import androidx.datastore.preferences.core.PreferenceDataStoreFactory import androidx.datastore.preferences.core.Preferences import androidx.datastore.preferences.core.emptyPreferences import androidx.datastore.preferences.preferencesDataStoreFile import com.tangem.datasource.local.preferences.PreferencesDataStore.INSTANCE +import com.tangem.datasource.local.preferences.utils.SharedPreferencesKeyMigration import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.SupervisorJob import timber.log.Timber @@ -23,6 +25,8 @@ import kotlin.coroutines.CoroutineContext internal object PreferencesDataStore { private const val PREFERENCES_FILE_NAME = "TAP_PREFS" + private const val LEGACY_TAP_PREFS_FILE_NAME = "tapPrefs" + private const val LEGACY_DEFAULT_KEY_NAME = "key" private var INSTANCE: DataStore? = null @@ -33,7 +37,7 @@ internal object PreferencesDataStore { private fun create(context: Context, dispatcher: CoroutineContext): DataStore { return PreferenceDataStoreFactory.create( corruptionHandler = createCorruptionHandler(), - migrations = createMigrations(), + migrations = createMigrations(context = context), scope = CoroutineScope(context = dispatcher + SupervisorJob()), produceFile = { context.preferencesDataStoreFile(name = PREFERENCES_FILE_NAME) }, ) @@ -48,7 +52,31 @@ internal object PreferencesDataStore { ) } - private fun createMigrations(): List> { - return listOf() + private fun createMigrations(context: Context): List> { + return listOf( + SharedPreferencesMigration( + context = context, + sharedPreferencesName = LEGACY_TAP_PREFS_FILE_NAME, + keysToMigrate = getTapPrefKeysToMigrate(), + ), + SharedPreferencesKeyMigration( + context = context, + legacyPrefsName = "app_theme", + legacyKeyName = LEGACY_DEFAULT_KEY_NAME, + keyName = PreferencesKeys.APP_THEME_MODE_KEY.name, + ), + SharedPreferencesKeyMigration( + context = context, + legacyPrefsName = "selected_app_currency", + legacyKeyName = LEGACY_DEFAULT_KEY_NAME, + keyName = PreferencesKeys.SELECTED_APP_CURRENCY_KEY.name, + ), + SharedPreferencesKeyMigration( + context = context, + legacyPrefsName = "balance_hiding_settings", + legacyKeyName = LEGACY_DEFAULT_KEY_NAME, + keyName = PreferencesKeys.BALANCE_HIDING_SETTINGS_KEY.name, + ), + ) } } \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/preferences/PreferencesKeys.kt b/core/datasource/src/main/java/com/tangem/datasource/local/preferences/PreferencesKeys.kt index 90f2b61270..d81065c147 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/local/preferences/PreferencesKeys.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/local/preferences/PreferencesKeys.kt @@ -1,13 +1,49 @@ package com.tangem.datasource.local.preferences +import androidx.datastore.preferences.core.* +import com.tangem.datasource.local.preferences.PreferencesKeys.APP_LAUNCH_COUNT_KEY +import com.tangem.datasource.local.preferences.PreferencesKeys.FUNDS_FOUND_DATE_KEY +import com.tangem.datasource.local.preferences.PreferencesKeys.SAVE_USER_WALLETS_KEY +import com.tangem.datasource.local.preferences.PreferencesKeys.SHOW_RATING_DIALOG_AT_LAUNCH_COUNT_KEY +import com.tangem.datasource.local.preferences.PreferencesKeys.USED_CARDS_INFO_KEY +import com.tangem.datasource.local.preferences.PreferencesKeys.USER_WAS_INTERACT_WITH_RATING_KEY + /** * All preferences keys that DataStore is stored. * [REDACTED_AUTHOR] */ -object PreferencesKeys +object PreferencesKeys { + + val SAVE_USER_WALLETS_KEY by lazy { booleanPreferencesKey(name = "saveUserWallets") } + + val APP_LAUNCH_COUNT_KEY by lazy { intPreferencesKey(name = "launchCount") } + + val SHOW_RATING_DIALOG_AT_LAUNCH_COUNT_KEY by lazy { intPreferencesKey(name = "showRatingDialogAtLaunchCount") } + + val FUNDS_FOUND_DATE_KEY by lazy { longPreferencesKey(name = "fundsFoundDate") } + + val USER_WAS_INTERACT_WITH_RATING_KEY by lazy { booleanPreferencesKey(name = "userWasInteractWithRating") } + + val USED_CARDS_INFO_KEY by lazy { stringPreferencesKey(name = "usedCardsInfo_v2") } + + val APP_THEME_MODE_KEY by lazy { stringPreferencesKey(name = "appThemeMode") } + + val SELECTED_APP_CURRENCY_KEY by lazy { stringPreferencesKey(name = "selectedAppCurrency") } + + val BALANCE_HIDING_SETTINGS_KEY by lazy { stringPreferencesKey(name = "balanceHidingSettings") } +} /** Preferences keys set that should be migrated from "PreferencesDataSource" to a new DataStore */ internal fun getTapPrefKeysToMigrate(): Set { - return setOf() + return setOf( + SAVE_USER_WALLETS_KEY, + APP_LAUNCH_COUNT_KEY, + SHOW_RATING_DIALOG_AT_LAUNCH_COUNT_KEY, + FUNDS_FOUND_DATE_KEY, + USER_WAS_INTERACT_WITH_RATING_KEY, + USED_CARDS_INFO_KEY, + ) + .map(Preferences.Key<*>::name) + .toSet() } \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/quote/DefaultQuotesStore.kt b/core/datasource/src/main/java/com/tangem/datasource/local/quote/DefaultQuotesStore.kt index 2b8de0afd9..fc0d1e0e42 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/local/quote/DefaultQuotesStore.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/local/quote/DefaultQuotesStore.kt @@ -30,6 +30,14 @@ internal class DefaultQuotesStore( } } + override suspend fun getSync(currenciesIds: Set): Set { + return currenciesIds.mapNotNull { currencyId -> + currencyId.rawCurrencyId?.let { + dataStore.getSyncOrNull(it) + } + }.toSet() + } + override suspend fun store(response: QuotesResponse) { val quotes = response.quotes.mapValues { (id, quote) -> StoredQuote(id, quote) diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/quote/QuotesStore.kt b/core/datasource/src/main/java/com/tangem/datasource/local/quote/QuotesStore.kt index 64b3bf2c9c..dd3f577782 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/local/quote/QuotesStore.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/local/quote/QuotesStore.kt @@ -9,5 +9,7 @@ interface QuotesStore { fun get(currenciesIds: Set): Flow> + suspend fun getSync(currenciesIds: Set): Set + suspend fun store(response: QuotesResponse) } \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/settings/AppLaunchCountStore.kt b/core/datasource/src/main/java/com/tangem/datasource/local/settings/AppLaunchCountStore.kt deleted file mode 100644 index a2ee494307..0000000000 --- a/core/datasource/src/main/java/com/tangem/datasource/local/settings/AppLaunchCountStore.kt +++ /dev/null @@ -1,21 +0,0 @@ -package com.tangem.datasource.local.settings - -import com.tangem.datasource.local.datastore.IntSharedPreferencesDataStore -import com.tangem.datasource.local.datastore.core.KeylessDataStoreDecorator -import kotlinx.coroutines.flow.Flow - -interface AppLaunchCountStore { - - fun get(): Flow - - suspend fun getSyncOrNull(): Int? - - suspend fun store(item: Int) -} - -internal class DefaultAppLaunchCountStore( - store: IntSharedPreferencesDataStore, -) : AppLaunchCountStore, KeylessDataStoreDecorator( - wrappedDataStore = store, - key = "launchCount", -) \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/settings/AppRatingShowingCountStore.kt b/core/datasource/src/main/java/com/tangem/datasource/local/settings/AppRatingShowingCountStore.kt deleted file mode 100644 index dfbb452f22..0000000000 --- a/core/datasource/src/main/java/com/tangem/datasource/local/settings/AppRatingShowingCountStore.kt +++ /dev/null @@ -1,21 +0,0 @@ -package com.tangem.datasource.local.settings - -import com.tangem.datasource.local.datastore.IntSharedPreferencesDataStore -import com.tangem.datasource.local.datastore.core.KeylessDataStoreDecorator -import kotlinx.coroutines.flow.Flow - -interface AppRatingShowingCountStore { - - fun get(): Flow - - suspend fun getSyncOrNull(): Int? - - suspend fun store(item: Int) -} - -internal class DefaultAppRatingShowingCountStore( - store: IntSharedPreferencesDataStore, -) : AppRatingShowingCountStore, KeylessDataStoreDecorator( - wrappedDataStore = store, - key = "showRatingDialogAtLaunchCount", -) \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/settings/FundsFoundDateInMillisStore.kt b/core/datasource/src/main/java/com/tangem/datasource/local/settings/FundsFoundDateInMillisStore.kt deleted file mode 100644 index 1e6a50f959..0000000000 --- a/core/datasource/src/main/java/com/tangem/datasource/local/settings/FundsFoundDateInMillisStore.kt +++ /dev/null @@ -1,21 +0,0 @@ -package com.tangem.datasource.local.settings - -import com.tangem.datasource.local.datastore.LongSharedPreferencesDataStore -import com.tangem.datasource.local.datastore.core.KeylessDataStoreDecorator -import kotlinx.coroutines.flow.Flow - -interface FundsFoundDateInMillisStore { - - fun get(): Flow - - suspend fun getSyncOrNull(): Long? - - suspend fun store(item: Long) -} - -internal class DefaultFundsFoundDateInMillisStore( - store: LongSharedPreferencesDataStore, -) : FundsFoundDateInMillisStore, KeylessDataStoreDecorator( - wrappedDataStore = store, - key = "fundsFoundDate", -) \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/settings/UserInteractingStatusStore.kt b/core/datasource/src/main/java/com/tangem/datasource/local/settings/UserInteractingStatusStore.kt deleted file mode 100644 index 1a1ed3bf03..0000000000 --- a/core/datasource/src/main/java/com/tangem/datasource/local/settings/UserInteractingStatusStore.kt +++ /dev/null @@ -1,21 +0,0 @@ -package com.tangem.datasource.local.settings - -import com.tangem.datasource.local.datastore.BooleanSharedPreferencesDataStore -import com.tangem.datasource.local.datastore.core.KeylessDataStoreDecorator -import kotlinx.coroutines.flow.Flow - -interface UserInteractingStatusStore { - - fun get(): Flow - - suspend fun getSyncOrNull(): Boolean? - - suspend fun store(item: Boolean) -} - -internal class DefaultUserInteractingStatusStore( - store: BooleanSharedPreferencesDataStore, -) : UserInteractingStatusStore, KeylessDataStoreDecorator( - wrappedDataStore = store, - key = "userWasInteractWithRating", -) \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/userwallet/ShouldSaveUserWalletStore.kt b/core/datasource/src/main/java/com/tangem/datasource/local/userwallet/ShouldSaveUserWalletStore.kt deleted file mode 100644 index cbc20ba792..0000000000 --- a/core/datasource/src/main/java/com/tangem/datasource/local/userwallet/ShouldSaveUserWalletStore.kt +++ /dev/null @@ -1,24 +0,0 @@ -package com.tangem.datasource.local.userwallet - -import com.tangem.datasource.local.datastore.BooleanSharedPreferencesDataStore -import com.tangem.datasource.local.datastore.core.KeylessDataStoreDecorator -import kotlinx.coroutines.flow.Flow - -/** -[REDACTED_AUTHOR] - */ -interface ShouldSaveUserWalletStore { - - fun get(): Flow - - suspend fun getSyncOrNull(): Boolean? - - suspend fun store(item: Boolean) -} - -internal class DefaultShouldSaveUserWalletStore( - store: BooleanSharedPreferencesDataStore, -) : ShouldSaveUserWalletStore, KeylessDataStoreDecorator( - wrappedDataStore = store, - key = "saveUserWallets", -) \ No newline at end of file diff --git a/data/app-currency/build.gradle.kts b/data/app-currency/build.gradle.kts index 69613e2e85..ca214f10a9 100644 --- a/data/app-currency/build.gradle.kts +++ b/data/app-currency/build.gradle.kts @@ -23,12 +23,15 @@ dependencies { /** Project - Utils */ implementation(projects.core.utils) + /** AndroidX */ + implementation(deps.androidx.datastore) + /** DI */ implementation(deps.hilt.core) kapt(deps.hilt.kapt) /** Other */ + implementation(deps.jodatime) implementation(deps.kotlin.coroutines) implementation(deps.timber) - implementation(deps.jodatime) } \ No newline at end of file diff --git a/data/app-currency/src/main/kotlin/com/tangem/data/appcurrency/DefaultAppCurrencyRepository.kt b/data/app-currency/src/main/kotlin/com/tangem/data/appcurrency/DefaultAppCurrencyRepository.kt index 520be9c24d..bce54591e8 100644 --- a/data/app-currency/src/main/kotlin/com/tangem/data/appcurrency/DefaultAppCurrencyRepository.kt +++ b/data/app-currency/src/main/kotlin/com/tangem/data/appcurrency/DefaultAppCurrencyRepository.kt @@ -6,12 +6,16 @@ import com.tangem.data.common.cache.CacheRegistry import com.tangem.datasource.api.tangemTech.TangemTechApi import com.tangem.datasource.api.tangemTech.models.CurrenciesResponse import com.tangem.datasource.local.appcurrency.AvailableAppCurrenciesStore -import com.tangem.datasource.local.appcurrency.SelectedAppCurrencyStore +import com.tangem.datasource.local.preferences.AppPreferencesStore +import com.tangem.datasource.local.preferences.PreferencesKeys +import com.tangem.datasource.local.preferences.utils.getObject +import com.tangem.datasource.local.preferences.utils.storeObject import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.appcurrency.repository.AppCurrencyRepository import com.tangem.utils.coroutines.CoroutineDispatcherProvider import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.channelFlow +import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch import kotlinx.coroutines.withContext @@ -19,23 +23,25 @@ import org.joda.time.Duration internal class DefaultAppCurrencyRepository( private val tangemTechApi: TangemTechApi, + private val appPreferencesStore: AppPreferencesStore, private val availableAppCurrenciesStore: AvailableAppCurrenciesStore, - private val selectedAppCurrencyStore: SelectedAppCurrencyStore, private val cacheRegistry: CacheRegistry, private val dispatchers: CoroutineDispatcherProvider, ) : AppCurrencyRepository { private val appCurrencyConverter = AppCurrencyConverter() - override fun getSelectedAppCurrency(): Flow = channelFlow { - launch(dispatchers.io) { - selectedAppCurrencyStore.get() - .map(appCurrencyConverter::convert) - .collect(::send) - } + override fun getSelectedAppCurrency(): Flow { + return channelFlow { + launch { + appPreferencesStore + .getObject(key = PreferencesKeys.SELECTED_APP_CURRENCY_KEY) + .filterNotNull() + .map(appCurrencyConverter::convert) + .collect(::send) + } - withContext(dispatchers.io) { - if (selectedAppCurrencyStore.isEmpty()) { + withContext(dispatchers.io) { fetchDefaultAppCurrency() } } @@ -61,7 +67,10 @@ internal class DefaultAppCurrencyRepository( "Unable to find app currency with provided code: $currencyCode" } - selectedAppCurrencyStore.store(currency) + appPreferencesStore.storeObject( + key = PreferencesKeys.SELECTED_APP_CURRENCY_KEY, + value = currency, + ) } } diff --git a/data/app-currency/src/main/kotlin/com/tangem/data/appcurrency/di/AppCurrencyDataModule.kt b/data/app-currency/src/main/kotlin/com/tangem/data/appcurrency/di/AppCurrencyDataModule.kt index cd80c7c52b..d9cb9be5f7 100644 --- a/data/app-currency/src/main/kotlin/com/tangem/data/appcurrency/di/AppCurrencyDataModule.kt +++ b/data/app-currency/src/main/kotlin/com/tangem/data/appcurrency/di/AppCurrencyDataModule.kt @@ -4,7 +4,7 @@ import com.tangem.data.appcurrency.DefaultAppCurrencyRepository import com.tangem.data.common.cache.CacheRegistry import com.tangem.datasource.api.tangemTech.TangemTechApi import com.tangem.datasource.local.appcurrency.AvailableAppCurrenciesStore -import com.tangem.datasource.local.appcurrency.SelectedAppCurrencyStore +import com.tangem.datasource.local.preferences.AppPreferencesStore import com.tangem.domain.appcurrency.repository.AppCurrencyRepository import com.tangem.utils.coroutines.CoroutineDispatcherProvider import dagger.Module @@ -21,17 +21,17 @@ internal object AppCurrencyDataModule { @Singleton fun provideAppCurrencyRepository( tangemTechApi: TangemTechApi, + appPreferencesStore: AppPreferencesStore, availableAppCurrenciesStore: AvailableAppCurrenciesStore, - selectedAppCurrencyStore: SelectedAppCurrencyStore, cacheRegistry: CacheRegistry, dispatchers: CoroutineDispatcherProvider, ): AppCurrencyRepository { return DefaultAppCurrencyRepository( - tangemTechApi, - availableAppCurrenciesStore, - selectedAppCurrencyStore, - cacheRegistry, - dispatchers, + tangemTechApi = tangemTechApi, + appPreferencesStore = appPreferencesStore, + availableAppCurrenciesStore = availableAppCurrenciesStore, + cacheRegistry = cacheRegistry, + dispatchers = dispatchers, ) } } \ No newline at end of file diff --git a/data/app-theme/build.gradle.kts b/data/app-theme/build.gradle.kts index 7996a21c65..92a28083d7 100644 --- a/data/app-theme/build.gradle.kts +++ b/data/app-theme/build.gradle.kts @@ -27,4 +27,7 @@ dependencies { /** Other */ implementation(deps.kotlin.coroutines) + + /** Local storages */ + implementation(deps.androidx.datastore) } \ No newline at end of file diff --git a/data/app-theme/src/main/kotlin/com/tangem/data/apptheme/DefaultAppThemeModeRepository.kt b/data/app-theme/src/main/kotlin/com/tangem/data/apptheme/DefaultAppThemeModeRepository.kt index 4d8ed9cf4c..8abef1097b 100644 --- a/data/app-theme/src/main/kotlin/com/tangem/data/apptheme/DefaultAppThemeModeRepository.kt +++ b/data/app-theme/src/main/kotlin/com/tangem/data/apptheme/DefaultAppThemeModeRepository.kt @@ -1,35 +1,25 @@ package com.tangem.data.apptheme -import com.tangem.datasource.local.apptheme.AppThemeModeStore +import com.tangem.datasource.local.preferences.AppPreferencesStore +import com.tangem.datasource.local.preferences.PreferencesKeys +import com.tangem.datasource.local.preferences.utils.getObject +import com.tangem.datasource.local.preferences.utils.storeObject import com.tangem.domain.apptheme.model.AppThemeMode import com.tangem.domain.apptheme.repository.AppThemeModeRepository -import com.tangem.utils.coroutines.CoroutineDispatcherProvider -import kotlinx.coroutines.flow.* -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext +import kotlinx.coroutines.flow.Flow internal class DefaultAppThemeModeRepository( - private val appThemeModeStore: AppThemeModeStore, - private val dispatchers: CoroutineDispatcherProvider, + private val appPreferencesStore: AppPreferencesStore, ) : AppThemeModeRepository { override fun getAppThemeMode(): Flow { - return channelFlow { - launch(dispatchers.io) { - if (appThemeModeStore.isEmpty()) { - appThemeModeStore.store(AppThemeMode.DEFAULT) - } - } - - launch(dispatchers.io) { - appThemeModeStore.get().collect(::send) - } - } + return appPreferencesStore.getObject( + key = PreferencesKeys.APP_THEME_MODE_KEY, + default = AppThemeMode.DEFAULT, + ) } override suspend fun changeAppThemeMode(mode: AppThemeMode) { - withContext(dispatchers.io) { - appThemeModeStore.store(mode) - } + appPreferencesStore.storeObject(key = PreferencesKeys.APP_THEME_MODE_KEY, value = mode) } } \ No newline at end of file diff --git a/data/app-theme/src/main/kotlin/com/tangem/data/apptheme/di/AppThemeModeDataModule.kt b/data/app-theme/src/main/kotlin/com/tangem/data/apptheme/di/AppThemeModeDataModule.kt index a360ba19b6..11925c23cd 100644 --- a/data/app-theme/src/main/kotlin/com/tangem/data/apptheme/di/AppThemeModeDataModule.kt +++ b/data/app-theme/src/main/kotlin/com/tangem/data/apptheme/di/AppThemeModeDataModule.kt @@ -1,9 +1,8 @@ package com.tangem.data.apptheme.di import com.tangem.data.apptheme.DefaultAppThemeModeRepository -import com.tangem.datasource.local.apptheme.AppThemeModeStore +import com.tangem.datasource.local.preferences.AppPreferencesStore import com.tangem.domain.apptheme.repository.AppThemeModeRepository -import com.tangem.utils.coroutines.CoroutineDispatcherProvider import dagger.Module import dagger.Provides import dagger.hilt.InstallIn @@ -16,10 +15,7 @@ internal object AppThemeModeDataModule { @Provides @Singleton - fun provideAppThemeModeRepository( - appThemeModeStore: AppThemeModeStore, - dispatchers: CoroutineDispatcherProvider, - ): AppThemeModeRepository { - return DefaultAppThemeModeRepository(appThemeModeStore, dispatchers) + fun provideAppThemeModeRepository(appPreferencesStore: AppPreferencesStore): AppThemeModeRepository { + return DefaultAppThemeModeRepository(appPreferencesStore = appPreferencesStore) } } \ No newline at end of file diff --git a/data/balance-hiding/build.gradle.kts b/data/balance-hiding/build.gradle.kts index 434d3e0a34..84db19b2d7 100644 --- a/data/balance-hiding/build.gradle.kts +++ b/data/balance-hiding/build.gradle.kts @@ -11,10 +11,10 @@ android { } dependencies { + implementation(deps.androidx.datastore) /** DI */ implementation(deps.hilt.android) - kapt(deps.hilt.kapt) implementation(deps.kotlin.coroutines) diff --git a/data/balance-hiding/src/main/java/com/tangem/data/balancehiding/DefaultBalanceHidingRepository.kt b/data/balance-hiding/src/main/java/com/tangem/data/balancehiding/DefaultBalanceHidingRepository.kt index 879bef5f17..948ec336de 100644 --- a/data/balance-hiding/src/main/java/com/tangem/data/balancehiding/DefaultBalanceHidingRepository.kt +++ b/data/balance-hiding/src/main/java/com/tangem/data/balancehiding/DefaultBalanceHidingRepository.kt @@ -1,36 +1,41 @@ package com.tangem.data.balancehiding -import com.tangem.datasource.local.appcurrency.BalanceHidingSettingsStore +import com.tangem.datasource.local.preferences.AppPreferencesStore +import com.tangem.datasource.local.preferences.PreferencesKeys +import com.tangem.datasource.local.preferences.utils.getObject +import com.tangem.datasource.local.preferences.utils.getObjectSyncOrDefault +import com.tangem.datasource.local.preferences.utils.storeObject import com.tangem.domain.balancehiding.BalanceHidingSettings import com.tangem.domain.balancehiding.repositories.BalanceHidingRepository -import com.tangem.utils.coroutines.CoroutineDispatcherProvider import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.distinctUntilChanged -import kotlinx.coroutines.flow.flowOn -import kotlinx.coroutines.flow.onStart -import kotlinx.coroutines.withContext internal class DefaultBalanceHidingRepository( - private val balanceHidingSettingsStore: BalanceHidingSettingsStore, - private val dispatchers: CoroutineDispatcherProvider, + private val appPreferencesStore: AppPreferencesStore, ) : BalanceHidingRepository { override fun getBalanceHidingSettingsFlow(): Flow { - return balanceHidingSettingsStore.get() - .onStart { emit(getBalanceHidingSettings()) } - .flowOn(dispatchers.io) - .distinctUntilChanged() + return appPreferencesStore.getObject( + key = PreferencesKeys.BALANCE_HIDING_SETTINGS_KEY, + default = DEFAULT_HIDING_SETTINGS, + ) } - override suspend fun storeBalanceHidingSettings(balanceHidingSettings: BalanceHidingSettings) { - withContext(dispatchers.io) { - balanceHidingSettingsStore.store(balanceHidingSettings) - } + override suspend fun storeBalanceHidingSettings(isBalanceHidden: BalanceHidingSettings) { + appPreferencesStore.storeObject(key = PreferencesKeys.BALANCE_HIDING_SETTINGS_KEY, value = isBalanceHidden) } override suspend fun getBalanceHidingSettings(): BalanceHidingSettings { - return withContext(dispatchers.io) { - balanceHidingSettingsStore.getSyncOrDefault() - } + return appPreferencesStore.getObjectSyncOrDefault( + key = PreferencesKeys.BALANCE_HIDING_SETTINGS_KEY, + default = DEFAULT_HIDING_SETTINGS, + ) + } + + private companion object { + val DEFAULT_HIDING_SETTINGS = BalanceHidingSettings( + isHidingEnabledInSettings = false, + isBalanceHidden = false, + isBalanceHidingNotificationEnabled = true, + ) } } \ No newline at end of file diff --git a/data/balance-hiding/src/main/java/com/tangem/data/balancehiding/di/BalanceHidingModule.kt b/data/balance-hiding/src/main/java/com/tangem/data/balancehiding/di/BalanceHidingModule.kt index 86b293b9fe..f83fac4932 100644 --- a/data/balance-hiding/src/main/java/com/tangem/data/balancehiding/di/BalanceHidingModule.kt +++ b/data/balance-hiding/src/main/java/com/tangem/data/balancehiding/di/BalanceHidingModule.kt @@ -3,16 +3,15 @@ package com.tangem.data.balancehiding.di import android.content.Context import com.tangem.data.balancehiding.DefaultBalanceHidingRepository import com.tangem.data.balancehiding.DefaultDeviceFlipDetector -import com.tangem.datasource.local.appcurrency.BalanceHidingSettingsStore +import com.tangem.datasource.local.preferences.AppPreferencesStore import com.tangem.domain.balancehiding.DeviceFlipDetector import com.tangem.domain.balancehiding.repositories.BalanceHidingRepository -import com.tangem.utils.coroutines.CoroutineDispatcherProvider 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 -import dagger.hilt.android.qualifiers.ApplicationContext @Module @InstallIn(SingletonComponent::class) @@ -20,14 +19,8 @@ internal object BalanceHidingModule { @Provides @Singleton - fun provideBalanceHidingRepository( - balanceHidingSettingsStore: BalanceHidingSettingsStore, - dispatchers: CoroutineDispatcherProvider, - ): BalanceHidingRepository { - return DefaultBalanceHidingRepository( - balanceHidingSettingsStore = balanceHidingSettingsStore, - dispatchers = dispatchers, - ) + fun provideBalanceHidingRepository(appPreferencesStore: AppPreferencesStore): BalanceHidingRepository { + return DefaultBalanceHidingRepository(appPreferencesStore = appPreferencesStore) } @Provides diff --git a/data/card/build.gradle.kts b/data/card/build.gradle.kts index c7a692bd7e..6015c1ed3a 100644 --- a/data/card/build.gradle.kts +++ b/data/card/build.gradle.kts @@ -11,6 +11,8 @@ android { } dependencies { + implementation(deps.androidx.datastore) + implementation(deps.hilt.android) kapt(deps.hilt.kapt) diff --git a/data/card/src/main/java/com/tangem/data/card/DefaultCardRepository.kt b/data/card/src/main/java/com/tangem/data/card/DefaultCardRepository.kt index 6f4a1fb553..7f0a56fd9a 100644 --- a/data/card/src/main/java/com/tangem/data/card/DefaultCardRepository.kt +++ b/data/card/src/main/java/com/tangem/data/card/DefaultCardRepository.kt @@ -1,43 +1,37 @@ package com.tangem.data.card import com.tangem.datasource.local.card.UsedCardInfo -import com.tangem.datasource.local.card.UsedCardsStore +import com.tangem.datasource.local.preferences.AppPreferencesStore +import com.tangem.datasource.local.preferences.PreferencesKeys +import com.tangem.datasource.local.preferences.utils.getObject import com.tangem.domain.card.repository.CardRepository -import com.tangem.utils.coroutines.CoroutineDispatcherProvider import com.tangem.utils.extensions.addOrReplace import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.channelFlow -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext +import kotlinx.coroutines.flow.map internal class DefaultCardRepository( - private val usedCardsStore: UsedCardsStore, - private val dispatchers: CoroutineDispatcherProvider, + private val appPreferencesStore: AppPreferencesStore, ) : CardRepository { override fun wasCardScanned(cardId: String): Flow { - return channelFlow { - launch(dispatchers.io) { - usedCardsStore.get() - .collect { savedCards -> - send(element = savedCards.any { it.cardId == cardId }) - } + return appPreferencesStore.getObject>(key = PreferencesKeys.USED_CARDS_INFO_KEY) + .map { savedCards -> + savedCards?.any { it.cardId == cardId } ?: false } - - withContext(dispatchers.io) { - if (usedCardsStore.getSyncOrNull() == null) { - send(element = false) - } - } - } } override suspend fun setCardWasScanned(cardId: String) { - withContext(dispatchers.io) { - usedCardsStore.store( - item = usedCardsStore.getSyncOrNull() - ?.updateCard(cardId) - ?: listOf(UsedCardInfo(cardId = cardId, isScanned = true)), + appPreferencesStore.editData { mutablePreferences -> + val usedCards: List? = mutablePreferences.getObject( + key = PreferencesKeys.USED_CARDS_INFO_KEY, + ) + + val updatedUsedCards = usedCards?.updateCard(cardId) + ?: listOf(UsedCardInfo(cardId = cardId, isScanned = true)) + + mutablePreferences.setObject( + key = PreferencesKeys.USED_CARDS_INFO_KEY, + value = updatedUsedCards, ) } } diff --git a/data/card/src/main/java/com/tangem/data/card/di/CardDataModule.kt b/data/card/src/main/java/com/tangem/data/card/di/CardDataModule.kt index 0c2cfdecbf..a526073cd2 100644 --- a/data/card/src/main/java/com/tangem/data/card/di/CardDataModule.kt +++ b/data/card/src/main/java/com/tangem/data/card/di/CardDataModule.kt @@ -4,10 +4,9 @@ import com.tangem.data.card.DefaultCardRepository import com.tangem.data.card.DefaultCardSdkConfigRepository import com.tangem.data.card.sdk.CardSdkProvider import com.tangem.data.source.preferences.PreferencesDataSource -import com.tangem.datasource.local.card.UsedCardsStore +import com.tangem.datasource.local.preferences.AppPreferencesStore import com.tangem.domain.card.repository.CardRepository import com.tangem.domain.card.repository.CardSdkConfigRepository -import com.tangem.utils.coroutines.CoroutineDispatcherProvider import dagger.Module import dagger.Provides import dagger.hilt.InstallIn @@ -32,10 +31,7 @@ internal object CardDataModule { @Provides @Singleton - fun provideCardRepository( - usedCardsStore: UsedCardsStore, - dispatchers: CoroutineDispatcherProvider, - ): CardRepository { - return DefaultCardRepository(usedCardsStore = usedCardsStore, dispatchers = dispatchers) + fun provideCardRepository(appPreferencesStore: AppPreferencesStore): CardRepository { + return DefaultCardRepository(appPreferencesStore = appPreferencesStore) } } \ No newline at end of file diff --git a/data/settings/build.gradle.kts b/data/settings/build.gradle.kts index e59302acd9..5daa9b86f0 100644 --- a/data/settings/build.gradle.kts +++ b/data/settings/build.gradle.kts @@ -12,18 +12,19 @@ android { dependencies { + implementation(projects.core.datasource) + implementation(projects.core.utils) + + implementation(projects.data.source.preferences) + + implementation(projects.domain.balanceHiding.models) + implementation(projects.domain.settings) + + implementation(deps.androidx.datastore) + /** DI */ implementation(deps.hilt.android) - kapt(deps.hilt.kapt) implementation(deps.kotlin.coroutines) - - implementation(projects.core.utils) - implementation(projects.core.datasource) - - implementation(projects.domain.settings) - implementation(projects.domain.balanceHiding.models) - - implementation(projects.data.source.preferences) } diff --git a/data/settings/src/main/java/com/tangem/data/settings/DefaultAppRatingRepository.kt b/data/settings/src/main/java/com/tangem/data/settings/DefaultAppRatingRepository.kt index e7bc353372..78e99623f1 100644 --- a/data/settings/src/main/java/com/tangem/data/settings/DefaultAppRatingRepository.kt +++ b/data/settings/src/main/java/com/tangem/data/settings/DefaultAppRatingRepository.kt @@ -1,68 +1,42 @@ package com.tangem.data.settings -import com.tangem.datasource.local.settings.AppLaunchCountStore -import com.tangem.datasource.local.settings.AppRatingShowingCountStore -import com.tangem.datasource.local.settings.FundsFoundDateInMillisStore -import com.tangem.datasource.local.settings.UserInteractingStatusStore +import androidx.datastore.preferences.core.MutablePreferences +import androidx.datastore.preferences.core.edit +import com.tangem.datasource.local.preferences.AppPreferencesStore +import com.tangem.datasource.local.preferences.PreferencesKeys +import com.tangem.datasource.local.preferences.utils.get import com.tangem.domain.settings.repositories.AppRatingRepository -import com.tangem.utils.coroutines.CoroutineDispatcherProvider import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.withContext import java.util.Calendar internal class DefaultAppRatingRepository( - private val fundsFoundDateInMillisStore: FundsFoundDateInMillisStore, - private val appLaunchCountStore: AppLaunchCountStore, - private val appRatingShowingCountStore: AppRatingShowingCountStore, - private val userInteractingStatusStore: UserInteractingStatusStore, - private val dispatchers: CoroutineDispatcherProvider, + private val appPreferencesStore: AppPreferencesStore, ) : AppRatingRepository { - override suspend fun initialize() { - fundsFoundDateInMillisStore.getSyncOrNull() - ?: fundsFoundDateInMillisStore.store(item = FUNDS_FOUND_DATE_UNDEFINED) - - appLaunchCountStore.getSyncOrNull() - ?: appLaunchCountStore.store(item = DEFAULT_APP_LAUNCH_COUNT) - - appRatingShowingCountStore.getSyncOrNull() - ?: appRatingShowingCountStore.store(item = FIRST_SHOWING_COUNT) - - userInteractingStatusStore.getSyncOrNull() - ?: userInteractingStatusStore.store(item = false) - } - override suspend fun setWalletWithFundsFound() { - withContext(dispatchers.io) { - val foundDate = fundsFoundDateInMillisStore.getSyncOrNull() - if (foundDate != null && foundDate != FUNDS_FOUND_DATE_UNDEFINED) return@withContext + appPreferencesStore.edit { mutablePreferences -> + val foundDate = mutablePreferences[PreferencesKeys.FUNDS_FOUND_DATE_KEY] + if (foundDate != null && foundDate != FUNDS_FOUND_DATE_UNDEFINED) return@edit - fundsFoundDateInMillisStore.store(item = Calendar.getInstance().timeInMillis) + mutablePreferences[PreferencesKeys.FUNDS_FOUND_DATE_KEY] = Calendar.getInstance().timeInMillis - val appLaunchCount = appLaunchCountStore.getSyncOrNull().let { count -> - if (count == null) { - appLaunchCountStore.store(item = DEFAULT_APP_LAUNCH_COUNT) - DEFAULT_APP_LAUNCH_COUNT - } else { - count - } - } - - appRatingShowingCountStore.store(item = appLaunchCount + FIRST_SHOWING_COUNT) - - userInteractingStatusStore.getSyncOrNull() - ?: userInteractingStatusStore.store(item = false) + val appLaunchCount = mutablePreferences[PreferencesKeys.APP_LAUNCH_COUNT_KEY] ?: DEFAULT_APP_LAUNCH_COUNT + mutablePreferences[PreferencesKeys.SHOW_RATING_DIALOG_AT_LAUNCH_COUNT_KEY] = + appLaunchCount + FIRST_SHOWING_COUNT } } override fun isReadyToShow(): Flow { // TODO: [REDACTED_JIRA] return combine( - userInteractingStatusStore.get(), - appRatingShowingCountStore.get(), - appLaunchCountStore.get(), - fundsFoundDateInMillisStore.get(), + appPreferencesStore.get(key = PreferencesKeys.USER_WAS_INTERACT_WITH_RATING_KEY, default = false), + appPreferencesStore.get( + key = PreferencesKeys.SHOW_RATING_DIALOG_AT_LAUNCH_COUNT_KEY, + default = FIRST_SHOWING_COUNT, + ), + appPreferencesStore.get(key = PreferencesKeys.APP_LAUNCH_COUNT_KEY, default = DEFAULT_APP_LAUNCH_COUNT), + appPreferencesStore.get(key = PreferencesKeys.FUNDS_FOUND_DATE_KEY, default = FUNDS_FOUND_DATE_UNDEFINED), ) { isInteracting, ratingShowingCount, appLaunchCount, fundsFoundDate -> if (!isInteracting) { val diff = Calendar.getInstance().timeInMillis - fundsFoundDate @@ -77,20 +51,22 @@ internal class DefaultAppRatingRepository( } override suspend fun remindLater() { - appLaunchCountStore.getSyncOrNull()?.let { - updateNextShowing(at = it + DEFER_SHOWING_COUNT) + appPreferencesStore.edit { mutablePreferences -> + mutablePreferences[PreferencesKeys.APP_LAUNCH_COUNT_KEY]?.let { + mutablePreferences.updateNextShowing(it + DEFER_SHOWING_COUNT) + } } } override suspend fun setNeverToShow() { - updateNextShowing(at = Int.MAX_VALUE) + appPreferencesStore.edit { mutablePreferences -> + mutablePreferences.updateNextShowing(at = Int.MAX_VALUE) + } } - private suspend fun updateNextShowing(at: Int) { - withContext(dispatchers.io) { - appRatingShowingCountStore.store(item = at) - userInteractingStatusStore.store(item = true) - } + private fun MutablePreferences.updateNextShowing(at: Int) { + this[PreferencesKeys.SHOW_RATING_DIALOG_AT_LAUNCH_COUNT_KEY] = at + this[PreferencesKeys.USER_WAS_INTERACT_WITH_RATING_KEY] = true } private companion object { diff --git a/data/settings/src/main/java/com/tangem/data/settings/di/SettingsDataModule.kt b/data/settings/src/main/java/com/tangem/data/settings/di/SettingsDataModule.kt index 68355c5d61..254235cf84 100644 --- a/data/settings/src/main/java/com/tangem/data/settings/di/SettingsDataModule.kt +++ b/data/settings/src/main/java/com/tangem/data/settings/di/SettingsDataModule.kt @@ -3,10 +3,7 @@ package com.tangem.data.settings.di import com.tangem.data.settings.DefaultAppRatingRepository import com.tangem.data.settings.DefaultSettingsRepository import com.tangem.data.source.preferences.PreferencesDataSource -import com.tangem.datasource.local.settings.AppLaunchCountStore -import com.tangem.datasource.local.settings.AppRatingShowingCountStore -import com.tangem.datasource.local.settings.FundsFoundDateInMillisStore -import com.tangem.datasource.local.settings.UserInteractingStatusStore +import com.tangem.datasource.local.preferences.AppPreferencesStore import com.tangem.domain.settings.repositories.AppRatingRepository import com.tangem.domain.settings.repositories.SettingsRepository import com.tangem.utils.coroutines.CoroutineDispatcherProvider @@ -34,19 +31,7 @@ internal object SettingsDataModule { @Provides @Singleton - fun provideAppRatingRepository( - fundsFoundDateInMillisStore: FundsFoundDateInMillisStore, - appLaunchCountStore: AppLaunchCountStore, - appRatingShowingCountStore: AppRatingShowingCountStore, - userInteractingStatusStore: UserInteractingStatusStore, - dispatchers: CoroutineDispatcherProvider, - ): AppRatingRepository { - return DefaultAppRatingRepository( - fundsFoundDateInMillisStore = fundsFoundDateInMillisStore, - appLaunchCountStore = appLaunchCountStore, - appRatingShowingCountStore = appRatingShowingCountStore, - userInteractingStatusStore = userInteractingStatusStore, - dispatchers = dispatchers, - ) + fun provideAppRatingRepository(appPreferencesStore: AppPreferencesStore): AppRatingRepository { + return DefaultAppRatingRepository(appPreferencesStore = appPreferencesStore) } } \ No newline at end of file diff --git a/data/tokens/build.gradle.kts b/data/tokens/build.gradle.kts index d36f42d591..88d7471830 100644 --- a/data/tokens/build.gradle.kts +++ b/data/tokens/build.gradle.kts @@ -32,6 +32,9 @@ dependencies { implementation(deps.tangem.blockchain) implementation(deps.tangem.card.core) + /** AndroidX */ + implementation(deps.androidx.datastore) + /** DI */ implementation(deps.hilt.core) kapt(deps.hilt.kapt) diff --git a/data/tokens/src/main/kotlin/com/tangem/data/tokens/di/TokensDataModule.kt b/data/tokens/src/main/kotlin/com/tangem/data/tokens/di/TokensDataModule.kt index b683931af9..1b8b65138e 100644 --- a/data/tokens/src/main/kotlin/com/tangem/data/tokens/di/TokensDataModule.kt +++ b/data/tokens/src/main/kotlin/com/tangem/data/tokens/di/TokensDataModule.kt @@ -7,8 +7,8 @@ import com.tangem.data.tokens.repository.DefaultNetworksRepository import com.tangem.data.tokens.repository.DefaultQuotesRepository import com.tangem.datasource.api.express.TangemExpressApi import com.tangem.datasource.api.tangemTech.TangemTechApi -import com.tangem.datasource.local.appcurrency.SelectedAppCurrencyStore import com.tangem.datasource.local.network.NetworksStatusesStore +import com.tangem.datasource.local.preferences.AppPreferencesStore import com.tangem.datasource.local.quote.QuotesStore import com.tangem.datasource.local.token.AssetsStore import com.tangem.datasource.local.token.UserTokensStore @@ -55,15 +55,15 @@ internal object TokensDataModule { @Singleton fun provideQuotesRepository( tangemTechApi: TangemTechApi, + appPreferencesStore: AppPreferencesStore, quotesStore: QuotesStore, - selectedAppCurrencyStore: SelectedAppCurrencyStore, cacheRegistry: CacheRegistry, dispatchers: CoroutineDispatcherProvider, ): QuotesRepository { return DefaultQuotesRepository( tangemTechApi = tangemTechApi, + appPreferencesStore = appPreferencesStore, quotesStore = quotesStore, - selectedAppCurrencyStore = selectedAppCurrencyStore, cacheRegistry = cacheRegistry, dispatchers = dispatchers, ) diff --git a/data/tokens/src/main/kotlin/com/tangem/data/tokens/repository/DefaultQuotesRepository.kt b/data/tokens/src/main/kotlin/com/tangem/data/tokens/repository/DefaultQuotesRepository.kt index 37a89fafd0..cdd04c62ce 100644 --- a/data/tokens/src/main/kotlin/com/tangem/data/tokens/repository/DefaultQuotesRepository.kt +++ b/data/tokens/src/main/kotlin/com/tangem/data/tokens/repository/DefaultQuotesRepository.kt @@ -5,7 +5,12 @@ import com.tangem.data.common.cache.CacheRegistry import com.tangem.data.tokens.utils.QuotesConverter import com.tangem.data.tokens.utils.QuotesUnsupportedCurrenciesIdAdapter import com.tangem.datasource.api.tangemTech.TangemTechApi -import com.tangem.datasource.local.appcurrency.SelectedAppCurrencyStore +import com.tangem.datasource.api.tangemTech.models.CurrenciesResponse +import com.tangem.datasource.local.* +import com.tangem.datasource.local.preferences.AppPreferencesStore +import com.tangem.datasource.local.preferences.PreferencesKeys +import com.tangem.datasource.local.preferences.utils.getObject +import com.tangem.datasource.local.preferences.utils.getObjectSyncOrNull import com.tangem.datasource.local.quote.QuotesStore import com.tangem.domain.tokens.model.CryptoCurrency import com.tangem.domain.tokens.model.Quote @@ -17,8 +22,8 @@ import kotlinx.coroutines.withContext internal class DefaultQuotesRepository( private val tangemTechApi: TangemTechApi, + private val appPreferencesStore: AppPreferencesStore, private val quotesStore: QuotesStore, - private val selectedAppCurrencyStore: SelectedAppCurrencyStore, private val cacheRegistry: CacheRegistry, private val dispatchers: CoroutineDispatcherProvider, ) : QuotesRepository { @@ -31,8 +36,11 @@ internal class DefaultQuotesRepository( @OptIn(ExperimentalCoroutinesApi::class) override fun getQuotesUpdates(currenciesIds: Set): Flow> { - return selectedAppCurrencyStore.get() + return appPreferencesStore.getObject( + key = PreferencesKeys.SELECTED_APP_CURRENCY_KEY, + ) .distinctUntilChanged() + .filterNotNull() .flatMapLatest { appCurrency -> fetchExpiredQuotes(currenciesIds, appCurrency.id, refresh = false) @@ -44,13 +52,16 @@ internal class DefaultQuotesRepository( override suspend fun getQuotesSync(currenciesIds: Set, refresh: Boolean): Set { return withContext(dispatchers.io) { - val selectedAppCurrency = requireNotNull(selectedAppCurrencyStore.getSyncOrNull()) { - "Unable to get selected application currency to update quotes" - } + val selectedAppCurrency = requireNotNull( + value = appPreferencesStore.getObjectSyncOrNull( + key = PreferencesKeys.SELECTED_APP_CURRENCY_KEY, + ), + lazyMessage = { "Unable to get selected application currency to update quotes" }, + ) fetchExpiredQuotes(currenciesIds, selectedAppCurrency.id, refresh) - val quotes = quotesStore.get(currenciesIds).first() + val quotes = quotesStore.getSync(currenciesIds) quotesConverter.convertSet(quotes) } diff --git a/data/wallets/build.gradle.kts b/data/wallets/build.gradle.kts index f39f9b3c1e..c1a86f55ca 100644 --- a/data/wallets/build.gradle.kts +++ b/data/wallets/build.gradle.kts @@ -13,10 +13,12 @@ android { dependencies { implementation(projects.core.datasource) implementation(projects.core.utils) - implementation(projects.data.source.preferences) implementation(projects.domain.wallets) /** DI */ implementation(deps.hilt.android) kapt(deps.hilt.kapt) + + /** Local storages */ + implementation(deps.androidx.datastore) } \ No newline at end of file diff --git a/data/wallets/src/main/java/com/tangem/data/wallets/DefaultWalletsRepository.kt b/data/wallets/src/main/java/com/tangem/data/wallets/DefaultWalletsRepository.kt index af326a1a45..2cc72cd098 100644 --- a/data/wallets/src/main/java/com/tangem/data/wallets/DefaultWalletsRepository.kt +++ b/data/wallets/src/main/java/com/tangem/data/wallets/DefaultWalletsRepository.kt @@ -1,29 +1,26 @@ package com.tangem.data.wallets -import com.tangem.datasource.local.userwallet.ShouldSaveUserWalletStore +import com.tangem.datasource.local.preferences.AppPreferencesStore +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.domain.wallets.repository.WalletsRepository -import com.tangem.utils.coroutines.CoroutineDispatcherProvider import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.withContext internal class DefaultWalletsRepository( - private val shouldSaveUserWalletStore: ShouldSaveUserWalletStore, - private val dispatchers: CoroutineDispatcherProvider, + private val appPreferencesStore: AppPreferencesStore, ) : WalletsRepository { - override suspend fun initialize() { - withContext(dispatchers.io) { - shouldSaveUserWalletStore.getSyncOrNull() ?: shouldSaveUserWalletStore.store(item = false) - } - } - override suspend fun shouldSaveUserWalletsSync(): Boolean { - return withContext(dispatchers.io) { shouldSaveUserWalletStore.getSyncOrNull() ?: false } + return appPreferencesStore.getSyncOrDefault(key = PreferencesKeys.SAVE_USER_WALLETS_KEY, default = false) } - override fun shouldSaveUserWallets(): Flow = shouldSaveUserWalletStore.get() + override fun shouldSaveUserWallets(): Flow { + return appPreferencesStore.get(key = PreferencesKeys.SAVE_USER_WALLETS_KEY, default = false) + } override suspend fun saveShouldSaveUserWallets(item: Boolean) { - withContext(dispatchers.io) { shouldSaveUserWalletStore.store(item = item) } + appPreferencesStore.store(key = PreferencesKeys.SAVE_USER_WALLETS_KEY, value = item) } } \ No newline at end of file diff --git a/data/wallets/src/main/java/com/tangem/data/wallets/di/WalletsDataModule.kt b/data/wallets/src/main/java/com/tangem/data/wallets/di/WalletsDataModule.kt index 80ff2c2567..29cd5fb5c0 100644 --- a/data/wallets/src/main/java/com/tangem/data/wallets/di/WalletsDataModule.kt +++ b/data/wallets/src/main/java/com/tangem/data/wallets/di/WalletsDataModule.kt @@ -1,9 +1,8 @@ package com.tangem.data.wallets.di import com.tangem.data.wallets.DefaultWalletsRepository -import com.tangem.datasource.local.userwallet.ShouldSaveUserWalletStore +import com.tangem.datasource.local.preferences.AppPreferencesStore import com.tangem.domain.wallets.repository.WalletsRepository -import com.tangem.utils.coroutines.CoroutineDispatcherProvider import dagger.Module import dagger.Provides import dagger.hilt.InstallIn @@ -12,17 +11,11 @@ import javax.inject.Singleton @Module @InstallIn(SingletonComponent::class) -object WalletsDataModule { +internal object WalletsDataModule { @Provides @Singleton - fun providesWalletsRepository( - shouldSaveUserWalletStore: ShouldSaveUserWalletStore, - coroutineDispatcherProvider: CoroutineDispatcherProvider, - ): WalletsRepository { - return DefaultWalletsRepository( - shouldSaveUserWalletStore = shouldSaveUserWalletStore, - dispatchers = coroutineDispatcherProvider, - ) + fun providesWalletsRepository(appPreferencesStore: AppPreferencesStore): WalletsRepository { + return DefaultWalletsRepository(appPreferencesStore = appPreferencesStore) } } \ No newline at end of file diff --git a/domain/settings/src/main/java/com/tangem/domain/settings/repositories/AppRatingRepository.kt b/domain/settings/src/main/java/com/tangem/domain/settings/repositories/AppRatingRepository.kt index e10dc94046..33772c3cf6 100644 --- a/domain/settings/src/main/java/com/tangem/domain/settings/repositories/AppRatingRepository.kt +++ b/domain/settings/src/main/java/com/tangem/domain/settings/repositories/AppRatingRepository.kt @@ -4,9 +4,6 @@ import kotlinx.coroutines.flow.Flow interface AppRatingRepository { - // FIXME: We must to initialize all stores before calling [isReadyToShow], otherwise flow will not emit data - suspend fun initialize() - suspend fun setWalletWithFundsFound() fun isReadyToShow(): Flow diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCryptoCurrencyStatusUseCase.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCryptoCurrencyStatusesSyncUseCase.kt similarity index 51% rename from domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCryptoCurrencyStatusUseCase.kt rename to domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCryptoCurrencyStatusesSyncUseCase.kt index d917a747c7..cdf58b3080 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCryptoCurrencyStatusUseCase.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCryptoCurrencyStatusesSyncUseCase.kt @@ -4,24 +4,21 @@ import arrow.core.Either import com.tangem.domain.tokens.error.TokenListError import com.tangem.domain.tokens.error.mapper.mapToTokenListError import com.tangem.domain.tokens.model.CryptoCurrencyStatus -import com.tangem.domain.tokens.model.TokenList import com.tangem.domain.tokens.operations.CurrenciesStatusesOperations -import com.tangem.domain.tokens.operations.TokenListOperations import com.tangem.domain.tokens.repository.CurrenciesRepository import com.tangem.domain.tokens.repository.NetworksRepository import com.tangem.domain.tokens.repository.QuotesRepository import com.tangem.domain.wallets.models.UserWalletId import com.tangem.utils.coroutines.CoroutineDispatcherProvider -import kotlinx.coroutines.flow.* -class GetCryptoCurrencyStatusUseCase( +class GetCryptoCurrencyStatusesSyncUseCase( internal val currenciesRepository: CurrenciesRepository, internal val quotesRepository: QuotesRepository, internal val networksRepository: NetworksRepository, internal val dispatchers: CoroutineDispatcherProvider, ) { - operator fun invoke(userWalletId: UserWalletId): Flow>> { + suspend operator fun invoke(userWalletId: UserWalletId): Either> { val operations = CurrenciesStatusesOperations( userWalletId = userWalletId, currenciesRepository = currenciesRepository, @@ -29,25 +26,7 @@ class GetCryptoCurrencyStatusUseCase( networksRepository = networksRepository, ) - return operations.getCurrenciesStatusesFlow() - .map { maybeCurrenciesStatuses -> - maybeCurrenciesStatuses.mapLeft(CurrenciesStatusesOperations.Error::mapToTokenListError) - } - } - - @Suppress("UnusedPrivateMember") - private fun createTokenList( - userWalletId: UserWalletId, - tokens: List, - ): Flow> { - val operations = TokenListOperations( - userWalletId = userWalletId, - tokens = tokens, - currenciesRepository = currenciesRepository, - ) - - return operations.getTokenListFlow().map { maybeTokenList -> - maybeTokenList.mapLeft(TokenListOperations.Error::mapToTokenListError) - } + return operations.getCurrenciesStatusesSync() + .mapLeft { error -> error.mapToTokenListError() } } } \ No newline at end of file diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/CurrenciesStatusesOperations.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/CurrenciesStatusesOperations.kt index 9bce6f0d35..3ce6112296 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/CurrenciesStatusesOperations.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/CurrenciesStatusesOperations.kt @@ -67,6 +67,24 @@ internal class CurrenciesStatusesOperations( } } + suspend fun getCurrenciesStatusesSync(): Either> { + return either { + catch( + block = { + val nonEmptyCurrencies = + currenciesRepository.getMultiCurrencyWalletCurrenciesSync(userWalletId).toNonEmptyListOrNull() + ?: return emptyList().right() + val (networks, currenciesIds) = getIds(nonEmptyCurrencies) + val quotes = quotesRepository.getQuotesSync(currenciesIds, false).right() + val networkStatuses = + networksRepository.getNetworkStatusesSync(userWalletId, networks, false).right() + return createCurrenciesStatuses(nonEmptyCurrencies, quotes, networkStatuses) + }, + catch = { raise(Error.DataError(it)) }, + ) + } + } + fun getCardCurrenciesStatusesFlow(): Flow>> { return flow { val nonEmptyCurrencies = recover( diff --git a/domain/wallets/src/main/java/com/tangem/domain/wallets/repository/WalletsRepository.kt b/domain/wallets/src/main/java/com/tangem/domain/wallets/repository/WalletsRepository.kt index 6190b6d2e0..003f9b9ff2 100644 --- a/domain/wallets/src/main/java/com/tangem/domain/wallets/repository/WalletsRepository.kt +++ b/domain/wallets/src/main/java/com/tangem/domain/wallets/repository/WalletsRepository.kt @@ -4,8 +4,6 @@ import kotlinx.coroutines.flow.Flow interface WalletsRepository { - suspend fun initialize() - suspend fun shouldSaveUserWalletsSync(): Boolean fun shouldSaveUserWallets(): Flow diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/domain/SendRecipientListContent.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/domain/SendRecipientListContent.kt index 6cb3516497..7f7216e6e3 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/domain/SendRecipientListContent.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/domain/SendRecipientListContent.kt @@ -17,5 +17,6 @@ internal sealed class SendRecipientListContent { data class Wallets( val list: PersistentList, + val isWalletsOnly: Boolean, ) : SendRecipientListContent() } \ No newline at end of file diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendStateFactory.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendStateFactory.kt index 3bb47678a9..38583d0676 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendStateFactory.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendStateFactory.kt @@ -105,10 +105,15 @@ internal class SendStateFactory( //endregion //region recipient - fun onLoadedRecipientList(wallets: List, txHistory: PagingData) { + fun onLoadedRecipientList( + wallets: List, + txHistory: PagingData, + txHistoryCount: Int, + ) { recipientListStateConverter.convert( wallets = wallets, txHistory = txHistory, + txHistoryCount = txHistoryCount, ) } diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/recipient/SendRecipientListConverter.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/recipient/SendRecipientListConverter.kt index da8a97622d..8fd734e781 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/recipient/SendRecipientListConverter.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/recipient/SendRecipientListConverter.kt @@ -22,7 +22,7 @@ internal class SendRecipientListConverter( private val cryptoCurrencyStatusProvider: Provider, ) { - fun convert(wallets: List, txHistory: PagingData) { + fun convert(wallets: List, txHistory: PagingData, txHistoryCount: Int) { val filteredWallets = wallets.filterNotNull() .groupBy { item -> item.name } .values.flatten() @@ -32,49 +32,58 @@ internal class SendRecipientListConverter( ) } + val walletsItem = getWalletItems(filteredWallets, txHistoryCount) + currentStateProvider().recipientList.update { - txHistory.filter { item -> - val isTransfer = item.type == TxHistoryItem.TransactionType.Transfer - val isNotContract = item.interactionAddressType is TxHistoryItem.InteractionAddressType.User - val isSingleAddress = if (item.isOutgoing) { - item.destinationType is TxHistoryItem.DestinationType.Single - } else { - item.sourceType is TxHistoryItem.SourceType.Single - } - isTransfer && isSingleAddress && isNotContract - }.map { tx -> - SendRecipientListContent.Item( - id = tx.txHash, - title = tx.extractAddress(), - subtitle = TextReference.Str(tx.getAmount()), - info = tx.extractTimestamp(), - subtitleIconRes = tx.extractIconRes(), - ) - }.insertWallets(filteredWallets) + if (txHistoryCount == 0) { + PagingData.from(listOf(walletsItem)) + } else { + txHistory.filter { item -> + val isTransfer = item.type == TxHistoryItem.TransactionType.Transfer + val isNotContract = item.interactionAddressType is TxHistoryItem.InteractionAddressType.User + val isSingleAddress = if (item.isOutgoing) { + item.destinationType is TxHistoryItem.DestinationType.Single + } else { + item.sourceType is TxHistoryItem.SourceType.Single + } + isTransfer && isSingleAddress && isNotContract + }.map { tx -> + SendRecipientListContent.Item( + id = tx.txHash, + title = tx.extractAddress(), + subtitle = TextReference.Str(tx.getAmount()), + info = tx.extractTimestamp(), + subtitleIconRes = tx.extractIconRes(), + ) + }.insertWallets(walletsItem) + } } } private fun PagingData.insertWallets( - wallets: List, + wallets: SendRecipientListContent.Wallets, ): PagingData { return insertSeparators(terminalSeparatorType = TerminalSeparatorType.SOURCE_COMPLETE) { before, after -> return@insertSeparators when { - before == null && after is SendRecipientListContent.Item -> { - SendRecipientListContent.Wallets( - wallets.map { - SendRecipientListContent.Item( - id = it.address, - title = TextReference.Str(it.address), - subtitle = TextReference.Str(it.name), - ) - }.toPersistentList(), - ) - } + before == null && after is SendRecipientListContent.Item -> wallets else -> null } } } + private fun getWalletItems(wallets: List, txHistoryCount: Int): SendRecipientListContent.Wallets { + return SendRecipientListContent.Wallets( + wallets.map { + SendRecipientListContent.Item( + id = it.address, + title = TextReference.Str(it.address), + subtitle = TextReference.Str(it.name), + ) + }.toPersistentList(), + isWalletsOnly = txHistoryCount == 0, + ) + } + private fun TxHistoryItem.extractAddress(): TextReference = if (isOutgoing) { when (val destination = destinationType) { is TxHistoryItem.DestinationType.Multiple -> TextReference.Res( diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/recipient/SendRecipientContent.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/recipient/SendRecipientContent.kt index ada2667527..30563155b4 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/recipient/SendRecipientContent.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/recipient/SendRecipientContent.kt @@ -80,6 +80,7 @@ internal fun SendRecipientContent( } } +@Suppress("LongMethod") @OptIn(ExperimentalFoundationApi::class) private fun LazyListScope.recipientListItem( recipientList: LazyPagingItems, @@ -106,10 +107,17 @@ private fun LazyListScope.recipientListItem( .padding(top = TangemTheme.dimens.spacing20) .then( if (index == 0) { + val bottomRadius = if (item.isWalletsOnly) { + TangemTheme.dimens.radius12 + } else { + TangemTheme.dimens.radius0 + } Modifier.clip( RoundedCornerShape( topEnd = TangemTheme.dimens.radius12, topStart = TangemTheme.dimens.radius12, + bottomStart = bottomRadius, + bottomEnd = bottomRadius, ), ) } else { @@ -182,18 +190,25 @@ private fun RecipientWalletListItem( onClick = { clickIntents.onRecipientAddressValueChange(title) }, ) } - Text( - text = stringResource(R.string.send_recent_transactions), - style = TangemTheme.typography.subtitle2, - color = TangemTheme.colors.text.tertiary, - modifier = Modifier - .fillMaxWidth() - .padding( - top = TangemTheme.dimens.spacing8, - bottom = TangemTheme.dimens.spacing8, - start = TangemTheme.dimens.spacing12, - end = TangemTheme.dimens.spacing12, - ), - ) + if (!item.isWalletsOnly) { + val topPadding = if (item.list.isNotEmpty()) { + TangemTheme.dimens.spacing8 + } else { + TangemTheme.dimens.spacing0 + } + Text( + text = stringResource(R.string.send_recent_transactions), + style = TangemTheme.typography.subtitle2, + color = TangemTheme.colors.text.tertiary, + modifier = Modifier + .fillMaxWidth() + .padding( + top = topPadding, + bottom = TangemTheme.dimens.spacing8, + start = TangemTheme.dimens.spacing12, + end = TangemTheme.dimens.spacing12, + ), + ) + } } } \ No newline at end of file diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/viewmodel/SendViewModel.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/viewmodel/SendViewModel.kt index 3e8bc7477f..02f2caefc6 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/viewmodel/SendViewModel.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/viewmodel/SendViewModel.kt @@ -20,6 +20,7 @@ import com.tangem.domain.tokens.model.CryptoCurrency import com.tangem.domain.tokens.model.CryptoCurrencyStatus import com.tangem.domain.transaction.usecase.GetFeeUseCase import com.tangem.domain.txhistory.models.TxHistoryItem +import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsCountUseCase import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsUseCase import com.tangem.domain.walletmanager.WalletManagersFacade import com.tangem.domain.wallets.models.UserWallet @@ -57,6 +58,7 @@ internal class SendViewModel @Inject constructor( private val getWalletsUseCase: GetWalletsUseCase, private val getCryptoCurrenciesUseCase: GetCryptoCurrenciesUseCase, private val txHistoryItemsUseCase: GetTxHistoryItemsUseCase, + private val txHistoryItemsCountUseCase: GetTxHistoryItemsCountUseCase, private val getFeeUseCase: GetFeeUseCase, private val walletManagersFacade: WalletManagersFacade, savedStateHandle: SavedStateHandle, @@ -97,7 +99,6 @@ internal class SendViewModel @Inject constructor( override fun onCreate(owner: LifecycleOwner) { getWalletAddresses() subscribeOnCurrencyStatusUpdates(owner) - getWalletsAndRecent() getFee() } @@ -134,6 +135,7 @@ internal class SendViewModel @Inject constructor( .onEach { either -> either.onRight { cryptoCurrencyStatus = it + getWalletsAndRecent() uiState = stateFactory.getReadyState() } } @@ -158,10 +160,12 @@ internal class SendViewModel @Inject constructor( combine( flow = getUserWallets().conflate(), flow2 = getTxHistory().conflate(), - ) { wallets, txHistory -> + flow3 = getTxHistoryCount().conflate(), + ) { wallets, txHistory, txHistoryCount -> stateFactory.onLoadedRecipientList( wallets = wallets, txHistory = txHistory, + txHistoryCount = txHistoryCount, ) } .flowOn(dispatchers.io) @@ -213,6 +217,18 @@ internal class SendViewModel @Inject constructor( } } + private fun getTxHistoryCount(): Flow { + return flow { + txHistoryItemsCountUseCase( + userWalletId = userWalletId, + currency = cryptoCurrency, + ).fold( + ifRight = { emit(it) }, + ifLeft = { emit(0) }, + ) + } + } + private fun getFee() { viewModelScope.launch(dispatchers.main) { uiState.currentState diff --git a/features/swap/data/src/main/java/com/tangem/feature/swap/SwapRepositoryImpl.kt b/features/swap/data/src/main/java/com/tangem/feature/swap/SwapRepositoryImpl.kt index ff7b2277ed..8d9f1918ab 100644 --- a/features/swap/data/src/main/java/com/tangem/feature/swap/SwapRepositoryImpl.kt +++ b/features/swap/data/src/main/java/com/tangem/feature/swap/SwapRepositoryImpl.kt @@ -294,7 +294,7 @@ internal class SwapRepositoryImpl @Inject constructor( return ExchangeQuote( toAmount = response.toAmount, - allowanceContract = response.allowanceContract + allowanceContract = response.allowanceContract, ) } diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt index aaa47663ff..68e8846de4 100644 --- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt @@ -2,7 +2,7 @@ package com.tangem.feature.swap.domain import arrow.core.getOrElse import com.tangem.domain.tokens.AddCryptoCurrenciesUseCase -import com.tangem.domain.tokens.GetCryptoCurrencyStatusUseCase +import com.tangem.domain.tokens.GetCryptoCurrencyStatusesSyncUseCase import com.tangem.domain.tokens.model.CryptoCurrency import com.tangem.domain.tokens.model.CryptoCurrencyStatus import com.tangem.domain.tokens.model.Network @@ -22,7 +22,6 @@ import com.tangem.lib.crypto.UserWalletManager import com.tangem.lib.crypto.models.* import com.tangem.lib.crypto.models.transactions.SendTxResult import com.tangem.utils.toFiatString -import kotlinx.coroutines.flow.first import timber.log.Timber import java.math.BigDecimal import java.math.RoundingMode @@ -39,7 +38,7 @@ internal class SwapInteractorImpl @Inject constructor( private val networksRepository: NetworksRepository, private val walletFeatureToggles: WalletFeatureToggles, private val getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase, - private val getMultiCryptoCurrencyStatusUseCase: GetCryptoCurrencyStatusUseCase, + private val getMultiCryptoCurrencyStatusUseCase: GetCryptoCurrencyStatusesSyncUseCase, ) : SwapInteractor { // TODO: Move to DI @@ -58,10 +57,9 @@ internal class SwapInteractorImpl @Inject constructor( ifRight = { it }, ) - requireNotNull(selectedWallet) + requireNotNull(selectedWallet) { "No selected wallet" } val walletCurrencyStatuses = getMultiCryptoCurrencyStatusUseCase(selectedWallet.walletId) - .first() .getOrElse { emptyList() } val walletCurrencyStatusesExceptInitial = walletCurrencyStatuses.filter { @@ -112,12 +110,13 @@ internal class SwapInteractorImpl @Inject constructor( status?.let { CryptoCurrencySwapInfo(it, pair.providers) } } - val unavailableCryptoCurrencies = - (cryptoCurrenciesList - availableCryptoCurrencies.map { it.currencyStatus }.toSet()) + val unavailableCryptoCurrencies = cryptoCurrenciesList - availableCryptoCurrencies + .map { it.currencyStatus } + .toSet() return CurrenciesGroup( available = availableCryptoCurrencies, - unavailable = unavailableCryptoCurrencies.map { CryptoCurrencySwapInfo(it, emptyList()) } + unavailable = unavailableCryptoCurrencies.map { CryptoCurrencySwapInfo(it, emptyList()) }, ) } @@ -138,14 +137,10 @@ internal class SwapInteractorImpl @Inject constructor( } } - private fun Currency.getContractAddress(): String { - return when (this) { - is Currency.NativeToken -> "0" - is Currency.NonNativeToken -> this.contractAddress - } - } - - suspend fun getPairs(initialCurrency: LeastTokenInfo, currenciesList: List): List { + private suspend fun getPairs( + initialCurrency: LeastTokenInfo, + currenciesList: List, + ): List { return repository.getPairs(initialCurrency, currenciesList) } diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapRepository.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapRepository.kt index 2e0a8cbf0f..d09b227b41 100644 --- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapRepository.kt +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapRepository.kt @@ -65,6 +65,7 @@ interface SwapRepository { amount: BigDecimal?, ): String + @Suppress("LongParameterList") suspend fun getExchangeQuote( fromContractAddress: String, fromNetwork: String, diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/di/SwapDomainModule.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/di/SwapDomainModule.kt index dc882859ae..7fa93f1c70 100644 --- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/di/SwapDomainModule.kt +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/di/SwapDomainModule.kt @@ -2,7 +2,7 @@ package com.tangem.feature.swap.domain.di import com.tangem.domain.tokens.GetCardTokensListUseCase import com.tangem.domain.tokens.GetCryptoCurrenciesUseCase -import com.tangem.domain.tokens.GetCryptoCurrencyStatusUseCase +import com.tangem.domain.tokens.GetCryptoCurrencyStatusesSyncUseCase import com.tangem.domain.tokens.repository.CurrenciesRepository import com.tangem.domain.tokens.repository.NetworksRepository import com.tangem.domain.tokens.repository.QuotesRepository @@ -35,7 +35,7 @@ class SwapDomainModule { networksRepository: NetworksRepository, walletFeatureToggles: WalletFeatureToggles, @SwapScope getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase, - @SwapScope getCryptoCurrencyStatusUseCase: GetCryptoCurrencyStatusUseCase, + @SwapScope getCryptoCurrencyStatusUseCase: GetCryptoCurrencyStatusesSyncUseCase, ): SwapInteractor { return SwapInteractorImpl( transactionManager = transactionManager, @@ -81,8 +81,8 @@ class SwapDomainModule { quotesRepository: QuotesRepository, networksRepository: NetworksRepository, dispatchers: CoroutineDispatcherProvider, - ): GetCryptoCurrencyStatusUseCase { - return GetCryptoCurrencyStatusUseCase( + ): GetCryptoCurrencyStatusesSyncUseCase { + return GetCryptoCurrencyStatusesSyncUseCase( currenciesRepository = currenciesRepository, quotesRepository = quotesRepository, networksRepository = networksRepository, diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/domain/SwapPairLeast.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/domain/SwapPairLeast.kt index a41f3d283d..ee772becce 100644 --- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/domain/SwapPairLeast.kt +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/domain/SwapPairLeast.kt @@ -17,7 +17,7 @@ data class SwapPairLeast( data class CryptoCurrencySwapInfo( val currencyStatus: CryptoCurrencyStatus, - val providers: List + val providers: List, ) /** diff --git a/features/swap/presentation/build.gradle.kts b/features/swap/presentation/build.gradle.kts index 1068c49d28..8be06eaf61 100644 --- a/features/swap/presentation/build.gradle.kts +++ b/features/swap/presentation/build.gradle.kts @@ -17,6 +17,8 @@ dependencies { implementation(projects.common) /** Domain modules **/ + implementation(projects.domain.appCurrency) + implementation(projects.domain.appCurrency.models) implementation(projects.domain.balanceHiding) implementation(projects.domain.balanceHiding.models) @@ -28,6 +30,7 @@ dependencies { implementation(deps.androidx.browser) /** Compose */ + implementation(deps.arrow.core) implementation(deps.compose.foundation) implementation(deps.compose.material) implementation(deps.compose.ui.tooling) diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/converters/TokensDataConverter.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/converters/TokensDataConverter.kt index bb52e2b01d..e3eff35d4c 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/converters/TokensDataConverter.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/converters/TokensDataConverter.kt @@ -2,52 +2,108 @@ package com.tangem.feature.swap.converters import com.tangem.common.Provider import com.tangem.core.ui.components.currency.tokenicon.TokenIconState +import com.tangem.core.ui.extensions.getTintForTokenIcon +import com.tangem.core.ui.extensions.networkIconResId +import com.tangem.core.ui.extensions.stringReference +import com.tangem.core.ui.extensions.tryGetBackgroundForTokenIcon +import com.tangem.core.ui.utils.BigDecimalFormatter +import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.tokens.model.CryptoCurrency -import com.tangem.feature.swap.domain.models.domain.NetworkInfo -import com.tangem.feature.swap.domain.models.ui.FoundTokensStateExpress -import com.tangem.feature.swap.domain.models.ui.TokenWithBalanceExpress -import com.tangem.feature.swap.models.Network +import com.tangem.domain.tokens.model.CryptoCurrencyStatus +import com.tangem.feature.swap.domain.models.domain.CryptoCurrencySwapInfo +import com.tangem.feature.swap.domain.models.ui.CurrenciesGroup import com.tangem.feature.swap.models.SwapSelectTokenStateHolder import com.tangem.feature.swap.models.TokenBalanceData import com.tangem.feature.swap.models.TokenToSelectState +import com.tangem.utils.converter.Converter import kotlinx.collections.immutable.toImmutableList class TokensDataConverter( private val onSearchEntered: (String) -> Unit, private val onTokenSelected: (String) -> Unit, private val isBalanceHiddenProvider: Provider, -) { + private val appCurrencyProvider: Provider, +) : Converter { - fun convertWithNetwork(value: FoundTokensStateExpress, network: NetworkInfo): SwapSelectTokenStateHolder { + override fun convert(value: CurrenciesGroup): SwapSelectTokenStateHolder { + val availableTitle = TokenToSelectState.Title(stringReference("My tokens")) // todo replace with resource + val unavailableTitle = TokenToSelectState.Title(stringReference("My tokens")) // todo replace with resource return SwapSelectTokenStateHolder( - availableTokens = value.tokensInWallet.map { tokenWithBalanceToTokenToSelect(it) }.toImmutableList(), - unavailableTokens = value.loadedTokens.map { tokenWithBalanceToTokenToSelect(it) }.toImmutableList(), + availableTokens = value.available.map { tokenWithBalanceToTokenToSelect(it, true) } + .toMutableList() + .apply { + this.add(0, availableTitle) + } + .toImmutableList(), + unavailableTokens = value.unavailable.map { tokenWithBalanceToTokenToSelect(it, false) } + .toMutableList() + .apply { + this.add(0, unavailableTitle) + } + .toImmutableList(), onSearchEntered = onSearchEntered, onTokenSelected = onTokenSelected, - network = Network(network.name, network.blockchainId), ) } private fun tokenWithBalanceToTokenToSelect( - tokenWithBalance: TokenWithBalanceExpress, - ): TokenToSelectState.TokenToSelect { + cryptoCurrencySwapInfo: CryptoCurrencySwapInfo, + isAvailable: Boolean, + ): TokenToSelectState { + val cryptoCurrencyStatus = cryptoCurrencySwapInfo.currencyStatus return TokenToSelectState.TokenToSelect( - id = tokenWithBalance.token.id.value, - name = tokenWithBalance.token.name, - symbol = tokenWithBalance.token.symbol, - isNative = tokenWithBalance.token is CryptoCurrency.Coin, - // todo replace converting - tokenIcon = TokenIconState.CoinIcon( - url = "", - fallbackResId = 0, - isGrayscale = false, - showCustomBadge = false, - ), + id = cryptoCurrencyStatus.currency.id.value, + name = cryptoCurrencyStatus.currency.name, + symbol = cryptoCurrencyStatus.currency.symbol, + available = isAvailable, + tokenIcon = convertIcon(cryptoCurrencyStatus.currency, isAvailable), addedTokenBalanceData = TokenBalanceData( - amount = tokenWithBalance.tokenBalanceData?.amount, - amountEquivalent = tokenWithBalance.tokenBalanceData?.amountEquivalent, + amount = formatCryptoAmount(cryptoCurrencyStatus), + amountEquivalent = formatFiatAmount(cryptoCurrencyStatus, appCurrencyProvider.invoke()), isBalanceHidden = isBalanceHiddenProvider.invoke(), ), ) } + + private fun convertIcon(currency: CryptoCurrency, isAvailable: Boolean): TokenIconState { + return when (currency) { + is CryptoCurrency.Coin -> { + TokenIconState.CoinIcon( + url = currency.iconUrl, + fallbackResId = currency.networkIconResId, + isGrayscale = !isAvailable, + showCustomBadge = currency.isCustom, + ) + } + is CryptoCurrency.Token -> { + val isGrayscale = currency.network.isTestnet + val background = currency.tryGetBackgroundForTokenIcon(isGrayscale) + val tint = getTintForTokenIcon(background) + TokenIconState.TokenIcon( + url = currency.iconUrl, + isGrayscale = !isAvailable, + showCustomBadge = currency.isCustom, + networkBadgeIconResId = currency.networkIconResId, + fallbackTint = tint, + fallbackBackground = background, + ) + } + } + } + + private fun formatCryptoAmount(cryptoCurrencyStatus: CryptoCurrencyStatus): String { + return BigDecimalFormatter.formatCryptoAmount( + cryptoCurrencyStatus.value.amount, + cryptoCurrencyStatus.currency.symbol, + cryptoCurrencyStatus.currency.decimals, + ) + } + + private fun formatFiatAmount(cryptoCurrencyStatus: CryptoCurrencyStatus, appCurrency: AppCurrency): String { + return BigDecimalFormatter.formatFiatAmount( + fiatAmount = cryptoCurrencyStatus.value.fiatAmount, + fiatCurrencyCode = appCurrency.code, + fiatCurrencySymbol = appCurrency.symbol, + ) + } } \ No newline at end of file diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/SwapSelectTokenStateHolder.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/SwapSelectTokenStateHolder.kt index 382da8e588..ac6762d7b7 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/SwapSelectTokenStateHolder.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/SwapSelectTokenStateHolder.kt @@ -1,30 +1,24 @@ package com.tangem.feature.swap.models import com.tangem.core.ui.components.currency.tokenicon.TokenIconState +import com.tangem.core.ui.extensions.TextReference import kotlinx.collections.immutable.ImmutableList data class SwapSelectTokenStateHolder( val availableTokens: ImmutableList, val unavailableTokens: ImmutableList, - val network: Network, val onSearchEntered: (String) -> Unit, val onTokenSelected: (String) -> Unit, ) -data class Network( - val name: String, - val blockchainId: String, -) - sealed class TokenToSelectState { - data class Title(val title: String) : TokenToSelectState() + data class Title(val title: TextReference) : TokenToSelectState() data class TokenToSelect( val id: String, val name: String, val symbol: String, - val isNative: Boolean, val tokenIcon: TokenIconState, val available: Boolean = true, val addedTokenBalanceData: TokenBalanceData? = null, diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt index bea53175af..510502e088 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt @@ -9,6 +9,7 @@ import com.tangem.core.ui.components.states.SelectableItemsState import com.tangem.core.ui.extensions.TextReference import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.extensions.wrappedList +import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.tokens.model.CryptoCurrency import com.tangem.feature.swap.converters.TokensDataConverter import com.tangem.feature.swap.domain.models.DataError @@ -24,12 +25,17 @@ import kotlinx.collections.immutable.toImmutableList * State builder creates a specific states for SwapScreen */ @Suppress("LargeClass") -internal class StateBuilder(val actions: UiActions, val isBalanceHiddenProvider: Provider) { +internal class StateBuilder( + private val actions: UiActions, + private val isBalanceHiddenProvider: Provider, + appCurrencyProvider: Provider, +) { private val tokensDataConverter = TokensDataConverter( onSearchEntered = actions.onSearchEntered, onTokenSelected = actions.onTokenSelected, isBalanceHiddenProvider = isBalanceHiddenProvider, + appCurrencyProvider = appCurrencyProvider, ) fun createInitialLoadingState(initialCurrency: CryptoCurrency, networkInfo: NetworkInfo): SwapStateHolder { @@ -247,15 +253,10 @@ internal class StateBuilder(val actions: UiActions, val isBalanceHiddenProvider: ) } - fun addTokensToState( - uiState: SwapStateHolder, - dataState: FoundTokensStateExpress, - networkInfo: NetworkInfo, - ): SwapStateHolder { + fun addTokensToState(uiState: SwapStateHolder, tokensDataState: CurrenciesGroup): SwapStateHolder { return uiState.copy( - selectTokenState = tokensDataConverter.convertWithNetwork( - value = dataState, - network = networkInfo, + selectTokenState = tokensDataConverter.convert( + value = tokensDataState, ), ) } diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapSelectTokenScreen.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapSelectTokenScreen.kt index 1faa262bb3..6e89f78c3a 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapSelectTokenScreen.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapSelectTokenScreen.kt @@ -11,7 +11,6 @@ import androidx.compose.material.Text import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import com.tangem.common.Strings @@ -20,7 +19,8 @@ import com.tangem.core.ui.components.appbar.ExpandableSearchView import com.tangem.core.ui.components.currency.tokenicon.TokenIcon import com.tangem.core.ui.components.currency.tokenicon.TokenIconState import com.tangem.core.ui.decorations.roundedShapeItemDecoration -import com.tangem.core.ui.extensions.getActiveIconRes +import com.tangem.core.ui.extensions.resolveReference +import com.tangem.core.ui.extensions.stringReference import com.tangem.core.ui.res.TangemTheme import com.tangem.feature.swap.models.* import com.tangem.feature.swap.presentation.R @@ -43,8 +43,7 @@ fun SwapSelectTokenScreen(state: SwapSelectTokenStateHolder, onBack: () -> Unit) placeholderSearchText = stringResource(id = R.string.common_search_tokens), onSearchChange = state.onSearchEntered, onSearchDisplayClose = { state.onSearchEntered("") }, - subtitle = state.network.name, - icon = painterResource(id = getActiveIconRes(state.network.blockchainId)), + subtitle = "", // todo add title ) }, ) @@ -112,7 +111,7 @@ private fun TitleHeader(item: TokenToSelectState.Title, modifier: Modifier = Mod .background(TangemTheme.colors.background.action), ) { Text( - text = item.title, + text = item.title.resolveReference().uppercase(), style = TangemTheme.typography.overline, modifier = Modifier .padding( @@ -134,7 +133,10 @@ private fun TokenItem( modifier = modifier .fillMaxWidth() .height(TangemTheme.dimens.size72) - .clickable(onClick = onTokenClick) + .clickable( + enabled = token.available, + onClick = onTokenClick, + ) .padding( vertical = TangemTheme.dimens.spacing14, horizontal = TangemTheme.dimens.spacing16, @@ -170,13 +172,7 @@ private fun TokenItem( Spacer(modifier = Modifier.weight(1f)) - if (!token.available) { - Text( - text = stringResource(id = R.string.swapping_token_not_available), - style = TangemTheme.typography.caption2, - color = TangemTheme.colors.text.tertiary, - ) - } else if (token.addedTokenBalanceData != null) { + if (token.addedTokenBalanceData != null) { Column( horizontalAlignment = Alignment.End, verticalArrangement = Arrangement.Center, @@ -191,7 +187,11 @@ private fun TokenItem( token.addedTokenBalanceData.amountEquivalent.orEmpty() }, style = TangemTheme.typography.subtitle1, - color = TangemTheme.colors.text.primary1, + color = if (token.available) { + TangemTheme.colors.text.primary1 + } else { + TangemTheme.colors.text.tertiary + }, ) SpacerW2() Text( @@ -220,7 +220,6 @@ private val token = TokenToSelectState.TokenToSelect( id = "", name = "USDC", symbol = "USDC", - isNative = false, addedTokenBalanceData = TokenBalanceData( amount = "15 000 $", amountEquivalent = "15 000 " + @@ -230,7 +229,7 @@ private val token = TokenToSelectState.TokenToSelect( ) private val title = TokenToSelectState.Title( - title = "MY TOKENS", + title = stringReference("MY TOKENS"), ) @Preview @@ -243,7 +242,6 @@ private fun TokenScreenPreview() { unavailableTokens = listOf(title, token, token, token).toImmutableList(), onSearchEntered = {}, onTokenSelected = {}, - network = Network("Ethereum", "ETH"), ), onBack = {}, ) diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapProcessDataState.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapProcessDataState.kt index 65abcf814c..c9018a2345 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapProcessDataState.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapProcessDataState.kt @@ -4,6 +4,7 @@ import com.tangem.domain.tokens.model.CryptoCurrency import com.tangem.feature.swap.domain.models.domain.Currency import com.tangem.feature.swap.domain.models.ui.RequestApproveStateData import com.tangem.feature.swap.domain.models.ui.SwapStateData +import com.tangem.feature.swap.domain.models.ui.TokensDataStateExpress import com.tangem.feature.swap.domain.models.ui.TxFee data class SwapProcessDataState( @@ -20,4 +21,5 @@ data class SwapProcessDataState( val approveDataModel: RequestApproveStateData? = null, val swapDataModel: SwapStateData? = null, val selectedFee: TxFee? = null, + val tokensDataState: TokensDataStateExpress? = null, ) \ No newline at end of file diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt index 8af439d54f..245b670cbe 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt @@ -4,9 +4,12 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.lifecycle.* +import arrow.core.getOrElse import com.tangem.common.Provider import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.ui.utils.InputNumberFormatter +import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase +import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase import com.tangem.domain.tokens.model.CryptoCurrency import com.tangem.feature.swap.analytics.SwapEvents @@ -29,11 +32,9 @@ import com.tangem.utils.coroutines.CoroutineDispatcherProvider import com.tangem.utils.coroutines.Debouncer import com.tangem.utils.coroutines.runCatching import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.flow.launchIn -import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.flow.* import kotlinx.coroutines.launch import kotlinx.coroutines.withContext -import kotlinx.serialization.json.Json import timber.log.Timber import java.text.DecimalFormat import java.text.NumberFormat @@ -49,6 +50,7 @@ internal class SwapViewModel @Inject constructor( private val dispatchers: CoroutineDispatcherProvider, private val analyticsEventHandler: AnalyticsEventHandler, private val getBalanceHidingSettingsUseCase: GetBalanceHidingSettingsUseCase, + private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase, savedStateHandle: SavedStateHandle, ) : ViewModel(), DefaultLifecycleObserver { @@ -57,9 +59,12 @@ internal class SwapViewModel @Inject constructor( private var isBalanceHidden = true + private val selectedAppCurrencyFlow: StateFlow = createSelectedAppCurrencyFlow() + private val stateBuilder = StateBuilder( actions = createUiActions(), isBalanceHiddenProvider = Provider { isBalanceHidden }, + appCurrencyProvider = Provider(selectedAppCurrencyFlow::value), ) private val inputNumberFormatter = @@ -89,7 +94,7 @@ internal class SwapViewModel @Inject constructor( derivationPath = initialCryptoCurrency.network.derivationPath.value, network = initialCryptoCurrency.network, ) - initTokens(initialCryptoCurrency) + initTokens() } override fun onCreate(owner: LifecycleOwner) { @@ -128,7 +133,7 @@ internal class SwapViewModel @Inject constructor( } @Suppress("UnusedPrivateMember") - private fun initTokens(currency: CryptoCurrency) { + private fun initTokens() { // new flow viewModelScope.launch(dispatchers.main) { runCatching(dispatchers.io) { @@ -136,16 +141,18 @@ internal class SwapViewModel @Inject constructor( }.onSuccess { state -> dataState = dataState.copy( fromCryptoCurrency = initialCryptoCurrency, - toCryptoCurrency = state.toGroup.available.first().currencyStatus.currency + toCryptoCurrency = state.toGroup.available.first().currencyStatus.currency, + tokensDataState = state, ) - // updateTokensState(dataState = state.foundTokensState) + //updateTokensState(state) + val toToken = state.toGroup.available.first() startLoadingQuotes( fromToken = initialCryptoCurrency, - toToken = toToken.currencyStatus.currency, + toToken = state.toGroup.available.first().currencyStatus.currency, amount = lastAmount.value, - toProvidersList = toToken.providers + toProvidersList = toToken.providers, ) }.onFailure { Timber.tag(loggingTag).e(it) @@ -175,11 +182,11 @@ internal class SwapViewModel @Inject constructor( // } } - private fun updateTokensState(dataState: FoundTokensStateExpress) { + private fun updateTokensState(dataState: TokensDataStateExpress) { + val tokensDataState = if (!isOrderReversed) dataState.toGroup else dataState.fromGroup uiState = stateBuilder.addTokensToState( uiState = uiState, - dataState = dataState, - networkInfo = blockchainInteractor.getBlockchainInfo(initialCryptoCurrency.network.backendId), + tokensDataState = tokensDataState, ) } @@ -381,28 +388,31 @@ internal class SwapViewModel @Inject constructor( swapInteractor.searchTokens(dataState.networkId, searchQuery) } .onSuccess { - updateTokensState(it) + // updateTokensState(it) } .onFailure { } } } private fun onTokenSelect(id: String) { - val foundToken = swapInteractor.findTokenById(id) + val tokens = dataState.tokensDataState ?: return + val foundToken = tokens.toGroup.available.firstOrNull { + it.currencyStatus.currency.id.value == id + } analyticsEventHandler.send( - event = SwapEvents.SearchTokenClicked(currencySymbol = foundToken?.symbol), + event = SwapEvents.SearchTokenClicked(currencySymbol = foundToken?.currencyStatus?.currency?.symbol), ) if (foundToken != null) { val fromToken: CryptoCurrency val toToken: CryptoCurrency if (isOrderReversed) { - fromToken = foundToken + fromToken = foundToken.currencyStatus.currency toToken = initialCryptoCurrency } else { fromToken = initialCryptoCurrency - toToken = foundToken + toToken = foundToken.currencyStatus.currency } dataState = dataState.copy( fromCryptoCurrency = fromToken, @@ -544,6 +554,18 @@ internal class SwapViewModel @Inject constructor( ) } + private fun createSelectedAppCurrencyFlow(): StateFlow { + return getSelectedAppCurrencyUseCase() + .map { maybeAppCurrency -> + maybeAppCurrency.getOrElse { AppCurrency.Default } + } + .stateIn( + scope = viewModelScope, + started = SharingStarted.Eagerly, + initialValue = AppCurrency.Default, + ) + } + companion object { private const val loggingTag = "SwapViewModel" private const val INITIAL_AMOUNT = ""