Updated on 2026-08-14
This commit is contained in:
commit
2baa5365b4
94 changed files with 705 additions and 1924 deletions
|
|
@ -24,17 +24,17 @@ import com.tangem.domain.feedback.SaveBlockchainErrorUseCase
|
|||
import com.tangem.domain.onboarding.SaveTwinsOnboardingShownUseCase
|
||||
import com.tangem.domain.onboarding.WasTwinsOnboardingShownUseCase
|
||||
import com.tangem.domain.settings.repositories.SettingsRepository
|
||||
import com.tangem.domain.settings.usercountry.GetUserCountryUseCase
|
||||
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||
import com.tangem.domain.tokens.repository.NetworksRepository
|
||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||
import com.tangem.domain.wallets.repository.WalletsRepository
|
||||
import com.tangem.domain.wallets.usecase.GenerateWalletNameUseCase
|
||||
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.domain.walletconnect2.domain.WalletConnectSessionsRepository
|
||||
import com.tangem.tap.features.customtoken.api.featuretoggles.CustomTokenFeatureToggles
|
||||
import com.tangem.tap.features.home.featuretoggles.HomeFeatureToggles
|
||||
import com.tangem.tap.proxy.AppStateHolder
|
||||
import dagger.hilt.EntryPoint
|
||||
import dagger.hilt.InstallIn
|
||||
|
|
@ -106,8 +106,6 @@ interface ApplicationEntryPoint {
|
|||
|
||||
fun getSaveBlockchainErrorUseCase(): SaveBlockchainErrorUseCase
|
||||
|
||||
fun getDetailsFeatureToggles(): DetailsFeatureToggles
|
||||
|
||||
fun getGetCardInfoUseCase(): GetCardInfoUseCase
|
||||
|
||||
fun getUrlOpener(): UrlOpener
|
||||
|
|
@ -116,7 +114,9 @@ interface ApplicationEntryPoint {
|
|||
|
||||
fun getAppRouter(): AppRouter
|
||||
|
||||
fun getPushNotificationsFeatureToggles(): PushNotificationsFeatureToggles
|
||||
|
||||
fun getTangemAppLogger(): TangemAppLoggerInitializer
|
||||
|
||||
fun getHomeFeatureToggles(): HomeFeatureToggles
|
||||
|
||||
fun getGetUserCountryCodeUseCase(): GetUserCountryUseCase
|
||||
}
|
||||
|
|
@ -65,7 +65,6 @@ import com.tangem.tap.common.OnActivityResultCallback
|
|||
import com.tangem.tap.common.SnackbarHandler
|
||||
import com.tangem.tap.common.apptheme.MutableAppThemeModeHolder
|
||||
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.redux.NotificationsHandler
|
||||
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.proxy.AppStateHolder
|
||||
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.configurator.AppRouterConfig
|
||||
import com.tangem.utils.coroutines.FeatureCoroutineExceptionHandler
|
||||
|
|
@ -539,11 +537,8 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
|
|||
}
|
||||
} else {
|
||||
lifecycleScope.launch {
|
||||
val toggles = store.inject(getDependency = DaggerGraphState::pushNotificationsFeatureToggles)
|
||||
val isPushPermissionEnabled = toggles.isPushNotificationsEnabled
|
||||
val shouldShowTos = !cardRepository.isTangemTOSAccepted() && isPushPermissionEnabled
|
||||
val wasPushInitiallyAsked = shouldInitiallyAskPermissionUseCase(PUSH_PERMISSION).getOrElse { false }
|
||||
val shouldShowInitialPush = wasPushInitiallyAsked && isPushPermissionEnabled
|
||||
val shouldShowTos = !cardRepository.isTangemTOSAccepted()
|
||||
val shouldShowInitialPush = shouldInitiallyAskPermissionUseCase(PUSH_PERMISSION).getOrElse { false }
|
||||
|
||||
val route = when {
|
||||
shouldShowTos -> AppRoute.Disclaimer(isTosAccepted = false)
|
||||
|
|
|
|||
|
|
@ -37,14 +37,13 @@ import com.tangem.domain.feedback.SaveBlockchainErrorUseCase
|
|||
import com.tangem.domain.onboarding.SaveTwinsOnboardingShownUseCase
|
||||
import com.tangem.domain.onboarding.WasTwinsOnboardingShownUseCase
|
||||
import com.tangem.domain.settings.repositories.SettingsRepository
|
||||
import com.tangem.domain.settings.usercountry.GetUserCountryUseCase
|
||||
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||
import com.tangem.domain.tokens.repository.NetworksRepository
|
||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||
import com.tangem.domain.wallets.repository.WalletsRepository
|
||||
import com.tangem.domain.wallets.usecase.GenerateWalletNameUseCase
|
||||
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.api.AnalyticsHandlerBuilder
|
||||
import com.tangem.tap.common.analytics.handlers.amplitude.AmplitudeAnalyticsHandler
|
||||
|
|
@ -60,6 +59,7 @@ import com.tangem.tap.common.redux.global.GlobalAction
|
|||
import com.tangem.tap.domain.tasks.product.DerivationsFinder
|
||||
import com.tangem.tap.domain.walletconnect2.domain.WalletConnectSessionsRepository
|
||||
import com.tangem.tap.features.customtoken.api.featuretoggles.CustomTokenFeatureToggles
|
||||
import com.tangem.tap.features.home.featuretoggles.HomeFeatureToggles
|
||||
import com.tangem.tap.proxy.AppStateHolder
|
||||
import com.tangem.tap.proxy.redux.DaggerGraphState
|
||||
import com.tangem.utils.coroutines.AppCoroutineDispatcherProvider
|
||||
|
|
@ -174,9 +174,6 @@ abstract class TangemApplication : Application(), ImageLoaderFactory {
|
|||
private val getCardInfoUseCase: GetCardInfoUseCase
|
||||
get() = entryPoint.getGetCardInfoUseCase()
|
||||
|
||||
private val detailsFeatureToggles: DetailsFeatureToggles
|
||||
get() = entryPoint.getDetailsFeatureToggles()
|
||||
|
||||
private val urlOpener
|
||||
get() = entryPoint.getUrlOpener()
|
||||
|
||||
|
|
@ -186,11 +183,14 @@ abstract class TangemApplication : Application(), ImageLoaderFactory {
|
|||
private val appRouter: AppRouter
|
||||
get() = entryPoint.getAppRouter()
|
||||
|
||||
private val pushNotificationsFeatureToggles: PushNotificationsFeatureToggles
|
||||
get() = entryPoint.getPushNotificationsFeatureToggles()
|
||||
|
||||
private val tangemAppLoggerInitializer: TangemAppLoggerInitializer
|
||||
get() = entryPoint.getTangemAppLogger()
|
||||
|
||||
private val homeFeatureToggles: HomeFeatureToggles
|
||||
get() = entryPoint.getHomeFeatureToggles()
|
||||
|
||||
private val getUserCountryUseCase: GetUserCountryUseCase
|
||||
get() = entryPoint.getGetUserCountryCodeUseCase()
|
||||
// endregion
|
||||
|
||||
override fun onCreate() {
|
||||
|
|
@ -268,11 +268,11 @@ abstract class TangemApplication : Application(), ImageLoaderFactory {
|
|||
getFeedbackEmailUseCase = getFeedbackEmailUseCase,
|
||||
getCardInfoUseCase = getCardInfoUseCase,
|
||||
assetLoader = assetLoader,
|
||||
detailsFeatureToggles = detailsFeatureToggles,
|
||||
urlOpener = urlOpener,
|
||||
shareManager = shareManager,
|
||||
appRouter = appRouter,
|
||||
pushNotificationsFeatureToggles = pushNotificationsFeatureToggles,
|
||||
homeFeatureToggles = homeFeatureToggles,
|
||||
getUserCountryUseCase = getUserCountryUseCase,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package com.tangem.tap.common.analytics.events
|
||||
|
||||
import com.tangem.core.analytics.models.AnalyticsEvent
|
||||
import com.tangem.tap.features.details.ui.details.SocialNetwork
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
|
|
@ -14,20 +13,8 @@ sealed class Settings(
|
|||
) : AnalyticsEvent(category, event, params, error) {
|
||||
|
||||
class ScreenOpened : Settings(event = "Settings Screen Opened")
|
||||
class ButtonChat : Settings(event = "Button - Chat")
|
||||
class ButtonSendFeedback : Settings(event = "Button - Send Feedback")
|
||||
class ButtonStartWalletConnectSession : Settings(event = "Button - Start Wallet Connect Session")
|
||||
class ButtonStopWalletConnectSession : Settings(event = "Button - Stop Wallet Connect Session")
|
||||
class ButtonCardSettings : Settings(event = "Button - Card Settings")
|
||||
class ButtonAppSettings : Settings(event = "Button - App Settings")
|
||||
class ButtonCreateBackup : Settings(event = "Button - Create Backup")
|
||||
class ButtonWalletConnect : Settings(event = "Button - Wallet Connect")
|
||||
object ScanNewCard : Settings(event = "Button - Scan New Card")
|
||||
|
||||
class ButtonSocialNetwork(network: SocialNetwork) : Settings(
|
||||
event = "Button - Social Network",
|
||||
params = mapOf("Network" to network.id),
|
||||
)
|
||||
|
||||
sealed class CardSettings(
|
||||
event: String,
|
||||
|
|
@ -63,8 +50,6 @@ sealed class Settings(
|
|||
error = error,
|
||||
)
|
||||
|
||||
class AccessCodeRecoveryButton : CardSettings("Button - Access Code Recovery")
|
||||
|
||||
class AccessCodeRecoveryChanged(status: AnalyticsParam.AccessCodeRecoveryStatus) : CardSettings(
|
||||
event = "Access Code Recovery Changed",
|
||||
params = mapOf(status.key to status.value),
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ package com.tangem.tap.common.redux
|
|||
import com.tangem.tap.common.redux.global.globalReducer
|
||||
import com.tangem.tap.features.details.redux.DetailsReducer
|
||||
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.onboarding.products.note.redux.OnboardingNoteReducer
|
||||
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),
|
||||
twinCardsState = TwinCardsReducer.reduce(action, state),
|
||||
detailsState = DetailsReducer.reduce(action, state),
|
||||
disclaimerState = DisclaimerReducer.reduce(action, state),
|
||||
tokensState = TokensReducer.reduce(action, state),
|
||||
walletConnectState = WalletConnectReducer.reduce(action, state.walletConnectState),
|
||||
welcomeState = WelcomeReducer.reduce(action, state),
|
||||
|
|
|
|||
|
|
@ -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.walletconnect.WalletConnectMiddleware
|
||||
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.HomeState
|
||||
import com.tangem.tap.features.onboarding.products.note.redux.OnboardingNoteMiddleware
|
||||
|
|
@ -43,7 +41,6 @@ data class AppState(
|
|||
val onboardingOtherCardsState: OnboardingOtherCardsState = OnboardingOtherCardsState(),
|
||||
val twinCardsState: TwinCardsState = TwinCardsState(),
|
||||
val detailsState: DetailsState = DetailsState(),
|
||||
val disclaimerState: DisclaimerState = DisclaimerState(),
|
||||
val tokensState: TokensState = TokensState(),
|
||||
val walletConnectState: WalletConnectState = WalletConnectState(),
|
||||
val welcomeState: WelcomeState = WelcomeState(),
|
||||
|
|
@ -75,7 +72,6 @@ data class AppState(
|
|||
OnboardingOtherCardsMiddleware.handler,
|
||||
TwinCardsMiddleware.handler,
|
||||
DetailsMiddleware().detailsMiddleware,
|
||||
DisclaimerMiddleware().disclaimerMiddleware,
|
||||
WalletConnectMiddleware().walletConnectMiddleware,
|
||||
BackupMiddleware().backupMiddleware,
|
||||
WelcomeMiddleware().middleware,
|
||||
|
|
|
|||
|
|
@ -92,21 +92,24 @@ private fun handleAction(action: Action, appState: () -> AppState?) {
|
|||
scope.launch { exchangeManager.update() }
|
||||
}
|
||||
is GlobalAction.FetchUserCountry -> {
|
||||
scope.launch {
|
||||
// TODO("After adding DI") get dependencies by DI
|
||||
runCatching { store.state.featureRepositoryProvider.homeRepository.getUserCountryCode() }
|
||||
.onSuccess {
|
||||
store.dispatchOnMain(
|
||||
GlobalAction.FetchUserCountry.Success(countryCode = it.code.lowercase()),
|
||||
)
|
||||
}
|
||||
.onFailure {
|
||||
store.dispatchOnMain(
|
||||
GlobalAction.FetchUserCountry.Success(
|
||||
countryCode = Locale.getDefault().country.lowercase(),
|
||||
),
|
||||
)
|
||||
}
|
||||
val homeFeatureToggles = store.inject(DaggerGraphState::homeFeatureToggles)
|
||||
|
||||
if (!homeFeatureToggles.isMigrateUserCountryCodeEnabled) {
|
||||
scope.launch {
|
||||
runCatching { store.state.featureRepositoryProvider.homeRepository.getUserCountryCode() }
|
||||
.onSuccess {
|
||||
store.dispatchOnMain(
|
||||
GlobalAction.FetchUserCountry.Success(countryCode = it.code.lowercase()),
|
||||
)
|
||||
}
|
||||
.onFailure {
|
||||
store.dispatchOnMain(
|
||||
GlobalAction.FetchUserCountry.Success(
|
||||
countryCode = Locale.getDefault().country.lowercase(),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,12 +2,9 @@ package com.tangem.tap.common.redux.global
|
|||
|
||||
import com.tangem.domain.redux.domainStore
|
||||
import com.tangem.domain.redux.global.DomainGlobalAction
|
||||
import com.tangem.tap.common.extensions.dispatchOnMain
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.features.home.redux.HomeAction
|
||||
import com.tangem.tap.features.onboarding.OnboardingManager
|
||||
import com.tangem.tap.proxy.AppStateHolder
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.utils.extensions.replaceBy
|
||||
import org.rekotlin.Action
|
||||
|
||||
|
|
@ -86,10 +83,7 @@ fun globalReducer(action: Action, state: AppState, appStateHolder: AppStateHolde
|
|||
is GlobalAction.SetIfCardVerifiedOnline ->
|
||||
globalState.copy(cardVerifiedOnline = action.verified)
|
||||
is GlobalAction.FetchUserCountry.Success -> {
|
||||
store.dispatchOnMain(HomeAction.UpdateCountryCode(action.countryCode))
|
||||
globalState.copy(
|
||||
userCountryCode = action.countryCode,
|
||||
)
|
||||
globalState.copy(userCountryCode = action.countryCode)
|
||||
}
|
||||
else -> globalState
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ data class GlobalState(
|
|||
val scanCardFailsCounter: Int = 0,
|
||||
val dialog: StateDialog? = null,
|
||||
val exchangeManager: CurrencyExchangeManager = CurrencyExchangeManager.dummy(),
|
||||
@Deprecated("Use GetUserCountryCodeUseCase instead")
|
||||
val userCountryCode: String? = null,
|
||||
val appThemeMode: AppThemeMode = AppThemeMode.DEFAULT,
|
||||
) : StateType
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@ import com.tangem.domain.settings.repositories.AppRatingRepository
|
|||
import com.tangem.domain.settings.repositories.PermissionRepository
|
||||
import com.tangem.domain.settings.repositories.PromoSettingsRepository
|
||||
import com.tangem.domain.settings.repositories.SettingsRepository
|
||||
import com.tangem.domain.settings.usercountry.FetchUserCountryUseCase
|
||||
import com.tangem.domain.settings.usercountry.GetUserCountryUseCase
|
||||
import com.tangem.tap.domain.sdk.TangemSdkManager
|
||||
import com.tangem.tap.domain.settings.DefaultLegacySettingsRepository
|
||||
import dagger.Module
|
||||
|
|
@ -212,4 +214,16 @@ internal object SettingsDomainModule {
|
|||
return ShouldSaveAccessCodesUseCase(settingsRepository = settingsRepository)
|
||||
}
|
||||
// endregion
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideFetchUserCountryCodeUseCase(settingsRepository: SettingsRepository): FetchUserCountryUseCase {
|
||||
return FetchUserCountryUseCase(settingsRepository)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideGetUserCountryCodeUseCase(settingsRepository: SettingsRepository): GetUserCountryUseCase {
|
||||
return GetUserCountryUseCase(settingsRepository)
|
||||
}
|
||||
}
|
||||
|
|
@ -13,8 +13,6 @@ import com.tangem.operations.attestation.Attestation
|
|||
import com.tangem.tap.common.extensions.inject
|
||||
import com.tangem.tap.common.extensions.setContext
|
||||
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.proxy.redux.DaggerGraphState
|
||||
import com.tangem.tap.store
|
||||
|
|
@ -62,7 +60,6 @@ class TapWalletManager(
|
|||
updateConfigManager(scanResponse)
|
||||
withMainContext {
|
||||
// Order is important
|
||||
store.dispatch(DisclaimerAction.SetDisclaimer(card.createDisclaimer()))
|
||||
store.dispatch(TwinCardsAction.IfTwinsPrepareState(scanResponse))
|
||||
store.dispatch(GlobalAction.SaveScanResponse(scanResponse))
|
||||
store.dispatch(GlobalAction.SetIfCardVerifiedOnline(!attestationFailed))
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ package com.tangem.tap.domain.scanCard
|
|||
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.common.core.TangemError
|
||||
import com.tangem.common.core.TangemSdkError
|
||||
import com.tangem.common.doOnFailure
|
||||
import com.tangem.common.doOnSuccess
|
||||
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.redux.global.GlobalAction
|
||||
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.products.twins.redux.TwinCardsAction
|
||||
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(
|
||||
scanResponse: ScanResponse,
|
||||
crossinline disclaimerWillShow: () -> Unit = {},
|
||||
|
|
@ -109,7 +107,6 @@ internal object LegacyScanProcessor {
|
|||
crossinline onFailure: suspend (error: TangemError) -> Unit,
|
||||
) {
|
||||
val disclaimer = scanResponse.card.createDisclaimer()
|
||||
store.dispatchOnMain(DisclaimerAction.SetDisclaimer(disclaimer))
|
||||
|
||||
if (disclaimer.isAccepted()) {
|
||||
nextHandler(scanResponse)
|
||||
|
|
@ -120,23 +117,9 @@ internal object LegacyScanProcessor {
|
|||
withContext(Dispatchers.Main.immediate) {
|
||||
disclaimerWillShow()
|
||||
|
||||
store.dispatch(
|
||||
DisclaimerAction.Show(
|
||||
from = DisclaimerSource.Home,
|
||||
callback = DisclaimerCallback(
|
||||
onAccept = {
|
||||
scope.launch(Dispatchers.Main.immediate) {
|
||||
nextHandler(scanResponse)
|
||||
}
|
||||
},
|
||||
onDismiss = {
|
||||
scope.launch(Dispatchers.Main.immediate) {
|
||||
onFailure(TangemSdkError.UserCancelled())
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
)
|
||||
store.dispatchNavigationAction {
|
||||
push(AppRoute.Disclaimer(isTosAccepted = false))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,11 +59,7 @@ internal object UseCaseScanProcessor {
|
|||
),
|
||||
)
|
||||
add(AnalyticsChain(Basic.CardWasScanned(analyticsSource)))
|
||||
val pushNotificationsToggles =
|
||||
store.inject(getDependency = DaggerGraphState::pushNotificationsFeatureToggles)
|
||||
if (pushNotificationsToggles.isPushNotificationsEnabled) {
|
||||
add(DisclaimerChain(store, disclaimerWillShow))
|
||||
}
|
||||
add(DisclaimerChain(store, disclaimerWillShow))
|
||||
add(CheckForOnboardingChain(store, store.state.globalState.tapWalletManager))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,21 +1,15 @@
|
|||
package com.tangem.tap.domain.scanCard.chains
|
||||
|
||||
import arrow.core.left
|
||||
import arrow.core.right
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.domain.card.ScanCardException
|
||||
import com.tangem.domain.core.chain.Chain
|
||||
import com.tangem.domain.core.chain.ResultChain
|
||||
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.features.disclaimer.Disclaimer
|
||||
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 kotlin.coroutines.resume
|
||||
|
||||
/**
|
||||
* Handles disclaimer display after the card scanning operation.
|
||||
|
|
@ -40,31 +34,13 @@ internal class DisclaimerChain(
|
|||
previousChainResult.right()
|
||||
} else {
|
||||
disclaimerWillShow()
|
||||
showDisclaimer(disclaimer, previousChainResult)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun showDisclaimer(disclaimer: Disclaimer, response: ScanResponse): ScanChainResult {
|
||||
store.dispatchOnMain(DisclaimerAction.SetDisclaimer(disclaimer))
|
||||
// TODO: [REDACTED_JIRA]
|
||||
store.dispatchNavigationAction {
|
||||
push(route = AppRoute.Disclaimer(isTosAccepted = false))
|
||||
}
|
||||
|
||||
return suspendCancellableCoroutine { continuation ->
|
||||
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())
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
)
|
||||
previousChainResult.right()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -239,9 +239,8 @@ class WalletConnectSdkHelper {
|
|||
private suspend fun signTransaction(data: WcTransactionData, cardId: String?): String? {
|
||||
val dataToSign = EthereumUtils.buildTransactionToSign(
|
||||
transactionData = data.transaction,
|
||||
nonce = null,
|
||||
blockchain = data.walletManager.wallet.blockchain,
|
||||
) ?: return null
|
||||
)
|
||||
|
||||
val command = SignHashCommand(
|
||||
hash = dataToSign.hash,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package com.tangem.tap.features.details.redux
|
||||
|
||||
import androidx.lifecycle.LifecycleCoroutineScope
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.apptheme.model.AppThemeMode
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
|
|
@ -14,15 +13,6 @@ sealed class DetailsAction : Action {
|
|||
val shouldSaveUserWallets: Boolean,
|
||||
) : DetailsAction()
|
||||
|
||||
data object ScanAndSaveUserWallet : DetailsAction() {
|
||||
|
||||
data object Success : DetailsAction()
|
||||
|
||||
data class Error(val error: TextReference?) : DetailsAction()
|
||||
}
|
||||
|
||||
data object DismissError : DetailsAction()
|
||||
|
||||
sealed class AppSettings : DetailsAction() {
|
||||
data class SwitchPrivacySetting(
|
||||
val enable: Boolean,
|
||||
|
|
|
|||
|
|
@ -2,36 +2,24 @@ package com.tangem.tap.features.details.redux
|
|||
|
||||
import androidx.lifecycle.LifecycleCoroutineScope
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.common.core.TangemError
|
||||
import com.tangem.common.core.TangemSdkError
|
||||
import com.tangem.common.doOnFailure
|
||||
import com.tangem.common.doOnSuccess
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.common.routing.utils.popTo
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.domain.apptheme.model.AppThemeMode
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.domain.wallets.builder.UserWalletBuilder
|
||||
import com.tangem.domain.wallets.legacy.UserWalletsListError
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.tap.*
|
||||
import com.tangem.tap.common.analytics.events.AnalyticsParam
|
||||
import com.tangem.tap.common.analytics.events.Settings
|
||||
import com.tangem.tap.common.extensions.dispatchNavigationAction
|
||||
import com.tangem.tap.common.extensions.dispatchWithMain
|
||||
import com.tangem.tap.common.extensions.inject
|
||||
import com.tangem.tap.common.extensions.onUserWalletSelected
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
import com.tangem.tap.features.demo.DemoHelper
|
||||
import com.tangem.tap.proxy.redux.DaggerGraphState
|
||||
import com.tangem.utils.coroutines.JobHolder
|
||||
import com.tangem.utils.coroutines.saveIn
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.flow
|
||||
|
|
@ -41,7 +29,6 @@ import kotlinx.coroutines.launch
|
|||
import org.rekotlin.Action
|
||||
import org.rekotlin.Middleware
|
||||
import timber.log.Timber
|
||||
import com.tangem.core.analytics.models.AnalyticsParam as CoreAnalyticsParam
|
||||
|
||||
class DetailsMiddleware {
|
||||
private val appSettingsMiddleware = AppSettingsMiddleware()
|
||||
|
|
@ -62,7 +49,6 @@ class DetailsMiddleware {
|
|||
private fun handleAction(state: DetailsState, action: Action) {
|
||||
when (action) {
|
||||
is DetailsAction.AppSettings -> appSettingsMiddleware.handle(state, action)
|
||||
is DetailsAction.ScanAndSaveUserWallet -> scanAndSaveUserWallet()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -278,95 +264,4 @@ class DetailsMiddleware {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun scanAndSaveUserWallet() = scope.launch(Dispatchers.IO) {
|
||||
val cardSdkConfigRepository = store.inject(DaggerGraphState::cardSdkConfigRepository)
|
||||
|
||||
val prevUseBiometricsForAccessCode = cardSdkConfigRepository.isBiometricsRequestPolicy()
|
||||
|
||||
// Update access code policy for access code saving when a card was scanned
|
||||
val shouldSaveAccessCodes = store.inject(DaggerGraphState::settingsRepository).shouldSaveAccessCodes()
|
||||
cardSdkConfigRepository.setAccessCodeRequestPolicy(isBiometricsRequestPolicy = shouldSaveAccessCodes)
|
||||
|
||||
store.inject(DaggerGraphState::scanCardProcessor).scan(
|
||||
analyticsSource = CoreAnalyticsParam.ScreensSources.Settings,
|
||||
onWalletNotCreated = {
|
||||
// No need to rollback policy, continue with the policy set before the card scan
|
||||
store.dispatchWithMain(DetailsAction.ScanAndSaveUserWallet.Success)
|
||||
},
|
||||
disclaimerWillShow = {
|
||||
store.dispatchNavigationAction(AppRouter::pop)
|
||||
},
|
||||
onSuccess = { scanResponse ->
|
||||
createUserWallet(scanResponse)
|
||||
.doOnSuccess {
|
||||
saveUserWalletAndPopBackToWalletScreen(
|
||||
userWallet = it,
|
||||
prevUseBiometricsForAccessCode = prevUseBiometricsForAccessCode,
|
||||
)
|
||||
}
|
||||
.doOnFailure { error ->
|
||||
Timber.e(error, "Unable to create user wallet")
|
||||
handleError(error = error, prevUseBiometricsForAccessCode = prevUseBiometricsForAccessCode)
|
||||
}
|
||||
},
|
||||
onFailure = { error ->
|
||||
Timber.e(error, "Unable to scan card")
|
||||
handleError(error = error, prevUseBiometricsForAccessCode = prevUseBiometricsForAccessCode)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
private suspend fun createUserWallet(scanResponse: ScanResponse): CompletionResult<UserWallet> {
|
||||
val walletNameGenerateUseCase = store.inject(DaggerGraphState::generateWalletNameUseCase)
|
||||
val userWallet = UserWalletBuilder(scanResponse, walletNameGenerateUseCase).build()
|
||||
|
||||
return if (userWallet != null) {
|
||||
CompletionResult.Success(userWallet)
|
||||
} else {
|
||||
CompletionResult.Failure(TangemSdkError.WalletIsNotCreated())
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun saveUserWalletAndPopBackToWalletScreen(
|
||||
userWallet: UserWallet,
|
||||
prevUseBiometricsForAccessCode: Boolean,
|
||||
) {
|
||||
val userWalletsListManager = store.inject(DaggerGraphState::generalUserWalletsListManager)
|
||||
|
||||
userWalletsListManager.save(userWallet)
|
||||
.doOnSuccess {
|
||||
store.onUserWalletSelected(userWallet)
|
||||
|
||||
store.dispatchWithMain(DetailsAction.ScanAndSaveUserWallet.Success)
|
||||
store.dispatchNavigationAction { popTo<AppRoute.Wallet>() }
|
||||
}
|
||||
.doOnFailure { error ->
|
||||
if (error is UserWalletsListError.WalletAlreadySaved) {
|
||||
userWalletsListManager.select(userWallet.walletId)
|
||||
store.onUserWalletSelected(userWallet)
|
||||
|
||||
store.dispatchWithMain(DetailsAction.ScanAndSaveUserWallet.Success)
|
||||
store.dispatchNavigationAction { popTo<AppRoute.Wallet>() }
|
||||
} else {
|
||||
Timber.e(error, "Unable to create user wallet")
|
||||
handleError(error, prevUseBiometricsForAccessCode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun handleError(error: TangemError, prevUseBiometricsForAccessCode: Boolean) {
|
||||
val cardSdkConfigRepository = store.inject(DaggerGraphState::cardSdkConfigRepository)
|
||||
|
||||
// Rollback policy if card saving was failed
|
||||
cardSdkConfigRepository.setAccessCodeRequestPolicy(prevUseBiometricsForAccessCode)
|
||||
|
||||
store.dispatchWithMain(DetailsAction.ScanAndSaveUserWallet.Error(error.toTextReference()))
|
||||
}
|
||||
|
||||
private fun TangemError.toTextReference(): TextReference? {
|
||||
if (silent) return null
|
||||
|
||||
return messageResId?.let(::resourceReference) ?: stringReference(customMessage)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
package com.tangem.tap.features.details.redux
|
||||
|
||||
import com.tangem.domain.apptheme.model.AppThemeMode
|
||||
import com.tangem.domain.models.scan.CardDTO
|
||||
import com.tangem.tap.common.extensions.inject
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.proxy.redux.DaggerGraphState
|
||||
|
|
@ -21,7 +20,7 @@ private fun internalReduce(action: Action, state: AppState): DetailsState {
|
|||
val detailsState = state.detailsState
|
||||
return when (action) {
|
||||
is DetailsAction.PrepareScreen -> {
|
||||
handlePrepareScreen(action, state)
|
||||
handlePrepareScreen(action)
|
||||
}
|
||||
is DetailsAction.AppSettings -> {
|
||||
handlePrivacyAction(action, detailsState)
|
||||
|
|
@ -31,26 +30,12 @@ private fun internalReduce(action: Action, state: AppState): DetailsState {
|
|||
selectedAppCurrency = action.currency,
|
||||
),
|
||||
)
|
||||
is DetailsAction.ScanAndSaveUserWallet -> detailsState.copy(
|
||||
isScanningInProgress = true,
|
||||
)
|
||||
is DetailsAction.ScanAndSaveUserWallet.Error -> detailsState.copy(
|
||||
isScanningInProgress = false,
|
||||
error = action.error,
|
||||
)
|
||||
is DetailsAction.ScanAndSaveUserWallet.Success -> detailsState.copy(
|
||||
isScanningInProgress = false,
|
||||
)
|
||||
is DetailsAction.DismissError -> detailsState.copy(
|
||||
error = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handlePrepareScreen(action: DetailsAction.PrepareScreen, state: AppState): DetailsState {
|
||||
private fun handlePrepareScreen(action: DetailsAction.PrepareScreen): DetailsState {
|
||||
return DetailsState(
|
||||
scanResponse = action.scanResponse,
|
||||
createBackupAllowed = action.scanResponse.card.backupStatus == CardDTO.BackupStatus.NoBackup,
|
||||
appSettingsState = AppSettingsState(
|
||||
isBiometricsAvailable = runBlocking {
|
||||
tangemSdkManager.checkCanUseBiometry()
|
||||
|
|
|
|||
|
|
@ -1,27 +1,16 @@
|
|||
package com.tangem.tap.features.details.redux
|
||||
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.apptheme.model.AppThemeMode
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import org.rekotlin.StateType
|
||||
|
||||
data class DetailsState(
|
||||
@Deprecated("Delete after onboarding refactoring")
|
||||
val scanResponse: ScanResponse? = null,
|
||||
val privacyPolicyUrl: String? = null,
|
||||
val createBackupAllowed: Boolean = false,
|
||||
val isScanningInProgress: Boolean = false,
|
||||
val error: TextReference? = null,
|
||||
val appSettingsState: AppSettingsState = AppSettingsState(),
|
||||
) : StateType
|
||||
|
||||
sealed class ResetCardDialog {
|
||||
data object StartResetDialog : ResetCardDialog()
|
||||
data object ContinueResetDialog : ResetCardDialog()
|
||||
data object InterruptedResetDialog : ResetCardDialog()
|
||||
data object CompletedResetDialog : ResetCardDialog()
|
||||
}
|
||||
|
||||
data class AppSettingsState(
|
||||
val saveWallets: Boolean = false,
|
||||
val saveAccessCodes: Boolean = false,
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ import com.tangem.domain.balancehiding.repositories.BalanceHidingRepository
|
|||
import com.tangem.domain.settings.CanUseBiometryUseCase
|
||||
import com.tangem.domain.settings.repositories.SettingsRepository
|
||||
import com.tangem.domain.wallets.repository.WalletsRepository
|
||||
import com.tangem.features.details.DetailsFeatureToggles
|
||||
import com.tangem.tap.common.analytics.events.AnalyticsParam
|
||||
import com.tangem.tap.common.analytics.events.Settings
|
||||
import com.tangem.tap.common.extensions.dispatchNavigationAction
|
||||
|
|
@ -45,7 +44,6 @@ internal class AppSettingsViewModel @Inject constructor(
|
|||
private val appThemeModeRepository: AppThemeModeRepository,
|
||||
private val settingsRepository: SettingsRepository,
|
||||
private val appSettingsItemsAnalyticsSender: AppSettingsItemsAnalyticsSender,
|
||||
private val detailsFeatureToggles: DetailsFeatureToggles,
|
||||
) : ViewModel(),
|
||||
StoreSubscriber<DetailsState>,
|
||||
DefaultLifecycleObserver {
|
||||
|
|
@ -62,9 +60,7 @@ internal class AppSettingsViewModel @Inject constructor(
|
|||
|
||||
init {
|
||||
bootstrapAppCurrencyUpdates()
|
||||
if (detailsFeatureToggles.isRedesignEnabled) {
|
||||
bootstrapBiometricsUpdates()
|
||||
}
|
||||
bootstrapBiometricsUpdates()
|
||||
|
||||
subscribeToStoreChanges()
|
||||
sendItemsAnalytics()
|
||||
|
|
|
|||
|
|
@ -1,71 +0,0 @@
|
|||
package com.tangem.tap.features.details.ui.details
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.core.ui.UiDependencies
|
||||
import com.tangem.core.ui.screen.ComposeFragment
|
||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||
import com.tangem.domain.wallets.repository.WalletsRepository
|
||||
import com.tangem.tap.common.analytics.events.Settings
|
||||
import com.tangem.tap.common.extensions.dispatchNavigationAction
|
||||
import com.tangem.tap.features.details.redux.DetailsState
|
||||
import com.tangem.tap.store
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import org.rekotlin.StoreSubscriber
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
internal class DetailsFragment : ComposeFragment(), StoreSubscriber<DetailsState> {
|
||||
|
||||
@Inject
|
||||
override lateinit var uiDependencies: UiDependencies
|
||||
|
||||
@Inject
|
||||
lateinit var walletsRepository: WalletsRepository
|
||||
|
||||
@Inject
|
||||
lateinit var userWalletsListManager: UserWalletsListManager
|
||||
|
||||
private lateinit var detailsViewModel: DetailsViewModel
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
detailsViewModel = DetailsViewModel(
|
||||
store = store,
|
||||
walletsRepository = walletsRepository,
|
||||
userWalletsListManager = userWalletsListManager,
|
||||
)
|
||||
Analytics.send(Settings.ScreenOpened())
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun ScreenContent(modifier: Modifier) {
|
||||
DetailsScreen(
|
||||
modifier = modifier,
|
||||
state = detailsViewModel.detailsScreenState.value,
|
||||
onBackClick = { store.dispatchNavigationAction(AppRouter::pop) },
|
||||
)
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
store.subscribe(this) { state ->
|
||||
state.skipRepeats { oldState, newState ->
|
||||
oldState.detailsState == newState.detailsState
|
||||
}.select { it.detailsState }
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
super.onStop()
|
||||
store.unsubscribe(this)
|
||||
}
|
||||
|
||||
override fun newState(state: DetailsState) {
|
||||
if (activity == null || view == null) return
|
||||
detailsViewModel.detailsScreenState.value = detailsViewModel.updateState(state)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,288 +0,0 @@
|
|||
package com.tangem.tap.features.details.ui.details
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyRow
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
|
||||
import com.tangem.core.ui.components.SpacerH
|
||||
import com.tangem.core.ui.components.SpacerHMax
|
||||
import com.tangem.core.ui.event.EventEffect
|
||||
import com.tangem.core.ui.event.StateEvent
|
||||
import com.tangem.core.ui.event.consumedEvent
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.res.TangemColorPalette
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.tap.features.details.ui.common.ScreenTitle
|
||||
import com.tangem.tap.features.details.ui.common.SettingsScreensScaffold
|
||||
import com.tangem.wallet.R
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
||||
@Composable
|
||||
internal fun DetailsScreen(state: DetailsScreenState, onBackClick: () -> Unit, modifier: Modifier = Modifier) {
|
||||
val snackbarHostState = remember { SnackbarHostState() }
|
||||
|
||||
SettingsScreensScaffold(
|
||||
modifier = modifier,
|
||||
snackbarHostState = snackbarHostState,
|
||||
content = { Content(state = state) },
|
||||
onBackClick = onBackClick,
|
||||
)
|
||||
|
||||
ShowSnackbarIfNeeded(
|
||||
snackbarHostState = snackbarHostState,
|
||||
messageEvent = state.showSnackbar,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Content(state: DetailsScreenState, modifier: Modifier = Modifier) {
|
||||
Box(modifier = modifier) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.verticalScroll(rememberScrollState()),
|
||||
) {
|
||||
ScreenTitle(titleRes = R.string.details_title)
|
||||
SpacerH(height = TangemTheme.dimens.spacing36)
|
||||
SettingsItems(
|
||||
items = state.elements,
|
||||
)
|
||||
SpacerHMax()
|
||||
TangemSocialAccounts(
|
||||
links = state.tangemLinks,
|
||||
onSocialNetworkClick = state.onSocialNetworkClick,
|
||||
)
|
||||
SpacerH(height = TangemTheme.dimens.spacing12)
|
||||
TangemAppVersion(
|
||||
appNameRes = state.appNameRes,
|
||||
version = state.tangemVersion,
|
||||
)
|
||||
SpacerH(height = TangemTheme.dimens.spacing16)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun SettingsItems(items: List<SettingsItem>) {
|
||||
items.forEach { item ->
|
||||
if (item.isLarge) {
|
||||
LargeDetailsItem(item)
|
||||
} else {
|
||||
DetailsItem(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun LargeDetailsItem(item: SettingsItem) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.clickable(onClick = item.onClick)
|
||||
.padding(horizontal = TangemTheme.dimens.spacing20)
|
||||
.heightIn(min = TangemTheme.dimens.size84)
|
||||
.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing20),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
if (item.showProgress) {
|
||||
CircularProgressIndicator(
|
||||
modifier = Modifier.size(TangemTheme.dimens.size24),
|
||||
color = TangemTheme.colors.icon.informative,
|
||||
)
|
||||
} else {
|
||||
Icon(
|
||||
modifier = Modifier.size(TangemTheme.dimens.size24),
|
||||
painter = painterResource(id = item.iconResId),
|
||||
contentDescription = item.title.resolveReference(),
|
||||
tint = TangemColorPalette.Azure,
|
||||
)
|
||||
}
|
||||
Column(
|
||||
modifier = Modifier.heightIn(min = TangemTheme.dimens.size56),
|
||||
horizontalAlignment = Alignment.Start,
|
||||
verticalArrangement = Arrangement.spacedBy(
|
||||
space = TangemTheme.dimens.spacing4,
|
||||
alignment = Alignment.CenterVertically,
|
||||
),
|
||||
) {
|
||||
Text(
|
||||
text = item.title.resolveReference(),
|
||||
style = TangemTheme.typography.h3,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
)
|
||||
|
||||
if (item.subtitle != null) {
|
||||
Text(
|
||||
text = item.subtitle.resolveReference(),
|
||||
style = TangemTheme.typography.body1,
|
||||
color = TangemTheme.colors.text.secondary,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun DetailsItem(item: SettingsItem) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.clickable(enabled = !item.showProgress, onClick = item.onClick)
|
||||
.padding(horizontal = TangemTheme.dimens.spacing20)
|
||||
.heightIn(min = TangemTheme.dimens.size56)
|
||||
.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing20),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
if (item.showProgress) {
|
||||
CircularProgressIndicator(
|
||||
modifier = Modifier.size(TangemTheme.dimens.size24),
|
||||
color = TangemTheme.colors.icon.informative,
|
||||
)
|
||||
} else {
|
||||
Icon(
|
||||
modifier = Modifier.size(TangemTheme.dimens.size24),
|
||||
painter = painterResource(id = item.iconResId),
|
||||
contentDescription = item.title.resolveReference(),
|
||||
tint = TangemTheme.colors.icon.secondary,
|
||||
)
|
||||
}
|
||||
|
||||
Column(
|
||||
horizontalAlignment = Alignment.Start,
|
||||
verticalArrangement = Arrangement.SpaceAround,
|
||||
) {
|
||||
Text(
|
||||
text = item.title.resolveReference(),
|
||||
style = TangemTheme.typography.subtitle1,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
)
|
||||
|
||||
if (item.subtitle != null) {
|
||||
Text(
|
||||
text = item.subtitle.resolveReference(),
|
||||
style = TangemTheme.typography.body2,
|
||||
color = TangemTheme.colors.text.secondary,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TangemSocialAccounts(links: List<SocialNetworkLink>, onSocialNetworkClick: (SocialNetworkLink) -> Unit) {
|
||||
LazyRow(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
contentPadding = PaddingValues(horizontal = TangemTheme.dimens.spacing8),
|
||||
) {
|
||||
items(links) {
|
||||
val onClick = remember(it) {
|
||||
{ onSocialNetworkClick(it) }
|
||||
}
|
||||
|
||||
IconButton(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = TangemTheme.dimens.spacing4)
|
||||
.size(TangemTheme.dimens.size32),
|
||||
onClick = onClick,
|
||||
) {
|
||||
Icon(
|
||||
modifier = Modifier.size(TangemTheme.dimens.size24),
|
||||
painter = painterResource(id = it.network.iconRes),
|
||||
tint = TangemTheme.colors.icon.informative,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ShowSnackbarIfNeeded(snackbarHostState: SnackbarHostState, messageEvent: StateEvent<TextReference>) {
|
||||
var message: TextReference? by remember { mutableStateOf(value = null) }
|
||||
val resolvedMessage by rememberUpdatedState(newValue = message?.resolveReference())
|
||||
|
||||
LaunchedEffect(resolvedMessage) {
|
||||
resolvedMessage?.let {
|
||||
snackbarHostState.showSnackbar(it)
|
||||
}
|
||||
}
|
||||
|
||||
EventEffect(messageEvent) {
|
||||
message = it
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TangemAppVersion(appNameRes: Int, version: String, modifier: Modifier = Modifier) {
|
||||
Text(
|
||||
modifier = modifier.padding(horizontal = TangemTheme.dimens.spacing16),
|
||||
text = "${stringResource(id = appNameRes)} $version",
|
||||
style = TangemTheme.typography.caption2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
)
|
||||
}
|
||||
|
||||
// region Preview
|
||||
@Preview(showBackground = true, widthDp = 360, heightDp = 900)
|
||||
@Preview(showBackground = true, widthDp = 360, heightDp = 900, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun DetailsScreenPreview(@PreviewParameter(DetailsScreenStateProvider::class) param: DetailsScreenState) {
|
||||
TangemThemePreview {
|
||||
DetailsScreen(param, onBackClick = {})
|
||||
}
|
||||
}
|
||||
|
||||
private class DetailsScreenStateProvider : CollectionPreviewParameterProvider<DetailsScreenState>(
|
||||
collection = buildList {
|
||||
DetailsScreenState(
|
||||
elements = buildList {
|
||||
SettingsItem.WalletConnect({}).let(::add)
|
||||
SettingsItem.AddWallet(showProgress = false, {}).let(::add)
|
||||
SettingsItem.LinkMoreCards({}).let(::add)
|
||||
SettingsItem.CardSettings({}).let(::add)
|
||||
SettingsItem.AppSettings({}).let(::add)
|
||||
// removed chat in task [REDACTED_TASK_KEY]
|
||||
// SettingsItem.Chat({}).let(::add)
|
||||
SettingsItem.SendFeedback({}).let(::add)
|
||||
SettingsItem.ReferralProgram({}).let(::add)
|
||||
SettingsItem.TermsOfService({}).let(::add)
|
||||
}.toImmutableList(),
|
||||
tangemLinks = TangemSocialAccounts.accountsEn,
|
||||
tangemVersion = "Tangem 2.14.12 (343)",
|
||||
showSnackbar = consumedEvent(),
|
||||
onSocialNetworkClick = {},
|
||||
).let(::add)
|
||||
|
||||
DetailsScreenState(
|
||||
elements = buildList {
|
||||
SettingsItem.WalletConnect({}).let(::add)
|
||||
SettingsItem.AddWallet(showProgress = true, {}).let(::add)
|
||||
SettingsItem.CardSettings({}).let(::add)
|
||||
SettingsItem.AppSettings({}).let(::add)
|
||||
// removed chat in task [REDACTED_TASK_KEY]
|
||||
// SettingsItem.Chat({}).let(::add)
|
||||
SettingsItem.SendFeedback({}).let(::add)
|
||||
SettingsItem.TermsOfService({}).let(::add)
|
||||
}.toImmutableList(),
|
||||
tangemLinks = TangemSocialAccounts.accountsRu,
|
||||
tangemVersion = "Tangem 2.14.12 (343)",
|
||||
showSnackbar = consumedEvent(),
|
||||
onSocialNetworkClick = {},
|
||||
).let(::add)
|
||||
},
|
||||
)
|
||||
// endregion Preview
|
||||
|
|
@ -1,162 +0,0 @@
|
|||
package com.tangem.tap.features.details.ui.details
|
||||
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.tangem.core.ui.event.StateEvent
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.wallet.R
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
||||
@Immutable
|
||||
internal data class DetailsScreenState(
|
||||
val elements: ImmutableList<SettingsItem>,
|
||||
val tangemLinks: ImmutableList<SocialNetworkLink>,
|
||||
val tangemVersion: String,
|
||||
val showSnackbar: StateEvent<TextReference>,
|
||||
val onSocialNetworkClick: (SocialNetworkLink) -> Unit,
|
||||
) {
|
||||
val appNameRes: Int = R.string.tangem_app_name
|
||||
}
|
||||
|
||||
@Immutable
|
||||
internal sealed class SettingsItem(
|
||||
@DrawableRes val iconResId: Int,
|
||||
val title: TextReference,
|
||||
val subtitle: TextReference? = null,
|
||||
val isLarge: Boolean = false,
|
||||
) {
|
||||
|
||||
abstract val onClick: () -> Unit
|
||||
|
||||
open val showProgress: Boolean = false
|
||||
|
||||
data class WalletConnect(
|
||||
override val onClick: () -> Unit,
|
||||
) : SettingsItem(
|
||||
iconResId = R.drawable.ic_wallet_connect_24,
|
||||
title = resourceReference(R.string.wallet_connect_title),
|
||||
subtitle = resourceReference(R.string.wallet_connect_subtitle),
|
||||
isLarge = true,
|
||||
)
|
||||
|
||||
data class AddWallet(
|
||||
override val showProgress: Boolean,
|
||||
override val onClick: () -> Unit,
|
||||
) : SettingsItem(
|
||||
iconResId = R.drawable.ic_plus_24,
|
||||
title = resourceReference(R.string.user_wallet_list_add_button),
|
||||
)
|
||||
|
||||
data class ScanWallet(
|
||||
override val showProgress: Boolean,
|
||||
override val onClick: () -> Unit,
|
||||
) : SettingsItem(
|
||||
iconResId = R.drawable.ic_plus_24,
|
||||
title = resourceReference(R.string.scan_card_settings_button),
|
||||
)
|
||||
|
||||
data class LinkMoreCards(
|
||||
override val onClick: () -> Unit,
|
||||
) : SettingsItem(
|
||||
iconResId = R.drawable.ic_more_cards_24,
|
||||
title = resourceReference(R.string.details_row_title_create_backup),
|
||||
)
|
||||
|
||||
data class CardSettings(
|
||||
override val onClick: () -> Unit,
|
||||
) : SettingsItem(
|
||||
iconResId = R.drawable.ic_card_settings_24,
|
||||
title = resourceReference(R.string.card_settings_title),
|
||||
)
|
||||
|
||||
data class AppSettings(
|
||||
override val onClick: () -> Unit,
|
||||
) : SettingsItem(
|
||||
iconResId = R.drawable.ic_settings,
|
||||
title = resourceReference(R.string.app_settings_title),
|
||||
)
|
||||
|
||||
data class Chat(
|
||||
override val onClick: () -> Unit,
|
||||
) : SettingsItem(
|
||||
iconResId = R.drawable.ic_chat_24,
|
||||
title = resourceReference(R.string.details_chat),
|
||||
)
|
||||
|
||||
data class SendFeedback(
|
||||
override val onClick: () -> Unit,
|
||||
) : SettingsItem(
|
||||
iconResId = R.drawable.ic_comment_24,
|
||||
title = resourceReference(R.string.details_row_title_contact_to_support),
|
||||
)
|
||||
|
||||
data class ReferralProgram(
|
||||
override val onClick: () -> Unit,
|
||||
) : SettingsItem(
|
||||
iconResId = R.drawable.ic_add_friends_24,
|
||||
title = resourceReference(R.string.details_referral_title),
|
||||
)
|
||||
|
||||
data class TermsOfService(
|
||||
override val onClick: () -> Unit,
|
||||
) : SettingsItem(
|
||||
iconResId = R.drawable.ic_text_24,
|
||||
title = resourceReference(R.string.disclaimer_title),
|
||||
)
|
||||
|
||||
data class TesterMenu(
|
||||
override val onClick: () -> Unit,
|
||||
) : SettingsItem(
|
||||
iconResId = R.drawable.ic_alert_24,
|
||||
title = resourceReference(R.string.tester_menu),
|
||||
)
|
||||
}
|
||||
|
||||
@Immutable
|
||||
internal data class SocialNetworkLink(
|
||||
val network: SocialNetwork,
|
||||
val url: String,
|
||||
)
|
||||
|
||||
internal sealed class EventError {
|
||||
object Empty : EventError()
|
||||
}
|
||||
|
||||
sealed class SocialNetwork(val id: String, val iconRes: Int) {
|
||||
object Twitter : SocialNetwork("Twitter", R.drawable.ic_twitter_24)
|
||||
object Telegram : SocialNetwork("Telegram", R.drawable.ic_telegram_24)
|
||||
object Discord : SocialNetwork("Discord", R.drawable.ic_discord_24)
|
||||
object Reddit : SocialNetwork("Reddit", R.drawable.ic_reddit_24)
|
||||
object Instagram : SocialNetwork("Instagram", R.drawable.ic_instagram_24)
|
||||
object GitHub : SocialNetwork("GitHub", R.drawable.ic_github_24)
|
||||
object Facebook : SocialNetwork("Facebook", R.drawable.ic_facebook_24)
|
||||
object LinkedIn : SocialNetwork("LinkedIn", R.drawable.ic_linkedin_24)
|
||||
object YouTube : SocialNetwork("YouTube", R.drawable.ic_youtube_24)
|
||||
}
|
||||
|
||||
internal object TangemSocialAccounts {
|
||||
val accountsEn: ImmutableList<SocialNetworkLink> = persistentListOf(
|
||||
SocialNetworkLink(SocialNetwork.Twitter, "https://x.com/tangem"),
|
||||
SocialNetworkLink(SocialNetwork.Telegram, "https://t.me/tangem_chat"),
|
||||
SocialNetworkLink(SocialNetwork.Discord, "https://discord.gg/tangem"),
|
||||
SocialNetworkLink(SocialNetwork.Reddit, "https://www.reddit.com/r/Tangem/"),
|
||||
SocialNetworkLink(SocialNetwork.Instagram, "https://www.instagram.com/tangemwallet"),
|
||||
SocialNetworkLink(SocialNetwork.GitHub, "https://github.com/tangem"),
|
||||
SocialNetworkLink(SocialNetwork.Facebook, "https://www.facebook.com/tangemwallet"),
|
||||
SocialNetworkLink(SocialNetwork.LinkedIn, "https://www.linkedin.com/company/tangem"),
|
||||
SocialNetworkLink(SocialNetwork.YouTube, "https://youtube.com/@tangem_official"),
|
||||
)
|
||||
val accountsRu: ImmutableList<SocialNetworkLink> = persistentListOf(
|
||||
SocialNetworkLink(SocialNetwork.Twitter, "https://x.com/tangem"),
|
||||
SocialNetworkLink(SocialNetwork.Telegram, "https://t.me/tangem_chat_ru"),
|
||||
SocialNetworkLink(SocialNetwork.Discord, "https://discord.gg/tangem"),
|
||||
SocialNetworkLink(SocialNetwork.Reddit, "https://www.reddit.com/r/Tangem/"),
|
||||
SocialNetworkLink(SocialNetwork.Instagram, "https://www.instagram.com/tangemwallet"),
|
||||
SocialNetworkLink(SocialNetwork.GitHub, "https://github.com/tangem"),
|
||||
SocialNetworkLink(SocialNetwork.Facebook, "https://www.facebook.com/tangemwallet"),
|
||||
SocialNetworkLink(SocialNetwork.LinkedIn, "https://www.linkedin.com/company/tangem"),
|
||||
SocialNetworkLink(SocialNetwork.YouTube, "https://youtube.com/@tangem_official"),
|
||||
)
|
||||
}
|
||||
|
|
@ -1,215 +0,0 @@
|
|||
package com.tangem.tap.features.details.ui.details
|
||||
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import com.tangem.common.extensions.guard
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.core.analytics.models.AnalyticsParam
|
||||
import com.tangem.core.analytics.models.Basic
|
||||
|
||||
import com.tangem.core.ui.event.StateEvent
|
||||
import com.tangem.core.ui.event.consumedEvent
|
||||
import com.tangem.core.ui.event.triggeredEvent
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.domain.common.util.cardTypesResolver
|
||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||
import com.tangem.domain.wallets.repository.WalletsRepository
|
||||
import com.tangem.tap.common.analytics.events.Settings
|
||||
import com.tangem.tap.common.extensions.*
|
||||
import com.tangem.tap.common.feedback.FeedbackEmail
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
import com.tangem.tap.features.details.redux.DetailsAction
|
||||
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.RUSSIA_COUNTRY_CODE
|
||||
import com.tangem.tap.scope
|
||||
import com.tangem.wallet.BuildConfig
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import org.rekotlin.Store
|
||||
import timber.log.Timber
|
||||
|
||||
internal class DetailsViewModel(
|
||||
private val store: Store<AppState>,
|
||||
private val walletsRepository: WalletsRepository,
|
||||
private val userWalletsListManager: UserWalletsListManager,
|
||||
) {
|
||||
|
||||
var detailsScreenState: MutableState<DetailsScreenState> = mutableStateOf(updateState(store.state.detailsState))
|
||||
private set
|
||||
|
||||
init {
|
||||
bootstrapScreenState()
|
||||
}
|
||||
|
||||
fun updateState(state: DetailsState): DetailsScreenState {
|
||||
return DetailsScreenState(
|
||||
elements = createSettingsItems(state),
|
||||
tangemLinks = getSocialLinks(),
|
||||
tangemVersion = getTangemAppVersion(),
|
||||
showSnackbar = triggerErrorSnackbarIfNeeded(state.error),
|
||||
onSocialNetworkClick = ::handleSocialNetworkClick,
|
||||
)
|
||||
}
|
||||
|
||||
private fun createSettingsItems(state: DetailsState): ImmutableList<SettingsItem> {
|
||||
val scanResponse = state.scanResponse ?: return persistentListOf()
|
||||
val cardTypesResolver = scanResponse.cardTypesResolver
|
||||
|
||||
return buildList {
|
||||
SettingsItem.WalletConnect(::navigateToWalletConnect)
|
||||
.takeIf { cardTypesResolver.isMultiwalletAllowed() }
|
||||
?.let(::add)
|
||||
|
||||
SettingsItem.AddWallet(showProgress = state.isScanningInProgress, ::scanAndSaveUserWallet)
|
||||
.takeIf { state.appSettingsState.saveWallets }
|
||||
?.let(::add)
|
||||
|
||||
SettingsItem.ScanWallet(showProgress = state.isScanningInProgress, ::scanAndSaveUserWallet)
|
||||
.takeUnless { state.appSettingsState.saveWallets }
|
||||
?.let(::add)
|
||||
|
||||
SettingsItem.LinkMoreCards(::linkMoreCards)
|
||||
.takeIf { state.createBackupAllowed }
|
||||
?.let(::add)
|
||||
|
||||
SettingsItem.CardSettings(::navigateToCardSettings)
|
||||
.let(::add)
|
||||
|
||||
SettingsItem.AppSettings(::navigateToAppSettings)
|
||||
.let(::add)
|
||||
|
||||
SettingsItem.SendFeedback(::sendFeedback)
|
||||
.let(::add)
|
||||
|
||||
SettingsItem.ReferralProgram(::navigateToReferralProgram)
|
||||
.takeIf { cardTypesResolver.isTangemWallet() }
|
||||
?.let(::add)
|
||||
|
||||
SettingsItem.TermsOfService(::navigateToToS)
|
||||
.let(::add)
|
||||
|
||||
SettingsItem.TesterMenu(::navigateToTesterMenu)
|
||||
.takeIf { BuildConfig.TESTER_MENU_ENABLED }
|
||||
?.let(::add)
|
||||
}.toImmutableList()
|
||||
}
|
||||
|
||||
private fun triggerErrorSnackbarIfNeeded(text: TextReference?): StateEvent<TextReference> {
|
||||
return if (text == null) {
|
||||
consumedEvent()
|
||||
} else {
|
||||
triggeredEvent(text) {
|
||||
store.dispatch(DetailsAction.DismissError)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getTangemAppVersion(): String {
|
||||
val versionCode: Int = BuildConfig.VERSION_CODE
|
||||
val versionName: String = BuildConfig.VERSION_NAME
|
||||
return "$versionName ($versionCode)"
|
||||
}
|
||||
|
||||
private fun navigateToTesterMenu() {
|
||||
store.dispatchNavigationAction {
|
||||
push(AppRoute.TesterMenu)
|
||||
}
|
||||
}
|
||||
|
||||
private fun navigateToToS() {
|
||||
store.dispatchOnMain(DisclaimerAction.Show(DisclaimerSource.Details))
|
||||
}
|
||||
|
||||
private fun navigateToReferralProgram() {
|
||||
val userWallet = userWalletsListManager.selectedUserWalletSync
|
||||
?: error("Selected wallet must be not null")
|
||||
|
||||
store.dispatchNavigationAction { push(AppRoute.ReferralProgram(userWallet.walletId)) }
|
||||
}
|
||||
|
||||
private fun sendFeedback() {
|
||||
Analytics.send(Basic.ButtonSupport(AnalyticsParam.ScreensSources.Settings))
|
||||
store.dispatchOnMain(
|
||||
GlobalAction.SendEmail(
|
||||
feedbackData = FeedbackEmail(),
|
||||
scanResponse = userWalletsListManager.selectedUserWalletSync?.scanResponse
|
||||
?: error("ScanResponse must be not null"),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private fun navigateToAppSettings() {
|
||||
Analytics.send(Settings.ButtonAppSettings())
|
||||
store.dispatchNavigationAction { push(AppRoute.AppSettings) }
|
||||
}
|
||||
|
||||
private fun navigateToCardSettings() {
|
||||
val userWalletId = userWalletsListManager.selectedUserWalletSync?.walletId
|
||||
?: error("UserWalletId must be not null")
|
||||
Analytics.send(Settings.ButtonCardSettings())
|
||||
store.dispatchNavigationAction { push(AppRoute.CardSettings(userWalletId)) }
|
||||
}
|
||||
|
||||
private fun linkMoreCards() {
|
||||
Analytics.send(Settings.ButtonCreateBackup())
|
||||
|
||||
val selectedUserWallet = userWalletsListManager.selectedUserWalletSync.guard {
|
||||
Timber.e("Unable to backup wallet, no user wallet selected")
|
||||
return
|
||||
}
|
||||
val scanResponse = selectedUserWallet.scanResponse
|
||||
Analytics.addContext(scanResponse)
|
||||
store.dispatch(GlobalAction.Onboarding.Start(scanResponse, canSkipBackup = false))
|
||||
store.dispatchNavigationAction { push(AppRoute.OnboardingWallet()) }
|
||||
}
|
||||
|
||||
private fun scanAndSaveUserWallet() {
|
||||
Analytics.send(Settings.ScanNewCard)
|
||||
store.dispatchOnMain(DetailsAction.ScanAndSaveUserWallet)
|
||||
}
|
||||
|
||||
private fun navigateToWalletConnect() {
|
||||
Analytics.send(Settings.ButtonWalletConnect())
|
||||
store.dispatchNavigationAction { push(AppRoute.WalletConnectSessions) }
|
||||
}
|
||||
|
||||
private fun handleSocialNetworkClick(link: SocialNetworkLink) {
|
||||
Analytics.send(Settings.ButtonSocialNetwork(link.network))
|
||||
store.dispatchOpenUrl(link.url)
|
||||
}
|
||||
|
||||
private fun getSocialLinks(): ImmutableList<SocialNetworkLink> {
|
||||
val locale = LocaleRegionProvider().getRegion()
|
||||
return if (locale.lowercase() == RUSSIA_COUNTRY_CODE) {
|
||||
TangemSocialAccounts.accountsRu
|
||||
} else {
|
||||
TangemSocialAccounts.accountsEn
|
||||
}
|
||||
}
|
||||
|
||||
private fun bootstrapScreenState() {
|
||||
userWalletsListManager.selectedUserWallet
|
||||
.distinctUntilChanged()
|
||||
.onEach { selectedUserWallet ->
|
||||
store.dispatchWithMain(
|
||||
DetailsAction.PrepareScreen(
|
||||
scanResponse = selectedUserWallet.scanResponse,
|
||||
shouldSaveUserWallets = walletsRepository.shouldSaveUserWalletsSync(),
|
||||
),
|
||||
)
|
||||
}
|
||||
.flowOn(Dispatchers.IO)
|
||||
.launchIn(scope)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
package com.tangem.tap.features.details.ui.resetcard
|
||||
|
||||
internal sealed class ResetCardDialog {
|
||||
data object StartResetDialog : ResetCardDialog()
|
||||
data object ContinueResetDialog : ResetCardDialog()
|
||||
data object InterruptedResetDialog : ResetCardDialog()
|
||||
data object CompletedResetDialog : ResetCardDialog()
|
||||
}
|
||||
|
|
@ -22,7 +22,6 @@ import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
|
|||
import com.tangem.tap.common.analytics.events.Settings
|
||||
import com.tangem.tap.common.extensions.dispatchNavigationAction
|
||||
import com.tangem.tap.common.extensions.onUserWalletSelected
|
||||
import com.tangem.tap.features.details.redux.ResetCardDialog
|
||||
import com.tangem.tap.features.details.ui.cardsettings.domain.CardSettingsInteractor
|
||||
import com.tangem.tap.features.details.ui.common.utils.getResetToFactoryDescription
|
||||
import com.tangem.tap.store
|
||||
|
|
|
|||
|
|
@ -24,12 +24,6 @@ abstract class BaseDisclaimer(
|
|||
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) {
|
||||
override fun getUri(): Uri = Uri.parse("$baseUrl/tangem_tos.html")
|
||||
}
|
||||
|
|
@ -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()
|
||||
}
|
||||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
package com.tangem.tap.features.disclaimer.redux
|
||||
|
||||
enum class DisclaimerSource {
|
||||
Home, Details
|
||||
}
|
||||
|
|
@ -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,
|
||||
)
|
||||
|
|
@ -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")
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
@ -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> 1. Tangem application (Software)</p>
|
||||
<p> The Software is intended for usage only with Tangem hardware wallets (Cards) via NFC interface. The
|
||||
Software DOES NOT:</p>
|
||||
<p> a) Generate, store, transmit, or have access to private (secret) cryptographic keys to blockchain
|
||||
wallets holding digital assets, including crypto-currency.</p>
|
||||
<p> 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> c) Provide exchange, trading, investment services on behalf of Tangem AG.</p>
|
||||
<p> 2. Risks related to the use of Software</p>
|
||||
<p> 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> 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> 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> 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> d) Security problems experienced by the user of any cryptocurrency-related software or service, e.g.,
|
||||
unauthorized access to users' wallets and/or accounts.</p>
|
||||
<p> 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> 3. Trading and Investment risks</p>
|
||||
<p> 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> 4. Electronic Trading Risks</p>
|
||||
<p> 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> 5. Compliance with tax obligations </p>
|
||||
<p> 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. </p>
|
||||
<p> 6. No warranties </p>
|
||||
<p> The Software is provided on an "as is" basis without any warranties of any kind regarding the
|
||||
Software and/or any content, data, materials and/or services provided on the Software.
|
||||
</p>
|
||||
<p> 7. Limitation of liability</p>
|
||||
<p> 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> 8. Last amendment</p>
|
||||
<p> This disclaimer was amended for the last time on October 1st, 2020.</p></body>
|
||||
</html>
|
||||
""".trimIndent()
|
||||
|
|
@ -58,7 +58,9 @@ internal fun StoriesScreen(
|
|||
}
|
||||
|
||||
StoriesScreenContent(
|
||||
modifier = Modifier.fillMaxSize().testTag(TestTags.STORIES_SCREEN),
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.testTag(TestTags.STORIES_SCREEN),
|
||||
config = StoriesScreenContentConfig(
|
||||
storiesSize = state.stories.lastIndex,
|
||||
currentStoryIndex = currentStoryIndex,
|
||||
|
|
@ -157,7 +159,7 @@ private fun StoriesScreenContent(config: StoriesScreenContentConfig, modifier: M
|
|||
duration = currentStoryDuration,
|
||||
)
|
||||
Stories.RevolutionaryWallet -> StoriesRevolutionaryWallet()
|
||||
is Stories.UltraSecureBackup -> StoriesUltraSecureBackup(
|
||||
Stories.UltraSecureBackup -> StoriesUltraSecureBackup(
|
||||
isPaused = isPaused,
|
||||
stepDuration = currentStoryDuration,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,12 @@
|
|||
package com.tangem.tap.features.home.featuretoggles
|
||||
|
||||
import com.tangem.core.featuretoggle.manager.FeatureTogglesManager
|
||||
import javax.inject.Inject
|
||||
|
||||
class HomeFeatureToggles @Inject constructor(
|
||||
private val featureTogglesManager: FeatureTogglesManager,
|
||||
) {
|
||||
|
||||
val isMigrateUserCountryCodeEnabled: Boolean
|
||||
get() = featureTogglesManager.isFeatureEnabled(name = "MIGRATE_USER_COUNTRY_CODE_ENABLED")
|
||||
}
|
||||
|
|
@ -15,6 +15,4 @@ sealed class HomeAction : Action {
|
|||
data class ReadCard(val scope: CoroutineScope) : HomeAction()
|
||||
|
||||
data class ScanInProgress(val scanInProgress: Boolean) : HomeAction()
|
||||
|
||||
data class UpdateCountryCode(val userCountryCode: String) : HomeAction()
|
||||
}
|
||||
|
|
@ -10,16 +10,10 @@ object HomeReducer {
|
|||
private fun internalReduce(action: Action, appState: AppState): HomeState {
|
||||
if (action !is HomeAction) return appState.homeState
|
||||
|
||||
var state = appState.homeState
|
||||
when (action) {
|
||||
return when (action) {
|
||||
is HomeAction.ScanInProgress -> {
|
||||
state = state.copy(scanInProgress = action.scanInProgress)
|
||||
appState.homeState.copy(scanInProgress = action.scanInProgress)
|
||||
}
|
||||
is HomeAction.UpdateCountryCode -> {
|
||||
state.onCountryCodeUpdate(state, action.userCountryCode)
|
||||
}
|
||||
else -> {}
|
||||
else -> appState.homeState
|
||||
}
|
||||
|
||||
return state
|
||||
}
|
||||
|
|
@ -1,56 +1,24 @@
|
|||
package com.tangem.tap.features.home.redux
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import org.rekotlin.StateType
|
||||
import java.util.Locale
|
||||
|
||||
@Immutable
|
||||
data class HomeState(
|
||||
val scanInProgress: Boolean = false,
|
||||
val stories: List<Stories> = initDefaultStories(),
|
||||
val stories: ImmutableList<Stories> = Stories.entries.toImmutableList(),
|
||||
) : StateType {
|
||||
|
||||
val firstStory: Stories
|
||||
get() = stories[0]
|
||||
val firstStory: Stories get() = stories[0]
|
||||
|
||||
fun stepOf(story: Stories): Int = stories.indexOf(story)
|
||||
|
||||
fun onCountryCodeUpdate(homeState: HomeState, countryCode: String) {
|
||||
val isNewWalletAvailable = !(countryCode == RUSSIA_COUNTRY_CODE || countryCode == BELARUS_COUNTRY_CODE)
|
||||
homeState.stories.forEach {
|
||||
it.isNewWalletAvailable.value = isNewWalletAvailable
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val RUSSIA_COUNTRY_CODE = "ru"
|
||||
private const val BELARUS_COUNTRY_CODE = "by"
|
||||
fun initDefaultStories(): List<Stories> = listOf(
|
||||
Stories.TangemIntro,
|
||||
Stories.RevolutionaryWallet,
|
||||
Stories.UltraSecureBackup,
|
||||
Stories.Currencies,
|
||||
Stories.Web3,
|
||||
Stories.WalletForEveryone,
|
||||
)
|
||||
|
||||
fun isNewWalletAvailableInit(): Boolean {
|
||||
val locale = Locale.getDefault().language
|
||||
return !(locale == RUSSIA_COUNTRY_CODE || locale == BELARUS_COUNTRY_CODE)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sealed class Stories(
|
||||
val duration: Int,
|
||||
val isNewWalletAvailable: MutableState<Boolean> = mutableStateOf(HomeState.isNewWalletAvailableInit()),
|
||||
) {
|
||||
object TangemIntro : Stories(duration = 6000)
|
||||
object RevolutionaryWallet : Stories(duration = 6000)
|
||||
object UltraSecureBackup : Stories(duration = 6000)
|
||||
object Currencies : Stories(duration = 6000)
|
||||
object Web3 : Stories(duration = 6000)
|
||||
object WalletForEveryone : Stories(duration = 6000)
|
||||
enum class Stories(val duration: Int = 6000) {
|
||||
TangemIntro,
|
||||
RevolutionaryWallet,
|
||||
UltraSecureBackup,
|
||||
Currencies,
|
||||
Web3,
|
||||
WalletForEveryone,
|
||||
}
|
||||
|
|
@ -16,11 +16,13 @@ import com.tangem.domain.balancehiding.UpdateBalanceHidingSettingsUseCase
|
|||
import com.tangem.domain.feedback.FeedbackManagerFeatureToggles
|
||||
import com.tangem.domain.settings.DeleteDeprecatedLogsUseCase
|
||||
import com.tangem.domain.settings.IncrementAppLaunchCounterUseCase
|
||||
import com.tangem.domain.settings.usercountry.FetchUserCountryUseCase
|
||||
import com.tangem.domain.staking.FetchStakingTokensUseCase
|
||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||
import com.tangem.features.staking.api.featuretoggles.StakingFeatureToggles
|
||||
import com.tangem.tap.common.extensions.setContext
|
||||
import com.tangem.tap.features.home.featuretoggles.HomeFeatureToggles
|
||||
import com.tangem.tap.features.main.model.MainScreenState
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
|
|
@ -47,6 +49,8 @@ internal class MainViewModel @Inject constructor(
|
|||
stakingFeatureToggles: StakingFeatureToggles,
|
||||
private val fetchStakingTokensUseCase: FetchStakingTokensUseCase,
|
||||
private val apiConfigsManager: ApiConfigsManager,
|
||||
private val homeFeatureToggles: HomeFeatureToggles,
|
||||
private val fetchUserCountryUseCase: FetchUserCountryUseCase,
|
||||
getBalanceHidingSettingsUseCase: GetBalanceHidingSettingsUseCase,
|
||||
) : ViewModel(), MainIntents {
|
||||
|
||||
|
|
@ -67,6 +71,14 @@ internal class MainViewModel @Inject constructor(
|
|||
|
||||
viewModelScope.launch(dispatchers.main) { incrementAppLaunchCounterUseCase() }
|
||||
|
||||
if (homeFeatureToggles.isMigrateUserCountryCodeEnabled) {
|
||||
viewModelScope.launch {
|
||||
fetchUserCountryUseCase().onLeft {
|
||||
Timber.e("Unable to fetch the user country code $it")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateAppCurrencies()
|
||||
observeFlips()
|
||||
displayBalancesHidingStatusToast()
|
||||
|
|
|
|||
|
|
@ -1,22 +1,31 @@
|
|||
package com.tangem.tap.features.onboarding
|
||||
|
||||
import com.tangem.blockchain.common.WalletManager
|
||||
import com.tangem.common.doOnFailure
|
||||
import com.tangem.common.doOnSuccess
|
||||
import com.tangem.common.extensions.guard
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.core.analytics.models.Basic
|
||||
import com.tangem.data.common.currency.CryptoCurrencyFactory
|
||||
|
||||
import com.tangem.domain.common.util.cardTypesResolver
|
||||
import com.tangem.domain.common.util.derivationStyleProvider
|
||||
import com.tangem.domain.common.util.twinsIsTwinned
|
||||
import com.tangem.domain.models.scan.CardDTO
|
||||
import com.tangem.domain.models.scan.ProductType
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.domain.settings.usercountry.models.UserCountry
|
||||
import com.tangem.domain.wallets.builder.UserWalletBuilder
|
||||
import com.tangem.domain.wallets.builder.UserWalletIdBuilder
|
||||
import com.tangem.tap.common.analytics.converters.ParamCardCurrencyConverter
|
||||
import com.tangem.tap.common.analytics.events.AnalyticsParam
|
||||
import com.tangem.tap.common.analytics.events.Onboarding
|
||||
import com.tangem.tap.common.extensions.*
|
||||
import com.tangem.tap.common.redux.AppDialog
|
||||
import com.tangem.tap.common.redux.global.GlobalState
|
||||
import com.tangem.tap.features.demo.DemoHelper
|
||||
import com.tangem.tap.features.home.RUSSIA_COUNTRY_CODE
|
||||
import com.tangem.tap.features.saveWallet.redux.SaveWalletAction
|
||||
import com.tangem.tap.mainScope
|
||||
import com.tangem.tap.proxy.redux.DaggerGraphState
|
||||
|
|
@ -138,6 +147,39 @@ object OnboardingHelper {
|
|||
}
|
||||
}
|
||||
|
||||
fun handleTopUpAction(walletManager: WalletManager, scanResponse: ScanResponse, globalState: GlobalState) {
|
||||
val blockchain = walletManager.wallet.blockchain
|
||||
val cryptoCurrency = CryptoCurrencyFactory().createCoin(
|
||||
blockchain = blockchain,
|
||||
extraDerivationPath = null,
|
||||
derivationStyleProvider = scanResponse.derivationStyleProvider,
|
||||
) ?: return
|
||||
|
||||
val topUpUrl = walletManager.getTopUpUrl(cryptoCurrency) ?: return
|
||||
|
||||
val currencyType = AnalyticsParam.CurrencyType.Blockchain(blockchain)
|
||||
Analytics.send(Onboarding.Topup.ButtonBuyCrypto(currencyType))
|
||||
|
||||
scope.launch {
|
||||
val homeFeatureToggles = store.inject(DaggerGraphState::homeFeatureToggles)
|
||||
|
||||
val isRussia = if (homeFeatureToggles.isMigrateUserCountryCodeEnabled) {
|
||||
val getUserCountryCodeUseCase = store.inject(DaggerGraphState::getUserCountryUseCase)
|
||||
|
||||
getUserCountryCodeUseCase().isRight { it is UserCountry.Russia }
|
||||
} else {
|
||||
globalState.userCountryCode == RUSSIA_COUNTRY_CODE
|
||||
}
|
||||
|
||||
if (isRussia) {
|
||||
val dialogData = AppDialog.RussianCardholdersWarningDialog.Data(topUpUrl)
|
||||
store.dispatchDialogShow(AppDialog.RussianCardholdersWarningDialog(dialogData))
|
||||
} else {
|
||||
store.dispatchOpenUrl(topUpUrl)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun proceedWithScanResponse(
|
||||
scanResponse: ScanResponse,
|
||||
backupCardsIds: List<String>?,
|
||||
|
|
|
|||
|
|
@ -4,12 +4,8 @@ import com.tangem.common.CompletionResult
|
|||
import com.tangem.common.extensions.guard
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.core.analytics.Analytics
|
||||
|
||||
import com.tangem.data.common.currency.CryptoCurrencyFactory
|
||||
import com.tangem.domain.common.extensions.makePrimaryWalletManager
|
||||
import com.tangem.domain.common.extensions.withMainContext
|
||||
import com.tangem.domain.common.util.derivationStyleProvider
|
||||
import com.tangem.tap.common.analytics.events.AnalyticsParam
|
||||
import com.tangem.tap.common.analytics.events.Onboarding
|
||||
import com.tangem.tap.common.entities.ProgressState
|
||||
import com.tangem.tap.common.extensions.*
|
||||
|
|
@ -20,7 +16,6 @@ import com.tangem.tap.common.redux.global.GlobalAction
|
|||
import com.tangem.tap.domain.TapError
|
||||
import com.tangem.tap.domain.model.Currency
|
||||
import com.tangem.tap.features.demo.DemoHelper
|
||||
import com.tangem.tap.features.home.RUSSIA_COUNTRY_CODE
|
||||
import com.tangem.tap.features.onboarding.OnboardingDialog
|
||||
import com.tangem.tap.features.onboarding.OnboardingHelper
|
||||
import com.tangem.tap.mainScope
|
||||
|
|
@ -178,23 +173,11 @@ private fun handleNoteAction(appState: () -> AppState?, action: Action, dispatch
|
|||
return
|
||||
}
|
||||
|
||||
val blockchain = walletManager.wallet.blockchain
|
||||
val cryptoCurrency = CryptoCurrencyFactory().createCoin(
|
||||
blockchain,
|
||||
null,
|
||||
scanResponse.derivationStyleProvider,
|
||||
) ?: return
|
||||
val topUpUrl = walletManager.getTopUpUrl(cryptoCurrency) ?: return
|
||||
|
||||
val currencyType = AnalyticsParam.CurrencyType.Blockchain(blockchain)
|
||||
Analytics.send(Onboarding.Topup.ButtonBuyCrypto(currencyType))
|
||||
|
||||
if (globalState.userCountryCode == RUSSIA_COUNTRY_CODE) {
|
||||
val dialogData = AppDialog.RussianCardholdersWarningDialog.Data(topUpUrl)
|
||||
store.dispatchDialogShow(AppDialog.RussianCardholdersWarningDialog(dialogData))
|
||||
} else {
|
||||
store.dispatchOpenUrl(topUpUrl)
|
||||
}
|
||||
OnboardingHelper.handleTopUpAction(
|
||||
walletManager = walletManager,
|
||||
scanResponse = scanResponse,
|
||||
globalState = globalState,
|
||||
)
|
||||
}
|
||||
is OnboardingNoteAction.Done -> {
|
||||
store.dispatch(GlobalAction.Onboarding.Stop)
|
||||
|
|
|
|||
|
|
@ -6,16 +6,12 @@ import com.tangem.common.extensions.guard
|
|||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.common.routing.utils.popTo
|
||||
import com.tangem.core.analytics.Analytics
|
||||
|
||||
import com.tangem.data.common.currency.CryptoCurrencyFactory
|
||||
import com.tangem.domain.common.extensions.makePrimaryWalletManager
|
||||
import com.tangem.domain.common.extensions.withMainContext
|
||||
import com.tangem.domain.common.util.derivationStyleProvider
|
||||
import com.tangem.domain.common.util.twinsIsTwinned
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.domain.wallets.builder.UserWalletIdBuilder
|
||||
import com.tangem.domain.wallets.legacy.asLockable
|
||||
import com.tangem.tap.common.analytics.events.AnalyticsParam
|
||||
import com.tangem.tap.common.analytics.events.Onboarding
|
||||
import com.tangem.tap.common.entities.ProgressState
|
||||
import com.tangem.tap.common.extensions.*
|
||||
|
|
@ -26,7 +22,6 @@ import com.tangem.tap.common.redux.global.GlobalAction
|
|||
import com.tangem.tap.domain.TapError
|
||||
import com.tangem.tap.domain.model.Currency
|
||||
import com.tangem.tap.domain.twins.TwinCardsManager
|
||||
import com.tangem.tap.features.home.RUSSIA_COUNTRY_CODE
|
||||
import com.tangem.tap.features.onboarding.OnboardingDialog
|
||||
import com.tangem.tap.features.onboarding.OnboardingHelper
|
||||
import com.tangem.tap.mainScope
|
||||
|
|
@ -301,24 +296,11 @@ private fun handle(action: Action, dispatch: DispatchFunction) {
|
|||
return
|
||||
}
|
||||
|
||||
val scanResponse = onboardingManager?.scanResponse ?: return
|
||||
val blockchain = walletManager.wallet.blockchain
|
||||
val cryptoCurrency = CryptoCurrencyFactory().createCoin(
|
||||
blockchain,
|
||||
null,
|
||||
scanResponse.derivationStyleProvider,
|
||||
) ?: return
|
||||
val topUpUrl = walletManager.getTopUpUrl(cryptoCurrency) ?: return
|
||||
|
||||
val currencyType = AnalyticsParam.CurrencyType.Blockchain(blockchain)
|
||||
Analytics.send(Onboarding.Topup.ButtonBuyCrypto(currencyType))
|
||||
|
||||
if (globalState.userCountryCode == RUSSIA_COUNTRY_CODE) {
|
||||
val dialogData = AppDialog.RussianCardholdersWarningDialog.Data(topUpUrl)
|
||||
store.dispatchDialogShow(AppDialog.RussianCardholdersWarningDialog(dialogData))
|
||||
} else {
|
||||
store.dispatchOpenUrl(topUpUrl)
|
||||
}
|
||||
OnboardingHelper.handleTopUpAction(
|
||||
walletManager = walletManager,
|
||||
scanResponse = onboardingManager?.scanResponse ?: return,
|
||||
globalState = globalState,
|
||||
)
|
||||
}
|
||||
TwinCardsAction.Done -> {
|
||||
val scanResponse = getScanResponse()
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import com.tangem.blockchain.common.Blockchain
|
|||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.domain.settings.usercountry.models.UserCountry
|
||||
import com.tangem.domain.tokens.legacy.TradeCryptoAction
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.tokens.model.NetworkAddress
|
||||
|
|
@ -70,16 +71,26 @@ object TradeCryptoMiddleware {
|
|||
isDarkTheme = MutableAppThemeModeHolder.isDarkThemeActive,
|
||||
)
|
||||
|
||||
if (action.checkUserLocation && state()?.globalState?.userCountryCode == RUSSIA_COUNTRY_CODE) {
|
||||
val dialogData = topUrl?.let {
|
||||
AppDialog.RussianCardholdersWarningDialog.Data(topUpUrl = it)
|
||||
}
|
||||
store.dispatchDialogShow(AppDialog.RussianCardholdersWarningDialog(data = dialogData))
|
||||
return
|
||||
}
|
||||
scope.launch {
|
||||
val homeFeatureToggles = store.inject(DaggerGraphState::homeFeatureToggles)
|
||||
|
||||
if (currency is CryptoCurrency.Token && currency.network.isTestnet) {
|
||||
scope.launch {
|
||||
val isRussia = if (homeFeatureToggles.isMigrateUserCountryCodeEnabled) {
|
||||
val getUserCountryCodeUseCase = store.inject(DaggerGraphState::getUserCountryUseCase)
|
||||
|
||||
getUserCountryCodeUseCase().isRight { it is UserCountry.Russia }
|
||||
} else {
|
||||
state()?.globalState?.userCountryCode == RUSSIA_COUNTRY_CODE
|
||||
}
|
||||
|
||||
if (action.checkUserLocation && isRussia) {
|
||||
val dialogData = topUrl?.let {
|
||||
AppDialog.RussianCardholdersWarningDialog.Data(topUpUrl = it)
|
||||
}
|
||||
store.dispatchDialogShow(AppDialog.RussianCardholdersWarningDialog(data = dialogData))
|
||||
return@launch
|
||||
}
|
||||
|
||||
if (currency is CryptoCurrency.Token && currency.network.isTestnet) {
|
||||
val walletManager = store.inject(DaggerGraphState::walletManagersFacade)
|
||||
.getOrCreateWalletManager(
|
||||
userWalletId = action.userWallet.walletId,
|
||||
|
|
@ -97,13 +108,13 @@ object TradeCryptoMiddleware {
|
|||
walletManager = walletManager,
|
||||
destinationAddress = currency.contractAddress,
|
||||
)
|
||||
return@launch
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
topUrl?.let {
|
||||
store.dispatchOpenUrl(it)
|
||||
Analytics.send(Token.Topup.ScreenOpened())
|
||||
topUrl?.let {
|
||||
store.dispatchOpenUrl(it)
|
||||
Analytics.send(Token.Topup.ScreenOpened())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import com.tangem.domain.feedback.SaveBlockchainErrorUseCase
|
|||
import com.tangem.domain.onboarding.SaveTwinsOnboardingShownUseCase
|
||||
import com.tangem.domain.onboarding.WasTwinsOnboardingShownUseCase
|
||||
import com.tangem.domain.settings.repositories.SettingsRepository
|
||||
import com.tangem.domain.settings.usercountry.GetUserCountryUseCase
|
||||
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||
import com.tangem.domain.tokens.repository.NetworksRepository
|
||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||
|
|
@ -29,8 +30,6 @@ import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
|||
import com.tangem.domain.wallets.repository.WalletsRepository
|
||||
import com.tangem.domain.wallets.usecase.GenerateWalletNameUseCase
|
||||
import com.tangem.feature.qrscanning.QrScanningRouter
|
||||
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.send.api.navigation.SendRouter
|
||||
import com.tangem.features.staking.api.navigation.StakingRouter
|
||||
|
|
@ -41,6 +40,7 @@ import com.tangem.tap.domain.walletconnect2.domain.LegacyWalletConnectRepository
|
|||
import com.tangem.tap.domain.walletconnect2.domain.WalletConnectInteractor
|
||||
import com.tangem.tap.domain.walletconnect2.domain.WalletConnectSessionsRepository
|
||||
import com.tangem.tap.features.customtoken.api.featuretoggles.CustomTokenFeatureToggles
|
||||
import com.tangem.tap.features.home.featuretoggles.HomeFeatureToggles
|
||||
import com.tangem.tap.proxy.AppStateHolder
|
||||
import org.rekotlin.StateType
|
||||
|
||||
|
|
@ -80,11 +80,11 @@ data class DaggerGraphState(
|
|||
val getFeedbackEmailUseCase: GetFeedbackEmailUseCase? = null,
|
||||
val getCardInfoUseCase: GetCardInfoUseCase? = null,
|
||||
val assetLoader: AssetLoader? = null,
|
||||
val detailsFeatureToggles: DetailsFeatureToggles? = null,
|
||||
val stakingRouter: StakingRouter? = null,
|
||||
val urlOpener: UrlOpener? = null,
|
||||
val shareManager: ShareManager? = null,
|
||||
val appRouter: AppRouter? = null,
|
||||
val pushNotificationsFeatureToggles: PushNotificationsFeatureToggles? = null,
|
||||
val pushNotificationsRouter: PushNotificationsRouter? = null,
|
||||
val homeFeatureToggles: HomeFeatureToggles? = null,
|
||||
val getUserCountryUseCase: GetUserCountryUseCase? = null,
|
||||
) : StateType
|
||||
|
|
@ -6,14 +6,12 @@ import com.tangem.feature.qrscanning.QrScanningRouter
|
|||
import com.tangem.feature.referral.ReferralFragment
|
||||
import com.tangem.feature.swap.presentation.SwapFragment
|
||||
import com.tangem.feature.walletsettings.component.WalletSettingsComponent
|
||||
import com.tangem.features.details.DetailsFeatureToggles
|
||||
import com.tangem.features.details.component.DetailsComponent
|
||||
import com.tangem.features.disclaimer.api.components.DisclaimerComponent
|
||||
import com.tangem.features.managetokens.ManageTokensToggles
|
||||
import com.tangem.features.managetokens.component.ManageTokensComponent
|
||||
import com.tangem.features.managetokens.component.ManageTokensSource
|
||||
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.send.api.navigation.SendRouter
|
||||
import com.tangem.features.staking.api.navigation.StakingRouter
|
||||
|
|
@ -25,11 +23,9 @@ import com.tangem.tap.features.details.ui.appcurrency.AppCurrencySelectorFragmen
|
|||
import com.tangem.tap.features.details.ui.appsettings.AppSettingsFragment
|
||||
import com.tangem.tap.features.details.ui.cardsettings.CardSettingsFragment
|
||||
import com.tangem.tap.features.details.ui.cardsettings.coderecovery.AccessCodeRecoveryFragment
|
||||
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.securitymode.SecurityModeFragment
|
||||
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.main.ui.ModalNotificationBottomSheetFragment
|
||||
import com.tangem.tap.features.onboarding.products.note.OnboardingNoteFragment
|
||||
|
|
@ -59,8 +55,6 @@ internal class ChildFactory @Inject constructor(
|
|||
private val qrScanningRouter: QrScanningRouter,
|
||||
private val stakingRouter: StakingRouter,
|
||||
private val testerRouter: TesterRouter,
|
||||
private val detailsFeatureToggles: DetailsFeatureToggles,
|
||||
private val pushNotificationsFeatureToggles: PushNotificationsFeatureToggles,
|
||||
private val manageTokensToggles: ManageTokensToggles,
|
||||
private val pushNotificationRouter: PushNotificationsRouter,
|
||||
) {
|
||||
|
|
@ -98,29 +92,21 @@ internal class ChildFactory @Inject constructor(
|
|||
route.asFragmentChild(Provider { CardSettingsFragment() })
|
||||
}
|
||||
is AppRoute.Details -> {
|
||||
if (detailsFeatureToggles.isRedesignEnabled) {
|
||||
route.asComponentChild(
|
||||
contextProvider = contextProvider(route, contextFactory),
|
||||
params = DetailsComponent.Params(route.userWalletId),
|
||||
componentFactory = detailsComponentFactory,
|
||||
)
|
||||
} else {
|
||||
route.asFragmentChild(Provider { DetailsFragment() })
|
||||
}
|
||||
route.asComponentChild(
|
||||
contextProvider = contextProvider(route, contextFactory),
|
||||
params = DetailsComponent.Params(route.userWalletId),
|
||||
componentFactory = detailsComponentFactory,
|
||||
)
|
||||
}
|
||||
is AppRoute.DetailsSecurity -> {
|
||||
route.asFragmentChild(Provider { SecurityModeFragment() })
|
||||
}
|
||||
is AppRoute.Disclaimer -> {
|
||||
if (pushNotificationsFeatureToggles.isPushNotificationsEnabled) {
|
||||
route.asComponentChild(
|
||||
contextProvider = contextProvider(route, contextFactory),
|
||||
params = DisclaimerComponent.Params(route.isTosAccepted),
|
||||
componentFactory = disclaimerComponentFactory,
|
||||
)
|
||||
} else {
|
||||
route.asFragmentChild(Provider { DisclaimerFragment() })
|
||||
}
|
||||
route.asComponentChild(
|
||||
contextProvider = contextProvider(route, contextFactory),
|
||||
params = DisclaimerComponent.Params(route.isTosAccepted),
|
||||
componentFactory = disclaimerComponentFactory,
|
||||
)
|
||||
}
|
||||
is AppRoute.Home -> {
|
||||
route.asFragmentChild(Provider { HomeFragment() })
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue