From efcb0dea7966515c5493fe8ee8779d5c06fac4d8 Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 30 May 2025 18:22:42 +0500 Subject: [PATCH] Updated on 2026-08-14 --- .../di/domain/NotificationsDomainModule.kt | 13 +- .../items/NetworkNameAndSymbolItem.kt | 77 ++++++++ .../main/res/drawable/ic_notification_48.xml | 31 ++++ data/notifications/build.gradle.kts | 5 + .../DefaultNotificationsRepository.kt | 2 +- .../NotificationsEligibleNetworkConverter.kt | 16 +- .../DefaultNotificationsRepositoryTest.kt | 2 +- .../models/NotificationsEligibleNetwork.kt | 3 +- ...etworksAvailableForNotificationsUseCase.kt | 14 ++ ...worksAvailableForNotificationsComponent.kt | 13 ++ .../wallet-settings/impl/build.gradle.kts | 2 + ...worksAvailableForNotificationsComponent.kt | 40 ++++ .../impl/DefaultWalletSettingsComponent.kt | 28 +++ .../NetworksAvailableForNotificationsModel.kt | 40 ++++ .../di/WalletSettingsComponentModule.kt | 8 + .../di/WalletSettingsModelModule.kt | 6 + ...etworksAvailableForNotificationBSConfig.kt | 6 + .../model/WalletSettingsModel.kt | 8 +- ...NetworksAvailableForNotificationsListBS.kt | 171 ++++++++++++++++++ .../NetworksAvailableForNotificationsUM.kt | 9 + 20 files changed, 477 insertions(+), 17 deletions(-) create mode 100644 core/ui/src/main/java/com/tangem/core/ui/components/items/NetworkNameAndSymbolItem.kt create mode 100644 core/ui/src/main/res/drawable/ic_notification_48.xml create mode 100644 domain/notifications/src/main/java/com/tangem/domain/notifications/GetNetworksAvailableForNotificationsUseCase.kt create mode 100644 features/wallet-settings/api/src/main/kotlin/com/tangem/feature/walletsettings/component/NetworksAvailableForNotificationsComponent.kt create mode 100644 features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/component/impl/DefaultNetworksAvailableForNotificationsComponent.kt create mode 100644 features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/component/impl/model/NetworksAvailableForNotificationsModel.kt create mode 100644 features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/entity/NetworksAvailableForNotificationBSConfig.kt create mode 100644 features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/ui/NetworksAvailableForNotificationsListBS.kt create mode 100644 features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/ui/state/NetworksAvailableForNotificationsUM.kt diff --git a/app/src/main/java/com/tangem/tap/di/domain/NotificationsDomainModule.kt b/app/src/main/java/com/tangem/tap/di/domain/NotificationsDomainModule.kt index 14df43efb0..c7b61fd1e0 100644 --- a/app/src/main/java/com/tangem/tap/di/domain/NotificationsDomainModule.kt +++ b/app/src/main/java/com/tangem/tap/di/domain/NotificationsDomainModule.kt @@ -1,10 +1,7 @@ package com.tangem.tap.di.domain import com.tangem.core.configtoggle.feature.FeatureTogglesManager -import com.tangem.domain.notifications.GetApplicationIdUseCase -import com.tangem.domain.notifications.GetTronFeeNotificationShowCountUseCase -import com.tangem.domain.notifications.IncrementNotificationsShowCountUseCase -import com.tangem.domain.notifications.SendPushTokenUseCase +import com.tangem.domain.notifications.* import com.tangem.domain.notifications.repository.NotificationsRepository import com.tangem.domain.notifications.toggles.NotificationsFeatureToggles import com.tangem.tap.domain.notifications.DefaultNotificationsFeatureToggles @@ -64,4 +61,12 @@ internal object NotificationsDomainModule { fun provideNotificationsFeatureToggles(featureTogglesManager: FeatureTogglesManager): NotificationsFeatureToggles { return DefaultNotificationsFeatureToggles(featureTogglesManager = featureTogglesManager) } + + @Provides + @Singleton + fun provideGetNetworksAvailableForNotifications( + notificationsRepository: NotificationsRepository, + ): GetNetworksAvailableForNotificationsUseCase { + return GetNetworksAvailableForNotificationsUseCase(notificationsRepository = notificationsRepository) + } } \ No newline at end of file diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/items/NetworkNameAndSymbolItem.kt b/core/ui/src/main/java/com/tangem/core/ui/components/items/NetworkNameAndSymbolItem.kt new file mode 100644 index 0000000000..ac61fcce71 --- /dev/null +++ b/core/ui/src/main/java/com/tangem/core/ui/components/items/NetworkNameAndSymbolItem.kt @@ -0,0 +1,77 @@ +package com.tangem.core.ui.components.items + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.* +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.tangem.core.ui.R +import com.tangem.core.ui.components.CircleShimmer +import com.tangem.core.ui.components.TextShimmer +import com.tangem.core.ui.res.TangemTheme +import com.tangem.core.ui.res.TangemThemePreview + +@Composable +fun NetworkNameAndSymbolItem(icon: Int, name: String, symbol: String, modifier: Modifier = Modifier) { + Row( + modifier = modifier.padding(14.dp), + horizontalArrangement = Arrangement.spacedBy(4.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + Image( + modifier = Modifier + .padding(end = 8.dp) + .size(24.dp), + painter = painterResource(icon), + contentDescription = null, + ) + Text( + modifier = Modifier.weight(1f, fill = false), + text = name, + style = TangemTheme.typography.subtitle2, + color = TangemTheme.colors.text.primary1, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + ) + Text(text = symbol, style = TangemTheme.typography.caption1, color = TangemTheme.colors.text.tertiary) + } +} + +@Composable +fun NetworkNameAndSymbolItemShimmer(modifier: Modifier = Modifier) { + Row( + modifier = modifier.padding(12.dp), + horizontalArrangement = Arrangement.spacedBy(4.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + CircleShimmer( + modifier = Modifier + .padding(end = 8.dp) + .size(24.dp), + ) + TextShimmer( + style = TangemTheme.typography.subtitle2, + modifier = Modifier.width(70.dp), + ) + } +} + +@Preview +@Composable +private fun ContentPreview() { + TangemThemePreview { + Column { + NetworkNameAndSymbolItemShimmer() + NetworkNameAndSymbolItem( + icon = R.drawable.ic_solana_16, + name = "Solana", + symbol = "SOL", + ) + } + } +} \ No newline at end of file diff --git a/core/ui/src/main/res/drawable/ic_notification_48.xml b/core/ui/src/main/res/drawable/ic_notification_48.xml new file mode 100644 index 0000000000..c75fbdc5cc --- /dev/null +++ b/core/ui/src/main/res/drawable/ic_notification_48.xml @@ -0,0 +1,31 @@ + + + + + + diff --git a/data/notifications/build.gradle.kts b/data/notifications/build.gradle.kts index b3c107f390..a54a8c6725 100644 --- a/data/notifications/build.gradle.kts +++ b/data/notifications/build.gradle.kts @@ -10,6 +10,9 @@ android { } dependencies { + // region sdk + implementation(tangemDeps.blockchain) + // endregion // region AndroidX libraries implementation(deps.androidx.datastore) @@ -28,6 +31,8 @@ dependencies { // region Core modules implementation(projects.core.datasource) implementation(projects.core.utils) + implementation(projects.core.ui) + implementation(projects.libs.blockchainSdk) // endregion // region Domain modules diff --git a/data/notifications/src/main/java/com/tangem/data/notifications/DefaultNotificationsRepository.kt b/data/notifications/src/main/java/com/tangem/data/notifications/DefaultNotificationsRepository.kt index d0ea5837e7..2adc501d9c 100644 --- a/data/notifications/src/main/java/com/tangem/data/notifications/DefaultNotificationsRepository.kt +++ b/data/notifications/src/main/java/com/tangem/data/notifications/DefaultNotificationsRepository.kt @@ -73,7 +73,7 @@ internal class DefaultNotificationsRepository @Inject constructor( } override suspend fun getEligibleNetworks(): List = withContext(dispatchers.io) { - tangemTechApi.getEligibleNetworksForPushNotifications().getOrThrow().map { + tangemTechApi.getEligibleNetworksForPushNotifications().getOrThrow().mapNotNull { NotificationsEligibleNetworkConverter.convert(it) } } diff --git a/data/notifications/src/main/java/com/tangem/data/notifications/converters/NotificationsEligibleNetworkConverter.kt b/data/notifications/src/main/java/com/tangem/data/notifications/converters/NotificationsEligibleNetworkConverter.kt index 471dd0b137..403718705e 100644 --- a/data/notifications/src/main/java/com/tangem/data/notifications/converters/NotificationsEligibleNetworkConverter.kt +++ b/data/notifications/src/main/java/com/tangem/data/notifications/converters/NotificationsEligibleNetworkConverter.kt @@ -1,15 +1,19 @@ package com.tangem.data.notifications.converters +import com.tangem.blockchain.common.Blockchain +import com.tangem.blockchainsdk.utils.fromNetworkId +import com.tangem.core.ui.extensions.getActiveIconRes import com.tangem.datasource.api.tangemTech.models.CryptoNetworkResponse import com.tangem.domain.notifications.models.NotificationsEligibleNetwork -import com.tangem.utils.converter.Converter -internal object NotificationsEligibleNetworkConverter : Converter { - override fun convert(value: CryptoNetworkResponse): NotificationsEligibleNetwork { +internal object NotificationsEligibleNetworkConverter { + fun convert(value: CryptoNetworkResponse): NotificationsEligibleNetwork? { + val blockchain: Blockchain = Blockchain.fromNetworkId(value.networkId) ?: return null return NotificationsEligibleNetwork( - id = value.id.toString(), - networkId = value.networkId, - name = value.name, + id = value.networkId, + name = blockchain.fullName, + symbol = blockchain.currency, + icon = getActiveIconRes(blockchain.id), ) } } \ No newline at end of file diff --git a/data/notifications/src/test/java/com/tangem/data/notifications/DefaultNotificationsRepositoryTest.kt b/data/notifications/src/test/java/com/tangem/data/notifications/DefaultNotificationsRepositoryTest.kt index 46c37951b1..f50c5c07c8 100644 --- a/data/notifications/src/test/java/com/tangem/data/notifications/DefaultNotificationsRepositoryTest.kt +++ b/data/notifications/src/test/java/com/tangem/data/notifications/DefaultNotificationsRepositoryTest.kt @@ -149,7 +149,7 @@ class DefaultNotificationsRepositoryTest { CryptoNetworkResponse( id = 1, name = "Ethereum", - networkId = "Ethereum", + networkId = "ethereum", ), CryptoNetworkResponse( id = 2, diff --git a/domain/notifications/models/src/main/java/com/tangem/domain/notifications/models/NotificationsEligibleNetwork.kt b/domain/notifications/models/src/main/java/com/tangem/domain/notifications/models/NotificationsEligibleNetwork.kt index 7cd89c6754..cdc471da70 100644 --- a/domain/notifications/models/src/main/java/com/tangem/domain/notifications/models/NotificationsEligibleNetwork.kt +++ b/domain/notifications/models/src/main/java/com/tangem/domain/notifications/models/NotificationsEligibleNetwork.kt @@ -2,6 +2,7 @@ package com.tangem.domain.notifications.models data class NotificationsEligibleNetwork( val id: String, - val networkId: String, val name: String, + val symbol: String, + val icon: Int, ) \ No newline at end of file diff --git a/domain/notifications/src/main/java/com/tangem/domain/notifications/GetNetworksAvailableForNotificationsUseCase.kt b/domain/notifications/src/main/java/com/tangem/domain/notifications/GetNetworksAvailableForNotificationsUseCase.kt new file mode 100644 index 0000000000..edc3de5294 --- /dev/null +++ b/domain/notifications/src/main/java/com/tangem/domain/notifications/GetNetworksAvailableForNotificationsUseCase.kt @@ -0,0 +1,14 @@ +package com.tangem.domain.notifications + +import arrow.core.Either +import com.tangem.domain.notifications.models.NotificationsEligibleNetwork +import com.tangem.domain.notifications.repository.NotificationsRepository + +class GetNetworksAvailableForNotificationsUseCase( + private val notificationsRepository: NotificationsRepository, +) { + + suspend operator fun invoke(): Either> = Either.catch { + notificationsRepository.getEligibleNetworks() + } +} \ No newline at end of file diff --git a/features/wallet-settings/api/src/main/kotlin/com/tangem/feature/walletsettings/component/NetworksAvailableForNotificationsComponent.kt b/features/wallet-settings/api/src/main/kotlin/com/tangem/feature/walletsettings/component/NetworksAvailableForNotificationsComponent.kt new file mode 100644 index 0000000000..82d0e9b33b --- /dev/null +++ b/features/wallet-settings/api/src/main/kotlin/com/tangem/feature/walletsettings/component/NetworksAvailableForNotificationsComponent.kt @@ -0,0 +1,13 @@ +package com.tangem.feature.walletsettings.component + +import com.tangem.core.decompose.factory.ComponentFactory +import com.tangem.core.ui.decompose.ComposableBottomSheetComponent + +interface NetworksAvailableForNotificationsComponent : ComposableBottomSheetComponent { + + data class Params( + val onDismiss: () -> Unit, + ) + + interface Factory : ComponentFactory +} \ No newline at end of file diff --git a/features/wallet-settings/impl/build.gradle.kts b/features/wallet-settings/impl/build.gradle.kts index 3cd73b77d8..189f291d65 100644 --- a/features/wallet-settings/impl/build.gradle.kts +++ b/features/wallet-settings/impl/build.gradle.kts @@ -37,6 +37,8 @@ dependencies { implementation(projects.domain.demo) implementation(projects.domain.nft) implementation(projects.domain.notifications.toggles) + implementation(projects.domain.notifications.models) + implementation(projects.domain.notifications) /* AndroidX */ implementation(deps.androidx.fragment.ktx) diff --git a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/component/impl/DefaultNetworksAvailableForNotificationsComponent.kt b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/component/impl/DefaultNetworksAvailableForNotificationsComponent.kt new file mode 100644 index 0000000000..496fdd5644 --- /dev/null +++ b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/component/impl/DefaultNetworksAvailableForNotificationsComponent.kt @@ -0,0 +1,40 @@ +package com.tangem.feature.walletsettings.component.impl + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.tangem.core.decompose.context.AppComponentContext +import com.tangem.core.decompose.model.getOrCreateModel +import com.tangem.feature.walletsettings.component.NetworksAvailableForNotificationsComponent +import com.tangem.feature.walletsettings.component.impl.model.NetworksAvailableForNotificationsModel +import com.tangem.feature.walletsettings.ui.NetworksAvailableForNotificationsListBS +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject + +internal class DefaultNetworksAvailableForNotificationsComponent @AssistedInject constructor( + @Assisted context: AppComponentContext, + @Assisted private val params: NetworksAvailableForNotificationsComponent.Params, +) : NetworksAvailableForNotificationsComponent, AppComponentContext by context { + + private val model: NetworksAvailableForNotificationsModel = getOrCreateModel(params) + + override fun dismiss() { + params.onDismiss() + } + + @Composable + override fun BottomSheet() { + val state by model.state.collectAsStateWithLifecycle() + + NetworksAvailableForNotificationsListBS(state = state, onBack = ::dismiss, onDismiss = ::dismiss) + } + + @AssistedFactory + interface Factory : NetworksAvailableForNotificationsComponent.Factory { + override fun create( + context: AppComponentContext, + params: NetworksAvailableForNotificationsComponent.Params, + ): DefaultNetworksAvailableForNotificationsComponent + } +} \ No newline at end of file diff --git a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/component/impl/DefaultWalletSettingsComponent.kt b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/component/impl/DefaultWalletSettingsComponent.kt index 1f4adf5af6..7cce71989f 100644 --- a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/component/impl/DefaultWalletSettingsComponent.kt +++ b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/component/impl/DefaultWalletSettingsComponent.kt @@ -11,10 +11,13 @@ import com.arkivanov.decompose.router.slot.dismiss import com.tangem.core.decompose.context.AppComponentContext import com.tangem.core.decompose.context.childByContext import com.tangem.core.decompose.model.getOrCreateModel +import com.tangem.core.ui.decompose.ComposableBottomSheetComponent import com.tangem.core.ui.decompose.ComposableDialogComponent +import com.tangem.feature.walletsettings.component.NetworksAvailableForNotificationsComponent import com.tangem.feature.walletsettings.component.RenameWalletComponent import com.tangem.feature.walletsettings.component.WalletSettingsComponent import com.tangem.feature.walletsettings.entity.DialogConfig +import com.tangem.feature.walletsettings.entity.NetworksAvailableForNotificationBSConfig import com.tangem.feature.walletsettings.model.WalletSettingsModel import com.tangem.feature.walletsettings.ui.WalletSettingsScreen import dagger.assisted.Assisted @@ -25,14 +28,24 @@ internal class DefaultWalletSettingsComponent @AssistedInject constructor( @Assisted context: AppComponentContext, @Assisted params: WalletSettingsComponent.Params, private val renameWalletComponentFactory: RenameWalletComponent.Factory, + private val networksAvailableForNotificationsComponent: NetworksAvailableForNotificationsComponent.Factory, ) : WalletSettingsComponent, AppComponentContext by context { private val model: WalletSettingsModel = getOrCreateModel(params) + private val bottomSheetSlot = childSlot( + source = model.bottomSheetNavigation, + serializer = null, + handleBackButton = false, + key = "bottomSheetSlot", + childFactory = ::bottomSheetChild, + ) + private val dialog = childSlot( source = model.dialogNavigation, serializer = DialogConfig.serializer(), handleBackButton = true, + key = "dialogSlot", childFactory = ::dialogChild, ) @@ -40,12 +53,15 @@ internal class DefaultWalletSettingsComponent @AssistedInject constructor( override fun Content(modifier: Modifier) { val state by model.state.collectAsStateWithLifecycle() val dialog by dialog.subscribeAsState() + val bottomSheet by bottomSheetSlot.subscribeAsState() WalletSettingsScreen( modifier = modifier, state = state, dialog = { dialog.child?.instance?.Dialog() }, ) + + bottomSheet.child?.instance?.BottomSheet() } private fun dialogChild( @@ -64,6 +80,18 @@ internal class DefaultWalletSettingsComponent @AssistedInject constructor( } } + @Suppress("UnusedPrivateMember") + private fun bottomSheetChild( + config: NetworksAvailableForNotificationBSConfig, + componentContext: ComponentContext, + ): ComposableBottomSheetComponent = networksAvailableForNotificationsComponent.create( + context = childByContext(componentContext), + params = NetworksAvailableForNotificationsComponent.Params( + onDismiss = model + .bottomSheetNavigation::dismiss, + ), + ) + @AssistedFactory interface Factory : WalletSettingsComponent.Factory { override fun create( diff --git a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/component/impl/model/NetworksAvailableForNotificationsModel.kt b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/component/impl/model/NetworksAvailableForNotificationsModel.kt new file mode 100644 index 0000000000..7d49112604 --- /dev/null +++ b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/component/impl/model/NetworksAvailableForNotificationsModel.kt @@ -0,0 +1,40 @@ +package com.tangem.feature.walletsettings.component.impl.model + +import com.tangem.core.decompose.di.ModelScoped +import com.tangem.core.decompose.model.Model +import com.tangem.domain.notifications.GetNetworksAvailableForNotificationsUseCase +import com.tangem.feature.walletsettings.ui.state.NetworksAvailableForNotificationsUM +import com.tangem.utils.coroutines.CoroutineDispatcherProvider +import kotlinx.collections.immutable.persistentListOf +import kotlinx.collections.immutable.toImmutableList +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch +import javax.inject.Inject + +@ModelScoped +internal class NetworksAvailableForNotificationsModel @Inject constructor( + private val getNetworksAvailableForNotificationsUseCase: GetNetworksAvailableForNotificationsUseCase, + override val dispatchers: CoroutineDispatcherProvider, +) : Model() { + + val state: StateFlow get() = _state + + private val _state = MutableStateFlow( + value = NetworksAvailableForNotificationsUM( + networks = persistentListOf(), + isLoading = true, + ), + ) + + init { + modelScope.launch { + getNetworksAvailableForNotificationsUseCase().onRight { networks -> + _state.update { + it.copy(networks = networks.toImmutableList(), isLoading = false) + } + } + } + } +} \ No newline at end of file diff --git a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/di/WalletSettingsComponentModule.kt b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/di/WalletSettingsComponentModule.kt index f3cc276efa..7e581247df 100644 --- a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/di/WalletSettingsComponentModule.kt +++ b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/di/WalletSettingsComponentModule.kt @@ -2,8 +2,10 @@ package com.tangem.feature.walletsettings.di import com.tangem.feature.walletsettings.component.RenameWalletComponent import com.tangem.feature.walletsettings.component.WalletSettingsComponent +import com.tangem.feature.walletsettings.component.impl.DefaultNetworksAvailableForNotificationsComponent import com.tangem.feature.walletsettings.component.impl.DefaultRenameWalletComponent import com.tangem.feature.walletsettings.component.impl.DefaultWalletSettingsComponent +import com.tangem.feature.walletsettings.component.NetworksAvailableForNotificationsComponent import dagger.Binds import dagger.Module import dagger.hilt.InstallIn @@ -23,4 +25,10 @@ internal interface WalletSettingsComponentModule { @Binds @Singleton fun bindRenameWalletComponentFactory(factory: DefaultRenameWalletComponent.Factory): RenameWalletComponent.Factory + + @Binds + @Singleton + fun bindNetworksComponentFactory( + factory: DefaultNetworksAvailableForNotificationsComponent.Factory, + ): NetworksAvailableForNotificationsComponent.Factory } \ No newline at end of file diff --git a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/di/WalletSettingsModelModule.kt b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/di/WalletSettingsModelModule.kt index 195e71a172..c8f2133883 100644 --- a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/di/WalletSettingsModelModule.kt +++ b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/di/WalletSettingsModelModule.kt @@ -2,6 +2,7 @@ package com.tangem.feature.walletsettings.di import com.tangem.core.decompose.di.ModelComponent import com.tangem.core.decompose.model.Model +import com.tangem.feature.walletsettings.component.impl.model.NetworksAvailableForNotificationsModel import com.tangem.feature.walletsettings.component.impl.model.RenameWalletModel import com.tangem.feature.walletsettings.model.WalletSettingsModel import dagger.Binds @@ -23,4 +24,9 @@ internal interface WalletSettingsModelModule { @IntoMap @ClassKey(RenameWalletModel::class) fun bindRenameWalletModel(model: RenameWalletModel): Model + + @Binds + @IntoMap + @ClassKey(NetworksAvailableForNotificationsModel::class) + fun bindNetworksAvailableForNotificationsModel(model: NetworksAvailableForNotificationsModel): Model } \ No newline at end of file diff --git a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/entity/NetworksAvailableForNotificationBSConfig.kt b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/entity/NetworksAvailableForNotificationBSConfig.kt new file mode 100644 index 0000000000..f101dc1c28 --- /dev/null +++ b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/entity/NetworksAvailableForNotificationBSConfig.kt @@ -0,0 +1,6 @@ +package com.tangem.feature.walletsettings.entity + +import kotlinx.serialization.Serializable + +@Serializable +internal object NetworksAvailableForNotificationBSConfig \ No newline at end of file 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 b00f2acc62..071c769167 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 @@ -13,9 +13,7 @@ import com.tangem.core.decompose.navigation.Router import com.tangem.core.decompose.ui.UiMessageSender import com.tangem.core.navigation.settings.SettingsManager import com.tangem.core.ui.extensions.resourceReference -import com.tangem.core.ui.message.DialogMessage -import com.tangem.core.ui.message.EventMessageAction -import com.tangem.core.ui.message.SnackbarMessage +import com.tangem.core.ui.message.* import com.tangem.domain.common.util.cardTypesResolver import com.tangem.domain.demo.IsDemoCardUseCase import com.tangem.domain.models.scan.CardDTO @@ -31,6 +29,7 @@ import com.tangem.domain.wallets.usecase.* import com.tangem.feature.walletsettings.analytics.Settings import com.tangem.feature.walletsettings.component.WalletSettingsComponent import com.tangem.feature.walletsettings.entity.DialogConfig +import com.tangem.feature.walletsettings.entity.NetworksAvailableForNotificationBSConfig import com.tangem.feature.walletsettings.entity.WalletSettingsItemUM import com.tangem.feature.walletsettings.entity.WalletSettingsUM import com.tangem.feature.walletsettings.impl.R @@ -70,6 +69,7 @@ internal class WalletSettingsModel @Inject constructor( val params: WalletSettingsComponent.Params = paramsContainer.require() val dialogNavigation = SlotNavigation() + val bottomSheetNavigation: SlotNavigation = SlotNavigation() val state: MutableStateFlow = MutableStateFlow( value = WalletSettingsUM( @@ -215,7 +215,7 @@ internal class WalletSettingsModel @Inject constructor( } private fun onNotificationsDescriptionClick() { - // TODO [REDACTED_JIRA] + bottomSheetNavigation.activate(NetworksAvailableForNotificationBSConfig) } private fun openPushSystemSettings() { diff --git a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/ui/NetworksAvailableForNotificationsListBS.kt b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/ui/NetworksAvailableForNotificationsListBS.kt new file mode 100644 index 0000000000..529f6aa643 --- /dev/null +++ b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/ui/NetworksAvailableForNotificationsListBS.kt @@ -0,0 +1,171 @@ +package com.tangem.feature.walletsettings.ui + +import android.content.res.Configuration +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.* +import androidx.compose.material3.Icon +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.key +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.util.fastForEach +import com.tangem.core.ui.R +import com.tangem.core.ui.components.SecondaryButton +import com.tangem.core.ui.components.SpacerH24 +import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig +import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent +import com.tangem.core.ui.components.bottomsheets.modal.TangemModalBottomSheetTitle +import com.tangem.core.ui.components.bottomsheets.modal.TangemModalBottomSheetWithFooter +import com.tangem.core.ui.components.items.NetworkNameAndSymbolItem +import com.tangem.core.ui.components.items.NetworkNameAndSymbolItemShimmer +import com.tangem.core.ui.extensions.* +import com.tangem.core.ui.res.TangemTheme +import com.tangem.core.ui.res.TangemThemePreview +import com.tangem.domain.notifications.models.NotificationsEligibleNetwork +import com.tangem.feature.walletsettings.ui.state.NetworksAvailableForNotificationsUM +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf + +@Composable +internal fun NetworksAvailableForNotificationsListBS( + state: NetworksAvailableForNotificationsUM, + onBack: () -> Unit, + onDismiss: () -> Unit, +) { + TangemModalBottomSheetWithFooter( + config = TangemBottomSheetConfig( + isShown = true, + onDismissRequest = onDismiss, + content = TangemBottomSheetConfigContent.Empty, + ), + containerColor = TangemTheme.colors.background.tertiary, + onBack = onBack, + title = { + TangemModalBottomSheetTitle( + endIconRes = R.drawable.ic_close_24, + onEndClick = onDismiss, + ) + }, + content = { + NetworksAvailableForNotificationsListBottomSheetContent( + modifier = Modifier.padding(horizontal = TangemTheme.dimens.spacing16), + state = state, + ) + }, + footer = { + SecondaryButton( + modifier = Modifier + .padding(horizontal = 16.dp) + .fillMaxWidth(), + text = stringResourceSafe(R.string.balance_hidden_got_it_button), + onClick = onDismiss, + ) + }, + ) +} + +@Composable +private fun NetworksAvailableForNotificationsListBottomSheetContent( + state: NetworksAvailableForNotificationsUM, + modifier: Modifier = Modifier, +) { + Column( + modifier = modifier.background(TangemTheme.colors.background.primary), + ) { + Header() + SpacerH24() + Networks(networks = state.networks, isLoading = state.isLoading) + } +} + +@Composable +private fun ColumnScope.Header() { + Icon( + painter = painterResource(id = R.drawable.ic_notification_48), + contentDescription = null, + tint = TangemTheme.colors.icon.accent, + modifier = Modifier + .align(Alignment.CenterHorizontally) + .size(TangemTheme.dimens.size56), + ) + Text( + text = stringResourceSafe(R.string.push_transactions_notifications_title), + style = TangemTheme.typography.h2, + color = TangemTheme.colors.text.primary1, + textAlign = TextAlign.Center, + modifier = Modifier + .align(Alignment.CenterHorizontally) + .padding( + start = TangemTheme.dimens.spacing34, + end = TangemTheme.dimens.spacing34, + top = TangemTheme.dimens.spacing28, + ), + ) + Text( + text = stringResourceSafe(R.string.push_transactions_notifications_description), + style = TangemTheme.typography.body2, + color = TangemTheme.colors.text.secondary, + textAlign = TextAlign.Center, + modifier = Modifier + .align(Alignment.CenterHorizontally) + .padding( + start = TangemTheme.dimens.spacing34, + end = TangemTheme.dimens.spacing34, + top = TangemTheme.dimens.spacing8, + ), + ) +} + +@Composable +private fun Networks( + networks: ImmutableList, + modifier: Modifier = Modifier, + isLoading: Boolean = false, +) { + Column(modifier = modifier) { + Text( + modifier = Modifier.padding(top = 12.dp, bottom = 4.dp, start = 12.dp, end = 12.dp), + text = stringResourceSafe(R.string.common_supported_networks), + style = TangemTheme.typography.subtitle2, + color = TangemTheme.colors.text.tertiary, + ) + if (isLoading) { + repeat(SHIMMERS_COUNT) { + NetworkNameAndSymbolItemShimmer() + } + } else { + networks.fastForEach { network -> + key(network.id) { + NetworkNameAndSymbolItem( + icon = network.icon, + name = network.name, + symbol = network.symbol, + ) + } + } + } + } +} + +private const val SHIMMERS_COUNT = 10 + +@Composable +@Preview(showBackground = true, widthDp = 360) +@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES) +private fun Preview_CustomTokenNetworkSelectorContent() { + TangemThemePreview { + NetworksAvailableForNotificationsListBS( + state = NetworksAvailableForNotificationsUM( + networks = persistentListOf(), + isLoading = true, + ), + onDismiss = {}, + onBack = {}, + ) + } +} \ No newline at end of file diff --git a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/ui/state/NetworksAvailableForNotificationsUM.kt b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/ui/state/NetworksAvailableForNotificationsUM.kt new file mode 100644 index 0000000000..541a2ffbea --- /dev/null +++ b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/ui/state/NetworksAvailableForNotificationsUM.kt @@ -0,0 +1,9 @@ +package com.tangem.feature.walletsettings.ui.state + +import com.tangem.domain.notifications.models.NotificationsEligibleNetwork +import kotlinx.collections.immutable.ImmutableList + +data class NetworksAvailableForNotificationsUM( + val networks: ImmutableList, + val isLoading: Boolean, +) \ No newline at end of file