diff --git a/app/src/main/assets/tangem-app-config b/app/src/main/assets/tangem-app-config index 328c13826f..5b216eeca7 160000 --- a/app/src/main/assets/tangem-app-config +++ b/app/src/main/assets/tangem-app-config @@ -1 +1 @@ -Subproject commit 328c13826f7e52ba783db1ba39de5b17b1b79bc5 +Subproject commit 5b216eeca70af8b9fa7b266d4d0c0f87f0c042c8 diff --git a/app/src/main/assets/testnet_tokens.json b/app/src/main/assets/testnet_tokens.json index cb960e3694..e6805136f2 100644 --- a/app/src/main/assets/testnet_tokens.json +++ b/app/src/main/assets/testnet_tokens.json @@ -718,6 +718,26 @@ "networkId": "sei-network/test" } ] + }, + { + "id": "energy-web-chain", + "name": "Energy Web Chain", + "symbol": "EWT", + "networks": [ + { + "networkId": "energy-web-chain/test" + } + ] + }, + { + "id": "energy-web-x", + "name": "Energy Web X", + "symbol": "EWT", + "networks": [ + { + "networkId": "energy-web-x/test" + } + ] } ] } diff --git a/app/src/main/java/com/tangem/tap/ApplicationEntryPoint.kt b/app/src/main/java/com/tangem/tap/ApplicationEntryPoint.kt index 21ab576e7f..72cd3046af 100644 --- a/app/src/main/java/com/tangem/tap/ApplicationEntryPoint.kt +++ b/app/src/main/java/com/tangem/tap/ApplicationEntryPoint.kt @@ -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 } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/MainActivity.kt b/app/src/main/java/com/tangem/tap/MainActivity.kt index 7735974a6d..312d9693a9 100644 --- a/app/src/main/java/com/tangem/tap/MainActivity.kt +++ b/app/src/main/java/com/tangem/tap/MainActivity.kt @@ -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) diff --git a/app/src/main/java/com/tangem/tap/TangemApplication.kt b/app/src/main/java/com/tangem/tap/TangemApplication.kt index ef8490029a..7b1ef60571 100644 --- a/app/src/main/java/com/tangem/tap/TangemApplication.kt +++ b/app/src/main/java/com/tangem/tap/TangemApplication.kt @@ -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, ), ), ) diff --git a/app/src/main/java/com/tangem/tap/common/analytics/events/Settings.kt b/app/src/main/java/com/tangem/tap/common/analytics/events/Settings.kt index 8ba8e26539..98b0289289 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/events/Settings.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/events/Settings.kt @@ -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), diff --git a/app/src/main/java/com/tangem/tap/common/redux/AppReducer.kt b/app/src/main/java/com/tangem/tap/common/redux/AppReducer.kt index cdc2bed475..1509ffe81b 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/AppReducer.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/AppReducer.kt @@ -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), diff --git a/app/src/main/java/com/tangem/tap/common/redux/AppState.kt b/app/src/main/java/com/tangem/tap/common/redux/AppState.kt index bdcb0bd1c1..8c30e94166 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/AppState.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/AppState.kt @@ -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, diff --git a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalMiddleware.kt b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalMiddleware.kt index 43d85d7fc5..65341daa53 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalMiddleware.kt @@ -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(), + ), + ) + } + } } } } diff --git a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalReducer.kt b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalReducer.kt index 6b011082d2..02c839de1f 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalReducer.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalReducer.kt @@ -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 } diff --git a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalState.kt b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalState.kt index 420951087b..86573ec741 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalState.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalState.kt @@ -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 diff --git a/app/src/main/java/com/tangem/tap/di/domain/SettingsDomainModule.kt b/app/src/main/java/com/tangem/tap/di/domain/SettingsDomainModule.kt index 1b5860c2c0..e175d51e25 100644 --- a/app/src/main/java/com/tangem/tap/di/domain/SettingsDomainModule.kt +++ b/app/src/main/java/com/tangem/tap/di/domain/SettingsDomainModule.kt @@ -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) + } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt b/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt index 256c8f1bf9..c25cf8552c 100644 --- a/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt @@ -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)) diff --git a/app/src/main/java/com/tangem/tap/domain/scanCard/LegacyScanProcessor.kt b/app/src/main/java/com/tangem/tap/domain/scanCard/LegacyScanProcessor.kt index ea7c4ac652..f851113e17 100644 --- a/app/src/main/java/com/tangem/tap/domain/scanCard/LegacyScanProcessor.kt +++ b/app/src/main/java/com/tangem/tap/domain/scanCard/LegacyScanProcessor.kt @@ -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)) + } } } } diff --git a/app/src/main/java/com/tangem/tap/domain/scanCard/UseCaseScanProcessor.kt b/app/src/main/java/com/tangem/tap/domain/scanCard/UseCaseScanProcessor.kt index 381d348980..10646e2bfa 100644 --- a/app/src/main/java/com/tangem/tap/domain/scanCard/UseCaseScanProcessor.kt +++ b/app/src/main/java/com/tangem/tap/domain/scanCard/UseCaseScanProcessor.kt @@ -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)) } diff --git a/app/src/main/java/com/tangem/tap/domain/scanCard/chains/DisclaimerChain.kt b/app/src/main/java/com/tangem/tap/domain/scanCard/chains/DisclaimerChain.kt index 8aa003b952..7bd4be874c 100644 --- a/app/src/main/java/com/tangem/tap/domain/scanCard/chains/DisclaimerChain.kt +++ b/app/src/main/java/com/tangem/tap/domain/scanCard/chains/DisclaimerChain.kt @@ -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() } } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/walletconnect/WalletConnectSdkHelper.kt b/app/src/main/java/com/tangem/tap/domain/walletconnect/WalletConnectSdkHelper.kt index 8c78ffa3a5..deb7e332b7 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletconnect/WalletConnectSdkHelper.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletconnect/WalletConnectSdkHelper.kt @@ -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, diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsAction.kt b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsAction.kt index 10bb1b383d..53844799aa 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsAction.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsAction.kt @@ -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, diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt index 40f3d03a11..713ffe5c9a 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt @@ -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 { - 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() } - } - .doOnFailure { error -> - if (error is UserWalletsListError.WalletAlreadySaved) { - userWalletsListManager.select(userWallet.walletId) - store.onUserWalletSelected(userWallet) - - store.dispatchWithMain(DetailsAction.ScanAndSaveUserWallet.Success) - store.dispatchNavigationAction { popTo() } - } 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) - } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsReducer.kt b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsReducer.kt index dbb450b426..bfe8750b2a 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsReducer.kt @@ -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() diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsState.kt b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsState.kt index c35d0c8d83..bc7f17a7b6 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsState.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsState.kt @@ -1,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, diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/AppSettingsViewModel.kt b/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/AppSettingsViewModel.kt index 34a693dbb4..55d16d7d80 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/AppSettingsViewModel.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/AppSettingsViewModel.kt @@ -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, DefaultLifecycleObserver { @@ -62,9 +60,7 @@ internal class AppSettingsViewModel @Inject constructor( init { bootstrapAppCurrencyUpdates() - if (detailsFeatureToggles.isRedesignEnabled) { - bootstrapBiometricsUpdates() - } + bootstrapBiometricsUpdates() subscribeToStoreChanges() sendItemsAnalytics() diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsFragment.kt b/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsFragment.kt deleted file mode 100644 index 5b41307402..0000000000 --- a/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsFragment.kt +++ /dev/null @@ -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 { - - @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) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsScreen.kt b/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsScreen.kt deleted file mode 100644 index f31718287c..0000000000 --- a/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsScreen.kt +++ /dev/null @@ -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) { - 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, 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) { - 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( - 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 \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsScreenState.kt b/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsScreenState.kt deleted file mode 100644 index acafefe8e7..0000000000 --- a/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsScreenState.kt +++ /dev/null @@ -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, - val tangemLinks: ImmutableList, - val tangemVersion: String, - val showSnackbar: StateEvent, - 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 = 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 = 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"), - ) -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsViewModel.kt b/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsViewModel.kt deleted file mode 100644 index d2c84a43db..0000000000 --- a/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsViewModel.kt +++ /dev/null @@ -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, - private val walletsRepository: WalletsRepository, - private val userWalletsListManager: UserWalletsListManager, -) { - - var detailsScreenState: MutableState = 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 { - 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 { - 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 { - 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) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/ResetCardDialog.kt b/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/ResetCardDialog.kt new file mode 100644 index 0000000000..c6efa99d33 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/ResetCardDialog.kt @@ -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() +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/ResetCardViewModel.kt b/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/ResetCardViewModel.kt index fefbdf122e..ebcdf702a9 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/ResetCardViewModel.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/ResetCardViewModel.kt @@ -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 diff --git a/app/src/main/java/com/tangem/tap/features/disclaimer/Disclaimer.kt b/app/src/main/java/com/tangem/tap/features/disclaimer/Disclaimer.kt index 9cda07b754..3524b38f40 100644 --- a/app/src/main/java/com/tangem/tap/features/disclaimer/Disclaimer.kt +++ b/app/src/main/java/com/tangem/tap/features/disclaimer/Disclaimer.kt @@ -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") } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/disclaimer/redux/DisclaimerAction.kt b/app/src/main/java/com/tangem/tap/features/disclaimer/redux/DisclaimerAction.kt deleted file mode 100644 index 9611dc80b5..0000000000 --- a/app/src/main/java/com/tangem/tap/features/disclaimer/redux/DisclaimerAction.kt +++ /dev/null @@ -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() -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/disclaimer/redux/DisclaimerMiddleware.kt b/app/src/main/java/com/tangem/tap/features/disclaimer/redux/DisclaimerMiddleware.kt deleted file mode 100644 index 60ffa51781..0000000000 --- a/app/src/main/java/com/tangem/tap/features/disclaimer/redux/DisclaimerMiddleware.kt +++ /dev/null @@ -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 = { 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() - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/disclaimer/redux/DisclaimerReducer.kt b/app/src/main/java/com/tangem/tap/features/disclaimer/redux/DisclaimerReducer.kt deleted file mode 100644 index 9b655697ba..0000000000 --- a/app/src/main/java/com/tangem/tap/features/disclaimer/redux/DisclaimerReducer.kt +++ /dev/null @@ -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, - ) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/disclaimer/redux/DisclaimerSource.kt b/app/src/main/java/com/tangem/tap/features/disclaimer/redux/DisclaimerSource.kt deleted file mode 100644 index cdfcbbdb90..0000000000 --- a/app/src/main/java/com/tangem/tap/features/disclaimer/redux/DisclaimerSource.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.tangem.tap.features.disclaimer.redux - -enum class DisclaimerSource { - Home, Details -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/disclaimer/redux/DisclaimerState.kt b/app/src/main/java/com/tangem/tap/features/disclaimer/redux/DisclaimerState.kt deleted file mode 100644 index c5ccfc7cfc..0000000000 --- a/app/src/main/java/com/tangem/tap/features/disclaimer/redux/DisclaimerState.kt +++ /dev/null @@ -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, -) \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/disclaimer/ui/DisclaimerFragment.kt b/app/src/main/java/com/tangem/tap/features/disclaimer/ui/DisclaimerFragment.kt deleted file mode 100644 index 9d217e6111..0000000000 --- a/app/src/main/java/com/tangem/tap/features/disclaimer/ui/DisclaimerFragment.kt +++ /dev/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 { - - 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") - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/disclaimer/ui/DisclaimerWebViewClient.kt b/app/src/main/java/com/tangem/tap/features/disclaimer/ui/DisclaimerWebViewClient.kt deleted file mode 100644 index c64d0b7543..0000000000 --- a/app/src/main/java/com/tangem/tap/features/disclaimer/ui/DisclaimerWebViewClient.kt +++ /dev/null @@ -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 - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/disclaimer/ui/LocalTermOfServices.kt b/app/src/main/java/com/tangem/tap/features/disclaimer/ui/LocalTermOfServices.kt deleted file mode 100644 index 6651d0fa75..0000000000 --- a/app/src/main/java/com/tangem/tap/features/disclaimer/ui/LocalTermOfServices.kt +++ /dev/null @@ -1,66 +0,0 @@ -package com.tangem.tap.features.disclaimer.ui - -internal val localTermsOfServices = """ - - - - - - - Legal Disclaimer - - -

Legal Disclaimer

-

    1. Tangem application (Software)

-

    The Software is intended for usage only with Tangem hardware wallets (Cards) via NFC interface. The - Software DOES NOT:

-

    a) Generate, store, transmit, or have access to private (secret) cryptographic keys to blockchain - wallets holding digital assets, including crypto-currency.

-

    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.

-

    c) Provide exchange, trading, investment services on behalf of Tangem AG.

-

    2. Risks related to the use of Software

-

    Tangem will not be responsible for any losses, damages or claims arising from events falling within the - scope of the following five categories:

-

    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.

-

    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.

-

    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.

-

    d) Security problems experienced by the user of any cryptocurrency-related software or service, e.g., - unauthorized access to users' wallets and/or accounts.

-

    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.

-

    3. Trading and Investment risks

-

    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.

-

    4. Electronic Trading Risks

-

    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.

-

    5. Compliance with tax obligations        

-

    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.        

-

    6. No warranties        

-

    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.       -  

-

    7. Limitation of liability

-

    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.

-

    8. Last amendment

-

    This disclaimer was amended for the last time on October 1st, 2020.

- -""".trimIndent() \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/home/compose/StoriesScreen.kt b/app/src/main/java/com/tangem/tap/features/home/compose/StoriesScreen.kt index 9f4e9fbaa9..f33229cf24 100644 --- a/app/src/main/java/com/tangem/tap/features/home/compose/StoriesScreen.kt +++ b/app/src/main/java/com/tangem/tap/features/home/compose/StoriesScreen.kt @@ -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, ) diff --git a/app/src/main/java/com/tangem/tap/features/home/featuretoggles/HomeFeatureToggles.kt b/app/src/main/java/com/tangem/tap/features/home/featuretoggles/HomeFeatureToggles.kt new file mode 100644 index 0000000000..ce8c0bcec3 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/home/featuretoggles/HomeFeatureToggles.kt @@ -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") +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/home/redux/HomeAction.kt b/app/src/main/java/com/tangem/tap/features/home/redux/HomeAction.kt index e3f0375cc1..05ba17df63 100644 --- a/app/src/main/java/com/tangem/tap/features/home/redux/HomeAction.kt +++ b/app/src/main/java/com/tangem/tap/features/home/redux/HomeAction.kt @@ -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() } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/home/redux/HomeReducer.kt b/app/src/main/java/com/tangem/tap/features/home/redux/HomeReducer.kt index f9d977fdec..ab41e3d89f 100644 --- a/app/src/main/java/com/tangem/tap/features/home/redux/HomeReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/home/redux/HomeReducer.kt @@ -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 } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/home/redux/HomeState.kt b/app/src/main/java/com/tangem/tap/features/home/redux/HomeState.kt index 2e584d3d35..5341631157 100644 --- a/app/src/main/java/com/tangem/tap/features/home/redux/HomeState.kt +++ b/app/src/main/java/com/tangem/tap/features/home/redux/HomeState.kt @@ -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 = initDefaultStories(), + val stories: ImmutableList = 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 = 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 = 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, } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/main/MainViewModel.kt b/app/src/main/java/com/tangem/tap/features/main/MainViewModel.kt index 6ba358cced..2fc52d0c05 100644 --- a/app/src/main/java/com/tangem/tap/features/main/MainViewModel.kt +++ b/app/src/main/java/com/tangem/tap/features/main/MainViewModel.kt @@ -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() diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingHelper.kt b/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingHelper.kt index bc085c6dca..130eddc672 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingHelper.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingHelper.kt @@ -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?, diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteMiddleware.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteMiddleware.kt index 52af2f7d66..d47862a648 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteMiddleware.kt @@ -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) diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt index 047a5caaa8..ef29db32d4 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt @@ -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() diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TradeCryptoMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TradeCryptoMiddleware.kt index 1abdf861b9..2f26b2a39a 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TradeCryptoMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TradeCryptoMiddleware.kt @@ -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()) + } } } diff --git a/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphState.kt b/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphState.kt index 45b2035717..b4249310fe 100644 --- a/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphState.kt +++ b/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphState.kt @@ -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 \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt b/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt index 0996998748..ec1b9c0c85 100644 --- a/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt +++ b/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt @@ -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() }) diff --git a/app/src/main/res/layout/fragment_disclaimer.xml b/app/src/main/res/layout/fragment_disclaimer.xml deleted file mode 100644 index 346cab4f03..0000000000 --- a/app/src/main/res/layout/fragment_disclaimer.xml +++ /dev/null @@ -1,129 +0,0 @@ - - - - - - - - - - - - - - - - - - - -