From 1485cebb6b4cd6b1a93800e33c9464f0ae802a82 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 20 Sep 2023 21:51:44 +0800 Subject: [PATCH] Updated on 2026-08-14 --- .../WallectSelectorScreenContent.kt | 2 +- core/res/src/main/res/values-ru/strings.xml | 13 +- .../src/main/res/values-zh-rTW/strings.xml | 6 +- core/res/src/main/res/values/strings.xml | 41 ++- .../components/notifications/Notification.kt | 60 +++-- .../notifications/NotificationConfig.kt | 2 + .../core/ui/extensions/TextReference.kt | 16 +- .../presentation/common/WalletPreviewData.kt | 9 +- .../components/WalletBottomSheetConfig.kt | 65 +---- .../state/components/WalletNotification.kt | 252 +++++++++--------- .../components/common/WalletNotifications.kt | 17 +- .../wallet/viewmodels/WalletClickIntents.kt | 10 +- .../WalletNotificationsListFactory.kt | 221 ++++++++------- .../wallet/viewmodels/WalletViewModel.kt | 103 ++----- 14 files changed, 420 insertions(+), 397 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/WallectSelectorScreenContent.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/WallectSelectorScreenContent.kt index 472a4322ec..0993a1c9ea 100644 --- a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/WallectSelectorScreenContent.kt +++ b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/WallectSelectorScreenContent.kt @@ -177,7 +177,7 @@ private fun Footer( PrimaryButton( modifier = Modifier.fillMaxWidth(), text = stringResource( - id = R.string.user_wallet_list_unlock_all, + id = R.string.user_wallet_list_unlock_all_with, stringResource(id = R.string.common_biometrics), ), showProgress = showUnlockProgress, diff --git a/core/res/src/main/res/values-ru/strings.xml b/core/res/src/main/res/values-ru/strings.xml index aca1c4e67a..510b31b595 100644 --- a/core/res/src/main/res/values-ru/strings.xml +++ b/core/res/src/main/res/values-ru/strings.xml @@ -71,6 +71,7 @@ биометрическую аутентификацию биометрией Купить + Купить %1$s Вы не предоставили доступ к камере, пожалуйста, измените настройки конфиденциальности. Отмена Закрыть @@ -192,6 +193,7 @@ Приложите карту Внутренняя ошибка: не удается найти менеджер кошельков Вы обновили данные биометрии, отсканируйте свою карту для входа + Чтобы начать отслеживать свои криптоактивы и транзакции, добавьте токены Вы успешно прошли все уроки и теперь можете получить 1INCH токены Пройдите 3 урока и получите %d 1INCH токен на свой кошелек @@ -215,6 +217,8 @@ Вам надо сгенерировать адреса для %d новых сетей, используя вашу карту Некоторые адреса отсутствуют + Добавить + Изменить Невозможно покрыть %1$s комиссию Вам необходимо установить единый код доступа для защиты всех ваших карт Защита @@ -325,6 +329,8 @@ за %d кошельков Получите ^^%1$s^^ на ваш адрес в сети %2$s %3$s ^^спустя 30 дней^^ за каждый кошелек, который купит ваш друг + Получите + на ваш адрес в сети %1$s%2$s за каждый кошелек, который купит ваш друг Вы Получит при покупке кошелька на сайте tangem.com @@ -491,10 +497,11 @@ Переименование кошелька Одновалютные Мои кошельки - Разблокировать все с %s + Разблокировать все + Разблокировать все с %s История транзакций Сеть недоступна - Блокчейн недоступен. Попробуй позже. + Блокчейн недоступен. Попробуйте позже. Баланс загружается… Отсканируйте карту Транзакция подтверждается… @@ -577,5 +584,5 @@ Войти с %s Сканировать карту Используйте %s или отсканируйте карту для входа в приложение - С возвращением! + C возвращением! diff --git a/core/res/src/main/res/values-zh-rTW/strings.xml b/core/res/src/main/res/values-zh-rTW/strings.xml index dbc98ef5f5..545a1272b2 100644 --- a/core/res/src/main/res/values-zh-rTW/strings.xml +++ b/core/res/src/main/res/values-zh-rTW/strings.xml @@ -38,6 +38,7 @@ 允許您使用此卡重置此錢包中其他卡上的訪問密碼 禁用重置此卡或此錢包中其他卡上的訪問密碼的功能 恢復訪問密碼 + 重置 您確定要這麼做嗎? 更改訪問密碼 訪問密碼將僅在此卡上更改 @@ -258,6 +259,8 @@ 無法加載有關推薦計劃的消息。請稍後再試 無法加載有關推薦計劃的消息。原因:%s。請稍後再試 您的朋友買 + 會得到 + 對於你的朋友在你的 %1$s 網絡地址%2$s上購買的每個錢包 得到 %s 折扣 @@ -277,7 +280,6 @@ 我了解執行此操作後,我將無法再訪問當前錢包 恢復原廠設置將從所選卡中完全刪除錢包。您將無法恢復當前錢包或使用卡恢復訪問密碼 恢復原廠設置將從所選卡中完全刪除錢包並將其從應用程序中刪除。您將無法恢復當前錢包 - 您有其他國家的銀行卡或銀聯卡嗎? 目前不接受俄羅斯銀行卡 登錄應用程序並在不掃描卡片的情況下檢查您的資產 訪問應用程序 @@ -402,7 +404,7 @@ 重新命名錢包 單一幣種 我的錢包 - 用 %s 解鎖全部 + 用 %s 解鎖全部 交易記錄 網路無法使用 區塊鍊無法使用。稍後再試 diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml index e869ddb5a2..660803875f 100644 --- a/core/res/src/main/res/values/strings.xml +++ b/core/res/src/main/res/values/strings.xml @@ -69,6 +69,7 @@ biometric authentication biometrics Buy + Buy %1$s You have not given access to your camera, please adjust your privacy settings Cancel Close @@ -134,7 +135,10 @@ Required field Decimal number must be a valid integer, no higher than %d Custom derivation + E. g. m/00\'/0000\'/0\'/0/0 + Enter custom derivation Decimals + Derivation Path Default BIP44 coin type The derivation path you\'ve entered is not valid @@ -142,6 +146,8 @@ Name Not selected Network + Token network + You can manually add a token that is not natively supported by Tangem E.g. USDC Token symbol This token/network has already been added to your list @@ -193,7 +199,7 @@ Tap the card Internal error: wallet manager not found You have updated biometrics, scan your card to enter - To begin tracking your crypto assets and transactions, add tokens. + To begin tracking your crypto assets and transactions, add tokens You have completed all of the lessons, and are now eligible to receive your 1INCH tokens Complete three lessons and receive %d 1INCH token to your wallet @@ -213,6 +219,29 @@ You need to generate addresses for %d new networks using your card Some addresses are missing + Add + Custom + Edit + Blockchain the cryptocurrency was initially created + Native network + Using non-native networks for tokens enables cross-blockchain interoperability, allowing assets to be utilized in diverse decentralized applications and smart contracts across platforms. However, this often involves a custodian or smart contract to hold the original asset securely, introducing centralization and counterparty risk. + Not original or primary blockchain the token is hosted + Non-native networks + Blockchain the cryptocurrency was initially created + Networks + Choose networks + Wallet + Couldn’t find this token, you can add it manually + %d of %#@total_wallets@ + + %d wallet + %d wallets + + e.g. BTC I trust, hodl I must + Coin market cap + The selected token is currently unavailable for actions within the crypto wallet. But worry not, you can express your interest by upvoting it. + Upvote + Choose wallet Unable to cover %1$s fee You have to set up a single access code to protect all your wallets Protect @@ -322,6 +351,8 @@ for %d wallets Will get ^^%1$s^^ for each wallet bought by your friend on your %2$s network address %3$s ^^30 days after^^ that + Will get + for each wallet bought by your friend on your %1$s network address%2$s You Will get a when buying a wallet on tangem.com @@ -484,7 +515,8 @@ Rename Wallet Single-currency My Wallets - Unlock all with %s + Unlock all + Unlock all with %s Transaction history Network is unreachable Blockchain is unreachable. Try later @@ -549,6 +581,7 @@ Tangem Can be better Learn more + Love it! Ok, Got it! Really cool! %1$s network has a concept of Existential Deposit. If your account drops below %2$s it will be deactivated and any remaining funds will be destroyed. @@ -559,7 +592,11 @@ How do you like Tangem? One question This card has signed transactions in the past + Network currently is unreachable. Please try again later. + Some networks currently are unreachable. Please try again later. This is a Testnet card. Don\'t accept it as a payment. This card must only be used for testing and development purposes. + Note top up + Some networks are unreachable Discard You have an interrupted backup. Do you want to resume? Yes, resume diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/notifications/Notification.kt b/core/ui/src/main/java/com/tangem/core/ui/components/notifications/Notification.kt index 213f8f90e8..6e569c56bb 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/notifications/Notification.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/notifications/Notification.kt @@ -1,9 +1,7 @@ package com.tangem.core.ui.components.notifications import androidx.annotation.DrawableRes -import androidx.compose.animation.AnimatedContent import androidx.compose.animation.AnimatedVisibility -import androidx.compose.animation.ExperimentalAnimationApi import androidx.compose.foundation.Image import androidx.compose.foundation.LocalIndication import androidx.compose.foundation.clickable @@ -25,9 +23,7 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider import com.tangem.core.ui.R -import com.tangem.core.ui.components.PrimaryButton -import com.tangem.core.ui.components.PrimaryButtonIconEnd -import com.tangem.core.ui.components.SecondaryButton +import com.tangem.core.ui.components.* import com.tangem.core.ui.extensions.TextReference import com.tangem.core.ui.extensions.resolveReference import com.tangem.core.ui.res.TangemTheme @@ -46,7 +42,7 @@ import com.tangem.core.ui.components.notifications.NotificationConfig.ButtonsSta */ @Composable fun Notification(config: NotificationConfig, modifier: Modifier = Modifier, iconTint: Color? = null) { - BaseContainer(buttonsState = config.buttonsState, modifier = modifier) { + BaseContainer(buttonsState = config.buttonsState, onClick = config.onClick, modifier = modifier) { Column( modifier = Modifier.padding(all = TangemTheme.dimens.spacing12), verticalArrangement = Arrangement.spacedBy(space = TangemTheme.dimens.spacing12), @@ -56,6 +52,7 @@ fun Notification(config: NotificationConfig, modifier: Modifier = Modifier, icon iconTint = iconTint, title = config.title, subtitle = config.subtitle, + isClickableComponent = config.onClick != null, ) Buttons(state = config.buttonsState) @@ -71,11 +68,12 @@ fun Notification(config: NotificationConfig, modifier: Modifier = Modifier, icon @Composable private fun BaseContainer( buttonsState: NotificationConfig.ButtonsState?, + onClick: (() -> Unit)?, modifier: Modifier = Modifier, content: @Composable BoxScope.() -> Unit, ) { val containerColor by rememberUpdatedState( - newValue = if (buttonsState != null) { + newValue = if (buttonsState != null || onClick != null) { TangemTheme.colors.background.primary } else { TangemTheme.colors.button.disabled @@ -83,9 +81,11 @@ private fun BaseContainer( ) Surface( + onClick = onClick ?: {}, modifier = modifier .defaultMinSize(minHeight = TangemTheme.dimens.size62) .fillMaxWidth(), + enabled = onClick != null, shape = TangemTheme.shapes.roundedCornersXMedium, color = containerColor, ) { @@ -94,15 +94,36 @@ private fun BaseContainer( } @Composable -private fun MainContent(iconResId: Int, iconTint: Color?, title: TextReference, subtitle: TextReference) { - Row(horizontalArrangement = Arrangement.spacedBy(space = TangemTheme.dimens.spacing10)) { +private fun MainContent( + iconResId: Int, + iconTint: Color?, + title: TextReference, + subtitle: TextReference, + isClickableComponent: Boolean, +) { + Row { Icon( iconResId = iconResId, tint = iconTint, modifier = Modifier.align(alignment = Alignment.CenterVertically), ) + SpacerW(width = TangemTheme.dimens.spacing10) + TextsBlock(title = title, subtitle = subtitle) + + if (isClickableComponent) { + SpacerWMax() + + Icon( + painter = painterResource(id = R.drawable.ic_chevron_right_24), + contentDescription = null, + modifier = Modifier + .size(size = TangemTheme.dimens.size20) + .align(alignment = Alignment.CenterVertically), + tint = TangemTheme.colors.icon.informative, + ) + } } } @@ -130,7 +151,7 @@ private fun TextsBlock(title: TextReference, subtitle: TextReference) { Text( text = title.resolveReference(), color = TangemTheme.colors.text.primary1, - style = TangemTheme.typography.body2, + style = TangemTheme.typography.button, ) Text( @@ -141,16 +162,13 @@ private fun TextsBlock(title: TextReference, subtitle: TextReference) { } } -@OptIn(ExperimentalAnimationApi::class) @Composable private fun Buttons(state: NotificationButtonsState?) { - AnimatedContent(targetState = state, label = "Update the buttons content") { animatedState -> - when (animatedState) { - is NotificationButtonsState.SecondaryButtonConfig -> SingleSecondaryButton(config = animatedState) - is NotificationButtonsState.PrimaryButtonConfig -> SinglePrimaryButton(config = animatedState) - is NotificationButtonsState.PairButtonsConfig -> PairButtons(config = animatedState) - null -> Unit - } + when (state) { + is NotificationButtonsState.SecondaryButtonConfig -> SingleSecondaryButton(config = state) + is NotificationButtonsState.PrimaryButtonConfig -> SinglePrimaryButton(config = state) + is NotificationButtonsState.PairButtonsConfig -> PairButtons(config = state) + null -> Unit } } @@ -266,6 +284,12 @@ private class NotificationConfigProvider : CollectionPreviewParameterProvider Unit)? = null, val onCloseClick: (() -> Unit)? = null, ) { diff --git a/core/ui/src/main/java/com/tangem/core/ui/extensions/TextReference.kt b/core/ui/src/main/java/com/tangem/core/ui/extensions/TextReference.kt index d90718dcb8..d44b32ecdf 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/extensions/TextReference.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/extensions/TextReference.kt @@ -109,7 +109,13 @@ fun combinedReference(refs: WrappedList): TextReference { @ReadOnlyComposable fun TextReference.resolveReference(): String { return when (this) { - is TextReference.Res -> stringResource(id, *formatArgs.toTypedArray()) + is TextReference.Res -> { + val args = formatArgs + .map { if (it is TextReference) it.resolveReference() else it } + .toTypedArray() + + stringResource(id = id, *args) + } is TextReference.PluralRes -> pluralStringResource(id, count, *formatArgs.toTypedArray()) is TextReference.Str -> value is TextReference.Combined -> { @@ -125,7 +131,13 @@ fun TextReference.resolveReference(): String { /** Resolve [TextReference] as [String] using [resources] (non-composable context) */ fun TextReference.resolveReference(resources: Resources): String { return when (this) { - is TextReference.Res -> resources.getString(id, *formatArgs.toTypedArray()) + is TextReference.Res -> { + val args = formatArgs + .map { if (it is TextReference) it.resolveReference(resources) else it } + .toTypedArray() + + resources.getString(id, *args) + } is TextReference.PluralRes -> resources.getQuantityString(id, count, *formatArgs.toTypedArray()) is TextReference.Str -> value is TextReference.Combined -> { diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/WalletPreviewData.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/WalletPreviewData.kt index 27df264a07..4b51515ef3 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/WalletPreviewData.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/WalletPreviewData.kt @@ -381,10 +381,9 @@ internal object WalletPreviewData { onRefresh = {}, ), notifications = persistentListOf( - WalletNotification.UnreachableNetworks, - WalletNotification.LikeTangemApp(onClick = {}), - WalletNotification.BackupCard(onClick = {}), - WalletNotification.ScanCard(onClick = {}), + WalletNotification.Critical.DevCard, + WalletNotification.MissingAddresses(missingAddressesCount = 0, onGenerateClick = {}), + WalletNotification.Warning.NetworksUnreachable, ), bottomSheetConfig = bottomSheet, tokenActionsBottomSheet = actionsBottomSheet, @@ -402,7 +401,7 @@ internal object WalletPreviewData { isRefreshing = false, onRefresh = {}, ), - notifications = persistentListOf(WalletNotification.LikeTangemApp(onClick = {})), + notifications = persistentListOf(WalletNotification.Warning.NetworksUnreachable), buttons = manageButtons, bottomSheetConfig = bottomSheet, marketPriceBlockState = MarketPriceBlockState.Content( diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/components/WalletBottomSheetConfig.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/components/WalletBottomSheetConfig.kt index 7b4abe968d..44d45cf615 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/components/WalletBottomSheetConfig.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/components/WalletBottomSheetConfig.kt @@ -4,7 +4,8 @@ import androidx.annotation.DrawableRes import androidx.compose.ui.graphics.Color import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent import com.tangem.core.ui.extensions.TextReference -import com.tangem.core.ui.extensions.WrappedList +import com.tangem.core.ui.extensions.resourceReference +import com.tangem.core.ui.extensions.wrappedList import com.tangem.core.ui.res.TangemColorPalette import com.tangem.feature.wallet.impl.R @@ -13,7 +14,6 @@ import com.tangem.feature.wallet.impl.R * [REDACTED_AUTHOR] */ -// TODO: Finalize notification strings [REDACTED_JIRA] sealed class WalletBottomSheetConfig( open val title: TextReference, open val subtitle: TextReference, @@ -29,61 +29,24 @@ sealed class WalletBottomSheetConfig( @DrawableRes val iconResId: Int? = null, ) - data class UnlockWallets( - val onUnlockClick: () -> Unit, - val onScanClick: () -> Unit, - ) : WalletBottomSheetConfig( - title = TextReference.Str(value = "Unlock needed"), - subtitle = TextReference.Str( - value = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor " + - "incididunt ut labore et dolore magna aliqua.", + data class UnlockWallets(val onUnlockClick: () -> Unit, val onScanClick: () -> Unit) : WalletBottomSheetConfig( + title = resourceReference(id = R.string.common_unlock_needed), + subtitle = resourceReference( + id = R.string.unlock_wallet_description_full, + formatArgs = wrappedList( + resourceReference(R.string.common_biometrics), + ), ), iconResId = R.drawable.ic_locked_24, tint = TangemColorPalette.Black, - primaryButtonConfig = ButtonConfig(text = TextReference.Str(value = "Unlock"), onClick = onUnlockClick), + primaryButtonConfig = ButtonConfig( + text = resourceReference(id = R.string.user_wallet_list_unlock_all), + onClick = onUnlockClick, + ), secondaryButtonConfig = ButtonConfig( - text = TextReference.Str(value = "Scan card"), + text = resourceReference(id = R.string.welcome_unlock_card), onClick = onScanClick, iconResId = R.drawable.ic_tangem_24, ), ) - - data class LikeTangemApp( - val onRateTheAppClick: () -> Unit, - val onShareClick: () -> Unit, - ) : WalletBottomSheetConfig( - title = TextReference.Str(value = "Like Tangem App?"), - subtitle = TextReference.Str(value = "How was your experience with our app? Let us know:"), - iconResId = R.drawable.ic_star_24, - tint = TangemColorPalette.Tangerine, - primaryButtonConfig = ButtonConfig( - text = TextReference.Str(value = "Rate the app"), - onClick = onRateTheAppClick, - ), - secondaryButtonConfig = ButtonConfig( - text = TextReference.Str(value = "Share feedback"), - onClick = onShareClick, - ), - ) - - data class CriticalWarningAlreadySignedHashes( - val onOkClick: () -> Unit, - val onCancelClick: () -> Unit, - ) : WalletBottomSheetConfig( - title = TextReference.Res( - id = R.string.warning_important_security_info, - formatArgs = WrappedList(listOf("\u26A0")), - ), - subtitle = TextReference.Res(id = R.string.alert_signed_hashes_message), - iconResId = R.drawable.img_attention_20, - tint = null, - primaryButtonConfig = ButtonConfig( - text = TextReference.Res(id = R.string.common_ok), - onClick = onOkClick, - ), - secondaryButtonConfig = ButtonConfig( - text = TextReference.Res(id = R.string.common_cancel), - onClick = onCancelClick, - ), - ) } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/components/WalletNotification.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/components/WalletNotification.kt index e5e9221005..c38b2b3bfa 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/components/WalletNotification.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/components/WalletNotification.kt @@ -2,8 +2,7 @@ package com.tangem.feature.wallet.presentation.wallet.state.components import androidx.compose.runtime.Immutable import com.tangem.core.ui.components.notifications.NotificationConfig -import com.tangem.core.ui.extensions.TextReference -import com.tangem.core.ui.extensions.WrappedList +import com.tangem.core.ui.extensions.* import com.tangem.feature.wallet.impl.R /** @@ -13,157 +12,144 @@ import com.tangem.feature.wallet.impl.R * [REDACTED_AUTHOR] */ -// TODO: Finalize notification strings [REDACTED_JIRA] @Immutable -sealed class WalletNotification(open val config: NotificationConfig) { +sealed class WalletNotification(val config: NotificationConfig) { - /** Clickable notification */ - sealed interface Clickable { + sealed class Critical(title: TextReference, subtitle: TextReference) : WalletNotification( + config = NotificationConfig( + title = title, + subtitle = subtitle, + iconResId = R.drawable.ic_alert_circle_24, + ), + ) { - /** Lambda be invoked when notification is clicked */ - val onClick: () -> Unit + object DevCard : Critical( + title = resourceReference(id = R.string.common_warning), + subtitle = resourceReference(id = R.string.alert_developer_card), + ) + + object DemoCard : Critical( + title = resourceReference(id = R.string.common_warning), + subtitle = resourceReference(id = R.string.alert_demo_message), + ) + + object TestNetCard : Critical( + title = resourceReference(id = R.string.common_warning), + subtitle = resourceReference(id = R.string.warning_testnet_card_message), + ) + + object FailedCardValidation : Critical( + title = resourceReference(id = R.string.warning_failed_to_verify_card_title), + subtitle = resourceReference(id = R.string.warning_failed_to_verify_card_message), + ) + + data class LowSignatures(val count: Int) : Critical( + title = resourceReference(id = R.string.common_warning), + subtitle = resourceReference( + id = R.string.warning_low_signatures_format, + formatArgs = wrappedList(count), + ), + ) } - /** "Development card" notification */ - object DevCard : WalletNotification( + sealed class Warning( + title: TextReference, + subtitle: TextReference, + buttonsState: NotificationConfig.ButtonsState? = null, + onClick: (() -> Unit)? = null, + ) : WalletNotification( config = NotificationConfig( - title = TextReference.Res(id = R.string.common_warning), - subtitle = TextReference.Res(id = R.string.alert_developer_card), - iconResId = R.drawable.ic_alert_circle_24, + title = title, + subtitle = subtitle, + iconResId = R.drawable.img_attention_20, + buttonsState = buttonsState, + onClick = onClick, ), - ) + ) { - /** "Test card" notification */ - object TestCard : WalletNotification( - config = NotificationConfig( - title = TextReference.Res(id = R.string.common_warning), - subtitle = TextReference.Res(id = R.string.warning_testnet_card_message), - iconResId = R.drawable.ic_alert_circle_24, - ), - ) + data class MissingBackup(val onStartBackupClick: () -> Unit) : Warning( + title = resourceReference(id = R.string.main_no_backup_warning_title), + subtitle = resourceReference(id = R.string.main_no_backup_warning_subtitle), + buttonsState = NotificationConfig.ButtonsState.SecondaryButtonConfig( + text = resourceReference(id = R.string.button_start_backup_process), + onClick = onStartBackupClick, + ), + ) - /** "Demo card" notification */ - object DemoCard : WalletNotification( - config = NotificationConfig( - title = TextReference.Res(id = R.string.common_warning), - subtitle = TextReference.Res(id = R.string.alert_demo_message), - iconResId = R.drawable.ic_alert_circle_24, - ), - ) + object NetworksUnreachable : Warning( + title = resourceReference(id = R.string.wallet_balance_blockchain_unreachable), + subtitle = resourceReference(id = R.string.warning_subtitle_network_unreachable), + ) - /** "Card verification failed" notification */ - object CardVerificationFailed : WalletNotification( - config = NotificationConfig( - title = TextReference.Res(id = R.string.warning_failed_to_verify_card_title), - subtitle = TextReference.Res(id = R.string.warning_failed_to_verify_card_message), - iconResId = R.drawable.ic_alert_circle_24, - ), - ) + object SomeNetworksUnreachable : Warning( + title = resourceReference(id = R.string.warning_title_some_networks_unreachable), + subtitle = resourceReference(id = R.string.warning_subtitle_some_networks_unreachable), + ) - /** - * "Remaining signatures left" notification - * - * @param count number of remaining signatures - */ - class RemainingSignaturesLeft(count: Int) : WalletNotification( + data class TopUpNote(val errorMessage: String) : Warning( + title = resourceReference(id = R.string.warning_title_note_top_up), + subtitle = stringReference(value = errorMessage), + ) + + object NumberOfSignedHashesIncorrect : Warning( + title = resourceReference(id = R.string.common_warning), + subtitle = resourceReference(id = R.string.alert_card_signed_transactions), + ) + + data class MultiWalletSignedHashesIncorrect(val onClick: () -> Unit) : Warning( + title = resourceReference(id = R.string.common_warning), + subtitle = resourceReference(id = R.string.warning_signed_tx_previously), + onClick = onClick, + ) + } + + data class MissingAddresses(val missingAddressesCount: Int, val onGenerateClick: () -> Unit) : WalletNotification( config = NotificationConfig( - title = TextReference.Res(id = R.string.common_warning), - subtitle = TextReference.Res( - id = R.string.warning_low_signatures_format, - formatArgs = WrappedList(data = listOf(count)), + title = resourceReference(id = R.string.main_warning_missing_derivation_title), + subtitle = pluralReference( + id = R.plurals.main_warning_missing_derivation_description, + count = missingAddressesCount, + formatArgs = wrappedList(missingAddressesCount), ), iconResId = R.drawable.ic_alert_circle_24, - ), - ) - - /** - * "Already topped up and signed hashes" warning notification - * - * @property onClick lambda be invoked when notification's close button is clicked - */ - data class WarningAlreadySignedHashes(override val onClick: () -> Unit) : Clickable, WalletNotification( - config = NotificationConfig( - title = TextReference.Res(id = R.string.common_warning), - subtitle = TextReference.Res(id = R.string.alert_card_signed_transactions), - iconResId = R.drawable.img_attention_20, - onCloseClick = onClick, - ), - ) - - /** - * "Already signed hashes" critical warning notification - * - * @property onClick lambda be invoked when notification is clicked - */ - data class CriticalWarningAlreadySignedHashes(override val onClick: () -> Unit) : Clickable, WalletNotification( - config = NotificationConfig( - title = TextReference.Res( - id = R.string.warning_important_security_info, - formatArgs = WrappedList(listOf("\u26A0")), + buttonsState = NotificationConfig.ButtonsState.PrimaryButtonConfig( + text = resourceReference(id = R.string.common_generate_addresses), + iconResId = R.drawable.ic_tangem_24, + onClick = onGenerateClick, ), - subtitle = TextReference.Res(id = R.string.warning_signed_tx_previously), - iconResId = R.drawable.img_attention_20, ), ) - /** - * "Backup the card" notification - * - * @property onClick lambda be invoked when notification is clicked - */ - data class BackupCard(override val onClick: () -> Unit) : Clickable, WalletNotification( + data class UnlockWallets(val onClick: () -> Unit) : WalletNotification( config = NotificationConfig( - title = TextReference.Str(value = "Backup your card"), - subtitle = TextReference.Str(value = ""), - iconResId = R.drawable.img_attention_20, - ), - ) - - /** "Unreachable networks" notification */ - object UnreachableNetworks : WalletNotification( - config = NotificationConfig( - title = TextReference.Str(value = "Some networks are unreachable"), - subtitle = TextReference.Str(value = ""), - iconResId = R.drawable.img_attention_20, - ), - ) - - /** - * "Like Tangem App" notification - * - * @property onClick lambda be invoked when notification is clicked - */ - data class LikeTangemApp(override val onClick: () -> Unit) : Clickable, WalletNotification( - config = NotificationConfig( - title = TextReference.Str(value = "Like Tangem App?"), - subtitle = TextReference.Str(value = ""), - iconResId = R.drawable.ic_star_24, - ), - ) - - /** - * "Scan the card" notification - * - * @property onClick lambda be invoked when notification is clicked - */ - data class ScanCard(override val onClick: () -> Unit) : Clickable, WalletNotification( - config = NotificationConfig( - title = TextReference.Str(value = "Scan your card to continue"), - subtitle = TextReference.Str(value = ""), - iconResId = R.drawable.ic_tangem_24, - ), - ) - - /** - * "Unlock wallets" notification - * - * @property onClick lambda be invoked when notification is clicked - */ - data class UnlockWallets(override val onClick: () -> Unit) : Clickable, WalletNotification( - config = NotificationConfig( - title = TextReference.Str(value = "Unlock needed"), - subtitle = TextReference.Str(value = ""), + title = resourceReference(id = R.string.common_unlock_needed), + subtitle = resourceReference( + id = R.string.unlock_wallet_description_short, + formatArgs = wrappedList( + resourceReference(R.string.common_biometrics), + ), + ), iconResId = R.drawable.ic_locked_24, + onClick = onClick, + ), + ) + + data class RateApp( + val onPositiveClick: () -> Unit, + val onNegativeClick: () -> Unit, + val onCloseClick: () -> Unit, + ) : WalletNotification( + config = NotificationConfig( + title = resourceReference(id = R.string.warning_rate_app_title), + subtitle = resourceReference(id = R.string.warning_rate_app_message), + iconResId = R.drawable.ic_star_24, + buttonsState = NotificationConfig.ButtonsState.PairButtonsConfig( + primaryText = resourceReference(id = R.string.warning_button_love_it), + onPrimaryClick = onPositiveClick, + secondaryText = resourceReference(id = R.string.warning_button_can_be_better), + onSecondaryClick = onNegativeClick, + ), + onCloseClick = onCloseClick, ), ) } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/common/WalletNotifications.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/common/WalletNotifications.kt index 730832731b..22c20dcfc7 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/common/WalletNotifications.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/common/WalletNotifications.kt @@ -5,6 +5,7 @@ import androidx.compose.foundation.lazy.LazyListScope import androidx.compose.foundation.lazy.items import androidx.compose.ui.Modifier import com.tangem.core.ui.components.notifications.Notification +import com.tangem.core.ui.res.TangemTheme import com.tangem.feature.wallet.presentation.wallet.state.components.WalletNotification import kotlinx.collections.immutable.ImmutableList @@ -20,8 +21,20 @@ import kotlinx.collections.immutable.ImmutableList internal fun LazyListScope.notifications(configs: ImmutableList, modifier: Modifier = Modifier) { items( items = configs, - key = { it.config.title.hashCode() }, + key = { it::class.java }, contentType = { it.config::class.java }, - itemContent = { Notification(config = it.config, modifier = modifier.animateItemPlacement()) }, + itemContent = { + Notification( + config = it.config, + modifier = modifier.animateItemPlacement(), + iconTint = when (it) { + is WalletNotification.Critical -> TangemTheme.colors.icon.warning + is WalletNotification.MissingAddresses -> TangemTheme.colors.icon.accent + is WalletNotification.RateApp -> TangemTheme.colors.icon.attention + is WalletNotification.UnlockWallets -> TangemTheme.colors.icon.primary1 + is WalletNotification.Warning -> null + }, + ) + }, ) } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletClickIntents.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletClickIntents.kt index b5267bd065..e0da1fe275 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletClickIntents.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletClickIntents.kt @@ -9,9 +9,7 @@ internal interface WalletClickIntents { fun onBackClick() - fun onScanCardClick() - - fun onScanCardNotificationClick() + fun onGenerateMissedAddressesClick() fun onScanToUnlockWalletClick() @@ -19,16 +17,12 @@ internal interface WalletClickIntents { fun onBackupCardClick() - fun onCriticalWarningAlreadySignedHashesClick() - - fun onCloseWarningAlreadySignedHashesClick() + fun onMultiWalletSignedHashesNotificationClick() fun onLikeTangemAppClick() fun onRateTheAppClick() - fun onShareClick() - fun onWalletChange(index: Int) fun onRefreshSwipe() diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletNotificationsListFactory.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletNotificationsListFactory.kt index 1d981cf79a..e6a3d1a22c 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletNotificationsListFactory.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletNotificationsListFactory.kt @@ -1,9 +1,10 @@ package com.tangem.feature.wallet.presentation.wallet.viewmodels +import com.tangem.domain.card.GetCardWasScannedUseCase import com.tangem.domain.common.CardTypesResolver +import com.tangem.domain.demo.IsDemoCardUseCase +import com.tangem.domain.settings.IsUserAlreadyRateAppUseCase import com.tangem.domain.tokens.model.CryptoCurrencyStatus -import com.tangem.domain.tokens.model.NetworkGroup -import com.tangem.domain.tokens.model.TokenList import com.tangem.feature.wallet.presentation.wallet.state.components.WalletNotification import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList @@ -13,126 +14,166 @@ import kotlinx.coroutines.flow.flow /** * Wallet notifications list factory * - * @property wasCardScannedCallback callback that check if card was scanned - * @property isUserAlreadyRateAppCallback callback that check if card is user already rate app - * @property isDemoCardCallback callback that check if card is demo - * @property clickIntents screen click intents + * @property isDemoCardUseCase use case that check if card is demo + * @property isUserAlreadyRateAppUseCase use case that check if card is user already rate app + * @property getCardWasScannedUseCase use case that check if card was scanned + * @property clickIntents screen click intents * [REDACTED_AUTHOR] */ internal class WalletNotificationsListFactory( - private val wasCardScannedCallback: suspend (String) -> Boolean, - private val isUserAlreadyRateAppCallback: suspend () -> Boolean, - private val isDemoCardCallback: (String) -> Boolean, + private val isDemoCardUseCase: IsDemoCardUseCase, + private val isUserAlreadyRateAppUseCase: IsUserAlreadyRateAppUseCase, + private val getCardWasScannedUseCase: GetCardWasScannedUseCase, private val clickIntents: WalletClickIntents, ) { - fun create(cardTypesResolver: CardTypesResolver, tokenList: TokenList?): Flow> { - // TODO: [REDACTED_JIRA] order + fun create( + cardTypesResolver: CardTypesResolver, + cryptoCurrencyList: List, + ): Flow> { return flow { emit( buildList { - if (cardTypesResolver.isTestCard()) { - add(element = WalletNotification.TestCard) - return@buildList - } + addCriticalNotifications(cardTypesResolver) - addRemainingSignaturesLeftNotifications(cardTypesResolver) + addMissingAddressesNotification(cryptoCurrencyList) - val isDemo = isDemoCardCallback(cardTypesResolver.getCardId()) - if (!cardTypesResolver.isReleaseFirmwareType()) { - add(element = WalletNotification.DevCard) - } else { - addReleaseSpecialNotifications(cardTypesResolver = cardTypesResolver, isDemo = isDemo) - } + addRateTheAppNotification() - if (isDemo) { - add(element = WalletNotification.DemoCard) - } - - if (hasUnreachableNetworks(tokenList)) { - add(element = WalletNotification.UnreachableNetworks) - } - - if (!cardTypesResolver.isBackupForbidden() && !cardTypesResolver.hasBackup()) { - add(element = WalletNotification.BackupCard(onClick = clickIntents::onBackupCardClick)) - } - - if (tokenList != null && tokenList.hasMissedDerivations()) { - add(element = WalletNotification.ScanCard(onClick = clickIntents::onScanCardNotificationClick)) - } - - if (isUserAlreadyRateAppCallback()) { - add(element = WalletNotification.LikeTangemApp(onClick = clickIntents::onLikeTangemAppClick)) - } - }.toImmutableList(), + addWarningNotifications(cardTypesResolver, cryptoCurrencyList) + } + .toImmutableList(), ) } } - private fun MutableList.addRemainingSignaturesLeftNotifications( - cardTypesResolver: CardTypesResolver, - ) { - val remainingSignatures = cardTypesResolver.getRemainingSignatures() - if (remainingSignatures != null && remainingSignatures <= MAX_REMAINING_SIGNATURES_COUNT) { - add(element = WalletNotification.RemainingSignaturesLeft(remainingSignatures)) + private fun MutableList.addCriticalNotifications(cardTypesResolver: CardTypesResolver) { + addIf( + element = WalletNotification.Critical.DevCard, + condition = !cardTypesResolver.isReleaseFirmwareType(), + ) + + addIf( + element = WalletNotification.Critical.DemoCard, + condition = isDemoCardUseCase(cardId = cardTypesResolver.getCardId()), + ) + + addIf( + element = WalletNotification.Critical.TestNetCard, + condition = cardTypesResolver.isTestCard(), + ) + + addIf( + element = WalletNotification.Critical.FailedCardValidation, + condition = cardTypesResolver.isReleaseFirmwareType() && cardTypesResolver.isAttestationFailed(), + ) + + cardTypesResolver.getRemainingSignatures()?.let { remainingSignatures -> + addIf( + element = WalletNotification.Critical.LowSignatures(count = remainingSignatures), + condition = remainingSignatures <= MAX_REMAINING_SIGNATURES_COUNT, + ) } } - private suspend fun MutableList.addReleaseSpecialNotifications( - cardTypesResolver: CardTypesResolver, - isDemo: Boolean, + private fun MutableList.addMissingAddressesNotification( + cryptoCurrencyList: List, ) { - if (!wasCardScannedCallback(cardTypesResolver.getCardId()) && cardTypesResolver.isMultiwalletAllowed() && - !isDemo - ) { - if (cardTypesResolver.isBackupForbidden() && cardTypesResolver.hasWalletSignedHashes()) { - add( - element = WalletNotification.CriticalWarningAlreadySignedHashes( - onClick = clickIntents::onCriticalWarningAlreadySignedHashesClick, - ), + val missedAddressesCount = cryptoCurrencyList.getMissedAddressesCount() + + addIf( + element = WalletNotification.MissingAddresses( + missingAddressesCount = missedAddressesCount, + onGenerateClick = clickIntents::onGenerateMissedAddressesClick, + ), + condition = missedAddressesCount > 0, + ) + } + + private fun List.getMissedAddressesCount(): Int { + return filterIsInstance().count() + } + + // TODO: [REDACTED_JIRA] + private suspend fun MutableList.addRateTheAppNotification() { + addIf( + element = WalletNotification.RateApp( + onPositiveClick = {}, + onNegativeClick = {}, + onCloseClick = {}, + ), + condition = isUserAlreadyRateAppUseCase(), + ) + } + + private suspend fun MutableList.addWarningNotifications( + cardTypesResolver: CardTypesResolver, + cryptoCurrencyList: List, + ) { + addIf( + element = WalletNotification.Warning.MissingBackup( + onStartBackupClick = clickIntents::onBackupCardClick, + ), + condition = !cardTypesResolver.isBackupForbidden() && !cardTypesResolver.hasBackup(), + ) + + val isDemo = isDemoCardUseCase(cardId = cardTypesResolver.getCardId()) + if (cardTypesResolver.isMultiwalletAllowed()) { + addIf( + element = WalletNotification.Warning.SomeNetworksUnreachable, + condition = cryptoCurrencyList.hasUnreachableNetworks(), + ) + + if (cardTypesResolver.isBackupForbidden()) { + addIf( + element = WalletNotification.Warning.NumberOfSignedHashesIncorrect, + condition = checkSignedHashes(cardTypesResolver = cardTypesResolver, isDemo = isDemo), ) - } else if (cardTypesResolver.hasWalletSignedHashes()) { - add( - element = WalletNotification.WarningAlreadySignedHashes( - onClick = clickIntents::onCloseWarningAlreadySignedHashesClick, + } else { + addIf( + element = WalletNotification.Warning.MultiWalletSignedHashesIncorrect( + onClick = clickIntents::onMultiWalletSignedHashesNotificationClick, ), + condition = checkSignedHashes(cardTypesResolver = cardTypesResolver, isDemo = isDemo), ) } - } + } else { + addIf( + element = WalletNotification.Warning.NetworksUnreachable, + condition = cryptoCurrencyList.hasUnreachableNetworks(), + ) - if (cardTypesResolver.isAttestationFailed()) { - add(element = WalletNotification.CardVerificationFailed) + // TODO: [REDACTED_JIRA] + addIf( + element = WalletNotification.Warning.TopUpNote( + errorMessage = "To activate card top up it with at least 1 XLM", + ), + condition = cryptoCurrencyList.hasNoAccountStatus(), + ) + + addIf( + element = WalletNotification.Warning.NumberOfSignedHashesIncorrect, + condition = checkSignedHashes(cardTypesResolver, isDemo), + ) } } - private fun hasUnreachableNetworks(tokenList: TokenList?): Boolean { - return when (tokenList) { - is TokenList.GroupedByNetwork -> { - tokenList.groups - .flatMap(NetworkGroup::currencies) - .map(CryptoCurrencyStatus::value) - .any { it is CryptoCurrencyStatus.Unreachable } - } - is TokenList.Ungrouped -> { - tokenList.currencies - .map(CryptoCurrencyStatus::value) - .any { it is CryptoCurrencyStatus.Unreachable } - } - is TokenList.NotInitialized, - null, - -> false - } + private fun MutableList.addIf(element: WalletNotification, condition: Boolean) { + if (condition) add(element = element) } - private fun TokenList.hasMissedDerivations(): Boolean { - val statuses = when (this) { - is TokenList.GroupedByNetwork -> groups.flatMap(NetworkGroup::currencies).map(CryptoCurrencyStatus::value) - is TokenList.Ungrouped -> currencies.map(CryptoCurrencyStatus::value) - TokenList.NotInitialized -> emptyList() - } + private fun List.hasUnreachableNetworks(): Boolean { + return any { it is CryptoCurrencyStatus.Unreachable } + } - return statuses.any { it is CryptoCurrencyStatus.MissedDerivation } + private fun List.hasNoAccountStatus(): Boolean { + return any { it is CryptoCurrencyStatus.NoAccount } + } + + private suspend fun checkSignedHashes(cardTypesResolver: CardTypesResolver, isDemo: Boolean): Boolean { + return cardTypesResolver.isReleaseFirmwareType() && cardTypesResolver.hasWalletSignedHashes() && + !isDemo && !getCardWasScannedUseCase(cardId = cardTypesResolver.getCardId()) } private companion object { diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt index e8ed3975b2..6e932219ae 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt @@ -11,7 +11,6 @@ import com.tangem.core.navigation.AppScreen import com.tangem.core.ui.components.bottomsheets.tokenreceive.AddressModel import com.tangem.core.ui.components.bottomsheets.tokenreceive.TokenReceiveBottomSheetConfig import com.tangem.core.ui.components.marketprice.MarketPriceBlockState -import com.tangem.core.ui.extensions.TextReference import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.balancehiding.IsBalanceHiddenUseCase @@ -25,6 +24,7 @@ import com.tangem.domain.settings.* import com.tangem.domain.tokens.* import com.tangem.domain.tokens.legacy.TradeCryptoAction import com.tangem.domain.tokens.model.CryptoCurrencyStatus +import com.tangem.domain.tokens.model.NetworkGroup import com.tangem.domain.tokens.model.TokenList import com.tangem.domain.tokens.models.CryptoCurrency import com.tangem.domain.tokens.models.Network @@ -32,7 +32,6 @@ import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsCountUseCase import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsUseCase import com.tangem.domain.userwallets.UserWalletBuilder import com.tangem.domain.walletmanager.WalletManagersFacade -import com.tangem.domain.wallets.models.SaveWalletError import com.tangem.domain.wallets.models.UserWallet import com.tangem.domain.wallets.models.UserWalletId import com.tangem.domain.wallets.usecase.* @@ -41,7 +40,6 @@ import com.tangem.feature.wallet.presentation.router.InnerWalletRouter import com.tangem.feature.wallet.presentation.wallet.analytics.PortfolioEvent import com.tangem.feature.wallet.presentation.wallet.analytics.WalletScreenAnalyticsEvent import com.tangem.feature.wallet.presentation.wallet.state.* -import com.tangem.feature.wallet.presentation.wallet.state.components.WalletBottomSheetConfig import com.tangem.feature.wallet.presentation.wallet.state.components.WalletCardState import com.tangem.feature.wallet.presentation.wallet.state.components.WalletTokensListState import com.tangem.feature.wallet.presentation.wallet.state.factory.WalletStateFactory @@ -80,9 +78,6 @@ internal class WalletViewModel @Inject constructor( private val getPrimaryCurrencyStatusUpdatesUseCase: GetPrimaryCurrencyStatusUpdatesUseCase, private val fetchCurrencyStatusUseCase: FetchCurrencyStatusUseCase, private val getNetworkCoinStatusUseCase: GetNetworkCoinStatusUseCase, - private val getCardWasScannedUseCase: GetCardWasScannedUseCase, - private val isUserAlreadyRateAppUseCase: IsUserAlreadyRateAppUseCase, - private val isDemoCardUseCase: IsDemoCardUseCase, private val scanCardProcessor: ScanCardProcessor, private val txHistoryItemsCountUseCase: GetTxHistoryItemsCountUseCase, private val txHistoryItemsUseCase: GetTxHistoryItemsUseCase, @@ -99,6 +94,9 @@ internal class WalletViewModel @Inject constructor( private val reduxStateHolder: ReduxStateHolder, private val dispatchers: CoroutineDispatcherProvider, private val analyticsEventsHandler: AnalyticsEventHandler, + getCardWasScannedUseCase: GetCardWasScannedUseCase, + isUserAlreadyRateAppUseCase: IsUserAlreadyRateAppUseCase, + isDemoCardUseCase: IsDemoCardUseCase, // endregion Parameters ) : ViewModel(), DefaultLifecycleObserver, WalletClickIntents { @@ -109,9 +107,9 @@ internal class WalletViewModel @Inject constructor( private var isBalanceHidden = true private val notificationsListFactory = WalletNotificationsListFactory( - wasCardScannedCallback = getCardWasScannedUseCase::invoke, - isUserAlreadyRateAppCallback = isUserAlreadyRateAppUseCase::invoke, - isDemoCardCallback = isDemoCardUseCase::invoke, + getCardWasScannedUseCase = getCardWasScannedUseCase, + isUserAlreadyRateAppUseCase = isUserAlreadyRateAppUseCase, + isDemoCardUseCase = isDemoCardUseCase, clickIntents = this, ) @@ -254,58 +252,9 @@ internal class WalletViewModel @Inject constructor( } } - override fun onScanCardClick() { + override fun onGenerateMissedAddressesClick() { analyticsEventsHandler.send(WalletScreenAnalyticsEvent.NoticeScanYourCardTapped) - viewModelScope.launch(dispatchers.io) { - scanCardProcessor.scan() - .doOnSuccess { - // If card's public key is null then user wallet will be null - val userWallet = UserWalletBuilder(scanResponse = it).build() - - if (userWallet != null) { - saveWalletUseCase(userWallet = userWallet, canOverride = false) - .onLeft { saveWalletError -> - showErrorIfWalletNotSaved( - error = saveWalletError, - scannedWalletId = userWallet.walletId, - ) - } - } - } - } - } - - private fun showErrorIfWalletNotSaved(error: SaveWalletError, scannedWalletId: UserWalletId) { - when (error) { - is SaveWalletError.DataError -> Unit - is SaveWalletError.WalletAlreadySaved -> { - viewModelScope.launch(dispatchers.main) { - val alreadySavedWalletIndex = (uiState as? WalletState.ContentState)?.walletsListConfig - ?.wallets?.indexOfFirst { it.id == scannedWalletId } - - if (alreadySavedWalletIndex != null && alreadySavedWalletIndex != -1) { - uiState = stateFactory.getStateAndTriggerEvent( - state = uiState, - event = WalletEvent.ChangeWallet(index = alreadySavedWalletIndex), - setUiState = { uiState = it }, - ) - - // Delay between events - delay(timeMillis = 500L) - } - - uiState = stateFactory.getStateAndTriggerEvent( - state = uiState, - event = WalletEvent.ShowError(text = TextReference.Res(error.messageId)), - setUiState = { uiState = it }, - ) - } - } - } - } - - override fun onScanCardNotificationClick() { scanToUpdateSelectedWallet( onSuccessSave = { // Reload currencies with missed derivation @@ -361,33 +310,15 @@ internal class WalletViewModel @Inject constructor( router.openOnboardingScreen() } - override fun onCriticalWarningAlreadySignedHashesClick() { - uiState = stateFactory.getStateWithOpenWalletBottomSheet( - content = WalletBottomSheetConfig.CriticalWarningAlreadySignedHashes( - onOkClick = {}, - onCancelClick = {}, - ), - ) - } - - override fun onCloseWarningAlreadySignedHashesClick() { + override fun onMultiWalletSignedHashesNotificationClick() { // TODO: [REDACTED_JIRA] } override fun onLikeTangemAppClick() { - uiState = stateFactory.getStateWithOpenWalletBottomSheet( - content = WalletBottomSheetConfig.LikeTangemApp( - onRateTheAppClick = ::onRateTheAppClick, - onShareClick = ::onShareClick, - ), - ) - } - - override fun onRateTheAppClick() { // TODO: [REDACTED_JIRA] } - override fun onShareClick() { + override fun onRateTheAppClick() { // TODO: [REDACTED_JIRA] } @@ -772,7 +703,19 @@ internal class WalletViewModel @Inject constructor( private fun updateNotifications(index: Int, tokenList: TokenList? = null) { notificationsListFactory.create( cardTypesResolver = getCardTypeResolver(index = index), - tokenList = tokenList, + cryptoCurrencyList = if (tokenList != null) { + when (tokenList) { + is TokenList.GroupedByNetwork -> { + tokenList.groups + .flatMap(NetworkGroup::currencies) + .map(CryptoCurrencyStatus::value) + } + is TokenList.Ungrouped -> tokenList.currencies.map(CryptoCurrencyStatus::value) + is TokenList.NotInitialized -> emptyList() + } + } else { + listOfNotNull(singleWalletCryptoCurrencyStatus?.value) + }, ) .distinctUntilChanged() .onEach { uiState = stateFactory.getStateByNotifications(notifications = it) }