Updated on 2026-08-14
This commit is contained in:
parent
aa03d39dc0
commit
49bd0090ff
18 changed files with 300 additions and 88 deletions
|
|
@ -13,6 +13,10 @@ android {
|
|||
namespace = "com.tangem.data.settings"
|
||||
}
|
||||
|
||||
tasks.withType<Test>().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)
|
||||
|
|
|
|||
|
|
@ -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<Boolean> =
|
||||
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<Boolean> = 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")
|
||||
}
|
||||
}
|
||||
|
|
@ -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<Boolean> = MutableStateFlow(true)
|
||||
|
||||
override fun isCreationEnabled(): StateFlow<Boolean> = state
|
||||
override fun isCreationEnabledSync(): Boolean = true
|
||||
override suspend fun toggleCreationEnabled() = Unit
|
||||
}
|
||||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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<AppPreferencesStore>(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<Preferences.Key<Boolean>>(), 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<Preferences.Key<Boolean>>(), 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<Preferences.Key<Boolean>>(), 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<Preferences.Key<Boolean>>(), 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<Preferences.Key<Boolean>>(), default = true)
|
||||
} returns flowOf(true)
|
||||
coEvery { appPreferencesStore.editData(any()) } returns mockk(relaxed = true)
|
||||
|
||||
val manager = DevHotWalletRestrictionManager(appPreferencesStore, dispatchers)
|
||||
manager.toggleCreationEnabled()
|
||||
|
||||
coVerify { appPreferencesStore.editData(any()) }
|
||||
}
|
||||
}
|
||||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
@ -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<Boolean>
|
||||
|
||||
/** Returns the latest cached restriction state synchronously. */
|
||||
fun isCreationEnabledSync(): Boolean
|
||||
|
||||
/** Toggles the restriction state. No-op in production. */
|
||||
suspend fun toggleCreationEnabled()
|
||||
}
|
||||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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<Boolean> = MutableStateFlow(true)
|
||||
override fun isCreationEnabledSync(): Boolean = true
|
||||
override suspend fun toggleCreationEnabled() = Unit
|
||||
},
|
||||
).buildAll(
|
||||
isWalletConnectAvailable = true,
|
||||
|
|
|
|||
|
|
@ -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<Boolean> = MutableStateFlow(value = false)
|
||||
private val isWalletCreationRestrictionEnabled: StateFlow<Boolean> =
|
||||
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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -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 = {},
|
||||
),
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,10 +11,10 @@
|
|||
<string name="environment_toggles" translatable="false">Environment toggles</string>
|
||||
<string name="tester_actions" translatable="false">Tester actions</string>
|
||||
<string name="hide_all_currencies" translatable="false">Hide all currencies</string>
|
||||
<string name="toggle_app_theme" translatable="false">Toggle app theme - %s</string>
|
||||
<string name="excluded_blockchains" translatable="false">Excluded blockchains</string>
|
||||
<string name="excluded_blockchains_search_placeholder" translatable="false">Filter by name or symbol</string>
|
||||
<string name="blockchain_providers" translatable="false">Blockchain providers</string>
|
||||
<string name="toggle_hot_wallet_restriction" translatable="false">Hot wallet creation restriction - %s</string>
|
||||
<string name="share_logs" translatable="false">Share logs</string>
|
||||
<string name="test_push" translatable="false">Test push</string>
|
||||
<string name="accounts" translatable="false">Accounts</string>
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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<ImmutableList<UserWalletItemUM>>(persistentListOf())
|
||||
private var routedOut = false
|
||||
private val isWalletCreationRestrictionEnabled: StateFlow<Boolean> =
|
||||
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)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue