diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 6f39ce42e9..36145b0415 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -188,6 +188,8 @@ dependencies { implementation(projects.features.stories.impl) implementation(projects.features.txhistory.api) implementation(projects.features.txhistory.impl) + implementation(projects.features.nft.api) + implementation(projects.features.nft.impl) /** AndroidX libraries */ implementation(deps.androidx.core.ktx) diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/preferences/PreferencesKeys.kt b/core/datasource/src/main/java/com/tangem/datasource/local/preferences/PreferencesKeys.kt index 52d244da2b..50275788dd 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/local/preferences/PreferencesKeys.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/local/preferences/PreferencesKeys.kt @@ -121,7 +121,7 @@ object PreferencesKeys { val SEED_FIRST_NOTIFICATION_SHOW_TIME by lazy { longPreferencesKey("seedFirstNotificationTime") } - val WALLETS_WITH_NFT_ENABLED_KEY by lazy { stringSetPreferencesKey(name = "walletsWithNftEnabled") } + val WALLETS_NFT_ENABLED_STATES_KEY by lazy { stringPreferencesKey(name = "walletsNftEnabledStates") } fun getShouldShowStoriesKey(storyId: String) = booleanPreferencesKey("shouldShowStories_$storyId") 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 e8a5b95b08..f2cb51f52a 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 @@ -11,6 +11,7 @@ import com.tangem.datasource.local.preferences.AppPreferencesStore import com.tangem.datasource.local.preferences.PreferencesKeys import com.tangem.datasource.local.preferences.PreferencesKeys.SEED_FIRST_NOTIFICATION_SHOW_TIME import com.tangem.datasource.local.preferences.utils.get +import com.tangem.datasource.local.preferences.utils.getObjectMap import com.tangem.datasource.local.preferences.utils.getSyncOrDefault import com.tangem.datasource.local.preferences.utils.store import com.tangem.datasource.local.userwallet.UserWalletsStore @@ -205,21 +206,27 @@ internal class DefaultWalletsRepository( override fun nftEnabledStatus(userWalletId: UserWalletId): Flow { return appPreferencesStore - .get(key = PreferencesKeys.WALLETS_WITH_NFT_ENABLED_KEY, default = emptySet()) - .map { it.contains(userWalletId.stringValue) } + .getObjectMap(PreferencesKeys.WALLETS_NFT_ENABLED_STATES_KEY) + .map { !it.contains(userWalletId.stringValue) || it[userWalletId.stringValue] == true } } override suspend fun enableNFT(userWalletId: UserWalletId) { appPreferencesStore.editData { - val added = it[PreferencesKeys.WALLETS_WITH_NFT_ENABLED_KEY].orEmpty() - it[PreferencesKeys.WALLETS_WITH_NFT_ENABLED_KEY] = added + userWalletId.stringValue + it.setObjectMap( + PreferencesKeys.WALLETS_NFT_ENABLED_STATES_KEY, + it.getObjectMap(PreferencesKeys.WALLETS_NFT_ENABLED_STATES_KEY) + .plus(userWalletId.stringValue to true), + ) } } override suspend fun disableNFT(userWalletId: UserWalletId) { appPreferencesStore.editData { - val added = it[PreferencesKeys.WALLETS_WITH_NFT_ENABLED_KEY].orEmpty() - it[PreferencesKeys.WALLETS_WITH_NFT_ENABLED_KEY] = added - userWalletId.stringValue + it.setObjectMap( + PreferencesKeys.WALLETS_NFT_ENABLED_STATES_KEY, + it.getObjectMap(PreferencesKeys.WALLETS_NFT_ENABLED_STATES_KEY) + .plus(userWalletId.stringValue to false), + ) } } } \ No newline at end of file diff --git a/features/nft/impl/build.gradle.kts b/features/nft/impl/build.gradle.kts index 0de9bbcd2d..40d3b149c9 100644 --- a/features/nft/impl/build.gradle.kts +++ b/features/nft/impl/build.gradle.kts @@ -32,8 +32,8 @@ dependencies { /** Tangem libraries */ implementation(projects.libs.tangemSdkApi) - implementation(deps.tangem.card.core) - implementation(deps.tangem.card.android) { + implementation(tangemDeps.card.core) + implementation(tangemDeps.card.android) { exclude(module = "joda-time") } diff --git a/features/wallet-settings/impl/build.gradle.kts b/features/wallet-settings/impl/build.gradle.kts index 9bad883a97..ca5f65ffc4 100644 --- a/features/wallet-settings/impl/build.gradle.kts +++ b/features/wallet-settings/impl/build.gradle.kts @@ -16,6 +16,7 @@ dependencies { /* Project - API */ implementation(projects.features.walletSettings.api) implementation(projects.features.manageTokens.api) + implementation(projects.features.nft.api) /* Project - Core */ implementation(projects.core.decompose) diff --git a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/component/preview/PreviewWalletSettingsComponent.kt b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/component/preview/PreviewWalletSettingsComponent.kt index 47d910bafc..4e77769e0d 100644 --- a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/component/preview/PreviewWalletSettingsComponent.kt +++ b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/component/preview/PreviewWalletSettingsComponent.kt @@ -23,6 +23,9 @@ internal class PreviewWalletSettingsComponent : WalletSettingsComponent { isReferralAvailable = true, isLinkMoreCardsAvailable = true, isRenameWalletAvailable = false, + isNFTFeatureEnabled = true, + isNFTEnabled = true, + onCheckedNFTChange = {}, renameWallet = {}, forgetWallet = {}, onLinkMoreCardsClick = {}, diff --git a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/entity/WalletSettingsItemUM.kt b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/entity/WalletSettingsItemUM.kt index ee17e4637b..3e2eb34bad 100644 --- a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/entity/WalletSettingsItemUM.kt +++ b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/entity/WalletSettingsItemUM.kt @@ -16,6 +16,13 @@ internal sealed class WalletSettingsItemUM { val blocks: ImmutableList, ) : WalletSettingsItemUM() + data class WithSwitch( + override val id: String, + val title: TextReference, + val isChecked: Boolean, + val onCheckedChange: (Boolean) -> Unit, + ) : WalletSettingsItemUM() + data class WithText( override val id: String, val title: TextReference, diff --git a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/model/WalletSettingsModel.kt b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/model/WalletSettingsModel.kt index 388279ff22..cbf8bafda7 100644 --- a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/model/WalletSettingsModel.kt +++ b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/model/WalletSettingsModel.kt @@ -21,6 +21,7 @@ import com.tangem.domain.models.scan.ScanResponse import com.tangem.domain.redux.LegacyAction import com.tangem.domain.redux.ReduxStateHolder import com.tangem.domain.wallets.models.UserWallet +import com.tangem.domain.wallets.repository.WalletsRepository import com.tangem.domain.wallets.usecase.DeleteWalletUseCase import com.tangem.domain.wallets.usecase.GetUserWalletUseCase import com.tangem.domain.wallets.usecase.ShouldSaveUserWalletsSyncUseCase @@ -31,6 +32,7 @@ import com.tangem.feature.walletsettings.entity.WalletSettingsItemUM import com.tangem.feature.walletsettings.entity.WalletSettingsUM import com.tangem.feature.walletsettings.impl.R import com.tangem.feature.walletsettings.utils.ItemsBuilder +import com.tangem.features.nft.NFTFeatureToggles import com.tangem.utils.coroutines.CoroutineDispatcherProvider import kotlinx.collections.immutable.PersistentList import kotlinx.collections.immutable.persistentListOf @@ -53,6 +55,8 @@ internal class WalletSettingsModel @Inject constructor( private val analyticsContextProxy: AnalyticsContextProxy, private val reduxStateHolder: ReduxStateHolder, private val getShouldSaveUserWalletsSyncUseCase: ShouldSaveUserWalletsSyncUseCase, + private val walletsRepository: WalletsRepository, + private val nftFeatureToggles: NFTFeatureToggles, ) : Model() { val params: WalletSettingsComponent.Params = paramsContainer.require() @@ -68,11 +72,19 @@ internal class WalletSettingsModel @Inject constructor( init { getWalletUseCase.invokeFlow(params.userWalletId) .distinctUntilChanged() - .onEach { maybeWallet -> - val wallet = maybeWallet.getOrNull() ?: return@onEach + .combine(walletsRepository.nftEnabledStatus(params.userWalletId)) { maybeWallet, nftEnabled -> + val wallet = maybeWallet.getOrNull() ?: return@combine val isRenameWalletAvailable = getShouldSaveUserWalletsSyncUseCase() state.update { value -> - value.copy(items = buildItems(wallet, dialogNavigation, isRenameWalletAvailable)) + value.copy( + items = buildItems( + userWallet = wallet, + dialogNavigation = dialogNavigation, + isRenameWalletAvailable = isRenameWalletAvailable, + isNFTFeatureEnabled = nftFeatureToggles.isNFTEnabled, + isNFTEnabled = nftEnabled, + ), + ) } } .launchIn(modelScope) @@ -82,6 +94,8 @@ internal class WalletSettingsModel @Inject constructor( userWallet: UserWallet, dialogNavigation: SlotNavigation, isRenameWalletAvailable: Boolean, + isNFTFeatureEnabled: Boolean, + isNFTEnabled: Boolean, ): PersistentList = itemsBuilder.buildItems( userWalletId = userWallet.walletId, userWalletName = userWallet.name, @@ -90,6 +104,11 @@ internal class WalletSettingsModel @Inject constructor( isManageTokensAvailable = userWallet.isMultiCurrency, isRenameWalletAvailable = isRenameWalletAvailable, renameWallet = { openRenameWalletDialog(userWallet, dialogNavigation) }, + isNFTFeatureEnabled = isNFTFeatureEnabled, + isNFTEnabled = isNFTEnabled, + onCheckedNFTChange = { isChecked -> + onCheckedNFTChange(isChecked) + }, forgetWallet = { val message = DialogMessage( message = resourceReference(R.string.user_wallet_list_delete_prompt), @@ -151,4 +170,14 @@ internal class WalletSettingsModel @Inject constructor( router.push(AppRoute.OnboardingWallet()) } + + private fun onCheckedNFTChange(isChecked: Boolean) { + modelScope.launch { + if (isChecked) { + walletsRepository.enableNFT(params.userWalletId) + } else { + walletsRepository.disableNFT(params.userWalletId) + } + } + } } \ No newline at end of file diff --git a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/ui/WalletSettingsScreen.kt b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/ui/WalletSettingsScreen.kt index b2c0270b20..675e86d521 100644 --- a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/ui/WalletSettingsScreen.kt +++ b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/ui/WalletSettingsScreen.kt @@ -14,6 +14,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.platform.testTag import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview +import com.tangem.core.ui.components.TangemSwitch import com.tangem.core.ui.components.appbar.TangemTopAppBar import com.tangem.core.ui.components.appbar.models.TopAppBarButtonUM import com.tangem.core.ui.components.block.BlockCard @@ -96,6 +97,10 @@ private fun Content(state: WalletSettingsUM, modifier: Modifier = Modifier) { modifier = itemModifier, model = item, ) + is WalletSettingsItemUM.WithSwitch -> SwitchBlock( + modifier = itemModifier, + model = item, + ) } } } @@ -165,6 +170,34 @@ private fun TextBlock(model: WalletSettingsItemUM.WithText, modifier: Modifier = } } +@Composable +private fun SwitchBlock(model: WalletSettingsItemUM.WithSwitch, modifier: Modifier = Modifier) { + BlockCard( + modifier = modifier.fillMaxWidth(), + enabled = model.isChecked, + ) { + Row( + modifier = Modifier.padding(all = TangemTheme.dimens.spacing12), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing12, Alignment.Start), + ) { + Text( + modifier = Modifier.weight(1f), + text = model.title.resolveReference(), + style = TangemTheme.typography.subtitle1, + color = TangemTheme.colors.text.primary1, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + ) + + TangemSwitch( + checked = model.isChecked, + onCheckedChange = model.onCheckedChange, + ) + } + } +} + // region Preview @Composable @Preview(showBackground = true, widthDp = 360) diff --git a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/utils/ItemsBuilder.kt b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/utils/ItemsBuilder.kt index e57d76ef57..75fbbc0e4b 100644 --- a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/utils/ItemsBuilder.kt +++ b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/utils/ItemsBuilder.kt @@ -31,20 +31,31 @@ internal class ItemsBuilder @Inject constructor( isReferralAvailable: Boolean, isManageTokensAvailable: Boolean, isRenameWalletAvailable: Boolean, + isNFTFeatureEnabled: Boolean, + isNFTEnabled: Boolean, + onCheckedNFTChange: (Boolean) -> Unit, forgetWallet: () -> Unit, renameWallet: () -> Unit, onLinkMoreCardsClick: () -> Unit, - ): PersistentList = persistentListOf( - buildNameItem(userWalletName, isRenameWalletAvailable, renameWallet), - buildCardItem( - userWalletId = userWalletId, - isLinkMoreCardsAvailable = isLinkMoreCardsAvailable, - isReferralAvailable = isReferralAvailable, - isManageTokensAvailable = isManageTokensAvailable, - onLinkMoreCardsClick = onLinkMoreCardsClick, - ), - buildForgetItem(forgetWallet), - ) + ): PersistentList = persistentListOf() + .add(buildNameItem(userWalletName, isRenameWalletAvailable, renameWallet)) + .run { + if (isNFTFeatureEnabled) { + add(buildNFTItem(isNFTEnabled, onCheckedNFTChange)) + } else { + this + } + } + .add( + buildCardItem( + userWalletId = userWalletId, + isLinkMoreCardsAvailable = isLinkMoreCardsAvailable, + isReferralAvailable = isReferralAvailable, + isManageTokensAvailable = isManageTokensAvailable, + onLinkMoreCardsClick = onLinkMoreCardsClick, + ), + ) + .add(buildForgetItem(forgetWallet)) private fun buildNameItem(walletName: String, isRenameWalletAvailable: Boolean, renameWallet: () -> Unit) = WalletSettingsItemUM.WithText( @@ -55,6 +66,14 @@ internal class ItemsBuilder @Inject constructor( onClick = renameWallet, ) + private fun buildNFTItem(isNFTEnabled: Boolean, onCheckedNFTChange: (Boolean) -> Unit) = + WalletSettingsItemUM.WithSwitch( + id = "nft", + title = resourceReference(id = R.string.details_nft_title), + isChecked = isNFTEnabled, + onCheckedChange = onCheckedNFTChange, + ) + private fun buildCardItem( userWalletId: UserWalletId, isLinkMoreCardsAvailable: Boolean, diff --git a/settings.gradle.kts b/settings.gradle.kts index 2e31c05b4e..73be74c713 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -227,6 +227,9 @@ include(":features:stories:impl") include(":features:txhistory:api") include(":features:txhistory:impl") + +include(":features:nft:api") +include(":features:nft:impl") // endregion Feature modules // region Domain modules