diff --git a/core/res/src/main/res/values-de/strings.xml b/core/res/src/main/res/values-de/strings.xml index 51b0328c1d..0fe3d3cfba 100644 --- a/core/res/src/main/res/values-de/strings.xml +++ b/core/res/src/main/res/values-de/strings.xml @@ -562,6 +562,10 @@ Eigenschaften Unbetitelte Sammlung %1$d NFTs in der %2$d Sammlung + + + %1$d NFTs in der %2$d Sammlung + Tippe hier, um das erste NFT zu erhalten NFT-Sammlungen Die Daten konnten nicht geladen werden diff --git a/core/res/src/main/res/values-fr/strings.xml b/core/res/src/main/res/values-fr/strings.xml index 6758225e1c..b7102eaf1b 100644 --- a/core/res/src/main/res/values-fr/strings.xml +++ b/core/res/src/main/res/values-fr/strings.xml @@ -520,6 +520,10 @@ Certaines données peuvent ne pas se charger Problèmes de chargement temporaires %1$d NFT dans la collection %2$d + + + %1$d NFT dans la collection %2$d + Appuyez ici pour recevoir le premier NFT Collections NFT Impossible de charger les données diff --git a/core/res/src/main/res/values-ja/strings.xml b/core/res/src/main/res/values-ja/strings.xml index 10a640eece..3c9bb51610 100644 --- a/core/res/src/main/res/values-ja/strings.xml +++ b/core/res/src/main/res/values-ja/strings.xml @@ -560,6 +560,9 @@ 特徴 無題のコレクション %2$dコレクションの%1$dNFT + + %2$dコレクションの%1$dNFT + ここをタップして最初のNFTを受け取ります NFTコレクション データを読み込めません @@ -1085,6 +1088,7 @@ %sを使用するか、カード / リングをスキャンしてウォレットにアクセスしてください 接続に失敗しました:このdAppは、サポートされていないWallet Connectバージョン1.0を使用しています。正常に接続するには、dAppがWallet Connectバージョン2.0をサポートしていることを確認してください。 最新の機能とニュースをお届けします + 受信取引の通知を受け取る 新しいプロモーション情報をいち早く入手しましょう プッシュ通知を使用しますか? 新しいウォレットを追加 diff --git a/core/res/src/main/res/values-ru/strings.xml b/core/res/src/main/res/values-ru/strings.xml index 45c1636058..2992c78399 100644 --- a/core/res/src/main/res/values-ru/strings.xml +++ b/core/res/src/main/res/values-ru/strings.xml @@ -569,6 +569,12 @@ Отправить NFT Черты %1$d NFTs в %2$d коллекциях + + + + + %1$d NFTs в %2$d коллекциях + Нажмите здесь, чтобы получить первую NFT NFT коллекции Невозможно загрузить данные diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml index c0aae1035e..232815179b 100644 --- a/core/res/src/main/res/values/strings.xml +++ b/core/res/src/main/res/values/strings.xml @@ -1,5 +1,6 @@ + Required minimum XLM reserve %1$s Can’t find your token? Go to the Market section on the main page and add it to your portfolio for purchase Can’t find your token? Go to the Market section on the main page and add it to your portfolio for selling. Sell @@ -271,6 +272,7 @@ %s hashes Device ID Contact support + Open support chat Link More Cards App Currency Flip-to-Hide Balances @@ -569,6 +571,10 @@ Traits Untitled collection %1$d NFTs in %2$d collections + + + %1$d NFTs in %2$d collections + Tap here to receive first NFT NFT collections Unable to load the data @@ -1077,6 +1083,8 @@ from: %s to: %s validator: %s + Notifications are enabled but won\'t work until you allow notifications in your device settings. + Transaction Notifications Minimum %s The minimum transaction amount is %1$s. Tron network fees for popular tokens can be higher. Staking TRX may help reduce transaction costs. @@ -1293,6 +1301,7 @@ Your review keeps us motivated to make Tangem Wallet even better Enjoying Tangem? You must associate your token before receiving tokens + You must open trustline before receiving tokens Network rent fee required Action required Did you contact support via the app within 7 days of creating your wallet? If yes, or if you\'re unsure, click \'Yes\' and follow the instructions. @@ -1308,6 +1317,9 @@ Swipe down to refresh or try again later. Some networks are unreachable Some token balances could not be updated + Open trustline + Open trustline subtiile + Open trustline title This is a Testnet card. It cannot process transactions and should only be used for testing and development purposes. For testing purposes only Balance may be outdated. Refresh the page. diff --git a/data/settings/src/main/java/com/tangem/data/settings/DefaultPermissionRepository.kt b/data/settings/src/main/java/com/tangem/data/settings/DefaultPermissionRepository.kt index e2528964fe..57c4716bab 100644 --- a/data/settings/src/main/java/com/tangem/data/settings/DefaultPermissionRepository.kt +++ b/data/settings/src/main/java/com/tangem/data/settings/DefaultPermissionRepository.kt @@ -1,5 +1,8 @@ package com.tangem.data.settings +import android.content.Context +import android.content.pm.PackageManager +import androidx.core.content.ContextCompat import com.tangem.datasource.local.preferences.AppPreferencesStore import com.tangem.datasource.local.preferences.PreferencesKeys.getShouldShowInitialPermissionScreen import com.tangem.datasource.local.preferences.PreferencesKeys.getShouldShowPermission @@ -9,6 +12,7 @@ import com.tangem.domain.settings.repositories.PermissionRepository internal class DefaultPermissionRepository( private val appPreferencesStore: AppPreferencesStore, + private val context: Context, ) : PermissionRepository { override suspend fun shouldInitiallyShowPermissionScreen(permission: String): Boolean { @@ -32,4 +36,12 @@ internal class DefaultPermissionRepository( override suspend fun neverAskPermission(permission: String) { appPreferencesStore.store(key = getShouldShowPermission(permission), value = false) } + + override fun hasRuntimePermission(permission: String): Boolean { + return context.isPermissionGranted(permission) + } + + private fun Context.isPermissionGranted(permission: String): Boolean { + return ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED + } } \ 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 4f04ee135b..8728678fe4 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,5 +1,6 @@ package com.tangem.data.settings.di +import android.content.Context import com.tangem.data.settings.DefaultAppRatingRepository import com.tangem.data.settings.DefaultPermissionRepository import com.tangem.data.settings.DefaultSettingsRepository @@ -13,6 +14,7 @@ import com.tangem.utils.coroutines.CoroutineDispatcherProvider import dagger.Module import dagger.Provides import dagger.hilt.InstallIn +import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.components.SingletonComponent import javax.inject.Singleton @@ -44,7 +46,13 @@ internal object SettingsDataModule { @Provides @Singleton - fun providePushPermissionRepository(appPreferencesStore: AppPreferencesStore): PermissionRepository { - return DefaultPermissionRepository(appPreferencesStore = appPreferencesStore) + fun providePushPermissionRepository( + appPreferencesStore: AppPreferencesStore, + @ApplicationContext context: Context, + ): PermissionRepository { + return DefaultPermissionRepository( + appPreferencesStore = appPreferencesStore, + context = context, + ) } } \ No newline at end of file diff --git a/domain/settings/src/main/java/com/tangem/domain/settings/repositories/PermissionRepository.kt b/domain/settings/src/main/java/com/tangem/domain/settings/repositories/PermissionRepository.kt index 21b476b233..2eec19c414 100644 --- a/domain/settings/src/main/java/com/tangem/domain/settings/repositories/PermissionRepository.kt +++ b/domain/settings/src/main/java/com/tangem/domain/settings/repositories/PermissionRepository.kt @@ -24,4 +24,9 @@ interface PermissionRepository { * Permanently deny [permission] and never request again */ suspend fun neverAskPermission(permission: String) + + /** + * Return is [permission] granted or not. + */ + fun hasRuntimePermission(permission: String): Boolean } \ 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 189f291d65..2de59a0dba 100644 --- a/features/wallet-settings/impl/build.gradle.kts +++ b/features/wallet-settings/impl/build.gradle.kts @@ -36,6 +36,7 @@ dependencies { implementation(projects.domain.wallets.models) implementation(projects.domain.demo) implementation(projects.domain.nft) + implementation(projects.domain.settings) implementation(projects.domain.notifications.toggles) implementation(projects.domain.notifications.models) implementation(projects.domain.notifications) 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 2df0907822..55a9a005e0 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 @@ -35,6 +35,7 @@ internal class PreviewWalletSettingsComponent : WalletSettingsComponent { isNotificationsFeatureEnabled = true, onCheckedNotificationsChanged = {}, onNotificationsDescriptionClick = {}, + isNotificationsPermissionGranted = false, ), requestPushNotificationsPermission = false, onPushNotificationPermissionGranted = {}, 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 4eabd5a71b..490fb2b00e 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 @@ -37,4 +37,10 @@ internal sealed class WalletSettingsItemUM { val more: TextReference, val onClick: () -> Unit, ) : WalletSettingsItemUM() + + data class NotificationPermission( + override val id: String, + val title: TextReference, + val description: TextReference, + ) : WalletSettingsItemUM() } \ 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 071c769167..c841e7acb9 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 @@ -1,5 +1,6 @@ package com.tangem.feature.walletsettings.model +import android.os.Build import arrow.core.getOrElse import com.arkivanov.decompose.router.slot.SlotNavigation import com.arkivanov.decompose.router.slot.activate @@ -22,6 +23,7 @@ import com.tangem.domain.nft.DisableWalletNFTUseCase import com.tangem.domain.nft.EnableWalletNFTUseCase import com.tangem.domain.nft.GetWalletNFTEnabledUseCase import com.tangem.domain.notifications.toggles.NotificationsFeatureToggles +import com.tangem.domain.settings.repositories.PermissionRepository import com.tangem.domain.wallets.models.UserWallet import com.tangem.domain.wallets.models.isMultiCurrency import com.tangem.domain.wallets.models.requireColdWallet @@ -65,6 +67,7 @@ internal class WalletSettingsModel @Inject constructor( private val getWalletNotificationsEnabledUseCase: GetWalletNotificationsEnabledUseCase, private val setNotificationsEnabledUseCase: SetNotificationsEnabledUseCase, private val settingsManager: SettingsManager, + private val permissionsRepository: PermissionRepository, ) : Model() { val params: WalletSettingsComponent.Params = paramsContainer.require() @@ -98,6 +101,7 @@ internal class WalletSettingsModel @Inject constructor( isNFTEnabled = nftEnabled, isNotificationsEnabled = notificationsEnabled, isNotificationsFeatureEnabled = notificationsToggles.isNotificationsEnabled, + isNotificationsPermissionGranted = isNotificationsPermissionGranted(), ), ) } @@ -105,6 +109,16 @@ internal class WalletSettingsModel @Inject constructor( .launchIn(modelScope) } + private fun isNotificationsPermissionGranted(): Boolean { + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + permissionsRepository.hasRuntimePermission( + android.Manifest.permission.POST_NOTIFICATIONS, + ) + } else { + true + } + } + private fun buildItems( userWallet: UserWallet, dialogNavigation: SlotNavigation, @@ -113,6 +127,7 @@ internal class WalletSettingsModel @Inject constructor( isNFTEnabled: Boolean, isNotificationsFeatureEnabled: Boolean, isNotificationsEnabled: Boolean, + isNotificationsPermissionGranted: Boolean, ): PersistentList = itemsBuilder.buildItems( userWalletId = userWallet.walletId, userWalletName = userWallet.name, @@ -147,6 +162,7 @@ internal class WalletSettingsModel @Inject constructor( onReferralClick = { onReferralClick(userWallet) }, isNotificationsEnabled = isNotificationsEnabled, isNotificationsFeatureEnabled = isNotificationsFeatureEnabled, + isNotificationsPermissionGranted = isNotificationsPermissionGranted, onCheckedNotificationsChanged = ::onCheckedNotificationsChange, onNotificationsDescriptionClick = ::onNotificationsDescriptionClick, ) 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 f934bc6c3e..64dc1120ee 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 @@ -21,6 +21,8 @@ import com.tangem.core.ui.components.appbar.models.TopAppBarButtonUM import com.tangem.core.ui.components.block.BlockCard import com.tangem.core.ui.components.block.BlockItem import com.tangem.core.ui.components.items.DescriptionItem +import com.tangem.core.ui.components.notifications.Notification +import com.tangem.core.ui.components.notifications.NotificationConfig import com.tangem.core.ui.extensions.resolveReference import com.tangem.core.ui.extensions.stringResourceSafe import com.tangem.core.ui.res.TangemTheme @@ -109,6 +111,10 @@ private fun Content(state: WalletSettingsUM, modifier: Modifier = Modifier) { yOffset = DESCRIPTION_OFFSET, onDescriptionClick = item.onClick, ) + is WalletSettingsItemUM.NotificationPermission -> NotificationAlertBlock( + modifier = itemModifier, + model = item, + ) } } } @@ -216,6 +222,18 @@ private fun SwitchBlock(model: WalletSettingsItemUM.WithSwitch, modifier: Modifi } } +@Composable +private fun NotificationAlertBlock(model: WalletSettingsItemUM.NotificationPermission, modifier: Modifier = Modifier) { + Notification( + config = NotificationConfig( + title = model.title, + subtitle = model.description, + iconResId = R.drawable.ic_alert_triangle_20, + ), + modifier = modifier, + ) +} + @Composable private fun DescriptionWithMoreBlock( model: WalletSettingsItemUM.DescriptionWithMore, 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 17a2b47350..0feb7b0851 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 @@ -36,6 +36,7 @@ internal class ItemsBuilder @Inject constructor( onCheckedNFTChange: (Boolean) -> Unit, isNotificationsFeatureEnabled: Boolean, isNotificationsEnabled: Boolean, + isNotificationsPermissionGranted: Boolean, onCheckedNotificationsChanged: (Boolean) -> Unit, onNotificationsDescriptionClick: () -> Unit, forgetWallet: () -> Unit, @@ -61,24 +62,34 @@ internal class ItemsBuilder @Inject constructor( onReferralClick = onReferralClick, ), ) - .run { - if (isNotificationsFeatureEnabled) { - add( - buildNotificationsSwitchItem( - isNotificationsEnabled, - onCheckedNotificationsChanged, - ), - ).add( - buildNotificationsDescriptionItem( - onDescriptionClick = onNotificationsDescriptionClick, - ), - ) - } else { - this - } - } + .addAll( + buildNotificationItems( + isNotificationsFeatureEnabled = isNotificationsFeatureEnabled, + isNotificationsPermissionGranted = isNotificationsPermissionGranted, + isNotificationsEnabled = isNotificationsEnabled, + onCheckedNotificationsChanged = onCheckedNotificationsChanged, + onNotificationsDescriptionClick = onNotificationsDescriptionClick, + ), + ) .add(buildForgetItem(forgetWallet)) + private fun buildNotificationItems( + isNotificationsFeatureEnabled: Boolean, + isNotificationsPermissionGranted: Boolean, + isNotificationsEnabled: Boolean, + onCheckedNotificationsChanged: (Boolean) -> Unit, + onNotificationsDescriptionClick: () -> Unit, + ): List { + if (!isNotificationsFeatureEnabled) return emptyList() + return buildList { + if (!isNotificationsPermissionGranted) { + add(buildNotificationsPermissionItem()) + } + add(buildNotificationsSwitchItem(isNotificationsEnabled, onCheckedNotificationsChanged)) + add(buildNotificationsDescriptionItem(onNotificationsDescriptionClick)) + } + } + private fun buildNameItem(walletName: String, isRenameWalletAvailable: Boolean, renameWallet: () -> Unit) = WalletSettingsItemUM.WithText( id = "wallet_name", @@ -96,6 +107,12 @@ internal class ItemsBuilder @Inject constructor( onCheckedChange = onCheckedNFTChange, ) + private fun buildNotificationsPermissionItem() = WalletSettingsItemUM.NotificationPermission( + id = "notifications_permission", + title = resourceReference(id = R.string.transaction_notifications_warning_title), + description = resourceReference(id = R.string.transaction_notifications_warning_description), + ) + private fun buildNotificationsSwitchItem(isNFTEnabled: Boolean, onCheckedNFTChange: (Boolean) -> Unit) = WalletSettingsItemUM.WithSwitch( id = "notifications",