Updated on 2026-08-14

This commit is contained in:
Tangem 2023-09-25 09:55:08 +08:00
parent 9a02d6a58a
commit 6c850776d5
37 changed files with 611 additions and 104 deletions

View file

@ -7,8 +7,8 @@ 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 com.tangem.datasource.local.datastore.SharedPreferencesDataStore
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
@ -35,7 +35,7 @@ internal object AppCurrencyDataModule {
@NetworkMoshi moshi: Moshi,
): SelectedAppCurrencyStore {
return DefaultSelectedAppCurrencyStore(
dataStore = SharedPreferencesDataStore(
dataStore = JsonSharedPreferencesDataStore(
preferencesName = "selected_app_currency",
context = context,
adapter = moshi.adapter(CurrenciesResponse.Currency::class.java),

View file

@ -4,7 +4,7 @@ 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.SharedPreferencesDataStore
import com.tangem.datasource.local.datastore.JsonSharedPreferencesDataStore
import com.tangem.domain.apptheme.model.AppThemeMode
import dagger.Module
import dagger.Provides
@ -19,7 +19,7 @@ internal object AppThemeModeDataModule {
@Provides
fun provideAppThemeModeStore(@ApplicationContext context: Context, @NetworkMoshi moshi: Moshi): AppThemeModeStore {
return DefaultAppThemeModeStore(
dataStore = SharedPreferencesDataStore(
dataStore = JsonSharedPreferencesDataStore(
preferencesName = "app_theme",
context = context,
adapter = moshi.adapter(AppThemeMode::class.java),

View file

@ -6,7 +6,7 @@ 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.SharedPreferencesDataStore
import com.tangem.datasource.local.datastore.JsonSharedPreferencesDataStore
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
@ -22,7 +22,7 @@ internal object CardDataModule {
@Singleton
fun provideUsedCardsStore(@ApplicationContext context: Context, @NetworkMoshi moshi: Moshi): UsedCardsStore {
return DefaultUsedCardsStore(
store = SharedPreferencesDataStore(
store = JsonSharedPreferencesDataStore(
preferencesName = "tapPrefs",
context = context,
adapter = moshi.adapter(

View file

@ -4,7 +4,7 @@ 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.SharedPreferencesDataStore
import com.tangem.datasource.local.datastore.JsonSharedPreferencesDataStore
import com.tangem.domain.balancehiding.BalanceHidingSettings
import dagger.Module
import dagger.Provides
@ -22,7 +22,7 @@ internal object HiddenBalanceDataModule {
@NetworkMoshi moshi: Moshi,
): BalanceHidingSettingsStore {
return BalanceStateHidingSettingsStore(
dataStore = SharedPreferencesDataStore(
dataStore = JsonSharedPreferencesDataStore(
preferencesName = "balance_hiding_settings",
context = context,
adapter = moshi.adapter(BalanceHidingSettings::class.java),

View file

@ -2,7 +2,7 @@ package com.tangem.datasource.di
import android.content.Context
import com.squareup.moshi.Moshi
import com.tangem.datasource.local.datastore.SharedPreferencesDataStore
import com.tangem.datasource.local.datastore.JsonSharedPreferencesDataStore
import com.tangem.datasource.local.quote.DefaultQuotesStore
import com.tangem.datasource.local.quote.QuotesStore
import com.tangem.datasource.local.quote.model.StoredQuote
@ -21,7 +21,7 @@ internal object QuotesStoreModule {
@Singleton
fun provideQuotesStore(@ApplicationContext context: Context, @NetworkMoshi moshi: Moshi): QuotesStore {
return DefaultQuotesStore(
dataStore = SharedPreferencesDataStore(
dataStore = JsonSharedPreferencesDataStore(
preferencesName = "quotes",
context = context,
adapter = moshi.adapter(StoredQuote::class.java),

View file

@ -0,0 +1,50 @@
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),
)
}
}

View file

@ -0,0 +1,16 @@
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) }
}
}

View file

@ -0,0 +1,16 @@
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) }
}
}

View file

@ -0,0 +1,24 @@
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) }
}
}

View file

@ -0,0 +1,16 @@
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) }
}
}

View file

@ -4,53 +4,47 @@ import android.content.Context
import android.content.Context.MODE_PRIVATE
import android.content.SharedPreferences
import androidx.core.content.edit
import com.squareup.moshi.JsonAdapter
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.filterNotNull
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.mapNotNull
import timber.log.Timber
internal class SharedPreferencesDataStore<Value : Any>(
internal abstract class SharedPreferencesDataStore<Value : Any>(
preferencesName: String,
private val context: Context,
private val adapter: JsonAdapter<Value>,
context: Context,
) : StringKeyDataStore<Value> {
private val sharedPreferences: SharedPreferences by lazy {
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 fun get(key: String): Flow<Value> {
return writeTrigger
.map { getInternal(key) }
.filterNotNull()
.mapNotNull { getInternal(key) }
.distinctUntilChanged()
}
override fun getAll(): Flow<List<Value>> {
return writeTrigger
.map { getAllInternal() }
.distinctUntilChanged()
throw UnsupportedOperationException("Unknown key")
}
override suspend fun getSyncOrNull(key: String): Value? {
return getInternal(key)
}
override suspend fun getSyncOrNull(key: String): Value? = getInternal(key)
override suspend fun getAllSyncOrNull(): List<Value> {
return getAllInternal()
throw UnsupportedOperationException("Unknown key")
}
override suspend fun store(key: String, value: Value) {
try {
val json = adapter.toJson(value)
sharedPreferences.edit { putString(key, json) }
storeByKey(key, value)
writeTrigger.trigger()
} catch (e: Throwable) {
Timber.e(e, "Unable to edit preferences: $key")
@ -74,26 +68,13 @@ internal class SharedPreferencesDataStore<Value : Any>(
}
private fun getInternal(key: String): Value? {
return try {
val json = sharedPreferences.getString(key, null) ?: return null
if (!sharedPreferences.contains(key)) return null
adapter.fromJson(json)
return try {
getByKey(key)
} catch (e: Throwable) {
Timber.e(e, "Unable to get value from preferences: $key")
null
}
}
private fun getAllInternal(): List<Value> {
return sharedPreferences.all.mapNotNull { (key, value) ->
try {
val json = value as? String ?: return@mapNotNull null
adapter.fromJson(json)
} catch (e: Throwable) {
Timber.e(e, "Unable to convert value from JSON: $key")
null
}
}
}
}

View file

@ -0,0 +1,21 @@
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",
)

View file

@ -0,0 +1,21 @@
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",
)

View file

@ -0,0 +1,21 @@
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",
)

View file

@ -0,0 +1,21 @@
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",
)