Updated on 2026-08-14

This commit is contained in:
Tangem 2023-09-22 16:53:59 +08:00
parent 0dd4d45b62
commit 479a67f3be
19 changed files with 257 additions and 61 deletions

View file

@ -0,0 +1,9 @@
package com.tangem.feature.wallet.presentation.wallet.state
import androidx.compose.runtime.Immutable
@Immutable
internal sealed class WalletAlertState {
data class WalletAlreadySignedHashes(val onUnderstandClick: () -> Unit) : WalletAlertState()
}

View file

@ -13,4 +13,6 @@ internal sealed class WalletEvent {
data class ShowToast(val text: TextReference) : WalletEvent()
data class CopyAddress(val address: String) : WalletEvent()
data class ShowWalletAlreadySignedHashesMessage(val onUnderstandClick: () -> Unit) : WalletEvent()
}

View file

@ -0,0 +1,34 @@
package com.tangem.feature.wallet.presentation.wallet.ui
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource
import com.tangem.core.ui.components.BasicDialog
import com.tangem.core.ui.components.DialogButton
import com.tangem.feature.wallet.impl.R
import com.tangem.feature.wallet.presentation.wallet.state.WalletAlertState
@Composable
internal fun WalletAlert(config: WalletAlertState, onDismiss: () -> Unit) {
when (config) {
is WalletAlertState.WalletAlreadySignedHashes -> {
WalletAlreadySignedHashesAlert(config = config, onDismiss = onDismiss)
}
}
}
@Composable
private fun WalletAlreadySignedHashesAlert(config: WalletAlertState.WalletAlreadySignedHashes, onDismiss: () -> Unit) {
BasicDialog(
message = stringResource(id = R.string.alert_signed_hashes_message),
confirmButton = DialogButton(
title = stringResource(id = R.string.common_understand),
onClick = {
config.onUnderstandClick()
onDismiss()
},
),
onDismissDialog = onDismiss,
title = stringResource(id = R.string.warning_important_security_info, "\u26A0"),
dismissButton = DialogButton(title = stringResource(id = R.string.common_cancel), onClick = onDismiss),
)
}

View file

@ -10,6 +10,7 @@ import androidx.compose.ui.text.AnnotatedString
import com.tangem.core.ui.event.EventEffect
import com.tangem.core.ui.event.StateEvent
import com.tangem.core.ui.extensions.resolveReference
import com.tangem.feature.wallet.presentation.wallet.state.WalletAlertState
import com.tangem.feature.wallet.presentation.wallet.state.WalletEvent
@Composable
@ -18,6 +19,7 @@ internal fun WalletEventEffect(
snackbarHostState: SnackbarHostState,
event: StateEvent<WalletEvent>,
onAutoScrollSet: () -> Unit,
onAlertConfigSet: (WalletAlertState) -> Unit,
) {
val context = LocalContext.current
val resources = LocalContext.current.resources
@ -39,6 +41,11 @@ internal fun WalletEventEffect(
is WalletEvent.CopyAddress -> {
clipboardManager.setText(AnnotatedString(value.address))
}
is WalletEvent.ShowWalletAlreadySignedHashesMessage -> {
onAlertConfigSet(
WalletAlertState.WalletAlreadySignedHashes(onUnderstandClick = value.onUnderstandClick),
)
}
}
},
)

View file

@ -12,10 +12,7 @@ import androidx.compose.material3.FabPosition
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
@ -30,6 +27,7 @@ import com.tangem.core.ui.components.transactions.state.TxHistoryState
import com.tangem.core.ui.res.TangemTheme
import com.tangem.feature.wallet.impl.R
import com.tangem.feature.wallet.presentation.common.WalletPreviewData
import com.tangem.feature.wallet.presentation.wallet.state.WalletAlertState
import com.tangem.feature.wallet.presentation.wallet.state.WalletMultiCurrencyState
import com.tangem.feature.wallet.presentation.wallet.state.WalletSingleCurrencyState
import com.tangem.feature.wallet.presentation.wallet.state.WalletState
@ -72,12 +70,19 @@ internal fun WalletScreen(state: WalletState) {
onAutoScrollReset = { isAutoScroll.value = false },
)
var alertConfig by remember { mutableStateOf<WalletAlertState?>(value = null) }
WalletEventEffect(
walletsListState = walletsListState,
snackbarHostState = snackbarHostState,
event = state.event,
onAutoScrollSet = { isAutoScroll.value = true },
onAlertConfigSet = { alertConfig = it },
)
alertConfig?.let {
WalletAlert(config = it, onDismiss = { alertConfig = null })
}
}
is WalletState.Initial -> Unit
}

View file

@ -1,6 +1,6 @@
package com.tangem.feature.wallet.presentation.wallet.viewmodels
import com.tangem.domain.card.GetCardWasScannedUseCase
import com.tangem.domain.card.WasCardScannedUseCase
import com.tangem.domain.common.CardTypesResolver
import com.tangem.domain.demo.IsDemoCardUseCase
import com.tangem.domain.settings.IsUserAlreadyRateAppUseCase
@ -10,14 +10,16 @@ import com.tangem.feature.wallet.presentation.wallet.state.components.WalletNoti
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
import kotlin.collections.count
/**
* Wallet notifications list factory
*
* @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 wasCardScannedUseCase use case that check if card was scanned
* @property clickIntents screen click intents
*
[REDACTED_AUTHOR]
@ -25,7 +27,7 @@ import kotlinx.coroutines.flow.flow
internal class WalletNotificationsListFactory(
private val isDemoCardUseCase: IsDemoCardUseCase,
private val isUserAlreadyRateAppUseCase: IsUserAlreadyRateAppUseCase,
private val getCardWasScannedUseCase: GetCardWasScannedUseCase,
private val wasCardScannedUseCase: WasCardScannedUseCase,
private val clickIntents: WalletClickIntents,
) {
@ -33,8 +35,9 @@ internal class WalletNotificationsListFactory(
cardTypesResolver: CardTypesResolver,
cryptoCurrencyList: List<CryptoCurrencyStatus>,
): Flow<ImmutableList<WalletNotification>> {
return flow {
emit(
return wasCardScannedUseCase.invoke(cardTypesResolver.getCardId())
.distinctUntilChanged()
.map {
buildList {
addCriticalNotifications(cardTypesResolver)
@ -42,11 +45,9 @@ internal class WalletNotificationsListFactory(
addRateTheAppNotification()
addWarningNotifications(cardTypesResolver, cryptoCurrencyList)
}
.toImmutableList(),
)
}
addWarningNotifications(cardTypesResolver, cryptoCurrencyList, it)
}.toImmutableList()
}
}
private fun MutableList<WalletNotification>.addCriticalNotifications(cardTypesResolver: CardTypesResolver) {
@ -112,9 +113,10 @@ internal class WalletNotificationsListFactory(
)
}
private suspend fun MutableList<WalletNotification>.addWarningNotifications(
private fun MutableList<WalletNotification>.addWarningNotifications(
cardTypesResolver: CardTypesResolver,
cryptoCurrencyList: List<CryptoCurrencyStatus>,
wasCardScanned: Boolean,
) {
addIf(
element = WalletNotification.Warning.MissingBackup(
@ -133,14 +135,22 @@ internal class WalletNotificationsListFactory(
if (cardTypesResolver.isBackupForbidden()) {
addIf(
element = WalletNotification.Warning.NumberOfSignedHashesIncorrect,
condition = checkSignedHashes(cardTypesResolver = cardTypesResolver, isDemo = isDemo),
condition = checkSignedHashes(
cardTypesResolver = cardTypesResolver,
isDemo = isDemo,
wasCardScanned,
),
)
} else {
addIf(
element = WalletNotification.Warning.MultiWalletSignedHashesIncorrect(
onClick = clickIntents::onMultiWalletSignedHashesNotificationClick,
),
condition = checkSignedHashes(cardTypesResolver = cardTypesResolver, isDemo = isDemo),
condition = checkSignedHashes(
cardTypesResolver = cardTypesResolver,
isDemo = isDemo,
wasCardScanned,
),
)
}
} else {
@ -159,7 +169,7 @@ internal class WalletNotificationsListFactory(
addIf(
element = WalletNotification.Warning.NumberOfSignedHashesIncorrect,
condition = checkSignedHashes(cardTypesResolver, isDemo),
condition = checkSignedHashes(cardTypesResolver, isDemo, wasCardScanned),
)
}
}
@ -176,9 +186,13 @@ internal class WalletNotificationsListFactory(
return any { it.value is CryptoCurrencyStatus.NoAccount }
}
private suspend fun checkSignedHashes(cardTypesResolver: CardTypesResolver, isDemo: Boolean): Boolean {
return cardTypesResolver.isReleaseFirmwareType() && cardTypesResolver.hasWalletSignedHashes() &&
!isDemo && !getCardWasScannedUseCase(cardId = cardTypesResolver.getCardId())
private fun checkSignedHashes(
cardTypesResolver: CardTypesResolver,
isDemo: Boolean,
wasCardScanned: Boolean,
): Boolean {
return cardTypesResolver.isReleaseFirmwareType() && cardTypesResolver.hasWalletSignedHashes() && !isDemo &&
!wasCardScanned
}
private companion object {

View file

@ -106,7 +106,8 @@ internal class WalletViewModel @Inject constructor(
private val reduxStateHolder: ReduxStateHolder,
private val dispatchers: CoroutineDispatcherProvider,
private val analyticsEventsHandler: AnalyticsEventHandler,
getCardWasScannedUseCase: GetCardWasScannedUseCase,
private val setCardWasScannedUseCase: SetCardWasScannedUseCase,
wasCardScannedUseCase: WasCardScannedUseCase,
isUserAlreadyRateAppUseCase: IsUserAlreadyRateAppUseCase,
isDemoCardUseCase: IsDemoCardUseCase,
// endregion Parameters
@ -119,7 +120,7 @@ internal class WalletViewModel @Inject constructor(
private var isBalanceHidden = true
private val notificationsListFactory = WalletNotificationsListFactory(
getCardWasScannedUseCase = getCardWasScannedUseCase,
wasCardScannedUseCase = wasCardScannedUseCase,
isUserAlreadyRateAppUseCase = isUserAlreadyRateAppUseCase,
isDemoCardUseCase = isDemoCardUseCase,
clickIntents = this,
@ -413,7 +414,21 @@ internal class WalletViewModel @Inject constructor(
}
override fun onMultiWalletSignedHashesNotificationClick() {
// TODO: [REDACTED_JIRA]
val state = uiState as? WalletState.ContentState ?: return
uiState = stateFactory.getStateAndTriggerEvent(
state = uiState,
event = WalletEvent.ShowWalletAlreadySignedHashesMessage(
onUnderstandClick = {
viewModelScope.launch(dispatchers.main) {
setCardWasScannedUseCase(
cardId = getWallet(index = state.walletsListConfig.selectedWalletIndex).cardId,
)
}
},
),
setUiState = { uiState = it },
)
}
override fun onLikeTangemAppClick() {