Updated on 2026-08-14
This commit is contained in:
parent
dc9341bb71
commit
222b5d75d1
23 changed files with 300 additions and 48 deletions
|
|
@ -1,6 +1,7 @@
|
|||
plugins {
|
||||
alias(deps.plugins.android.library)
|
||||
alias(deps.plugins.kotlin.android)
|
||||
alias(deps.plugins.kotlin.serialization)
|
||||
id("configuration")
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import com.tangem.core.ui.extensions.TextReference
|
|||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toPersistentList
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Immutable
|
||||
data class MessageBottomSheetUMV2(
|
||||
|
|
@ -24,6 +25,7 @@ data class MessageBottomSheetUMV2(
|
|||
val closeScope = CloseScope()
|
||||
|
||||
@Immutable
|
||||
@Serializable
|
||||
sealed interface Element
|
||||
|
||||
@Immutable
|
||||
|
|
@ -90,7 +92,7 @@ annotation class MessageBottomSheetV2Dsl
|
|||
|
||||
// region: DSL
|
||||
|
||||
internal fun messageBottomSheetUM(init: @MessageBottomSheetV2Dsl MessageBottomSheetUMV2.() -> Unit) =
|
||||
fun messageBottomSheetUM(init: @MessageBottomSheetV2Dsl MessageBottomSheetUMV2.() -> Unit) =
|
||||
MessageBottomSheetUMV2().apply(init)
|
||||
|
||||
fun MessageBottomSheetUMV2.onDismiss(block: () -> Unit) = MessageBottomSheetUMV2().apply { onDismissRequest = block }
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import androidx.compose.foundation.shape.RoundedCornerShape
|
|||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
|
|
@ -33,23 +34,31 @@ import kotlinx.collections.immutable.toPersistentList
|
|||
|
||||
@Composable
|
||||
fun MessageBottomSheetV2(state: MessageBottomSheetUMV2, onDismissRequest: () -> Unit) {
|
||||
val stateWithOnDismiss = remember(state) {
|
||||
state.copy(
|
||||
onDismissRequest = {
|
||||
state.onDismissRequest.invoke()
|
||||
onDismissRequest()
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
val config = TangemBottomSheetConfig(
|
||||
isShown = true,
|
||||
content = state,
|
||||
onDismissRequest = onDismissRequest,
|
||||
content = stateWithOnDismiss,
|
||||
onDismissRequest = stateWithOnDismiss.onDismissRequest,
|
||||
)
|
||||
|
||||
TangemModalBottomSheet(
|
||||
config,
|
||||
config = config,
|
||||
title = {
|
||||
TangemModalBottomSheetTitle(
|
||||
endIconRes = R.drawable.ic_close_24,
|
||||
onEndClick = state.onDismissRequest,
|
||||
onEndClick = stateWithOnDismiss.onDismissRequest,
|
||||
)
|
||||
},
|
||||
) { content: MessageBottomSheetUMV2 ->
|
||||
MessageBottomSheetV2Content(content.copy(onDismissRequest = onDismissRequest))
|
||||
}
|
||||
content = { content: MessageBottomSheetUMV2 -> MessageBottomSheetV2Content(content) },
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
|
|
|||
|
|
@ -27,4 +27,15 @@ fun Modifier.clickableSingle(
|
|||
indication = LocalIndication.current,
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Conditionally applies a modifier based on a boolean condition.
|
||||
*/
|
||||
fun Modifier.conditional(condition: Boolean, modifier: Modifier.() -> Modifier): Modifier {
|
||||
return if (condition) {
|
||||
then(modifier(Modifier))
|
||||
} else {
|
||||
this
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
package com.tangem.features.walletconnect.connections.components
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.ui.components.bottomsheets.message.MessageBottomSheetUMV2
|
||||
import com.tangem.core.ui.components.bottomsheets.message.MessageBottomSheetV2
|
||||
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
internal class AlertsComponentV2(
|
||||
appComponentContext: AppComponentContext,
|
||||
private val elements: ImmutableList<MessageBottomSheetUMV2.Element>,
|
||||
private val onDismissRequest: () -> Unit = {},
|
||||
) : AppComponentContext by appComponentContext, ComposableBottomSheetComponent {
|
||||
|
||||
override fun dismiss() {
|
||||
router.pop()
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun BottomSheet() {
|
||||
MessageBottomSheetV2(
|
||||
state = MessageBottomSheetUMV2(elements = elements, onDismissRequest = onDismissRequest),
|
||||
onDismissRequest = ::dismiss,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -6,7 +6,6 @@ import androidx.compose.runtime.getValue
|
|||
import androidx.compose.ui.Modifier
|
||||
import com.arkivanov.decompose.ComponentContext
|
||||
import com.arkivanov.decompose.extensions.compose.subscribeAsState
|
||||
import com.arkivanov.decompose.router.stack.StackNavigation
|
||||
import com.arkivanov.decompose.router.stack.childStack
|
||||
import com.arkivanov.decompose.router.stack.pop
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
|
|
@ -25,15 +24,14 @@ internal class WcPairComponent(
|
|||
params: Params,
|
||||
) : AppComponentContext by appComponentContext, ComposableContentComponent {
|
||||
|
||||
private val stackNavigation = StackNavigation<WcAppInfoRoutes>()
|
||||
private val model: WcPairModel = getOrCreateModel(params = params)
|
||||
private val innerRouter = InnerRouter<WcAppInfoRoutes>(
|
||||
stackNavigation = stackNavigation,
|
||||
stackNavigation = model.stackNavigation,
|
||||
popCallback = { onChildBack() },
|
||||
)
|
||||
private val model: WcPairModel = getOrCreateModel(params = params, router = innerRouter)
|
||||
private val contentStack = childStack(
|
||||
key = "WcConnectionFlowStack",
|
||||
source = stackNavigation,
|
||||
source = model.stackNavigation,
|
||||
serializer = WcAppInfoRoutes.serializer(),
|
||||
initialConfiguration = WcAppInfoRoutes.AppInfo,
|
||||
handleBackButton = true,
|
||||
|
|
@ -59,7 +57,7 @@ internal class WcPairComponent(
|
|||
is WcAppInfoRoutes.Alert,
|
||||
is WcAppInfoRoutes.SelectNetworks,
|
||||
is WcAppInfoRoutes.SelectWallet,
|
||||
-> stackNavigation.pop()
|
||||
-> model.stackNavigation.pop()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -77,7 +75,10 @@ internal class WcPairComponent(
|
|||
onDismiss = ::dismiss,
|
||||
model = model,
|
||||
)
|
||||
is WcAppInfoRoutes.Alert -> TODO()
|
||||
is WcAppInfoRoutes.Alert -> AlertsComponentV2(
|
||||
appComponentContext = appComponentContext,
|
||||
elements = config.elements,
|
||||
)
|
||||
is WcAppInfoRoutes.SelectNetworks -> WcSelectNetworksComponent(
|
||||
appComponentContext = appComponentContext,
|
||||
params = WcSelectNetworksComponent.WcSelectNetworksParams(
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ internal sealed class WcAppInfoUM : TangemBottomSheetConfigContent {
|
|||
data class Content(
|
||||
val appName: String,
|
||||
val appIcon: String,
|
||||
val isVerified: Boolean,
|
||||
val verifiedDAppState: VerifiedDAppState,
|
||||
val appSubtitle: String,
|
||||
val notification: WcAppInfoSecurityNotification?,
|
||||
val walletName: String,
|
||||
|
|
@ -34,6 +34,12 @@ internal sealed class WcAppInfoUM : TangemBottomSheetConfigContent {
|
|||
) : WcAppInfoUM()
|
||||
}
|
||||
|
||||
@Immutable
|
||||
sealed class VerifiedDAppState {
|
||||
data class Verified(val onVerifiedClick: () -> Unit) : VerifiedDAppState()
|
||||
data object Unknown : VerifiedDAppState()
|
||||
}
|
||||
|
||||
sealed class WcAppInfoSecurityNotification(
|
||||
title: TextReference,
|
||||
subtitle: TextReference,
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ data class WcConnectedAppInfoUM(
|
|||
val appName: String,
|
||||
val appIcon: String,
|
||||
val isVerified: Boolean,
|
||||
val verifiedDAppState: VerifiedDAppState,
|
||||
val appSubtitle: String,
|
||||
val walletName: String,
|
||||
val networks: ImmutableList<WcNetworkInfoItem.Required>,
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import com.tangem.domain.walletconnect.model.WcSession
|
|||
import com.tangem.domain.walletconnect.usecase.WcSessionsUseCase
|
||||
import com.tangem.domain.walletconnect.usecase.disconnect.WcDisconnectUseCase
|
||||
import com.tangem.features.walletconnect.connections.components.WcConnectedAppInfoComponent
|
||||
import com.tangem.features.walletconnect.connections.entity.VerifiedDAppState
|
||||
import com.tangem.features.walletconnect.connections.entity.WcConnectedAppInfoUM
|
||||
import com.tangem.features.walletconnect.connections.entity.WcNetworkInfoItem
|
||||
import com.tangem.features.walletconnect.connections.entity.WcPrimaryButtonConfig
|
||||
|
|
@ -56,6 +57,7 @@ internal class WcConnectedAppInfoModel @Inject constructor(
|
|||
appName = session.sdkModel.appMetaData.name,
|
||||
appIcon = session.sdkModel.appMetaData.icons.firstOrNull().orEmpty(),
|
||||
isVerified = session.securityStatus == CheckDAppResult.SAFE,
|
||||
verifiedDAppState = extractVerifiedState(session),
|
||||
appSubtitle = session.sdkModel.appMetaData.description,
|
||||
walletName = session.wallet.name,
|
||||
networks = session.networks
|
||||
|
|
@ -79,6 +81,15 @@ internal class WcConnectedAppInfoModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun extractVerifiedState(session: WcSession): VerifiedDAppState {
|
||||
return VerifiedDAppState.Verified(onVerifiedClick = {})
|
||||
return if (session.securityStatus == CheckDAppResult.SAFE) {
|
||||
VerifiedDAppState.Verified(onVerifiedClick = {})
|
||||
} else {
|
||||
VerifiedDAppState.Unknown
|
||||
}
|
||||
}
|
||||
|
||||
private fun disconnect(session: WcSession) {
|
||||
uiState.update { state ->
|
||||
state?.copy(
|
||||
|
|
|
|||
|
|
@ -1,10 +1,18 @@
|
|||
package com.tangem.features.walletconnect.connections.model
|
||||
|
||||
import androidx.compose.runtime.Stable
|
||||
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.decompose.di.ModelScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
import com.tangem.core.decompose.navigation.Router
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.components.bottomsheets.message.*
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.wrappedList
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.domain.walletconnect.model.WcPairRequest
|
||||
import com.tangem.domain.walletconnect.model.WcSessionApprove
|
||||
|
|
@ -21,6 +29,7 @@ import com.tangem.features.walletconnect.connections.entity.WcPrimaryButtonConfi
|
|||
import com.tangem.features.walletconnect.connections.model.transformers.WcAppInfoTransformer
|
||||
import com.tangem.features.walletconnect.connections.model.transformers.WcAppInfoWalletChangedTransformer
|
||||
import com.tangem.features.walletconnect.connections.model.transformers.WcConnectButtonProgressTransformer
|
||||
import com.tangem.features.walletconnect.connections.model.transformers.WcDAppVerifiedStateConverter
|
||||
import com.tangem.features.walletconnect.connections.routes.WcAppInfoRoutes
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.flow.*
|
||||
|
|
@ -52,11 +61,14 @@ internal class WcPairModel @Inject constructor(
|
|||
),
|
||||
)
|
||||
|
||||
val stackNavigation = StackNavigation<WcAppInfoRoutes>()
|
||||
|
||||
private val selectedUserWalletFlow =
|
||||
MutableStateFlow(getWalletsUseCase.invokeSync().first { it.walletId == params.userWalletId })
|
||||
private var proposalNetwork by Delegates.notNull<WcSessionProposal.ProposalNetwork>()
|
||||
internal var sessionProposal by Delegates.notNull<WcSessionProposal>()
|
||||
private var sessionProposal by Delegates.notNull<WcSessionProposal>()
|
||||
private val additionallyEnabledNetworks = mutableSetOf<Network.RawID>()
|
||||
private val dAppVerifiedStateConverter = WcDAppVerifiedStateConverter(onVerifiedClick = ::showVerifiedAlert)
|
||||
|
||||
val appInfoUiState: StateFlow<WcAppInfoUM>
|
||||
field = MutableStateFlow<WcAppInfoUM>(createLoadingState())
|
||||
|
|
@ -87,16 +99,17 @@ internal class WcPairModel @Inject constructor(
|
|||
proposalNetwork = sessionProposal.proposalNetwork.getValue(selectedUserWalletFlow.value)
|
||||
appInfoUiState.transformerUpdate(
|
||||
WcAppInfoTransformer(
|
||||
dAppSession = pairState.dAppSession,
|
||||
dAppSession = sessionProposal,
|
||||
dAppVerifiedStateConverter = dAppVerifiedStateConverter,
|
||||
onDismiss = ::rejectPairing,
|
||||
onConnect = ::onConnect,
|
||||
onWalletClick = {
|
||||
router.push(
|
||||
stackNavigation.pushNew(
|
||||
WcAppInfoRoutes.SelectWallet(selectedUserWalletFlow.value.walletId),
|
||||
)
|
||||
},
|
||||
onNetworksClick = {
|
||||
router.push(
|
||||
stackNavigation.pushNew(
|
||||
WcAppInfoRoutes.SelectNetworks(
|
||||
missingRequiredNetworks = proposalNetwork.missingRequired,
|
||||
requiredNetworks = proposalNetwork.required,
|
||||
|
|
@ -120,7 +133,15 @@ internal class WcPairModel @Inject constructor(
|
|||
wcPairUseCase.reject()
|
||||
}
|
||||
|
||||
private fun onConnect() {
|
||||
private fun onConnect(securityStatus: CheckDAppResult) {
|
||||
when (securityStatus) {
|
||||
CheckDAppResult.SAFE -> connect()
|
||||
CheckDAppResult.UNSAFE -> showSecurityRiskAlert()
|
||||
CheckDAppResult.FAILED_TO_VERIFY -> showUnknownDomainAlert()
|
||||
}
|
||||
}
|
||||
|
||||
private fun connect() {
|
||||
val enabledAvailableNetworks =
|
||||
proposalNetwork.available.filter { network -> network.id.rawId in additionallyEnabledNetworks }
|
||||
wcPairUseCase.approve(
|
||||
|
|
@ -131,6 +152,79 @@ internal class WcPairModel @Inject constructor(
|
|||
)
|
||||
}
|
||||
|
||||
private fun connectFromAlert() {
|
||||
stackNavigation.pop()
|
||||
connect()
|
||||
}
|
||||
|
||||
private fun showUnknownDomainAlert() {
|
||||
val message = messageBottomSheetUM {
|
||||
infoBlock {
|
||||
icon(R.drawable.img_knight_shield_32) {
|
||||
type = MessageBottomSheetUMV2.Icon.Type.Attention
|
||||
backgroundType = MessageBottomSheetUMV2.Icon.BackgroundType.SameAsTint
|
||||
}
|
||||
title = resourceReference(R.string.security_alert_title)
|
||||
body = resourceReference(R.string.wc_alert_domain_issues_description)
|
||||
chip(resourceReference(R.string.wc_alert_audit_unknown_domain)) {
|
||||
type = MessageBottomSheetUMV2.Chip.Type.Unspecified
|
||||
}
|
||||
}
|
||||
primaryButton {
|
||||
text = resourceReference(R.string.common_cancel)
|
||||
onClick { closeBs() }
|
||||
}
|
||||
secondaryButton {
|
||||
text = resourceReference(R.string.wc_alert_connect_anyway)
|
||||
onClick { connectFromAlert() }
|
||||
}
|
||||
}
|
||||
stackNavigation.pushNew(WcAppInfoRoutes.Alert(elements = message.elements))
|
||||
}
|
||||
|
||||
private fun showSecurityRiskAlert() {
|
||||
val message = messageBottomSheetUM {
|
||||
infoBlock {
|
||||
icon(R.drawable.img_knight_shield_32) {
|
||||
type = MessageBottomSheetUMV2.Icon.Type.Warning
|
||||
backgroundType = MessageBottomSheetUMV2.Icon.BackgroundType.SameAsTint
|
||||
}
|
||||
title = resourceReference(R.string.security_alert_title)
|
||||
body = resourceReference(R.string.wc_alert_domain_issues_description)
|
||||
chip(resourceReference(R.string.wc_alert_audit_unknown_domain)) {
|
||||
type = MessageBottomSheetUMV2.Chip.Type.Warning
|
||||
}
|
||||
}
|
||||
primaryButton {
|
||||
text = resourceReference(R.string.common_cancel)
|
||||
onClick { closeBs() }
|
||||
}
|
||||
secondaryButton {
|
||||
text = resourceReference(R.string.wc_alert_connect_anyway)
|
||||
onClick { connectFromAlert() }
|
||||
}
|
||||
}
|
||||
stackNavigation.pushNew(WcAppInfoRoutes.Alert(elements = message.elements))
|
||||
}
|
||||
|
||||
private fun showVerifiedAlert(appName: String) {
|
||||
val message = messageBottomSheetUM {
|
||||
infoBlock {
|
||||
icon(R.drawable.img_approvale2_20) {
|
||||
type = MessageBottomSheetUMV2.Icon.Type.Accent
|
||||
backgroundType = MessageBottomSheetUMV2.Icon.BackgroundType.Unspecified
|
||||
}
|
||||
title = resourceReference(R.string.wc_alert_verified_domain_title)
|
||||
body = resourceReference(R.string.wc_alert_verified_domain_description, wrappedList(appName))
|
||||
}
|
||||
secondaryButton {
|
||||
text = resourceReference(R.string.common_done)
|
||||
onClick { closeBs() }
|
||||
}
|
||||
}
|
||||
stackNavigation.pushNew(WcAppInfoRoutes.Alert(elements = message.elements))
|
||||
}
|
||||
|
||||
override fun onWalletSelected(userWalletId: UserWalletId) {
|
||||
val selectedUserWallet = sessionProposal.proposalNetwork.keys.first { it.walletId == userWalletId }
|
||||
proposalNetwork = sessionProposal.proposalNetwork.getValue(selectedUserWallet)
|
||||
|
|
@ -147,7 +241,7 @@ internal class WcPairModel @Inject constructor(
|
|||
private fun createLoadingState(): WcAppInfoUM.Loading {
|
||||
return WcAppInfoUM.Loading(
|
||||
onDismiss = ::rejectPairing,
|
||||
connectButtonConfig = WcPrimaryButtonConfig(showProgress = false, enabled = false, onClick = ::onConnect),
|
||||
connectButtonConfig = WcPrimaryButtonConfig(showProgress = false, enabled = false, onClick = {}),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -3,14 +3,17 @@ package com.tangem.features.walletconnect.connections.model.transformers
|
|||
import com.domain.blockaid.models.dapp.CheckDAppResult
|
||||
import com.tangem.domain.walletconnect.model.WcSessionProposal
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.features.walletconnect.connections.entity.*
|
||||
import com.tangem.features.walletconnect.connections.entity.WcAppInfoSecurityNotification
|
||||
import com.tangem.features.walletconnect.connections.entity.WcAppInfoUM
|
||||
import com.tangem.features.walletconnect.connections.entity.WcPrimaryButtonConfig
|
||||
import com.tangem.utils.transformer.Transformer
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
internal class WcAppInfoTransformer(
|
||||
private val dAppSession: WcSessionProposal,
|
||||
private val dAppVerifiedStateConverter: WcDAppVerifiedStateConverter,
|
||||
private val onDismiss: () -> Unit,
|
||||
private val onConnect: () -> Unit,
|
||||
private val onConnect: (securityStatus: CheckDAppResult) -> Unit,
|
||||
private val onWalletClick: () -> Unit,
|
||||
private val onNetworksClick: () -> Unit,
|
||||
private val userWallet: UserWallet,
|
||||
|
|
@ -21,7 +24,9 @@ internal class WcAppInfoTransformer(
|
|||
return WcAppInfoUM.Content(
|
||||
appName = dAppSession.dAppMetaData.name,
|
||||
appIcon = dAppSession.dAppMetaData.icons.firstOrNull().orEmpty(),
|
||||
isVerified = dAppSession.securityStatus == CheckDAppResult.SAFE,
|
||||
verifiedDAppState = dAppVerifiedStateConverter.convert(
|
||||
dAppSession.securityStatus to dAppSession.dAppMetaData.name,
|
||||
),
|
||||
appSubtitle = dAppSession.dAppMetaData.description,
|
||||
notification = createNotification(dAppSession.securityStatus),
|
||||
walletName = userWallet.name,
|
||||
|
|
@ -31,7 +36,7 @@ internal class WcAppInfoTransformer(
|
|||
connectButtonConfig = WcPrimaryButtonConfig(
|
||||
showProgress = false,
|
||||
enabled = proposalNetwork.missingRequired.isEmpty(),
|
||||
onClick = onConnect,
|
||||
onClick = { onConnect(dAppSession.securityStatus) },
|
||||
),
|
||||
onDismiss = onDismiss,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
package com.tangem.features.walletconnect.connections.model.transformers
|
||||
|
||||
import com.domain.blockaid.models.dapp.CheckDAppResult
|
||||
import com.tangem.features.walletconnect.connections.entity.VerifiedDAppState
|
||||
import com.tangem.utils.converter.Converter
|
||||
|
||||
internal class WcDAppVerifiedStateConverter(
|
||||
private val onVerifiedClick: (String) -> Unit,
|
||||
) : Converter<Pair<CheckDAppResult, String>, VerifiedDAppState> {
|
||||
|
||||
override fun convert(value: Pair<CheckDAppResult, String>): VerifiedDAppState {
|
||||
val (checkDAppResult, appName) = value
|
||||
return if (checkDAppResult == CheckDAppResult.SAFE) {
|
||||
VerifiedDAppState.Verified(
|
||||
onVerifiedClick = { onVerifiedClick.invoke(appName) },
|
||||
)
|
||||
} else {
|
||||
VerifiedDAppState.Unknown
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,9 +3,10 @@ package com.tangem.features.walletconnect.connections.routes
|
|||
import androidx.compose.runtime.Immutable
|
||||
import com.tangem.core.decompose.navigation.Route
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
|
||||
import com.tangem.core.ui.components.bottomsheets.message.MessageBottomSheetUMV2
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.features.walletconnect.connections.components.AlertsComponent
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
|
|
@ -27,5 +28,5 @@ internal sealed class WcAppInfoRoutes : TangemBottomSheetConfigContent, Route {
|
|||
) : WcAppInfoRoutes()
|
||||
|
||||
@Serializable
|
||||
data class Alert(val alertType: AlertsComponent.AlertType) : WcAppInfoRoutes()
|
||||
data class Alert(val elements: ImmutableList<MessageBottomSheetUMV2.Element>) : WcAppInfoRoutes()
|
||||
}
|
||||
|
|
@ -14,7 +14,10 @@ import androidx.compose.ui.res.painterResource
|
|||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import coil.compose.AsyncImage
|
||||
import com.tangem.core.ui.extensions.clickableSingle
|
||||
import com.tangem.core.ui.extensions.conditional
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.features.walletconnect.connections.entity.VerifiedDAppState
|
||||
import com.tangem.features.walletconnect.impl.R
|
||||
|
||||
@Composable
|
||||
|
|
@ -22,11 +25,18 @@ internal fun WcAppInfoItem(
|
|||
iconUrl: String,
|
||||
title: String,
|
||||
subtitle: String,
|
||||
isVerified: Boolean,
|
||||
verifiedDAppState: VerifiedDAppState,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Row(
|
||||
modifier = modifier.padding(TangemTheme.dimens.spacing12),
|
||||
modifier = modifier
|
||||
.conditional(
|
||||
condition = verifiedDAppState is VerifiedDAppState.Verified,
|
||||
modifier = {
|
||||
clickableSingle { (verifiedDAppState as VerifiedDAppState.Verified).onVerifiedClick() }
|
||||
},
|
||||
)
|
||||
.padding(TangemTheme.dimens.spacing12),
|
||||
horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing16),
|
||||
) {
|
||||
AsyncImage(
|
||||
|
|
@ -50,7 +60,7 @@ internal fun WcAppInfoItem(
|
|||
color = TangemTheme.colors.text.primary1,
|
||||
style = TangemTheme.typography.h3,
|
||||
)
|
||||
if (isVerified) {
|
||||
if (verifiedDAppState is VerifiedDAppState.Verified) {
|
||||
Icon(
|
||||
modifier = Modifier.size(20.dp),
|
||||
painter = painterResource(R.drawable.img_approvale2_20),
|
||||
|
|
@ -81,7 +91,9 @@ internal fun WcNetworkInfoItem(@DrawableRes icon: Int, name: String, symbol: Str
|
|||
tint = Color.Unspecified,
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier.padding(start = 12.dp).weight(1f, fill = false),
|
||||
modifier = Modifier
|
||||
.padding(start = 12.dp)
|
||||
.weight(1f, fill = false),
|
||||
text = name,
|
||||
style = TangemTheme.typography.body1,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
|
|
|
|||
|
|
@ -127,11 +127,12 @@ private fun WcAppInfoModalBottomSheetContent(state: WcAppInfoUM.Content, modifie
|
|||
private fun WcAppInfoFirstBlock(state: WcAppInfoUM.Content, modifier: Modifier = Modifier) {
|
||||
var connectionRequestExpanded by remember { mutableStateOf(false) }
|
||||
Column(modifier = modifier) {
|
||||
val verifiedDAppState = state.verifiedDAppState
|
||||
WcAppInfoItem(
|
||||
iconUrl = state.appIcon,
|
||||
title = state.appName,
|
||||
subtitle = state.appSubtitle,
|
||||
isVerified = state.isVerified,
|
||||
verifiedDAppState = state.verifiedDAppState,
|
||||
)
|
||||
HorizontalDivider(thickness = 1.dp, color = TangemTheme.colors.stroke.primary)
|
||||
ConnectionRequestBlock(
|
||||
|
|
@ -594,7 +595,7 @@ private class WcAppInfoStateProvider : CollectionPreviewParameterProvider<WcAppI
|
|||
WcAppInfoUM.Content(
|
||||
appName = "React App",
|
||||
appIcon = "",
|
||||
isVerified = true,
|
||||
verifiedDAppState = VerifiedDAppState.Verified {},
|
||||
appSubtitle = "react-app.walletconnect.com",
|
||||
notification = WcAppInfoSecurityNotification.SecurityRisk,
|
||||
walletName = "Tangem 2.0",
|
||||
|
|
@ -640,7 +641,7 @@ private class WcAppInfoStateProvider : CollectionPreviewParameterProvider<WcAppI
|
|||
WcAppInfoUM.Content(
|
||||
appName = "React App",
|
||||
appIcon = "",
|
||||
isVerified = false,
|
||||
verifiedDAppState = VerifiedDAppState.Unknown,
|
||||
appSubtitle = "react-app.walletconnect.com",
|
||||
notification = WcAppInfoSecurityNotification.UnknownDomain,
|
||||
walletName = "Tangem 2.0",
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import com.tangem.core.ui.extensions.resourceReference
|
|||
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.features.walletconnect.connections.entity.VerifiedDAppState
|
||||
import com.tangem.features.walletconnect.connections.entity.WcConnectedAppInfoUM
|
||||
import com.tangem.features.walletconnect.connections.entity.WcNetworkInfoItem
|
||||
import com.tangem.features.walletconnect.connections.entity.WcPrimaryButtonConfig
|
||||
|
|
@ -97,7 +98,7 @@ private fun AppInfoFirstBlock(state: WcConnectedAppInfoUM, modifier: Modifier =
|
|||
iconUrl = state.appIcon,
|
||||
title = state.appName,
|
||||
subtitle = state.appSubtitle,
|
||||
isVerified = state.isVerified,
|
||||
verifiedDAppState = state.verifiedDAppState,
|
||||
)
|
||||
HorizontalDivider(thickness = 1.dp, color = TangemTheme.colors.stroke.primary)
|
||||
Row(
|
||||
|
|
@ -159,6 +160,7 @@ private fun WcConnectedAppInfoBS_Preview() {
|
|||
state = WcConnectedAppInfoUM(
|
||||
appName = "React App",
|
||||
appIcon = "",
|
||||
verifiedDAppState = VerifiedDAppState.Verified {},
|
||||
isVerified = true,
|
||||
appSubtitle = "react-app.walletconnect.com",
|
||||
walletName = "Tangem 2.0",
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import androidx.compose.runtime.Immutable
|
|||
|
||||
@Immutable
|
||||
internal data class WcTransactionActionsUM(
|
||||
val onShowVerifiedAlert: (String) -> Unit,
|
||||
val onDismiss: () -> Unit,
|
||||
val onSign: () -> Unit,
|
||||
val onCopy: () -> Unit,
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
package com.tangem.features.walletconnect.transaction.entity.common
|
||||
|
||||
import com.tangem.features.walletconnect.connections.entity.VerifiedDAppState
|
||||
|
||||
internal data class WcTransactionAppInfoContentUM(
|
||||
val appName: String,
|
||||
val appIcon: String,
|
||||
val isVerified: Boolean,
|
||||
val verifiedState: VerifiedDAppState,
|
||||
val appSubtitle: String,
|
||||
)
|
||||
|
|
@ -5,7 +5,16 @@ import com.tangem.core.decompose.di.ModelScoped
|
|||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
import com.tangem.core.decompose.navigation.Router
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.clipboard.ClipboardManager
|
||||
import com.tangem.core.ui.components.bottomsheets.message.MessageBottomSheetUMV2
|
||||
import com.tangem.core.ui.components.bottomsheets.message.icon
|
||||
import com.tangem.core.ui.components.bottomsheets.message.infoBlock
|
||||
import com.tangem.core.ui.components.bottomsheets.message.messageBottomSheetUM
|
||||
import com.tangem.core.ui.components.bottomsheets.message.onClick
|
||||
import com.tangem.core.ui.components.bottomsheets.message.secondaryButton
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.wrappedList
|
||||
import com.tangem.domain.walletconnect.WcRequestUseCaseFactory
|
||||
import com.tangem.domain.walletconnect.usecase.method.WcSignState
|
||||
import com.tangem.domain.walletconnect.usecase.method.WcSignStep
|
||||
|
|
@ -46,6 +55,7 @@ internal class WcSignTransactionModel @Inject constructor(
|
|||
val signTransactionUM = useCase.toUM(
|
||||
signState = signState,
|
||||
actions = WcTransactionActionsUM(
|
||||
onShowVerifiedAlert = ::showVerifiedAlert,
|
||||
onDismiss = { cancel(useCase) },
|
||||
onSign = useCase::sign,
|
||||
onCopy = { copyData(useCase.rawSdkRequest.request.params) },
|
||||
|
|
@ -61,6 +71,25 @@ internal class WcSignTransactionModel @Inject constructor(
|
|||
_uiState.value?.transaction?.onDismiss?.invoke() ?: router.pop()
|
||||
}
|
||||
|
||||
private fun showVerifiedAlert(appName: String) {
|
||||
val message = messageBottomSheetUM {
|
||||
infoBlock {
|
||||
icon(R.drawable.img_approvale2_20) {
|
||||
type = MessageBottomSheetUMV2.Icon.Type.Accent
|
||||
backgroundType = MessageBottomSheetUMV2.Icon.BackgroundType.Unspecified
|
||||
}
|
||||
title = resourceReference(R.string.wc_alert_verified_domain_title)
|
||||
body = resourceReference(R.string.wc_alert_verified_domain_description, wrappedList(appName))
|
||||
}
|
||||
secondaryButton {
|
||||
text = resourceReference(R.string.common_done)
|
||||
onClick { closeBs() }
|
||||
}
|
||||
}
|
||||
// TODO(wc): Nastya [REDACTED_JIRA]
|
||||
// router.push(WcAppInfoRoutes.Alert(elements = message.elements))
|
||||
}
|
||||
|
||||
private fun signingIsDone(signState: WcSignState<*>): Boolean {
|
||||
(signState.domainStep as? WcSignStep.Result)?.result?.let {
|
||||
router.pop()
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import com.tangem.core.ui.components.divider.DividerWithPadding
|
|||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.features.walletconnect.connections.entity.VerifiedDAppState
|
||||
import com.tangem.features.walletconnect.connections.ui.WcAppInfoItem
|
||||
import com.tangem.features.walletconnect.impl.R
|
||||
import com.tangem.features.walletconnect.transaction.entity.approve.WcApproveTransactionItemUM
|
||||
|
|
@ -50,7 +51,7 @@ internal fun WcApproveTransactionModalBottomSheetContent(
|
|||
iconUrl = state.appInfo.appIcon,
|
||||
title = state.appInfo.appName,
|
||||
subtitle = state.appInfo.appSubtitle,
|
||||
isVerified = state.appInfo.isVerified,
|
||||
verifiedDAppState = state.appInfo.verifiedState,
|
||||
)
|
||||
DividerWithPadding(start = 0.dp, end = 0.dp)
|
||||
WcTransactionRequestItem(
|
||||
|
|
@ -120,7 +121,7 @@ private class WcApproveTransactionStateProvider : CollectionPreviewParameterProv
|
|||
appInfo = WcTransactionAppInfoContentUM(
|
||||
appName = "React App",
|
||||
appIcon = "",
|
||||
isVerified = true,
|
||||
verifiedState = VerifiedDAppState.Verified {},
|
||||
appSubtitle = "react-app.walletconnect.com",
|
||||
),
|
||||
spendAllowance = WcSpendAllowanceUM(amountText = "Unlimited USDT", tokenImageUrl = ""),
|
||||
|
|
|
|||
|
|
@ -4,7 +4,9 @@ import android.content.res.Configuration
|
|||
import androidx.compose.animation.animateContentSize
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
|
|
@ -21,11 +23,15 @@ import com.tangem.core.ui.components.divider.DividerWithPadding
|
|||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.features.walletconnect.connections.entity.VerifiedDAppState
|
||||
import com.tangem.features.walletconnect.connections.ui.WcAppInfoItem
|
||||
import com.tangem.features.walletconnect.impl.R
|
||||
import com.tangem.features.walletconnect.transaction.entity.chain.WcAddEthereumChainItemUM
|
||||
import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionAppInfoContentUM
|
||||
import com.tangem.features.walletconnect.transaction.ui.common.*
|
||||
import com.tangem.features.walletconnect.transaction.ui.common.WcSmallTitleItem
|
||||
import com.tangem.features.walletconnect.transaction.ui.common.WcTransactionRequestButtons
|
||||
import com.tangem.features.walletconnect.transaction.ui.common.WcTransactionRequestItem
|
||||
import com.tangem.features.walletconnect.transaction.ui.common.WcWalletItem
|
||||
|
||||
@Composable
|
||||
internal fun WcAddEthereumChainModalBottomSheetContent(
|
||||
|
|
@ -48,7 +54,7 @@ internal fun WcAddEthereumChainModalBottomSheetContent(
|
|||
iconUrl = state.appInfo.appIcon,
|
||||
title = state.appInfo.appName,
|
||||
subtitle = state.appInfo.appSubtitle,
|
||||
isVerified = state.appInfo.isVerified,
|
||||
verifiedDAppState = state.appInfo.verifiedState,
|
||||
)
|
||||
DividerWithPadding(start = 0.dp, end = 0.dp)
|
||||
WcTransactionRequestItem(
|
||||
|
|
@ -130,7 +136,7 @@ private class WcAddEthereumChainStateProvider : CollectionPreviewParameterProvid
|
|||
appInfo = WcTransactionAppInfoContentUM(
|
||||
appName = "React App",
|
||||
appIcon = "",
|
||||
isVerified = true,
|
||||
verifiedState = VerifiedDAppState.Verified {},
|
||||
appSubtitle = "react-app.walletconnect.com",
|
||||
),
|
||||
walletName = "Tangem 2.0",
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import com.tangem.core.ui.components.divider.DividerWithPadding
|
|||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.features.walletconnect.connections.entity.VerifiedDAppState
|
||||
import com.tangem.features.walletconnect.connections.ui.WcAppInfoItem
|
||||
import com.tangem.features.walletconnect.impl.R
|
||||
import com.tangem.features.walletconnect.transaction.entity.common.WcNetworkInfoUM
|
||||
|
|
@ -51,7 +52,7 @@ internal fun WcSignTransactionModalBottomSheetContent(
|
|||
iconUrl = state.appInfo.appIcon,
|
||||
title = state.appInfo.appName,
|
||||
subtitle = state.appInfo.appSubtitle,
|
||||
isVerified = state.appInfo.isVerified,
|
||||
verifiedDAppState = state.appInfo.verifiedState,
|
||||
)
|
||||
DividerWithPadding(start = 0.dp, end = 0.dp)
|
||||
WcTransactionRequestItem(
|
||||
|
|
@ -146,7 +147,7 @@ private class WcSignTransactionStateProvider : CollectionPreviewParameterProvide
|
|||
appInfo = WcTransactionAppInfoContentUM(
|
||||
appName = "React App",
|
||||
appIcon = "",
|
||||
isVerified = true,
|
||||
verifiedState = VerifiedDAppState.Verified {},
|
||||
appSubtitle = "react-app.walletconnect.com",
|
||||
),
|
||||
walletName = "Tangem 2.0",
|
||||
|
|
@ -158,7 +159,7 @@ private class WcSignTransactionStateProvider : CollectionPreviewParameterProvide
|
|||
appInfo = WcTransactionAppInfoContentUM(
|
||||
appName = "React App",
|
||||
appIcon = "",
|
||||
isVerified = true,
|
||||
verifiedState = VerifiedDAppState.Verified {},
|
||||
appSubtitle = "react-app.walletconnect.com",
|
||||
),
|
||||
walletName = "Tangem 2.0",
|
||||
|
|
|
|||
|
|
@ -1,11 +1,16 @@
|
|||
package com.tangem.features.walletconnect.transaction.utils
|
||||
|
||||
import com.domain.blockaid.models.dapp.CheckDAppResult
|
||||
import com.tangem.core.ui.extensions.getActiveIconRes
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.domain.walletconnect.model.WcEthMethod
|
||||
import com.tangem.domain.walletconnect.model.WcSolanaMethod
|
||||
import com.tangem.domain.walletconnect.model.sdkcopy.WcSdkSessionRequest
|
||||
import com.tangem.domain.walletconnect.usecase.method.*
|
||||
import com.tangem.domain.walletconnect.usecase.method.WcMessageSignUseCase
|
||||
import com.tangem.domain.walletconnect.usecase.method.WcSignState
|
||||
import com.tangem.domain.walletconnect.usecase.method.WcSignStep
|
||||
import com.tangem.domain.walletconnect.usecase.method.WcSignUseCase
|
||||
import com.tangem.features.walletconnect.connections.model.transformers.WcDAppVerifiedStateConverter
|
||||
import com.tangem.features.walletconnect.impl.R
|
||||
import com.tangem.features.walletconnect.transaction.entity.chain.WcAddEthereumChainItemUM
|
||||
import com.tangem.features.walletconnect.transaction.entity.chain.WcAddEthereumChainUM
|
||||
|
|
@ -148,7 +153,9 @@ private fun WcMethodContext.basicTransactionRequestInfoBlocks() = persistentList
|
|||
private fun WcMethodContext.appInfo() = WcTransactionAppInfoContentUM(
|
||||
appName = session.sdkModel.appMetaData.name,
|
||||
appIcon = session.sdkModel.appMetaData.url,
|
||||
isVerified = session.securityStatus == com.domain.blockaid.models.dapp.CheckDAppResult.SAFE,
|
||||
verifiedState = WcDAppVerifiedStateConverter(onVerifiedClick = actions.onShowVerifiedAlert).convert(
|
||||
session.securityStatus to session.sdkModel.appMetaData.name,
|
||||
),
|
||||
appSubtitle = session.sdkModel.appMetaData.description,
|
||||
)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue