Updated on 2026-08-14

This commit is contained in:
Tangem 2024-02-19 23:53:28 +07:00
parent 494aa88d35
commit aa059666ba
10 changed files with 96 additions and 51 deletions

View file

@ -8,8 +8,8 @@ import android.net.Uri
interface Disclaimer {
fun type(): DisclaimerType
fun getUri(): Uri
fun accept()
fun isAccepted(): Boolean
suspend fun accept()
suspend fun isAccepted(): Boolean
}
abstract class BaseDisclaimer(
@ -18,32 +18,28 @@ abstract class BaseDisclaimer(
val baseUrl = "https://tangem.com"
override fun accept() {
dataProvider.storage().accept(getPreferenceKey())
override suspend fun accept() {
dataProvider.accept()
}
override fun isAccepted(): Boolean = dataProvider.storage().isAccepted(getPreferenceKey())
protected open fun getPreferenceKey(): String = type().name
override suspend fun isAccepted(): Boolean = dataProvider.isAccepted()
}
class DummyDisclaimer : Disclaimer {
override fun type(): DisclaimerType = DisclaimerType.Tangem
override fun getUri(): Uri = Uri.parse("https://tangem.com/tangem_tos.html")
override fun accept() {}
override fun isAccepted(): Boolean = false
override suspend fun accept() {}
override suspend fun isAccepted(): Boolean = false
}
class TangemDisclaimer(dataProvider: DisclaimerDataProvider) : BaseDisclaimer(dataProvider) {
override fun type(): DisclaimerType = DisclaimerType.Tangem
override fun getUri(): Uri = Uri.parse("$baseUrl/tangem_tos.html")
override fun getPreferenceKey(): String = "tangem_tos_accepted"
}
class Start2CoinDisclaimer(dataProvider: DisclaimerDataProvider) : BaseDisclaimer(dataProvider) {
override fun type(): DisclaimerType = DisclaimerType.Start2Coin
override fun getUri(): Uri = Uri.parse("$baseUrl/" + filename(dataProvider.getLanguage(), getRegion()))
override fun getPreferenceKey(): String = "start2Coin_tos_accepted_${getRegion()}"
@Suppress("ComplexMethod")
private fun filename(languageCode: String, regionCode: String?): String {

View file

@ -1,12 +1,11 @@
package com.tangem.tap.features.disclaimer
import com.tangem.data.source.preferences.storage.DisclaimerPrefStorage
/**
[REDACTED_AUTHOR]
*/
interface DisclaimerDataProvider {
fun getLanguage(): String
fun getCardId(): String
fun storage(): DisclaimerPrefStorage
suspend fun accept()
suspend fun isAccepted(): Boolean
}

View file

@ -2,8 +2,8 @@ package com.tangem.tap.features.disclaimer
import com.tangem.domain.common.TapWorkarounds.isStart2Coin
import com.tangem.domain.models.scan.CardDTO
import com.tangem.data.source.preferences.storage.DisclaimerPrefStorage
import com.tangem.tap.preferencesStorage
import com.tangem.tap.proxy.redux.DaggerGraphState
import com.tangem.tap.store
import java.util.Locale
/**
@ -25,7 +25,7 @@ enum class DisclaimerType {
}
fun DisclaimerType.createDisclaimer(cardDTO: CardDTO): Disclaimer {
val dataProvider = provideDisclaimerDataProvider(cardDTO.cardId)
val dataProvider = provideDisclaimerDataProvider(cardDTO.cardId, this)
return when (this) {
DisclaimerType.Tangem -> TangemDisclaimer(dataProvider)
DisclaimerType.Start2Coin -> Start2CoinDisclaimer(dataProvider)
@ -34,10 +34,24 @@ fun DisclaimerType.createDisclaimer(cardDTO: CardDTO): Disclaimer {
fun CardDTO.createDisclaimer(): Disclaimer = DisclaimerType.get(this).createDisclaimer(this)
private fun provideDisclaimerDataProvider(cardId: String): DisclaimerDataProvider {
private fun provideDisclaimerDataProvider(cardId: String, disclaimerType: DisclaimerType): DisclaimerDataProvider {
val cardRepository = store.state.daggerGraphState.get(DaggerGraphState::cardRepository)
return object : DisclaimerDataProvider {
override fun getLanguage(): String = Locale.getDefault().language
override fun getCardId(): String = cardId
override fun storage(): DisclaimerPrefStorage = preferencesStorage.disclaimerPrefStorage
override suspend fun accept() {
when (disclaimerType) {
DisclaimerType.Tangem -> cardRepository.acceptTangemTOS()
DisclaimerType.Start2Coin -> cardRepository.acceptStart2CoinTOS(cardId)
}
}
override suspend fun isAccepted(): Boolean {
return when (disclaimerType) {
DisclaimerType.Tangem -> cardRepository.isTangemTOSAccepted()
DisclaimerType.Start2Coin -> cardRepository.isStart2CoinTOSAccepted(cardId)
}
}
}
}

View file

@ -3,7 +3,9 @@ package com.tangem.tap.features.disclaimer.redux
import com.tangem.core.navigation.AppScreen
import com.tangem.core.navigation.NavigationAction
import com.tangem.tap.common.redux.AppState
import com.tangem.tap.mainScope
import com.tangem.tap.store
import kotlinx.coroutines.launch
import org.rekotlin.Action
import org.rekotlin.Middleware
@ -26,9 +28,11 @@ private fun handleDisclaimerMiddleware(action: Action, appState: AppState) {
store.dispatch(NavigationAction.NavigateTo(AppScreen.Disclaimer))
}
is DisclaimerAction.AcceptDisclaimer -> {
state.disclaimer.accept()
store.dispatch(NavigationAction.PopBackTo())
state.callback?.onAccept?.invoke()
mainScope.launch {
state.disclaimer.accept()
store.dispatch(NavigationAction.PopBackTo())
state.callback?.onAccept?.invoke()
}
}
is DisclaimerAction.OnBackPressed -> {
store.dispatch(NavigationAction.PopBackTo())

View file

@ -4,6 +4,7 @@ import android.os.Bundle
import android.view.View
import android.view.View.OVER_SCROLL_NEVER
import android.webkit.WebView
import androidx.lifecycle.lifecycleScope
import androidx.transition.TransitionInflater
import by.kirich1409.viewbindingdelegate.viewBinding
import com.tangem.core.navigation.AppScreen
@ -21,6 +22,7 @@ import com.tangem.tap.features.disclaimer.redux.DisclaimerState
import com.tangem.tap.store
import com.tangem.wallet.R
import com.tangem.wallet.databinding.FragmentDisclaimerBinding
import kotlinx.coroutines.launch
import org.rekotlin.StoreSubscriber
class DisclaimerFragment : BaseFragment(R.layout.fragment_disclaimer), StoreSubscriber<DisclaimerState> {
@ -92,10 +94,12 @@ class DisclaimerFragment : BaseFragment(R.layout.fragment_disclaimer), StoreSubs
store.dispatch(DisclaimerAction.OnBackPressed)
}
override fun newState(state: DisclaimerState) = with(binding) {
if (activity == null || view == null) return
override fun newState(state: DisclaimerState) {
return with(binding) {
if (activity == null || view == null) return
updateUiVisibility(state.disclaimer, state.progressState)
updateUiVisibility(state.disclaimer, state.progressState)
}
}
private fun updateUiVisibility(disclaimer: Disclaimer, progressState: ProgressState?) = with(binding) {
@ -112,7 +116,9 @@ class DisclaimerFragment : BaseFragment(R.layout.fragment_disclaimer), StoreSubs
groupError.hide()
groupLoading.hide()
webView.show()
groupAccept.show(!disclaimer.isAccepted())
lifecycleScope.launch {
groupAccept.show(!disclaimer.isAccepted())
}
}
ProgressState.Error -> {
root.beginDelayedTransition()

View file

@ -3,6 +3,7 @@ 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.IS_TANGEM_TOS_ACCEPTED_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
@ -57,6 +58,10 @@ object PreferencesKeys {
val FEATURE_TOGGLES_KEY by lazy { stringPreferencesKey(name = "featureToggles") }
val WAS_TWINS_ONBOARDING_SHOWN by lazy { booleanPreferencesKey(name = "twinsOnboardingShown") }
val IS_TANGEM_TOS_ACCEPTED_KEY by lazy { booleanPreferencesKey(name = "tangem_tos_accepted") }
fun getStart2CoinTOSAcceptedKey(region: String?) = booleanPreferencesKey(name = "start2Coin_tos_accepted_$region")
}
/** Preferences keys set that should be migrated from "PreferencesDataSource" to a new DataStore<Preferences> */
@ -69,6 +74,7 @@ internal fun getTapPrefKeysToMigrate(): Set<String> {
USER_WAS_INTERACT_WITH_RATING_KEY,
USED_CARDS_INFO_KEY,
WAS_TWINS_ONBOARDING_SHOWN,
IS_TANGEM_TOS_ACCEPTED_KEY,
)
.map(Preferences.Key<*>::name)
.toSet()

View file

@ -6,6 +6,8 @@ import com.tangem.datasource.local.preferences.AppPreferencesStore
import com.tangem.datasource.local.preferences.PreferencesKeys
import com.tangem.datasource.local.preferences.utils.getObjectList
import com.tangem.datasource.local.preferences.utils.getObjectListSync
import com.tangem.datasource.local.preferences.utils.getSyncOrDefault
import com.tangem.datasource.local.preferences.utils.store
import com.tangem.domain.card.repository.CardRepository
import com.tangem.utils.extensions.addOrReplace
import kotlinx.coroutines.flow.Flow
@ -64,6 +66,28 @@ internal class DefaultCardRepository(
return card.isActivationStarted && !card.isActivationFinished
}
override suspend fun isTangemTOSAccepted(): Boolean {
return appPreferencesStore.getSyncOrDefault(key = PreferencesKeys.IS_TANGEM_TOS_ACCEPTED_KEY, default = false)
}
override suspend fun isStart2CoinTOSAccepted(cardId: String): Boolean {
return appPreferencesStore.getSyncOrDefault(
key = PreferencesKeys.getStart2CoinTOSAcceptedKey(region = getRegion(cardId)),
default = false,
)
}
override suspend fun acceptTangemTOS() {
return appPreferencesStore.store(key = PreferencesKeys.IS_TANGEM_TOS_ACCEPTED_KEY, true)
}
override suspend fun acceptStart2CoinTOS(cardId: String) {
appPreferencesStore.store(
key = PreferencesKeys.getStart2CoinTOSAcceptedKey(region = getRegion(cardId)),
value = true,
)
}
private suspend fun AppPreferencesStore.editUsedCards(cardId: String, update: (UsedCardInfo) -> UsedCardInfo) {
editData { mutablePreferences ->
val usedCards = mutablePreferences.getUsedCards()
@ -92,4 +116,15 @@ internal class DefaultCardRepository(
return appPreferencesStore.getObjectListSync<UsedCardInfo>(PreferencesKeys.USED_CARDS_INFO_KEY)
.firstOrNull { it.cardId == cardId }
}
private fun getRegion(cardId: String): String? {
if (cardId.isEmpty()) return null
return when (cardId[1]) {
'0' -> "fr"
'1' -> "ch"
'2' -> "at"
else -> null
}
}
}

View file

@ -3,7 +3,6 @@ package com.tangem.data.source.preferences
import android.content.Context
import android.content.SharedPreferences
import androidx.core.content.edit
import com.tangem.data.source.preferences.storage.DisclaimerPrefStorage
import javax.inject.Inject
// 🔥FIXME: Only logic to work with preferences must be here, must be separated to repositories
@ -11,14 +10,11 @@ import javax.inject.Inject
@Deprecated("Create repository instead")
class PreferencesDataSource @Inject internal constructor(applicationContext: Context) {
val disclaimerPrefStorage: DisclaimerPrefStorage
private val preferences: SharedPreferences =
applicationContext.getSharedPreferences(PREFERENCES_NAME, Context.MODE_PRIVATE)
init {
incrementLaunchCounter()
disclaimerPrefStorage = DisclaimerPrefStorage(preferences)
}
var shouldShowSaveUserWalletScreen: Boolean

View file

@ -1,21 +0,0 @@
package com.tangem.data.source.preferences.storage
import android.content.SharedPreferences
import androidx.core.content.edit
/**
[REDACTED_AUTHOR]
*/
@Deprecated("Create repository instead")
class DisclaimerPrefStorage internal constructor(
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

@ -22,4 +22,14 @@ interface CardRepository {
@Throws
suspend fun isActivationInProgress(cardId: String): Boolean
@Throws
suspend fun isTangemTOSAccepted(): Boolean
@Throws
suspend fun isStart2CoinTOSAccepted(cardId: String): Boolean
suspend fun acceptTangemTOS()
suspend fun acceptStart2CoinTOS(cardId: String)
}