From afcde269ce124dbdb4beb0b319608abb62d28588 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 10 Oct 2023 14:50:19 +0800 Subject: [PATCH] Updated on 2026-08-14 --- .../java/com/tangem/tap/TapApplication.kt | 74 ++++++++++--------- .../common/feedback/AdditionalFeedbackInfo.kt | 29 +------- .../common/redux/global/GlobalMiddleware.kt | 23 +++++- .../tap/di/domain/WalletsDomainModule.kt | 8 ++ .../com/tangem/tap/domain/TapWalletManager.kt | 3 +- .../features/details/redux/DetailsAction.kt | 1 + .../details/redux/DetailsMiddleware.kt | 9 ++- .../features/details/redux/DetailsReducer.kt | 2 +- .../details/ui/details/DetailsFragment.kt | 6 +- .../details/ui/details/DetailsViewModel.kt | 10 ++- .../features/onboarding/OnboardingHelper.kt | 62 ++++++++-------- .../twins/redux/TwinCardsMiddleware.kt | 13 +++- .../saveWallet/redux/SaveWalletMiddleware.kt | 5 +- .../tap/proxy/redux/DaggerGraphState.kt | 2 + .../tangem/datasource/di/WalletsDataModule.kt | 26 +++++++ .../userwallet/ShouldSaveUserWalletStore.kt | 24 ++++++ .../preferences/PreferencesDataSource.kt | 7 -- data/wallets/build.gradle.kts | 1 + .../data/wallets/DefaultWalletsRepository.kt | 21 +++++- .../data/wallets/di/WalletsDataModule.kt | 6 +- .../wallets/repository/WalletsRepository.kt | 10 ++- .../ShouldSaveUserWalletsSyncUseCase.kt | 8 ++ .../usecase/ShouldSaveUserWalletsUseCase.kt | 3 +- .../wallet/viewmodels/WalletViewModel.kt | 21 ++++-- 24 files changed, 243 insertions(+), 131 deletions(-) create mode 100644 core/datasource/src/main/java/com/tangem/datasource/di/WalletsDataModule.kt create mode 100644 core/datasource/src/main/java/com/tangem/datasource/local/userwallet/ShouldSaveUserWalletStore.kt create mode 100644 domain/wallets/src/main/java/com/tangem/domain/wallets/usecase/ShouldSaveUserWalletsSyncUseCase.kt diff --git a/app/src/main/java/com/tangem/tap/TapApplication.kt b/app/src/main/java/com/tangem/tap/TapApplication.kt index 919b23292e..599ad22aa3 100644 --- a/app/src/main/java/com/tangem/tap/TapApplication.kt +++ b/app/src/main/java/com/tangem/tap/TapApplication.kt @@ -34,6 +34,7 @@ import com.tangem.domain.tokens.repository.CurrenciesRepository import com.tangem.domain.walletmanager.WalletManagersFacade import com.tangem.domain.wallets.legacy.UserWalletsListManager import com.tangem.domain.wallets.legacy.WalletManagersRepository +import com.tangem.domain.wallets.repository.WalletsRepository import com.tangem.features.tokendetails.featuretoggles.TokenDetailsFeatureToggles import com.tangem.features.wallet.featuretoggles.WalletFeatureToggles import com.tangem.tap.common.analytics.AnalyticsFactory @@ -44,6 +45,7 @@ import com.tangem.tap.common.analytics.handlers.appsFlyer.AppsFlyerAnalyticsHand import com.tangem.tap.common.analytics.handlers.firebase.FirebaseAnalyticsHandler import com.tangem.tap.common.analytics.topup.TopUpController import com.tangem.tap.common.chat.ChatManager +import com.tangem.tap.common.extensions.dispatchOnMain import com.tangem.tap.common.feedback.AdditionalFeedbackInfo import com.tangem.tap.common.feedback.FeedbackManager import com.tangem.tap.common.images.createCoilImageLoader @@ -207,34 +209,15 @@ internal class TapApplication : Application(), ImageLoaderFactory { @Inject lateinit var getAppThemeModeUseCase: GetAppThemeModeUseCase + + @Inject + lateinit var walletsRepository: WalletsRepository // endregion Injected override fun onCreate() { super.onCreate() - store = Store( - reducer = { action, state -> appReducer(action, state, appStateHolder) }, - middleware = AppState.getMiddleware(), - state = AppState( - daggerGraphState = DaggerGraphState( - assetReader = assetReader, - networkConnectionManager = networkConnectionManager, - customTokenFeatureToggles = customTokenFeatureToggles, - walletFeatureToggles = walletFeatureToggles, - walletConnectRepository = walletConnect2Repository, - walletConnectSessionsRepository = walletConnectSessionsRepository, - tokenDetailsFeatureToggles = tokenDetailsFeatureToggles, - scanCardProcessor = scanCardProcessor, - appCurrencyRepository = appCurrencyRepository, - walletManagersFacade = walletManagersFacade, - appStateHolder = appStateHolder, - currenciesRepository = currenciesRepository, - appThemeModeRepository = appThemeModeRepository, - balanceHidingRepository = balanceHidingRepository, - detailsFeatureToggles = detailsFeatureToggles, - ), - ), - ) + store = createReduxStore() if (BuildConfig.DEBUG) { Logger.addLogAdapter(AndroidLogAdapter(TimberFormatStrategy())) @@ -254,17 +237,17 @@ internal class TapApplication : Application(), ImageLoaderFactory { preferencesStorage = preferencesDataSource walletConnectRepository = WalletConnectRepository(this) - val configLoader = FeaturesLocalLoader(assetReader, MoshiConverter.sdkMoshi, BuildConfig.ENVIRONMENT) - initUserWalletsListManager() - // TODO: Try to performance and user experience. // [REDACTED_JIRA] runBlocking { + initUserWalletsListManager() featureTogglesManager.init() appRatingRepository.initialize() + walletsRepository.initialize() // learn2earnInteractor.init() } + val configLoader = FeaturesLocalLoader(assetReader, MoshiConverter.sdkMoshi, BuildConfig.ENVIRONMENT) initConfigManager(configLoader, ::initWithConfigDependency) initWarningMessagesManager() @@ -296,6 +279,33 @@ internal class TapApplication : Application(), ImageLoaderFactory { walletConnect2Repository.init(projectId = configManager.config.walletConnectProjectId) } + private fun createReduxStore(): Store { + return Store( + reducer = { action, state -> appReducer(action, state, appStateHolder) }, + middleware = AppState.getMiddleware(), + state = AppState( + daggerGraphState = DaggerGraphState( + assetReader = assetReader, + networkConnectionManager = networkConnectionManager, + customTokenFeatureToggles = customTokenFeatureToggles, + walletFeatureToggles = walletFeatureToggles, + walletConnectRepository = walletConnect2Repository, + walletConnectSessionsRepository = walletConnectSessionsRepository, + tokenDetailsFeatureToggles = tokenDetailsFeatureToggles, + scanCardProcessor = scanCardProcessor, + appCurrencyRepository = appCurrencyRepository, + walletManagersFacade = walletManagersFacade, + appStateHolder = appStateHolder, + currenciesRepository = currenciesRepository, + appThemeModeRepository = appThemeModeRepository, + balanceHidingRepository = balanceHidingRepository, + detailsFeatureToggles = detailsFeatureToggles, + walletsRepository = walletsRepository, + ), + ), + ) + } + private fun initTopUpController() { val topUpController = TopUpController( scanResponseProvider = { @@ -356,11 +366,7 @@ internal class TapApplication : Application(), ImageLoaderFactory { store: Store, ) { fun initAdditionalFeedbackInfo(context: Context): AdditionalFeedbackInfo { - return AdditionalFeedbackInfo( - userWalletsListManager = userWalletsListManager, - walletManagersFacade = walletManagersFacade, - walletFeatureToggles = walletFeatureToggles, - ).apply { + return AdditionalFeedbackInfo().apply { appVersion = try { // TODO don't use deprecated method val pInfo = context.packageManager.getPackageInfo(context.packageName, 0) @@ -403,13 +409,13 @@ internal class TapApplication : Application(), ImageLoaderFactory { store.dispatch(GlobalAction.SetWarningManager(WarningMessagesManager())) } - private fun initUserWalletsListManager() { - val manager = if (preferencesStorage.shouldSaveUserWallets) { + private suspend fun initUserWalletsListManager() { + val manager = if (walletsRepository.shouldSaveUserWalletsSync()) { UserWalletsListManager.provideBiometricImplementation(applicationContext) } else { UserWalletsListManager.provideRuntimeImplementation() } - store.dispatch(GlobalAction.UpdateUserWalletsListManager(manager)) + store.dispatchOnMain(GlobalAction.UpdateUserWalletsListManager(manager)) } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/feedback/AdditionalFeedbackInfo.kt b/app/src/main/java/com/tangem/tap/common/feedback/AdditionalFeedbackInfo.kt index a3407ad4d2..e1d67df755 100644 --- a/app/src/main/java/com/tangem/tap/common/feedback/AdditionalFeedbackInfo.kt +++ b/app/src/main/java/com/tangem/tap/common/feedback/AdditionalFeedbackInfo.kt @@ -6,35 +6,10 @@ import com.tangem.blockchain.common.address.Address import com.tangem.domain.models.scan.CardDTO import com.tangem.domain.models.scan.ScanResponse import com.tangem.domain.userwallets.UserWalletIdBuilder -import com.tangem.domain.walletmanager.WalletManagersFacade -import com.tangem.domain.wallets.legacy.UserWalletsListManager -import com.tangem.features.wallet.featuretoggles.WalletFeatureToggles import com.tangem.tap.common.extensions.stripZeroPlainString -import com.tangem.tap.scope -import kotlinx.coroutines.flow.distinctUntilChanged -import kotlinx.coroutines.flow.launchIn -import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.flow.* -class AdditionalFeedbackInfo( - userWalletsListManager: UserWalletsListManager, - walletManagersFacade: WalletManagersFacade, - walletFeatureToggles: WalletFeatureToggles, -) { - - init { - if (walletFeatureToggles.isRedesignedScreenEnabled) { - userWalletsListManager.selectedUserWallet - .distinctUntilChanged() - .onEach { userWallet -> - setCardInfo(data = userWallet.scanResponse) - - walletManagersFacade.getAll(userWalletId = userWallet.walletId) - .onEach(::setWalletsInfo) - .launchIn(scope) - } - .launchIn(scope) - } - } +class AdditionalFeedbackInfo { class EmailWalletInfo( var blockchain: Blockchain = Blockchain.Unknown, 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 e7421cf777..9f6d1d71c0 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 @@ -29,7 +29,8 @@ import com.tangem.tap.proxy.redux.DaggerGraphState import com.tangem.tap.scope import com.tangem.tap.store import com.tangem.tap.walletCurrenciesManager -import kotlinx.coroutines.flow.firstOrNull +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.* import kotlinx.coroutines.launch import org.rekotlin.Action import org.rekotlin.DispatchFunction @@ -174,6 +175,26 @@ private fun handleAction(action: Action, appState: () -> AppState?, dispatch: Di is GlobalAction.SetTopUpController -> { walletCurrenciesManager.addListener(action.topUpController) } + is GlobalAction.UpdateUserWalletsListManager -> { + /* + * If UserWalletsListManager's implementation is changed, + * then all selectedUserWallet's observers is became irrelevant + */ + action.manager.selectedUserWallet + .distinctUntilChanged() + .onEach { userWallet -> + store.state.globalState.feedbackManager?.infoHolder?.let { infoHolder -> + infoHolder.setCardInfo(data = userWallet.scanResponse) + + store.state.daggerGraphState.get(DaggerGraphState::walletManagersFacade) + .getAll(userWalletId = userWallet.walletId) + .onEach(infoHolder::setWalletsInfo) + .launchIn(scope) + } + } + .flowOn(Dispatchers.IO) + .launchIn(scope) + } } } diff --git a/app/src/main/java/com/tangem/tap/di/domain/WalletsDomainModule.kt b/app/src/main/java/com/tangem/tap/di/domain/WalletsDomainModule.kt index 2d12ae7b0b..e491a32ba9 100644 --- a/app/src/main/java/com/tangem/tap/di/domain/WalletsDomainModule.kt +++ b/app/src/main/java/com/tangem/tap/di/domain/WalletsDomainModule.kt @@ -68,6 +68,14 @@ internal object WalletsDomainModule { return DeleteWalletUseCase(walletsStateHolder = walletsStateHolder) } + @Provides + @ViewModelScoped + fun providesShouldSaveUserWalletsSyncUseCase( + walletsRepository: WalletsRepository, + ): ShouldSaveUserWalletsSyncUseCase { + return ShouldSaveUserWalletsSyncUseCase(walletsRepository = walletsRepository) + } + @Provides @ViewModelScoped fun providesShouldSaveUserWalletsUseCase(walletsRepository: WalletsRepository): ShouldSaveUserWalletsUseCase { 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 729e96fe27..9edc4ee417 100644 --- a/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt @@ -81,7 +81,8 @@ class TapWalletManager( store.dispatchWalletAction(action = WalletAction.UserWalletChanged(userWallet)) store.dispatchWalletAction( action = WalletAction.UpdateCanSaveUserWallets( - canSaveUserWallets = preferencesStorage.shouldSaveUserWallets, + canSaveUserWallets = store.state.daggerGraphState.get(DaggerGraphState::walletsRepository) + .shouldSaveUserWalletsSync(), ), ) store.dispatch(TwinCardsAction.IfTwinsPrepareState(scanResponse)) 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 0190c0aa97..338e8f255c 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 @@ -14,6 +14,7 @@ sealed class DetailsAction : Action { data class PrepareScreen( val scanResponse: ScanResponse, val darkThemeSwitchEnabled: Boolean, + val shouldSaveUserWallets: Boolean, ) : DetailsAction() object ReCreateTwinsWallet : DetailsAction() diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt index bdf4867874..3dac94f996 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 @@ -291,7 +291,8 @@ class DetailsMiddleware { private fun toggleSaveWallets(state: DetailsState, enable: Boolean) = scope.launch { // Nothing to change - if (preferencesStorage.shouldSaveUserWallets == enable) { + val walletsRepository = store.state.daggerGraphState.get(DaggerGraphState::walletsRepository) + if (walletsRepository.shouldSaveUserWalletsSync() == enable) { store.dispatchWithMain(DetailsAction.AppSettings.SwitchPrivacySetting.Success) return@launch } @@ -379,7 +380,8 @@ class DetailsMiddleware { Analytics.send(Settings.AppSettings.SaveWalletSwitcherChanged(AnalyticsParam.OnOffState.On)) preferencesStorage.shouldShowSaveUserWalletScreen = false - preferencesStorage.shouldSaveUserWallets = true + store.state.daggerGraphState.get(DaggerGraphState::walletsRepository) + .saveShouldSaveUserWallets(item = true) store.dispatchWithMain(WalletAction.UpdateCanSaveUserWallets(canSaveUserWallets = true)) } @@ -395,7 +397,8 @@ class DetailsMiddleware { Analytics.send(Settings.AppSettings.SaveWalletSwitcherChanged(AnalyticsParam.OnOffState.Off)) deleteSavedAccessCodes() updateUserWalletsListManager(enableUserWalletsSaving = false) - preferencesStorage.shouldSaveUserWallets = false + store.state.daggerGraphState.get(DaggerGraphState::walletsRepository) + .saveShouldSaveUserWallets(item = false) store.dispatchWithMain(WalletAction.UpdateCanSaveUserWallets(canSaveUserWallets = true)) store.dispatchWithMain(NavigationAction.PopBackTo(AppScreen.Home)) 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 a3dc4cfe98..ff94b5cc7a 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 @@ -72,7 +72,7 @@ private fun handlePrepareScreen(action: DetailsAction.PrepareScreen): DetailsSta createBackupAllowed = action.scanResponse.card.backupStatus == CardDTO.BackupStatus.NoBackup, appSettingsState = AppSettingsState( isBiometricsAvailable = tangemSdkManager.canUseBiometry, - saveWallets = preferencesStorage.shouldSaveUserWallets, + saveWallets = action.shouldSaveUserWallets, saveAccessCodes = preferencesStorage.shouldSaveAccessCodes, selectedFiatCurrency = store.state.globalState.appCurrency, selectedThemeMode = runBlocking { 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 index 3d819cd6d0..d3d215551c 100644 --- 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 @@ -7,6 +7,7 @@ import com.tangem.core.analytics.Analytics import com.tangem.core.navigation.NavigationAction import com.tangem.core.ui.screen.ComposeFragment import com.tangem.core.ui.theme.AppThemeModeHolder +import com.tangem.domain.wallets.repository.WalletsRepository import com.tangem.tap.common.analytics.events.Settings import com.tangem.tap.features.details.DarkThemeFeatureToggle import com.tangem.tap.features.details.redux.DetailsState @@ -24,11 +25,14 @@ internal class DetailsFragment : ComposeFragment(), StoreSubscriber, private val darkThemeFeatureToggle: DarkThemeFeatureToggle, -) { // TODO: change to Android ViewModel + private val walletsRepository: WalletsRepository, +) { var detailsScreenState: MutableState = mutableStateOf(updateState(store.state.detailsState)) private set @@ -186,8 +189,9 @@ internal class DetailsViewModel( .onEach { selectedUserWallet -> store.dispatchWithMain( DetailsAction.PrepareScreen( - selectedUserWallet.scanResponse, - darkThemeFeatureToggle.isDarkThemeEnabled, + scanResponse = selectedUserWallet.scanResponse, + darkThemeSwitchEnabled = darkThemeFeatureToggle.isDarkThemeEnabled, + shouldSaveUserWallets = walletsRepository.shouldSaveUserWalletsSync(), ), ) } 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 baf5ed2fcf..29c6d0fe98 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 @@ -17,6 +17,7 @@ import com.tangem.tap.common.extensions.onUserWalletSelected import com.tangem.tap.common.extensions.removeContext import com.tangem.tap.common.extensions.setContext import com.tangem.tap.features.saveWallet.redux.SaveWalletAction +import com.tangem.tap.proxy.redux.DaggerGraphState import kotlinx.coroutines.delay import kotlinx.coroutines.launch import timber.log.Timber @@ -70,40 +71,39 @@ object OnboardingHelper { backupCardsIds: List? = null, ) { Analytics.setContext(scanResponse) - when { - // When should save user wallets, then save card without navigate to save wallet screen - preferencesStorage.shouldSaveUserWallets -> scope.launch { - proceedWithScanResponse(scanResponse, backupCardsIds) + scope.launch { + when { + // When should save user wallets, then save card without navigate to save wallet screen + store.state.daggerGraphState.get(DaggerGraphState::walletsRepository).shouldSaveUserWalletsSync() -> { + proceedWithScanResponse(scanResponse, backupCardsIds) - store.dispatchOnMain( - SaveWalletAction.ProvideBackupInfo( - scanResponse = scanResponse, - accessCode = accessCode, - backupCardsIds = backupCardsIds?.toSet(), - ), - ) - store.dispatchOnMain(SaveWalletAction.Save) - } - // When should not save user wallets but device has biometry and save wallet screen has not been shown, - // then open save wallet screen - tangemSdkManager.canUseBiometry && - preferencesStorage.shouldShowSaveUserWalletScreen -> scope.launch { - proceedWithScanResponse(scanResponse, backupCardsIds) + store.dispatchOnMain( + SaveWalletAction.ProvideBackupInfo( + scanResponse = scanResponse, + accessCode = accessCode, + backupCardsIds = backupCardsIds?.toSet(), + ), + ) + store.dispatchOnMain(SaveWalletAction.Save) + } + // When should not save user wallets but device has biometry and save wallet screen has not been shown, + // then open save wallet screen + tangemSdkManager.canUseBiometry && preferencesStorage.shouldShowSaveUserWalletScreen -> { + proceedWithScanResponse(scanResponse, backupCardsIds) - delay(timeMillis = 1_200) + delay(timeMillis = 1_200) - store.dispatchOnMain( - SaveWalletAction.ProvideBackupInfo( - scanResponse = scanResponse, - accessCode = accessCode, - backupCardsIds = backupCardsIds?.toSet(), - ), - ) - store.dispatchOnMain(NavigationAction.NavigateTo(AppScreen.SaveWallet)) - } - // If device has no biometry and save wallet screen has been shown, then go through old scenario - else -> scope.launch { - proceedWithScanResponse(scanResponse, backupCardsIds) + store.dispatchOnMain( + SaveWalletAction.ProvideBackupInfo( + scanResponse = scanResponse, + accessCode = accessCode, + backupCardsIds = backupCardsIds?.toSet(), + ), + ) + store.dispatchOnMain(NavigationAction.NavigateTo(AppScreen.SaveWallet)) + } + // If device has no biometry and save wallet screen has been shown, then go through old scenario + else -> proceedWithScanResponse(scanResponse, backupCardsIds) } } 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 f68fa7e806..ee8ba338c9 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 @@ -29,6 +29,7 @@ import com.tangem.tap.features.wallet.models.Currency import com.tangem.tap.features.wallet.redux.ProgressState import com.tangem.tap.features.wallet.redux.WalletAction import com.tangem.tap.features.wallet.redux.models.WalletDialog +import com.tangem.tap.proxy.redux.DaggerGraphState import kotlinx.coroutines.delay import kotlinx.coroutines.launch import org.rekotlin.Action @@ -292,10 +293,14 @@ private fun handle(action: Action, dispatch: DispatchFunction) { OnboardingHelper.trySaveWalletAndNavigateToWalletScreen(scanResponse) } CreateTwinWalletMode.RecreateWallet -> { - if (preferencesStorage.shouldSaveUserWallets) { - OnboardingHelper.trySaveWalletAndNavigateToWalletScreen(scanResponse) - } else { - store.dispatchOnMain(NavigationAction.PopBackTo(AppScreen.Home)) + scope.launch { + val walletsRepository = store.state.daggerGraphState.get(DaggerGraphState::walletsRepository) + + if (walletsRepository.shouldSaveUserWalletsSync()) { + OnboardingHelper.trySaveWalletAndNavigateToWalletScreen(scanResponse) + } else { + store.dispatchOnMain(NavigationAction.PopBackTo(AppScreen.Home)) + } } } } diff --git a/app/src/main/java/com/tangem/tap/features/saveWallet/redux/SaveWalletMiddleware.kt b/app/src/main/java/com/tangem/tap/features/saveWallet/redux/SaveWalletMiddleware.kt index 29e8ad6a02..f68fa4579e 100644 --- a/app/src/main/java/com/tangem/tap/features/saveWallet/redux/SaveWalletMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/saveWallet/redux/SaveWalletMiddleware.kt @@ -107,10 +107,11 @@ internal class SaveWalletMiddleware { store.dispatchWithMain(SaveWalletAction.Save.Error(error)) } .doOnSuccess { - preferencesStorage.shouldSaveUserWallets = true + store.state.daggerGraphState.get(DaggerGraphState::walletsRepository) + .saveShouldSaveUserWallets(item = true) + // Enable saving access codes only if this is the first time user save the wallet if (isFirstSavedWallet) { - preferencesStorage.shouldSaveAccessCodes = true store.state.daggerGraphState.get(DaggerGraphState::cardSdkConfigRepository) .setAccessCodeRequestPolicy( isBiometricsRequestPolicy = userWallet.hasAccessCode, 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 cd68dae6e3..441afa259c 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 @@ -10,6 +10,7 @@ import com.tangem.domain.card.ScanCardUseCase import com.tangem.domain.card.repository.CardSdkConfigRepository import com.tangem.domain.tokens.repository.CurrenciesRepository import com.tangem.domain.walletmanager.WalletManagersFacade +import com.tangem.domain.wallets.repository.WalletsRepository import com.tangem.features.tester.api.TesterRouter import com.tangem.features.tokendetails.featuretoggles.TokenDetailsFeatureToggles import com.tangem.features.tokendetails.navigation.TokenDetailsRouter @@ -44,6 +45,7 @@ data class DaggerGraphState( val appThemeModeRepository: AppThemeModeRepository? = null, val balanceHidingRepository: BalanceHidingRepository? = null, val detailsFeatureToggles: DetailsFeatureToggles? = null, + val walletsRepository: WalletsRepository? = null, // FIXME: It is used only for TokensList screen. Remove after refactoring of TokensList val currenciesRepository: CurrenciesRepository? = null, diff --git a/core/datasource/src/main/java/com/tangem/datasource/di/WalletsDataModule.kt b/core/datasource/src/main/java/com/tangem/datasource/di/WalletsDataModule.kt new file mode 100644 index 0000000000..61cdcacad3 --- /dev/null +++ b/core/datasource/src/main/java/com/tangem/datasource/di/WalletsDataModule.kt @@ -0,0 +1,26 @@ +package com.tangem.datasource.di + +import android.content.Context +import com.tangem.datasource.local.datastore.BooleanSharedPreferencesDataStore +import com.tangem.datasource.local.settings.* +import com.tangem.datasource.local.userwallet.DefaultShouldSaveUserWalletStore +import com.tangem.datasource.local.userwallet.ShouldSaveUserWalletStore +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.android.qualifiers.ApplicationContext +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +internal object WalletsDataModule { + + @Provides + @Singleton + fun provideShouldSaveUserWalletsStore(@ApplicationContext context: Context): ShouldSaveUserWalletStore { + return DefaultShouldSaveUserWalletStore( + store = BooleanSharedPreferencesDataStore(preferencesName = "tapPrefs", context = context), + ) + } +} \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/userwallet/ShouldSaveUserWalletStore.kt b/core/datasource/src/main/java/com/tangem/datasource/local/userwallet/ShouldSaveUserWalletStore.kt new file mode 100644 index 0000000000..cbc20ba792 --- /dev/null +++ b/core/datasource/src/main/java/com/tangem/datasource/local/userwallet/ShouldSaveUserWalletStore.kt @@ -0,0 +1,24 @@ +package com.tangem.datasource.local.userwallet + +import com.tangem.datasource.local.datastore.BooleanSharedPreferencesDataStore +import com.tangem.datasource.local.datastore.core.KeylessDataStoreDecorator +import kotlinx.coroutines.flow.Flow + +/** +[REDACTED_AUTHOR] + */ +interface ShouldSaveUserWalletStore { + + fun get(): Flow + + suspend fun getSyncOrNull(): Boolean? + + suspend fun store(item: Boolean) +} + +internal class DefaultShouldSaveUserWalletStore( + store: BooleanSharedPreferencesDataStore, +) : ShouldSaveUserWalletStore, KeylessDataStoreDecorator( + wrappedDataStore = store, + key = "saveUserWallets", +) \ No newline at end of file diff --git a/data/source/preferences/src/main/kotlin/com/tangem/data/source/preferences/PreferencesDataSource.kt b/data/source/preferences/src/main/kotlin/com/tangem/data/source/preferences/PreferencesDataSource.kt index ec8b43876b..218863ac9a 100644 --- a/data/source/preferences/src/main/kotlin/com/tangem/data/source/preferences/PreferencesDataSource.kt +++ b/data/source/preferences/src/main/kotlin/com/tangem/data/source/preferences/PreferencesDataSource.kt @@ -56,12 +56,6 @@ class PreferencesDataSource @Inject internal constructor(applicationContext: Con putBoolean(SAVE_WALLET_DIALOG_SHOWN_KEY, value) } - var shouldSaveUserWallets: Boolean - get() = preferences.getBoolean(SAVE_USER_WALLETS_KEY, false) - set(value) = preferences.edit { - putBoolean(SAVE_USER_WALLETS_KEY, value) - } - var shouldSaveAccessCodes: Boolean get() = preferences.getBoolean(SAVE_ACCESS_CODES_KEY, false) set(value) = preferences.edit { @@ -102,7 +96,6 @@ class PreferencesDataSource @Inject internal constructor(applicationContext: Con private const val ZENDESK_FIRST_LAUNCH_KEY = "chatFirstLaunchKey" private const val SPRINKLR_FIRST_LAUNCH_KEY = "sprinklrFirstLaunch" private const val SAVE_WALLET_DIALOG_SHOWN_KEY = "saveUserWalletShown" - private const val SAVE_USER_WALLETS_KEY = "saveUserWallets" private const val SAVE_ACCESS_CODES_KEY = "saveAccessCodes" private const val APPLICATION_STOPPED_KEY = "applicationStopped" private const val OPEN_WELCOME_ON_RESUME_KEY = "openWelcomeOnResume" diff --git a/data/wallets/build.gradle.kts b/data/wallets/build.gradle.kts index 7bc383e45b..f39f9b3c1e 100644 --- a/data/wallets/build.gradle.kts +++ b/data/wallets/build.gradle.kts @@ -11,6 +11,7 @@ android { } dependencies { + implementation(projects.core.datasource) implementation(projects.core.utils) implementation(projects.data.source.preferences) implementation(projects.domain.wallets) diff --git a/data/wallets/src/main/java/com/tangem/data/wallets/DefaultWalletsRepository.kt b/data/wallets/src/main/java/com/tangem/data/wallets/DefaultWalletsRepository.kt index 848735ca16..af326a1a45 100644 --- a/data/wallets/src/main/java/com/tangem/data/wallets/DefaultWalletsRepository.kt +++ b/data/wallets/src/main/java/com/tangem/data/wallets/DefaultWalletsRepository.kt @@ -1,16 +1,29 @@ package com.tangem.data.wallets -import com.tangem.data.source.preferences.PreferencesDataSource +import com.tangem.datasource.local.userwallet.ShouldSaveUserWalletStore import com.tangem.domain.wallets.repository.WalletsRepository import com.tangem.utils.coroutines.CoroutineDispatcherProvider +import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.withContext internal class DefaultWalletsRepository( - private val preferencesDataSource: PreferencesDataSource, + private val shouldSaveUserWalletStore: ShouldSaveUserWalletStore, private val dispatchers: CoroutineDispatcherProvider, ) : WalletsRepository { - override suspend fun shouldSaveUserWallets(): Boolean { - return withContext(dispatchers.io) { preferencesDataSource.shouldSaveUserWallets } + override suspend fun initialize() { + withContext(dispatchers.io) { + shouldSaveUserWalletStore.getSyncOrNull() ?: shouldSaveUserWalletStore.store(item = false) + } + } + + override suspend fun shouldSaveUserWalletsSync(): Boolean { + return withContext(dispatchers.io) { shouldSaveUserWalletStore.getSyncOrNull() ?: false } + } + + override fun shouldSaveUserWallets(): Flow = shouldSaveUserWalletStore.get() + + override suspend fun saveShouldSaveUserWallets(item: Boolean) { + withContext(dispatchers.io) { shouldSaveUserWalletStore.store(item = item) } } } \ No newline at end of file diff --git a/data/wallets/src/main/java/com/tangem/data/wallets/di/WalletsDataModule.kt b/data/wallets/src/main/java/com/tangem/data/wallets/di/WalletsDataModule.kt index 3f418202cb..80ff2c2567 100644 --- a/data/wallets/src/main/java/com/tangem/data/wallets/di/WalletsDataModule.kt +++ b/data/wallets/src/main/java/com/tangem/data/wallets/di/WalletsDataModule.kt @@ -1,7 +1,7 @@ package com.tangem.data.wallets.di -import com.tangem.data.source.preferences.PreferencesDataSource import com.tangem.data.wallets.DefaultWalletsRepository +import com.tangem.datasource.local.userwallet.ShouldSaveUserWalletStore import com.tangem.domain.wallets.repository.WalletsRepository import com.tangem.utils.coroutines.CoroutineDispatcherProvider import dagger.Module @@ -17,11 +17,11 @@ object WalletsDataModule { @Provides @Singleton fun providesWalletsRepository( - preferencesDataSource: PreferencesDataSource, + shouldSaveUserWalletStore: ShouldSaveUserWalletStore, coroutineDispatcherProvider: CoroutineDispatcherProvider, ): WalletsRepository { return DefaultWalletsRepository( - preferencesDataSource = preferencesDataSource, + shouldSaveUserWalletStore = shouldSaveUserWalletStore, dispatchers = coroutineDispatcherProvider, ) } diff --git a/domain/wallets/src/main/java/com/tangem/domain/wallets/repository/WalletsRepository.kt b/domain/wallets/src/main/java/com/tangem/domain/wallets/repository/WalletsRepository.kt index 7d5d65f233..6190b6d2e0 100644 --- a/domain/wallets/src/main/java/com/tangem/domain/wallets/repository/WalletsRepository.kt +++ b/domain/wallets/src/main/java/com/tangem/domain/wallets/repository/WalletsRepository.kt @@ -1,6 +1,14 @@ package com.tangem.domain.wallets.repository +import kotlinx.coroutines.flow.Flow + interface WalletsRepository { - suspend fun shouldSaveUserWallets(): Boolean + suspend fun initialize() + + suspend fun shouldSaveUserWalletsSync(): Boolean + + fun shouldSaveUserWallets(): Flow + + suspend fun saveShouldSaveUserWallets(item: Boolean) } \ No newline at end of file diff --git a/domain/wallets/src/main/java/com/tangem/domain/wallets/usecase/ShouldSaveUserWalletsSyncUseCase.kt b/domain/wallets/src/main/java/com/tangem/domain/wallets/usecase/ShouldSaveUserWalletsSyncUseCase.kt new file mode 100644 index 0000000000..16efc0eadb --- /dev/null +++ b/domain/wallets/src/main/java/com/tangem/domain/wallets/usecase/ShouldSaveUserWalletsSyncUseCase.kt @@ -0,0 +1,8 @@ +package com.tangem.domain.wallets.usecase + +import com.tangem.domain.wallets.repository.WalletsRepository + +class ShouldSaveUserWalletsSyncUseCase(private val walletsRepository: WalletsRepository) { + + suspend operator fun invoke(): Boolean = walletsRepository.shouldSaveUserWalletsSync() +} \ No newline at end of file diff --git a/domain/wallets/src/main/java/com/tangem/domain/wallets/usecase/ShouldSaveUserWalletsUseCase.kt b/domain/wallets/src/main/java/com/tangem/domain/wallets/usecase/ShouldSaveUserWalletsUseCase.kt index b21f04a003..fc62813050 100644 --- a/domain/wallets/src/main/java/com/tangem/domain/wallets/usecase/ShouldSaveUserWalletsUseCase.kt +++ b/domain/wallets/src/main/java/com/tangem/domain/wallets/usecase/ShouldSaveUserWalletsUseCase.kt @@ -1,8 +1,9 @@ package com.tangem.domain.wallets.usecase import com.tangem.domain.wallets.repository.WalletsRepository +import kotlinx.coroutines.flow.Flow class ShouldSaveUserWalletsUseCase(private val walletsRepository: WalletsRepository) { - suspend operator fun invoke(): Boolean = walletsRepository.shouldSaveUserWallets() + operator fun invoke(): Flow = walletsRepository.shouldSaveUserWallets() } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt index c06afd4d6b..e690d4303a 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt @@ -106,6 +106,7 @@ internal class WalletViewModel @Inject constructor( private val shouldShowSaveWalletScreenUseCase: ShouldShowSaveWalletScreenUseCase, private val canUseBiometryUseCase: CanUseBiometryUseCase, private val shouldSaveUserWalletsUseCase: ShouldSaveUserWalletsUseCase, + private val shouldSaveUserWalletsSyncUseCase: ShouldSaveUserWalletsSyncUseCase, private val isBalanceHiddenUseCase: IsBalanceHiddenUseCase, private val listenToFlipsUseCase: ListenToFlipsUseCase, private val removeCurrencyUseCase: RemoveCurrencyUseCase, @@ -182,12 +183,18 @@ internal class WalletViewModel @Inject constructor( } } - getWalletsUseCase() - .flowWithLifecycle(owner.lifecycle) - .distinctUntilChanged() - .onEach(::updateWallets) - .flowOn(dispatchers.io) - .launchIn(viewModelScope) + viewModelScope.launch(dispatchers.io) { + shouldSaveUserWalletsUseCase() + .flowWithLifecycle(owner.lifecycle) + .collectLatest { + getWalletsUseCase() + .flowWithLifecycle(owner.lifecycle) + .distinctUntilChanged() + .onEach(::updateWallets) + .flowOn(dispatchers.io) + .launchIn(viewModelScope) + } + } isBalanceHiddenUseCase() .flowWithLifecycle(owner.lifecycle) @@ -274,7 +281,7 @@ internal class WalletViewModel @Inject constructor( override fun onBackClick() { viewModelScope.launch(dispatchers.main) { - router.popBackStack(screen = if (shouldSaveUserWalletsUseCase()) AppScreen.Welcome else AppScreen.Home) + router.popBackStack(screen = if (shouldSaveUserWalletsSyncUseCase()) AppScreen.Welcome else AppScreen.Home) } }