Updated on 2026-08-14
This commit is contained in:
parent
4c903fc654
commit
1485cebb6b
14 changed files with 420 additions and 397 deletions
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -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,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -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<WalletNotification>, 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
|
||||
},
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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<ImmutableList<WalletNotification>> {
|
||||
// TODO: [REDACTED_JIRA] order
|
||||
fun create(
|
||||
cardTypesResolver: CardTypesResolver,
|
||||
cryptoCurrencyList: List<CryptoCurrencyStatus.Status>,
|
||||
): Flow<ImmutableList<WalletNotification>> {
|
||||
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<WalletNotification>.addRemainingSignaturesLeftNotifications(
|
||||
cardTypesResolver: CardTypesResolver,
|
||||
) {
|
||||
val remainingSignatures = cardTypesResolver.getRemainingSignatures()
|
||||
if (remainingSignatures != null && remainingSignatures <= MAX_REMAINING_SIGNATURES_COUNT) {
|
||||
add(element = WalletNotification.RemainingSignaturesLeft(remainingSignatures))
|
||||
private fun MutableList<WalletNotification>.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<WalletNotification>.addReleaseSpecialNotifications(
|
||||
cardTypesResolver: CardTypesResolver,
|
||||
isDemo: Boolean,
|
||||
private fun MutableList<WalletNotification>.addMissingAddressesNotification(
|
||||
cryptoCurrencyList: List<CryptoCurrencyStatus.Status>,
|
||||
) {
|
||||
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<CryptoCurrencyStatus.Status>.getMissedAddressesCount(): Int {
|
||||
return filterIsInstance<CryptoCurrencyStatus.MissedDerivation>().count()
|
||||
}
|
||||
|
||||
// TODO: [REDACTED_JIRA]
|
||||
private suspend fun MutableList<WalletNotification>.addRateTheAppNotification() {
|
||||
addIf(
|
||||
element = WalletNotification.RateApp(
|
||||
onPositiveClick = {},
|
||||
onNegativeClick = {},
|
||||
onCloseClick = {},
|
||||
),
|
||||
condition = isUserAlreadyRateAppUseCase(),
|
||||
)
|
||||
}
|
||||
|
||||
private suspend fun MutableList<WalletNotification>.addWarningNotifications(
|
||||
cardTypesResolver: CardTypesResolver,
|
||||
cryptoCurrencyList: List<CryptoCurrencyStatus.Status>,
|
||||
) {
|
||||
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<WalletNotification>.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<CryptoCurrencyStatus.Status>.hasUnreachableNetworks(): Boolean {
|
||||
return any { it is CryptoCurrencyStatus.Unreachable }
|
||||
}
|
||||
|
||||
return statuses.any { it is CryptoCurrencyStatus.MissedDerivation }
|
||||
private fun List<CryptoCurrencyStatus.Status>.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 {
|
||||
|
|
|
|||
|
|
@ -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) }
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue