Updated on 2026-08-14

This commit is contained in:
Tangem 2024-09-22 11:19:30 +03:00
parent 73b80b5ef9
commit dad8ccb8da
27 changed files with 24 additions and 677 deletions

View file

@ -32,7 +32,6 @@ import com.tangem.domain.wallets.legacy.UserWalletsListManager
import com.tangem.domain.wallets.repository.WalletsRepository import com.tangem.domain.wallets.repository.WalletsRepository
import com.tangem.domain.wallets.usecase.GenerateWalletNameUseCase import com.tangem.domain.wallets.usecase.GenerateWalletNameUseCase
import com.tangem.features.details.DetailsFeatureToggles import com.tangem.features.details.DetailsFeatureToggles
import com.tangem.features.pushnotifications.api.featuretoggles.PushNotificationsFeatureToggles
import com.tangem.tap.common.log.TangemAppLoggerInitializer import com.tangem.tap.common.log.TangemAppLoggerInitializer
import com.tangem.tap.domain.walletconnect2.domain.WalletConnectSessionsRepository import com.tangem.tap.domain.walletconnect2.domain.WalletConnectSessionsRepository
import com.tangem.tap.features.customtoken.api.featuretoggles.CustomTokenFeatureToggles import com.tangem.tap.features.customtoken.api.featuretoggles.CustomTokenFeatureToggles
@ -118,8 +117,6 @@ interface ApplicationEntryPoint {
fun getAppRouter(): AppRouter fun getAppRouter(): AppRouter
fun getPushNotificationsFeatureToggles(): PushNotificationsFeatureToggles
fun getTangemAppLogger(): TangemAppLoggerInitializer fun getTangemAppLogger(): TangemAppLoggerInitializer
fun getHomeFeatureToggles(): HomeFeatureToggles fun getHomeFeatureToggles(): HomeFeatureToggles

View file

@ -65,7 +65,6 @@ import com.tangem.tap.common.OnActivityResultCallback
import com.tangem.tap.common.SnackbarHandler import com.tangem.tap.common.SnackbarHandler
import com.tangem.tap.common.apptheme.MutableAppThemeModeHolder import com.tangem.tap.common.apptheme.MutableAppThemeModeHolder
import com.tangem.tap.common.extensions.dispatchNavigationAction import com.tangem.tap.common.extensions.dispatchNavigationAction
import com.tangem.tap.common.extensions.inject
import com.tangem.tap.common.extensions.showFragmentAllowingStateLoss import com.tangem.tap.common.extensions.showFragmentAllowingStateLoss
import com.tangem.tap.common.redux.NotificationsHandler import com.tangem.tap.common.redux.NotificationsHandler
import com.tangem.tap.domain.sdk.TangemSdkManager import com.tangem.tap.domain.sdk.TangemSdkManager
@ -78,7 +77,6 @@ import com.tangem.tap.features.main.model.Toast
import com.tangem.tap.features.onboarding.products.wallet.redux.BackupAction import com.tangem.tap.features.onboarding.products.wallet.redux.BackupAction
import com.tangem.tap.proxy.AppStateHolder import com.tangem.tap.proxy.AppStateHolder
import com.tangem.tap.proxy.redux.DaggerGraphAction import com.tangem.tap.proxy.redux.DaggerGraphAction
import com.tangem.tap.proxy.redux.DaggerGraphState
import com.tangem.tap.routing.RoutingComponent import com.tangem.tap.routing.RoutingComponent
import com.tangem.tap.routing.configurator.AppRouterConfig import com.tangem.tap.routing.configurator.AppRouterConfig
import com.tangem.utils.coroutines.FeatureCoroutineExceptionHandler import com.tangem.utils.coroutines.FeatureCoroutineExceptionHandler
@ -539,11 +537,8 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
} }
} else { } else {
lifecycleScope.launch { lifecycleScope.launch {
val toggles = store.inject(getDependency = DaggerGraphState::pushNotificationsFeatureToggles) val shouldShowTos = !cardRepository.isTangemTOSAccepted()
val isPushPermissionEnabled = toggles.isPushNotificationsEnabled val shouldShowInitialPush = shouldInitiallyAskPermissionUseCase(PUSH_PERMISSION).getOrElse { false }
val shouldShowTos = !cardRepository.isTangemTOSAccepted() && isPushPermissionEnabled
val wasPushInitiallyAsked = shouldInitiallyAskPermissionUseCase(PUSH_PERMISSION).getOrElse { false }
val shouldShowInitialPush = wasPushInitiallyAsked && isPushPermissionEnabled
val route = when { val route = when {
shouldShowTos -> AppRoute.Disclaimer(isTosAccepted = false) shouldShowTos -> AppRoute.Disclaimer(isTosAccepted = false)

View file

@ -45,7 +45,6 @@ import com.tangem.domain.wallets.legacy.UserWalletsListManager
import com.tangem.domain.wallets.repository.WalletsRepository import com.tangem.domain.wallets.repository.WalletsRepository
import com.tangem.domain.wallets.usecase.GenerateWalletNameUseCase import com.tangem.domain.wallets.usecase.GenerateWalletNameUseCase
import com.tangem.features.details.DetailsFeatureToggles import com.tangem.features.details.DetailsFeatureToggles
import com.tangem.features.pushnotifications.api.featuretoggles.PushNotificationsFeatureToggles
import com.tangem.tap.common.analytics.AnalyticsFactory import com.tangem.tap.common.analytics.AnalyticsFactory
import com.tangem.tap.common.analytics.api.AnalyticsHandlerBuilder import com.tangem.tap.common.analytics.api.AnalyticsHandlerBuilder
import com.tangem.tap.common.analytics.handlers.amplitude.AmplitudeAnalyticsHandler import com.tangem.tap.common.analytics.handlers.amplitude.AmplitudeAnalyticsHandler
@ -188,9 +187,6 @@ abstract class TangemApplication : Application(), ImageLoaderFactory {
private val appRouter: AppRouter private val appRouter: AppRouter
get() = entryPoint.getAppRouter() get() = entryPoint.getAppRouter()
private val pushNotificationsFeatureToggles: PushNotificationsFeatureToggles
get() = entryPoint.getPushNotificationsFeatureToggles()
private val tangemAppLoggerInitializer: TangemAppLoggerInitializer private val tangemAppLoggerInitializer: TangemAppLoggerInitializer
get() = entryPoint.getTangemAppLogger() get() = entryPoint.getTangemAppLogger()
@ -280,7 +276,6 @@ abstract class TangemApplication : Application(), ImageLoaderFactory {
urlOpener = urlOpener, urlOpener = urlOpener,
shareManager = shareManager, shareManager = shareManager,
appRouter = appRouter, appRouter = appRouter,
pushNotificationsFeatureToggles = pushNotificationsFeatureToggles,
homeFeatureToggles = homeFeatureToggles, homeFeatureToggles = homeFeatureToggles,
getUserCountryUseCase = getUserCountryUseCase, getUserCountryUseCase = getUserCountryUseCase,
), ),

View file

@ -3,7 +3,6 @@ package com.tangem.tap.common.redux
import com.tangem.tap.common.redux.global.globalReducer import com.tangem.tap.common.redux.global.globalReducer
import com.tangem.tap.features.details.redux.DetailsReducer import com.tangem.tap.features.details.redux.DetailsReducer
import com.tangem.tap.features.details.redux.walletconnect.WalletConnectReducer import com.tangem.tap.features.details.redux.walletconnect.WalletConnectReducer
import com.tangem.tap.features.disclaimer.redux.DisclaimerReducer
import com.tangem.tap.features.home.redux.HomeReducer import com.tangem.tap.features.home.redux.HomeReducer
import com.tangem.tap.features.onboarding.products.note.redux.OnboardingNoteReducer import com.tangem.tap.features.onboarding.products.note.redux.OnboardingNoteReducer
import com.tangem.tap.features.onboarding.products.otherCards.redux.OnboardingOtherCardsReducer import com.tangem.tap.features.onboarding.products.otherCards.redux.OnboardingOtherCardsReducer
@ -28,7 +27,6 @@ fun appReducer(action: Action, state: AppState?, appStateHolder: AppStateHolder)
onboardingOtherCardsState = OnboardingOtherCardsReducer.reduce(action, state), onboardingOtherCardsState = OnboardingOtherCardsReducer.reduce(action, state),
twinCardsState = TwinCardsReducer.reduce(action, state), twinCardsState = TwinCardsReducer.reduce(action, state),
detailsState = DetailsReducer.reduce(action, state), detailsState = DetailsReducer.reduce(action, state),
disclaimerState = DisclaimerReducer.reduce(action, state),
tokensState = TokensReducer.reduce(action, state), tokensState = TokensReducer.reduce(action, state),
walletConnectState = WalletConnectReducer.reduce(action, state.walletConnectState), walletConnectState = WalletConnectReducer.reduce(action, state.walletConnectState),
welcomeState = WelcomeReducer.reduce(action, state), welcomeState = WelcomeReducer.reduce(action, state),

View file

@ -10,8 +10,6 @@ import com.tangem.tap.features.details.redux.DetailsMiddleware
import com.tangem.tap.features.details.redux.DetailsState import com.tangem.tap.features.details.redux.DetailsState
import com.tangem.tap.features.details.redux.walletconnect.WalletConnectMiddleware import com.tangem.tap.features.details.redux.walletconnect.WalletConnectMiddleware
import com.tangem.tap.features.details.redux.walletconnect.WalletConnectState import com.tangem.tap.features.details.redux.walletconnect.WalletConnectState
import com.tangem.tap.features.disclaimer.redux.DisclaimerMiddleware
import com.tangem.tap.features.disclaimer.redux.DisclaimerState
import com.tangem.tap.features.home.redux.HomeMiddleware import com.tangem.tap.features.home.redux.HomeMiddleware
import com.tangem.tap.features.home.redux.HomeState import com.tangem.tap.features.home.redux.HomeState
import com.tangem.tap.features.onboarding.products.note.redux.OnboardingNoteMiddleware import com.tangem.tap.features.onboarding.products.note.redux.OnboardingNoteMiddleware
@ -43,7 +41,6 @@ data class AppState(
val onboardingOtherCardsState: OnboardingOtherCardsState = OnboardingOtherCardsState(), val onboardingOtherCardsState: OnboardingOtherCardsState = OnboardingOtherCardsState(),
val twinCardsState: TwinCardsState = TwinCardsState(), val twinCardsState: TwinCardsState = TwinCardsState(),
val detailsState: DetailsState = DetailsState(), val detailsState: DetailsState = DetailsState(),
val disclaimerState: DisclaimerState = DisclaimerState(),
val tokensState: TokensState = TokensState(), val tokensState: TokensState = TokensState(),
val walletConnectState: WalletConnectState = WalletConnectState(), val walletConnectState: WalletConnectState = WalletConnectState(),
val welcomeState: WelcomeState = WelcomeState(), val welcomeState: WelcomeState = WelcomeState(),
@ -75,7 +72,6 @@ data class AppState(
OnboardingOtherCardsMiddleware.handler, OnboardingOtherCardsMiddleware.handler,
TwinCardsMiddleware.handler, TwinCardsMiddleware.handler,
DetailsMiddleware().detailsMiddleware, DetailsMiddleware().detailsMiddleware,
DisclaimerMiddleware().disclaimerMiddleware,
WalletConnectMiddleware().walletConnectMiddleware, WalletConnectMiddleware().walletConnectMiddleware,
BackupMiddleware().backupMiddleware, BackupMiddleware().backupMiddleware,
WelcomeMiddleware().middleware, WelcomeMiddleware().middleware,

View file

@ -13,8 +13,6 @@ import com.tangem.operations.attestation.Attestation
import com.tangem.tap.common.extensions.inject import com.tangem.tap.common.extensions.inject
import com.tangem.tap.common.extensions.setContext import com.tangem.tap.common.extensions.setContext
import com.tangem.tap.common.redux.global.GlobalAction import com.tangem.tap.common.redux.global.GlobalAction
import com.tangem.tap.features.disclaimer.createDisclaimer
import com.tangem.tap.features.disclaimer.redux.DisclaimerAction
import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsAction import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsAction
import com.tangem.tap.proxy.redux.DaggerGraphState import com.tangem.tap.proxy.redux.DaggerGraphState
import com.tangem.tap.store import com.tangem.tap.store
@ -62,7 +60,6 @@ class TapWalletManager(
updateConfigManager(scanResponse) updateConfigManager(scanResponse)
withMainContext { withMainContext {
// Order is important // Order is important
store.dispatch(DisclaimerAction.SetDisclaimer(card.createDisclaimer()))
store.dispatch(TwinCardsAction.IfTwinsPrepareState(scanResponse)) store.dispatch(TwinCardsAction.IfTwinsPrepareState(scanResponse))
store.dispatch(GlobalAction.SaveScanResponse(scanResponse)) store.dispatch(GlobalAction.SaveScanResponse(scanResponse))
store.dispatch(GlobalAction.SetIfCardVerifiedOnline(!attestationFailed)) store.dispatch(GlobalAction.SetIfCardVerifiedOnline(!attestationFailed))

View file

@ -2,7 +2,6 @@ package com.tangem.tap.domain.scanCard
import com.tangem.common.CompletionResult import com.tangem.common.CompletionResult
import com.tangem.common.core.TangemError import com.tangem.common.core.TangemError
import com.tangem.common.core.TangemSdkError
import com.tangem.common.doOnFailure import com.tangem.common.doOnFailure
import com.tangem.common.doOnSuccess import com.tangem.common.doOnSuccess
import com.tangem.common.routing.AppRoute import com.tangem.common.routing.AppRoute
@ -18,9 +17,6 @@ import com.tangem.tap.common.analytics.paramsInterceptor.CardContextInterceptor
import com.tangem.tap.common.extensions.* import com.tangem.tap.common.extensions.*
import com.tangem.tap.common.redux.global.GlobalAction import com.tangem.tap.common.redux.global.GlobalAction
import com.tangem.tap.features.disclaimer.createDisclaimer 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.DisclaimerSource
import com.tangem.tap.features.onboarding.OnboardingHelper import com.tangem.tap.features.onboarding.OnboardingHelper
import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsAction import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsAction
import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsStep import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsStep
@ -102,6 +98,8 @@ internal object LegacyScanProcessor {
} }
} }
// TODO: [REDACTED_JIRA]
@Suppress("UnusedPrivateMember")
private suspend inline fun showDisclaimerIfNeed( private suspend inline fun showDisclaimerIfNeed(
scanResponse: ScanResponse, scanResponse: ScanResponse,
crossinline disclaimerWillShow: () -> Unit = {}, crossinline disclaimerWillShow: () -> Unit = {},
@ -109,7 +107,6 @@ internal object LegacyScanProcessor {
crossinline onFailure: suspend (error: TangemError) -> Unit, crossinline onFailure: suspend (error: TangemError) -> Unit,
) { ) {
val disclaimer = scanResponse.card.createDisclaimer() val disclaimer = scanResponse.card.createDisclaimer()
store.dispatchOnMain(DisclaimerAction.SetDisclaimer(disclaimer))
if (disclaimer.isAccepted()) { if (disclaimer.isAccepted()) {
nextHandler(scanResponse) nextHandler(scanResponse)
@ -120,23 +117,9 @@ internal object LegacyScanProcessor {
withContext(Dispatchers.Main.immediate) { withContext(Dispatchers.Main.immediate) {
disclaimerWillShow() disclaimerWillShow()
store.dispatch( store.dispatchNavigationAction {
DisclaimerAction.Show( push(AppRoute.Disclaimer(isTosAccepted = false))
from = DisclaimerSource.Home, }
callback = DisclaimerCallback(
onAccept = {
scope.launch(Dispatchers.Main.immediate) {
nextHandler(scanResponse)
}
},
onDismiss = {
scope.launch(Dispatchers.Main.immediate) {
onFailure(TangemSdkError.UserCancelled())
}
},
),
),
)
} }
} }
} }

View file

@ -59,11 +59,7 @@ internal object UseCaseScanProcessor {
), ),
) )
add(AnalyticsChain(Basic.CardWasScanned(analyticsSource))) add(AnalyticsChain(Basic.CardWasScanned(analyticsSource)))
val pushNotificationsToggles = add(DisclaimerChain(store, disclaimerWillShow))
store.inject(getDependency = DaggerGraphState::pushNotificationsFeatureToggles)
if (pushNotificationsToggles.isPushNotificationsEnabled) {
add(DisclaimerChain(store, disclaimerWillShow))
}
add(CheckForOnboardingChain(store, store.state.globalState.tapWalletManager)) add(CheckForOnboardingChain(store, store.state.globalState.tapWalletManager))
} }

View file

@ -1,21 +1,15 @@
package com.tangem.tap.domain.scanCard.chains package com.tangem.tap.domain.scanCard.chains
import arrow.core.left
import arrow.core.right import arrow.core.right
import com.tangem.common.routing.AppRoute
import com.tangem.domain.card.ScanCardException import com.tangem.domain.card.ScanCardException
import com.tangem.domain.core.chain.Chain import com.tangem.domain.core.chain.Chain
import com.tangem.domain.core.chain.ResultChain import com.tangem.domain.core.chain.ResultChain
import com.tangem.domain.models.scan.ScanResponse import com.tangem.domain.models.scan.ScanResponse
import com.tangem.tap.common.extensions.dispatchOnMain import com.tangem.tap.common.extensions.dispatchNavigationAction
import com.tangem.tap.common.redux.AppState import com.tangem.tap.common.redux.AppState
import com.tangem.tap.features.disclaimer.Disclaimer
import com.tangem.tap.features.disclaimer.createDisclaimer 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.DisclaimerSource
import kotlinx.coroutines.suspendCancellableCoroutine
import org.rekotlin.Store import org.rekotlin.Store
import kotlin.coroutines.resume
/** /**
* Handles disclaimer display after the card scanning operation. * Handles disclaimer display after the card scanning operation.
@ -40,31 +34,13 @@ internal class DisclaimerChain(
previousChainResult.right() previousChainResult.right()
} else { } else {
disclaimerWillShow() disclaimerWillShow()
showDisclaimer(disclaimer, previousChainResult)
}
}
private suspend fun showDisclaimer(disclaimer: Disclaimer, response: ScanResponse): ScanChainResult { // TODO: [REDACTED_JIRA]
store.dispatchOnMain(DisclaimerAction.SetDisclaimer(disclaimer)) store.dispatchNavigationAction {
push(route = AppRoute.Disclaimer(isTosAccepted = false))
}
return suspendCancellableCoroutine { continuation -> previousChainResult.right()
store.dispatchOnMain(
DisclaimerAction.Show(
from = DisclaimerSource.Home,
callback = DisclaimerCallback(
onAccept = {
if (continuation.isActive) {
continuation.resume(response.right())
}
},
onDismiss = {
if (continuation.isActive) {
continuation.resume(ScanChainException.DisclaimerWasCanceled.left())
}
},
),
),
)
} }
} }
} }

View file

@ -7,7 +7,6 @@ import com.tangem.common.routing.AppRoute
import com.tangem.core.analytics.Analytics import com.tangem.core.analytics.Analytics
import com.tangem.core.analytics.models.AnalyticsParam import com.tangem.core.analytics.models.AnalyticsParam
import com.tangem.core.analytics.models.Basic import com.tangem.core.analytics.models.Basic
import com.tangem.core.ui.event.StateEvent import com.tangem.core.ui.event.StateEvent
import com.tangem.core.ui.event.consumedEvent import com.tangem.core.ui.event.consumedEvent
import com.tangem.core.ui.event.triggeredEvent import com.tangem.core.ui.event.triggeredEvent
@ -22,8 +21,6 @@ import com.tangem.tap.common.redux.AppState
import com.tangem.tap.common.redux.global.GlobalAction import com.tangem.tap.common.redux.global.GlobalAction
import com.tangem.tap.features.details.redux.DetailsAction import com.tangem.tap.features.details.redux.DetailsAction
import com.tangem.tap.features.details.redux.DetailsState import com.tangem.tap.features.details.redux.DetailsState
import com.tangem.tap.features.disclaimer.redux.DisclaimerAction
import com.tangem.tap.features.disclaimer.redux.DisclaimerSource
import com.tangem.tap.features.home.LocaleRegionProvider import com.tangem.tap.features.home.LocaleRegionProvider
import com.tangem.tap.features.home.RUSSIA_COUNTRY_CODE import com.tangem.tap.features.home.RUSSIA_COUNTRY_CODE
import com.tangem.tap.scope import com.tangem.tap.scope
@ -128,7 +125,9 @@ internal class DetailsViewModel(
} }
private fun navigateToToS() { private fun navigateToToS() {
store.dispatchOnMain(DisclaimerAction.Show(DisclaimerSource.Details)) store.dispatchNavigationAction {
push(AppRoute.Disclaimer(isTosAccepted = true))
}
} }
private fun navigateToReferralProgram() { private fun navigateToReferralProgram() {

View file

@ -24,12 +24,6 @@ abstract class BaseDisclaimer(
override suspend fun isAccepted(): Boolean = dataProvider.isAccepted() override suspend fun isAccepted(): Boolean = dataProvider.isAccepted()
} }
class DummyDisclaimer : Disclaimer {
override fun getUri(): Uri = Uri.parse("https://tangem.com/tangem_tos.html")
override suspend fun accept() {}
override suspend fun isAccepted(): Boolean = false
}
class TangemDisclaimer(dataProvider: DisclaimerDataProvider) : BaseDisclaimer(dataProvider) { class TangemDisclaimer(dataProvider: DisclaimerDataProvider) : BaseDisclaimer(dataProvider) {
override fun getUri(): Uri = Uri.parse("$baseUrl/tangem_tos.html") override fun getUri(): Uri = Uri.parse("$baseUrl/tangem_tos.html")
} }

View file

@ -1,20 +0,0 @@
package com.tangem.tap.features.disclaimer.redux
import com.tangem.tap.common.entities.ProgressState
import com.tangem.tap.features.disclaimer.Disclaimer
import org.rekotlin.Action
sealed class DisclaimerAction : Action {
data class SetDisclaimer(val disclaimer: Disclaimer) : DisclaimerAction()
data class Show(
val from: DisclaimerSource,
val callback: DisclaimerCallback? = null,
) : DisclaimerAction()
object AcceptDisclaimer : DisclaimerAction()
object OnBackPressed : DisclaimerAction()
data class OnProgressStateChanged(val state: ProgressState?) : DisclaimerAction()
}

View file

@ -1,45 +0,0 @@
package com.tangem.tap.features.disclaimer.redux
import com.tangem.common.routing.AppRoute
import com.tangem.common.routing.AppRouter
import com.tangem.tap.common.extensions.dispatchNavigationAction
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
class DisclaimerMiddleware {
val disclaimerMiddleware: Middleware<AppState> = { dispatch, state ->
{ next ->
{ action ->
state()?.let { handleDisclaimerMiddleware(action, it) }
next(action)
}
}
}
}
private fun handleDisclaimerMiddleware(action: Action, appState: AppState) {
val state = appState.disclaimerState
when (action) {
is DisclaimerAction.Show -> {
store.dispatchNavigationAction {
push(AppRoute.Disclaimer(isTosAccepted = action.from == DisclaimerSource.Details))
}
}
is DisclaimerAction.AcceptDisclaimer -> {
mainScope.launch {
state.disclaimer.accept()
store.dispatchNavigationAction(AppRouter::pop)
state.callback?.onAccept?.invoke()
}
}
is DisclaimerAction.OnBackPressed -> {
store.dispatchNavigationAction(AppRouter::pop)
state.callback?.onDismiss?.invoke()
}
}
}

View file

@ -1,31 +0,0 @@
package com.tangem.tap.features.disclaimer.redux
import com.tangem.tap.common.redux.AppState
import org.rekotlin.Action
object DisclaimerReducer {
fun reduce(action: Action, state: AppState): DisclaimerState = internalReduce(action, state)
}
private fun internalReduce(action: Action, state: AppState): DisclaimerState {
if (action !is DisclaimerAction) return state.disclaimerState
val disclaimerState = state.disclaimerState
return when (action) {
is DisclaimerAction.SetDisclaimer -> disclaimerState.copy(
disclaimer = action.disclaimer,
)
is DisclaimerAction.Show -> disclaimerState.copy(
showedFrom = action.from,
callback = action.callback,
)
is DisclaimerAction.AcceptDisclaimer, is DisclaimerAction.OnBackPressed -> disclaimerState.copy(
callback = null,
progressState = null,
)
is DisclaimerAction.OnProgressStateChanged -> disclaimerState.copy(
progressState = action.state,
)
}
}

View file

@ -1,5 +0,0 @@
package com.tangem.tap.features.disclaimer.redux
enum class DisclaimerSource {
Home, Details
}

View file

@ -1,20 +0,0 @@
package com.tangem.tap.features.disclaimer.redux
import com.tangem.common.extensions.VoidCallback
import com.tangem.tap.common.entities.ProgressState
import com.tangem.tap.features.disclaimer.Disclaimer
import com.tangem.tap.features.disclaimer.DummyDisclaimer
import org.rekotlin.StateType
data class DisclaimerState(
val disclaimer: Disclaimer = DummyDisclaimer(),
val showedFrom: DisclaimerSource = DisclaimerSource.Home,
val callback: DisclaimerCallback? = null,
val progressState: ProgressState? = null,
) : StateType
data class DisclaimerCallback(
val onAccept: VoidCallback? = null,
val onDismiss: VoidCallback? = null,
)

View file

@ -1,139 +0,0 @@
package com.tangem.tap.features.disclaimer.ui
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.ui.extensions.setStatusBarColor
import com.tangem.tap.common.entities.ProgressState
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.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.DisclaimerSource
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> {
private val binding: FragmentDisclaimerBinding by viewBinding(FragmentDisclaimerBinding::bind)
private val webViewClient = DisclaimerWebViewClient()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
addBackPressHandler(handler = this)
binding.apply {
toolbar.setNavigationOnClickListener { handleOnBackPressed() }
webView.apply {
settings.allowFileAccess = false
settings.javaScriptEnabled = false
overScrollMode = OVER_SCROLL_NEVER
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.background_secondary)
webViewClient.onProgressStateChanged = { store.dispatch(DisclaimerAction.OnProgressStateChanged(it)) }
store.subscribe(subscriber = this) { state ->
state
.skipRepeats { oldState, newState -> oldState.disclaimerState == newState.disclaimerState }
.select(AppState::disclaimerState)
}
}
override fun onStop() {
webViewClient.onProgressStateChanged = null
store.unsubscribe(this)
super.onStop()
}
override fun configureTransitions() {
val inflater = TransitionInflater.from(requireContext())
when (store.state.disclaimerState.showedFrom) {
DisclaimerSource.Home -> {
enterTransition = inflater.inflateTransition(android.R.transition.slide_bottom)
exitTransition = inflater.inflateTransition(android.R.transition.slide_top)
}
DisclaimerSource.Details -> {
super.configureTransitions()
}
}
}
override fun handleOnBackPressed() {
store.dispatch(DisclaimerAction.OnBackPressed)
}
override fun newState(state: DisclaimerState) {
return with(binding) {
if (activity == null || view == null) return
updateUiVisibility(state.disclaimer, state.progressState)
}
}
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()
lifecycleScope.launch {
groupAccept.show(!disclaimer.isAccepted())
}
}
ProgressState.Error -> {
root.beginDelayedTransition()
webView.show()
groupAccept.show()
groupLoading.hide()
groupError.hide()
webView.loadLocalTermsOfServices()
}
else -> {
webView.setBackgroundColor(resources.getColor(R.color.transparent, null))
webView.loadUrl(disclaimer.getUri().toString())
}
}
}
private fun WebView.loadLocalTermsOfServices() {
loadData(localTermsOfServices, "text/html", "UTF-8")
}
}

View file

@ -1,64 +0,0 @@
package com.tangem.tap.features.disclaimer.ui
import android.graphics.Bitmap
import android.webkit.*
import com.tangem.common.extensions.ifNotNull
import com.tangem.tap.common.entities.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 < RESPONSE_USER_ERROR_STATUS_CODE) return
if (progressState != ProgressState.Done) return
progressState = ProgressState.Error
}
}
companion object {
private const val RESPONSE_USER_ERROR_STATUS_CODE = 400
}
}

View file

@ -1,66 +0,0 @@
package com.tangem.tap.features.disclaimer.ui
internal val localTermsOfServices = """
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Legal Disclaimer</title>
<style>
@font-face{font-family:"SF Pro Display";src:url(/fonts/sf-pro/SFProDisplay-Light.eot) format("embedded-opentype"),url(/fonts/sf-pro/SFProDisplay-Light.woff2) format("woff2"),url(/fonts/sf-pro/SFProDisplay-Light.woff) format("woff"),url(/fonts/sf-pro/SFProDisplay-Light.ttf) format("truetype");font-weight:300;font-style:normal;font-display:swap}@font-face{font-family:"SF Pro Display";src:url(/fonts/sf-pro/SFProDisplay-Regular.eot) format("embedded-opentype"),url(/fonts/sf-pro/SFProDisplay-Regular.woff2) format("woff2"),url(/fonts/sf-pro/SFProDisplay-Regular.woff) format("woff"),url(/fonts/sf-pro/SFProDisplay-Regular.ttf) format("truetype");font-weight:400;font-style:normal;font-display:swap}@font-face{font-family:"SF Pro Display";src:url(/fonts/sf-pro/SFProDisplay-Medium.eot) format("embedded-opentype"),url(/fonts/sf-pro/SFProDisplay-Medium.woff2) format("woff2"),url(/fonts/sf-pro/SFProDisplay-Medium.woff) format("woff"),url(/fonts/sf-pro/SFProDisplay-Medium.ttf) format("truetype");font-weight:500;font-style:normal;font-display:swap}@font-face{font-family:"SF Pro Display";src:url(/fonts/sf-pro/SFProDisplay-Semibold.eot) format("embedded-opentype"),url(/fonts/sf-pro/SFProDisplay-Semibold.woff2) format("woff2"),url(/fonts/sf-pro/SFProDisplay-Semibold.woff) format("woff"),url(/fonts/sf-pro/SFProDisplay-Semibold.ttf) format("truetype");font-weight:600;font-style:normal;font-display:swap}@font-face{font-family:"SF Pro Display";src:url(/fonts/sf-pro/SFProDisplay-Bold.eot) format("embedded-opentype"),url(/fonts/sf-pro/SFProDisplay-Bold.woff2) format("woff2"),url(/fonts/sf-pro/SFProDisplay-Bold.woff) format("woff"),url(/fonts/sf-pro/SFProDisplay-Bold.ttf) format("truetype");font-weight:700;font-style:normal;font-display:swap}*{margin:0;padding:0}body{padding:0;margin:1rem;color:rgb(0 0 0);font-family:'SF Pro Display',-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif}h1{font-weight:700;font-size:30px;line-height:1.2;margin-bottom:1rem}p{font-size:16px;line-height:20px;letter-spacing:-.24px;margin-bottom:1rem}
</style>
</head>
<body><h1>Legal Disclaimer</h1>
<p>&nbsp; &nbsp; 1. Tangem application (Software)</p>
<p>&nbsp; &nbsp; The Software is intended for usage only with Tangem hardware wallets (Cards) via NFC interface. The
Software DOES NOT:</p>
<p>&nbsp; &nbsp; a) Generate, store, transmit, or have access to private (secret) cryptographic keys to blockchain
wallets holding digital assets, including crypto-currency.</p>
<p>&nbsp; &nbsp; b) Generate, store, transmit, or have access to secret keys, passwords, passphrases, recovery phrases
that can be used to restore or to copy private (secret) keys to blockchain wallets holding digital assets, including
crypto-currency.</p>
<p>&nbsp; &nbsp; c) Provide exchange, trading, investment services on behalf of Tangem AG.</p>
<p>&nbsp; &nbsp; 2. Risks related to the use of Software</p>
<p>&nbsp; &nbsp; Tangem will not be responsible for any losses, damages or claims arising from events falling within the
scope of the following five categories:</p>
<p>&nbsp; &nbsp; a) Mistakes made by the user of any cryptocurrency-related software or service, e.g., forgotten
passwords, payments sent to wrong addresses, and accidental deletion of blockchain wallets on Cards.</p>
<p>&nbsp; &nbsp; b) Problems of Software and/or any blockchain- or cryptocurrency- related software or service, e.g.,
corrupted files, incorrectly constructed transactions, unsafe cryptographic libraries, malware.</p>
<p>&nbsp; &nbsp; c) Technical failures in the hardware of the user, including Cards, of any cryptocurrency-related
software or service, e.g., data loss due to a faulty or damaged storage device.</p>
<p>&nbsp; &nbsp; d) Security problems experienced by the user of any cryptocurrency-related software or service, e.g.,
unauthorized access to users&apos; wallets and/or accounts.</p>
<p>&nbsp; &nbsp; e) Actions or inactions of third parties and/or events experienced by third parties, e.g., bankruptcy
of service providers, information security attacks on service providers, and fraud conducted by third parties.</p>
<p>&nbsp; &nbsp; 3. Trading and Investment risks</p>
<p>&nbsp; &nbsp; There is considerable exposure to risk in any crypto-currency or other digital asset exchange
transaction. Any transaction involving currencies involves risks including, but not limited to, the potential for
changing economic conditions that may substantially affect the price or liquidity of a currency. Investments in
crypto-currency exchange speculation may also be susceptible to sharp rises and falls as the relevant market values
fluctuate. It is for this reason that when speculating in such markets it is advisable to use only risk capital.</p>
<p>&nbsp; &nbsp; 4. Electronic Trading Risks</p>
<p>&nbsp; &nbsp; Before you engage in transactions using an electronic system, you should carefully review the rules and
regulations of the exchanges offering the system and/or listing the instruments you intend to trade. Online trading
has inherent risk due to system response and access times that may vary due to market conditions, system
performance, and other factors. You should understand these and additional risks before trading.</p>
<p>&nbsp; &nbsp; 5. Compliance with tax obligations &nbsp; &nbsp; &nbsp; &nbsp;</p>
<p>&nbsp; &nbsp; The users of the Software are solely responsible to determinate what, if any, taxes apply to their
crypto-currency transactions. The owners of, or contributors to, the Software are NOT responsible for determining
the taxes that apply to crypto-currency transactions. &nbsp; &nbsp; &nbsp; &nbsp;</p>
<p>&nbsp; &nbsp; 6. No warranties &nbsp; &nbsp; &nbsp; &nbsp;</p>
<p>&nbsp; &nbsp; The Software is provided on an &quot;as is&quot; basis without any warranties of any kind regarding the
Software and/or any content, data, materials and/or services provided on the Software. &nbsp; &nbsp; &nbsp;
&nbsp;</p>
<p>&nbsp; &nbsp; 7. Limitation of liability</p>
<p>&nbsp; &nbsp; Unless otherwise required by law, in no event shall the owners of, or contributors to, the Software be
liable for any damages of any kind, including, but not limited to, loss of use, loss of profits, or loss of data
arising out of or in any way connected with the use of the Software. In no way are the owners of, or contributors
to, the Software responsible for the actions, decisions, or other behavior taken or not taken by you in reliance
upon the Software.</p>
<p>&nbsp; &nbsp; 8. Last amendment</p>
<p>&nbsp; &nbsp; This disclaimer was amended for the last time on October 1st, 2020.</p></body>
</html>
""".trimIndent()

View file

@ -31,7 +31,6 @@ import com.tangem.domain.wallets.repository.WalletsRepository
import com.tangem.domain.wallets.usecase.GenerateWalletNameUseCase import com.tangem.domain.wallets.usecase.GenerateWalletNameUseCase
import com.tangem.feature.qrscanning.QrScanningRouter import com.tangem.feature.qrscanning.QrScanningRouter
import com.tangem.features.details.DetailsFeatureToggles import com.tangem.features.details.DetailsFeatureToggles
import com.tangem.features.pushnotifications.api.featuretoggles.PushNotificationsFeatureToggles
import com.tangem.features.pushnotifications.api.navigation.PushNotificationsRouter import com.tangem.features.pushnotifications.api.navigation.PushNotificationsRouter
import com.tangem.features.send.api.navigation.SendRouter import com.tangem.features.send.api.navigation.SendRouter
import com.tangem.features.staking.api.navigation.StakingRouter import com.tangem.features.staking.api.navigation.StakingRouter
@ -87,7 +86,6 @@ data class DaggerGraphState(
val urlOpener: UrlOpener? = null, val urlOpener: UrlOpener? = null,
val shareManager: ShareManager? = null, val shareManager: ShareManager? = null,
val appRouter: AppRouter? = null, val appRouter: AppRouter? = null,
val pushNotificationsFeatureToggles: PushNotificationsFeatureToggles? = null,
val pushNotificationsRouter: PushNotificationsRouter? = null, val pushNotificationsRouter: PushNotificationsRouter? = null,
val homeFeatureToggles: HomeFeatureToggles? = null, val homeFeatureToggles: HomeFeatureToggles? = null,
val getUserCountryUseCase: GetUserCountryUseCase? = null, val getUserCountryUseCase: GetUserCountryUseCase? = null,

View file

@ -12,7 +12,6 @@ import com.tangem.features.disclaimer.api.components.DisclaimerComponent
import com.tangem.features.managetokens.ManageTokensToggles import com.tangem.features.managetokens.ManageTokensToggles
import com.tangem.features.managetokens.component.ManageTokensComponent import com.tangem.features.managetokens.component.ManageTokensComponent
import com.tangem.features.markets.details.MarketsTokenDetailsComponent import com.tangem.features.markets.details.MarketsTokenDetailsComponent
import com.tangem.features.pushnotifications.api.featuretoggles.PushNotificationsFeatureToggles
import com.tangem.features.pushnotifications.api.navigation.PushNotificationsRouter import com.tangem.features.pushnotifications.api.navigation.PushNotificationsRouter
import com.tangem.features.send.api.navigation.SendRouter import com.tangem.features.send.api.navigation.SendRouter
import com.tangem.features.staking.api.navigation.StakingRouter import com.tangem.features.staking.api.navigation.StakingRouter
@ -28,7 +27,6 @@ import com.tangem.tap.features.details.ui.details.DetailsFragment
import com.tangem.tap.features.details.ui.resetcard.ResetCardFragment import com.tangem.tap.features.details.ui.resetcard.ResetCardFragment
import com.tangem.tap.features.details.ui.securitymode.SecurityModeFragment import com.tangem.tap.features.details.ui.securitymode.SecurityModeFragment
import com.tangem.tap.features.details.ui.walletconnect.WalletConnectFragment import com.tangem.tap.features.details.ui.walletconnect.WalletConnectFragment
import com.tangem.tap.features.disclaimer.ui.DisclaimerFragment
import com.tangem.tap.features.home.HomeFragment import com.tangem.tap.features.home.HomeFragment
import com.tangem.tap.features.main.ui.ModalNotificationBottomSheetFragment import com.tangem.tap.features.main.ui.ModalNotificationBottomSheetFragment
import com.tangem.tap.features.onboarding.products.note.OnboardingNoteFragment import com.tangem.tap.features.onboarding.products.note.OnboardingNoteFragment
@ -59,7 +57,6 @@ internal class ChildFactory @Inject constructor(
private val stakingRouter: StakingRouter, private val stakingRouter: StakingRouter,
private val testerRouter: TesterRouter, private val testerRouter: TesterRouter,
private val detailsFeatureToggles: DetailsFeatureToggles, private val detailsFeatureToggles: DetailsFeatureToggles,
private val pushNotificationsFeatureToggles: PushNotificationsFeatureToggles,
private val manageTokensToggles: ManageTokensToggles, private val manageTokensToggles: ManageTokensToggles,
private val pushNotificationRouter: PushNotificationsRouter, private val pushNotificationRouter: PushNotificationsRouter,
) { ) {
@ -111,15 +108,11 @@ internal class ChildFactory @Inject constructor(
route.asFragmentChild(Provider { SecurityModeFragment() }) route.asFragmentChild(Provider { SecurityModeFragment() })
} }
is AppRoute.Disclaimer -> { is AppRoute.Disclaimer -> {
if (pushNotificationsFeatureToggles.isPushNotificationsEnabled) { route.asComponentChild(
route.asComponentChild( contextProvider = contextProvider(route, contextFactory),
contextProvider = contextProvider(route, contextFactory), params = DisclaimerComponent.Params(route.isTosAccepted),
params = DisclaimerComponent.Params(route.isTosAccepted), componentFactory = disclaimerComponentFactory,
componentFactory = disclaimerComponentFactory, )
)
} else {
route.asFragmentChild(Provider { DisclaimerFragment() })
}
} }
is AppRoute.Home -> { is AppRoute.Home -> {
route.asFragmentChild(Provider { HomeFragment() }) route.asFragmentChild(Provider { HomeFragment() })

View file

@ -1,129 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/coordinator_details_confirm"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/background_secondary"
android:orientation="vertical">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/app_bar"
style="@style/Widget.MaterialComponents.Toolbar.Surface"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/background_secondary"
android:fitsSystemWindows="true"
app:liftOnScroll="true">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:navigationIcon="@drawable/ic_baseline_arrow_back_24"
app:navigationIconTint="@color/icon_primary_1"
app:titleTextColor="@color/text_primary_1"
app:title="@string/disclaimer_title" />
</com.google.android.material.appbar.AppBarLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cl_details_confirm"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/background_secondary"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<WebView
android:id="@+id/web_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="74dp"
app:layout_constraintBottom_toTopOf="@id/btn_accept"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<View
android:id="@+id/half_transparent_overlay"
android:layout_width="match_parent"
android:layout_height="110dp"
android:background="@drawable/bg_half_transparent_overlay"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<ProgressBar
android:id="@+id/progress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_error"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:lineSpacingExtra="5sp"
android:text="@string/disclaimer_error_loading"
android:textAlignment="center"
android:textSize="16sp"
app:layout_constraintBottom_toTopOf="@+id/btn_repeat"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed" />
<Button
android:id="@+id/btn_repeat"
style="@style/TapSecondaryButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="@string/common_retry"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_error" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_accept"
style="@style/TapPrimaryButton"
android:layout_width="0dp"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="24dp"
android:text="@string/common_accept"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<androidx.constraintlayout.widget.Group
android:id="@+id/group_error"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:constraint_referenced_ids="btn_repeat, tv_error" />
<androidx.constraintlayout.widget.Group
android:id="@+id/group_loading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:constraint_referenced_ids="progress" />
<androidx.constraintlayout.widget.Group
android:id="@+id/group_accept"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:constraint_referenced_ids="btn_accept, half_transparent_overlay" />
</androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout>

View file

@ -19,10 +19,6 @@
"name": "DETAILS_REDESIGN_ENABLED", "name": "DETAILS_REDESIGN_ENABLED",
"version": "5.13.0" "version": "5.13.0"
}, },
{
"name": "PUSH_NOTIFICATIONS_ENABLED",
"version": "5.13.0"
},
{ {
"name": "MARKETS_ENABLED", "name": "MARKETS_ENABLED",
"version": "5.15.0" "version": "5.15.0"

View file

@ -1,9 +0,0 @@
package com.tangem.features.pushnotifications.api.featuretoggles
/**
* Push notifications feature toggles
*/
interface PushNotificationsFeatureToggles {
/** Availability of push notifications */
val isPushNotificationsEnabled: Boolean
}

View file

@ -1,24 +0,0 @@
package com.tangem.features.pushnotifications.impl.di
import com.tangem.core.featuretoggle.manager.FeatureTogglesManager
import com.tangem.features.pushnotifications.api.featuretoggles.PushNotificationsFeatureToggles
import com.tangem.features.pushnotifications.impl.featuretoggles.DefaultPushNotificationsFeatureToggles
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton
/**
* DI module provides implementation of [PushNotificationsFeatureToggles]
*/
@Module
@InstallIn(SingletonComponent::class)
internal object PushNotificationsFeatureTogglesModule {
@Provides
@Singleton
fun provideSendFeatureToggles(featureTogglesManager: FeatureTogglesManager): PushNotificationsFeatureToggles {
return DefaultPushNotificationsFeatureToggles(featureTogglesManager = featureTogglesManager)
}
}

View file

@ -1,11 +0,0 @@
package com.tangem.features.pushnotifications.impl.featuretoggles
import com.tangem.core.featuretoggle.manager.FeatureTogglesManager
import com.tangem.features.pushnotifications.api.featuretoggles.PushNotificationsFeatureToggles
internal class DefaultPushNotificationsFeatureToggles(
private val featureTogglesManager: FeatureTogglesManager,
) : PushNotificationsFeatureToggles {
override val isPushNotificationsEnabled: Boolean
get() = featureTogglesManager.isFeatureEnabled("PUSH_NOTIFICATIONS_ENABLED")
}

View file

@ -28,7 +28,6 @@ import com.tangem.feature.wallet.presentation.wallet.state.utils.WalletEventSend
import com.tangem.feature.wallet.presentation.wallet.utils.ScreenLifecycleProvider import com.tangem.feature.wallet.presentation.wallet.utils.ScreenLifecycleProvider
import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntents import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntents
import com.tangem.features.markets.MarketsFeatureToggles import com.tangem.features.markets.MarketsFeatureToggles
import com.tangem.features.pushnotifications.api.featuretoggles.PushNotificationsFeatureToggles
import com.tangem.features.pushnotifications.api.utils.PUSH_PERMISSION import com.tangem.features.pushnotifications.api.utils.PUSH_PERMISSION
import com.tangem.features.pushnotifications.api.utils.getPushPermissionOrNull import com.tangem.features.pushnotifications.api.utils.getPushPermissionOrNull
import com.tangem.utils.Provider import com.tangem.utils.Provider
@ -67,7 +66,6 @@ internal class WalletViewModel @Inject constructor(
private val walletNameMigrationUseCase: WalletNameMigrationUseCase, private val walletNameMigrationUseCase: WalletNameMigrationUseCase,
private val refreshMultiCurrencyWalletQuotesUseCase: RefreshMultiCurrencyWalletQuotesUseCase, private val refreshMultiCurrencyWalletQuotesUseCase: RefreshMultiCurrencyWalletQuotesUseCase,
private val shouldAskPermissionUseCase: ShouldAskPermissionUseCase, private val shouldAskPermissionUseCase: ShouldAskPermissionUseCase,
private val pushNotificationsFeatureToggles: PushNotificationsFeatureToggles,
private val marketsFeatureToggles: MarketsFeatureToggles, private val marketsFeatureToggles: MarketsFeatureToggles,
analyticsEventsHandler: AnalyticsEventHandler, analyticsEventsHandler: AnalyticsEventHandler,
) : ViewModel() { ) : ViewModel() {
@ -166,10 +164,9 @@ internal class WalletViewModel @Inject constructor(
private fun subscribeOnPushNotificationsPermission() { private fun subscribeOnPushNotificationsPermission() {
viewModelScope.launch { viewModelScope.launch {
val isPushToggled = pushNotificationsFeatureToggles.isPushNotificationsEnabled
val shouldRequestPush = shouldAskPermissionUseCase(PUSH_PERMISSION) val shouldRequestPush = shouldAskPermissionUseCase(PUSH_PERMISSION)
val isPushPermissionAvailable = getPushPermissionOrNull() != null val isPushPermissionAvailable = getPushPermissionOrNull() != null
if (!isPushToggled || !shouldRequestPush || !isPushPermissionAvailable) return@launch if (!shouldRequestPush || !isPushPermissionAvailable) return@launch
delay(timeMillis = 1_800) delay(timeMillis = 1_800)