Updated on 2026-08-14

This commit is contained in:
Tangem 2025-04-29 12:48:02 +04:00
parent e9512b1afe
commit ecd02950fb
15 changed files with 796 additions and 0 deletions

View file

@ -1299,6 +1299,7 @@
<string name="wc_connection_reqeust_will_not">Will not be able to</string>
<string name="wc_connection_reqeust_would_like">Would like to</string>
<string name="wc_connection_request">Connection request</string>
<string name="wc_transaction_request">Transaction request</string>
<string name="wc_connections">Connections</string>
<string name="wc_disconnect_all">Disconnect all</string>
<string name="wc_disconnect_all_alert_desc">Text about discnected all dApps</string>
@ -1311,6 +1312,12 @@
<string name="wc_notification_security_risk_subtitle">This domain is flagged as unsafe by multiple security providers. Leave immediately to protect your assets</string>
<string name="wc_notification_security_risk_title">Known security risk</string>
<string name="wc_wallet_connect">Wallet connect</string>
<string name="wc_request_from">Request from</string>
<string name="wc_sign_message_button_text">Sign</string>
<string name="wc_copy_data_button_text">Copy data</string>
<string name="wc_transaction_request_title">Transaction request</string>
<string name="wc_signature_type">Signature Type</string>
<string name="wc_contents">Contents</string>
<string name="welcome_interrupted_backup_alert_discard">Discard</string>
<string name="welcome_interrupted_backup_alert_message">You have an interrupted backup. Do you want to resume?</string>
<string name="welcome_interrupted_backup_alert_resume">Yes, resume</string>

View file

@ -0,0 +1,19 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M8,8.028C7.586,8.028 7.25,8.363 7.25,8.778C7.25,9.192 7.586,9.528 8,9.528L16,9.528C16.414,9.528 16.75,9.192 16.75,8.778C16.75,8.363 16.414,8.028 16,8.028L8,8.028Z"
android:fillColor="#000000"/>
<path
android:pathData="M8,11.25C7.586,11.25 7.25,11.586 7.25,12C7.25,12.415 7.586,12.75 8,12.75L16,12.75C16.414,12.75 16.75,12.415 16.75,12C16.75,11.586 16.414,11.25 16,11.25L8,11.25Z"
android:fillColor="#000000"/>
<path
android:pathData="M8,14.473C7.586,14.473 7.25,14.809 7.25,15.223C7.25,15.637 7.586,15.973 8,15.973H12.171C12.585,15.973 12.921,15.637 12.921,15.223C12.921,14.809 12.585,14.473 12.171,14.473H8Z"
android:fillColor="#000000"/>
<path
android:pathData="M19.652,4.11C19.05,3.508 18.292,3.25 17.392,3.129C16.526,3.013 15.425,3.013 14.06,3.013L9.945,3.013C8.578,3.013 7.475,3.013 6.608,3.129C5.708,3.25 4.95,3.509 4.348,4.111C3.746,4.713 3.488,5.471 3.367,6.371C3.25,7.238 3.25,8.34 3.25,9.708L3.25,14.293C3.25,15.66 3.25,16.763 3.367,17.63C3.488,18.53 3.746,19.288 4.348,19.89C4.95,20.492 5.708,20.75 6.608,20.871C7.475,20.988 8.578,20.988 9.945,20.988L14.055,20.987C15.422,20.987 16.525,20.987 17.392,20.871C18.292,20.75 19.05,20.491 19.652,19.889C20.254,19.287 20.513,18.529 20.633,17.629C20.75,16.762 20.75,15.66 20.75,14.292L20.75,9.707C20.75,8.34 20.75,7.237 20.633,6.37C20.513,5.47 20.254,4.712 19.652,4.11ZM14,4.513C15.436,4.513 16.437,4.514 17.192,4.616C17.926,4.714 18.314,4.894 18.591,5.171C18.868,5.448 19.048,5.836 19.147,6.57C19.248,7.326 19.25,8.327 19.25,9.762L19.25,14.237C19.25,15.673 19.248,16.674 19.147,17.429C19.048,18.163 18.868,18.552 18.591,18.828C18.314,19.105 17.926,19.285 17.192,19.384C16.437,19.486 15.435,19.487 14,19.487L10,19.488C8.565,19.488 7.563,19.486 6.808,19.385C6.074,19.286 5.686,19.106 5.409,18.829C5.132,18.552 4.952,18.164 4.853,17.43C4.752,16.674 4.75,15.673 4.75,14.238L4.75,9.763C4.75,8.327 4.752,7.326 4.853,6.571C4.952,5.837 5.132,5.448 5.409,5.172C5.686,4.895 6.074,4.714 6.808,4.616C7.563,4.514 8.565,4.513 10,4.513L14,4.513Z"
android:fillColor="#000000"
android:fillType="evenOdd"/>
</vector>

View file

@ -5,6 +5,7 @@ import com.tangem.core.decompose.model.Model
import com.tangem.features.walletconnect.connections.model.WcAppInfoModel
import com.tangem.features.walletconnect.connections.model.WcConnectedAppInfoModel
import com.tangem.features.walletconnect.connections.model.WcConnectionsModel
import com.tangem.features.walletconnect.transaction.model.WcSignTransactionModel
import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
@ -29,4 +30,9 @@ internal interface WalletConnectModelModule {
@IntoMap
@ClassKey(WcConnectedAppInfoModel::class)
fun bindWcConnectedAppInfoModel(model: WcConnectedAppInfoModel): Model
@Binds
@IntoMap
@ClassKey(WcSignTransactionModel::class)
fun bindWcSignTransactionModel(model: WcSignTransactionModel): Model
}

View file

@ -0,0 +1,37 @@
package com.tangem.features.walletconnect.transaction.components
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.core.decompose.model.getOrCreateModel
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
import com.tangem.core.ui.decompose.ComposableContentComponent
import com.tangem.domain.walletconnect.model.sdkcopy.WcSdkSessionRequest
import com.tangem.features.walletconnect.transaction.model.WcSignTransactionModel
import com.tangem.features.walletconnect.transaction.ui.sign.WcSignTransactionModalBottomSheet
internal class WcSignTransactionComponent(
appComponentContext: AppComponentContext,
params: Params,
) : AppComponentContext by appComponentContext, ComposableContentComponent {
private val model: WcSignTransactionModel = getOrCreateModel(params)
@Composable
override fun Content(modifier: Modifier) {
val content by model.uiState.collectAsStateWithLifecycle()
content?.let {
WcSignTransactionModalBottomSheet(
config = TangemBottomSheetConfig(
isShown = true,
onDismissRequest = it.actions.onDismiss,
content = it,
),
)
}
}
data class Params(val rawRequest: WcSdkSessionRequest)
}

View file

@ -0,0 +1,60 @@
package com.tangem.features.walletconnect.transaction.entity
import androidx.annotation.DrawableRes
import androidx.compose.runtime.Immutable
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
import com.tangem.core.ui.extensions.TextReference
import kotlinx.collections.immutable.ImmutableList
@Immutable
internal data class WcSignTransactionUM(
@DrawableRes val startIconRes: Int,
@DrawableRes val endIconRes: Int,
@DrawableRes val transactionIconRes: Int,
val actions: WcTransactionActionsUM,
val state: State = State.TRANSACTION,
val transaction: WcTransactionUM,
val transactionRequestInfo: WcTransactionRequestInfoUM,
) : TangemBottomSheetConfigContent {
enum class State {
TRANSACTION, TRANSACTION_REQUEST_INFO
}
}
@Immutable
internal data class WcTransactionUM(
val appName: String,
val appIcon: String,
val isVerified: Boolean,
val appSubtitle: String,
val walletName: String,
val networkInfo: WcNetworkInfoUM,
val isLoading: Boolean = false,
)
@Immutable
internal data class WcTransactionRequestInfoUM(
val info: ImmutableList<WcTransactionRequestInfoItemUM>,
)
@Immutable
internal data class WcTransactionRequestInfoItemUM(
val title: TextReference,
val description: String,
)
@Immutable
internal data class WcTransactionActionsUM(
val transactionRequestOnClick: () -> Unit,
val onDismiss: () -> Unit,
val onSign: () -> Unit,
val onBack: () -> Unit,
val onCopy: () -> Unit,
)
@Immutable
internal data class WcNetworkInfoUM(
val name: String,
@DrawableRes val iconRes: Int,
)

View file

@ -0,0 +1,86 @@
package com.tangem.features.walletconnect.transaction.model
import androidx.compose.runtime.Stable
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.clipboard.ClipboardManager
import com.tangem.domain.walletconnect.WcRequestUseCaseFactory
import com.tangem.domain.walletconnect.usecase.sign.WcSignState
import com.tangem.domain.walletconnect.usecase.sign.WcSignStep
import com.tangem.domain.walletconnect.usecase.sign.WcSignUseCase
import com.tangem.features.walletconnect.transaction.components.WcSignTransactionComponent
import com.tangem.features.walletconnect.transaction.entity.WcSignTransactionUM
import com.tangem.features.walletconnect.transaction.entity.WcTransactionActionsUM
import com.tangem.features.walletconnect.transaction.utils.toUM
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import javax.inject.Inject
@Stable
@ModelScoped
internal class WcSignTransactionModel @Inject constructor(
paramsContainer: ParamsContainer,
override val dispatchers: CoroutineDispatcherProvider,
private val router: Router,
private val clipboardManager: ClipboardManager,
private val useCaseFactory: WcRequestUseCaseFactory,
) : Model() {
private val _uiState = MutableStateFlow<WcSignTransactionUM?>(null)
val uiState: StateFlow<WcSignTransactionUM?> = _uiState
private val params = paramsContainer.require<WcSignTransactionComponent.Params>()
init {
modelScope.launch {
val useCase: WcSignUseCase.SimpleRun<*> = useCaseFactory.createUseCase(params.rawRequest)
useCase.invoke()
.onEach { signState ->
if (signingIsDone(signState)) return@onEach
val signTransactionUM = (useCase as? WcSignUseCase)?.toUM(
signState = signState,
actions = WcTransactionActionsUM(
onDismiss = { cancel(useCase) },
onBack = ::showTransactionState,
onSign = useCase::sign,
onCopy = { copyData(useCase.rawSdkRequest.request.params) },
transactionRequestOnClick = ::showTransactionRequestState,
),
)
_uiState.emit(signTransactionUM)
}
.launchIn(this)
}
}
private fun signingIsDone(signState: WcSignState<*>): Boolean {
(signState.domainStep as? WcSignStep.Result)?.result?.let {
router.pop()
return true
}
return false
}
private fun cancel(useCase: WcSignUseCase) {
useCase.cancel()
router.pop()
}
private fun copyData(text: String) {
clipboardManager.setText(text = text, isSensitive = true)
}
private fun showTransactionRequestState() {
_uiState.value = _uiState.value?.copy(state = WcSignTransactionUM.State.TRANSACTION_REQUEST_INFO)
}
private fun showTransactionState() {
_uiState.value = _uiState.value?.copy(state = WcSignTransactionUM.State.TRANSACTION)
}
}

View file

@ -0,0 +1,64 @@
package com.tangem.features.walletconnect.transaction.ui.common
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.unit.dp
import com.tangem.core.ui.components.SecondaryButtonIconEnd
import com.tangem.core.ui.extensions.resolveReference
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.TangemTheme
import com.tangem.features.walletconnect.impl.R
import com.tangem.features.walletconnect.transaction.entity.WcSignTransactionUM
@Composable
internal fun TransactionRequestInfoContent(state: WcSignTransactionUM) {
Box(
modifier = Modifier
.fillMaxWidth()
.heightIn(min = 310.dp)
.padding(horizontal = TangemTheme.dimens.spacing16),
) {
Column(
modifier = Modifier
.fillMaxWidth()
.clip(RoundedCornerShape(TangemTheme.dimens.radius16))
.background(TangemTheme.colors.background.action)
.padding(
start = TangemTheme.dimens.spacing16,
end = TangemTheme.dimens.spacing16,
bottom = TangemTheme.dimens.spacing20,
),
) {
state.transactionRequestInfo.info.forEach { item ->
Text(
text = item.title.resolveReference(),
modifier = Modifier.padding(top = TangemTheme.dimens.spacing20),
style = TangemTheme.typography.subtitle2,
color = TangemTheme.colors.text.tertiary,
)
Text(
text = item.description,
modifier = Modifier.padding(top = TangemTheme.dimens.spacing4),
style = TangemTheme.typography.body2,
color = TangemTheme.colors.text.primary1,
)
}
}
SecondaryButtonIconEnd(
modifier = Modifier
.align(Alignment.BottomCenter)
.padding(bottom = TangemTheme.dimens.spacing20)
.fillMaxWidth(),
text = stringResourceSafe(R.string.wc_copy_data_button_text),
onClick = state.actions.onCopy,
iconResId = R.drawable.ic_copy_24,
)
}
}

View file

@ -0,0 +1,60 @@
package com.tangem.features.walletconnect.transaction.ui.common
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.TangemTheme
import com.tangem.features.walletconnect.impl.R
import com.tangem.features.walletconnect.transaction.entity.WcNetworkInfoUM
@Composable
internal fun WcNetworkItem(networkInfo: WcNetworkInfoUM, modifier: Modifier = Modifier) {
Row(
modifier = modifier,
verticalAlignment = Alignment.CenterVertically,
) {
Icon(
modifier = Modifier.size(TangemTheme.dimens.size24),
painter = painterResource(R.drawable.ic_network_new_24),
contentDescription = null,
tint = TangemTheme.colors.icon.accent,
)
Text(
modifier = Modifier
.padding(start = TangemTheme.dimens.spacing4)
.weight(1f),
text = stringResourceSafe(R.string.wc_common_network),
style = TangemTheme.typography.body1,
color = TangemTheme.colors.text.primary1,
)
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.End,
modifier = Modifier.weight(1f),
) {
Text(
text = networkInfo.name,
style = TangemTheme.typography.body1,
color = TangemTheme.colors.text.tertiary,
)
Spacer(modifier = Modifier.width(TangemTheme.dimens.spacing6))
Image(
painter = painterResource(id = networkInfo.iconRes),
contentDescription = null,
contentScale = ContentScale.Crop,
modifier = Modifier
.clip(CircleShape)
.size(TangemTheme.dimens.size20),
)
}
}
}

View file

@ -0,0 +1,22 @@
package com.tangem.features.walletconnect.transaction.ui.common
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.TangemTheme
import com.tangem.features.walletconnect.impl.R
@Composable
fun RequestFromItem(modifier: Modifier = Modifier) {
Text(
modifier = modifier
.fillMaxWidth()
.padding(top = TangemTheme.dimens.spacing12, start = TangemTheme.dimens.spacing12),
text = stringResourceSafe(R.string.wc_request_from),
color = TangemTheme.colors.text.tertiary,
style = TangemTheme.typography.subtitle2,
)
}

View file

@ -0,0 +1,39 @@
package com.tangem.features.walletconnect.transaction.ui.common
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import com.tangem.core.ui.components.PrimaryButtonIconEnd
import com.tangem.core.ui.components.SecondaryButton
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.TangemTheme
import com.tangem.features.walletconnect.impl.R
@Composable
internal fun WcTransactionRequestButtons(
isLoading: Boolean,
onDismiss: () -> Unit,
onSign: () -> Unit,
modifier: Modifier = Modifier,
) {
Row(modifier = modifier, horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing8)) {
SecondaryButton(
modifier = Modifier
.fillMaxWidth()
.weight(1f),
text = stringResourceSafe(R.string.common_cancel),
onClick = onDismiss,
)
PrimaryButtonIconEnd(
modifier = Modifier
.fillMaxWidth()
.weight(1f),
text = stringResourceSafe(R.string.wc_sign_message_button_text),
onClick = onSign,
iconResId = R.drawable.ic_tangem_24,
showProgress = isLoading,
)
}
}

View file

@ -0,0 +1,43 @@
package com.tangem.features.walletconnect.transaction.ui.common
import androidx.annotation.DrawableRes
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.TangemTheme
import com.tangem.features.walletconnect.impl.R
@Composable
internal fun WcTransactionRequestItem(@DrawableRes iconRes: Int, modifier: Modifier = Modifier) {
Row(modifier = modifier, verticalAlignment = Alignment.CenterVertically) {
Icon(
modifier = Modifier.size(TangemTheme.dimens.size24),
painter = painterResource(iconRes),
contentDescription = null,
tint = TangemTheme.colors.icon.accent,
)
Text(
modifier = Modifier
.padding(start = TangemTheme.dimens.spacing4)
.weight(1f),
text = stringResourceSafe(R.string.wc_transaction_request),
style = TangemTheme.typography.body1,
color = TangemTheme.colors.text.primary1,
)
Icon(
modifier = Modifier
.padding(start = TangemTheme.dimens.spacing12)
.size(width = TangemTheme.dimens.size18, height = TangemTheme.dimens.size24),
painter = painterResource(R.drawable.ic_chevron_right_24),
contentDescription = null,
tint = TangemTheme.colors.icon.informative,
)
}
}

View file

@ -0,0 +1,44 @@
package com.tangem.features.walletconnect.transaction.ui.common
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.style.TextAlign
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.TangemTheme
import com.tangem.features.walletconnect.impl.R
@Composable
internal fun WcWalletItem(walletName: String, modifier: Modifier = Modifier) {
Row(modifier = modifier, verticalAlignment = Alignment.CenterVertically) {
Icon(
modifier = Modifier.size(TangemTheme.dimens.size24),
painter = painterResource(R.drawable.ic_wallet_new_24),
contentDescription = null,
tint = TangemTheme.colors.icon.accent,
)
Text(
modifier = Modifier
.padding(start = TangemTheme.dimens.spacing4)
.weight(1f),
text = stringResourceSafe(R.string.manage_tokens_network_selector_wallet),
style = TangemTheme.typography.body1,
color = TangemTheme.colors.text.primary1,
)
Text(
modifier = Modifier
.padding(start = TangemTheme.dimens.spacing16)
.weight(1f),
text = walletName,
textAlign = TextAlign.End,
style = TangemTheme.typography.body1,
color = TangemTheme.colors.text.tertiary,
)
}
}

View file

@ -0,0 +1,154 @@
package com.tangem.features.walletconnect.transaction.ui.sign
import android.content.res.Configuration
import androidx.compose.animation.animateContentSize
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Devices
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
import com.tangem.core.ui.components.bottomsheets.modal.TangemModalBottomSheet
import com.tangem.core.ui.components.bottomsheets.modal.TangemModalBottomSheetTitle
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.impl.R
import com.tangem.features.walletconnect.transaction.entity.*
import com.tangem.features.walletconnect.transaction.ui.common.TransactionRequestInfoContent
import kotlinx.collections.immutable.persistentListOf
@Composable
internal fun WcSignTransactionModalBottomSheet(config: TangemBottomSheetConfig) {
TangemModalBottomSheet<WcSignTransactionUM>(
config = config,
containerColor = TangemTheme.colors.background.tertiary,
title = { state ->
TangemModalBottomSheetTitle(
title = when (state.state) {
WcSignTransactionUM.State.TRANSACTION -> {
resourceReference(R.string.wallet_connect_title)
}
WcSignTransactionUM.State.TRANSACTION_REQUEST_INFO -> {
resourceReference(R.string.wc_transaction_request_title)
}
},
endIconRes = state.endIconRes.takeIf {
state.state == WcSignTransactionUM.State.TRANSACTION
},
onEndClick = state.actions.onDismiss,
startIconRes = state.startIconRes.takeIf {
state.state == WcSignTransactionUM.State.TRANSACTION_REQUEST_INFO
},
onStartClick = state.actions.onBack,
)
},
content = { state ->
Box(
modifier = Modifier
.fillMaxWidth()
.animateContentSize(),
) {
when (state.state) {
WcSignTransactionUM.State.TRANSACTION -> {
WcSignTransactionModalBottomSheetContent(state)
}
WcSignTransactionUM.State.TRANSACTION_REQUEST_INFO -> {
TransactionRequestInfoContent(state)
}
}
}
},
)
}
@Composable
@Preview(showBackground = true, device = Devices.PIXEL_7_PRO)
@Preview(showBackground = true, device = Devices.PIXEL_7_PRO, uiMode = Configuration.UI_MODE_NIGHT_YES)
private fun WcSignTransactionBottomSheetPreview(
@PreviewParameter(WcSignTransactionStateProvider::class) state: WcSignTransactionUM,
) {
TangemThemePreview {
WcSignTransactionModalBottomSheet(
config = TangemBottomSheetConfig(
isShown = true,
onDismissRequest = {},
content = state,
),
)
}
}
private class WcSignTransactionStateProvider : CollectionPreviewParameterProvider<WcSignTransactionUM>(
listOf(
WcSignTransactionUM(
startIconRes = R.drawable.ic_back_24,
endIconRes = R.drawable.ic_close_24,
transactionIconRes = R.drawable.ic_doc_new_24,
state = WcSignTransactionUM.State.TRANSACTION,
transaction = WcTransactionUM(
appName = "React App",
appIcon = "",
isVerified = true,
appSubtitle = "react-app.walletconnect.com",
walletName = "Tangem 2.0",
networkInfo = WcNetworkInfoUM(name = "Ethereum", iconRes = R.drawable.img_eth_22),
),
transactionRequestInfo = WcTransactionRequestInfoUM(
persistentListOf(
WcTransactionRequestInfoItemUM(
title = resourceReference(R.string.wc_signature_type),
description = "personal_sign",
),
WcTransactionRequestInfoItemUM(
title = resourceReference(R.string.wc_contents),
description = "Hello! My name is John Dow. test@tange.com",
),
),
),
actions = WcTransactionActionsUM(
onDismiss = {},
onBack = {},
onSign = {},
onCopy = {},
transactionRequestOnClick = {},
),
),
WcSignTransactionUM(
startIconRes = R.drawable.ic_back_24,
endIconRes = R.drawable.ic_close_24,
transactionIconRes = R.drawable.ic_doc_new_24,
state = WcSignTransactionUM.State.TRANSACTION_REQUEST_INFO,
transaction = WcTransactionUM(
appName = "React App",
appIcon = "",
isVerified = true,
appSubtitle = "react-app.walletconnect.com",
walletName = "Tangem 2.0",
networkInfo = WcNetworkInfoUM(name = "Ethereum", iconRes = R.drawable.img_eth_22),
),
transactionRequestInfo = WcTransactionRequestInfoUM(
persistentListOf(
WcTransactionRequestInfoItemUM(
title = resourceReference(R.string.wc_signature_type),
description = "personal_sign",
),
WcTransactionRequestInfoItemUM(
title = resourceReference(R.string.wc_contents),
description = "Hello! My name is John Dow. test@tange.com",
),
),
),
actions = WcTransactionActionsUM(
onDismiss = {},
onBack = {},
onSign = {},
onCopy = {},
transactionRequestOnClick = {},
),
),
),
)

View file

@ -0,0 +1,89 @@
package com.tangem.features.walletconnect.transaction.ui.sign
import androidx.compose.animation.animateContentSize
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
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.material3.HorizontalDivider
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import com.tangem.core.ui.res.TangemTheme
import com.tangem.features.walletconnect.connections.ui.WcAppInfoItem
import com.tangem.features.walletconnect.transaction.entity.WcSignTransactionUM
import com.tangem.features.walletconnect.transaction.ui.common.*
import com.tangem.features.walletconnect.transaction.ui.common.WcNetworkItem
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 WcSignTransactionModalBottomSheetContent(state: WcSignTransactionUM) {
Column(modifier = Modifier.padding(horizontal = TangemTheme.dimens.spacing16)) {
Column(
modifier = Modifier
.clip(RoundedCornerShape(TangemTheme.dimens.radius14))
.background(color = TangemTheme.colors.background.action)
.fillMaxWidth()
.animateContentSize(),
) {
RequestFromItem()
WcAppInfoItem(
iconUrl = state.transaction.appIcon,
title = state.transaction.appName,
subtitle = state.transaction.appSubtitle,
isVerified = state.transaction.isVerified,
)
HorizontalDivider(
thickness = TangemTheme.dimens.size1,
color = TangemTheme.colors.stroke.primary,
)
WcTransactionRequestItem(
iconRes = state.transactionIconRes,
modifier = Modifier
.fillMaxWidth()
.clickable { state.actions.transactionRequestOnClick() }
.padding(TangemTheme.dimens.spacing12),
)
}
Column(modifier = Modifier.padding(top = TangemTheme.dimens.spacing16)) {
Column(
modifier = Modifier
.clip(RoundedCornerShape(TangemTheme.dimens.radius14))
.background(color = TangemTheme.colors.background.action)
.fillMaxWidth()
.animateContentSize(),
) {
val itemsModifier = Modifier
.fillMaxWidth()
.padding(TangemTheme.dimens.spacing12)
HorizontalDivider(
thickness = TangemTheme.dimens.size1,
color = TangemTheme.colors.stroke.primary,
)
WcWalletItem(
modifier = itemsModifier,
walletName = state.transaction.walletName,
)
HorizontalDivider(
thickness = TangemTheme.dimens.size1,
color = TangemTheme.colors.stroke.primary,
)
WcNetworkItem(
modifier = itemsModifier,
networkInfo = state.transaction.networkInfo,
)
}
WcTransactionRequestButtons(
modifier = Modifier.padding(vertical = TangemTheme.dimens.spacing16),
onDismiss = state.actions.onDismiss,
onSign = state.actions.onSign,
isLoading = state.transaction.isLoading,
)
}
}
}

View file

@ -0,0 +1,66 @@
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.usecase.ethereum.WcEthMessageSignUseCase
import com.tangem.domain.walletconnect.usecase.sign.WcSignState
import com.tangem.domain.walletconnect.usecase.sign.WcSignStep
import com.tangem.domain.walletconnect.usecase.sign.WcSignUseCase
import com.tangem.features.walletconnect.impl.R
import com.tangem.features.walletconnect.transaction.entity.WcNetworkInfoUM
import com.tangem.features.walletconnect.transaction.entity.WcSignTransactionUM
import com.tangem.features.walletconnect.transaction.entity.WcTransactionActionsUM
import com.tangem.features.walletconnect.transaction.entity.WcTransactionRequestInfoItemUM
import com.tangem.features.walletconnect.transaction.entity.WcTransactionRequestInfoUM
import com.tangem.features.walletconnect.transaction.entity.WcTransactionUM
import kotlinx.collections.immutable.persistentListOf
internal fun WcSignUseCase.toUM(signState: WcSignState<*>, actions: WcTransactionActionsUM): WcSignTransactionUM? {
return when (this) {
is WcEthMessageSignUseCase -> {
ethMessageSignToUM(
signState = signState,
signModel = signState.signModel as WcEthMessageSignUseCase.SignModel,
actions = actions,
)
}
else -> null
}
}
private fun WcEthMessageSignUseCase.ethMessageSignToUM(
signState: WcSignState<*>,
signModel: WcEthMessageSignUseCase.SignModel,
actions: WcTransactionActionsUM,
) = WcSignTransactionUM(
startIconRes = R.drawable.ic_back_24,
endIconRes = R.drawable.ic_close_24,
transactionIconRes = R.drawable.ic_doc_new_24,
state = WcSignTransactionUM.State.TRANSACTION,
actions = actions,
transaction = WcTransactionUM(
appName = session.sdkModel.appMetaData.name,
appIcon = session.sdkModel.appMetaData.url,
isVerified = session.securityStatus == CheckDAppResult.SAFE,
appSubtitle = session.sdkModel.appMetaData.description,
walletName = session.wallet.name,
networkInfo = WcNetworkInfoUM(
name = network.name,
iconRes = getActiveIconRes(network.id.value),
),
isLoading = signState.domainStep == WcSignStep.Signing,
),
transactionRequestInfo = WcTransactionRequestInfoUM(
persistentListOf(
WcTransactionRequestInfoItemUM(
title = resourceReference(R.string.wc_signature_type),
description = rawSdkRequest.request.method,
),
WcTransactionRequestInfoItemUM(
title = resourceReference(R.string.wc_contents),
description = signModel.humanMsg,
),
),
),
)