Updated on 2026-08-14

This commit is contained in:
Tangem 2023-04-26 13:20:44 +03:00
parent 938d7baee1
commit 5d1cd85382
30 changed files with 332 additions and 204 deletions

View file

@ -20,6 +20,7 @@ import com.tangem.datasource.config.models.Config
import com.tangem.datasource.connection.NetworkConnectionManager
import com.tangem.domain.DomainLayer
import com.tangem.domain.common.LogConfig
import com.tangem.data.source.preferences.PreferencesDataSource
import com.tangem.tap.common.IntentHandler
import com.tangem.tap.common.analytics.AnalyticsFactory
import com.tangem.tap.common.analytics.api.AnalyticsHandlerBuilder
@ -51,7 +52,6 @@ import com.tangem.tap.domain.walletStores.repository.di.provideDefaultImplementa
import com.tangem.tap.domain.walletconnect.WalletConnectRepository
import com.tangem.tap.features.customtoken.api.featuretoggles.CustomTokenFeatureToggles
import com.tangem.tap.features.tokens.api.featuretoggles.TokensListFeatureToggles
import com.tangem.tap.persistence.PreferencesStorage
import com.tangem.tap.proxy.AppStateHolder
import com.tangem.tap.proxy.redux.DaggerGraphState
import com.tangem.wallet.BuildConfig
@ -66,7 +66,7 @@ lateinit var store: Store<AppState>
lateinit var foregroundActivityObserver: ForegroundActivityObserver
lateinit var activityResultCaller: ActivityResultCaller
lateinit var preferencesStorage: PreferencesStorage
lateinit var preferencesStorage: PreferencesDataSource
lateinit var walletConnectRepository: WalletConnectRepository
lateinit var shopService: TangemShopService
lateinit var userTokensRepository: UserTokensRepository
@ -134,6 +134,9 @@ class TapApplication : Application(), ImageLoaderFactory {
@Inject
lateinit var customTokenFeatureToggles: CustomTokenFeatureToggles
@Inject
lateinit var preferencesDataSource: PreferencesDataSource
override fun onCreate() {
super.onCreate()
@ -161,7 +164,7 @@ class TapApplication : Application(), ImageLoaderFactory {
registerActivityLifecycleCallbacks(foregroundActivityObserver.callbacks)
DomainLayer.init()
preferencesStorage = PreferencesStorage(this)
preferencesStorage = preferencesDataSource
walletConnectRepository = WalletConnectRepository(this)
val configLoader = FeaturesLocalLoader(assetReader, MoshiConverter.sdkMoshi, BuildConfig.ENVIRONMENT)
@ -246,7 +249,7 @@ class TapApplication : Application(), ImageLoaderFactory {
private fun initFeedbackManager(
context: Context,
preferencesStorage: PreferencesStorage,
preferencesStorage: PreferencesDataSource,
foregroundActivityObserver: ForegroundActivityObserver,
store: Store<AppState>,
) {

View file

@ -3,9 +3,11 @@ package com.tangem.tap.common.analytics.topup
import com.tangem.common.extensions.guard
import com.tangem.common.extensions.isZero
import com.tangem.core.analytics.Analytics
import com.tangem.data.source.preferences.model.DataSourceTopupInfo
import com.tangem.data.source.preferences.storage.ToppedUpWalletStorage
import com.tangem.domain.common.CardTypesResolver
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.common.util.UserWalletId
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.tap.common.analytics.converters.TopUpEventConverter
import com.tangem.tap.common.analytics.events.AnalyticsParam
@ -19,7 +21,6 @@ import com.tangem.tap.domain.tokens.models.BlockchainNetwork
import com.tangem.tap.domain.walletCurrencies.WalletCurrenciesManager
import com.tangem.tap.domain.walletStores.WalletStoresManager
import com.tangem.tap.features.wallet.models.Currency
import com.tangem.tap.persistence.ToppedUpWalletStorage
import com.tangem.tap.scope
import kotlinx.coroutines.launch
import java.math.BigDecimal
@ -90,9 +91,9 @@ class TopUpController(
val isToppedUpInPast = findToppedUpCurrenciesInPast(walletDataModels).isNotEmpty()
if (isToppedUpInPast) {
val newWalletInfo = ToppedUpWalletStorage.TopupInfo(
val newWalletInfo = DataSourceTopupInfo(
walletId = userWalletId.stringValue,
cardBalanceState = AnalyticsParam.CardBalanceState.Full,
cardBalanceState = DataSourceTopupInfo.CardBalanceState.Full,
)
topupWalletStorage.save(newWalletInfo)
return@launch
@ -109,9 +110,9 @@ class TopUpController(
fun registerEmptyWallet(scanResponse: ScanResponse) {
UserWalletIdBuilder.scanResponse(scanResponse).build()?.let {
topupWalletStorage.save(
ToppedUpWalletStorage.TopupInfo(
DataSourceTopupInfo(
walletId = it.stringValue,
cardBalanceState = AnalyticsParam.CardBalanceState.Empty,
cardBalanceState = DataSourceTopupInfo.CardBalanceState.Empty,
),
)
}
@ -129,17 +130,28 @@ class TopUpController(
cardTypesResolver: CardTypesResolver,
) {
val topupInfo = topupWalletStorage.restore(userWalletId.stringValue).guard {
val topupInfo = ToppedUpWalletStorage.TopupInfo(
val topupInfo = DataSourceTopupInfo(
walletId = userWalletId.stringValue,
cardBalanceState = cardBalanceState,
cardBalanceState = when (cardBalanceState) {
AnalyticsParam.CardBalanceState.BlockchainError ->
DataSourceTopupInfo.CardBalanceState.BlockchainError
AnalyticsParam.CardBalanceState.CustomToken ->
DataSourceTopupInfo.CardBalanceState.CustomToken
AnalyticsParam.CardBalanceState.Empty ->
DataSourceTopupInfo.CardBalanceState.Empty
AnalyticsParam.CardBalanceState.Full ->
DataSourceTopupInfo.CardBalanceState.Full
},
)
topupWalletStorage.save(topupInfo)
return
}
if (topupInfo.isToppedUp) return
if (!topupInfo.isToppedUp && cardBalanceState.isToppedUp()) {
topupWalletStorage.save(topupInfo.copy(cardBalanceState = AnalyticsParam.CardBalanceState.Full))
val isToppedUp = topupInfo.cardBalanceState == DataSourceTopupInfo.CardBalanceState.Full
if (isToppedUp) return
if (cardBalanceState.isToppedUp()) {
topupWalletStorage.save(topupInfo.copy(cardBalanceState = DataSourceTopupInfo.CardBalanceState.Full))
TopUpEventConverter().convert(cardTypesResolver)?.let {
Analytics.send(it)
}

View file

@ -2,19 +2,19 @@ package com.tangem.tap.common.chat
import android.content.Context
import android.os.Build
import com.tangem.tap.ForegroundActivityObserver
import com.tangem.datasource.config.models.ChatConfig
import com.tangem.tap.common.chat.opener.ChatOpener
import com.tangem.datasource.config.models.SprinklrConfig
import com.tangem.datasource.config.models.ZendeskConfig
import com.tangem.data.source.preferences.PreferencesDataSource
import com.tangem.tap.ForegroundActivityObserver
import com.tangem.tap.common.chat.opener.ChatOpener
import com.tangem.tap.common.chat.opener.implementation.SprinklrChatOpener
import com.tangem.tap.common.chat.opener.implementation.ZendeskChatOpener
import com.tangem.tap.common.redux.AppState
import com.tangem.tap.persistence.PreferencesStorage
import org.rekotlin.Store
class ChatManager(
private val preferencesStorage: PreferencesStorage,
private val preferencesStorage: PreferencesDataSource,
private val foregroundActivityObserver: ForegroundActivityObserver,
private val store: Store<AppState>,
) {

View file

@ -5,11 +5,12 @@ import com.tangem.common.core.TangemSdkError
import com.tangem.common.extensions.guard
import com.tangem.datasource.config.models.Config
import com.tangem.domain.common.LogConfig
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.common.extensions.withMainContext
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.models.scan.CardDTO
import com.tangem.domain.models.scan.ProductType
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.tap.common.entities.FiatCurrency
import com.tangem.tap.common.extensions.dispatchDebugErrorNotification
import com.tangem.tap.common.extensions.dispatchDialogShow
import com.tangem.tap.common.extensions.dispatchOnMain
@ -75,7 +76,9 @@ private fun handleAction(action: Action, appState: () -> AppState?, dispatch: Di
is GlobalAction.RestoreAppCurrency -> {
store.dispatch(
GlobalAction.RestoreAppCurrency.Success(
preferencesStorage.fiatCurrenciesPrefStorage.getAppCurrency(),
preferencesStorage.fiatCurrenciesPrefStorage.getAppCurrency()
?.run { FiatCurrency(code, name, symbol) }
?: FiatCurrency.Default,
),
)
}

View file

@ -19,9 +19,6 @@ import com.tangem.common.tlv.Tlv
import com.tangem.common.tlv.TlvDecoder
import com.tangem.crypto.CryptoUtils
import com.tangem.crypto.hdWallet.DerivationPath
import com.tangem.domain.models.scan.CardDTO
import com.tangem.domain.models.scan.ProductType
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.common.TapWorkarounds.isExcluded
import com.tangem.domain.common.TapWorkarounds.isNotSupportedInThatRelease
import com.tangem.domain.common.TapWorkarounds.isSaltPay
@ -29,6 +26,9 @@ import com.tangem.domain.common.TapWorkarounds.isStart2Coin
import com.tangem.domain.common.TapWorkarounds.isTangemTwins
import com.tangem.domain.common.TapWorkarounds.useOldStyleDerivation
import com.tangem.domain.common.TwinsHelper
import com.tangem.domain.models.scan.CardDTO
import com.tangem.domain.models.scan.ProductType
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.operations.PreflightReadMode
import com.tangem.operations.PreflightReadTask
import com.tangem.operations.ScanTask

View file

@ -1,6 +1,6 @@
package com.tangem.tap.features.disclaimer
import com.tangem.tap.persistence.DisclaimerPrefStorage
import com.tangem.data.source.preferences.storage.DisclaimerPrefStorage
/**
[REDACTED_AUTHOR]

View file

@ -1,11 +1,11 @@
package com.tangem.tap.features.disclaimer
import com.tangem.domain.models.scan.CardDTO
import com.tangem.domain.common.TapWorkarounds.isSaltPay
import com.tangem.domain.common.TapWorkarounds.isStart2Coin
import com.tangem.tap.persistence.DisclaimerPrefStorage
import com.tangem.domain.models.scan.CardDTO
import com.tangem.data.source.preferences.storage.DisclaimerPrefStorage
import com.tangem.tap.preferencesStorage
import java.util.*
import java.util.Locale
/**
[REDACTED_AUTHOR]

View file

@ -15,7 +15,7 @@ import com.tangem.tap.domain.extensions.getOrLoadCardArtworkUrl
import com.tangem.tap.features.wallet.models.Currency
import com.tangem.tap.features.wallet.models.hasPendingTransactions
import com.tangem.tap.features.wallet.redux.ProgressState
import com.tangem.tap.persistence.UsedCardsPrefStorage
import com.tangem.data.source.preferences.storage.UsedCardsPrefStorage
import timber.log.Timber
import java.math.BigDecimal

View file

@ -2,7 +2,9 @@ package com.tangem.tap.features.wallet.redux.middlewares
import com.tangem.common.extensions.guard
import com.tangem.core.analytics.Analytics
import com.tangem.datasource.api.tangemTech.models.CurrenciesResponse
import com.tangem.data.source.preferences.model.DataSourceCurrency
import com.tangem.data.source.preferences.model.DataSourceFiatCurrency
import com.tangem.data.source.preferences.storage.FiatCurrenciesPrefStorage
import com.tangem.tap.common.analytics.events.AnalyticsParam
import com.tangem.tap.common.analytics.events.MainScreen
import com.tangem.tap.common.entities.FiatCurrency
@ -14,7 +16,6 @@ import com.tangem.tap.features.wallet.domain.WalletRepository
import com.tangem.tap.features.wallet.redux.WalletAction
import com.tangem.tap.features.wallet.redux.models.WalletDialog
import com.tangem.tap.features.walletSelector.redux.WalletSelectorAction
import com.tangem.tap.persistence.FiatCurrenciesPrefStorage
import com.tangem.tap.scope
import com.tangem.tap.store
import com.tangem.tap.userWalletsListManager
@ -47,8 +48,10 @@ class AppCurrencyMiddleware(
scope.launch {
runCatching { walletRepository.getCurrencyList() }
.onSuccess {
val currenciesList = it.currencies
.onSuccess { response ->
val currenciesList = response.currencies
.map { with(it) { DataSourceCurrency(id, code, name, rateBTC, unit, type) } }
if (currenciesList.isNotEmpty() && currenciesList.toSet() != storedFiatCurrencies.toSet()) {
fiatCurrenciesPrefStorage.save(currenciesList)
store.dispatchDialogShow(
@ -64,7 +67,9 @@ class AppCurrencyMiddleware(
private fun selectCurrency(action: WalletAction.AppCurrencyAction.SelectAppCurrency) {
Analytics.send(MainScreen.MainCurrencyChanged(AnalyticsParam.CurrencyType.FiatCurrency(action.fiatCurrency)))
fiatCurrenciesPrefStorage.saveAppCurrency(action.fiatCurrency)
fiatCurrenciesPrefStorage.saveAppCurrency(
with(action.fiatCurrency) { DataSourceFiatCurrency(code, name, symbol) },
)
store.dispatch(GlobalAction.ChangeAppCurrency(action.fiatCurrency))
store.dispatch(DetailsAction.ChangeAppCurrency(action.fiatCurrency))
store.dispatch(WalletSelectorAction.ChangeAppCurrency(action.fiatCurrency))
@ -77,7 +82,7 @@ class AppCurrencyMiddleware(
}
}
private fun List<CurrenciesResponse.Currency>.mapToUiModel(): List<FiatCurrency> {
private fun List<DataSourceCurrency>.mapToUiModel(): List<FiatCurrency> {
return this.map {
FiatCurrency(
code = it.code,

View file

@ -1,20 +0,0 @@
package com.tangem.tap.persistence
import com.squareup.moshi.FromJson
import com.squareup.moshi.ToJson
import com.tangem.tap.common.analytics.events.AnalyticsParam
class CardBalanceStateAdapter {
@ToJson
fun toJson(src: AnalyticsParam.CardBalanceState): String = src.value
@FromJson
fun fromJson(json: String): AnalyticsParam.CardBalanceState {
return when (json) {
AnalyticsParam.CardBalanceState.Empty.value -> AnalyticsParam.CardBalanceState.Empty
AnalyticsParam.CardBalanceState.Full.value -> AnalyticsParam.CardBalanceState.Full
else -> error("CardBalanceState not found")
}
}
}

View file

@ -1,20 +0,0 @@
package com.tangem.tap.persistence
import android.content.SharedPreferences
import androidx.core.content.edit
/**
[REDACTED_AUTHOR]
*/
class DisclaimerPrefStorage(
private val preferences: SharedPreferences,
) {
fun accept(disclaimerKey: String) {
preferences.edit { putBoolean(disclaimerKey, true) }
}
fun isAccepted(disclaimerKey: String): Boolean {
return preferences.getBoolean(disclaimerKey, false)
}
}

View file

@ -1,55 +0,0 @@
package com.tangem.tap.persistence
import android.content.SharedPreferences
import androidx.core.content.edit
import com.tangem.common.json.MoshiJsonConverter
import com.tangem.datasource.api.tangemTech.models.CurrenciesResponse
import com.tangem.tap.common.entities.FiatCurrency
/**
[REDACTED_AUTHOR]
*/
class FiatCurrenciesPrefStorage(
private val preferences: SharedPreferences,
private val converter: MoshiJsonConverter,
) {
fun migrate() {
preferences.edit(true) {
remove(FIAT_CURRENCIES_KEY_OLD)
remove(APP_CURRENCY_KEY_OLD)
}
}
fun getAppCurrency(): FiatCurrency {
val json = preferences.getString(APP_CURRENCY_KEY, "")
if (json.isNullOrBlank()) return FiatCurrency.Default
return converter.fromJson(json) ?: FiatCurrency.Default
}
fun saveAppCurrency(fiatCurrency: FiatCurrency) {
val json = converter.toJson(fiatCurrency)
preferences.edit { putString(APP_CURRENCY_KEY, json) }
}
fun save(currencies: List<CurrenciesResponse.Currency>) {
val json: String = converter.toJson(currencies)
return preferences.edit().putString(FIAT_CURRENCIES_KEY, json).apply()
}
fun restore(): List<CurrenciesResponse.Currency> {
val json = preferences.getString(FIAT_CURRENCIES_KEY, "")
val type = converter.typedList(CurrenciesResponse.Currency::class.java)
if (json.isNullOrBlank()) return emptyList()
return converter.fromJson(json, type) ?: emptyList()
}
companion object {
private const val FIAT_CURRENCIES_KEY_OLD = "fiatCurrencies"
private const val APP_CURRENCY_KEY_OLD = "appCurrency"
private const val FIAT_CURRENCIES_KEY = "fiatCurrencies_v2"
private const val APP_CURRENCY_KEY = "appCurrency_v2"
}
}

View file

@ -1,171 +0,0 @@
package com.tangem.tap.persistence
import android.app.Application
import android.content.Context
import android.content.SharedPreferences
import androidx.core.content.edit
import com.tangem.common.json.MoshiJsonConverter
import com.tangem.datasource.api.common.BigDecimalAdapter
import java.util.*
class PreferencesStorage(applicationContext: Application) {
val appRatingLaunchObserver: AppRatingLaunchObserver
val usedCardsPrefStorage: UsedCardsPrefStorage
val fiatCurrenciesPrefStorage: FiatCurrenciesPrefStorage
val disclaimerPrefStorage: DisclaimerPrefStorage
val toppedUpWalletStorage: ToppedUpWalletStorage
private val preferences: SharedPreferences =
applicationContext.getSharedPreferences(PREFERENCES_NAME, Context.MODE_PRIVATE)
private val moshiConverter = MoshiJsonConverter(
adapters = listOf(BigDecimalAdapter(), CardBalanceStateAdapter()) + MoshiJsonConverter.getTangemSdkAdapters(),
typedAdapters = MoshiJsonConverter.getTangemSdkTypedAdapters(),
)
init {
incrementLaunchCounter()
appRatingLaunchObserver = AppRatingLaunchObserver(preferences, getCountOfLaunches())
usedCardsPrefStorage = UsedCardsPrefStorage(preferences, moshiConverter)
usedCardsPrefStorage.migrate()
fiatCurrenciesPrefStorage = FiatCurrenciesPrefStorage(preferences, moshiConverter)
fiatCurrenciesPrefStorage.migrate()
disclaimerPrefStorage = DisclaimerPrefStorage(preferences)
toppedUpWalletStorage = ToppedUpWalletStorage(preferences, moshiConverter)
}
var zendeskFirstLaunchTime: Long?
get() = preferences.getLong(ZENDESK_FIRST_LAUNCH_KEY, 0).takeIf { it != 0L }
set(value) = preferences.edit { putLong(ZENDESK_FIRST_LAUNCH_KEY, value ?: 0) }
var sprinklrFirstLaunchTime: Long?
get() = preferences.getLong(SPRINKLR_FIRST_LAUNCH_KEY, 0).takeIf { it != 0L }
set(value) = preferences.edit { putLong(SPRINKLR_FIRST_LAUNCH_KEY, value ?: 0) }
var shouldShowSaveUserWalletScreen: Boolean
get() = preferences.getBoolean(SAVE_WALLET_DIALOG_SHOWN_KEY, true)
set(value) = preferences.edit {
putBoolean(SAVE_WALLET_DIALOG_SHOWN_KEY, value)
}
var shouldSaveUserWallets: Boolean
get() = preferences.getBoolean(SAVE_USER_WALLETS_KEY, false)
set(value) = preferences.edit {
putBoolean(SAVE_USER_WALLETS_KEY, value)
}
var shouldSaveAccessCodes: Boolean
get() = preferences.getBoolean(SAVE_ACCESS_CODES_KEY, false)
set(value) = preferences.edit {
putBoolean(SAVE_ACCESS_CODES_KEY, value)
}
var wasApplicationStopped: Boolean
get() = preferences.getBoolean(APPLICATION_STOPPED_KEY, false)
set(value) = preferences.edit {
putBoolean(APPLICATION_STOPPED_KEY, value)
}
var shouldOpenWelcomeScreenOnResume: Boolean
get() = preferences.getBoolean(OPEN_WELCOME_ON_RESUME_KEY, false)
set(value) = preferences.edit {
putBoolean(OPEN_WELCOME_ON_RESUME_KEY, value)
}
fun getCountOfLaunches(): Int = preferences.getInt(APP_LAUNCH_COUNT_KEY, 1)
fun saveTwinsOnboardingShown() {
preferences.edit { putBoolean(TWINS_ONBOARDING_SHOWN_KEY, true) }
}
fun wasTwinsOnboardingShown(): Boolean {
return preferences.getBoolean(TWINS_ONBOARDING_SHOWN_KEY, false)
}
private fun incrementLaunchCounter() {
var count = preferences.getInt(APP_LAUNCH_COUNT_KEY, 0)
preferences.edit { putInt(APP_LAUNCH_COUNT_KEY, ++count) }
}
companion object {
private const val PREFERENCES_NAME = "tapPrefs"
private const val TWINS_ONBOARDING_SHOWN_KEY = "twinsOnboardingShown"
private const val APP_LAUNCH_COUNT_KEY = "launchCount"
private const val ZENDESK_FIRST_LAUNCH_KEY = "chatFirstLaunchKey"
private const val SPRINKLR_FIRST_LAUNCH_KEY = "sprinklrFirstLaunch"
private const val SAVE_WALLET_DIALOG_SHOWN_KEY = "saveUserWalletShown"
private const val SAVE_USER_WALLETS_KEY = "saveUserWallets"
private const val SAVE_ACCESS_CODES_KEY = "saveAccessCodes"
private const val APPLICATION_STOPPED_KEY = "applicationStopped"
private const val OPEN_WELCOME_ON_RESUME_KEY = "openWelcomeOnResume"
}
}
class AppRatingLaunchObserver(
private val preferences: SharedPreferences,
private val launchCounts: Int,
) {
private val deferShowing = 20
private val firstShowing = 3
private var fundsFoundDate: Calendar? = null
init {
val msWhenFundsWasFound = preferences.getLong(K_FUNDS_FOUND_DATE, FUNDS_FOUND_DATE_UNDEFINED)
if (msWhenFundsWasFound != FUNDS_FOUND_DATE_UNDEFINED) {
fundsFoundDate = Calendar.getInstance().apply { timeInMillis = msWhenFundsWasFound }
}
}
fun foundWalletWithFunds() {
if (fundsFoundDate != null) return
fundsFoundDate = Calendar.getInstance()
preferences.edit(true) {
putLong(K_FUNDS_FOUND_DATE, fundsFoundDate!!.timeInMillis).apply()
putInt(K_SHOW_RATING_AT_LAUNCH_COUNT, launchCounts + firstShowing)
}
}
@Suppress("MagicNumber")
fun isReadyToShow(): Boolean {
val fundsDate = fundsFoundDate ?: return false
if (!userWasInteractWithRating()) {
val diff = Calendar.getInstance().timeInMillis - fundsDate.timeInMillis
val diffInDays = diff / (1000 * 60 * 60 * 24)
return launchCounts >= getCounterOfNextShowing() && diffInDays >= firstShowing
}
val nextShowing = getCounterOfNextShowing()
return launchCounts >= nextShowing
}
fun applyDelayedShowing() {
updateNextShowing(launchCounts + deferShowing)
}
@Suppress("MagicNumber")
fun setNeverToShow() {
updateNextShowing(999999999)
}
private fun updateNextShowing(at: Int) {
val editor = preferences.edit()
editor.putInt(K_SHOW_RATING_AT_LAUNCH_COUNT, at)
editor.putBoolean(K_USER_WAS_INTERACT_WITH_RATING, true)
editor.apply()
}
private fun userWasInteractWithRating(): Boolean = preferences.getBoolean(K_USER_WAS_INTERACT_WITH_RATING, false)
private fun getCounterOfNextShowing(): Int = preferences.getInt(K_SHOW_RATING_AT_LAUNCH_COUNT, firstShowing)
companion object {
private const val K_SHOW_RATING_AT_LAUNCH_COUNT = "showRatingDialogAtLaunchCount"
private const val K_FUNDS_FOUND_DATE = "fundsFoundDate"
private const val K_USER_WAS_INTERACT_WITH_RATING = "userWasInteractWithRating"
private const val FUNDS_FOUND_DATE_UNDEFINED = -1L
}
}

View file

@ -1,66 +0,0 @@
package com.tangem.tap.persistence
import android.content.SharedPreferences
import androidx.core.content.edit
import com.tangem.common.json.MoshiJsonConverter
import com.tangem.tap.common.analytics.events.AnalyticsParam
import timber.log.Timber
/**
[REDACTED_AUTHOR]
*/
class ToppedUpWalletStorage(
private val preferences: SharedPreferences,
private val jsonConverter: MoshiJsonConverter,
) {
private val walletList: MutableSet<TopupInfo> = mutableSetOf()
init {
walletList.addAll(restore())
}
fun save(userWalletInfo: TopupInfo): Boolean {
walletList.removeAll { it.walletId == userWalletInfo.walletId }
walletList.add(userWalletInfo)
return save(walletList)
}
fun restore(walletId: String): TopupInfo? {
return walletList.firstOrNull { it.walletId == walletId }
}
private fun save(userWallets: MutableSet<TopupInfo>): Boolean {
return try {
val json = jsonConverter.toJson(userWallets)
preferences.edit(true) { putString(KEY, json) }
true
} catch (ex: Exception) {
Timber.e(ex)
false
}
}
private fun restore(): MutableSet<TopupInfo> {
val json = preferences.getString(KEY, null) ?: return mutableSetOf()
return try {
val typedList = jsonConverter.typedList(TopupInfo::class.java)
val listData = jsonConverter.fromJson<List<TopupInfo>>(json, typedList)!!
listData.toMutableSet()
} catch (ex: Exception) {
preferences.edit(true) { remove(KEY) }
mutableSetOf()
}
}
data class TopupInfo(
val walletId: String,
val cardBalanceState: AnalyticsParam.CardBalanceState,
) {
val isToppedUp: Boolean = cardBalanceState == AnalyticsParam.CardBalanceState.Full
}
companion object {
private const val KEY = "userWalletsInfo"
}
}

View file

@ -1,154 +0,0 @@
package com.tangem.tap.persistence
import android.content.SharedPreferences
import androidx.core.content.edit
import com.tangem.common.json.MoshiJsonConverter
import com.tangem.tap.common.extensions.replaceByOrAdd
import timber.log.Timber
/**
[REDACTED_AUTHOR]
*/
class UsedCardsPrefStorage(
private val preferences: SharedPreferences,
private val jsonConverter: MoshiJsonConverter,
) {
private val migrationList = mutableListOf(
UserCardInfoToV2(this),
)
internal fun migrate() {
migrationList.forEach { it.migrate() }
migrationList.clear()
}
fun scanned(cardId: String) {
val restoredList = restore()
val foundItem = findCardInfo(cardId, restoredList)?.copy(isScanned = true)
?: UsedCardInfo(cardId, true)
save(foundItem, restoredList)
}
fun wasScanned(cardId: String): Boolean {
return findCardInfo(cardId)?.isScanned ?: false
}
fun activationStarted(cardId: String) {
val restoredList = restore()
val foundItem = findCardInfo(cardId, restoredList)?.copy(isActivationStarted = true)
?: UsedCardInfo(cardId, isActivationStarted = true)
save(foundItem, restoredList)
}
fun activationFinished(cardId: String) {
val restoredList = restore()
var foundItem = findCardInfo(cardId, restoredList) ?: UsedCardInfo(cardId)
foundItem = foundItem.copy(
isActivationStarted = true,
isActivationFinished = true,
)
save(foundItem, restoredList)
}
fun isActivationStarted(cardId: String): Boolean {
return findCardInfo(cardId)?.isActivationStarted ?: false
}
fun isActivationFinished(cardId: String): Boolean {
return findCardInfo(cardId)?.isActivationFinished ?: false
}
fun isActivationInProgress(cardId: String): Boolean {
val cardInfo = findCardInfo(cardId) ?: return false
return cardInfo.isActivationStarted && !cardInfo.isActivationFinished
}
private fun findCardInfo(cardId: String, list: MutableList<UsedCardInfo>? = null): UsedCardInfo? {
val findInList = list ?: restore()
return findInList.firstOrNull { it.cardId == cardId }
}
private fun save(usedCardInfo: UsedCardInfo?, usedCardsInfo: MutableList<UsedCardInfo>) {
val info = usedCardInfo ?: return
usedCardsInfo.replaceByOrAdd(info) { it.cardId == info.cardId }
save(usedCardsInfo)
}
private fun save(list: MutableList<UsedCardInfo>): Boolean {
return try {
val json = jsonConverter.toJson(list)
preferences.edit { putString(USED_CARDS_INFO_V2, json) }
true
} catch (ex: Exception) {
Timber.e(ex)
false
}
}
private fun restore(): MutableList<UsedCardInfo> {
val json = preferences.getString(USED_CARDS_INFO_V2, null) ?: return mutableListOf()
return try {
jsonConverter.fromJson(json, jsonConverter.typedList(UsedCardInfo::class.java))!!
} catch (ex: Exception) {
preferences.edit(true) { remove(USED_CARDS_INFO_V2) }
mutableListOf()
}
}
companion object {
private const val USED_CARDS_INFO_V2 = "usedCardsInfo_v2"
private const val USED_CARDS_INFO = "usedCardsInfo"
}
private class UserCardInfoToV2(
private val storage: UsedCardsPrefStorage,
) : Migration {
override fun migrate() {
val restoredCardsInfo = restore()
if (restoredCardsInfo.isEmpty()) return
val newCardsInfo = restoredCardsInfo.map { cardInfo ->
UsedCardInfo(
cardId = cardInfo.cardId,
isScanned = cardInfo.isScanned,
isActivationStarted = true,
isActivationFinished = !cardInfo.isActivationStarted,
)
}.toMutableList()
storage.save(newCardsInfo)
}
private fun restore(): MutableList<UsedCardInfoOld> {
val json = storage.preferences.getString(USED_CARDS_INFO, null) ?: return mutableListOf()
return try {
storage.jsonConverter.fromJson(json, storage.jsonConverter.typedList(UsedCardInfoOld::class.java))!!
} catch (ex: Exception) {
mutableListOf()
} finally {
storage.preferences.edit(true) { remove(USED_CARDS_INFO) }
}
}
}
private data class UsedCardInfo(
val cardId: String,
val isScanned: Boolean = false,
val isActivationStarted: Boolean = false,
val isActivationFinished: Boolean = false,
)
private data class UsedCardInfoOld(
val cardId: String,
val isScanned: Boolean = false,
val isActivationStarted: Boolean = false,
)
}
private interface Migration {
fun migrate()
}