diff --git a/app/src/main/java/com/tangem/tap/MainActivity.kt b/app/src/main/java/com/tangem/tap/MainActivity.kt
index 526a308532..fa9d503de0 100644
--- a/app/src/main/java/com/tangem/tap/MainActivity.kt
+++ b/app/src/main/java/com/tangem/tap/MainActivity.kt
@@ -49,7 +49,6 @@ import com.tangem.domain.tokens.GetPolkadotCheckHasImmortalUseCase
import com.tangem.domain.tokens.GetPolkadotCheckHasResetUseCase
import com.tangem.domain.wallets.legacy.UserWalletsListManager
import com.tangem.feature.wallet.presentation.wallet.analytics.WalletScreenAnalyticsEvent
-import com.tangem.features.pushnotifications.api.utils.PUSH_PERMISSION
import com.tangem.features.tester.api.TesterMenuLauncher
import com.tangem.features.walletconnect.components.WalletConnectFeatureToggles
import com.tangem.google.GoogleServicesHelper
@@ -468,12 +467,11 @@ class MainActivity : AppCompatActivity(), ActivityResultCallbackHolder {
} else {
lifecycleScope.launch {
val shouldShowTos = !cardRepository.isTangemTOSAccepted()
- val shouldShowInitialPush = shouldInitiallyAskPermissionUseCase(PUSH_PERMISSION).getOrElse { false }
- val route = when {
- shouldShowTos -> AppRoute.Disclaimer(isTosAccepted = false)
- shouldShowInitialPush -> AppRoute.PushNotification
- else -> AppRoute.Home(launchMode = launchMode)
+ val route = if (shouldShowTos) {
+ AppRoute.Disclaimer(isTosAccepted = false)
+ } else {
+ AppRoute.Home(launchMode = launchMode)
}
store.dispatchNavigationAction { replaceAll(route) }
diff --git a/app/src/main/java/com/tangem/tap/data/FirebasePushNotificationsTokenProvider.kt b/app/src/main/java/com/tangem/tap/data/FirebasePushNotificationsTokenProvider.kt
index 6167cea5a0..358bdd3d61 100644
--- a/app/src/main/java/com/tangem/tap/data/FirebasePushNotificationsTokenProvider.kt
+++ b/app/src/main/java/com/tangem/tap/data/FirebasePushNotificationsTokenProvider.kt
@@ -3,10 +3,16 @@ package com.tangem.tap.data
import com.google.firebase.messaging.FirebaseMessaging
import com.tangem.utils.notifications.PushNotificationsTokenProvider
import kotlinx.coroutines.tasks.await
+import timber.log.Timber
import javax.inject.Inject
internal class FirebasePushNotificationsTokenProvider @Inject constructor() : PushNotificationsTokenProvider {
override suspend fun getToken(): String {
- return FirebaseMessaging.getInstance().token.await()
+ return try {
+ FirebaseMessaging.getInstance().token.await()
+ } catch (ex: Exception) {
+ Timber.e(ex)
+ ""
+ }
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/implementation/DefaultSelectedUserWalletRepository.kt b/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/implementation/DefaultSelectedUserWalletRepository.kt
index 8398b7726d..37a9a6fc2e 100644
--- a/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/implementation/DefaultSelectedUserWalletRepository.kt
+++ b/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/implementation/DefaultSelectedUserWalletRepository.kt
@@ -4,26 +4,35 @@ import com.tangem.common.services.secure.SecureStorage
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.tap.domain.userWalletList.repository.SelectedUserWalletRepository
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
+import kotlinx.coroutines.sync.Mutex
+import kotlinx.coroutines.sync.withLock
import kotlinx.coroutines.withContext
internal class DefaultSelectedUserWalletRepository(
private val secureStorage: SecureStorage,
private val dispatchers: CoroutineDispatcherProvider,
) : SelectedUserWalletRepository {
+
+ private val mutex = Mutex()
+
override suspend fun get(): UserWalletId? = withContext(dispatchers.io) {
- secureStorage.get(StorageKey.SelectedWalletId.name)
- ?.decodeToString(throwOnInvalidSequence = true)
- ?.let { UserWalletId(it) }
+ mutex.withLock {
+ secureStorage.get(StorageKey.SelectedWalletId.name)
+ ?.decodeToString(throwOnInvalidSequence = true)
+ ?.let { UserWalletId(it) }
+ }
}
override suspend fun set(walletId: UserWalletId?) = withContext(dispatchers.io) {
- if (walletId == null) {
- secureStorage.delete(StorageKey.SelectedWalletId.name)
- } else {
- secureStorage.store(
- data = walletId.stringValue.encodeToByteArray(throwOnInvalidSequence = true),
- account = StorageKey.SelectedWalletId.name,
- )
+ mutex.withLock {
+ if (walletId == null) {
+ secureStorage.delete(StorageKey.SelectedWalletId.name)
+ } else {
+ secureStorage.store(
+ data = walletId.stringValue.encodeToByteArray(throwOnInvalidSequence = true),
+ account = StorageKey.SelectedWalletId.name,
+ )
+ }
}
}
diff --git a/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt b/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt
index c18697013f..436c6fcc3a 100644
--- a/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt
+++ b/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt
@@ -23,6 +23,8 @@ import com.tangem.features.nft.component.NFTComponent
import com.tangem.features.onboarding.v2.entry.OnboardingEntryComponent
import com.tangem.features.onramp.component.*
import com.tangem.features.pushnotifications.api.PushNotificationsComponent
+import com.tangem.features.pushnotifications.api.PushNotificationsModelCallbacksStub
+import com.tangem.features.pushnotifications.api.PushNotificationsParams
import com.tangem.features.send.v2.api.NFTSendComponent
import com.tangem.features.send.v2.api.SendComponent
import com.tangem.features.send.v2.api.SendEntryPointComponent
@@ -381,7 +383,9 @@ internal class ChildFactory @Inject constructor(
is AppRoute.PushNotification -> {
createComponentChild(
context = context,
- params = PushNotificationsComponent.Params.Route(AppRoute.Home()),
+ params = PushNotificationsParams(
+ modelCallbacks = PushNotificationsModelCallbacksStub(),
+ ),
componentFactory = pushNotificationsComponentFactory,
)
}
diff --git a/core/datasource/src/main/java/com/tangem/datasource/info/AndroidAppInfoProvider.kt b/core/datasource/src/main/java/com/tangem/datasource/info/AndroidAppInfoProvider.kt
index 0bc5462596..d33089ff1b 100644
--- a/core/datasource/src/main/java/com/tangem/datasource/info/AndroidAppInfoProvider.kt
+++ b/core/datasource/src/main/java/com/tangem/datasource/info/AndroidAppInfoProvider.kt
@@ -21,4 +21,7 @@ internal class AndroidAppInfoProvider @Inject constructor(
get() = TimeZone.getDefault().id
override val appVersion: String
get() = appVersionProvider.versionName
+ override val isHuaweiDevice: Boolean
+ get() = Build.MANUFACTURER.equals("HUAWEI", ignoreCase = true) ||
+ Build.BRAND.equals("HUAWEI", ignoreCase = true)
}
\ No newline at end of file
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 d39a5c15a8..a737416dd5 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
@@ -134,6 +134,18 @@ object PreferencesKeys {
val NOTIFICATIONS_ENABLED_STATES_KEY by lazy { stringPreferencesKey(name = "notificationsEnabledStates") }
+ val NOTIFICATIONS_AUTOMATICALLY_ENABLED_STATES_KEY by lazy {
+ stringPreferencesKey(
+ name = "notificationsAutomaticallyEnabledStates",
+ )
+ }
+
+ val NOTIFICATIONS_USER_ALLOW_SEND_ADDRESSES_KEY by lazy {
+ booleanPreferencesKey(
+ name = "userAllowSendAddresses",
+ )
+ }
+
val TRON_NETWORK_FEE_NOTIFICATION_SHOW_COUNT_KEY by lazy {
intPreferencesKey(name = "tronNetworkFeeNotificationShowCount")
}
diff --git a/core/res/src/main/res/values-fr/strings.xml b/core/res/src/main/res/values-fr/strings.xml
index 5d857cb793..075f05f465 100644
--- a/core/res/src/main/res/values-fr/strings.xml
+++ b/core/res/src/main/res/values-fr/strings.xml
@@ -1087,6 +1087,8 @@
de : %s
à : %s
validateur : %s
+ Les notifications sont activées, mais elles ne fonctionneront pas tant que vous n\'aurez pas autorisé les notifications dans les paramètres de votre appareil.
+ Notifications de transaction
Minimum %s
Le montant minimum pour effectuer cette transaction est %1$s.
Réessayez
diff --git a/core/res/src/main/res/values-ja/strings.xml b/core/res/src/main/res/values-ja/strings.xml
index 7af3b7a089..af6731c66e 100644
--- a/core/res/src/main/res/values-ja/strings.xml
+++ b/core/res/src/main/res/values-ja/strings.xml
@@ -61,6 +61,13 @@
システムのデフォルト
テーマ
アプリ設定
+ ウォレットを追加
+ ログインするウォレットを選択する
+ お帰りなさい!
+
+ - %d 枚のカード
+
+ スマートフォンウォレット
ウォレットのバックアップが正常に完了しました。
これらの単語は紛失した場合、復元できません。必ず安全な場所に保管してください。
バックアップが完了しました
@@ -846,6 +853,7 @@
%1$s 、 %2$s
宛先タグ
アドレスを入力
+ ENS名またはアドレスを入力
アドレスはウォレットアドレスと同じです
最低額は%sです
最小の変更は%sです
@@ -927,11 +935,15 @@
無効な金額
手数料が残高を超えています
合計金額が残高を超えています
+ トークンを変更してもよろしいですか? 変更後、以前のデータはリセットされます。
+ トークンの変更
スワップして送信
トークンを送信すれば、送信中に変換されます。受信者は必要なものをシームレスに受け取ります。
受信者は受け取ります
受信者に送信されます
受取金額
+ 変換をキャンセルしてもよろしいですか? 変更後、以前のデータはリセットされます。
+ キャンセルの確認
スワップして送信
取引が送信されました
設定したいカードまたはリングをスキャンするために準備してください。
@@ -1428,6 +1440,8 @@
取引リクエスト
取引リクエスト
無制限
+ 各ペアリング試行で、新しくユニークなURIが使用されていることを確認します
+ URIはすでに使用されています
ウォレットコネクト
破棄
バックアップが中断されました。再開しますか?
diff --git a/core/res/src/main/res/values-ru/strings.xml b/core/res/src/main/res/values-ru/strings.xml
index 071f03c35f..5a430645a7 100644
--- a/core/res/src/main/res/values-ru/strings.xml
+++ b/core/res/src/main/res/values-ru/strings.xml
@@ -1105,6 +1105,8 @@
от: %s
на: %s
валидатор: %s
+ Уведомления включены, но не будут работать, пока вы не разрешите их в настройках устройства.
+ Уведомления о транзакциях
Минимум %s
Минимальная сумма транзакции равна %1$s.
Комиссии сети Tron для популярных токенов могут быть выше. Стейкинг TRX может помочь снизить расходы на транзакции.
@@ -1182,6 +1184,7 @@
Получите доступ к более чем 13 000 криптовалют. Покупайте, продавайте, обменивайте и стейкайте в один клик. Свяжите до трех карт для резервного копирования.
Откройте Tangem Wallet
Получайте уведомления о входящих транзакциях в кошельке и обновлениях Tangem.
+ В настоящий момент push-уведомления могут не работать на устройствах Huawei. Мы уже работаем над решением этой проблемы и планируем исправление в ближайших обновлениях. Спасибо за понимание!
Уведомления о транзакциях
Настройки кошелька
Tangem
diff --git a/core/res/src/main/res/values-uk-rUA/strings.xml b/core/res/src/main/res/values-uk-rUA/strings.xml
index fe103942ab..9b3e3dfe52 100644
--- a/core/res/src/main/res/values-uk-rUA/strings.xml
+++ b/core/res/src/main/res/values-uk-rUA/strings.xml
@@ -1105,6 +1105,8 @@
від: %s
до: %s
валідатор: %s
+ Сповіщення ввімкнені, але не працюватимуть, доки ви не дозволите їх у налаштуваннях пристрою.
+ Сповіщення про транзакції
Мінімум %s
Мінімальна сума транзакції становить %1$s.
Комісії мережі Tron для популярних токенів можуть бути вищими. Стейкінг TRX може допомогти знизити транзакційні витрати.
diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml
index 8623c22b55..a8961f599c 100644
--- a/core/res/src/main/res/values/strings.xml
+++ b/core/res/src/main/res/values/strings.xml
@@ -430,6 +430,7 @@
To complete setup, back up your wallet and secure app access with a Access Code.
Finish Now
Finish Wallet Activation
+ To complete setup, secure app access with Access Code.
Recover an existing wallet stored in your Google Drive backup
Google Drive Backup
Go to backup
@@ -1350,6 +1351,7 @@
Secret code to protect this wallet. Used for login and signatures.
Set/Change Access Code
Stay notified on wallet incoming transactions and Tangem updates.
+ Push notifications may currently not work on Huawei devices. We\'re actively working on a solution and will release a fix in an upcoming update. Thank you for your understanding!
Transaction Notifications
Wallet settings
Tangem
@@ -1506,6 +1508,8 @@
Transaction request
Transaction request
Unlimited Amount
+ Ensure that each pairing attempt uses a fresh and unique URI
+ URI already used
Wallet connect
Discard
You have an interrupted backup. Do you want to resume?
diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/showcase/Showcase.kt b/core/ui/src/main/java/com/tangem/core/ui/components/showcase/Showcase.kt
index 8112024b54..48f79e027f 100644
--- a/core/ui/src/main/java/com/tangem/core/ui/components/showcase/Showcase.kt
+++ b/core/ui/src/main/java/com/tangem/core/ui/components/showcase/Showcase.kt
@@ -66,7 +66,7 @@ fun Showcase(
}
@Composable
-private fun ShowcaseButtons(
+fun ShowcaseButtons(
primaryButtonText: TextReference,
secondaryButtonText: TextReference,
onPrimaryClick: () -> Unit,
diff --git a/core/ui/src/main/java/com/tangem/core/ui/utils/RequestPermission.kt b/core/ui/src/main/java/com/tangem/core/ui/utils/RequestPermission.kt
new file mode 100644
index 0000000000..9e0910e239
--- /dev/null
+++ b/core/ui/src/main/java/com/tangem/core/ui/utils/RequestPermission.kt
@@ -0,0 +1,43 @@
+package com.tangem.core.ui.utils
+
+import android.os.Build
+import androidx.annotation.ChecksSdkIntAtLeast
+import androidx.compose.runtime.Composable
+import com.google.accompanist.permissions.ExperimentalPermissionsApi
+import com.google.accompanist.permissions.isGranted
+import com.google.accompanist.permissions.rememberPermissionState
+
+/**
+ * Returns push permission requester.
+ * Handles granting permission from app settings.
+ */
+@Suppress("LongParameterList")
+@OptIn(ExperimentalPermissionsApi::class)
+@Composable
+fun requestPermission(permission: String, onAllow: () -> Unit, onDeny: () -> Unit): () -> Unit {
+ val permissionState = rememberPermissionState(
+ permission = permission,
+ onPermissionResult = { isGranted ->
+ if (isGranted) {
+ onAllow()
+ } else {
+ onDeny()
+ }
+ },
+ )
+ return when {
+ permissionState.status.isGranted == false -> {
+ if (isRequirePushPermission) {
+ permissionState::launchPermissionRequest
+ } else {
+ onDeny // on versions below Tiramisu call onDeny directly and then open settings
+ }
+ }
+ else -> {
+ onAllow
+ }
+ }
+}
+
+@ChecksSdkIntAtLeast(api = Build.VERSION_CODES.TIRAMISU)
+private val isRequirePushPermission = Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU
\ No newline at end of file
diff --git a/core/ui/src/main/java/com/tangem/core/ui/utils/RequestPushPermission.kt b/core/ui/src/main/java/com/tangem/core/ui/utils/RequestPushPermission.kt
deleted file mode 100644
index 4f6cc6d0df..0000000000
--- a/core/ui/src/main/java/com/tangem/core/ui/utils/RequestPushPermission.kt
+++ /dev/null
@@ -1,33 +0,0 @@
-package com.tangem.core.ui.utils
-
-import androidx.compose.runtime.Composable
-import com.google.accompanist.permissions.ExperimentalPermissionsApi
-import com.google.accompanist.permissions.rememberPermissionState
-
-/**
- * Returns push permission requester.
- * Handles granting permission from app settings.
- */
-@Suppress("LongParameterList")
-@OptIn(ExperimentalPermissionsApi::class)
-@Composable
-fun requestPushPermission(pushPermission: String?, onAllow: () -> Unit, onDeny: () -> Unit): () -> Unit {
- val permissionState = pushPermission?.let { permission ->
- rememberPermissionState(
- permission = permission,
- onPermissionResult = { isGranted ->
- if (isGranted) {
- onAllow()
- } else {
- onDeny()
- }
- },
- )
- }
-
- return if (permissionState == null) {
- {}
- } else {
- permissionState::launchPermissionRequest
- }
-}
\ No newline at end of file
diff --git a/core/utils/src/main/java/com/tangem/utils/info/AppInfoProvider.kt b/core/utils/src/main/java/com/tangem/utils/info/AppInfoProvider.kt
index 0ab3e32398..7337a4f114 100644
--- a/core/utils/src/main/java/com/tangem/utils/info/AppInfoProvider.kt
+++ b/core/utils/src/main/java/com/tangem/utils/info/AppInfoProvider.kt
@@ -7,4 +7,5 @@ interface AppInfoProvider {
val language: String
val timezone: String
val appVersion: String
+ val isHuaweiDevice: Boolean
}
\ No newline at end of file
diff --git a/data/common/src/main/kotlin/com/tangem/data/common/currency/UserTokensResponseAddressesEnricher.kt b/data/common/src/main/kotlin/com/tangem/data/common/currency/UserTokensResponseAddressesEnricher.kt
index ad55f36ea3..96f45165c5 100644
--- a/data/common/src/main/kotlin/com/tangem/data/common/currency/UserTokensResponseAddressesEnricher.kt
+++ b/data/common/src/main/kotlin/com/tangem/data/common/currency/UserTokensResponseAddressesEnricher.kt
@@ -10,7 +10,9 @@ import com.tangem.domain.wallets.repository.WalletsRepository
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.withContext
+import kotlinx.coroutines.withTimeoutOrNull
import javax.inject.Inject
+import kotlin.time.Duration.Companion.seconds
class UserTokensResponseAddressesEnricher @Inject constructor(
private val notificationsFeatureToggles: NotificationsFeatureToggles,
@@ -28,7 +30,10 @@ class UserTokensResponseAddressesEnricher @Inject constructor(
return withContext(dispatchers.default) {
val networksStatuses = if (isNotificationsEnabled) {
- multiNetworkStatusSupplier.invoke(MultiNetworkStatusProducer.Params(userWalletId)).first()
+ withTimeoutOrNull(
+ FETCH_TIMEOUT_SECONDS.seconds,
+ { multiNetworkStatusSupplier.invoke(MultiNetworkStatusProducer.Params(userWalletId)).first() },
+ ) ?: emptySet()
} else {
emptySet()
}
@@ -61,4 +66,8 @@ class UserTokensResponseAddressesEnricher @Inject constructor(
response.copy(tokens = enrichedTokens, notifyStatus = isNotificationsEnabled)
}
}
+
+ companion object {
+ private const val FETCH_TIMEOUT_SECONDS = 3
+ }
}
\ No newline at end of file
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 dcb85f6ef2..d386676472 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
@@ -2,7 +2,9 @@ package com.tangem.data.notifications
import com.tangem.datasource.local.preferences.AppPreferencesStore
import com.tangem.datasource.local.preferences.PreferencesKeys
+import com.tangem.datasource.local.preferences.utils.getObjectMapSync
import com.tangem.datasource.local.preferences.utils.getSyncOrDefault
+import com.tangem.datasource.local.preferences.utils.getSyncOrNull
import com.tangem.datasource.local.preferences.utils.store
import com.tangem.domain.notifications.repository.NotificationsRepository
import javax.inject.Inject
@@ -35,4 +37,36 @@ class DefaultNotificationsRepository @Inject constructor(
default = 0,
)
}
+
+ override suspend fun shouldShowSubscribeOnNotificationsAfterUpdate(): Boolean {
+ return appPreferencesStore.getSyncOrNull(
+ key = PreferencesKeys.NOTIFICATIONS_USER_ALLOW_SEND_ADDRESSES_KEY,
+ ) == null
+ }
+
+ override suspend fun isUserAllowToSubscribeOnPushNotifications(): Boolean {
+ return appPreferencesStore.getSyncOrDefault(
+ key = PreferencesKeys.NOTIFICATIONS_USER_ALLOW_SEND_ADDRESSES_KEY,
+ default = false,
+ )
+ }
+
+ override suspend fun setUserAllowToSubscribeOnPushNotifications(value: Boolean) {
+ appPreferencesStore.store(PreferencesKeys.NOTIFICATIONS_USER_ALLOW_SEND_ADDRESSES_KEY, value)
+ }
+
+ override suspend fun getWalletAutomaticallyEnabledList(): List = appPreferencesStore
+ .getObjectMapSync(PreferencesKeys.NOTIFICATIONS_AUTOMATICALLY_ENABLED_STATES_KEY).map {
+ it.key
+ }
+
+ override suspend fun setNotificationsWasEnabledAutomatically(userWalletId: String) {
+ appPreferencesStore.editData {
+ it.setObjectMap(
+ key = PreferencesKeys.NOTIFICATIONS_AUTOMATICALLY_ENABLED_STATES_KEY,
+ value = it.getObjectMap(PreferencesKeys.NOTIFICATIONS_AUTOMATICALLY_ENABLED_STATES_KEY)
+ .plus(userWalletId to true),
+ )
+ }
+ }
}
\ No newline at end of file
diff --git a/domain/notifications/src/main/java/com/tangem/domain/notifications/GetIsHuaweiDeviceWithoutGoogleServicesUseCase.kt b/domain/notifications/src/main/java/com/tangem/domain/notifications/GetIsHuaweiDeviceWithoutGoogleServicesUseCase.kt
new file mode 100644
index 0000000000..50dee4a7a0
--- /dev/null
+++ b/domain/notifications/src/main/java/com/tangem/domain/notifications/GetIsHuaweiDeviceWithoutGoogleServicesUseCase.kt
@@ -0,0 +1,15 @@
+package com.tangem.domain.notifications
+
+import com.tangem.utils.info.AppInfoProvider
+import com.tangem.utils.notifications.PushNotificationsTokenProvider
+import javax.inject.Inject
+
+class GetIsHuaweiDeviceWithoutGoogleServicesUseCase @Inject constructor(
+ private val appInfoProvider: AppInfoProvider,
+ private val pushNotificationsTokenProvider: PushNotificationsTokenProvider,
+) {
+
+ suspend operator fun invoke(): Boolean {
+ return appInfoProvider.isHuaweiDevice && pushNotificationsTokenProvider.getToken().isEmpty()
+ }
+}
\ No newline at end of file
diff --git a/domain/notifications/src/main/java/com/tangem/domain/notifications/repository/NotificationsRepository.kt b/domain/notifications/src/main/java/com/tangem/domain/notifications/repository/NotificationsRepository.kt
index 377fc84984..0f1d3cb606 100644
--- a/domain/notifications/src/main/java/com/tangem/domain/notifications/repository/NotificationsRepository.kt
+++ b/domain/notifications/src/main/java/com/tangem/domain/notifications/repository/NotificationsRepository.kt
@@ -37,4 +37,14 @@ interface NotificationsRepository {
* Increments the counter tracking how many times the Tron token fee notification has been shown.
*/
suspend fun incrementTronTokenFeeNotificationShowCounter()
+
+ suspend fun shouldShowSubscribeOnNotificationsAfterUpdate(): Boolean
+
+ suspend fun isUserAllowToSubscribeOnPushNotifications(): Boolean
+
+ suspend fun setUserAllowToSubscribeOnPushNotifications(value: Boolean)
+
+ suspend fun getWalletAutomaticallyEnabledList(): List
+
+ suspend fun setNotificationsWasEnabledAutomatically(userWalletId: String)
}
\ No newline at end of file
diff --git a/domain/wallets/src/main/java/com/tangem/domain/wallets/usecase/GetIsBiometricsEnabledUseCase.kt b/domain/wallets/src/main/java/com/tangem/domain/wallets/usecase/GetIsBiometricsEnabledUseCase.kt
new file mode 100644
index 0000000000..b57e8d3ec8
--- /dev/null
+++ b/domain/wallets/src/main/java/com/tangem/domain/wallets/usecase/GetIsBiometricsEnabledUseCase.kt
@@ -0,0 +1,11 @@
+package com.tangem.domain.wallets.usecase
+
+import com.tangem.sdk.api.TangemSdkManager
+import javax.inject.Inject
+
+class GetIsBiometricsEnabledUseCase @Inject constructor(
+ private val tangemSdkManager: TangemSdkManager,
+) {
+
+ operator fun invoke(): Boolean = runCatching(tangemSdkManager::needEnrollBiometrics).getOrNull() ?: false
+}
\ No newline at end of file
diff --git a/domain/wallets/src/main/java/com/tangem/domain/wallets/usecase/GetWalletsForAutomaticallyPushEnablingUseCase.kt b/domain/wallets/src/main/java/com/tangem/domain/wallets/usecase/GetWalletsForAutomaticallyPushEnablingUseCase.kt
new file mode 100644
index 0000000000..3eb6bc9629
--- /dev/null
+++ b/domain/wallets/src/main/java/com/tangem/domain/wallets/usecase/GetWalletsForAutomaticallyPushEnablingUseCase.kt
@@ -0,0 +1,27 @@
+package com.tangem.domain.wallets.usecase
+
+import com.tangem.domain.models.wallet.UserWalletId
+import com.tangem.domain.wallets.legacy.UserWalletsListManager
+import com.tangem.utils.coroutines.CoroutineDispatcherProvider
+import kotlinx.coroutines.withContext
+import javax.inject.Inject
+
+/**
+ * Use case for retrieving wallets where automatically enabling push notifications was not applied.
+ * * This use case filters out wallets that have already had push notifications automatically enabled
+ * from the complete list of user wallets, returning only those wallets that still need to have
+ * push notifications automatically enabled.
+ * * @property userWalletsListManager Manager for user wallets list operations
+ * @property dispatchers Coroutine dispatcher provider for background operations
+ */
+class GetWalletsForAutomaticallyPushEnablingUseCase @Inject constructor(
+ private val userWalletsListManager: UserWalletsListManager,
+ private val dispatchers: CoroutineDispatcherProvider,
+) {
+
+ suspend operator fun invoke(walletsListWherePushWasEnabled: List): List =
+ withContext(dispatchers.default) {
+ val allLocalWallets = userWalletsListManager.userWalletsSync.map { it.walletId }
+ allLocalWallets - walletsListWherePushWasEnabled.toSet()
+ }
+}
\ No newline at end of file
diff --git a/features/disclaimer/impl/build.gradle.kts b/features/disclaimer/impl/build.gradle.kts
index 9144b3fbb0..3454262136 100644
--- a/features/disclaimer/impl/build.gradle.kts
+++ b/features/disclaimer/impl/build.gradle.kts
@@ -37,6 +37,7 @@ dependencies {
implementation(projects.domain.models)
implementation(projects.domain.card)
implementation(projects.domain.settings)
+ implementation(projects.domain.notifications)
/** Feature modules */
implementation(projects.features.disclaimer.api)
diff --git a/features/disclaimer/impl/src/main/java/com/tangem/features/disclaimer/impl/entity/DisclaimerUM.kt b/features/disclaimer/impl/src/main/java/com/tangem/features/disclaimer/impl/entity/DisclaimerUM.kt
index 155a91269b..4e15c1b3dd 100644
--- a/features/disclaimer/impl/src/main/java/com/tangem/features/disclaimer/impl/entity/DisclaimerUM.kt
+++ b/features/disclaimer/impl/src/main/java/com/tangem/features/disclaimer/impl/entity/DisclaimerUM.kt
@@ -3,7 +3,7 @@ package com.tangem.features.disclaimer.impl.entity
internal data class DisclaimerUM(
val url: String,
val isTosAccepted: Boolean,
- val onAccept: (Boolean) -> Unit,
+ val onAccept: () -> Unit,
val popBack: () -> Unit,
)
diff --git a/features/disclaimer/impl/src/main/java/com/tangem/features/disclaimer/impl/model/DisclaimerModel.kt b/features/disclaimer/impl/src/main/java/com/tangem/features/disclaimer/impl/model/DisclaimerModel.kt
index 1ea5597638..a1d162c8a3 100644
--- a/features/disclaimer/impl/src/main/java/com/tangem/features/disclaimer/impl/model/DisclaimerModel.kt
+++ b/features/disclaimer/impl/src/main/java/com/tangem/features/disclaimer/impl/model/DisclaimerModel.kt
@@ -7,6 +7,8 @@ import com.tangem.core.decompose.model.ParamsContainer
import com.tangem.core.decompose.navigation.Router
import com.tangem.core.navigation.finisher.AppFinisher
import com.tangem.domain.card.repository.CardRepository
+import com.tangem.domain.notifications.GetIsHuaweiDeviceWithoutGoogleServicesUseCase
+import com.tangem.domain.notifications.repository.NotificationsRepository
import com.tangem.domain.settings.NeverRequestPermissionUseCase
import com.tangem.domain.settings.NeverToInitiallyAskPermissionUseCase
import com.tangem.features.disclaimer.api.components.DisclaimerComponent
@@ -26,6 +28,9 @@ internal class DisclaimerModel @Inject constructor(
private val neverToInitiallyAskPermissionUseCase: NeverToInitiallyAskPermissionUseCase,
private val neverRequestPermissionUseCase: NeverRequestPermissionUseCase,
private val appFinisher: AppFinisher,
+ private val notificationsRepository: NotificationsRepository,
+ private val getIsHuaweiDeviceWithoutGoogleServicesUseCase: GetIsHuaweiDeviceWithoutGoogleServicesUseCase,
+
paramsContainer: ParamsContainer,
) : Model() {
@@ -40,13 +45,14 @@ internal class DisclaimerModel @Inject constructor(
),
)
- private fun onAccept(shouldAskPushPermission: Boolean) = modelScope.launch {
+ private fun onAccept() = modelScope.launch {
if (params.isTosAccepted) {
router.pop()
} else {
cardRepository.acceptTangemTOS()
-
- if (shouldAskPushPermission) {
+ val shouldAskPushPermission = notificationsRepository.shouldShowSubscribeOnNotificationsAfterUpdate()
+ val isHuaweiDevice = getIsHuaweiDeviceWithoutGoogleServicesUseCase()
+ if (shouldAskPushPermission && !isHuaweiDevice) {
router.push(AppRoute.PushNotification)
} else {
neverToInitiallyAskPermissionUseCase(PUSH_PERMISSION)
diff --git a/features/disclaimer/impl/src/main/java/com/tangem/features/disclaimer/impl/ui/DisclaimerScreen.kt b/features/disclaimer/impl/src/main/java/com/tangem/features/disclaimer/impl/ui/DisclaimerScreen.kt
index 46e17998f8..1a01b428fb 100644
--- a/features/disclaimer/impl/src/main/java/com/tangem/features/disclaimer/impl/ui/DisclaimerScreen.kt
+++ b/features/disclaimer/impl/src/main/java/com/tangem/features/disclaimer/impl/ui/DisclaimerScreen.kt
@@ -17,9 +17,6 @@ import androidx.compose.ui.platform.testTag
import androidx.compose.ui.semantics.contentDescription
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.tooling.preview.Preview
-import com.google.accompanist.permissions.ExperimentalPermissionsApi
-import com.google.accompanist.permissions.isGranted
-import com.google.accompanist.permissions.rememberPermissionState
import com.google.accompanist.web.WebView
import com.google.accompanist.web.WebViewNavigator
import com.google.accompanist.web.rememberWebViewNavigator
@@ -40,7 +37,6 @@ import com.tangem.features.disclaimer.impl.R
import com.tangem.features.disclaimer.impl.entity.DisclaimerUM
import com.tangem.features.disclaimer.impl.entity.DummyDisclaimer
import com.tangem.features.disclaimer.impl.local.localTermsOfServices
-import com.tangem.features.pushnotifications.api.utils.getPushPermissionOrNull
import com.tangem.utils.coroutines.JobHolder
import com.tangem.utils.coroutines.withDebounce
import java.nio.charset.StandardCharsets
@@ -171,15 +167,11 @@ private fun WebViewNavigator.loadLocalToS() {
)
}
-@OptIn(ExperimentalPermissionsApi::class)
@Composable
-private fun BoxScope.DisclaimerButton(onAccept: (Boolean) -> Unit) {
- val isPermissionGranted = getPushPermissionOrNull()?.let { permission ->
- rememberPermissionState(permission = permission).status.isGranted
- } ?: true
+private fun BoxScope.DisclaimerButton(onAccept: () -> Unit) {
PrimaryButton(
text = stringResourceSafe(id = R.string.common_accept),
- onClick = { onAccept(!isPermissionGranted) },
+ onClick = onAccept,
colors = ButtonColors(
containerColor = TangemColorPalette.Light4,
contentColor = TangemColorPalette.Dark6,
diff --git a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/addexistingwallet/entry/AddExistingWalletModel.kt b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/addexistingwallet/entry/AddExistingWalletModel.kt
index b7eb62a719..b404d14746 100644
--- a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/addexistingwallet/entry/AddExistingWalletModel.kt
+++ b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/addexistingwallet/entry/AddExistingWalletModel.kt
@@ -1,23 +1,18 @@
package com.tangem.features.hotwallet.addexistingwallet.entry
-import com.arkivanov.decompose.router.stack.StackNavigation
-import com.arkivanov.decompose.router.stack.pop
-import com.arkivanov.decompose.router.stack.push
-import com.arkivanov.decompose.router.stack.replaceAll
-import com.arkivanov.decompose.router.stack.replaceCurrent
+import com.arkivanov.decompose.router.stack.*
import com.tangem.common.routing.AppRoute
import com.tangem.core.decompose.di.ModelScoped
import com.tangem.core.decompose.model.Model
import com.tangem.core.decompose.navigation.Router
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.domain.settings.ShouldAskPermissionUseCase
-import com.tangem.features.hotwallet.addexistingwallet.im.port.AddExistingWalletImportComponent
import com.tangem.features.hotwallet.addexistingwallet.entry.routing.AddExistingWalletRoute
+import com.tangem.features.hotwallet.addexistingwallet.im.port.AddExistingWalletImportComponent
import com.tangem.features.hotwallet.addexistingwallet.start.AddExistingWalletStartComponent
import com.tangem.features.hotwallet.manualbackup.completed.ManualBackupCompletedComponent
import com.tangem.features.hotwallet.setaccesscode.AccessCodeComponent
import com.tangem.features.hotwallet.setupfinished.MobileWalletSetupFinishedComponent
-import com.tangem.features.pushnotifications.api.PushNotificationsComponent
import com.tangem.features.pushnotifications.api.utils.PUSH_PERMISSION
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.coroutines.launch
@@ -33,7 +28,6 @@ internal class AddExistingWalletModel @Inject constructor(
val addExistingWalletStartModelCallbacks = AddExistingWalletStartModelCallbacks()
val addExistingWalletImportModelCallbacks = AddExistingWalletImportModelCallbacks()
val manualBackupCompletedComponentModelCallbacks = ManualBackupCompletedComponentModelCallbacks()
- val pushNotificationsComponentModelCallbacks = PushNotificationsComponentModelCallbacks()
val accessCodeModelCallbacks = AccessCodeModelCallbacks()
val mobileWalletSetupFinishedComponentModelCallbacks = MobileWalletSetupFinishedComponentModelCallbacks()
@@ -100,12 +94,6 @@ internal class AddExistingWalletModel @Inject constructor(
}
}
- inner class PushNotificationsComponentModelCallbacks : PushNotificationsComponent.ModelCallbacks {
- override fun onResult() {
- stackNavigation.replaceCurrent(AddExistingWalletRoute.SetupFinished)
- }
- }
-
inner class MobileWalletSetupFinishedComponentModelCallbacks :
MobileWalletSetupFinishedComponent.ModelCallbacks {
override fun onContinueClick() {
diff --git a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/addexistingwallet/entry/routing/AddExistingWalletChildFactory.kt b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/addexistingwallet/entry/routing/AddExistingWalletChildFactory.kt
index 2b68c1b132..710b2da90f 100644
--- a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/addexistingwallet/entry/routing/AddExistingWalletChildFactory.kt
+++ b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/addexistingwallet/entry/routing/AddExistingWalletChildFactory.kt
@@ -2,13 +2,15 @@ package com.tangem.features.hotwallet.addexistingwallet.entry.routing
import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.core.ui.decompose.ComposableContentComponent
-import com.tangem.features.hotwallet.setaccesscode.AccessCodeComponent
import com.tangem.features.hotwallet.addexistingwallet.entry.AddExistingWalletModel
-import com.tangem.features.hotwallet.addexistingwallet.start.AddExistingWalletStartComponent
import com.tangem.features.hotwallet.addexistingwallet.im.port.AddExistingWalletImportComponent
+import com.tangem.features.hotwallet.addexistingwallet.start.AddExistingWalletStartComponent
import com.tangem.features.hotwallet.manualbackup.completed.ManualBackupCompletedComponent
+import com.tangem.features.hotwallet.setaccesscode.AccessCodeComponent
import com.tangem.features.hotwallet.setupfinished.MobileWalletSetupFinishedComponent
import com.tangem.features.pushnotifications.api.PushNotificationsComponent
+import com.tangem.features.pushnotifications.api.PushNotificationsModelCallbacksStub
+import com.tangem.features.pushnotifications.api.PushNotificationsParams
import javax.inject.Inject
internal class AddExistingWalletChildFactory @Inject constructor(
@@ -60,8 +62,8 @@ internal class AddExistingWalletChildFactory @Inject constructor(
)
is AddExistingWalletRoute.PushNotifications -> pushNotificationsComponent.create(
context = childContext,
- params = PushNotificationsComponent.Params.Callbacks(
- callbacks = model.pushNotificationsComponentModelCallbacks,
+ params = PushNotificationsParams(
+ modelCallbacks = PushNotificationsModelCallbacksStub(),
),
)
is AddExistingWalletRoute.SetupFinished -> MobileWalletSetupFinishedComponent(
diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/DefaultOnboardingMultiWalletComponent.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/DefaultOnboardingMultiWalletComponent.kt
index ff138a6d70..90696c234b 100644
--- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/DefaultOnboardingMultiWalletComponent.kt
+++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/DefaultOnboardingMultiWalletComponent.kt
@@ -33,7 +33,7 @@ import com.tangem.features.onboarding.v2.multiwallet.impl.child.backup.MultiWall
import com.tangem.features.onboarding.v2.multiwallet.impl.child.chooseoption.Wallet1ChooseOptionComponent
import com.tangem.features.onboarding.v2.multiwallet.impl.child.createwallet.MultiWalletCreateWalletComponent
import com.tangem.features.onboarding.v2.multiwallet.impl.child.finalize.MultiWalletFinalizeComponent
-import com.tangem.features.onboarding.v2.multiwallet.impl.child.scanprimary.Wallet1ScanPrimaryComponent
+import com.tangem.features.onboarding.v2.multiwallet.impl.child.scanprimary.MultiWalletScanPrimaryComponent
import com.tangem.features.onboarding.v2.multiwallet.impl.child.seedphrase.MultiWalletSeedPhraseComponent
import com.tangem.features.onboarding.v2.multiwallet.impl.model.OnboardingMultiWalletModel
import com.tangem.features.onboarding.v2.multiwallet.impl.model.OnboardingMultiWalletState
@@ -159,7 +159,7 @@ internal class DefaultOnboardingMultiWalletComponent @AssistedInject constructor
backButtonClickFlow = backButtonClickFlow,
onBack = { stackNavigation.pop() },
)
- ScanPrimary -> Wallet1ScanPrimaryComponent(
+ ScanPrimary -> MultiWalletScanPrimaryComponent(
context = childContext,
params = childParams,
onDone = { handleNavigationEvent(AddBackupDevice) },
diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/backup/model/MultiWalletBackupModel.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/backup/model/MultiWalletBackupModel.kt
index cee887eceb..4628feb506 100644
--- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/backup/model/MultiWalletBackupModel.kt
+++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/backup/model/MultiWalletBackupModel.kt
@@ -84,6 +84,15 @@ class MultiWalletBackupModel @Inject constructor(
}
analyticsEventHandler.send(OnboardingEvent.Backup.Started)
+
+ // Clear any saved backup before starting the backup process
+ // also clears the primary card if it was set
+ backupService.discardSavedBackup()
+
+ // Primary card from ScanTask or from the ScanPrimaryModel or from MultiWalletCreateWalletModel
+ // always not null for this step
+ val primaryCard = requireNotNull(scanResponse.primaryCard)
+ backupService.setPrimaryCard(primaryCard)
}
private fun getInitState(): MultiWalletBackupUM {
@@ -93,24 +102,11 @@ class MultiWalletBackupModel @Inject constructor(
finalizeButtonEnabled = false,
addBackupButtonEnabled = true,
addBackupButtonLoading = false,
- onAddBackupClick = ::startBackupWallet,
+ onAddBackupClick = ::addBackupCardWithService,
onFinalizeButtonClick = ::onFinalizeClick,
)
}
- private fun startBackupWallet() {
- if (state.value.numberOfBackupCards == 0 && scanResponse.primaryCard != null) {
- backupService.discardSavedBackup()
- }
-
- val primaryCard = scanResponse.primaryCard
- if (primaryCard != null) {
- backupService.setPrimaryCard(primaryCard)
- }
-
- addBackupCardWithService()
- }
-
private fun setNumberOfBackupCards(number: Int) {
// set state for adding backup cards and disable button if there is more than 2 backup cards
_uiState.update { st ->
diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/scanprimary/Wallet1ScanPrimaryComponent.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/scanprimary/MultiWalletScanPrimaryComponent.kt
similarity index 85%
rename from features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/scanprimary/Wallet1ScanPrimaryComponent.kt
rename to features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/scanprimary/MultiWalletScanPrimaryComponent.kt
index f17700e3ed..8e84c772ff 100644
--- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/scanprimary/Wallet1ScanPrimaryComponent.kt
+++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/scanprimary/MultiWalletScanPrimaryComponent.kt
@@ -8,18 +8,18 @@ import com.tangem.core.ui.decompose.ComposableContentComponent
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.features.onboarding.v2.impl.R
import com.tangem.features.onboarding.v2.multiwallet.impl.child.MultiWalletChildParams
-import com.tangem.features.onboarding.v2.multiwallet.impl.child.scanprimary.model.Wallet1ScanPrimaryModel
-import com.tangem.features.onboarding.v2.multiwallet.impl.child.scanprimary.ui.Wallet1ScanPrimary
+import com.tangem.features.onboarding.v2.multiwallet.impl.child.scanprimary.model.MultiWalletScanPrimaryModel
+import com.tangem.features.onboarding.v2.multiwallet.impl.child.scanprimary.ui.MultiWalletScanPrimary
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
-internal class Wallet1ScanPrimaryComponent(
+internal class MultiWalletScanPrimaryComponent(
context: AppComponentContext,
params: MultiWalletChildParams,
onDone: () -> Unit,
) : AppComponentContext by context, ComposableContentComponent {
- private val model: Wallet1ScanPrimaryModel = getOrCreateModel(params)
+ private val model: MultiWalletScanPrimaryModel = getOrCreateModel(params)
init {
params.innerNavigation.update {
@@ -38,7 +38,7 @@ internal class Wallet1ScanPrimaryComponent(
@Composable
override fun Content(modifier: Modifier) {
- Wallet1ScanPrimary(
+ MultiWalletScanPrimary(
isRing = model.isRing,
onScanPrimaryClick = model::onScanPrimaryClick,
)
diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/scanprimary/model/Wallet1ScanPrimaryModel.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/scanprimary/model/MultiWalletScanPrimaryModel.kt
similarity index 72%
rename from features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/scanprimary/model/Wallet1ScanPrimaryModel.kt
rename to features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/scanprimary/model/MultiWalletScanPrimaryModel.kt
index fc8ee3fd60..b40337c12e 100644
--- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/scanprimary/model/Wallet1ScanPrimaryModel.kt
+++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/scanprimary/model/MultiWalletScanPrimaryModel.kt
@@ -5,21 +5,24 @@ import com.tangem.common.CompletionResult
import com.tangem.core.decompose.di.ModelScoped
import com.tangem.core.decompose.model.Model
import com.tangem.core.decompose.model.ParamsContainer
+import com.tangem.domain.card.repository.CardRepository
import com.tangem.domain.card.common.util.cardTypesResolver
import com.tangem.features.onboarding.v2.impl.R
import com.tangem.features.onboarding.v2.multiwallet.impl.child.MultiWalletChildParams
import com.tangem.sdk.api.BackupServiceHolder
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import javax.inject.Inject
@Stable
@ModelScoped
-internal class Wallet1ScanPrimaryModel @Inject constructor(
+internal class MultiWalletScanPrimaryModel @Inject constructor(
paramsContainer: ParamsContainer,
override val dispatchers: CoroutineDispatcherProvider,
private val backupServiceHolder: BackupServiceHolder,
+ private val cardRepository: CardRepository,
) : Model() {
private val params = paramsContainer.require()
@@ -31,9 +34,20 @@ internal class Wallet1ScanPrimaryModel @Inject constructor(
fun onScanPrimaryClick() {
val backupService = backupServiceHolder.backupService.get() ?: return
val iconScanRes = R.drawable.img_hand_scan_ring.takeIf { isRing }
+
backupService.readPrimaryCard(iconScanRes = iconScanRes, cardId = scanResponse.card.cardId) { result ->
when (result) {
is CompletionResult.Success -> {
+ modelScope.launch {
+ cardRepository.startCardActivation(cardId = scanResponse.card.cardId)
+ }
+ params.multiWalletState.update {
+ it.copy(
+ currentScanResponse = scanResponse.copy(
+ primaryCard = result.data,
+ ),
+ )
+ }
modelScope.launch { onDone.emit(Unit) }
}
is CompletionResult.Failure -> Unit
diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/scanprimary/ui/Wallet1ScanPrimary.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/scanprimary/ui/MultiWalletScanPrimary.kt
similarity index 94%
rename from features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/scanprimary/ui/Wallet1ScanPrimary.kt
rename to features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/scanprimary/ui/MultiWalletScanPrimary.kt
index e15c5a640a..f5dd3d3d56 100644
--- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/scanprimary/ui/Wallet1ScanPrimary.kt
+++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/scanprimary/ui/MultiWalletScanPrimary.kt
@@ -17,7 +17,7 @@ import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.features.onboarding.v2.impl.R
@Composable
-internal fun Wallet1ScanPrimary(isRing: Boolean, onScanPrimaryClick: () -> Unit, modifier: Modifier = Modifier) {
+internal fun MultiWalletScanPrimary(isRing: Boolean, onScanPrimaryClick: () -> Unit, modifier: Modifier = Modifier) {
Column(
modifier = modifier
.fillMaxSize()
@@ -66,7 +66,7 @@ internal fun Wallet1ScanPrimary(isRing: Boolean, onScanPrimaryClick: () -> Unit,
@Composable
private fun Preview() {
TangemThemePreview {
- Wallet1ScanPrimary(
+ MultiWalletScanPrimary(
isRing = true,
onScanPrimaryClick = {},
)
diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/di/ComponentModule.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/di/ComponentModule.kt
index 9054f73faa..45a7844f49 100644
--- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/di/ComponentModule.kt
+++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/di/ComponentModule.kt
@@ -9,7 +9,7 @@ import com.tangem.features.onboarding.v2.multiwallet.impl.child.backup.model.Mul
import com.tangem.features.onboarding.v2.multiwallet.impl.child.chooseoption.model.Wallet1ChooseOptionModel
import com.tangem.features.onboarding.v2.multiwallet.impl.child.createwallet.model.MultiWalletCreateWalletModel
import com.tangem.features.onboarding.v2.multiwallet.impl.child.finalize.model.MultiWalletFinalizeModel
-import com.tangem.features.onboarding.v2.multiwallet.impl.child.scanprimary.model.Wallet1ScanPrimaryModel
+import com.tangem.features.onboarding.v2.multiwallet.impl.child.scanprimary.model.MultiWalletScanPrimaryModel
import com.tangem.features.onboarding.v2.multiwallet.impl.child.seedphrase.model.MultiWalletSeedPhraseModel
import com.tangem.features.onboarding.v2.multiwallet.impl.model.OnboardingMultiWalletModel
import dagger.Binds
@@ -70,6 +70,6 @@ internal interface ModelModule {
@Binds
@IntoMap
- @ClassKey(Wallet1ScanPrimaryModel::class)
- fun provideModel8(model: Wallet1ScanPrimaryModel): Model
+ @ClassKey(MultiWalletScanPrimaryModel::class)
+ fun provideModel8(model: MultiWalletScanPrimaryModel): Model
}
\ No newline at end of file
diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/model/OnboardingMultiWalletState.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/model/OnboardingMultiWalletState.kt
index 587cf76440..aeb5dc4011 100644
--- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/model/OnboardingMultiWalletState.kt
+++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/model/OnboardingMultiWalletState.kt
@@ -24,6 +24,9 @@ data class OnboardingMultiWalletState(
* -> [Done]
*
* Wallet2/Ring
+ *
+ * ScanPrimary -> | (BackupService is cleared, no PrimaryCard)
+ * |
* CreateWallet -> SeedPhrase -> AddBackupDevice -> Finalize -> [Done]
* |
* -> AddBackupDevice -> Finalize -> [Done]
diff --git a/features/push-notifications/api/src/main/java/com/tangem/features/pushnotifications/api/PushNotificationsBottomSheetComponent.kt b/features/push-notifications/api/src/main/java/com/tangem/features/pushnotifications/api/PushNotificationsBottomSheetComponent.kt
new file mode 100644
index 0000000000..b72b8c418c
--- /dev/null
+++ b/features/push-notifications/api/src/main/java/com/tangem/features/pushnotifications/api/PushNotificationsBottomSheetComponent.kt
@@ -0,0 +1,9 @@
+package com.tangem.features.pushnotifications.api
+
+import com.tangem.core.decompose.factory.ComponentFactory
+import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
+
+interface PushNotificationsBottomSheetComponent : ComposableBottomSheetComponent {
+
+ interface Factory : ComponentFactory
+}
\ No newline at end of file
diff --git a/features/push-notifications/api/src/main/java/com/tangem/features/pushnotifications/api/PushNotificationsComponent.kt b/features/push-notifications/api/src/main/java/com/tangem/features/pushnotifications/api/PushNotificationsComponent.kt
index fd0b224d91..a514eb89a5 100644
--- a/features/push-notifications/api/src/main/java/com/tangem/features/pushnotifications/api/PushNotificationsComponent.kt
+++ b/features/push-notifications/api/src/main/java/com/tangem/features/pushnotifications/api/PushNotificationsComponent.kt
@@ -1,19 +1,9 @@
package com.tangem.features.pushnotifications.api
-import com.tangem.common.routing.AppRoute
import com.tangem.core.decompose.factory.ComponentFactory
import com.tangem.core.ui.decompose.ComposableContentComponent
interface PushNotificationsComponent : ComposableContentComponent {
- interface Factory : ComponentFactory
-
- interface ModelCallbacks {
- fun onResult()
- }
-
- sealed class Params {
- data class Callbacks(val callbacks: ModelCallbacks) : Params()
- data class Route(val route: AppRoute) : Params()
- }
+ interface Factory : ComponentFactory
}
\ No newline at end of file
diff --git a/features/push-notifications/api/src/main/java/com/tangem/features/pushnotifications/api/PushNotificationsModelCallbacks.kt b/features/push-notifications/api/src/main/java/com/tangem/features/pushnotifications/api/PushNotificationsModelCallbacks.kt
new file mode 100644
index 0000000000..60582b60df
--- /dev/null
+++ b/features/push-notifications/api/src/main/java/com/tangem/features/pushnotifications/api/PushNotificationsModelCallbacks.kt
@@ -0,0 +1,17 @@
+package com.tangem.features.pushnotifications.api
+
+interface PushNotificationsModelCallbacks {
+ fun onAllowSystemPermission()
+ fun onDenySystemPermission()
+ fun onDismiss()
+}
+
+class PushNotificationsModelCallbacksStub(
+ val onAllowSystemPermission: () -> Unit = {},
+ val onDenySystemPermission: () -> Unit = {},
+ val onDismiss: () -> Unit = {},
+) : PushNotificationsModelCallbacks {
+ override fun onAllowSystemPermission() = onAllowSystemPermission.invoke()
+ override fun onDenySystemPermission() = onDenySystemPermission.invoke()
+ override fun onDismiss() = onDismiss.invoke()
+}
\ No newline at end of file
diff --git a/features/push-notifications/api/src/main/java/com/tangem/features/pushnotifications/api/PushNotificationsParams.kt b/features/push-notifications/api/src/main/java/com/tangem/features/pushnotifications/api/PushNotificationsParams.kt
new file mode 100644
index 0000000000..27bc4d7131
--- /dev/null
+++ b/features/push-notifications/api/src/main/java/com/tangem/features/pushnotifications/api/PushNotificationsParams.kt
@@ -0,0 +1,6 @@
+package com.tangem.features.pushnotifications.api
+
+data class PushNotificationsParams(
+ val isBottomSheet: Boolean = false,
+ val modelCallbacks: PushNotificationsModelCallbacks,
+)
\ No newline at end of file
diff --git a/features/push-notifications/impl/build.gradle.kts b/features/push-notifications/impl/build.gradle.kts
index 68fc33bd13..2f2c875648 100644
--- a/features/push-notifications/impl/build.gradle.kts
+++ b/features/push-notifications/impl/build.gradle.kts
@@ -16,6 +16,8 @@ dependencies {
implementation(deps.androidx.activity.compose)
/** Compose */
+ implementation(deps.compose.material3)
+ implementation(deps.compose.ui.tooling)
implementation(deps.compose.foundation)
implementation(deps.compose.accompanist.systemUiController)
implementation(deps.compose.accompanist.permission)
@@ -39,6 +41,7 @@ dependencies {
/** Domain module */
implementation(projects.domain.settings)
implementation(projects.domain.notifications.toggles)
+ implementation(projects.domain.notifications)
/** Feature modules */
implementation(projects.features.pushNotifications.api)
diff --git a/features/push-notifications/impl/src/main/java/com/tangem/features/pushnotifications/impl/DefaultPushNotificationsBottomSheetComponent.kt b/features/push-notifications/impl/src/main/java/com/tangem/features/pushnotifications/impl/DefaultPushNotificationsBottomSheetComponent.kt
new file mode 100644
index 0000000000..259b0bacf0
--- /dev/null
+++ b/features/push-notifications/impl/src/main/java/com/tangem/features/pushnotifications/impl/DefaultPushNotificationsBottomSheetComponent.kt
@@ -0,0 +1,62 @@
+package com.tangem.features.pushnotifications.impl
+
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.collectAsState
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.remember
+import com.tangem.core.decompose.context.AppComponentContext
+import com.tangem.core.decompose.model.getOrCreateModel
+import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
+import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
+import com.tangem.features.pushnotifications.api.PushNotificationsBottomSheetComponent
+import com.tangem.features.pushnotifications.api.PushNotificationsParams
+import com.tangem.features.pushnotifications.impl.model.PushNotificationsModel
+import com.tangem.features.pushnotifications.impl.presentation.ui.PushNotificationsBottomSheet
+import com.tangem.features.pushnotifications.impl.presentation.ui.PushNotificationsContent
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+
+internal class DefaultPushNotificationsBottomSheetComponent @AssistedInject constructor(
+ @Assisted appComponentContext: AppComponentContext,
+ @Assisted private val params: PushNotificationsParams,
+) : PushNotificationsBottomSheetComponent, AppComponentContext by appComponentContext {
+
+ private val model: PushNotificationsModel = getOrCreateModel(params)
+
+ @AssistedFactory
+ interface Factory : PushNotificationsBottomSheetComponent.Factory {
+ override fun create(
+ context: AppComponentContext,
+ params: PushNotificationsParams,
+ ): DefaultPushNotificationsBottomSheetComponent
+ }
+
+ override fun dismiss() {
+ params.modelCallbacks.onDismiss()
+ }
+
+ @Composable
+ override fun BottomSheet() {
+ val state by model.state.collectAsState()
+ val bottomSheetConfig = remember(key1 = this) {
+ TangemBottomSheetConfig(
+ isShown = true,
+ onDismissRequest = ::dismiss,
+ content = TangemBottomSheetConfigContent.Empty,
+ )
+ }
+
+ PushNotificationsBottomSheet(
+ config = bottomSheetConfig,
+ ) {
+ PushNotificationsContent(
+ onAllowClick = model::onAllowClick,
+ onLaterClick = model::onLaterClick,
+ onAllowPermission = model::onAllowPermission,
+ onDenyPermission = model::onDenyPermission,
+ showNotificationsInfo = state.showInfoAboutNotifications,
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/features/push-notifications/impl/src/main/java/com/tangem/features/pushnotifications/impl/DefaultPushNotificationsComponent.kt b/features/push-notifications/impl/src/main/java/com/tangem/features/pushnotifications/impl/DefaultPushNotificationsComponent.kt
index 35ed4ef76a..458d977d4e 100644
--- a/features/push-notifications/impl/src/main/java/com/tangem/features/pushnotifications/impl/DefaultPushNotificationsComponent.kt
+++ b/features/push-notifications/impl/src/main/java/com/tangem/features/pushnotifications/impl/DefaultPushNotificationsComponent.kt
@@ -11,6 +11,7 @@ import com.tangem.core.decompose.model.getOrCreateModel
import com.tangem.core.ui.components.NavigationBar3ButtonsScrim
import com.tangem.core.ui.utils.findActivity
import com.tangem.features.pushnotifications.api.PushNotificationsComponent
+import com.tangem.features.pushnotifications.api.PushNotificationsParams
import com.tangem.features.pushnotifications.impl.model.PushNotificationsModel
import com.tangem.features.pushnotifications.impl.presentation.ui.PushNotificationsScreen
import dagger.assisted.Assisted
@@ -19,7 +20,7 @@ import dagger.assisted.AssistedInject
internal class DefaultPushNotificationsComponent @AssistedInject constructor(
@Assisted appComponentContext: AppComponentContext,
- @Assisted params: PushNotificationsComponent.Params,
+ @Assisted private val params: PushNotificationsParams,
) : PushNotificationsComponent, AppComponentContext by appComponentContext {
private val model: PushNotificationsModel = getOrCreateModel(params)
@@ -31,8 +32,8 @@ internal class DefaultPushNotificationsComponent @AssistedInject constructor(
BackHandler(onBack = { activity.finish() })
NavigationBar3ButtonsScrim()
PushNotificationsScreen(
- onRequest = model::onRequest,
- onNeverRequest = model::onNeverRequest,
+ onAllowClick = model::onAllowClick,
+ onLaterClick = model::onLaterClick,
onAllowPermission = model::onAllowPermission,
onDenyPermission = model::onDenyPermission,
showNotificationsInfo = state.showInfoAboutNotifications,
@@ -43,7 +44,7 @@ internal class DefaultPushNotificationsComponent @AssistedInject constructor(
interface Factory : PushNotificationsComponent.Factory {
override fun create(
context: AppComponentContext,
- params: PushNotificationsComponent.Params,
+ params: PushNotificationsParams,
): DefaultPushNotificationsComponent
}
}
\ No newline at end of file
diff --git a/features/push-notifications/impl/src/main/java/com/tangem/features/pushnotifications/impl/di/PushNotificationsModule.kt b/features/push-notifications/impl/src/main/java/com/tangem/features/pushnotifications/impl/di/PushNotificationsModule.kt
index edbd3dc188..06d4376447 100644
--- a/features/push-notifications/impl/src/main/java/com/tangem/features/pushnotifications/impl/di/PushNotificationsModule.kt
+++ b/features/push-notifications/impl/src/main/java/com/tangem/features/pushnotifications/impl/di/PushNotificationsModule.kt
@@ -1,7 +1,9 @@
package com.tangem.features.pushnotifications.impl.di
import com.tangem.core.decompose.model.Model
+import com.tangem.features.pushnotifications.api.PushNotificationsBottomSheetComponent
import com.tangem.features.pushnotifications.api.PushNotificationsComponent
+import com.tangem.features.pushnotifications.impl.DefaultPushNotificationsBottomSheetComponent
import com.tangem.features.pushnotifications.impl.DefaultPushNotificationsComponent
import com.tangem.features.pushnotifications.impl.model.PushNotificationsModel
import dagger.Binds
@@ -15,6 +17,11 @@ import dagger.multibindings.IntoMap
@InstallIn(SingletonComponent::class)
internal interface PushNotificationsModule {
+ @Binds
+ fun bindBottomSheetComponentFactory(
+ impl: DefaultPushNotificationsBottomSheetComponent.Factory,
+ ): PushNotificationsBottomSheetComponent.Factory
+
@Binds
fun bindComponentFactory(impl: DefaultPushNotificationsComponent.Factory): PushNotificationsComponent.Factory
diff --git a/features/push-notifications/impl/src/main/java/com/tangem/features/pushnotifications/impl/model/PushNotificationsClickIntents.kt b/features/push-notifications/impl/src/main/java/com/tangem/features/pushnotifications/impl/model/PushNotificationsClickIntents.kt
index 99b02a379c..ad7b69bc71 100644
--- a/features/push-notifications/impl/src/main/java/com/tangem/features/pushnotifications/impl/model/PushNotificationsClickIntents.kt
+++ b/features/push-notifications/impl/src/main/java/com/tangem/features/pushnotifications/impl/model/PushNotificationsClickIntents.kt
@@ -1,9 +1,9 @@
package com.tangem.features.pushnotifications.impl.model
internal interface PushNotificationsClickIntents {
- fun onRequest()
+ fun onAllowClick()
- fun onNeverRequest()
+ fun onLaterClick()
fun onAllowPermission()
diff --git a/features/push-notifications/impl/src/main/java/com/tangem/features/pushnotifications/impl/model/PushNotificationsModel.kt b/features/push-notifications/impl/src/main/java/com/tangem/features/pushnotifications/impl/model/PushNotificationsModel.kt
index 1d34193a8f..735932ce2c 100644
--- a/features/push-notifications/impl/src/main/java/com/tangem/features/pushnotifications/impl/model/PushNotificationsModel.kt
+++ b/features/push-notifications/impl/src/main/java/com/tangem/features/pushnotifications/impl/model/PushNotificationsModel.kt
@@ -1,16 +1,18 @@
package com.tangem.features.pushnotifications.impl.model
import androidx.compose.runtime.Stable
+import com.tangem.common.routing.AppRoute
import com.tangem.common.routing.AppRouter
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.analytics.models.AnalyticsParam
import com.tangem.core.decompose.di.ModelScoped
import com.tangem.core.decompose.model.Model
import com.tangem.core.decompose.model.ParamsContainer
+import com.tangem.domain.notifications.repository.NotificationsRepository
import com.tangem.domain.notifications.toggles.NotificationsFeatureToggles
import com.tangem.domain.settings.NeverRequestPermissionUseCase
import com.tangem.domain.settings.NeverToInitiallyAskPermissionUseCase
-import com.tangem.features.pushnotifications.api.PushNotificationsComponent
+import com.tangem.features.pushnotifications.api.PushNotificationsParams
import com.tangem.features.pushnotifications.api.analytics.PushNotificationAnalyticEvents
import com.tangem.features.pushnotifications.api.utils.PUSH_PERMISSION
import com.tangem.features.pushnotifications.impl.presentation.state.PushNotificationsUM
@@ -20,9 +22,9 @@ import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
import javax.inject.Inject
+@Suppress("LongParameterList")
@Stable
@ModelScoped
-@Suppress("LongParameterList")
internal class PushNotificationsModel @Inject constructor(
paramsContainer: ParamsContainer,
override val dispatchers: CoroutineDispatcherProvider,
@@ -30,10 +32,11 @@ internal class PushNotificationsModel @Inject constructor(
private val neverToInitiallyAskPermissionUseCase: NeverToInitiallyAskPermissionUseCase,
private val appRouter: AppRouter,
private val analyticHandler: AnalyticsEventHandler,
- notificationsFeatureToggles: NotificationsFeatureToggles,
+ private val notificationsFeatureToggles: NotificationsFeatureToggles,
+ private val notificationsRepository: NotificationsRepository,
) : Model(), PushNotificationsClickIntents {
- private val params: PushNotificationsComponent.Params = paramsContainer.require()
+ val params: PushNotificationsParams = paramsContainer.require()
private val _state = MutableStateFlow(
PushNotificationsUM(
@@ -43,20 +46,33 @@ internal class PushNotificationsModel @Inject constructor(
val state = _state.asStateFlow()
- override fun onRequest() {
+ override fun onAllowClick() {
+ if (notificationsFeatureToggles.isNotificationsEnabled) {
+ modelScope.launch {
+ notificationsRepository.setUserAllowToSubscribeOnPushNotifications(true)
+ }
+ }
analyticHandler.send(
PushNotificationAnalyticEvents.ButtonAllow(AnalyticsParam.ScreensSources.Stories),
)
}
- override fun onNeverRequest() {
+ override fun onLaterClick() {
+ if (notificationsFeatureToggles.isNotificationsEnabled) {
+ modelScope.launch {
+ notificationsRepository.setUserAllowToSubscribeOnPushNotifications(false)
+ }
+ }
analyticHandler.send(
PushNotificationAnalyticEvents.ButtonLater(AnalyticsParam.ScreensSources.Stories),
)
modelScope.launch {
neverRequestPermissionUseCase(PUSH_PERMISSION)
neverToInitiallyAskPermissionUseCase(PUSH_PERMISSION)
- onResult()
+ params.modelCallbacks.onDenySystemPermission()
+ if (!params.isBottomSheet) {
+ appRouter.push(AppRoute.Home())
+ }
}
}
@@ -67,7 +83,10 @@ internal class PushNotificationsModel @Inject constructor(
modelScope.launch {
neverRequestPermissionUseCase(PUSH_PERMISSION)
neverToInitiallyAskPermissionUseCase(PUSH_PERMISSION)
- onResult()
+ params.modelCallbacks.onAllowSystemPermission()
+ if (!params.isBottomSheet) {
+ appRouter.push(AppRoute.Home())
+ }
}
}
@@ -78,17 +97,9 @@ internal class PushNotificationsModel @Inject constructor(
modelScope.launch {
neverRequestPermissionUseCase(PUSH_PERMISSION)
neverToInitiallyAskPermissionUseCase(PUSH_PERMISSION)
- onResult()
- }
- }
-
- private fun onResult() {
- when (params) {
- is PushNotificationsComponent.Params.Callbacks -> {
- params.callbacks.onResult()
- }
- is PushNotificationsComponent.Params.Route -> {
- appRouter.push(params.route)
+ params.modelCallbacks.onDenySystemPermission()
+ if (!params.isBottomSheet) {
+ appRouter.push(AppRoute.Home())
}
}
}
diff --git a/features/push-notifications/impl/src/main/java/com/tangem/features/pushnotifications/impl/presentation/ui/PushNotificationsBottomSheet.kt b/features/push-notifications/impl/src/main/java/com/tangem/features/pushnotifications/impl/presentation/ui/PushNotificationsBottomSheet.kt
new file mode 100644
index 0000000000..fa78628411
--- /dev/null
+++ b/features/push-notifications/impl/src/main/java/com/tangem/features/pushnotifications/impl/presentation/ui/PushNotificationsBottomSheet.kt
@@ -0,0 +1,118 @@
+package com.tangem.features.pushnotifications.impl.presentation.ui
+
+import android.content.res.Configuration
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.padding
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.tooling.preview.Preview
+import com.tangem.core.ui.R
+import com.tangem.core.ui.components.SpacerH28
+import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
+import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
+import com.tangem.core.ui.components.bottomsheets.modal.TangemModalBottomSheet
+import com.tangem.core.ui.components.bottomsheets.modal.TangemModalBottomSheetTitle
+import com.tangem.core.ui.components.showcase.ShowcaseButtons
+import com.tangem.core.ui.components.showcase.ShowcaseContent
+import com.tangem.core.ui.components.showcase.model.ShowcaseItemModel
+import com.tangem.core.ui.extensions.resourceReference
+import com.tangem.core.ui.res.TangemTheme
+import com.tangem.core.ui.res.TangemThemePreview
+import com.tangem.core.ui.utils.requestPermission
+import com.tangem.features.pushnotifications.api.utils.PUSH_PERMISSION
+import kotlinx.collections.immutable.persistentListOf
+
+@Composable
+internal fun PushNotificationsBottomSheet(config: TangemBottomSheetConfig, content: @Composable () -> Unit) {
+ TangemModalBottomSheet(
+ config = config,
+ title = {
+ TangemModalBottomSheetTitle(
+ endIconRes = R.drawable.ic_close_24,
+ onEndClick = config.onDismissRequest,
+ )
+ },
+ ) {
+ content()
+ }
+}
+
+@Composable
+internal fun PushNotificationsContent(
+ onAllowClick: () -> Unit,
+ onLaterClick: () -> Unit,
+ onAllowPermission: () -> Unit,
+ onDenyPermission: () -> Unit,
+ showNotificationsInfo: Boolean,
+) {
+ val requestPushPermission = requestPermission(
+ onAllow = onAllowPermission,
+ onDeny = onDenyPermission,
+ permission = PUSH_PERMISSION,
+ )
+
+ Column(modifier = Modifier.background(TangemTheme.colors.background.primary)) {
+ ShowcaseContent(
+ headerIconRes = R.drawable.ic_notifications_unread_24,
+ headerText = resourceReference(R.string.user_push_notification_agreement_header),
+ showcaseItems = persistentListOf(
+ ShowcaseItemModel(
+ R.drawable.ic_rocket_launch_24,
+ resourceReference(R.string.user_push_notification_agreement_argument_one),
+ ),
+ ShowcaseItemModel(
+ R.drawable.ic_storefront_24,
+ resourceReference(R.string.user_push_notification_agreement_argument_two),
+ ),
+ ).let { baseItems ->
+ if (showNotificationsInfo) {
+ baseItems.add(
+ ShowcaseItemModel(
+ R.drawable.ic_notifications_24,
+ resourceReference(R.string.user_push_notification_agreement_argument_three),
+ ),
+ )
+ } else {
+ baseItems
+ }
+ },
+ modifier = Modifier.padding(top = TangemTheme.dimens.spacing40),
+ )
+ SpacerH28()
+ ShowcaseButtons(
+ primaryButtonText = resourceReference(R.string.common_allow),
+ onPrimaryClick = {
+ onAllowClick()
+ requestPushPermission()
+ },
+ secondaryButtonText = resourceReference(R.string.common_later),
+ onSecondaryClick = {
+ onLaterClick()
+ },
+ )
+ }
+}
+
+@Composable
+@Preview(showBackground = true, widthDp = 360)
+@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
+private fun Preview_PushNotificationsBottomSheet() {
+ TangemThemePreview {
+ PushNotificationsBottomSheet(
+ config = TangemBottomSheetConfig(
+ isShown = true,
+ onDismissRequest = {},
+ content = TangemBottomSheetConfigContent.Empty,
+ ),
+ ) {
+ PushNotificationsContent(
+ onAllowClick = {},
+ onLaterClick = {},
+ onAllowPermission = {},
+ onDenyPermission = {},
+ showNotificationsInfo = true,
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/features/push-notifications/impl/src/main/java/com/tangem/features/pushnotifications/impl/presentation/ui/PushNotificationsScreen.kt b/features/push-notifications/impl/src/main/java/com/tangem/features/pushnotifications/impl/presentation/ui/PushNotificationsScreen.kt
index 4d6a0e3406..4750463f50 100644
--- a/features/push-notifications/impl/src/main/java/com/tangem/features/pushnotifications/impl/presentation/ui/PushNotificationsScreen.kt
+++ b/features/push-notifications/impl/src/main/java/com/tangem/features/pushnotifications/impl/presentation/ui/PushNotificationsScreen.kt
@@ -1,29 +1,29 @@
package com.tangem.features.pushnotifications.impl.presentation.ui
import androidx.compose.foundation.layout.systemBarsPadding
-import androidx.compose.runtime.*
+import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import com.tangem.core.ui.components.showcase.Showcase
import com.tangem.core.ui.components.showcase.model.ShowcaseButtonModel
import com.tangem.core.ui.components.showcase.model.ShowcaseItemModel
import com.tangem.core.ui.extensions.resourceReference
-import com.tangem.core.ui.utils.requestPushPermission
+import com.tangem.core.ui.utils.requestPermission
import com.tangem.feature.pushnotifications.impl.R
-import com.tangem.features.pushnotifications.api.utils.getPushPermissionOrNull
+import com.tangem.features.pushnotifications.api.utils.PUSH_PERMISSION
import kotlinx.collections.immutable.persistentListOf
@Composable
internal fun PushNotificationsScreen(
- onRequest: () -> Unit,
- onNeverRequest: () -> Unit,
+ onAllowClick: () -> Unit,
+ onLaterClick: () -> Unit,
onAllowPermission: () -> Unit,
onDenyPermission: () -> Unit,
showNotificationsInfo: Boolean,
) {
- val requestPushPermission = requestPushPermission(
+ val requestPushPermission = requestPermission(
onAllow = onAllowPermission,
onDeny = onDenyPermission,
- pushPermission = getPushPermissionOrNull(),
+ permission = PUSH_PERMISSION,
)
Showcase(
@@ -53,13 +53,15 @@ internal fun PushNotificationsScreen(
primaryButton = ShowcaseButtonModel(
buttonText = resourceReference(R.string.common_allow),
onClick = {
- onRequest()
+ onAllowClick()
requestPushPermission()
},
),
secondaryButton = ShowcaseButtonModel(
buttonText = resourceReference(R.string.common_later),
- onClick = onNeverRequest,
+ onClick = {
+ onLaterClick()
+ },
),
modifier = Modifier.systemBarsPadding(),
)
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 42ea4e9a86..7f8da42be9 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
@@ -26,6 +26,8 @@ import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.nft.DisableWalletNFTUseCase
import com.tangem.domain.nft.EnableWalletNFTUseCase
import com.tangem.domain.nft.GetWalletNFTEnabledUseCase
+import com.tangem.domain.notifications.GetIsHuaweiDeviceWithoutGoogleServicesUseCase
+import com.tangem.domain.notifications.repository.NotificationsRepository
import com.tangem.domain.notifications.toggles.NotificationsFeatureToggles
import com.tangem.domain.settings.repositories.PermissionRepository
import com.tangem.domain.models.wallet.UserWallet
@@ -74,6 +76,8 @@ internal class WalletSettingsModel @Inject constructor(
private val settingsManager: SettingsManager,
private val permissionsRepository: PermissionRepository,
private val hotWalletFeatureToggles: HotWalletFeatureToggles,
+ private val notificationsRepository: NotificationsRepository,
+ private val getIsHuaweiDeviceWithoutGoogleServicesUseCase: GetIsHuaweiDeviceWithoutGoogleServicesUseCase,
) : Model() {
val params: WalletSettingsComponent.Params = paramsContainer.require()
@@ -98,6 +102,8 @@ internal class WalletSettingsModel @Inject constructor(
val wallet = maybeWallet.getOrNull() ?: return@combine
wallet.requireColdWallet() // TODO [REDACTED_TASK_KEY] [Hot Wallet] Wallet Settings
val isRenameWalletAvailable = getShouldSaveUserWalletsSyncUseCase()
+ val isNeedShowNotifications = notificationsToggles.isNotificationsEnabled &&
+ !getIsHuaweiDeviceWithoutGoogleServicesUseCase()
state.update { value ->
value.copy(
items = buildItems(
@@ -106,7 +112,7 @@ internal class WalletSettingsModel @Inject constructor(
isRenameWalletAvailable = isRenameWalletAvailable,
isNFTEnabled = nftEnabled,
isNotificationsEnabled = notificationsEnabled,
- isNotificationsFeatureEnabled = notificationsToggles.isNotificationsEnabled,
+ isNotificationsFeatureEnabled = isNeedShowNotifications,
isNotificationsPermissionGranted = isNotificationsPermissionGranted(),
isHotWalletEnabled = hotWalletFeatureToggles.isHotWalletEnabled,
),
@@ -230,6 +236,10 @@ internal class WalletSettingsModel @Inject constructor(
private fun onCheckedNotificationsChange(isChecked: Boolean) {
modelScope.launch {
if (isChecked) {
+ if (getIsHuaweiDeviceWithoutGoogleServicesUseCase()) {
+ showHuaweiDialog()
+ return@launch
+ }
state.update { value ->
value.copy(
requestPushNotificationsPermission = true,
@@ -242,6 +252,21 @@ internal class WalletSettingsModel @Inject constructor(
}
}
+ private fun showHuaweiDialog() {
+ val message = DialogMessage(
+ message = resourceReference(R.string.wallet_settings_push_notifications_huawei_warning),
+ firstActionBuilder = {
+ EventMessageAction(
+ title = resourceReference(R.string.common_ok),
+ warning = true,
+ onClick = {},
+ )
+ },
+ )
+
+ messageSender.send(message)
+ }
+
private fun onNotificationsDescriptionClick() {
bottomSheetNavigation.activate(NetworksAvailableForNotificationBSConfig)
}
@@ -260,6 +285,7 @@ internal class WalletSettingsModel @Inject constructor(
if (isGranted) {
modelScope.launch {
setNotificationsEnabledUseCase(params.userWalletId, true).onRight {
+ notificationsRepository.setNotificationsWasEnabledAutomatically(params.userWalletId.stringValue)
analyticsEventHandler.send(PushNotificationAnalyticEvents.NotificationsEnabled(true))
}
}
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 08719a0e52..fe95f8129a 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
@@ -8,6 +8,7 @@ import androidx.compose.foundation.lazy.items
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.testTag
@@ -28,12 +29,12 @@ 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.test.WalletSettingsScreenTestTags
-import com.tangem.core.ui.utils.requestPushPermission
+import com.tangem.core.ui.utils.requestPermission
import com.tangem.feature.walletsettings.component.preview.PreviewWalletSettingsComponent
import com.tangem.feature.walletsettings.entity.WalletSettingsItemUM
import com.tangem.feature.walletsettings.entity.WalletSettingsUM
import com.tangem.feature.walletsettings.impl.R
-import com.tangem.features.pushnotifications.api.utils.getPushPermissionOrNull
+import com.tangem.features.pushnotifications.api.utils.PUSH_PERMISSION
@Composable
internal fun WalletSettingsScreen(
@@ -119,14 +120,16 @@ private fun Content(state: WalletSettingsUM, modifier: Modifier = Modifier) {
}
}
- val requestPushPermission = requestPushPermission(
+ val requestPushPermission = requestPermission(
onAllow = { state.onPushNotificationPermissionGranted(true) },
onDeny = { state.onPushNotificationPermissionGranted(false) },
- pushPermission = getPushPermissionOrNull(),
+ permission = PUSH_PERMISSION,
)
if (state.requestPushNotificationsPermission) {
- requestPushPermission()
+ LaunchedEffect(Unit) {
+ requestPushPermission()
+ }
}
}
diff --git a/features/wallet/impl/build.gradle.kts b/features/wallet/impl/build.gradle.kts
index 6899c4cad4..77dd37708d 100644
--- a/features/wallet/impl/build.gradle.kts
+++ b/features/wallet/impl/build.gradle.kts
@@ -95,6 +95,8 @@ dependencies {
implementation(projects.domain.visa)
implementation(projects.domain.wallets)
implementation(projects.domain.wallets.models)
+ implementation(projects.domain.notifications)
+ implementation(projects.domain.notifications.toggles)
/** Feature Apis */
implementation(projects.features.details.api)
diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/WalletComponent.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/WalletComponent.kt
index 21400eff17..07a629a880 100644
--- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/WalletComponent.kt
+++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/WalletComponent.kt
@@ -21,6 +21,8 @@ import com.tangem.feature.wallet.presentation.wallet.ui.WalletScreen
import com.tangem.feature.walletsettings.component.RenameWalletComponent
import com.tangem.features.biometry.AskBiometryComponent
import com.tangem.features.markets.entry.MarketsEntryComponent
+import com.tangem.features.pushnotifications.api.PushNotificationsBottomSheetComponent
+import com.tangem.features.pushnotifications.api.PushNotificationsParams
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
@@ -32,6 +34,7 @@ internal class WalletComponent @AssistedInject constructor(
private val renameWalletComponentFactory: RenameWalletComponent.Factory,
private val marketsEntryComponentFactory: MarketsEntryComponent.Factory,
private val askBiometryComponentFactory: AskBiometryComponent.Factory,
+ private val pushNotificationsBottomSheetComponent: PushNotificationsBottomSheetComponent.Factory,
) : ComposableContentComponent, AppComponentContext by appComponentContext {
private val model: WalletModel = getOrCreateModel()
@@ -66,6 +69,13 @@ internal class WalletComponent @AssistedInject constructor(
),
)
}
+ WalletDialogConfig.AskForPushNotifications -> pushNotificationsBottomSheetComponent.create(
+ context = childByContext(componentContext),
+ params = PushNotificationsParams(
+ isBottomSheet = true,
+ modelCallbacks = model.askForPushNotificationsModelCallbacks,
+ ),
+ )
}
},
)
diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/WalletModel.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/WalletModel.kt
index 2202b93333..e62305cd29 100644
--- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/WalletModel.kt
+++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/WalletModel.kt
@@ -11,16 +11,18 @@ import com.tangem.core.decompose.di.ModelScoped
import com.tangem.core.decompose.model.Model
import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase
import com.tangem.domain.card.common.util.cardTypesResolver
+import com.tangem.domain.models.wallet.UserWallet
+import com.tangem.domain.models.wallet.UserWalletId
+import com.tangem.domain.models.wallet.isMultiCurrency
import com.tangem.domain.nft.ObserveAndClearNFTCacheIfNeedUseCase
+import com.tangem.domain.notifications.GetIsHuaweiDeviceWithoutGoogleServicesUseCase
+import com.tangem.domain.notifications.repository.NotificationsRepository
+import com.tangem.domain.notifications.toggles.NotificationsFeatureToggles
import com.tangem.domain.settings.*
import com.tangem.domain.tokens.FetchCurrencyStatusUseCase
import com.tangem.domain.tokens.RefreshMultiCurrencyWalletQuotesUseCase
import com.tangem.domain.tokens.TokensFeatureToggles
-import com.tangem.domain.models.wallet.UserWallet
-import com.tangem.domain.models.wallet.UserWalletId
-import com.tangem.domain.models.wallet.isMultiCurrency
-import com.tangem.domain.wallets.usecase.GetSelectedWalletUseCase
-import com.tangem.domain.wallets.usecase.GetWalletsUseCase
+import com.tangem.domain.wallets.usecase.*
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
import com.tangem.feature.wallet.presentation.router.InnerWalletRouter
import com.tangem.feature.wallet.presentation.wallet.analytics.WalletScreenAnalyticsEvent
@@ -28,7 +30,6 @@ import com.tangem.feature.wallet.presentation.wallet.analytics.utils.SelectedWal
import com.tangem.feature.wallet.presentation.wallet.domain.*
import com.tangem.feature.wallet.presentation.wallet.loaders.WalletScreenContentLoader
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
-import com.tangem.feature.wallet.presentation.wallet.state.model.PushNotificationsBottomSheetConfig
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletDialogConfig
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletEvent
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletEvent.DemonstrateWalletsScrollPreview.Direction
@@ -37,8 +38,8 @@ import com.tangem.feature.wallet.presentation.wallet.state.transformers.*
import com.tangem.feature.wallet.presentation.wallet.state.utils.WalletEventSender
import com.tangem.feature.wallet.presentation.wallet.utils.ScreenLifecycleProvider
import com.tangem.features.biometry.AskBiometryComponent
+import com.tangem.features.pushnotifications.api.PushNotificationsModelCallbacks
import com.tangem.features.pushnotifications.api.utils.PUSH_PERMISSION
-import com.tangem.features.pushnotifications.api.utils.getPushPermissionOrNull
import com.tangem.features.wallet.deeplink.WalletDeepLinkActionListener
import com.tangem.utils.Provider
import com.tangem.utils.coroutines.*
@@ -79,11 +80,18 @@ internal class WalletModel @Inject constructor(
private val tokensFeatureToggles: TokensFeatureToggles,
private val observeAndClearNFTCacheIfNeedUseCase: ObserveAndClearNFTCacheIfNeedUseCase,
private val walletDeepLinkActionListener: WalletDeepLinkActionListener,
+ private val notificationsRepository: NotificationsRepository,
+ private val getWalletsListForEnablingUseCase: GetWalletsForAutomaticallyPushEnablingUseCase,
+ private val setNotificationsEnabledUseCase: SetNotificationsEnabledUseCase,
+ private val notificationsFeatureToggles: NotificationsFeatureToggles,
+ private val getIsBiometryIsEnabledUseCase: GetIsBiometricsEnabledUseCase,
+ private val getIsHuaweiDeviceWithoutGoogleServicesUseCase: GetIsHuaweiDeviceWithoutGoogleServicesUseCase,
val screenLifecycleProvider: ScreenLifecycleProvider,
val innerWalletRouter: InnerWalletRouter,
) : Model() {
val askBiometryModelCallbacks = AskBiometryModelCallbacks()
+ val askForPushNotificationsModelCallbacks = AskForPushNotificationsCallbacks()
val uiState: StateFlow = stateHolder.uiState
private val walletsUpdateJobHolder = JobHolder()
@@ -106,6 +114,7 @@ internal class WalletModel @Inject constructor(
subscribeOnSelectedWalletFlow()
subscribeToScreenBackgroundState()
subscribeOnPushNotificationsPermission()
+ enableNotificationsIfNeeded()
clickIntents.initialize(innerWalletRouter, modelScope)
}
@@ -201,20 +210,19 @@ internal class WalletModel @Inject constructor(
private fun subscribeOnPushNotificationsPermission() {
modelScope.launch {
- val shouldRequestPush = shouldAskPermissionUseCase(PUSH_PERMISSION)
- val isPushPermissionAvailable = getPushPermissionOrNull() != null
- if (!shouldRequestPush || !isPushPermissionAvailable) return@launch
+ val shouldAskPermission = shouldAskPermissionUseCase(PUSH_PERMISSION)
+ val afterUpdate = notificationsRepository.shouldShowSubscribeOnNotificationsAfterUpdate()
+ val isBiometricsEnabled = getIsBiometryIsEnabledUseCase()
+ val isHuaweiDevice = getIsHuaweiDeviceWithoutGoogleServicesUseCase()
+ val shouldShowBottomSheet = shouldAskPermission || afterUpdate
+ if (!isBiometricsEnabled) return@launch
+ if (isHuaweiDevice) return@launch
+ if (!shouldShowBottomSheet) return@launch
delay(timeMillis = 1_800)
- stateHolder.showBottomSheet(
- content = PushNotificationsBottomSheetConfig(
- onRequest = clickIntents::onRequestPushPermission,
- onNeverRequest = { clickIntents.onNeverAskPushPermission(false) },
- onAllow = clickIntents::onAllowPushPermission,
- onDeny = clickIntents::onDenyPushPermission,
- ),
- onDismiss = { clickIntents.onNeverAskPushPermission(true) },
+ innerWalletRouter.dialogNavigation.activate(
+ configuration = WalletDialogConfig.AskForPushNotifications,
)
}
}
@@ -435,6 +443,8 @@ internal class WalletModel @Inject constructor(
it.copy(selectedWalletIndex = action.selectedWalletIndex)
}
}
+
+ enableNotificationsIfNeeded()
}
private fun deleteWallet(action: WalletsUpdateActionResolver.Action.DeleteWallet) {
@@ -552,6 +562,26 @@ internal class WalletModel @Inject constructor(
}
}
+ private fun enableNotificationsIfNeeded() {
+ if (!notificationsFeatureToggles.isNotificationsEnabled) return
+ modelScope.launch {
+ val isUserAllowToEnableNotifications = notificationsRepository.isUserAllowToSubscribeOnPushNotifications()
+ if (isUserAllowToEnableNotifications) {
+ val alreadyEnabledWallets = notificationsRepository.getWalletAutomaticallyEnabledList().map {
+ UserWalletId(it)
+ }
+ val walletsListWhichShouldBeEnabled = getWalletsListForEnablingUseCase(alreadyEnabledWallets)
+ walletsListWhichShouldBeEnabled.forEach { userWalletId ->
+ setNotificationsEnabledUseCase(userWalletId, true).onRight {
+ notificationsRepository.setNotificationsWasEnabledAutomatically(userWalletId.stringValue)
+ }.onLeft {
+ Timber.e(it)
+ }
+ }
+ }
+ }
+ }
+
inner class AskBiometryModelCallbacks : AskBiometryComponent.ModelCallbacks {
override fun onAllowed() {
analyticsEventsHandler.send(MainScreenAnalyticsEvent.EnableBiometrics(AnalyticsParam.OnOffState.On))
@@ -564,6 +594,23 @@ internal class WalletModel @Inject constructor(
}
}
+ inner class AskForPushNotificationsCallbacks : PushNotificationsModelCallbacks {
+
+ override fun onAllowSystemPermission() {
+ innerWalletRouter.dialogNavigation.dismiss()
+ enableNotificationsIfNeeded()
+ }
+
+ override fun onDenySystemPermission() {
+ innerWalletRouter.dialogNavigation.dismiss()
+ enableNotificationsIfNeeded()
+ }
+
+ override fun onDismiss() {
+ innerWalletRouter.dialogNavigation.dismiss()
+ }
+ }
+
private companion object {
const val REFRESH_WALLET_BACKGROUND_TIMER_MILLIS = 10000L
const val EXPRESS_STATUS_UPDATE_DELAY = 10000L
diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletDialogConfig.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletDialogConfig.kt
index eaff76d36d..2134c40ef5 100644
--- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletDialogConfig.kt
+++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletDialogConfig.kt
@@ -16,4 +16,7 @@ internal sealed interface WalletDialogConfig {
@Serializable
data object AskForBiometry : WalletDialogConfig
+
+ @Serializable
+ data object AskForPushNotifications : WalletDialogConfig
}
\ No newline at end of file
diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/WalletScreen.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/WalletScreen.kt
index f499ecb99e..9f053d4423 100644
--- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/WalletScreen.kt
+++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/WalletScreen.kt
@@ -75,7 +75,6 @@ import com.tangem.feature.wallet.impl.R
import com.tangem.feature.wallet.presentation.common.preview.WalletScreenPreviewData.walletScreenState
import com.tangem.feature.wallet.presentation.wallet.state.model.*
import com.tangem.feature.wallet.presentation.wallet.state.model.holder.TxHistoryStateHolder
-import com.tangem.feature.wallet.presentation.wallet.ui.components.PushNotificationsBottomSheet
import com.tangem.feature.wallet.presentation.wallet.ui.components.TokenActionsBottomSheet
import com.tangem.feature.wallet.presentation.wallet.ui.components.WalletsList
import com.tangem.feature.wallet.presentation.wallet.ui.components.common.*
@@ -709,7 +708,6 @@ private fun ShowBottomSheet(bottomSheetConfig: TangemBottomSheetConfig?) {
is ChooseAddressBottomSheetConfig -> ChooseAddressBottomSheet(config = bottomSheetConfig)
is BalancesAndLimitsBottomSheetConfig -> BalancesAndLimitsBottomSheet(config = bottomSheetConfig)
is VisaTxDetailsBottomSheetConfig -> VisaTxDetailsBottomSheet(config = bottomSheetConfig)
- is PushNotificationsBottomSheetConfig -> PushNotificationsBottomSheet(config = bottomSheetConfig)
is ExpressStatusBottomSheetConfig -> ExpressStatusBottomSheet(config = bottomSheetConfig)
}
}
diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/PushNotificationsBottomSheet.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/PushNotificationsBottomSheet.kt
deleted file mode 100644
index e61ceddcbf..0000000000
--- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/PushNotificationsBottomSheet.kt
+++ /dev/null
@@ -1,111 +0,0 @@
-package com.tangem.feature.wallet.presentation.wallet.ui.components
-
-import android.content.res.Configuration
-import androidx.compose.foundation.background
-import androidx.compose.foundation.layout.Arrangement
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.Row
-import androidx.compose.foundation.layout.padding
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.tooling.preview.Preview
-import com.tangem.core.ui.components.PrimaryButton
-import com.tangem.core.ui.components.SecondaryButton
-import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
-import com.tangem.core.ui.components.bottomsheets.sheet.TangemBottomSheet
-import com.tangem.core.ui.components.showcase.ShowcaseContent
-import com.tangem.core.ui.components.showcase.model.ShowcaseItemModel
-import com.tangem.core.ui.extensions.resourceReference
-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.requestPushPermission
-import com.tangem.feature.wallet.impl.R
-import com.tangem.feature.wallet.presentation.wallet.state.model.PushNotificationsBottomSheetConfig
-import com.tangem.features.pushnotifications.api.utils.getPushPermissionOrNull
-import kotlinx.collections.immutable.persistentListOf
-
-@Composable
-internal fun PushNotificationsBottomSheet(config: TangemBottomSheetConfig) {
- TangemBottomSheet(config = config) {
- PushNotificationsSheetContent(content = it, onDismiss = config.onDismissRequest)
- }
-}
-
-@Composable
-private fun PushNotificationsSheetContent(content: PushNotificationsBottomSheetConfig, onDismiss: () -> Unit) {
- val requestPushPermission = requestPushPermission(
- pushPermission = getPushPermissionOrNull(),
- onAllow = {
- content.onAllow()
- onDismiss()
- },
- onDeny = {
- content.onDeny()
- onDismiss()
- },
- )
-
- Column(modifier = Modifier.background(TangemTheme.colors.background.primary)) {
- ShowcaseContent(
- headerIconRes = R.drawable.ic_notifications_unread_24,
- headerText = resourceReference(R.string.user_push_notification_agreement_header),
- showcaseItems = persistentListOf(
- ShowcaseItemModel(
- iconRes = R.drawable.ic_rocket_launch_24,
- text = resourceReference(R.string.user_push_notification_agreement_argument_one),
- ),
- ShowcaseItemModel(
- iconRes = R.drawable.ic_storefront_24,
- text = resourceReference(R.string.user_push_notification_agreement_argument_two),
- ),
- ),
- modifier = Modifier.padding(top = TangemTheme.dimens.spacing40),
- )
- Row(
- horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing12),
- modifier = Modifier.padding(
- start = TangemTheme.dimens.spacing16,
- end = TangemTheme.dimens.spacing16,
- top = TangemTheme.dimens.spacing40,
- bottom = TangemTheme.dimens.spacing16,
- ),
- ) {
- SecondaryButton(
- text = stringResourceSafe(R.string.common_later),
- onClick = {
- content.onNeverRequest()
- onDismiss()
- },
- modifier = Modifier.weight(1f),
- )
- PrimaryButton(
- text = stringResourceSafe(R.string.common_allow),
- onClick = {
- content.onRequest()
- requestPushPermission()
- },
- modifier = Modifier.weight(1f),
- )
- }
- }
-}
-
-// region Preview
-@Preview(showBackground = true, widthDp = 360)
-@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
-@Composable
-private fun PushNotificationsSheetContent_Preview() {
- TangemThemePreview {
- PushNotificationsSheetContent(
- PushNotificationsBottomSheetConfig(
- onRequest = {},
- onNeverRequest = {},
- onAllow = {},
- onDeny = {},
- ),
- onDismiss = {},
- )
- }
-}
-// endregion
\ No newline at end of file
diff --git a/gradle/tangem_dependencies.toml b/gradle/tangem_dependencies.toml
index e3fa514003..78d485789e 100644
--- a/gradle/tangem_dependencies.toml
+++ b/gradle/tangem_dependencies.toml
@@ -5,9 +5,9 @@
# https://github.com/tangem/tangem-sdk-android/
# https://github.com/tangem/vico
-tangemBlockchainSdk = "develop-1125"
+tangemBlockchainSdk = "develop-1129"
#tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds
-tangemCardSdk = "develop-505"
+tangemCardSdk = "develop-509"
#tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^
tangemVico = "2.0.0-alpha.25-tangem12"
#tangemVico = "0.0.1" # Keep it! - used for local builds ^
diff --git a/mock_resources/config_dev.json b/mock_resources/config_dev.json
deleted file mode 100644
index 7bdbf5433b..0000000000
--- a/mock_resources/config_dev.json
+++ /dev/null
@@ -1,169 +0,0 @@
-{
- "amplitudeApiKey": "place_your_key_here_if_needed",
- "appsFlyer": {
- "appsFlyerDevKey": "place_your_key_here_if_needed",
- "appsFlyerAppID": "place_your_key_here_if_needed"
- },
- "blockchairApiKeys": ["place_your_key_here_if_needed"],
- "blockchairAuthorizationToken": "",
- "blockcypherTokens": [
- "place_your_key_here_if_needed",
- "place_your_key_here_if_needed",
- "place_your_key_here_if_needed"
- ],
- "bscQuiknodeApiKey": "",
- "bscQuiknodeSubdomain": "place_your_data_here",
- "getBlockAccessTokens": {
- "avalanche": {
- "jsonRpc": "place_your_key_here_if_needed"
- },
- "ethereum": {
- "jsonRpc": "place_your_key_here_if_needed"
- },
- "ethereumClassic": {
- "jsonRpc": "place_your_key_here_if_needed"
- },
- "fantom": {
- "jsonRpc": "place_your_key_here_if_needed"
- },
- "rsk": {
- "jsonRpc": "place_your_key_here_if_needed"
- },
- "bsc": {
- "jsonRpc": "place_your_key_here_if_needed"
- },
- "polygon": {
- "jsonRpc": "place_your_key_here_if_needed"
- },
- "xdai": {
- "jsonRpc": "place_your_key_here_if_needed"
- },
- "cronos": {
- "jsonRpc": "place_your_key_here_if_needed"
- },
- "solana": {
- "jsonRpc": "place_your_key_here_if_needed"
- },
- "ton": {
- "jsonRpc": "place_your_key_here_if_needed"
- },
- "tron": {
- "rest": "place_your_key_here_if_needed"
- },
- "cosmos-hub": {
- "rest": "place_your_key_here_if_needed"
- },
- "near": {
- "jsonRpc": "place_your_key_here_if_needed"
- },
- "xrp": {
- "jsonRpc": "place_your_key_here_if_needed"
- },
- "cardano": {
- "rosetta": "place_your_key_here_if_needed"
- },
- "dogecoin": {
- "blockBookRest": "place_your_key_here_if_needed",
- "jsonRpc": "place_your_key_here_if_needed"
- },
- "litecoin": {
- "blockBookRest": "place_your_key_here_if_needed",
- "jsonRpc": "place_your_key_here_if_needed"
- },
- "dash": {
- "blockBookRest": "place_your_key_here_if_needed",
- "jsonRpc": "place_your_key_here_if_needed"
- },
- "bitcoin": {
- "blockBookRest": "place_your_key_here_if_needed",
- "jsonRpc": "place_your_key_here_if_needed"
- },
- "aptos": {
- "rest": "place_your_key_here_if_needed"
- },
- "algorand": {
- "rest": "place_your_key_here_if_needed"
- },
- "polygon-zkevm": {
- "jsonRpc": "place_your_key_here_if_needed"
- },
- "zksync": {
- "jsonRpc": "place_your_key_here_if_needed"
- },
- "base": {
- "jsonRpc": "place_your_key_here_if_needed"
- },
- "blast": {
- "jsonRpc": "place_your_key_here_if_needed"
- },
- "filecoin": {
- "jsonRpc": "place_your_key_here_if_needed"
- },
- "arbitrum-one": {
- "jsonRpc": "place_your_key_here_if_needed"
- },
- "bitcoinCash": {
- "blockBookRest": "place_your_key_here_if_needed",
- "jsonRpc": "place_your_key_here_if_needed"
- },
- "kusama": {
- "jsonRpc": "place_your_key_here_if_needed"
- },
- "moonbeam": {
- "jsonRpc": "place_your_key_here_if_needed"
- },
- "optimism": {
- "jsonRpc": "place_your_key_here_if_needed"
- },
- "polkadot": {
- "jsonRpc": "place_your_key_here_if_needed"
- },
- "shibarium": {
- "jsonRpc": "place_your_key_here_if_needed"
- },
- "sui": {
- "jsonRpc": "place_your_key_here_if_needed"
- },
- "telos": {
- "jsonRpc": "place_your_key_here_if_needed"
- },
- "tezos": {
- "rest": "place_your_key_here_if_needed"
- }
- },
- "kaspaSecondaryApiUrl": "place_your_kaspa_api_here",
- "infuraProjectId": "place_your_key_here_if_needed",
- "mercuryoSecret": "place_your_key_here_if_needed",
- "mercuryoWidgetId": "place_your_key_here_if_needed",
- "moonPayApiKey": "place_your_key_here_if_needed",
- "moonPayApiSecretKey": "place_your_key_here_if_needed",
- "nowNodesApiKey": "place_your_key_here_if_needed",
- "tonCenterApiKey": {
- "mainnet": "place_your_key_here_if_needed",
- "testnet": "place_your_key_here_if_needed"
- },
- "quiknodeApiKey": "",
- "quiknodeSubdomain": "place_your_data_here_if_needed",
- "tronGridApiKey": "place_your_key_here_if_needed",
- "walletConnectProjectId": "place_your_key_here_if_needed",
- "chiaFireAcademyApiKey": "place_your_key_here_if_needed",
- "chiaTangemApiKey": "place_your_key_here_if_needed",
- "express": {
- "apiKey": "place_your_key_here_if_needed",
- "signVerifierPublicKey": "place_your_key_here_if_needed"
- },
- "devExpress": {
- "apiKey": "place_your_key_here_if_needed",
- "signVerifierPublicKey": "place_your_key_here_if_needed"
- },
- "hederaArkhiaKey": "place_your_key_here_if_needed",
- "polygonScanApiKey": "place_your_key_here_if_needed",
- "koinosProApiKey": "place_your_key_here_if_needed",
- "stakeKitApiKey": "place_your_key_here_if_needed",
- "bittensorDwellirKey": "place_your_key_here_if_needed",
- "bittensorOnfinalityKey": "place_your_key_here_if_needed",
- "alephiumTangemApiKey": "place_your_key_here_if_needed",
- "moralisApiKey": "place_your_key_here_if_needed",
- "nftScanApiKey": "place_your_key_here_if_needed",
- "blockaidApiKey": "place_your_key_here_if_needed"
-}
diff --git a/tangem-android-tools b/tangem-android-tools
index 936cd7232c..bc4cd43085 160000
--- a/tangem-android-tools
+++ b/tangem-android-tools
@@ -1 +1 @@
-Subproject commit 936cd7232c2d316c91e2901034417b0b38a63dd1
+Subproject commit bc4cd430853ca794614b8d5163c9b28b9ca26112