Updated on 2026-08-14
This commit is contained in:
parent
f968430c59
commit
905792c77e
20 changed files with 384 additions and 197 deletions
|
|
@ -21,10 +21,10 @@ import com.tangem.tap.common.redux.AppDialog
|
|||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
import com.tangem.tap.common.redux.navigation.AppScreen
|
||||
import com.tangem.tap.common.redux.navigation.NavigationAction
|
||||
import com.tangem.tap.features.disclaimer.DisclaimerType
|
||||
import com.tangem.tap.features.disclaimer.createDisclaimer
|
||||
import com.tangem.tap.features.disclaimer.redux.DisclaimerAction
|
||||
import com.tangem.tap.features.disclaimer.redux.DisclaimerCallback
|
||||
import com.tangem.tap.features.disclaimer.redux.DisclaimerType
|
||||
import com.tangem.tap.features.disclaimer.redux.isAccepted
|
||||
import com.tangem.tap.features.onboarding.OnboardingHelper
|
||||
import com.tangem.tap.features.onboarding.OnboardingSaltPayHelper
|
||||
import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsAction
|
||||
|
|
@ -137,16 +137,17 @@ object ScanCardProcessor {
|
|||
crossinline nextHandler: suspend (ScanResponse) -> Unit,
|
||||
crossinline onFailure: suspend (error: TangemError) -> Unit,
|
||||
) {
|
||||
val disclaimerType = DisclaimerType.get(scanResponse)
|
||||
store.dispatchOnMain(DisclaimerAction.SetDisclaimerType(disclaimerType))
|
||||
val disclaimer = DisclaimerType.get(scanResponse.card).createDisclaimer(scanResponse.card)
|
||||
store.dispatchOnMain(DisclaimerAction.SetDisclaimer(disclaimer))
|
||||
|
||||
if (disclaimerType.isAccepted()) {
|
||||
if (disclaimer.isAccepted()) {
|
||||
nextHandler((scanResponse))
|
||||
} else scope.launch(Dispatchers.Main) {
|
||||
} else scope.launch {
|
||||
delay(DELAY_SDK_DIALOG_CLOSE)
|
||||
disclaimerWillShow()
|
||||
store.dispatchOnMain(
|
||||
dispatchOnMain(
|
||||
DisclaimerAction.Show(
|
||||
fromScreen = AppScreen.Home,
|
||||
callback = DisclaimerCallback(
|
||||
onAccept = {
|
||||
scope.launch(Dispatchers.Main) {
|
||||
|
|
|
|||
|
|
@ -1,47 +0,0 @@
|
|||
package com.tangem.tap.domain.termsOfUse
|
||||
|
||||
import android.content.res.Resources
|
||||
import android.net.Uri
|
||||
import androidx.core.os.ConfigurationCompat
|
||||
import com.tangem.domain.common.CardDTO
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
class CardTou {
|
||||
private val locale: Locale =
|
||||
ConfigurationCompat.getLocales(Resources.getSystem().configuration).get(0)!!
|
||||
|
||||
fun getUrl(card: CardDTO): Uri? {
|
||||
val issuerName = card.issuer.name
|
||||
if (issuerName.lowercase(Locale.getDefault()) != "start2coin") return null
|
||||
|
||||
val baseUrl = "https://app.tangem.com/tou/"
|
||||
val regionCode = regionCode(card.cardId) ?: "fr"
|
||||
val filename = filename(locale.language, regionCode)
|
||||
return Uri.parse(baseUrl + filename)
|
||||
}
|
||||
|
||||
private fun filename(languageCode: String, regionCode: String): String {
|
||||
return when {
|
||||
languageCode == "fr" && regionCode == "ch" -> "Start2Coin-fr-ch-tangem.pdf"
|
||||
languageCode == "de" && regionCode == "ch" -> "Start2Coin-de-ch-tangem.pdf"
|
||||
languageCode == "en" && regionCode == "ch" -> "Start2Coin-en-ch-tangem.pdf"
|
||||
languageCode == "it" && regionCode == "ch" -> "Start2Coin-it-ch-tangem.pdf"
|
||||
languageCode == "fr" && regionCode == "fr" -> "Start2Coin-fr-fr-atangem.pdf"
|
||||
languageCode == "de" && regionCode == "at" -> "Start2Coin-de-at-tangem.pdf"
|
||||
regionCode == "fr" -> "Start2Coin-fr-fr-atangem.pdf"
|
||||
regionCode == "ch" -> "Start2Coin-en-ch-tangem.pdf"
|
||||
regionCode == "at" -> "Start2Coin-de-at-tangem.pdf"
|
||||
else -> "Start2Coin-fr-fr-atangem.pdf"
|
||||
}
|
||||
}
|
||||
|
||||
private fun regionCode(cardId: String): String? = when (cardId[1]) {
|
||||
'0' -> "fr"
|
||||
'1' -> "ch"
|
||||
'2' -> "at"
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
|
@ -4,7 +4,6 @@ import com.tangem.blockchain.common.Wallet
|
|||
import com.tangem.domain.common.CardDTO
|
||||
import com.tangem.domain.common.ScanResponse
|
||||
import com.tangem.tap.common.entities.FiatCurrency
|
||||
import com.tangem.tap.domain.termsOfUse.CardTou
|
||||
import org.rekotlin.Action
|
||||
|
||||
sealed class DetailsAction : Action {
|
||||
|
|
@ -12,10 +11,8 @@ sealed class DetailsAction : Action {
|
|||
data class PrepareScreen(
|
||||
val scanResponse: ScanResponse,
|
||||
val wallets: List<Wallet>,
|
||||
val cardTou: CardTou,
|
||||
) : DetailsAction()
|
||||
|
||||
object ShowDisclaimer : DetailsAction()
|
||||
object ReCreateTwinsWallet : DetailsAction()
|
||||
|
||||
sealed class ResetToFactory : DetailsAction() {
|
||||
|
|
|
|||
|
|
@ -61,12 +61,6 @@ class DetailsMiddleware {
|
|||
is DetailsAction.ResetToFactory -> eraseWalletMiddleware.handle(action)
|
||||
is DetailsAction.ManageSecurity -> manageSecurityMiddleware.handle(action)
|
||||
is DetailsAction.AppSettings -> managePrivacyMiddleware.handle(state, action)
|
||||
is DetailsAction.ShowDisclaimer -> {
|
||||
val uri = state.cardTermsOfUseUrl
|
||||
if (uri != null) {
|
||||
store.dispatch(NavigationAction.OpenDocument(uri))
|
||||
}
|
||||
}
|
||||
is DetailsAction.ReCreateTwinsWallet -> {
|
||||
store.dispatch(TwinCardsAction.SetMode(CreateTwinWalletMode.RecreateWallet))
|
||||
store.dispatch(NavigationAction.NavigateTo(AppScreen.OnboardingTwins))
|
||||
|
|
|
|||
|
|
@ -52,7 +52,6 @@ private fun handlePrepareScreen(
|
|||
return DetailsState(
|
||||
scanResponse = action.scanResponse,
|
||||
wallets = action.wallets,
|
||||
cardTermsOfUseUrl = action.cardTou.getUrl(action.scanResponse.card),
|
||||
createBackupAllowed = action.scanResponse.card.backupStatus == CardDTO.BackupStatus.NoBackup,
|
||||
appCurrency = store.state.globalState.appCurrency,
|
||||
isBiometricsAvailable = tangemSdkManager.canUseBiometry,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
package com.tangem.tap.features.details.redux
|
||||
|
||||
import android.net.Uri
|
||||
import com.tangem.blockchain.common.Wallet
|
||||
import com.tangem.domain.common.CardDTO
|
||||
import com.tangem.domain.common.ScanResponse
|
||||
|
|
@ -16,7 +15,6 @@ data class DetailsState(
|
|||
val scanResponse: ScanResponse? = null,
|
||||
val wallets: List<Wallet> = emptyList(),
|
||||
val cardSettingsState: CardSettingsState? = null,
|
||||
val cardTermsOfUseUrl: Uri? = null,
|
||||
val privacyPolicyUrl: String? = null,
|
||||
val createBackupAllowed: Boolean = false,
|
||||
val appCurrency: FiatCurrency = FiatCurrency.Default,
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@ enum class SettingsElement(
|
|||
AppSettings(R.drawable.ic_settings, R.string.app_settings_title),
|
||||
LinkMoreCards(R.drawable.ic_more_cards, R.string.details_row_title_create_backup),
|
||||
TermsOfService(R.drawable.ic_text, R.string.disclaimer_title), // General Terms of Service of the App
|
||||
TermsOfUse(R.drawable.ic_text, R.string.details_row_title_card_tou), // Terms of Use for S2C cards only
|
||||
PrivacyPolicy(R.drawable.ic_lock_24, R.string.details_row_privacy_policy);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -38,7 +38,6 @@ class DetailsViewModel(private val store: Store<AppState>) {
|
|||
}
|
||||
SettingsElement.AppSettings -> if (state.isBiometricsAvailable) it else null
|
||||
SettingsElement.AppCurrency -> if (state.scanResponse?.card?.isMultiwalletAllowed != true) it else null
|
||||
SettingsElement.TermsOfUse -> if (state.scanResponse?.card?.isStart2Coin == true) it else null
|
||||
// SettingsElement.ReferralProgram -> if (state.scanResponse?.card?.isTangemWallet == true) it else null
|
||||
else -> it
|
||||
}
|
||||
|
|
@ -88,10 +87,7 @@ class DetailsViewModel(private val store: Store<AppState>) {
|
|||
store.dispatch(DetailsAction.CreateBackup)
|
||||
}
|
||||
SettingsElement.TermsOfService -> {
|
||||
store.dispatch(DisclaimerAction.Show())
|
||||
}
|
||||
SettingsElement.TermsOfUse -> {
|
||||
store.dispatch(DetailsAction.ShowDisclaimer)
|
||||
store.dispatch(DisclaimerAction.Show(AppScreen.Details))
|
||||
}
|
||||
SettingsElement.PrivacyPolicy -> {
|
||||
// TODO: To be available later
|
||||
|
|
|
|||
|
|
@ -0,0 +1,80 @@
|
|||
package com.tangem.tap.features.disclaimer
|
||||
|
||||
import android.net.Uri
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
interface Disclaimer {
|
||||
fun type(): DisclaimerType
|
||||
fun getUri(): Uri
|
||||
fun accept()
|
||||
fun isAccepted(): Boolean
|
||||
}
|
||||
|
||||
abstract class BaseDisclaimer(
|
||||
protected val dataProvider: DisclaimerDataProvider,
|
||||
) : Disclaimer {
|
||||
|
||||
val baseUrl = "https://tangem.com"
|
||||
|
||||
override fun accept() {
|
||||
dataProvider.storage().accept(getPreferenceKey())
|
||||
}
|
||||
|
||||
override fun isAccepted(): Boolean = dataProvider.storage().isAccepted(getPreferenceKey())
|
||||
|
||||
protected open fun getPreferenceKey(): String = type().name
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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 SaltPayDisclaimer(dataProvider: DisclaimerDataProvider) : BaseDisclaimer(dataProvider) {
|
||||
override fun type(): DisclaimerType = DisclaimerType.SaltPay
|
||||
override fun getUri(): Uri = Uri.parse("$baseUrl/soltpay_tos.html")
|
||||
override fun getPreferenceKey(): String = "saltPay_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()}"
|
||||
|
||||
private fun filename(languageCode: String, regionCode: String?): String {
|
||||
return when {
|
||||
languageCode == "fr" && regionCode == "ch" -> "Start2Coin-fr-ch-tangem.html"
|
||||
languageCode == "de" && regionCode == "ch" -> "Start2Coin-de-ch-tangem.html"
|
||||
languageCode == "en" && regionCode == "ch" -> "Start2Coin-en-ch-tangem.html"
|
||||
languageCode == "it" && regionCode == "ch" -> "Start2Coin-it-ch-tangem.html"
|
||||
languageCode == "fr" && regionCode == "fr" -> "Start2Coin-fr-fr-atangem.html"
|
||||
languageCode == "de" && regionCode == "at" -> "Start2Coin-de-at-tangem.html"
|
||||
regionCode == "fr" -> "Start2Coin-fr-fr-atangem.html"
|
||||
regionCode == "ch" -> "Start2Coin-en-ch-tangem.html"
|
||||
regionCode == "at" -> "Start2Coin-de-at-tangem.html"
|
||||
else -> "Start2Coin-fr-fr-atangem.html"
|
||||
}
|
||||
}
|
||||
|
||||
private fun getRegion(): String? {
|
||||
val cardId = dataProvider.getCardId()
|
||||
if (cardId.isEmpty()) return null
|
||||
|
||||
return when (cardId[1]) {
|
||||
'0' -> "fr"
|
||||
'1' -> "ch"
|
||||
'2' -> "at"
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
package com.tangem.tap.features.disclaimer
|
||||
|
||||
import com.tangem.tap.persistence.DisclaimerPrefStorage
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
interface DisclaimerDataProvider {
|
||||
fun getLanguage(): String
|
||||
fun getCardId(): String
|
||||
fun storage(): DisclaimerPrefStorage
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
package com.tangem.tap.features.disclaimer
|
||||
|
||||
import com.tangem.domain.common.CardDTO
|
||||
import com.tangem.domain.common.TapWorkarounds.isSaltPay
|
||||
import com.tangem.domain.common.TapWorkarounds.isStart2Coin
|
||||
import com.tangem.tap.persistence.DisclaimerPrefStorage
|
||||
import com.tangem.tap.preferencesStorage
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
enum class DisclaimerType {
|
||||
Tangem,
|
||||
SaltPay,
|
||||
Start2Coin;
|
||||
|
||||
companion object {
|
||||
fun get(cardDTO: CardDTO): DisclaimerType {
|
||||
return when {
|
||||
cardDTO.isSaltPay -> SaltPay
|
||||
cardDTO.isStart2Coin -> Start2Coin
|
||||
else -> Tangem
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun DisclaimerType.createDisclaimer(cardDTO: CardDTO): Disclaimer {
|
||||
val dataProvider = provideDisclaimerDataProvider(cardDTO.cardId)
|
||||
return when (this) {
|
||||
DisclaimerType.Tangem -> TangemDisclaimer(dataProvider)
|
||||
DisclaimerType.SaltPay -> SaltPayDisclaimer(dataProvider)
|
||||
DisclaimerType.Start2Coin -> Start2CoinDisclaimer(dataProvider)
|
||||
}
|
||||
}
|
||||
|
||||
private fun provideDisclaimerDataProvider(cardId: String): DisclaimerDataProvider {
|
||||
return object : DisclaimerDataProvider {
|
||||
override fun getLanguage(): String = Locale.getDefault().language
|
||||
override fun getCardId(): String = cardId
|
||||
override fun storage(): DisclaimerPrefStorage = preferencesStorage.disclaimerPrefStorage
|
||||
}
|
||||
}
|
||||
|
|
@ -1,26 +1,21 @@
|
|||
package com.tangem.tap.features.disclaimer.redux
|
||||
|
||||
import com.tangem.common.extensions.VoidCallback
|
||||
import com.tangem.tap.common.redux.navigation.AppScreen
|
||||
import com.tangem.tap.features.disclaimer.Disclaimer
|
||||
import com.tangem.tap.features.wallet.redux.ProgressState
|
||||
import org.rekotlin.Action
|
||||
|
||||
sealed class DisclaimerAction : Action {
|
||||
|
||||
data class SetDisclaimerType(
|
||||
val type: DisclaimerType,
|
||||
) : DisclaimerAction()
|
||||
data class SetDisclaimer(val disclaimer: Disclaimer) : DisclaimerAction()
|
||||
|
||||
data class Show(
|
||||
val fromScreen: AppScreen,
|
||||
val callback: DisclaimerCallback? = null,
|
||||
) : DisclaimerAction()
|
||||
|
||||
data class AcceptDisclaimer(val type: DisclaimerType) : DisclaimerAction()
|
||||
|
||||
internal data class UpdateState(val type: DisclaimerType, val accepted: Boolean) : DisclaimerAction()
|
||||
|
||||
object AcceptDisclaimer : DisclaimerAction()
|
||||
object OnBackPressed : DisclaimerAction()
|
||||
}
|
||||
|
||||
data class DisclaimerCallback(
|
||||
val onAccept: VoidCallback? = null,
|
||||
val onDismiss: VoidCallback? = null,
|
||||
)
|
||||
data class OnProgressStateChanged(val state: ProgressState?) : DisclaimerAction()
|
||||
}
|
||||
|
|
@ -3,7 +3,6 @@ package com.tangem.tap.features.disclaimer.redux
|
|||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.common.redux.navigation.AppScreen
|
||||
import com.tangem.tap.common.redux.navigation.NavigationAction
|
||||
import com.tangem.tap.preferencesStorage
|
||||
import com.tangem.tap.store
|
||||
import org.rekotlin.Action
|
||||
import org.rekotlin.Middleware
|
||||
|
|
@ -23,16 +22,11 @@ private fun handleDisclaimerMiddleware(action: Action, appState: AppState) {
|
|||
val state = appState.disclaimerState
|
||||
|
||||
when (action) {
|
||||
is DisclaimerAction.SetDisclaimerType -> {
|
||||
handleUpdateState = action.type.createUpdateState()
|
||||
}
|
||||
is DisclaimerAction.Show -> {
|
||||
handleUpdateState = state.type.createUpdateState()
|
||||
store.dispatch(NavigationAction.NavigateTo(AppScreen.Disclaimer))
|
||||
}
|
||||
is DisclaimerAction.AcceptDisclaimer -> {
|
||||
action.type.accept()
|
||||
handleUpdateState = action.type.createUpdateState()
|
||||
state.disclaimer.accept()
|
||||
store.dispatch(NavigationAction.PopBackTo())
|
||||
state.callback?.onAccept?.invoke()
|
||||
}
|
||||
|
|
@ -41,29 +35,4 @@ private fun handleDisclaimerMiddleware(action: Action, appState: AppState) {
|
|||
state.callback?.onDismiss?.invoke()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun DisclaimerType.accept() = when (this) {
|
||||
DisclaimerType.Tangem -> preferencesStorage.disclaimerPrefStorage.hasTangemTosAccepted = true
|
||||
DisclaimerType.Start2Coin -> preferencesStorage.disclaimerPrefStorage.hasStart2CoinTosAccepted = true
|
||||
DisclaimerType.SaltPay -> preferencesStorage.disclaimerPrefStorage.hasSaltPayTosAccepted = true
|
||||
}
|
||||
|
||||
fun DisclaimerType.isAccepted(): Boolean = when (this) {
|
||||
DisclaimerType.Tangem -> preferencesStorage.disclaimerPrefStorage.hasTangemTosAccepted
|
||||
DisclaimerType.Start2Coin -> preferencesStorage.disclaimerPrefStorage.hasStart2CoinTosAccepted
|
||||
DisclaimerType.SaltPay -> preferencesStorage.disclaimerPrefStorage.hasSaltPayTosAccepted
|
||||
}
|
||||
|
||||
private fun DisclaimerType.createUpdateState(): DisclaimerAction.UpdateState {
|
||||
return DisclaimerAction.UpdateState(this, this.isAccepted())
|
||||
}
|
||||
|
||||
private var handleUpdateState: DisclaimerAction.UpdateState = DisclaimerAction.UpdateState(
|
||||
type = DisclaimerType.Tangem,
|
||||
accepted = false,
|
||||
)
|
||||
set(value) {
|
||||
field = value
|
||||
store.dispatch(value)
|
||||
}
|
||||
}
|
||||
|
|
@ -15,15 +15,19 @@ private fun internalReduce(action: Action, state: AppState): DisclaimerState {
|
|||
val disclaimerState = state.disclaimerState
|
||||
|
||||
return when (action) {
|
||||
is DisclaimerAction.Show -> disclaimerState.copy(
|
||||
callback = action.callback,
|
||||
is DisclaimerAction.SetDisclaimer -> disclaimerState.copy(
|
||||
disclaimer = action.disclaimer,
|
||||
)
|
||||
is DisclaimerAction.UpdateState -> disclaimerState.copy(
|
||||
type = action.type,
|
||||
accepted = action.accepted,
|
||||
is DisclaimerAction.Show -> disclaimerState.copy(
|
||||
showedFromScreen = action.fromScreen,
|
||||
callback = action.callback,
|
||||
)
|
||||
is DisclaimerAction.AcceptDisclaimer, is DisclaimerAction.OnBackPressed -> disclaimerState.copy(
|
||||
callback = null,
|
||||
progressState = null,
|
||||
)
|
||||
is DisclaimerAction.OnProgressStateChanged -> disclaimerState.copy(
|
||||
progressState = action.state,
|
||||
)
|
||||
else -> disclaimerState
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,32 +1,21 @@
|
|||
package com.tangem.tap.features.disclaimer.redux
|
||||
|
||||
import android.net.Uri
|
||||
import com.tangem.domain.common.CardDTO
|
||||
import com.tangem.domain.common.ScanResponse
|
||||
import com.tangem.domain.common.TapWorkarounds.isSaltPay
|
||||
import com.tangem.domain.common.TapWorkarounds.isStart2Coin
|
||||
import com.tangem.common.extensions.VoidCallback
|
||||
import com.tangem.tap.common.redux.navigation.AppScreen
|
||||
import com.tangem.tap.features.disclaimer.Disclaimer
|
||||
import com.tangem.tap.features.disclaimer.DummyDisclaimer
|
||||
import com.tangem.tap.features.wallet.redux.ProgressState
|
||||
import org.rekotlin.StateType
|
||||
|
||||
data class DisclaimerState(
|
||||
val accepted: Boolean = false,
|
||||
val type: DisclaimerType = DisclaimerType.Tangem,
|
||||
val disclaimer: Disclaimer = DummyDisclaimer(),
|
||||
val showedFromScreen: AppScreen = AppScreen.Home,
|
||||
val callback: DisclaimerCallback? = null,
|
||||
) : StateType
|
||||
val progressState: ProgressState? = null,
|
||||
) : StateType {
|
||||
}
|
||||
|
||||
sealed class DisclaimerType(
|
||||
val uri: Uri,
|
||||
) {
|
||||
object Tangem : DisclaimerType(Uri.parse("https://tangem.com/tangem_tos.html"))
|
||||
object Start2Coin : DisclaimerType(Uri.parse("https://tangem.com/tangem_tos.html"))
|
||||
object SaltPay : DisclaimerType(Uri.parse("https://tangem.com/soltpay_tos.html"))
|
||||
|
||||
companion object {
|
||||
fun get(scanResponse: ScanResponse): DisclaimerType = get(scanResponse.card)
|
||||
|
||||
fun get(card: CardDTO): DisclaimerType = when {
|
||||
card.isSaltPay -> SaltPay
|
||||
card.isStart2Coin -> Start2Coin
|
||||
else -> Tangem
|
||||
}
|
||||
}
|
||||
}
|
||||
data class DisclaimerCallback(
|
||||
val onAccept: VoidCallback? = null,
|
||||
val onDismiss: VoidCallback? = null,
|
||||
)
|
||||
|
|
@ -5,13 +5,17 @@ import android.view.View
|
|||
import androidx.transition.TransitionInflater
|
||||
import by.kirich1409.viewbindingdelegate.viewBinding
|
||||
import com.tangem.core.ui.fragments.setStatusBarColor
|
||||
import com.tangem.tap.common.extensions.configureSettings
|
||||
import com.tangem.tap.common.extensions.beginDelayedTransition
|
||||
import com.tangem.tap.common.extensions.hide
|
||||
import com.tangem.tap.common.extensions.show
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.common.redux.navigation.AppScreen
|
||||
import com.tangem.tap.features.BaseFragment
|
||||
import com.tangem.tap.features.addBackPressHandler
|
||||
import com.tangem.tap.features.disclaimer.Disclaimer
|
||||
import com.tangem.tap.features.disclaimer.redux.DisclaimerAction
|
||||
import com.tangem.tap.features.disclaimer.redux.DisclaimerState
|
||||
import com.tangem.tap.features.wallet.redux.ProgressState
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
import com.tangem.wallet.databinding.FragmentDisclaimerBinding
|
||||
|
|
@ -20,17 +24,52 @@ import org.rekotlin.StoreSubscriber
|
|||
class DisclaimerFragment : BaseFragment(R.layout.fragment_disclaimer), StoreSubscriber<DisclaimerState> {
|
||||
|
||||
private val binding: FragmentDisclaimerBinding by viewBinding(FragmentDisclaimerBinding::bind)
|
||||
private val webViewClient = DisclaimerWebViewClient()
|
||||
|
||||
override fun configureTransitions() {
|
||||
val inflater = TransitionInflater.from(requireContext())
|
||||
when (store.state.disclaimerState.showedFromScreen) {
|
||||
AppScreen.Home -> {
|
||||
enterTransition = inflater.inflateTransition(android.R.transition.slide_bottom)
|
||||
exitTransition = inflater.inflateTransition(android.R.transition.slide_top)
|
||||
}
|
||||
AppScreen.Details -> {
|
||||
enterTransition = inflater.inflateTransition(android.R.transition.fade)
|
||||
exitTransition = inflater.inflateTransition(android.R.transition.fade)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
addBackPressHandler(handler = this)
|
||||
binding.toolbar.setNavigationOnClickListener { handleOnBackPressed() }
|
||||
binding.webView.configureSettings()
|
||||
|
||||
binding.apply {
|
||||
toolbar.setNavigationOnClickListener { handleOnBackPressed() }
|
||||
webView.apply {
|
||||
settings.allowFileAccess = false
|
||||
settings.javaScriptEnabled = false
|
||||
webViewClient = this@DisclaimerFragment.webViewClient
|
||||
}
|
||||
webView.hide()
|
||||
groupError.hide()
|
||||
groupAccept.hide()
|
||||
groupLoading.hide()
|
||||
|
||||
btnAccept.setOnClickListener {
|
||||
store.dispatch(DisclaimerAction.AcceptDisclaimer)
|
||||
}
|
||||
btnRepeat.setOnClickListener {
|
||||
webViewClient.reset()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
setStatusBarColor(R.color.backgroundLightGray)
|
||||
|
||||
webViewClient.onProgressStateChanged = { store.dispatch(DisclaimerAction.OnProgressStateChanged(it)) }
|
||||
store.subscribe(subscriber = this) { state ->
|
||||
state
|
||||
.skipRepeats { oldState, newState -> oldState.disclaimerState == newState.disclaimerState }
|
||||
|
|
@ -39,30 +78,43 @@ class DisclaimerFragment : BaseFragment(R.layout.fragment_disclaimer), StoreSubs
|
|||
}
|
||||
|
||||
override fun onStop() {
|
||||
super.onStop()
|
||||
webViewClient.onProgressStateChanged = null
|
||||
store.unsubscribe(this)
|
||||
}
|
||||
|
||||
override fun configureTransitions() {
|
||||
super.configureTransitions()
|
||||
val inflater = TransitionInflater.from(requireContext())
|
||||
enterTransition = inflater.inflateTransition(android.R.transition.fade)
|
||||
exitTransition = inflater.inflateTransition(android.R.transition.fade)
|
||||
super.onStop()
|
||||
}
|
||||
|
||||
override fun newState(state: DisclaimerState) = with(binding) {
|
||||
if (activity == null || view == null) return
|
||||
|
||||
if (state.accepted) {
|
||||
halfTransparentOverlay.hide()
|
||||
btnAccept.hide()
|
||||
}
|
||||
updateUiVisibility(state.disclaimer, state.progressState)
|
||||
binding.webView.loadUrl(state.disclaimer.getUri().toString())
|
||||
}
|
||||
|
||||
btnAccept.setOnClickListener {
|
||||
store.dispatch(DisclaimerAction.AcceptDisclaimer(state.type))
|
||||
private fun updateUiVisibility(disclaimer: Disclaimer, progressState: ProgressState?) = with(binding) {
|
||||
when (progressState) {
|
||||
ProgressState.Loading -> {
|
||||
root.beginDelayedTransition()
|
||||
webView.hide()
|
||||
groupError.hide()
|
||||
groupAccept.hide()
|
||||
groupLoading.show()
|
||||
}
|
||||
ProgressState.Done -> {
|
||||
root.beginDelayedTransition()
|
||||
groupError.hide()
|
||||
groupLoading.hide()
|
||||
webView.show()
|
||||
groupAccept.show(!disclaimer.isAccepted())
|
||||
}
|
||||
ProgressState.Error -> {
|
||||
root.beginDelayedTransition()
|
||||
webView.hide()
|
||||
groupAccept.hide()
|
||||
groupLoading.hide()
|
||||
groupError.show()
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
|
||||
webView.loadUrl(state.type.uri.toString())
|
||||
}
|
||||
|
||||
override fun handleOnBackPressed() {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,68 @@
|
|||
package com.tangem.tap.features.disclaimer.ui
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import android.webkit.WebResourceError
|
||||
import android.webkit.WebResourceRequest
|
||||
import android.webkit.WebResourceResponse
|
||||
import android.webkit.WebView
|
||||
import android.webkit.WebViewClient
|
||||
import com.tangem.common.extensions.ifNotNull
|
||||
import com.tangem.tap.features.wallet.redux.ProgressState
|
||||
|
||||
class DisclaimerWebViewClient : WebViewClient() {
|
||||
|
||||
var onProgressStateChanged: ((ProgressState) -> Unit)? = null
|
||||
|
||||
private var loadingUrl: String? = null
|
||||
private var loadedUrl: String? = null
|
||||
|
||||
private var progressState: ProgressState = ProgressState.Loading
|
||||
set(value) {
|
||||
field = value
|
||||
onProgressStateChanged?.invoke(value)
|
||||
}
|
||||
|
||||
fun reset() {
|
||||
loadingUrl = null
|
||||
loadedUrl = null
|
||||
progressState = ProgressState.Loading
|
||||
}
|
||||
|
||||
override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
|
||||
super.onPageStarted(view, url, favicon)
|
||||
|
||||
if (loadingUrl != url) progressState = ProgressState.Loading
|
||||
loadingUrl = url
|
||||
}
|
||||
|
||||
override fun onPageFinished(view: WebView?, url: String?) {
|
||||
super.onPageFinished(view, url)
|
||||
|
||||
if (loadedUrl != url) progressState = ProgressState.Done
|
||||
loadedUrl = url
|
||||
}
|
||||
|
||||
override fun onReceivedError(
|
||||
view: WebView?,
|
||||
resourceRequest: WebResourceRequest?,
|
||||
error: WebResourceError?,
|
||||
) {
|
||||
super.onReceivedError(view, resourceRequest, error)
|
||||
error?.let { progressState = ProgressState.Error }
|
||||
}
|
||||
|
||||
override fun onReceivedHttpError(
|
||||
view: WebView?,
|
||||
resourceRequest: WebResourceRequest?,
|
||||
errorResponse: WebResourceResponse?,
|
||||
) {
|
||||
super.onReceivedHttpError(view, resourceRequest, errorResponse)
|
||||
|
||||
ifNotNull(resourceRequest, errorResponse) { request, response ->
|
||||
if (request.url?.toString() != loadingUrl || response.statusCode < 400) return
|
||||
if (progressState != ProgressState.Done) return
|
||||
|
||||
progressState = ProgressState.Error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -34,7 +34,6 @@ import com.tangem.tap.common.redux.navigation.NavigationAction
|
|||
import com.tangem.tap.domain.configurable.warningMessage.WarningMessage
|
||||
import com.tangem.tap.domain.statePrinter.printScanResponseState
|
||||
import com.tangem.tap.domain.statePrinter.printWalletState
|
||||
import com.tangem.tap.domain.termsOfUse.CardTou
|
||||
import com.tangem.tap.features.details.redux.DetailsAction
|
||||
import com.tangem.tap.features.wallet.redux.ErrorType
|
||||
import com.tangem.tap.features.wallet.redux.ProgressState
|
||||
|
|
@ -245,7 +244,6 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), StoreSubscriber<Walle
|
|||
DetailsAction.PrepareScreen(
|
||||
scanResponse = scanNoteResponse,
|
||||
wallets = store.state.walletState.walletManagers.map { it.wallet },
|
||||
cardTou = CardTou(),
|
||||
),
|
||||
)
|
||||
store.dispatch(NavigationAction.NavigateTo(AppScreen.Details))
|
||||
|
|
|
|||
|
|
@ -10,21 +10,11 @@ class DisclaimerPrefStorage(
|
|||
private val preferences: SharedPreferences,
|
||||
) {
|
||||
|
||||
var hasTangemTosAccepted: Boolean
|
||||
get() = preferences.getBoolean(KEY_TANGEM_TOS, false)
|
||||
set(value) = preferences.edit { putBoolean(KEY_TANGEM_TOS, value) }
|
||||
fun accept(disclaimerKey: String) {
|
||||
preferences.edit { putBoolean(disclaimerKey, true) }
|
||||
}
|
||||
|
||||
var hasStart2CoinTosAccepted: Boolean
|
||||
get() = preferences.getBoolean(KEY_START_2_COIN_TOS, false)
|
||||
set(value) = preferences.edit { putBoolean(KEY_START_2_COIN_TOS, value) }
|
||||
|
||||
var hasSaltPayTosAccepted: Boolean
|
||||
get() = preferences.getBoolean(KEY_SALT_PAY_TOS, false)
|
||||
set(value) = preferences.edit { putBoolean(KEY_SALT_PAY_TOS, value) }
|
||||
|
||||
companion object {
|
||||
private const val KEY_TANGEM_TOS = "tangem_tos_accepted"
|
||||
private const val KEY_START_2_COIN_TOS = "s2c_tos_accepted"
|
||||
private const val KEY_SALT_PAY_TOS = "saltPay_tos_accepted"
|
||||
fun isAccepted(disclaimerKey: String): Boolean {
|
||||
return preferences.getBoolean(disclaimerKey, false)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue