Updated on 2026-08-14
This commit is contained in:
commit
6e20ef6027
57 changed files with 360 additions and 864 deletions
|
|
@ -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()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
|
@ -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),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -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),
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -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),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -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),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -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),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -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' */
|
||||
|
|
|
|||
|
|
@ -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<BalanceHidingSettings>
|
||||
|
||||
suspend fun getSyncOrDefault(): BalanceHidingSettings
|
||||
|
||||
suspend fun store(settings: BalanceHidingSettings)
|
||||
}
|
||||
|
|
@ -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<CurrenciesResponse.Currency>
|
||||
|
||||
suspend fun getSyncOrNull(): CurrenciesResponse.Currency?
|
||||
|
||||
suspend fun store(item: CurrenciesResponse.Currency)
|
||||
|
||||
suspend fun isEmpty(): Boolean
|
||||
}
|
||||
|
|
@ -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<BalanceHidingSettings>,
|
||||
) : BalanceHidingSettingsStore, KeylessDataStoreDecorator<BalanceHidingSettings>(dataStore) {
|
||||
|
||||
override suspend fun getSyncOrDefault(): BalanceHidingSettings {
|
||||
return getSyncOrNull() ?: BalanceHidingSettings(
|
||||
isHidingEnabledInSettings = false,
|
||||
isBalanceHidden = false,
|
||||
isBalanceHidingNotificationEnabled = true,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -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<CurrenciesResponse.Currency>,
|
||||
) : SelectedAppCurrencyStore, KeylessDataStoreDecorator<CurrenciesResponse.Currency>(dataStore)
|
||||
|
|
@ -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<AppThemeMode>
|
||||
|
||||
suspend fun store(item: AppThemeMode)
|
||||
|
||||
suspend fun isEmpty(): Boolean
|
||||
}
|
||||
|
|
@ -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<AppThemeMode>,
|
||||
) : AppThemeModeStore, KeylessDataStoreDecorator<AppThemeMode>(dataStore)
|
||||
|
|
@ -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<List<UsedCardInfo>>
|
||||
|
||||
suspend fun getSyncOrNull(): List<UsedCardInfo>?
|
||||
|
||||
suspend fun store(item: List<UsedCardInfo>)
|
||||
}
|
||||
|
||||
internal class DefaultUsedCardsStore(
|
||||
store: SharedPreferencesDataStore<List<UsedCardInfo>>,
|
||||
) : UsedCardsStore, KeylessDataStoreDecorator<List<UsedCardInfo>>(
|
||||
wrappedDataStore = store,
|
||||
key = "usedCardsInfo_v2",
|
||||
)
|
||||
|
|
@ -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<Boolean>(preferencesName, context) {
|
||||
|
||||
override fun getByKey(key: String): Boolean = sharedPreferences.getBoolean(key, false)
|
||||
|
||||
override fun storeByKey(key: String, value: Boolean) {
|
||||
sharedPreferences.edit { putBoolean(key, value) }
|
||||
}
|
||||
}
|
||||
|
|
@ -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<Int>(preferencesName, context) {
|
||||
|
||||
override fun getByKey(key: String): Int = sharedPreferences.getInt(key, 0)
|
||||
|
||||
override fun storeByKey(key: String, value: Int) {
|
||||
sharedPreferences.edit { putInt(key, value) }
|
||||
}
|
||||
}
|
||||
|
|
@ -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<Value : Any>(
|
||||
preferencesName: String,
|
||||
context: Context,
|
||||
private val adapter: JsonAdapter<Value>,
|
||||
) : SharedPreferencesDataStore<Value>(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) }
|
||||
}
|
||||
}
|
||||
|
|
@ -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<Long>(preferencesName, context) {
|
||||
|
||||
override fun getByKey(key: String): Long = sharedPreferences.getLong(key, 0)
|
||||
|
||||
override fun storeByKey(key: String, value: Long) {
|
||||
sharedPreferences.edit { putLong(key, value) }
|
||||
}
|
||||
}
|
||||
|
|
@ -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<Value : Any>(
|
||||
preferencesName: String,
|
||||
context: Context,
|
||||
) : StringKeyDataStore<Value> {
|
||||
|
||||
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<Value> {
|
||||
return writeTrigger
|
||||
.mapNotNull { getInternal(key) }
|
||||
.distinctUntilChanged()
|
||||
}
|
||||
|
||||
override fun getAll(): Flow<List<Value>> {
|
||||
throw UnsupportedOperationException("Unknown key")
|
||||
}
|
||||
|
||||
override suspend fun getSyncOrNull(key: String): Value? = getInternal(key)
|
||||
|
||||
override suspend fun getAllSyncOrNull(): List<Value> {
|
||||
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<String, Value>) {
|
||||
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<String>) {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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<Preferences>? = null
|
||||
|
||||
|
|
@ -33,7 +37,7 @@ internal object PreferencesDataStore {
|
|||
private fun create(context: Context, dispatcher: CoroutineContext): DataStore<Preferences> {
|
||||
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<DataMigration<Preferences>> {
|
||||
return listOf()
|
||||
private fun createMigrations(context: Context): List<DataMigration<Preferences>> {
|
||||
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,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -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<Preferences> 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<Preferences> */
|
||||
internal fun getTapPrefKeysToMigrate(): Set<String> {
|
||||
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()
|
||||
}
|
||||
|
|
@ -30,6 +30,14 @@ internal class DefaultQuotesStore(
|
|||
}
|
||||
}
|
||||
|
||||
override suspend fun getSync(currenciesIds: Set<CryptoCurrency.ID>): Set<StoredQuote> {
|
||||
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)
|
||||
|
|
|
|||
|
|
@ -9,5 +9,7 @@ interface QuotesStore {
|
|||
|
||||
fun get(currenciesIds: Set<CryptoCurrency.ID>): Flow<Set<StoredQuote>>
|
||||
|
||||
suspend fun getSync(currenciesIds: Set<CryptoCurrency.ID>): Set<StoredQuote>
|
||||
|
||||
suspend fun store(response: QuotesResponse)
|
||||
}
|
||||
|
|
@ -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<Int>
|
||||
|
||||
suspend fun getSyncOrNull(): Int?
|
||||
|
||||
suspend fun store(item: Int)
|
||||
}
|
||||
|
||||
internal class DefaultAppLaunchCountStore(
|
||||
store: IntSharedPreferencesDataStore,
|
||||
) : AppLaunchCountStore, KeylessDataStoreDecorator<Int>(
|
||||
wrappedDataStore = store,
|
||||
key = "launchCount",
|
||||
)
|
||||
|
|
@ -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<Int>
|
||||
|
||||
suspend fun getSyncOrNull(): Int?
|
||||
|
||||
suspend fun store(item: Int)
|
||||
}
|
||||
|
||||
internal class DefaultAppRatingShowingCountStore(
|
||||
store: IntSharedPreferencesDataStore,
|
||||
) : AppRatingShowingCountStore, KeylessDataStoreDecorator<Int>(
|
||||
wrappedDataStore = store,
|
||||
key = "showRatingDialogAtLaunchCount",
|
||||
)
|
||||
|
|
@ -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<Long>
|
||||
|
||||
suspend fun getSyncOrNull(): Long?
|
||||
|
||||
suspend fun store(item: Long)
|
||||
}
|
||||
|
||||
internal class DefaultFundsFoundDateInMillisStore(
|
||||
store: LongSharedPreferencesDataStore,
|
||||
) : FundsFoundDateInMillisStore, KeylessDataStoreDecorator<Long>(
|
||||
wrappedDataStore = store,
|
||||
key = "fundsFoundDate",
|
||||
)
|
||||
|
|
@ -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<Boolean>
|
||||
|
||||
suspend fun getSyncOrNull(): Boolean?
|
||||
|
||||
suspend fun store(item: Boolean)
|
||||
}
|
||||
|
||||
internal class DefaultUserInteractingStatusStore(
|
||||
store: BooleanSharedPreferencesDataStore,
|
||||
) : UserInteractingStatusStore, KeylessDataStoreDecorator<Boolean>(
|
||||
wrappedDataStore = store,
|
||||
key = "userWasInteractWithRating",
|
||||
)
|
||||
|
|
@ -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<Boolean>
|
||||
|
||||
suspend fun getSyncOrNull(): Boolean?
|
||||
|
||||
suspend fun store(item: Boolean)
|
||||
}
|
||||
|
||||
internal class DefaultShouldSaveUserWalletStore(
|
||||
store: BooleanSharedPreferencesDataStore,
|
||||
) : ShouldSaveUserWalletStore, KeylessDataStoreDecorator<Boolean>(
|
||||
wrappedDataStore = store,
|
||||
key = "saveUserWallets",
|
||||
)
|
||||
|
|
@ -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)
|
||||
}
|
||||
|
|
@ -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<AppCurrency> = channelFlow {
|
||||
launch(dispatchers.io) {
|
||||
selectedAppCurrencyStore.get()
|
||||
.map(appCurrencyConverter::convert)
|
||||
.collect(::send)
|
||||
}
|
||||
override fun getSelectedAppCurrency(): Flow<AppCurrency> {
|
||||
return channelFlow {
|
||||
launch {
|
||||
appPreferencesStore
|
||||
.getObject<CurrenciesResponse.Currency>(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,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -27,4 +27,7 @@ dependencies {
|
|||
|
||||
/** Other */
|
||||
implementation(deps.kotlin.coroutines)
|
||||
|
||||
/** Local storages */
|
||||
implementation(deps.androidx.datastore)
|
||||
}
|
||||
|
|
@ -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<AppThemeMode> {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
@ -11,10 +11,10 @@ android {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
implementation(deps.androidx.datastore)
|
||||
|
||||
/** DI */
|
||||
implementation(deps.hilt.android)
|
||||
|
||||
kapt(deps.hilt.kapt)
|
||||
|
||||
implementation(deps.kotlin.coroutines)
|
||||
|
|
|
|||
|
|
@ -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<BalanceHidingSettings> {
|
||||
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,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ android {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
implementation(deps.androidx.datastore)
|
||||
|
||||
implementation(deps.hilt.android)
|
||||
kapt(deps.hilt.kapt)
|
||||
|
||||
|
|
|
|||
|
|
@ -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<Boolean> {
|
||||
return channelFlow {
|
||||
launch(dispatchers.io) {
|
||||
usedCardsStore.get()
|
||||
.collect { savedCards ->
|
||||
send(element = savedCards.any { it.cardId == cardId })
|
||||
}
|
||||
return appPreferencesStore.getObject<List<UsedCardInfo>>(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<UsedCardInfo>? = 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,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<Boolean> {
|
||||
// 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 {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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<CryptoCurrency.ID>): Flow<Set<Quote>> {
|
||||
return selectedAppCurrencyStore.get()
|
||||
return appPreferencesStore.getObject<CurrenciesResponse.Currency>(
|
||||
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<CryptoCurrency.ID>, refresh: Boolean): Set<Quote> {
|
||||
return withContext(dispatchers.io) {
|
||||
val selectedAppCurrency = requireNotNull(selectedAppCurrencyStore.getSyncOrNull()) {
|
||||
"Unable to get selected application currency to update quotes"
|
||||
}
|
||||
val selectedAppCurrency = requireNotNull(
|
||||
value = appPreferencesStore.getObjectSyncOrNull<CurrenciesResponse.Currency>(
|
||||
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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
@ -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<Boolean> = shouldSaveUserWalletStore.get()
|
||||
override fun shouldSaveUserWallets(): Flow<Boolean> {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
@ -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<Boolean>
|
||||
|
|
|
|||
|
|
@ -4,8 +4,6 @@ import kotlinx.coroutines.flow.Flow
|
|||
|
||||
interface WalletsRepository {
|
||||
|
||||
suspend fun initialize()
|
||||
|
||||
suspend fun shouldSaveUserWalletsSync(): Boolean
|
||||
|
||||
fun shouldSaveUserWallets(): Flow<Boolean>
|
||||
|
|
|
|||
|
|
@ -17,5 +17,6 @@ internal sealed class SendRecipientListContent {
|
|||
|
||||
data class Wallets(
|
||||
val list: PersistentList<Item>,
|
||||
val isWalletsOnly: Boolean,
|
||||
) : SendRecipientListContent()
|
||||
}
|
||||
|
|
@ -105,10 +105,15 @@ internal class SendStateFactory(
|
|||
//endregion
|
||||
|
||||
//region recipient
|
||||
fun onLoadedRecipientList(wallets: List<AvailableWallet?>, txHistory: PagingData<TxHistoryItem>) {
|
||||
fun onLoadedRecipientList(
|
||||
wallets: List<AvailableWallet?>,
|
||||
txHistory: PagingData<TxHistoryItem>,
|
||||
txHistoryCount: Int,
|
||||
) {
|
||||
recipientListStateConverter.convert(
|
||||
wallets = wallets,
|
||||
txHistory = txHistory,
|
||||
txHistoryCount = txHistoryCount,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ internal class SendRecipientListConverter(
|
|||
private val cryptoCurrencyStatusProvider: Provider<CryptoCurrencyStatus>,
|
||||
) {
|
||||
|
||||
fun convert(wallets: List<AvailableWallet?>, txHistory: PagingData<TxHistoryItem>) {
|
||||
fun convert(wallets: List<AvailableWallet?>, txHistory: PagingData<TxHistoryItem>, 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<TxHistoryItem, SendRecipientListContent> { 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<TxHistoryItem, SendRecipientListContent> { 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<SendRecipientListContent>.insertWallets(
|
||||
wallets: List<AvailableWallet>,
|
||||
wallets: SendRecipientListContent.Wallets,
|
||||
): PagingData<SendRecipientListContent> {
|
||||
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<AvailableWallet>, 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(
|
||||
|
|
|
|||
|
|
@ -80,6 +80,7 @@ internal fun SendRecipientContent(
|
|||
}
|
||||
}
|
||||
|
||||
@Suppress("LongMethod")
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
private fun LazyListScope.recipientListItem(
|
||||
recipientList: LazyPagingItems<SendRecipientListContent>,
|
||||
|
|
@ -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,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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<Int> {
|
||||
return flow {
|
||||
txHistoryItemsCountUseCase(
|
||||
userWalletId = userWalletId,
|
||||
currency = cryptoCurrency,
|
||||
).fold(
|
||||
ifRight = { emit(it) },
|
||||
ifLeft = { emit(0) },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getFee() {
|
||||
viewModelScope.launch(dispatchers.main) {
|
||||
uiState.currentState
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue