diff --git a/app/src/main/java/com/tangem/tap/domain/scanCard/ScanCardProcessor.kt b/app/src/main/java/com/tangem/tap/domain/scanCard/ScanCardProcessor.kt index e9b7d1a7e3..7b33c2f9fc 100644 --- a/app/src/main/java/com/tangem/tap/domain/scanCard/ScanCardProcessor.kt +++ b/app/src/main/java/com/tangem/tap/domain/scanCard/ScanCardProcessor.kt @@ -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) { diff --git a/app/src/main/java/com/tangem/tap/domain/termsOfUse/CardTou.kt b/app/src/main/java/com/tangem/tap/domain/termsOfUse/CardTou.kt deleted file mode 100644 index 6644362bf5..0000000000 --- a/app/src/main/java/com/tangem/tap/domain/termsOfUse/CardTou.kt +++ /dev/null @@ -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 - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsAction.kt b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsAction.kt index d08fd627f5..5447faf5b0 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsAction.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsAction.kt @@ -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, - val cardTou: CardTou, ) : DetailsAction() - object ShowDisclaimer : DetailsAction() object ReCreateTwinsWallet : DetailsAction() sealed class ResetToFactory : DetailsAction() { diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt index fda0a60ea4..f6e2c4b7c4 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt @@ -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)) diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsReducer.kt b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsReducer.kt index 11b737097a..142d59fbf3 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsReducer.kt @@ -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, diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsState.kt b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsState.kt index 3cb211b7c5..a22b810f7c 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsState.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsState.kt @@ -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 = emptyList(), val cardSettingsState: CardSettingsState? = null, - val cardTermsOfUseUrl: Uri? = null, val privacyPolicyUrl: String? = null, val createBackupAllowed: Boolean = false, val appCurrency: FiatCurrency = FiatCurrency.Default, diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsScreenState.kt b/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsScreenState.kt index e55525ae1d..ac69fe0ad8 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsScreenState.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsScreenState.kt @@ -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); } diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsViewModel.kt b/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsViewModel.kt index 42fbc5b252..6165dc5c39 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsViewModel.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsViewModel.kt @@ -38,7 +38,6 @@ class DetailsViewModel(private val store: Store) { } 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) { 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 diff --git a/app/src/main/java/com/tangem/tap/features/disclaimer/Disclaimer.kt b/app/src/main/java/com/tangem/tap/features/disclaimer/Disclaimer.kt new file mode 100644 index 0000000000..a3f28bfb73 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/disclaimer/Disclaimer.kt @@ -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 + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/disclaimer/DisclaimerDataProvider.kt b/app/src/main/java/com/tangem/tap/features/disclaimer/DisclaimerDataProvider.kt new file mode 100644 index 0000000000..0097f34142 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/disclaimer/DisclaimerDataProvider.kt @@ -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 +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/disclaimer/DisclaimerType.kt b/app/src/main/java/com/tangem/tap/features/disclaimer/DisclaimerType.kt new file mode 100644 index 0000000000..d6af0e0596 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/disclaimer/DisclaimerType.kt @@ -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 + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/disclaimer/redux/DisclaimerAction.kt b/app/src/main/java/com/tangem/tap/features/disclaimer/redux/DisclaimerAction.kt index 395137228c..1a712e1c49 100644 --- a/app/src/main/java/com/tangem/tap/features/disclaimer/redux/DisclaimerAction.kt +++ b/app/src/main/java/com/tangem/tap/features/disclaimer/redux/DisclaimerAction.kt @@ -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, -) \ No newline at end of file + data class OnProgressStateChanged(val state: ProgressState?) : DisclaimerAction() +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/disclaimer/redux/DisclaimerMiddleware.kt b/app/src/main/java/com/tangem/tap/features/disclaimer/redux/DisclaimerMiddleware.kt index a604d3275f..ca71193f2a 100644 --- a/app/src/main/java/com/tangem/tap/features/disclaimer/redux/DisclaimerMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/disclaimer/redux/DisclaimerMiddleware.kt @@ -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) - } \ No newline at end of file +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/disclaimer/redux/DisclaimerReducer.kt b/app/src/main/java/com/tangem/tap/features/disclaimer/redux/DisclaimerReducer.kt index d44d02e993..456818fe70 100644 --- a/app/src/main/java/com/tangem/tap/features/disclaimer/redux/DisclaimerReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/disclaimer/redux/DisclaimerReducer.kt @@ -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 } diff --git a/app/src/main/java/com/tangem/tap/features/disclaimer/redux/DisclaimerState.kt b/app/src/main/java/com/tangem/tap/features/disclaimer/redux/DisclaimerState.kt index d8dcbddd2a..99db90b3d8 100644 --- a/app/src/main/java/com/tangem/tap/features/disclaimer/redux/DisclaimerState.kt +++ b/app/src/main/java/com/tangem/tap/features/disclaimer/redux/DisclaimerState.kt @@ -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 - } - } -} \ No newline at end of file +data class DisclaimerCallback( + val onAccept: VoidCallback? = null, + val onDismiss: VoidCallback? = null, +) \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/disclaimer/ui/DisclaimerFragment.kt b/app/src/main/java/com/tangem/tap/features/disclaimer/ui/DisclaimerFragment.kt index 7761de53b6..3c177a29e7 100644 --- a/app/src/main/java/com/tangem/tap/features/disclaimer/ui/DisclaimerFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/disclaimer/ui/DisclaimerFragment.kt @@ -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 { 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() { diff --git a/app/src/main/java/com/tangem/tap/features/disclaimer/ui/DisclaimerWebViewClient.kt b/app/src/main/java/com/tangem/tap/features/disclaimer/ui/DisclaimerWebViewClient.kt new file mode 100644 index 0000000000..c1a024fc0c --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/disclaimer/ui/DisclaimerWebViewClient.kt @@ -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 + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt index 860939d53c..7c622df177 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt @@ -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 - - + + + + +