Updated on 2026-08-14

This commit is contained in:
Tangem 2022-10-25 15:46:12 +05:00
parent 26f476bcd0
commit 7913e52216
12 changed files with 181 additions and 1430 deletions

View file

@ -78,8 +78,7 @@ class DetailsViewModel(private val store: Store<AppState>) {
store.dispatch(DetailsAction.CreateBackup)
}
SettingsElement.TermsOfService -> {
store.dispatch(DisclaimerAction.ShowAcceptedDisclaimer)
store.dispatch(NavigationAction.NavigateTo(AppScreen.Disclaimer))
store.dispatch(DisclaimerAction.Show())
}
SettingsElement.TermsOfUse -> {
store.dispatch(DetailsAction.ShowDisclaimer)

View file

@ -1,8 +1,17 @@
package com.tangem.tap.features.disclaimer.redux
import com.tangem.common.extensions.VoidCallback
import org.rekotlin.Action
sealed class DisclaimerAction: Action {
object AcceptDisclaimer : DisclaimerAction()
object ShowAcceptedDisclaimer : DisclaimerAction()
sealed class DisclaimerAction : Action {
data class SetDisclaimerType(
val type: DisclaimerType,
) : DisclaimerAction()
data class Show(val onAcceptCallback: VoidCallback? = null) : DisclaimerAction()
data class AcceptDisclaimer(val type: DisclaimerType) : DisclaimerAction()
internal data class UpdateState(val type: DisclaimerType, val accepted: Boolean) : DisclaimerAction()
internal data class SetOnAcceptCallback(val onAcceptCallback: VoidCallback? = null) : DisclaimerAction()
}

View file

@ -1,28 +1,65 @@
package com.tangem.tap.features.disclaimer.redux
import com.tangem.tap.common.post
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.features.home.redux.HomeAction
import com.tangem.tap.preferencesStorage
import com.tangem.tap.store
import org.rekotlin.Action
import org.rekotlin.Middleware
class DisclaimerMiddleware {
val disclaimerMiddleware: Middleware<AppState> = { dispatch, state ->
{ next ->
{ action ->
when (action) {
is DisclaimerAction.AcceptDisclaimer -> {
preferencesStorage.saveDisclaimerAccepted()
store.dispatch(NavigationAction.PopBackTo())
//delayed sending used for better animation
post(550) { store.dispatch(HomeAction.ReadCard) }
}
}
state()?.let { handleDisclaimerMiddleware(action, it) }
next(action)
}
}
}
}
}
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(DisclaimerAction.SetOnAcceptCallback(action.onAcceptCallback))
store.dispatch(NavigationAction.NavigateTo(AppScreen.Disclaimer))
}
is DisclaimerAction.AcceptDisclaimer -> {
action.type.accept()
handleUpdateState = action.type.createUpdateState()
store.dispatch(NavigationAction.PopBackTo())
state.onAcceptCallback?.invoke()
store.dispatch(DisclaimerAction.SetOnAcceptCallback(null))
}
}
}
private fun DisclaimerType.accept() = when (this) {
DisclaimerType.SaltPay -> preferencesStorage.disclaimerPrefStorage.hasSaltPayTosAccepted = true
DisclaimerType.Tangem -> preferencesStorage.disclaimerPrefStorage.hasTangemTosAccepted = true
}
fun DisclaimerType.isAccepted(): Boolean = when (this) {
DisclaimerType.SaltPay -> preferencesStorage.disclaimerPrefStorage.hasSaltPayTosAccepted
DisclaimerType.Tangem -> preferencesStorage.disclaimerPrefStorage.hasTangemTosAccepted
}
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)
}

View file

@ -13,9 +13,15 @@ private fun internalReduce(action: Action, state: AppState): DisclaimerState {
if (action !is DisclaimerAction) return state.disclaimerState
val disclaimerState = state.disclaimerState
return when (action) {
is DisclaimerAction.AcceptDisclaimer, DisclaimerAction.ShowAcceptedDisclaimer -> {
disclaimerState.copy(accepted = true)
}
is DisclaimerAction.UpdateState -> disclaimerState.copy(
type = action.type,
accepted = action.accepted,
)
is DisclaimerAction.SetOnAcceptCallback -> disclaimerState.copy(
onAcceptCallback = action.onAcceptCallback,
)
else -> disclaimerState
}
}

View file

@ -1,7 +1,30 @@
package com.tangem.tap.features.disclaimer.redux
import android.net.Uri
import com.tangem.common.card.Card
import com.tangem.common.extensions.VoidCallback
import com.tangem.domain.common.ScanResponse
import com.tangem.domain.common.TapWorkarounds.isSaltPay
import org.rekotlin.StateType
data class DisclaimerState(
val accepted: Boolean = false
val accepted: Boolean = false,
val type: DisclaimerType = DisclaimerType.Tangem,
val onAcceptCallback: VoidCallback? = null,
) : StateType
sealed class DisclaimerType(
val uri: Uri,
) {
object Tangem : 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: Card): DisclaimerType = when {
card.isSaltPay -> SaltPay
else -> Tangem
}
}
}

View file

@ -55,25 +55,25 @@ class DisclaimerFragment : Fragment(R.layout.fragment_disclaimer),
binding.toolbar.setNavigationOnClickListener {
store.dispatch(NavigationAction.PopBackTo())
}
initAndLoadTOS()
setOnClickListeners()
initViews()
}
private fun initAndLoadTOS() {
private fun initViews() {
binding.webView.configureSettings()
binding.webView.loadUrl("file:///android_asset/tos.html")
}
private fun setOnClickListeners() {
binding.btnAccept.setOnClickListener { store.dispatch(DisclaimerAction.AcceptDisclaimer) }
}
override fun newState(state: DisclaimerState) {
override fun newState(state: DisclaimerState) = with(binding) {
if (activity == null || view == null) return
if (state.accepted) {
binding.halfTransparentOverlay.hide()
binding.btnAccept.hide()
halfTransparentOverlay.hide()
btnAccept.hide()
}
btnAccept.setOnClickListener {
store.dispatch(DisclaimerAction.AcceptDisclaimer(state.type))
}
webView.loadUrl(state.type.uri.toString())
}
}

View file

@ -13,6 +13,5 @@ sealed class HomeAction : Action {
data class ShouldScanCardOnResume(val shouldScanCard: Boolean) : HomeAction()
object Init : HomeAction()
data class SetTermsOfUseState(val isDisclaimerAccepted: Boolean) : HomeAction()
data class ChangeScanCardButtonState(val state: IndeterminateProgressButton) : HomeAction()
}

View file

@ -20,6 +20,9 @@ import com.tangem.tap.common.redux.global.GlobalAction
import com.tangem.tap.common.redux.navigation.AppScreen
import com.tangem.tap.common.redux.navigation.FragmentShareTransition
import com.tangem.tap.common.redux.navigation.NavigationAction
import com.tangem.tap.features.disclaimer.redux.DisclaimerAction
import com.tangem.tap.features.disclaimer.redux.DisclaimerType
import com.tangem.tap.features.disclaimer.redux.isAccepted
import com.tangem.tap.features.home.BELARUS_COUNTRY_CODE
import com.tangem.tap.features.home.RUSSIA_COUNTRY_CODE
import com.tangem.tap.features.home.redux.HomeMiddleware.Companion.BUY_WALLET_URL
@ -63,7 +66,6 @@ private fun handleHomeAction(appState: () -> AppState?, action: Action, dispatch
is HomeAction.Init -> {
store.dispatch(GlobalAction.RestoreAppCurrency)
store.dispatch(GlobalAction.ExchangeManager.Init)
store.dispatch(HomeAction.SetTermsOfUseState(preferencesStorage.wasDisclaimerAccepted()))
store.dispatch(GlobalAction.FetchUserCountry)
}
is HomeAction.ShouldScanCardOnResume -> {
@ -73,17 +75,16 @@ private fun handleHomeAction(appState: () -> AppState?, action: Action, dispatch
}
}
is HomeAction.ReadCard -> {
if (!preferencesStorage.wasDisclaimerAccepted()) {
store.dispatch(NavigationAction.NavigateTo(AppScreen.Disclaimer))
} else {
changeButtonState(ButtonState.PROGRESS)
val scanCardAction = GlobalAction.ScanCard(
onSuccess = ::onScanSuccess,
onFailure = ::onScanFailure,
)
store.dispatch(HomeAction.ScanInProgress(true))
postUiDelayBg(300) { store.dispatch(scanCardAction) }
}
changeButtonState(ButtonState.PROGRESS)
val scanCardAction = GlobalAction.ScanCard(
onSuccess = {
store.dispatch(HomeAction.ScanInProgress(false))
checkForDisclaimer(it, ::onScanSuccess)
},
onFailure = ::onScanFailure,
)
store.dispatch(HomeAction.ScanInProgress(true))
postUiDelayBg(300) { store.dispatch(scanCardAction) }
}
is HomeAction.GoToShop -> {
when (action.userCountryCode) {
@ -98,12 +99,28 @@ private fun handleHomeAction(appState: () -> AppState?, action: Action, dispatch
}
}
private fun checkForDisclaimer(scanResponse: ScanResponse, onDisclaimerAccepted: (ScanResponse) -> Unit) {
val disclaimerType = DisclaimerType.get(scanResponse)
store.dispatch(DisclaimerAction.SetDisclaimerType(disclaimerType))
if (disclaimerType.isAccepted()) {
onDisclaimerAccepted((scanResponse))
} else {
changeButtonState(ButtonState.ENABLED)
store.dispatch(
DisclaimerAction.Show {
changeButtonState(ButtonState.PROGRESS)
onDisclaimerAccepted(scanResponse)
},
)
}
}
private fun onScanSuccess(scanResponse: ScanResponse) {
val globalState = store.state.globalState
val tapWalletManager = globalState.tapWalletManager
tapWalletManager.updateConfigManager(scanResponse)
store.dispatch(HomeAction.ScanInProgress(false))
store.dispatch(TwinCardsAction.IfTwinsPrepareState(scanResponse))
if (scanResponse.isSaltPay()) {