Updated on 2026-08-14
This commit is contained in:
parent
0159b2f1ff
commit
0257c23494
12 changed files with 128 additions and 64 deletions
|
|
@ -32,12 +32,13 @@ import com.tangem.core.ui.components.PrimaryButton
|
|||
import com.tangem.core.ui.components.TangemSwitch
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
|
||||
import com.tangem.core.ui.components.bottomsheets.modal.TangemModalBottomSheet
|
||||
import com.tangem.core.ui.components.bottomsheets.modal.TangemModalBottomSheetTitle
|
||||
import com.tangem.core.ui.components.bottomsheets.modal.TangemModalBottomSheetWithFooter
|
||||
import com.tangem.core.ui.components.notifications.Notification
|
||||
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.extensions.wrappedList
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.domain.models.network.Network
|
||||
|
|
@ -145,8 +146,11 @@ private fun MissingRequiredBlock(missingNetworks: ImmutableList<WcNetworkInfoIte
|
|||
val missingNetworksName = missingNetworks.joinToString { it.name }
|
||||
val notificationUM = remember(missingNetworks) {
|
||||
NotificationUM.Info(
|
||||
title = stringReference("The wallet has no required networks"),
|
||||
subtitle = stringReference("Add the $missingNetworksName network to your portfolio for this wallet."),
|
||||
title = resourceReference(R.string.wc_missing_required_network_title),
|
||||
subtitle = resourceReference(
|
||||
R.string.wc_missing_required_network_description,
|
||||
wrappedList(missingNetworksName),
|
||||
),
|
||||
)
|
||||
}
|
||||
Column(modifier = modifier) {
|
||||
|
|
@ -288,7 +292,7 @@ private fun NetworkNameAndSymbol(name: String, symbol: String, modifier: Modifie
|
|||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true, device = Devices.PIXEL_7_PRO)
|
||||
@Preview(showBackground = true, device = Devices.PIXEL_7_PRO, uiMode = Configuration.UI_MODE_NIGHT_NO)
|
||||
@Preview(showBackground = true, device = Devices.PIXEL_7_PRO, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun WcSelectNetworksContent_Preview(
|
||||
|
|
@ -296,29 +300,7 @@ private fun WcSelectNetworksContent_Preview(
|
|||
state: WcSelectNetworksUM,
|
||||
) {
|
||||
TangemThemePreview {
|
||||
TangemModalBottomSheet<TangemBottomSheetConfigContent.Empty>(
|
||||
containerColor = TangemTheme.colors.background.tertiary,
|
||||
config = TangemBottomSheetConfig(
|
||||
isShown = true,
|
||||
onDismissRequest = {},
|
||||
content = TangemBottomSheetConfigContent.Empty,
|
||||
),
|
||||
title = {
|
||||
TangemModalBottomSheetTitle(
|
||||
title = stringReference("Choose wallet"),
|
||||
onEndClick = {},
|
||||
endIconRes = R.drawable.ic_close_24,
|
||||
)
|
||||
},
|
||||
content = {
|
||||
WcSelectNetworksContent(
|
||||
modifier = Modifier
|
||||
.background(TangemTheme.colors.background.tertiary)
|
||||
.padding(horizontal = TangemTheme.dimens.spacing16),
|
||||
state = state,
|
||||
)
|
||||
},
|
||||
)
|
||||
WcSelectNetworksBS(state = state, onBack = {}, onDismiss = {})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -328,7 +310,7 @@ private class WcSelectNetworksProvider : CollectionPreviewParameterProvider<WcSe
|
|||
missing = persistentListOf(
|
||||
WcNetworkInfoItem.Required(
|
||||
id = "ethereum",
|
||||
name = "EthereumEthereumEthereumEthereumEthereumEthereumEthereumEthereum",
|
||||
name = "Ethereum",
|
||||
symbol = "ETH",
|
||||
icon = R.drawable.ic_solana_16,
|
||||
),
|
||||
|
|
@ -380,6 +362,7 @@ private class WcSelectNetworksProvider : CollectionPreviewParameterProvider<WcSe
|
|||
),
|
||||
),
|
||||
onDone = {},
|
||||
doneButtonEnabled = false,
|
||||
),
|
||||
WcSelectNetworksUM(
|
||||
missing = persistentListOf(),
|
||||
|
|
@ -424,6 +407,7 @@ private class WcSelectNetworksProvider : CollectionPreviewParameterProvider<WcSe
|
|||
),
|
||||
),
|
||||
onDone = {},
|
||||
doneButtonEnabled = true,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
|
@ -57,6 +57,7 @@ sealed class WcAppInfoSecurityNotification(
|
|||
|
||||
@Immutable
|
||||
internal sealed class WcNetworksInfo {
|
||||
data object NoneNetworksAdded : WcNetworksInfo()
|
||||
data class MissingRequiredNetworkInfo(val networks: String) : WcNetworksInfo()
|
||||
data class ContainsAllRequiredNetworks(val items: ImmutableList<WcNetworkInfoItem>) : WcNetworksInfo()
|
||||
}
|
||||
|
|
@ -8,5 +8,5 @@ internal data class WcSelectNetworksUM(
|
|||
val available: ImmutableList<WcNetworkInfoItem.Checkable>,
|
||||
val notAdded: ImmutableList<WcNetworkInfoItem.ReadOnly>,
|
||||
val onDone: () -> Unit,
|
||||
val doneButtonEnabled: Boolean = true,
|
||||
val doneButtonEnabled: Boolean,
|
||||
)
|
||||
|
|
@ -1,7 +1,9 @@
|
|||
package com.tangem.features.walletconnect.connections.model
|
||||
|
||||
import androidx.compose.runtime.Stable
|
||||
import com.arkivanov.decompose.router.stack.*
|
||||
import com.arkivanov.decompose.router.stack.StackNavigation
|
||||
import com.arkivanov.decompose.router.stack.pop
|
||||
import com.arkivanov.decompose.router.stack.pushNew
|
||||
import com.domain.blockaid.models.dapp.CheckDAppResult
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
|
|
@ -10,18 +12,16 @@ import com.tangem.core.decompose.model.ParamsContainer
|
|||
import com.tangem.core.decompose.navigation.Router
|
||||
import com.tangem.core.decompose.ui.UiMessageSender
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.message.SnackbarMessage
|
||||
import com.tangem.core.ui.message.ToastMessage
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.domain.walletconnect.WcAnalyticEvents
|
||||
import com.tangem.domain.walletconnect.model.WcPairError
|
||||
import com.tangem.domain.walletconnect.model.WcPairRequest
|
||||
import com.tangem.domain.walletconnect.model.WcSessionApprove
|
||||
import com.tangem.domain.walletconnect.model.WcSessionProposal
|
||||
import com.tangem.domain.walletconnect.usecase.pair.WcPairState
|
||||
import com.tangem.domain.walletconnect.usecase.pair.WcPairUseCase
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.models.wallet.isLocked
|
||||
import com.tangem.domain.models.wallet.isMultiCurrency
|
||||
import com.tangem.domain.walletconnect.WcAnalyticEvents
|
||||
import com.tangem.domain.walletconnect.model.*
|
||||
import com.tangem.domain.walletconnect.usecase.pair.WcPairState
|
||||
import com.tangem.domain.walletconnect.usecase.pair.WcPairUseCase
|
||||
import com.tangem.domain.wallets.usecase.GetWalletsUseCase
|
||||
import com.tangem.features.walletconnect.connections.components.WcPairComponent
|
||||
import com.tangem.features.walletconnect.connections.components.WcSelectNetworksComponent
|
||||
|
|
@ -91,7 +91,9 @@ internal class WcPairModel @Inject constructor(
|
|||
appInfoUiState.transformerUpdate(
|
||||
WcConnectButtonProgressTransformer(showProgress = false),
|
||||
)
|
||||
pairState.result.onLeft(::processError)
|
||||
pairState.result
|
||||
.onLeft(::processError)
|
||||
.onRight(::processSuccessfullyConnected)
|
||||
router.pop()
|
||||
}
|
||||
is WcPairState.Error -> {
|
||||
|
|
@ -196,6 +198,13 @@ internal class WcPairModel @Inject constructor(
|
|||
stackNavigation.pushNew(WcAppInfoRoutes.Alert(WcAppInfoRoutes.Alert.Type.Verified(appName)))
|
||||
}
|
||||
|
||||
private fun processSuccessfullyConnected(session: WcSession) {
|
||||
// TODO: [REDACTED_JIRA] localization
|
||||
messageSender.send(
|
||||
SnackbarMessage(message = stringReference("Connected to ${session.sdkModel.appMetaData.name}")),
|
||||
)
|
||||
}
|
||||
|
||||
private fun processError(error: WcPairError) {
|
||||
val alert = when (error) {
|
||||
is WcPairError.UnsupportedDApp -> {
|
||||
|
|
@ -236,6 +245,8 @@ internal class WcPairModel @Inject constructor(
|
|||
WcNetworksSelectedTransformer(
|
||||
missingNetworks = proposalNetwork.missingRequired,
|
||||
requiredNetworks = proposalNetwork.required,
|
||||
availableNetworks = proposalNetwork.available,
|
||||
notAddedNetworks = proposalNetwork.notAdded,
|
||||
additionallyEnabledNetworks = additionallyEnabledNetworks,
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -60,6 +60,9 @@ internal class WcSelectNetworksModel @Inject constructor(
|
|||
|
||||
private fun getInitialState(): WcSelectNetworksUM {
|
||||
val editEnabled = params.missingRequiredNetworks.isEmpty()
|
||||
val doneButtonEnabled = params.missingRequiredNetworks.isEmpty() &&
|
||||
(params.requiredNetworks.isNotEmpty() || params.availableNetworks.isNotEmpty())
|
||||
|
||||
return WcSelectNetworksUM(
|
||||
missing = params.missingRequiredNetworks.map { network ->
|
||||
WcNetworkInfoItem.Required(
|
||||
|
|
@ -98,7 +101,7 @@ internal class WcSelectNetworksModel @Inject constructor(
|
|||
)
|
||||
}.toImmutableList(),
|
||||
onDone = ::onDone,
|
||||
doneButtonEnabled = editEnabled,
|
||||
doneButtonEnabled = doneButtonEnabled,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -2,8 +2,8 @@ package com.tangem.features.walletconnect.connections.model.transformers
|
|||
|
||||
import com.domain.blockaid.models.dapp.CheckDAppResult
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.domain.walletconnect.model.WcSessionProposal
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.walletconnect.model.WcSessionProposal
|
||||
import com.tangem.features.walletconnect.connections.entity.WcAppInfoSecurityNotification
|
||||
import com.tangem.features.walletconnect.connections.entity.WcAppInfoUM
|
||||
import com.tangem.features.walletconnect.connections.entity.WcPrimaryButtonConfig
|
||||
|
|
@ -37,13 +37,22 @@ internal class WcAppInfoTransformer(
|
|||
value = WcNetworksInfoConverter.Input(
|
||||
missingNetworks = proposalNetwork.missingRequired,
|
||||
requiredNetworks = proposalNetwork.required,
|
||||
availableNetworks = proposalNetwork.available,
|
||||
notAddedNetworks = proposalNetwork.notAdded,
|
||||
additionallyEnabledNetworks = additionallyEnabledNetworks,
|
||||
),
|
||||
),
|
||||
onNetworksClick = onNetworksClick,
|
||||
connectButtonConfig = WcPrimaryButtonConfig(
|
||||
showProgress = false,
|
||||
enabled = proposalNetwork.missingRequired.isEmpty(),
|
||||
enabled = WcConnectButtonAvailabilityConverter.convert(
|
||||
WcConnectButtonAvailabilityConverter.Input(
|
||||
missingNetworks = proposalNetwork.missingRequired,
|
||||
requiredNetworks = proposalNetwork.required,
|
||||
availableNetworks = proposalNetwork.available,
|
||||
selectedNetworks = additionallyEnabledNetworks,
|
||||
),
|
||||
),
|
||||
onClick = { onConnect(dAppSession.securityStatus) },
|
||||
),
|
||||
onDismiss = onDismiss,
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
package com.tangem.features.walletconnect.connections.model.transformers
|
||||
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.domain.walletconnect.model.WcSessionProposal
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.walletconnect.model.WcSessionProposal
|
||||
import com.tangem.features.walletconnect.connections.entity.WcAppInfoUM
|
||||
import com.tangem.utils.transformer.Transformer
|
||||
|
||||
|
|
@ -19,11 +19,20 @@ internal class WcAppInfoWalletChangedTransformer(
|
|||
WcNetworksInfoConverter.Input(
|
||||
missingNetworks = proposalNetwork.missingRequired,
|
||||
requiredNetworks = proposalNetwork.required,
|
||||
availableNetworks = proposalNetwork.available,
|
||||
notAddedNetworks = proposalNetwork.notAdded,
|
||||
additionallyEnabledNetworks = additionallyEnabledNetworks,
|
||||
),
|
||||
),
|
||||
connectButtonConfig = prevState.connectButtonConfig.copy(
|
||||
enabled = proposalNetwork.missingRequired.isEmpty(),
|
||||
enabled = WcConnectButtonAvailabilityConverter.convert(
|
||||
WcConnectButtonAvailabilityConverter.Input(
|
||||
missingNetworks = proposalNetwork.missingRequired,
|
||||
requiredNetworks = proposalNetwork.required,
|
||||
availableNetworks = proposalNetwork.available,
|
||||
selectedNetworks = additionallyEnabledNetworks,
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
package com.tangem.features.walletconnect.connections.model.transformers
|
||||
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.utils.converter.Converter
|
||||
|
||||
@Suppress("DestructuringDeclarationWithTooManyEntries")
|
||||
internal object WcConnectButtonAvailabilityConverter : Converter<WcConnectButtonAvailabilityConverter.Input, Boolean> {
|
||||
|
||||
override fun convert(value: Input): Boolean {
|
||||
val (missingNetworks, requiredNetworks, availableNetworks, selectedNetworks) = value
|
||||
|
||||
return missingNetworks.isEmpty() &&
|
||||
(requiredNetworks.isNotEmpty() || availableNetworks.isNotEmpty() || selectedNetworks.isNotEmpty())
|
||||
}
|
||||
|
||||
data class Input(
|
||||
val missingNetworks: Set<Network>,
|
||||
val requiredNetworks: Set<Network>,
|
||||
val availableNetworks: Set<Network>,
|
||||
val selectedNetworks: Set<Network>,
|
||||
)
|
||||
}
|
||||
|
|
@ -7,31 +7,34 @@ import com.tangem.features.walletconnect.connections.entity.WcNetworksInfo
|
|||
import com.tangem.utils.converter.Converter
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
||||
@Suppress("DestructuringDeclarationWithTooManyEntries")
|
||||
internal object WcNetworksInfoConverter : Converter<WcNetworksInfoConverter.Input, WcNetworksInfo> {
|
||||
override fun convert(value: Input): WcNetworksInfo {
|
||||
return if (value.missingNetworks.isNotEmpty()) {
|
||||
WcNetworksInfo.MissingRequiredNetworkInfo(
|
||||
networks = value.missingNetworks.joinToString { it.name },
|
||||
)
|
||||
} else {
|
||||
WcNetworksInfo.ContainsAllRequiredNetworks(
|
||||
items = (value.requiredNetworks + value.additionallyEnabledNetworks)
|
||||
.map {
|
||||
val (missing, required, available, notAdded, additionallyEnabled) = value
|
||||
return when {
|
||||
missing.isNotEmpty() -> WcNetworksInfo.MissingRequiredNetworkInfo(missing.joinToString { it.name })
|
||||
required.isEmpty() && available.isEmpty() && notAdded.isNotEmpty() -> WcNetworksInfo.NoneNetworksAdded
|
||||
else -> {
|
||||
val combinedNetworks = required + additionallyEnabled
|
||||
WcNetworksInfo.ContainsAllRequiredNetworks(
|
||||
items = combinedNetworks.map { network ->
|
||||
WcNetworkInfoItem.Required(
|
||||
id = it.rawId,
|
||||
icon = it.iconResId,
|
||||
name = it.name,
|
||||
symbol = it.currencySymbol,
|
||||
id = network.rawId,
|
||||
icon = network.iconResId,
|
||||
name = network.name,
|
||||
symbol = network.currencySymbol,
|
||||
)
|
||||
}
|
||||
.toImmutableList(),
|
||||
)
|
||||
}.toImmutableList(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class Input(
|
||||
val missingNetworks: Set<Network>,
|
||||
val requiredNetworks: Set<Network>,
|
||||
val availableNetworks: Set<Network>,
|
||||
val notAddedNetworks: Set<Network>,
|
||||
val additionallyEnabledNetworks: Set<Network>,
|
||||
)
|
||||
}
|
||||
|
|
@ -7,19 +7,29 @@ import com.tangem.utils.transformer.Transformer
|
|||
internal class WcNetworksSelectedTransformer(
|
||||
private val missingNetworks: Set<Network>,
|
||||
private val requiredNetworks: Set<Network>,
|
||||
private val availableNetworks: Set<Network>,
|
||||
private val notAddedNetworks: Set<Network>,
|
||||
private val additionallyEnabledNetworks: Set<Network>,
|
||||
) : Transformer<WcAppInfoUM> {
|
||||
override fun transform(prevState: WcAppInfoUM): WcAppInfoUM {
|
||||
val contentState = prevState as? WcAppInfoUM.Content ?: return prevState
|
||||
return contentState.copy(
|
||||
connectButtonConfig = contentState.connectButtonConfig.copy(
|
||||
enabled = missingNetworks.isEmpty() &&
|
||||
(requiredNetworks.isNotEmpty() || additionallyEnabledNetworks.isNotEmpty()),
|
||||
enabled = WcConnectButtonAvailabilityConverter.convert(
|
||||
WcConnectButtonAvailabilityConverter.Input(
|
||||
missingNetworks = missingNetworks,
|
||||
requiredNetworks = requiredNetworks,
|
||||
availableNetworks = availableNetworks,
|
||||
selectedNetworks = additionallyEnabledNetworks,
|
||||
),
|
||||
),
|
||||
),
|
||||
networksInfo = WcNetworksInfoConverter.convert(
|
||||
value = WcNetworksInfoConverter.Input(
|
||||
missingNetworks = missingNetworks,
|
||||
requiredNetworks = requiredNetworks,
|
||||
availableNetworks = availableNetworks,
|
||||
notAddedNetworks = notAddedNetworks,
|
||||
additionallyEnabledNetworks = additionallyEnabledNetworks,
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -35,10 +35,7 @@ import com.tangem.core.ui.components.bottomsheets.modal.TangemModalBottomSheetTi
|
|||
import com.tangem.core.ui.components.bottomsheets.modal.TangemModalBottomSheetWithFooter
|
||||
import com.tangem.core.ui.components.notifications.Notification
|
||||
import com.tangem.core.ui.components.notifications.NotificationConfig
|
||||
import com.tangem.core.ui.extensions.clickableSingle
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||
import com.tangem.core.ui.extensions.wrappedList
|
||||
import com.tangem.core.ui.extensions.*
|
||||
import com.tangem.core.ui.res.TangemColorPalette
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
|
|
@ -284,6 +281,19 @@ private fun WcAppInfoSecondBlock(state: WcAppInfoUM.Content, modifier: Modifier
|
|||
)
|
||||
when (state.networksInfo) {
|
||||
is WcNetworksInfo.ContainsAllRequiredNetworks -> Unit
|
||||
is WcNetworksInfo.NoneNetworksAdded -> {
|
||||
HorizontalDivider(thickness = 1.dp, color = TangemTheme.colors.stroke.primary)
|
||||
Notification(
|
||||
config = NotificationConfig(
|
||||
iconResId = R.drawable.ic_alert_circle_24,
|
||||
// TODO: [REDACTED_JIRA] localization
|
||||
title = stringReference("Specify selected networks"),
|
||||
subtitle = stringReference("At least one network is required for dApp connection"),
|
||||
),
|
||||
iconTint = TangemTheme.colors.icon.attention,
|
||||
containerColor = TangemTheme.colors.background.action,
|
||||
)
|
||||
}
|
||||
is WcNetworksInfo.MissingRequiredNetworkInfo -> {
|
||||
HorizontalDivider(thickness = 1.dp, color = TangemTheme.colors.stroke.primary)
|
||||
Notification(
|
||||
|
|
@ -370,6 +380,7 @@ private fun SelectNetworksBlock(networksInfo: WcNetworksInfo, modifier: Modifier
|
|||
when (networksInfo) {
|
||||
is WcNetworksInfo.ContainsAllRequiredNetworks -> NetworkIcons(items = networksInfo.items)
|
||||
is WcNetworksInfo.MissingRequiredNetworkInfo -> Unit
|
||||
is WcNetworksInfo.NoneNetworksAdded -> Unit
|
||||
}
|
||||
Icon(
|
||||
modifier = Modifier.size(width = 18.dp, height = 24.dp),
|
||||
|
|
|
|||
|
|
@ -192,6 +192,7 @@ private fun ConnectionItem(connection: WcConnectionsUM, modifier: Modifier = Mod
|
|||
private fun AppInfoItem(appInfo: WcConnectedAppInfo, modifier: Modifier = Modifier) {
|
||||
Row(
|
||||
modifier = modifier,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing12),
|
||||
) {
|
||||
AsyncImage(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue