diff --git a/data/settings/build.gradle.kts b/data/settings/build.gradle.kts index 3b71894edc..5bae11084f 100644 --- a/data/settings/build.gradle.kts +++ b/data/settings/build.gradle.kts @@ -13,6 +13,10 @@ android { namespace = "com.tangem.data.settings" } +tasks.withType().configureEach { + useJUnitPlatform() +} + dependencies { implementation(projects.core.datasource) @@ -28,6 +32,11 @@ dependencies { kapt(deps.hilt.kapt) // endregion + // region Test + testImplementation(projects.test.core) + testRuntimeOnly(deps.test.junit5.engine) + // endregion + // region Others dependencies implementation(deps.jodatime) implementation(deps.kotlin.coroutines) diff --git a/data/settings/src/main/java/com/tangem/data/settings/DevHotWalletRestrictionManager.kt b/data/settings/src/main/java/com/tangem/data/settings/DevHotWalletRestrictionManager.kt new file mode 100644 index 0000000000..87b20c09a8 --- /dev/null +++ b/data/settings/src/main/java/com/tangem/data/settings/DevHotWalletRestrictionManager.kt @@ -0,0 +1,56 @@ +package com.tangem.data.settings + +import androidx.datastore.preferences.core.booleanPreferencesKey +import com.tangem.datasource.local.preferences.AppPreferencesStore +import com.tangem.datasource.local.preferences.utils.get +import com.tangem.domain.settings.HotWalletRestrictionManager +import com.tangem.utils.coroutines.CoroutineDispatcherProvider +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.stateIn + +/** + * Development implementation of [HotWalletRestrictionManager]. + * + * Reads and writes the restriction state from [AppPreferencesStore], + * allowing testers to toggle it via the Tester Menu. + * The preference [Flow] is converted to a [StateFlow] on construction, + * so [isCreationEnabledSync] can be called from non-suspending contexts. + * Defaults to `true` (restriction enabled) when no value is stored. + */ +internal class DevHotWalletRestrictionManager( + private val appPreferencesStore: AppPreferencesStore, + dispatchers: CoroutineDispatcherProvider, +) : HotWalletRestrictionManager { + + private val isCreationEnabledState: StateFlow = + appPreferencesStore + .get(key = IS_HOT_WALLET_CREATION_RESTRICTION_ENABLED_KEY, default = true) + .stateIn( + scope = CoroutineScope(dispatchers.io + SupervisorJob()), + started = SharingStarted.Eagerly, + initialValue = true, + ) + + override fun isCreationEnabled(): StateFlow = isCreationEnabledState + + override fun isCreationEnabledSync(): Boolean = isCreationEnabledState.value + + override suspend fun toggleCreationEnabled() { + appPreferencesStore.editData { preferences -> + val isEnabled = preferences.getOrDefault( + key = IS_HOT_WALLET_CREATION_RESTRICTION_ENABLED_KEY, + default = true, + ) + preferences[IS_HOT_WALLET_CREATION_RESTRICTION_ENABLED_KEY] = !isEnabled + } + } + + private companion object { + val IS_HOT_WALLET_CREATION_RESTRICTION_ENABLED_KEY = + booleanPreferencesKey(name = "isHotWalletCreationRestrictionEnabled") + } +} \ No newline at end of file diff --git a/data/settings/src/main/java/com/tangem/data/settings/ProdHotWalletRestrictionManager.kt b/data/settings/src/main/java/com/tangem/data/settings/ProdHotWalletRestrictionManager.kt new file mode 100644 index 0000000000..0626befff2 --- /dev/null +++ b/data/settings/src/main/java/com/tangem/data/settings/ProdHotWalletRestrictionManager.kt @@ -0,0 +1,21 @@ +package com.tangem.data.settings + +import com.tangem.domain.settings.HotWalletRestrictionManager +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow + +/** + * Production implementation of [HotWalletRestrictionManager]. + * + * Hot wallet creation restriction is always enabled in production builds — + * users must scan a physical Tangem card to add a wallet. + * [toggleCreationEnabled] is a no-op since the restriction cannot be changed at runtime. + */ +internal class ProdHotWalletRestrictionManager : HotWalletRestrictionManager { + + private val state: StateFlow = MutableStateFlow(true) + + override fun isCreationEnabled(): StateFlow = state + override fun isCreationEnabledSync(): Boolean = true + override suspend fun toggleCreationEnabled() = Unit +} \ No newline at end of file diff --git a/data/settings/src/main/java/com/tangem/data/settings/di/SettingsDataModule.kt b/data/settings/src/main/java/com/tangem/data/settings/di/SettingsDataModule.kt index 8728678fe4..ebc5c40001 100644 --- a/data/settings/src/main/java/com/tangem/data/settings/di/SettingsDataModule.kt +++ b/data/settings/src/main/java/com/tangem/data/settings/di/SettingsDataModule.kt @@ -1,12 +1,16 @@ package com.tangem.data.settings.di import android.content.Context +import com.tangem.data.settings.BuildConfig import com.tangem.data.settings.DefaultAppRatingRepository import com.tangem.data.settings.DefaultPermissionRepository import com.tangem.data.settings.DefaultSettingsRepository +import com.tangem.data.settings.DevHotWalletRestrictionManager +import com.tangem.data.settings.ProdHotWalletRestrictionManager import com.tangem.datasource.api.tangemTech.TangemTechApi import com.tangem.datasource.local.logs.AppLogsStore import com.tangem.datasource.local.preferences.AppPreferencesStore +import com.tangem.domain.settings.HotWalletRestrictionManager import com.tangem.domain.settings.repositories.AppRatingRepository import com.tangem.domain.settings.repositories.PermissionRepository import com.tangem.domain.settings.repositories.SettingsRepository @@ -55,4 +59,17 @@ internal object SettingsDataModule { context = context, ) } + + @Provides + @Singleton + fun provideHotWalletRestrictionManager( + appPreferencesStore: AppPreferencesStore, + dispatchers: CoroutineDispatcherProvider, + ): HotWalletRestrictionManager { + return if (BuildConfig.TESTER_MENU_ENABLED) { + DevHotWalletRestrictionManager(appPreferencesStore, dispatchers) + } else { + ProdHotWalletRestrictionManager() + } + } } \ No newline at end of file diff --git a/data/settings/src/test/java/com/tangem/data/settings/DevHotWalletRestrictionManagerTest.kt b/data/settings/src/test/java/com/tangem/data/settings/DevHotWalletRestrictionManagerTest.kt new file mode 100644 index 0000000000..1cb2dacb6e --- /dev/null +++ b/data/settings/src/test/java/com/tangem/data/settings/DevHotWalletRestrictionManagerTest.kt @@ -0,0 +1,99 @@ +package com.tangem.data.settings + +import androidx.datastore.preferences.core.Preferences +import com.google.common.truth.Truth.assertThat +import com.tangem.datasource.local.preferences.AppPreferencesStore +import com.tangem.datasource.local.preferences.utils.get +import com.tangem.test.core.getEmittedValues +import com.tangem.utils.coroutines.CoroutineDispatcherProvider +import com.tangem.utils.coroutines.TestingCoroutineDispatcherProvider +import io.mockk.coEvery +import io.mockk.coVerify +import io.mockk.every +import io.mockk.mockk +import io.mockk.mockkStatic +import io.mockk.unmockkStatic +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.test.runTest +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.TestInstance + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class DevHotWalletRestrictionManagerTest { + + private val appPreferencesStore = mockk(relaxed = true) + private val dispatchers: CoroutineDispatcherProvider = TestingCoroutineDispatcherProvider() + + @BeforeEach + fun setup() { + mockkStatic("com.tangem.datasource.local.preferences.utils.PreferencesDataStoreExtKt") + } + + @AfterEach + fun tearDown() { + unmockkStatic("com.tangem.datasource.local.preferences.utils.PreferencesDataStoreExtKt") + } + + @Test + fun `GIVEN preference is true WHEN isCreationEnabled THEN emits true`() = runTest { + every { + appPreferencesStore.get(key = any>(), default = true) + } returns flowOf(true) + + val manager = DevHotWalletRestrictionManager(appPreferencesStore, dispatchers) + + val emitted = getEmittedValues(manager.isCreationEnabled()) + + assertThat(emitted).containsExactly(true) + } + + @Test + fun `GIVEN preference is false WHEN isCreationEnabled THEN emits false`() = runTest { + every { + appPreferencesStore.get(key = any>(), default = true) + } returns flowOf(false) + + val manager = DevHotWalletRestrictionManager(appPreferencesStore, dispatchers) + + val emitted = getEmittedValues(manager.isCreationEnabled()) + + assertThat(emitted).containsExactly(false) + } + + @Test + fun `GIVEN preference Flow emits true WHEN isCreationEnabledSync THEN returns cached true`() = runTest { + every { + appPreferencesStore.get(key = any>(), default = true) + } returns flowOf(true) + + val manager = DevHotWalletRestrictionManager(appPreferencesStore, dispatchers) + + assertThat(manager.isCreationEnabledSync()).isTrue() + } + + @Test + fun `GIVEN preference Flow emits false WHEN isCreationEnabledSync THEN returns cached false`() = runTest { + every { + appPreferencesStore.get(key = any>(), default = true) + } returns flowOf(false) + + val manager = DevHotWalletRestrictionManager(appPreferencesStore, dispatchers) + + assertThat(manager.isCreationEnabledSync()).isFalse() + } + + @Test + fun `WHEN toggleCreationEnabled THEN opens editData transaction`() = runTest { + every { + appPreferencesStore.get(key = any>(), default = true) + } returns flowOf(true) + coEvery { appPreferencesStore.editData(any()) } returns mockk(relaxed = true) + + val manager = DevHotWalletRestrictionManager(appPreferencesStore, dispatchers) + manager.toggleCreationEnabled() + + coVerify { appPreferencesStore.editData(any()) } + } +} \ No newline at end of file diff --git a/data/settings/src/test/java/com/tangem/data/settings/ProdHotWalletRestrictionManagerTest.kt b/data/settings/src/test/java/com/tangem/data/settings/ProdHotWalletRestrictionManagerTest.kt new file mode 100644 index 0000000000..32ca85becf --- /dev/null +++ b/data/settings/src/test/java/com/tangem/data/settings/ProdHotWalletRestrictionManagerTest.kt @@ -0,0 +1,31 @@ +package com.tangem.data.settings + +import com.google.common.truth.Truth.assertThat +import com.tangem.test.core.getEmittedValues +import kotlinx.coroutines.test.runTest +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.TestInstance + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class ProdHotWalletRestrictionManagerTest { + + private val manager = ProdHotWalletRestrictionManager() + + @Test + fun `WHEN isCreationEnabled THEN always emits true`() = runTest { + val emitted = getEmittedValues(manager.isCreationEnabled()) + + assertThat(emitted).containsExactly(true) + } + + @Test + fun `WHEN isCreationEnabledSync THEN returns true`() = runTest { + assertThat(manager.isCreationEnabledSync()).isTrue() + } + + @Test + fun `WHEN toggleCreationEnabled THEN isCreationEnabledSync still returns true`() = runTest { + manager.toggleCreationEnabled() + assertThat(manager.isCreationEnabledSync()).isTrue() + } +} \ No newline at end of file diff --git a/domain/settings/src/main/java/com/tangem/domain/settings/HotWalletRestrictionManager.kt b/domain/settings/src/main/java/com/tangem/domain/settings/HotWalletRestrictionManager.kt new file mode 100644 index 0000000000..dfae240b0f --- /dev/null +++ b/domain/settings/src/main/java/com/tangem/domain/settings/HotWalletRestrictionManager.kt @@ -0,0 +1,21 @@ +package com.tangem.domain.settings + +import kotlinx.coroutines.flow.StateFlow + +/** + * Manages the hot wallet creation restriction setting. + * + * When the restriction is enabled, users are forced to scan a physical Tangem card + * instead of being able to create a new software (hot) wallet. + */ +interface HotWalletRestrictionManager { + + /** Observes the current restriction state as a [StateFlow]. */ + fun isCreationEnabled(): StateFlow + + /** Returns the latest cached restriction state synchronously. */ + fun isCreationEnabledSync(): Boolean + + /** Toggles the restriction state. No-op in production. */ + suspend fun toggleCreationEnabled() +} \ No newline at end of file diff --git a/features/details/impl/build.gradle.kts b/features/details/impl/build.gradle.kts index 742988403b..7fc4587458 100644 --- a/features/details/impl/build.gradle.kts +++ b/features/details/impl/build.gradle.kts @@ -19,7 +19,6 @@ dependencies { implementation(projects.features.disclaimer.api) implementation(projects.features.tester.api) implementation(projects.features.createWalletSelection.api) - implementation(projects.features.hotWallet.api) implementation(projects.features.tangempay.details.api) /* Project - Core */ @@ -49,6 +48,7 @@ dependencies { implementation(projects.domain.balanceHiding) implementation(projects.domain.balanceHiding.models) implementation(projects.domain.legacy) + implementation(projects.domain.settings) implementation(projects.domain.visa) /* SDK */ diff --git a/features/details/impl/src/main/kotlin/com/tangem/features/details/component/preview/PreviewDetailsComponent.kt b/features/details/impl/src/main/kotlin/com/tangem/features/details/component/preview/PreviewDetailsComponent.kt index f8cde8a2e6..15b152f01b 100644 --- a/features/details/impl/src/main/kotlin/com/tangem/features/details/component/preview/PreviewDetailsComponent.kt +++ b/features/details/impl/src/main/kotlin/com/tangem/features/details/component/preview/PreviewDetailsComponent.kt @@ -6,13 +6,15 @@ import com.tangem.core.decompose.navigation.DummyRouter import com.tangem.core.navigation.url.DummyUrlOpener import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig import com.tangem.domain.models.wallet.UserWalletId +import com.tangem.domain.settings.HotWalletRestrictionManager import com.tangem.features.details.component.DetailsComponent import com.tangem.features.details.entity.DetailsFooterUM import com.tangem.features.details.entity.DetailsUM import com.tangem.features.details.ui.DetailsScreen import com.tangem.features.details.utils.ItemsBuilder import com.tangem.features.details.utils.SocialsBuilder -import com.tangem.features.hotwallet.HotWalletFeatureToggles +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.runBlocking internal class PreviewDetailsComponent : DetailsComponent { @@ -20,9 +22,10 @@ internal class PreviewDetailsComponent : DetailsComponent { private val previewBlocks = runBlocking { ItemsBuilder( router = DummyRouter(), - hotWalletFeatureToggles = object : HotWalletFeatureToggles { - override val isWalletCreationRestrictionEnabled: Boolean = true - override val isAssetsDiscoveryEnabled: Boolean = true + hotWalletRestrictionManager = object : HotWalletRestrictionManager { + override fun isCreationEnabled(): StateFlow = MutableStateFlow(true) + override fun isCreationEnabledSync(): Boolean = true + override suspend fun toggleCreationEnabled() = Unit }, ).buildAll( isWalletConnectAvailable = true, diff --git a/features/details/impl/src/main/kotlin/com/tangem/features/details/model/UserWalletListModel.kt b/features/details/impl/src/main/kotlin/com/tangem/features/details/model/UserWalletListModel.kt index 5c00ab323d..dfa422bab2 100644 --- a/features/details/impl/src/main/kotlin/com/tangem/features/details/model/UserWalletListModel.kt +++ b/features/details/impl/src/main/kotlin/com/tangem/features/details/model/UserWalletListModel.kt @@ -19,8 +19,8 @@ import com.tangem.domain.wallets.usecase.UnlockWalletUseCase import com.tangem.features.details.entity.UserWalletListUM import com.tangem.features.details.entity.WalletReorderUM import com.tangem.features.details.impl.R +import com.tangem.domain.settings.HotWalletRestrictionManager import com.tangem.features.details.utils.UserWalletSaver -import com.tangem.features.hotwallet.HotWalletFeatureToggles import com.tangem.features.wallet.featuretoggles.WalletFeatureToggles import com.tangem.features.wallet.utils.UserWalletsFetcher import com.tangem.utils.coroutines.CoroutineDispatcherProvider @@ -40,7 +40,7 @@ internal class UserWalletListModel @Inject constructor( private val messageSender: UiMessageSender, override val dispatchers: CoroutineDispatcherProvider, private val userWalletSaver: UserWalletSaver, - private val hotWalletFeatureToggles: HotWalletFeatureToggles, + private val hotWalletRestrictionManager: HotWalletRestrictionManager, private val unlockWalletUseCase: UnlockWalletUseCase, private val analyticsEventHandler: AnalyticsEventHandler, private val walletFeatureToggles: WalletFeatureToggles, @@ -48,6 +48,8 @@ internal class UserWalletListModel @Inject constructor( ) : Model() { private val isWalletSavingInProgress: MutableStateFlow = MutableStateFlow(value = false) + private val isWalletCreationRestrictionEnabled: StateFlow = + hotWalletRestrictionManager.isCreationEnabled() private val userWalletsFetcher = userWalletsFetcherFactory.create( messageSender = messageSender, onlyMultiCurrency = false, @@ -101,7 +103,7 @@ internal class UserWalletListModel @Inject constructor( private fun onAddNewWalletClick() { analyticsEventHandler.send(SignIn.ButtonAddWallet(AnalyticsParam.ScreensSources.Settings)) - if (hotWalletFeatureToggles.isWalletCreationRestrictionEnabled) { + if (isWalletCreationRestrictionEnabled.value) { withProgress(isWalletSavingInProgress) { userWalletSaver.scanAndSaveUserWallet(modelScope) } diff --git a/features/details/impl/src/main/kotlin/com/tangem/features/details/utils/ItemsBuilder.kt b/features/details/impl/src/main/kotlin/com/tangem/features/details/utils/ItemsBuilder.kt index 9746070c35..7bd5b7bd35 100644 --- a/features/details/impl/src/main/kotlin/com/tangem/features/details/utils/ItemsBuilder.kt +++ b/features/details/impl/src/main/kotlin/com/tangem/features/details/utils/ItemsBuilder.kt @@ -6,9 +6,9 @@ import com.tangem.core.decompose.navigation.Router import com.tangem.core.ui.components.block.model.BlockUM import com.tangem.core.ui.extensions.resourceReference import com.tangem.domain.models.wallet.UserWalletId +import com.tangem.domain.settings.HotWalletRestrictionManager import com.tangem.features.details.entity.DetailsItemUM import com.tangem.features.details.impl.R -import com.tangem.features.hotwallet.HotWalletFeatureToggles import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList @@ -20,7 +20,7 @@ private const val TANGEM_PAY_ITEM_ID = "get_tangem_pay" @ModelScoped internal class ItemsBuilder @Inject constructor( private val router: Router, - private val hotWalletFeatureToggles: HotWalletFeatureToggles, + private val hotWalletRestrictionManager: HotWalletRestrictionManager, ) { @Suppress("LongParameterList") @@ -36,7 +36,7 @@ internal class ItemsBuilder @Inject constructor( buildWalletConnectBlock(isWalletConnectAvailable, userWalletId)?.let(::add) buildUserWalletListBlock().let(::add) - if (hotWalletFeatureToggles.isWalletCreationRestrictionEnabled && hasAnyMobileWallet) { + if (hotWalletRestrictionManager.isCreationEnabledSync() && hasAnyMobileWallet) { DetailsItemUM.UnderSectionText( id = "only_one_mobile_wallet_explanation", text = resourceReference(R.string.only_one_mobile_wallet_explanation), diff --git a/features/tester/impl/build.gradle.kts b/features/tester/impl/build.gradle.kts index 3c61c2ed70..f96c63f4b4 100644 --- a/features/tester/impl/build.gradle.kts +++ b/features/tester/impl/build.gradle.kts @@ -31,8 +31,6 @@ dependencies { /** Domain modules */ implementation(projects.domain.account) - implementation(projects.domain.appTheme) - implementation(projects.domain.appTheme.models) implementation(projects.domain.card) implementation(projects.domain.feedback) implementation(projects.domain.markets.models) @@ -42,6 +40,7 @@ dependencies { implementation(projects.domain.wallets.models) implementation(projects.domain.wallets) implementation(projects.domain.feedback.models) + implementation(projects.domain.settings) implementation(projects.data.common) diff --git a/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/actions/TesterActionsContentState.kt b/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/actions/TesterActionsContentState.kt index 9307de43a7..fe09060e52 100644 --- a/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/actions/TesterActionsContentState.kt +++ b/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/actions/TesterActionsContentState.kt @@ -1,23 +1,23 @@ package com.tangem.feature.tester.presentation.actions import androidx.compose.runtime.Immutable -import com.tangem.domain.apptheme.model.AppThemeMode import java.io.File internal data class TesterActionsContentState( val hideAllCurrenciesUM: HideAllCurrenciesUM, - val toggleAppThemeUM: ToggleAppThemeUM, + val toggleHotWalletRestrictionUM: ToggleHotWalletRestrictionUM, val shareLogsUM: ShareLogsUM, val onBackClick: () -> Unit, ) { + @Immutable sealed class HideAllCurrenciesUM { data class Clickable(val onClick: () -> Unit) : HideAllCurrenciesUM() data object Progress : HideAllCurrenciesUM() } - data class ToggleAppThemeUM( - val currentAppTheme: AppThemeMode, + data class ToggleHotWalletRestrictionUM( + val isEnabled: Boolean, val onClick: () -> Unit, ) diff --git a/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/actions/TesterActionsScreen.kt b/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/actions/TesterActionsScreen.kt index bad48fc458..a3e947b392 100644 --- a/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/actions/TesterActionsScreen.kt +++ b/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/actions/TesterActionsScreen.kt @@ -22,10 +22,9 @@ import com.tangem.core.ui.extensions.stringResourceSafe import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.res.TangemThemePreview import com.tangem.core.ui.utils.findActivity -import com.tangem.domain.apptheme.model.AppThemeMode import com.tangem.feature.tester.impl.R import com.tangem.feature.tester.presentation.actions.TesterActionsContentState.HideAllCurrenciesUM -import com.tangem.feature.tester.presentation.actions.TesterActionsContentState.ToggleAppThemeUM +import com.tangem.feature.tester.presentation.actions.TesterActionsContentState.ToggleHotWalletRestrictionUM import com.tangem.utils.logging.TangemLogger import java.io.File @@ -57,10 +56,11 @@ internal fun TesterActionsScreen(state: TesterActionsContentState, modifier: Mod } item { - val config = state.toggleAppThemeUM + val config = state.toggleHotWalletRestrictionUM + val statusText = if (config.isEnabled) "ON" else "OFF" TesterActionItem( - name = stringResourceSafe(id = R.string.toggle_app_theme, config.currentAppTheme.name), + name = stringResourceSafe(id = R.string.toggle_hot_wallet_restriction, statusText), onClick = config.onClick, ) } @@ -125,7 +125,7 @@ private fun TesterActionsScreenSample(modifier: Modifier = Modifier) { TesterActionsScreen( state = TesterActionsContentState( hideAllCurrenciesUM = HideAllCurrenciesUM.Clickable {}, - toggleAppThemeUM = ToggleAppThemeUM(AppThemeMode.DEFAULT) {}, + toggleHotWalletRestrictionUM = ToggleHotWalletRestrictionUM(isEnabled = true) {}, shareLogsUM = TesterActionsContentState.ShareLogsUM(file = null), onBackClick = {}, ), diff --git a/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/actions/TesterActionsViewModel.kt b/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/actions/TesterActionsViewModel.kt index 5eeb879082..fb6e223f88 100644 --- a/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/actions/TesterActionsViewModel.kt +++ b/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/actions/TesterActionsViewModel.kt @@ -5,31 +5,25 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import arrow.core.getOrElse import com.tangem.data.common.account.WalletAccountsSaver -import com.tangem.domain.apptheme.ChangeAppThemeModeUseCase -import com.tangem.domain.apptheme.GetAppThemeModeUseCase -import com.tangem.domain.apptheme.model.AppThemeMode import com.tangem.domain.common.wallets.UserWalletsListRepository import com.tangem.domain.feedback.repository.FeedbackRepository +import com.tangem.domain.settings.HotWalletRestrictionManager import com.tangem.feature.tester.presentation.actions.TesterActionsContentState.HideAllCurrenciesUM -import com.tangem.feature.tester.presentation.actions.TesterActionsContentState.ToggleAppThemeUM +import com.tangem.feature.tester.presentation.actions.TesterActionsContentState.ToggleHotWalletRestrictionUM import com.tangem.feature.tester.presentation.navigation.InnerTesterRouter import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch -import com.tangem.utils.logging.TangemLogger import javax.inject.Inject @HiltViewModel internal class TesterActionsViewModel @Inject constructor( - private val changeAppThemeModeUseCase: ChangeAppThemeModeUseCase, - private val getAppThemeModeUseCase: GetAppThemeModeUseCase, private val feedbackRepository: FeedbackRepository, private val userWalletsListRepository: UserWalletsListRepository, private val walletAccountsSaver: WalletAccountsSaver, + private val hotWalletRestrictionManager: HotWalletRestrictionManager, ) : ViewModel() { var uiState: TesterActionsContentState by mutableStateOf(initialState) @@ -38,16 +32,16 @@ internal class TesterActionsViewModel @Inject constructor( private val initialState: TesterActionsContentState get() = TesterActionsContentState( hideAllCurrenciesUM = HideAllCurrenciesUM.Clickable(this::hideAllCurrencies), - toggleAppThemeUM = ToggleAppThemeUM( - currentAppTheme = AppThemeMode.DEFAULT, - onClick = this::toggleAppTheme, + toggleHotWalletRestrictionUM = ToggleHotWalletRestrictionUM( + isEnabled = hotWalletRestrictionManager.isCreationEnabledSync(), + onClick = this::toggleHotWalletRestriction, ), shareLogsUM = TesterActionsContentState.ShareLogsUM(file = feedbackRepository.getLogFile()), onBackClick = { /* no-op */ }, ) init { - bootstrapAppThemeModeUpdates() + bootstrapHotWalletRestrictionUpdates() } fun setupNavigation(router: InnerTesterRouter) { @@ -78,57 +72,16 @@ internal class TesterActionsViewModel @Inject constructor( ) } - private fun toggleAppTheme() = viewModelScope.launch { - val currentAppThemeMode = uiState.toggleAppThemeUM.currentAppTheme - val newAppThemeMode = when (currentAppThemeMode) { - AppThemeMode.FORCE_DARK -> AppThemeMode.FORCE_LIGHT - AppThemeMode.FORCE_LIGHT -> AppThemeMode.FOLLOW_SYSTEM - AppThemeMode.FOLLOW_SYSTEM -> AppThemeMode.FORCE_DARK - } - - TangemLogger.d( - """ - Change app theme mode - |- Current theme mode: $currentAppThemeMode - |- New theme mode: $newAppThemeMode - """.trimIndent(), - ) - - changeAppThemeModeUseCase(newAppThemeMode).onLeft { error -> - TangemLogger.e( - """ - Unable to change app theme mode - |- Error: $error - """.trimIndent(), - ) - } + private fun toggleHotWalletRestriction() = viewModelScope.launch { + hotWalletRestrictionManager.toggleCreationEnabled() } - private fun bootstrapAppThemeModeUpdates() { - getAppThemeModeUseCase() - .distinctUntilChanged() - .onEach { maybeAppThemeMode -> - TangemLogger.d( - """ - Current app theme mode updated - |- Previous app theme mode: ${uiState.toggleAppThemeUM.currentAppTheme} - |- New app theme mode: $maybeAppThemeMode - """.trimIndent(), - ) - + private fun bootstrapHotWalletRestrictionUpdates() { + hotWalletRestrictionManager.isCreationEnabled() + .onEach { isEnabled -> uiState = uiState.copy( - toggleAppThemeUM = uiState.toggleAppThemeUM.copy( - currentAppTheme = maybeAppThemeMode.getOrElse { error -> - TangemLogger.e( - """ - Unable to get current app theme mode, using default - |- Default theme mode: ${AppThemeMode.DEFAULT} - |- Error: $error - """.trimIndent(), - ) - - AppThemeMode.DEFAULT - }, + toggleHotWalletRestrictionUM = uiState.toggleHotWalletRestrictionUM.copy( + isEnabled = isEnabled, ), ) } diff --git a/features/tester/impl/src/main/res/values/strings.xml b/features/tester/impl/src/main/res/values/strings.xml index f6d9e5cf50..5edc7e890f 100644 --- a/features/tester/impl/src/main/res/values/strings.xml +++ b/features/tester/impl/src/main/res/values/strings.xml @@ -11,10 +11,10 @@ Environment toggles Tester actions Hide all currencies - Toggle app theme - %s Excluded blockchains Filter by name or symbol Blockchain providers + Hot wallet creation restriction - %s Share logs Test push Accounts diff --git a/features/welcome/impl/build.gradle.kts b/features/welcome/impl/build.gradle.kts index e21ec865c7..11cc45a04f 100644 --- a/features/welcome/impl/build.gradle.kts +++ b/features/welcome/impl/build.gradle.kts @@ -14,7 +14,6 @@ android { dependencies { implementation(projects.features.welcome.api) implementation(projects.features.wallet.api) - implementation(projects.features.hotWallet.api) /** Core */ implementation(projects.core.configToggles) diff --git a/features/welcome/impl/src/main/kotlin/com/tangem/features/welcome/impl/model/WelcomeModel.kt b/features/welcome/impl/src/main/kotlin/com/tangem/features/welcome/impl/model/WelcomeModel.kt index 5c16293dd7..5ecd009e00 100644 --- a/features/welcome/impl/src/main/kotlin/com/tangem/features/welcome/impl/model/WelcomeModel.kt +++ b/features/welcome/impl/src/main/kotlin/com/tangem/features/welcome/impl/model/WelcomeModel.kt @@ -23,11 +23,11 @@ import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.models.wallet.UserWalletId import com.tangem.domain.models.wallet.isLocked import com.tangem.domain.settings.CanUseBiometryUseCase +import com.tangem.domain.settings.HotWalletRestrictionManager import com.tangem.domain.wallets.builder.ColdUserWalletBuilder import com.tangem.domain.wallets.repository.WalletsRepository import com.tangem.domain.wallets.usecase.NonBiometricUnlockWalletUseCase import com.tangem.domain.wallets.usecase.SaveWalletUseCase -import com.tangem.features.hotwallet.HotWalletFeatureToggles import com.tangem.features.wallet.utils.UserWalletsFetcher import com.tangem.features.welcome.impl.ui.state.WelcomeUM import com.tangem.utils.coroutines.CoroutineDispatcherProvider @@ -54,7 +54,7 @@ internal class WelcomeModel @Inject constructor( private val trackingContextProxy: TrackingContextProxy, private val analyticsEventHandler: AnalyticsEventHandler, userWalletsFetcherFactory: UserWalletsFetcher.Factory, - private val hotWalletFeatureToggles: HotWalletFeatureToggles, + private val hotWalletRestrictionManager: HotWalletRestrictionManager, private val scanCardProcessor: ScanCardProcessor, private val messageSender: UiMessageSender, ) : Model() { @@ -90,6 +90,8 @@ internal class WelcomeModel @Inject constructor( private val walletsFetcherJobHolder = JobHolder() private val wallets = MutableStateFlow>(persistentListOf()) private var routedOut = false + private val isWalletCreationRestrictionEnabled: StateFlow = + hotWalletRestrictionManager.isCreationEnabled() init { modelScope.launch { @@ -181,7 +183,7 @@ internal class WelcomeModel @Inject constructor( private fun addWalletClick() { analyticsEventHandler.send(SignIn.ButtonAddWallet(AnalyticsParam.ScreensSources.SignIn)) - if (hotWalletFeatureToggles.isWalletCreationRestrictionEnabled) { + if (isWalletCreationRestrictionEnabled.value) { scanCard() } else { router.push(AppRoute.CreateWalletSelection)