Updated on 2026-08-14

This commit is contained in:
Tangem 2023-01-18 18:05:18 +08:00
parent e98780ff93
commit 479d142807
283 changed files with 2338 additions and 2730 deletions

View file

@ -5,8 +5,8 @@ import com.tangem.common.core.TangemSdkError
import com.tangem.common.doOnFailure
import com.tangem.common.doOnSuccess
import com.tangem.common.flatMap
import com.tangem.domain.common.TapWorkarounds.isTangemTwins
import com.tangem.core.analytics.Analytics
import com.tangem.domain.common.TapWorkarounds.isTangemTwins
import com.tangem.tap.common.analytics.events.AnalyticsParam
import com.tangem.tap.common.analytics.events.Settings
import com.tangem.tap.common.extensions.dispatchDialogShow
@ -146,6 +146,7 @@ class DetailsMiddleware {
}
class ManageSecurityMiddleware {
@Suppress("ComplexMethod")
fun handle(action: DetailsAction.ManageSecurity) {
when (action) {
is DetailsAction.ManageSecurity.OpenSecurity -> {

View file

@ -15,10 +15,8 @@ import com.tangem.tap.tangemSdkManager
import org.rekotlin.Action
import java.util.*
class DetailsReducer {
companion object {
fun reduce(action: Action, state: AppState): DetailsState = internalReduce(action, state)
}
object DetailsReducer {
fun reduce(action: Action, state: AppState): DetailsState = internalReduce(action, state)
}
private fun internalReduce(action: Action, state: AppState): DetailsState {
@ -104,8 +102,7 @@ private fun prepareSecurityOptions(card: CardDTO): ManageSecurityState {
private fun isResetToFactoryAllowedByCard(card: CardDTO): Boolean {
val notAllowedByAnyWallet = card.wallets.any { it.settings.isPermanent }
val notAllowedByCard = notAllowedByAnyWallet ||
(card.isWalletDataSupported && (!card.isTangemNote && !card.settings.isBackupAllowed)) ||
card.isSaltPay
card.isWalletDataSupported && !card.isTangemNote && !card.settings.isBackupAllowed || card.isSaltPay
return !notAllowedByCard
}
@ -188,6 +185,7 @@ private fun prepareAllowedSecurityOptions(
return allowedSecurityOptions
}
@Suppress("MagicNumber")
private fun CardDTO.toCardInfo(): CardInfo {
val cardId = this.cardId.chunked(4).joinToString(separator = " ")
val issuer = this.issuer.name

View file

@ -40,6 +40,7 @@ class WalletConnectMiddleware {
}
}
@Suppress("ComplexMethod", "LongMethod")
private fun handle(state: () -> AppState?, action: Action) {
if (DemoHelper.tryHandle(state, action)) return
@ -49,10 +50,8 @@ class WalletConnectMiddleware {
walletConnectManager.restoreSessions(action.scanResponse)
}
is WalletConnectAction.HandleDeepLink -> {
if (!action.wcUri.isNullOrBlank()) {
if (WalletConnectManager.isCorrectWcUri(action.wcUri)) {
store.dispatchOnMain(WalletConnectAction.OpenSession(action.wcUri))
}
if (!action.wcUri.isNullOrBlank() && WalletConnectManager.isCorrectWcUri(action.wcUri)) {
store.dispatchOnMain(WalletConnectAction.OpenSession(action.wcUri))
}
}
is WalletConnectAction.StartWalletConnect -> {

View file

@ -2,47 +2,44 @@ package com.tangem.tap.features.details.redux.walletconnect
import org.rekotlin.Action
class WalletConnectReducer {
companion object {
fun reduce(
action: Action, state: WalletConnectState,
): WalletConnectState {
if (action !is WalletConnectAction) return state
object WalletConnectReducer {
fun reduce(
action: Action, state: WalletConnectState,
): WalletConnectState {
if (action !is WalletConnectAction) return state
return when (action) {
is WalletConnectAction.ResetState -> return WalletConnectState()
is WalletConnectAction.ApproveSession.Success -> {
state.copy(
loading = false,
sessions = state.sessions + action.session,
)
}
is WalletConnectAction.OpenSession -> {
state.copy(loading = true)
}
is WalletConnectAction.SetNewSessionData -> {
state.copy(newSessionData = action.newSession)
}
is WalletConnectAction.SetSessionsRestored ->
WalletConnectState(sessions = action.sessions)
is WalletConnectAction.RemoveSession -> {
val sessions =
state.sessions.filterNot { it.session.toUri() == action.session.toUri() }
state.copy(sessions = sessions)
}
is WalletConnectAction.UnsupportedCard -> state.copy(loading = false)
is WalletConnectAction.RefuseOpeningSession -> state.copy(loading = false)
is WalletConnectAction.OpeningSessionTimeout -> state.copy(loading = false)
is WalletConnectAction.FailureEstablishingSession -> state.copy(loading = false)
is WalletConnectAction.UpdateBlockchain -> state.copy(
sessions = state.sessions
.filterNot { it.peerId == action.updatedSession.peerId }
+ action.updatedSession
return when (action) {
is WalletConnectAction.ResetState -> return WalletConnectState()
is WalletConnectAction.ApproveSession.Success -> {
state.copy(
loading = false,
sessions = state.sessions + action.session,
)
else -> state
}
}
is WalletConnectAction.OpenSession -> {
state.copy(loading = true)
}
is WalletConnectAction.SetNewSessionData -> {
state.copy(newSessionData = action.newSession)
}
is WalletConnectAction.SetSessionsRestored ->
WalletConnectState(sessions = action.sessions)
is WalletConnectAction.RemoveSession -> {
val sessions =
state.sessions.filterNot { it.session.toUri() == action.session.toUri() }
state.copy(sessions = sessions)
}
is WalletConnectAction.UnsupportedCard -> state.copy(loading = false)
is WalletConnectAction.RefuseOpeningSession -> state.copy(loading = false)
is WalletConnectAction.OpeningSessionTimeout -> state.copy(loading = false)
is WalletConnectAction.FailureEstablishingSession -> state.copy(loading = false)
is WalletConnectAction.UpdateBlockchain -> state.copy(
sessions = state.sessions
.filterNot { it.peerId == action.updatedSession.peerId }
+ action.updatedSession,
)
else -> state
}
}
}

View file

@ -74,7 +74,7 @@ data class WalletForSession(
}
override fun hashCode(): Int {
var result = (walletPublicKey?.contentHashCode() ?: 0)
var result = walletPublicKey?.contentHashCode() ?: 0
result = 31 * result + (derivedPublicKey?.contentHashCode() ?: 0)
result = 31 * result + (derivationPath?.hashCode() ?: 0)
result = 31 * result + isTestNet.hashCode()

View file

@ -89,6 +89,7 @@ private fun AppSettings(
}
}
@Suppress("LongMethod")
@Composable
private fun AppSettingsElement(
modifier: Modifier = Modifier,

View file

@ -51,6 +51,7 @@ fun CardSettingsScreen(
)
}
@Suppress("MagicNumber")
@Composable
fun CardSettingsReadCard(
onScanCardClick: () -> Unit,
@ -114,6 +115,7 @@ fun CardSettingsReadCard(
}
}
@Suppress("ComplexMethod")
@Composable
fun CardSettings(
state: CardSettingsScreenState,

View file

@ -1,14 +1,13 @@
package com.tangem.tap.features.details.ui.cardsettings
import com.tangem.core.analytics.Analytics
import com.tangem.domain.common.TapWorkarounds.isTangemTwins
import com.tangem.domain.common.getTwinCardIdForUser
import com.tangem.core.analytics.Analytics
import com.tangem.tap.common.analytics.events.AnalyticsParam
import com.tangem.tap.common.analytics.events.Settings
import com.tangem.tap.common.redux.AppState
import com.tangem.tap.features.details.redux.CardSettingsState
import com.tangem.tap.features.details.redux.DetailsAction
import com.tangem.wallet.R
import org.rekotlin.Store
class CardSettingsViewModel(private val store: Store<AppState>) {

View file

@ -30,6 +30,7 @@ import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import com.tangem.wallet.R
@Suppress("MagicNumber")
@Composable
fun TangemSwitch(
modifier: Modifier = Modifier,

View file

@ -1,8 +1,7 @@
package com.tangem.tap.features.details.ui.details
import com.tangem.domain.common.TapWorkarounds.isSaltPay
import com.tangem.domain.common.TapWorkarounds.isStart2Coin
import com.tangem.core.analytics.Analytics
import com.tangem.domain.common.TapWorkarounds.isSaltPay
import com.tangem.tap.common.analytics.events.Settings
import com.tangem.tap.common.feedback.FeedbackEmail
import com.tangem.tap.common.feedback.SupportInfo
@ -21,6 +20,8 @@ import com.tangem.wallet.BuildConfig
import org.rekotlin.Store
class DetailsViewModel(private val store: Store<AppState>) {
@Suppress("ComplexMethod")
fun updateState(state: DetailsState): DetailsScreenState {
val settings = SettingsElement.values().mapNotNull {
when (it) {

View file

@ -42,6 +42,7 @@ fun ResetCardScreen(state: ResetCardScreenState, onBackPressed: () -> Unit) {
)
}
@Suppress("LongMethod", "MagicNumber")
@Composable
fun ResetCardView(state: ResetCardScreenState) {
Column(

View file

@ -9,13 +9,15 @@ import org.rekotlin.Store
class SecurityModeViewModel(val store: Store<AppState>) {
fun updateState(state: ManageSecurityState?): SecurityModeScreenState {
if (state == null) return SecurityModeScreenState(
availableOptions = emptyList(),
selectedSecurityMode = SecurityOption.LongTap,
isSaveChangesEnabled = false,
onNewModeSelected = {},
onSaveChangesClicked = {},
)
if (state == null) {
return SecurityModeScreenState(
availableOptions = emptyList(),
selectedSecurityMode = SecurityOption.LongTap,
isSaveChangesEnabled = false,
onNewModeSelected = {},
onSaveChangesClicked = {},
)
}
return SecurityModeScreenState(
availableOptions = state.allowedOptions.toList(),
selectedSecurityMode = state.selectedOption,

View file

@ -9,38 +9,36 @@ import com.tangem.tap.features.details.redux.walletconnect.WalletConnectSession
import com.tangem.tap.store
import com.tangem.wallet.R
class ApproveWcSessionDialog {
companion object {
fun create(session: WalletConnectSession, networks: List<Blockchain>, context: Context): AlertDialog {
val sessionBlockchain = requireNotNull(session.wallet.blockchain) { "session network is null" }
val message = context.getString(
R.string.wallet_connect_request_session_start,
session.peerMeta.name,
sessionBlockchain.fullName,
session.peerMeta.url,
)
return AlertDialog.Builder(context).apply {
setTitle(context.getString(R.string.wallet_connect_title))
setMessage(message)
setPositiveButton(context.getText(R.string.common_start)) { _, _ ->
object ApproveWcSessionDialog {
fun create(session: WalletConnectSession, networks: List<Blockchain>, context: Context): AlertDialog {
val sessionBlockchain = requireNotNull(session.wallet.blockchain) { "session network is null" }
val message = context.getString(
R.string.wallet_connect_request_session_start,
session.peerMeta.name,
sessionBlockchain.fullName,
session.peerMeta.url,
)
return AlertDialog.Builder(context).apply {
setTitle(context.getString(R.string.wallet_connect_title))
setMessage(message)
setPositiveButton(context.getText(R.string.common_start)) { _, _ ->
store.dispatch(GlobalAction.HideDialog)
store.dispatch(WalletConnectAction.ChooseNetwork(sessionBlockchain))
}
if (networks.size > 1) {
setNeutralButton(context.getText(R.string.wallet_connect_select_network)) { _, _ ->
store.dispatch(GlobalAction.HideDialog)
store.dispatch(WalletConnectAction.ChooseNetwork(sessionBlockchain))
store.dispatch(WalletConnectAction.SelectNetwork(session = session, networks = networks))
}
if (networks.size > 1) {
setNeutralButton(context.getText(R.string.wallet_connect_select_network)) { _, _ ->
store.dispatch(GlobalAction.HideDialog)
store.dispatch(WalletConnectAction.SelectNetwork(session = session, networks = networks))
}
}
setNegativeButton(context.getText(R.string.common_reject)) { _, _ ->
store.dispatch(GlobalAction.HideDialog)
store.dispatch(WalletConnectAction.FailureEstablishingSession(session.session))
}
setOnCancelListener {
store.dispatch(GlobalAction.HideDialog)
store.dispatch(WalletConnectAction.FailureEstablishingSession(session.session))
}
}.create()
}
}
setNegativeButton(context.getText(R.string.common_reject)) { _, _ ->
store.dispatch(GlobalAction.HideDialog)
store.dispatch(WalletConnectAction.FailureEstablishingSession(session.session))
}
setOnCancelListener {
store.dispatch(GlobalAction.HideDialog)
store.dispatch(WalletConnectAction.FailureEstablishingSession(session.session))
}
}.create()
}
}

View file

@ -9,59 +9,57 @@ import com.tangem.tap.store
import com.tangem.wallet.R
import com.trustwallet.walletconnect.models.session.WCSession
class BnbTransactionDialog {
companion object {
fun create(
data: BinanceMessageData,
session: WCSession,
sessionId: Long,
dAppName: String,
context: Context,
): AlertDialog {
object BnbTransactionDialog {
fun create(
data: BinanceMessageData,
session: WCSession,
sessionId: Long,
dAppName: String,
context: Context,
): AlertDialog {
val message = when (data) {
is BinanceMessageData.Trade -> data.tradeData.map {
context.getString(
R.string.wallet_connect_bnb_trade_order_message,
it.symbol,
it.price,
it.quantity,
it.amount,
)
}.joinToString(separator = "\n\n")
is BinanceMessageData.Transfer -> context.getString(
R.string.wallet_connect_bnb_transaction_message,
data.address,
data.outputAddress,
data.amount,
val message = when (data) {
is BinanceMessageData.Trade -> data.tradeData.map {
context.getString(
R.string.wallet_connect_bnb_trade_order_message,
it.symbol,
it.price,
it.quantity,
it.amount,
)
}.joinToString(separator = "\n\n")
is BinanceMessageData.Transfer -> context.getString(
R.string.wallet_connect_bnb_transaction_message,
data.address,
data.outputAddress,
data.amount,
)
}
val fullMessage = context.getString(
R.string.wallet_connect_bnb_sign_message,
dAppName, message,
)
val positiveButtonTitle = context.getText(R.string.common_sign)
return AlertDialog.Builder(context).apply {
setTitle(context.getString(R.string.wallet_connect_title))
setMessage(fullMessage)
setPositiveButton(positiveButtonTitle) { _, _ ->
store.dispatch(
WalletConnectAction.BinanceTransaction.Sign(
id = sessionId,
data = data.data,
sessionData = session,
),
)
}
val fullMessage = context.getString(
R.string.wallet_connect_bnb_sign_message,
dAppName, message,
)
val positiveButtonTitle = context.getText(R.string.common_sign)
return AlertDialog.Builder(context).apply {
setTitle(context.getString(R.string.wallet_connect_title))
setMessage(fullMessage)
setPositiveButton(positiveButtonTitle) { _, _ ->
store.dispatch(
WalletConnectAction.BinanceTransaction.Sign(
id = sessionId,
data = data.data,
sessionData = session,
),
)
}
setNegativeButton(context.getText(R.string.common_reject)) { _, _ ->
store.dispatch(WalletConnectAction.RejectRequest(session, sessionId))
}
setOnDismissListener {
store.dispatch(GlobalAction.HideDialog)
}
}.create()
}
setNegativeButton(context.getText(R.string.common_reject)) { _, _ ->
store.dispatch(WalletConnectAction.RejectRequest(session, sessionId))
}
setOnDismissListener {
store.dispatch(GlobalAction.HideDialog)
}
}.create()
}
}

View file

@ -9,22 +9,20 @@ import com.tangem.tap.features.details.redux.walletconnect.WalletConnectAction
import com.tangem.tap.store
import com.tangem.wallet.R
class ClipboardOrScanQrDialog {
companion object {
fun create(wcUri: String, context: Context): AlertDialog {
return AlertDialog.Builder(context).apply {
setTitle(context.getString(R.string.wallet_connect_title))
setMessage(context.getText(R.string.wallet_connect_clipboard_alert))
setPositiveButton(context.getText(R.string.wallet_connect_paste_from_clipboard)) { _, _ ->
store.dispatch(WalletConnectAction.OpenSession(wcUri))
}
setNegativeButton(context.getText(R.string.wallet_connect_scan_new_code)) { _, _ ->
store.dispatch(NavigationAction.NavigateTo(AppScreen.QrScan))
}
setOnDismissListener {
store.dispatch(GlobalAction.HideDialog)
}
}.create()
}
object ClipboardOrScanQrDialog {
fun create(wcUri: String, context: Context): AlertDialog {
return AlertDialog.Builder(context).apply {
setTitle(context.getString(R.string.wallet_connect_title))
setMessage(context.getText(R.string.wallet_connect_clipboard_alert))
setPositiveButton(context.getText(R.string.wallet_connect_paste_from_clipboard)) { _, _ ->
store.dispatch(WalletConnectAction.OpenSession(wcUri))
}
setNegativeButton(context.getText(R.string.wallet_connect_scan_new_code)) { _, _ ->
store.dispatch(NavigationAction.NavigateTo(AppScreen.QrScan))
}
setOnDismissListener {
store.dispatch(GlobalAction.HideDialog)
}
}.create()
}
}

View file

@ -8,24 +8,22 @@ import com.tangem.tap.store
import com.tangem.wallet.R
import com.trustwallet.walletconnect.models.session.WCSession
class PersonalSignDialog {
companion object {
fun create(data: PersonalSignDialogData, context: Context): AlertDialog {
val message = context.getString(R.string.wallet_connect_alert_sign_message, data.message)
return AlertDialog.Builder(context).apply {
setTitle(context.getString(R.string.wallet_connect_title))
setMessage(message)
setPositiveButton(context.getText(R.string.common_sign)) { _, _ ->
store.dispatch(WalletConnectAction.SignMessage(data.session))
}
setNegativeButton(context.getText(R.string.common_reject)) { _, _ ->
store.dispatch(WalletConnectAction.RejectRequest(data.session, data.id))
}
setOnDismissListener {
store.dispatch(GlobalAction.HideDialog)
}
}.create()
}
object PersonalSignDialog {
fun create(data: PersonalSignDialogData, context: Context): AlertDialog {
val message = context.getString(R.string.wallet_connect_alert_sign_message, data.message)
return AlertDialog.Builder(context).apply {
setTitle(context.getString(R.string.wallet_connect_title))
setMessage(message)
setPositiveButton(context.getText(R.string.common_sign)) { _, _ ->
store.dispatch(WalletConnectAction.SignMessage(data.session))
}
setNegativeButton(context.getText(R.string.common_reject)) { _, _ ->
store.dispatch(WalletConnectAction.RejectRequest(data.session, data.id))
}
setOnDismissListener {
store.dispatch(GlobalAction.HideDialog)
}
}.create()
}
}

View file

@ -9,45 +9,40 @@ import com.tangem.tap.store
import com.tangem.wallet.R
import com.trustwallet.walletconnect.models.session.WCSession
class TransactionDialog {
companion object {
fun create(
data: TransactionRequestDialogData,
context: Context,
): AlertDialog {
val message = context.getString(
R.string.wallet_connect_create_tx_message,
data.dAppName,
data.dAppUrl,
data.amount,
data.gasAmount,
data.totalAmount,
data.balance,
)
object TransactionDialog {
fun create(data: TransactionRequestDialogData, context: Context): AlertDialog {
val message = context.getString(
R.string.wallet_connect_create_tx_message,
data.dAppName,
data.dAppUrl,
data.amount,
data.gasAmount,
data.totalAmount,
data.balance,
)
val positiveButtonTitle = when (data.type) {
WcTransactionType.EthSignTransaction -> context.getText(R.string.common_sign)
WcTransactionType.EthSendTransaction -> context.getText(R.string.common_sign_and_send)
}
return AlertDialog.Builder(context).apply {
setTitle(context.getString(R.string.wallet_connect_title))
setMessage(message)
setPositiveButton(positiveButtonTitle) { _, _ ->
if (data.isEnoughFundsToSend) {
store.dispatch(WalletConnectAction.SendTransaction(data.session))
} else {
store.dispatch(WalletConnectAction.RejectRequest(data.session, data.id))
store.dispatch(WalletConnectAction.NotEnoughFunds)
}
}
setNegativeButton(context.getText(R.string.common_reject)) { _, _ ->
store.dispatch(WalletConnectAction.RejectRequest(data.session, data.id))
}
setOnDismissListener {
store.dispatch(GlobalAction.HideDialog)
}
}.create()
val positiveButtonTitle = when (data.type) {
WcTransactionType.EthSignTransaction -> context.getText(R.string.common_sign)
WcTransactionType.EthSendTransaction -> context.getText(R.string.common_sign_and_send)
}
return AlertDialog.Builder(context).apply {
setTitle(context.getString(R.string.wallet_connect_title))
setMessage(message)
setPositiveButton(positiveButtonTitle) { _, _ ->
if (data.isEnoughFundsToSend) {
store.dispatch(WalletConnectAction.SendTransaction(data.session))
} else {
store.dispatch(WalletConnectAction.RejectRequest(data.session, data.id))
store.dispatch(WalletConnectAction.NotEnoughFunds)
}
}
setNegativeButton(context.getText(R.string.common_reject)) { _, _ ->
store.dispatch(WalletConnectAction.RejectRequest(data.session, data.id))
}
setOnDismissListener {
store.dispatch(GlobalAction.HideDialog)
}
}.create()
}
}

View file

@ -1,55 +0,0 @@
package com.tangem.tap.features.details.ui.walletconnect.dialogs
import android.content.Context
import androidx.appcompat.app.AlertDialog
class WcDialog {
companion object {
fun create(dialogData: DialogData, context: Context): AlertDialog {
return AlertDialog.Builder(context).apply {
setTitle(dialogData.title)
setMessage(dialogData.message)
setPositiveButton(dialogData.positiveButton.title) { _, _ ->
dialogData.positiveButton.action()
}
setNegativeButton(dialogData.negativeButton.title) { _, _ ->
dialogData.negativeButton.action()
}
setOnDismissListener { dialogData.onDismissAction() }
}.create()
}
}
}
data class DialogData(
val title: String,
val message: String,
val positiveButton: ButtonData,
val negativeButton: ButtonData,
val onDismissAction: () -> Unit,
)
data class ButtonData(
val title: String,
val action: () -> Unit,
)
//class WcDialogMessageBuilder(val messageRes: Int, val data: DialogMessageData? = null) {
// fun build(context: Context): String {
// when (data) {
// null -> context.getString(messageRes)
// }
// }
//}
interface DialogMessageData
data class WcTransactionDialogMessageData(
val dAppName: String,
val dAppUrl: String,
val amount: String,
val gasAmount: String,
val totalAmount: String,
val balance: String,
val isEnoughFundsToSend: Boolean,
)