Updated on 2026-08-14

This commit is contained in:
Tangem 2025-05-07 22:47:07 +04:00
parent 63133bb8fb
commit 03686da34d
21 changed files with 308 additions and 551 deletions

View file

@ -20,7 +20,7 @@ internal class WcSignTransactionComponent(
if (content != null) {
WcSignTransactionModalBottomSheetContent(
state = content,
state = content.transaction,
onClickTransactionRequest = transactionInfoOnClick,
)
}

View file

@ -18,7 +18,7 @@ internal class WcSignTransactionRequestInfoComponent(
val content = model.uiState.collectAsStateWithLifecycle().value
if (content != null) {
TransactionRequestInfoContent(content)
TransactionRequestInfoContent(content.transactionRequestInfo)
}
}
}

View file

@ -1,56 +0,0 @@
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(
val actions: WcTransactionActionsUM,
val transaction: WcTransactionUM,
val transactionRequestInfo: WcTransactionRequestInfoUM,
) : TangemBottomSheetConfigContent
@Immutable
internal data class WcTransactionUM(
val appName: String,
val appIcon: String,
val isVerified: Boolean,
val appSubtitle: String,
val walletName: String,
val networkInfo: WcNetworkInfoUM,
val addressText: String? = null,
val networkFee: String? = null,
val isLoading: Boolean = false,
)
@Immutable
internal data class WcTransactionRequestInfoUM(
val blocks: ImmutableList<WcTransactionRequestBlockUM>,
)
@Immutable
internal data class WcTransactionRequestBlockUM(
val info: ImmutableList<WcTransactionRequestInfoItemUM>,
)
@Immutable
internal data class WcTransactionRequestInfoItemUM(
val title: TextReference,
val description: String = "",
)
@Immutable
internal data class WcTransactionActionsUM(
val onDismiss: () -> Unit,
val onSign: () -> Unit,
val onCopy: () -> Unit,
)
@Immutable
internal data class WcNetworkInfoUM(
val name: String,
@DrawableRes val iconRes: Int,
)

View file

@ -1,20 +1,35 @@
package com.tangem.features.walletconnect.transaction.entity.approve
import androidx.annotation.DrawableRes
import androidx.compose.runtime.Immutable
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionActionsUM
import com.tangem.features.walletconnect.transaction.entity.common.WcNetworkInfoUM
import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionAppInfoContentUM
import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionRequestInfoUM
import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionUM
@Immutable
internal data class WcApproveTransactionUM(
val actions: WcTransactionActionsUM,
val state: State = State.TRANSACTION,
val transaction: WcTransactionUM,
val transaction: WcApproveTransactionItemUM,
val transactionRequestInfo: WcTransactionRequestInfoUM,
) : TangemBottomSheetConfigContent {
val customAllowance: WcCustomAllowanceUM,
)
enum class State {
TRANSACTION, CUSTOM_ALLOWANCE, TRANSACTION_REQUEST_INFO
}
}
@Immutable
internal data class WcApproveTransactionItemUM(
val onDismiss: () -> Unit,
val onSend: () -> Unit,
val appInfo: WcTransactionAppInfoContentUM,
val spendAllowance: WcSpendAllowanceUM? = null,
val walletName: String,
val networkInfo: WcNetworkInfoUM,
val networkFee: String? = null,
val isLoading: Boolean = false,
) : TangemBottomSheetConfigContent
@Immutable
internal data class WcCustomAllowanceUM(
@DrawableRes val networkIconRes: Int,
val tokenIconUrl: String,
val amountText: String,
val isUnlimited: Boolean,
)

View file

@ -1,6 +1,6 @@
package com.tangem.features.walletconnect.transaction.entity.approve
internal data class SpendAllowanceUM(
internal data class WcSpendAllowanceUM(
val amountText: String,
val tokenImageUrl: String,
)

View file

@ -0,0 +1,10 @@
package com.tangem.features.walletconnect.transaction.entity.common
import androidx.annotation.DrawableRes
import androidx.compose.runtime.Immutable
@Immutable
internal data class WcNetworkInfoUM(
val name: String,
@DrawableRes val iconRes: Int,
)

View file

@ -0,0 +1,10 @@
package com.tangem.features.walletconnect.transaction.entity.common
import androidx.compose.runtime.Immutable
@Immutable
internal data class WcTransactionActionsUM(
val onDismiss: () -> Unit,
val onSign: () -> Unit,
val onCopy: () -> Unit,
)

View file

@ -0,0 +1,8 @@
package com.tangem.features.walletconnect.transaction.entity.common
internal data class WcTransactionAppInfoContentUM(
val appName: String,
val appIcon: String,
val isVerified: Boolean,
val appSubtitle: String,
)

View file

@ -1,13 +1,15 @@
package com.tangem.features.walletconnect.transaction.entity.common
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 WcTransactionRequestInfoUM(
val blocks: ImmutableList<WcTransactionRequestBlockUM>,
)
val onCopy: () -> Unit,
) : TangemBottomSheetConfigContent
@Immutable
internal data class WcTransactionRequestBlockUM(

View file

@ -1,36 +0,0 @@
package com.tangem.features.walletconnect.transaction.entity.common
import androidx.annotation.DrawableRes
import androidx.compose.runtime.Immutable
import com.tangem.core.ui.extensions.TextReference
import com.tangem.features.walletconnect.transaction.entity.approve.SpendAllowanceUM
@Immutable
internal data class WcTransactionUM(
val appName: String,
val appIcon: String,
val isVerified: Boolean,
val appSubtitle: String,
val walletName: String,
val networkInfo: WcNetworkInfoUM,
val activeButtonText: TextReference,
val addressText: String? = null,
val networkFee: String? = null,
val spendAllowance: SpendAllowanceUM? = null,
val isLoading: Boolean = false,
)
@Immutable
internal data class WcTransactionActionsUM(
val transactionRequestOnClick: () -> Unit,
val onDismiss: () -> Unit,
val activeButtonOnClick: () -> Unit,
val onBack: () -> Unit,
val onCopy: () -> Unit,
)
@Immutable
internal data class WcNetworkInfoUM(
val name: String,
@DrawableRes val iconRes: Int,
)

View file

@ -2,19 +2,23 @@ package com.tangem.features.walletconnect.transaction.entity.sign
import androidx.compose.runtime.Immutable
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionActionsUM
import com.tangem.features.walletconnect.transaction.entity.common.WcNetworkInfoUM
import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionAppInfoContentUM
import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionRequestInfoUM
import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionUM
@Immutable
internal data class WcSignTransactionUM(
val actions: WcTransactionActionsUM,
val state: State = State.TRANSACTION,
val transaction: WcTransactionUM,
val transaction: WcSignTransactionItemUM,
val transactionRequestInfo: WcTransactionRequestInfoUM,
) : TangemBottomSheetConfigContent {
)
enum class State {
TRANSACTION, TRANSACTION_REQUEST_INFO
}
}
@Immutable
internal data class WcSignTransactionItemUM(
val onDismiss: () -> Unit,
val onSign: () -> Unit,
val appInfo: WcTransactionAppInfoContentUM,
val walletName: String,
val networkInfo: WcNetworkInfoUM,
val addressText: String? = null,
val isLoading: Boolean = false,
) : TangemBottomSheetConfigContent

View file

@ -11,8 +11,8 @@ 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.transaction.components.WcSignTransactionContainerComponent
import com.tangem.features.walletconnect.transaction.entity.WcSignTransactionUM
import com.tangem.features.walletconnect.transaction.entity.WcTransactionActionsUM
import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionActionsUM
import com.tangem.features.walletconnect.transaction.entity.sign.WcSignTransactionUM
import com.tangem.features.walletconnect.transaction.utils.toUM
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.coroutines.flow.MutableStateFlow
@ -58,7 +58,7 @@ internal class WcSignTransactionModel @Inject constructor(
}
fun dismiss() {
_uiState.value?.actions?.onDismiss?.invoke() ?: router.pop()
_uiState.value?.transaction?.onDismiss?.invoke() ?: router.pop()
}
private fun signingIsDone(signState: WcSignState<*>): Boolean {

View file

@ -2,78 +2,125 @@ package com.tangem.features.walletconnect.transaction.ui.approve
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.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
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 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 androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
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.connections.ui.WcAppInfoItem
import com.tangem.features.walletconnect.impl.R
import com.tangem.features.walletconnect.transaction.entity.approve.SpendAllowanceUM
import com.tangem.features.walletconnect.transaction.entity.approve.WcApproveTransactionUM
import com.tangem.features.walletconnect.transaction.entity.approve.WcApproveTransactionItemUM
import com.tangem.features.walletconnect.transaction.entity.approve.WcSpendAllowanceUM
import com.tangem.features.walletconnect.transaction.entity.common.WcNetworkInfoUM
import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionActionsUM
import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionRequestInfoUM
import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionUM
import com.tangem.features.walletconnect.transaction.ui.common.WcTransactionRequestInfoContent
import com.tangem.features.walletconnect.transaction.ui.sign.WcTransactionModalBottomSheetContent
import kotlinx.collections.immutable.persistentListOf
import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionAppInfoContentUM
import com.tangem.features.walletconnect.transaction.ui.common.*
@Composable
internal fun WcApproveTransactionModalBottomSheet(config: TangemBottomSheetConfig) {
TangemModalBottomSheet<WcApproveTransactionUM>(
config = config,
containerColor = TangemTheme.colors.background.tertiary,
title = { state ->
TangemModalBottomSheetTitle(
title = when (state.state) {
WcApproveTransactionUM.State.TRANSACTION -> {
resourceReference(R.string.wallet_connect_title)
}
WcApproveTransactionUM.State.CUSTOM_ALLOWANCE -> {
resourceReference(R.string.wc_custom_allowance_title)
}
WcApproveTransactionUM.State.TRANSACTION_REQUEST_INFO -> {
resourceReference(R.string.wc_transaction_request_title)
}
},
endIconRes = R.drawable.ic_close_24.takeIf {
state.state == WcApproveTransactionUM.State.TRANSACTION
},
onEndClick = state.actions.onDismiss,
startIconRes = R.drawable.ic_back_24.takeIf {
state.state != WcApproveTransactionUM.State.TRANSACTION
},
onStartClick = state.actions.onBack,
internal fun WcApproveTransactionModalBottomSheetContent(
state: WcApproveTransactionItemUM,
onClickTransactionRequest: () -> Unit,
) {
Column(
modifier = Modifier
.padding(horizontal = TangemTheme.dimens.spacing16),
) {
Column(
modifier = Modifier
.clip(RoundedCornerShape(TangemTheme.dimens.radius14))
.background(color = TangemTheme.colors.background.action)
.fillMaxWidth()
.animateContentSize(),
) {
WcSmallTitleItem(R.string.wc_request_from)
WcAppInfoItem(
iconUrl = state.appInfo.appIcon,
title = state.appInfo.appName,
subtitle = state.appInfo.appSubtitle,
isVerified = state.appInfo.isVerified,
)
},
content = { state ->
Box(
DividerWithPadding(start = 0.dp, end = 0.dp)
WcTransactionRequestItem(
iconRes = R.drawable.ic_doc_new_24,
modifier = Modifier
.fillMaxWidth()
.animateContentSize(),
) {
when (state.state) {
WcApproveTransactionUM.State.TRANSACTION -> {
WcTransactionModalBottomSheetContent(state.transaction, state.actions)
}
WcApproveTransactionUM.State.CUSTOM_ALLOWANCE -> {
TODO("Will be done in the second part of the PR")
}
WcApproveTransactionUM.State.TRANSACTION_REQUEST_INFO -> {
WcTransactionRequestInfoContent(state.transactionRequestInfo, state.actions)
}
}
.clickable { onClickTransactionRequest() }
.padding(TangemTheme.dimens.spacing12),
)
}
Column(modifier = Modifier.padding(top = TangemTheme.dimens.spacing16)) {
if (state.spendAllowance != null) {
WcSpendAllowanceItem(state.spendAllowance)
Spacer(Modifier.height(TangemTheme.dimens.spacing16))
}
},
WcApproveTransactionItems(state)
WcTransactionRequestButtons(
modifier = Modifier.padding(vertical = TangemTheme.dimens.spacing16),
onDismiss = state.onDismiss,
onClickActiveButton = state.onSend,
activeButtonText = resourceReference(R.string.common_send),
isLoading = state.isLoading,
)
}
}
}
@Composable
private fun WcApproveTransactionItems(state: WcApproveTransactionItemUM) {
Column(
modifier = Modifier
.clip(RoundedCornerShape(TangemTheme.dimens.radius14))
.background(color = TangemTheme.colors.background.action)
.fillMaxWidth()
.animateContentSize(),
) {
val itemsModifier = Modifier
.fillMaxWidth()
.padding(TangemTheme.dimens.spacing12)
DividerWithPadding(start = 0.dp, end = 0.dp)
WcWalletItem(
modifier = itemsModifier,
walletName = state.walletName,
)
DividerWithPadding(start = TangemTheme.dimens.spacing40, end = TangemTheme.dimens.spacing12)
WcNetworkItem(
modifier = itemsModifier,
networkInfo = state.networkInfo,
)
if (!state.networkFee.isNullOrEmpty()) {
DividerWithPadding(start = TangemTheme.dimens.spacing40, end = TangemTheme.dimens.spacing12)
WcNetworkFeeItem(
modifier = itemsModifier,
networkFeeText = state.networkFee,
)
}
}
}
@Composable
internal fun DividerWithPadding(start: Dp, end: Dp) {
HorizontalDivider(
modifier = Modifier.padding(
start = start,
end = end,
),
thickness = TangemTheme.dimens.size1,
color = TangemTheme.colors.stroke.primary,
)
}
@ -81,42 +128,47 @@ internal fun WcApproveTransactionModalBottomSheet(config: TangemBottomSheetConfi
@Preview(showBackground = true, device = Devices.PIXEL_7_PRO)
@Preview(showBackground = true, device = Devices.PIXEL_7_PRO, uiMode = Configuration.UI_MODE_NIGHT_YES)
private fun WcApproveTransactionBottomSheetPreview(
@PreviewParameter(WcApproveTransactionStateProvider::class) state: WcApproveTransactionUM,
@PreviewParameter(WcApproveTransactionStateProvider::class) state: WcApproveTransactionItemUM,
) {
TangemThemePreview {
WcApproveTransactionModalBottomSheet(
TangemModalBottomSheet<WcApproveTransactionItemUM>(
config = TangemBottomSheetConfig(
isShown = true,
onDismissRequest = {},
content = state,
),
containerColor = TangemTheme.colors.background.tertiary,
title = {
TangemModalBottomSheetTitle(
title = resourceReference(R.string.wallet_connect_title),
endIconRes = R.drawable.ic_close_24,
onEndClick = {},
startIconRes = null,
onStartClick = {},
)
},
content = {
WcApproveTransactionModalBottomSheetContent(state = state, onClickTransactionRequest = {})
},
)
}
}
private class WcApproveTransactionStateProvider : CollectionPreviewParameterProvider<WcApproveTransactionUM>(
private class WcApproveTransactionStateProvider : CollectionPreviewParameterProvider<WcApproveTransactionItemUM>(
listOf(
WcApproveTransactionUM(
state = WcApproveTransactionUM.State.TRANSACTION,
transaction = WcTransactionUM(
WcApproveTransactionItemUM(
onDismiss = {},
onSend = {},
appInfo = WcTransactionAppInfoContentUM(
appName = "React App",
appIcon = "",
isVerified = true,
appSubtitle = "react-app.walletconnect.com",
walletName = "Tangem 2.0",
activeButtonText = resourceReference(R.string.common_send),
networkInfo = WcNetworkInfoUM(name = "Ethereum", iconRes = R.drawable.img_eth_22),
networkFee = "~ 0.22 $",
spendAllowance = SpendAllowanceUM(amountText = "Unlimited USDT", tokenImageUrl = ""),
),
transactionRequestInfo = WcTransactionRequestInfoUM(persistentListOf()),
actions = WcTransactionActionsUM(
onDismiss = {},
onBack = {},
activeButtonOnClick = {},
onCopy = {},
transactionRequestOnClick = {},
),
spendAllowance = WcSpendAllowanceUM(amountText = "Unlimited USDT", tokenImageUrl = ""),
walletName = "Tangem 2.0",
networkInfo = WcNetworkInfoUM(name = "Ethereum", iconRes = R.drawable.img_eth_22),
networkFee = "~ 0.22 $",
),
),
)

View file

@ -15,11 +15,11 @@ import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import coil.compose.AsyncImage
import com.tangem.core.ui.res.TangemTheme
import com.tangem.features.walletconnect.transaction.entity.approve.SpendAllowanceUM
import com.tangem.features.walletconnect.transaction.entity.approve.WcSpendAllowanceUM
import com.tangem.features.walletconnect.transaction.ui.common.WcSmallTitleItem
@Composable
internal fun SpendAllowanceItem(spendAllowance: SpendAllowanceUM, modifier: Modifier = Modifier) {
internal fun WcSpendAllowanceItem(spendAllowance: WcSpendAllowanceUM, modifier: Modifier = Modifier) {
Column(
modifier = modifier
.clip(RoundedCornerShape(TangemTheme.dimens.radius14))

View file

@ -27,19 +27,16 @@ 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.impl.R
import com.tangem.features.walletconnect.transaction.entity.*
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.WcTransactionRequestInfoUM
import com.tangem.features.walletconnect.transaction.entity.WcTransactionUM
import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionRequestBlockUM
import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionRequestInfoItemUM
import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionRequestInfoUM
import kotlinx.collections.immutable.persistentListOf
private const val MIN_HEIGHT_SCREEN_PERCENT = 0.35f
private const val MAX_HEIGHT_SCREEN_PERCENT = 0.75f
@Composable
internal fun TransactionRequestInfoContent(state: WcSignTransactionUM) {
internal fun TransactionRequestInfoContent(state: WcTransactionRequestInfoUM) {
val screenHeight = LocalConfiguration.current.screenHeightDp
val minHeight = (screenHeight * MIN_HEIGHT_SCREEN_PERCENT).dp
val maxHeight = (screenHeight * MAX_HEIGHT_SCREEN_PERCENT).dp
@ -55,7 +52,7 @@ internal fun TransactionRequestInfoContent(state: WcSignTransactionUM) {
.fillMaxWidth(),
contentPadding = PaddingValues(top = TangemTheme.dimens.spacing8, bottom = TangemTheme.dimens.spacing70),
) {
items(state.transactionRequestInfo.blocks) { block ->
items(state.blocks) { block ->
Column(
modifier = Modifier
.fillMaxWidth()
@ -98,7 +95,7 @@ internal fun TransactionRequestInfoContent(state: WcSignTransactionUM) {
.padding(bottom = TangemTheme.dimens.spacing20)
.fillMaxWidth(),
text = stringResourceSafe(R.string.wc_copy_data_button_text),
onClick = state.actions.onCopy,
onClick = state.onCopy,
iconResId = R.drawable.ic_copy_24,
)
}
@ -108,10 +105,10 @@ internal fun TransactionRequestInfoContent(state: WcSignTransactionUM) {
@Preview(showBackground = true, device = Devices.PIXEL_7_PRO)
@Preview(showBackground = true, device = Devices.PIXEL_7_PRO, uiMode = Configuration.UI_MODE_NIGHT_YES)
private fun WcSignTransactionRequestInfoBottomSheetPreview(
@PreviewParameter(WcSignTransactionStateProvider::class) state: WcSignTransactionUM,
@PreviewParameter(WcSignTransactionStateProvider::class) state: WcTransactionRequestInfoUM,
) {
TangemThemePreview {
TangemModalBottomSheet<WcSignTransactionUM>(
TangemModalBottomSheet<WcTransactionRequestInfoUM>(
config = TangemBottomSheetConfig(
isShown = true,
onDismissRequest = {},
@ -134,86 +131,56 @@ private fun WcSignTransactionRequestInfoBottomSheetPreview(
}
}
private class WcSignTransactionStateProvider : CollectionPreviewParameterProvider<WcSignTransactionUM>(
private class WcSignTransactionStateProvider : CollectionPreviewParameterProvider<WcTransactionRequestInfoUM>(
listOf(
WcSignTransactionUM(
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(
blocks = persistentListOf(
WcTransactionRequestBlockUM(
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",
),
WcTransactionRequestInfoUM(
blocks = persistentListOf(
WcTransactionRequestBlockUM(
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 = {},
onSign = {},
onCopy = {},
),
onCopy = {},
),
WcSignTransactionUM(
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),
addressText = "0x345FF...34FA",
networkFee = "~ 0.22 $",
),
transactionRequestInfo = WcTransactionRequestInfoUM(
blocks = persistentListOf(
WcTransactionRequestBlockUM(
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",
),
WcTransactionRequestInfoUM(
blocks = persistentListOf(
WcTransactionRequestBlockUM(
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",
),
),
WcTransactionRequestBlockUM(
persistentListOf(
WcTransactionRequestInfoItemUM(
title = resourceReference(R.string.wc_transaction_info_to_title),
),
WcTransactionRequestInfoItemUM(
title = resourceReference(R.string.settings_wallet_name_title),
description = "Bob",
),
WcTransactionRequestInfoItemUM(
title = resourceReference(R.string.wc_common_wallet),
description = "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826",
),
),
WcTransactionRequestBlockUM(
persistentListOf(
WcTransactionRequestInfoItemUM(
title = resourceReference(R.string.wc_transaction_info_to_title),
),
WcTransactionRequestInfoItemUM(
title = resourceReference(R.string.settings_wallet_name_title),
description = "Bob",
),
WcTransactionRequestInfoItemUM(
title = resourceReference(R.string.wc_common_wallet),
description = "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826",
),
),
),
),
actions = WcTransactionActionsUM(
onDismiss = {},
onSign = {},
onCopy = {},
),
onCopy = {},
),
),
)

View file

@ -18,7 +18,7 @@ internal fun WcTransactionRequestButtons(
activeButtonText: TextReference,
isLoading: Boolean,
onDismiss: () -> Unit,
onSign: () -> Unit,
onClickActiveButton: () -> Unit,
modifier: Modifier = Modifier,
) {
Row(modifier = modifier, horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing8)) {
@ -34,7 +34,7 @@ internal fun WcTransactionRequestButtons(
.fillMaxWidth()
.weight(1f),
text = activeButtonText.resolveReference(),
onClick = onSign,
onClick = onClickActiveButton,
iconResId = R.drawable.ic_tangem_24,
showProgress = isLoading,
)

View file

@ -1,90 +0,0 @@
package com.tangem.features.walletconnect.transaction.ui.common
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
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.platform.LocalConfiguration
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.common.WcTransactionActionsUM
import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionRequestInfoUM
private const val MIN_HEIGHT_SCREEN_PERCENT = 0.35f
private const val MAX_HEIGHT_SCREEN_PERCENT = 0.75f
@Composable
internal fun WcTransactionRequestInfoContent(info: WcTransactionRequestInfoUM, actions: WcTransactionActionsUM) {
val screenHeight = LocalConfiguration.current.screenHeightDp
val minHeight = (screenHeight * MIN_HEIGHT_SCREEN_PERCENT).dp
val maxHeight = (screenHeight * MAX_HEIGHT_SCREEN_PERCENT).dp
Box(
modifier = Modifier
.fillMaxWidth()
.heightIn(min = minHeight, max = maxHeight)
.padding(horizontal = TangemTheme.dimens.spacing16),
) {
LazyColumn(
modifier = Modifier
.fillMaxWidth(),
contentPadding = PaddingValues(top = TangemTheme.dimens.spacing8, bottom = TangemTheme.dimens.spacing70),
) {
items(info.blocks) { block ->
Column(
modifier = Modifier
.fillMaxWidth()
.clip(RoundedCornerShape(TangemTheme.dimens.radius16))
.background(TangemTheme.colors.background.action)
.padding(
start = TangemTheme.dimens.spacing16,
end = TangemTheme.dimens.spacing16,
top = TangemTheme.dimens.spacing20,
),
) {
block.info.forEach { item ->
Text(
text = item.title.resolveReference(),
style = TangemTheme.typography.subtitle2,
color = TangemTheme.colors.text.tertiary,
)
if (item.description.isNotEmpty()) {
Text(
text = item.description,
modifier = Modifier.padding(
top = TangemTheme.dimens.spacing4,
bottom = TangemTheme.dimens.spacing20,
),
style = TangemTheme.typography.body2,
color = TangemTheme.colors.text.primary1,
)
} else {
Spacer(modifier = Modifier.size(TangemTheme.dimens.size12))
}
}
}
Spacer(modifier = Modifier.size(TangemTheme.dimens.size20))
}
}
SecondaryButtonIconEnd(
modifier = Modifier
.align(Alignment.BottomCenter)
.padding(bottom = TangemTheme.dimens.spacing20)
.fillMaxWidth(),
text = stringResourceSafe(R.string.wc_copy_data_button_text),
onClick = actions.onCopy,
iconResId = R.drawable.ic_copy_24,
)
}
}

View file

@ -26,13 +26,14 @@ import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.features.walletconnect.connections.ui.WcAppInfoItem
import com.tangem.features.walletconnect.impl.R
import com.tangem.features.walletconnect.transaction.entity.*
import com.tangem.features.walletconnect.transaction.entity.common.WcNetworkInfoUM
import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionAppInfoContentUM
import com.tangem.features.walletconnect.transaction.entity.sign.WcSignTransactionItemUM
import com.tangem.features.walletconnect.transaction.ui.common.*
import kotlinx.collections.immutable.persistentListOf
@Composable
internal fun WcSignTransactionModalBottomSheetContent(
state: WcSignTransactionUM,
state: WcSignTransactionItemUM,
onClickTransactionRequest: () -> Unit,
) {
Column(
@ -46,12 +47,12 @@ internal fun WcSignTransactionModalBottomSheetContent(
.fillMaxWidth()
.animateContentSize(),
) {
RequestFromItem()
WcSmallTitleItem(R.string.wc_request_from)
WcAppInfoItem(
iconUrl = state.transaction.appIcon,
title = state.transaction.appName,
subtitle = state.transaction.appSubtitle,
isVerified = state.transaction.isVerified,
iconUrl = state.appInfo.appIcon,
title = state.appInfo.appName,
subtitle = state.appInfo.appSubtitle,
isVerified = state.appInfo.isVerified,
)
DividerWithPadding(start = 0.dp, end = 0.dp)
WcTransactionRequestItem(
@ -66,16 +67,17 @@ internal fun WcSignTransactionModalBottomSheetContent(
WcSignTransactionItems(state)
WcTransactionRequestButtons(
modifier = Modifier.padding(vertical = TangemTheme.dimens.spacing16),
onDismiss = state.actions.onDismiss,
onSign = state.actions.onSign,
isLoading = state.transaction.isLoading,
onDismiss = state.onDismiss,
onClickActiveButton = state.onSign,
activeButtonText = resourceReference(R.string.common_sign),
isLoading = state.isLoading,
)
}
}
}
@Composable
private fun WcSignTransactionItems(state: WcSignTransactionUM) {
private fun WcSignTransactionItems(state: WcSignTransactionItemUM) {
Column(
modifier = Modifier
.clip(RoundedCornerShape(TangemTheme.dimens.radius14))
@ -90,32 +92,25 @@ private fun WcSignTransactionItems(state: WcSignTransactionUM) {
DividerWithPadding(start = 0.dp, end = 0.dp)
WcWalletItem(
modifier = itemsModifier,
walletName = state.transaction.walletName,
walletName = state.walletName,
)
DividerWithPadding(start = TangemTheme.dimens.spacing40, end = TangemTheme.dimens.spacing12)
WcNetworkItem(
modifier = itemsModifier,
networkInfo = state.transaction.networkInfo,
networkInfo = state.networkInfo,
)
if (!state.transaction.addressText.isNullOrEmpty()) {
if (!state.addressText.isNullOrEmpty()) {
DividerWithPadding(start = TangemTheme.dimens.spacing40, end = TangemTheme.dimens.spacing12)
WcAddressItem(
modifier = itemsModifier,
addressText = state.transaction.addressText,
)
}
if (!state.transaction.networkFee.isNullOrEmpty()) {
DividerWithPadding(start = TangemTheme.dimens.spacing40, end = TangemTheme.dimens.spacing12)
WcNetworkFeeItem(
modifier = itemsModifier,
networkFeeText = state.transaction.networkFee,
addressText = state.addressText,
)
}
}
}
@Composable
private fun DividerWithPadding(start: Dp, end: Dp) {
internal fun DividerWithPadding(start: Dp, end: Dp) {
HorizontalDivider(
modifier = Modifier.padding(
start = start,
@ -130,10 +125,10 @@ private fun DividerWithPadding(start: Dp, end: Dp) {
@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,
@PreviewParameter(WcSignTransactionStateProvider::class) state: WcSignTransactionItemUM,
) {
TangemThemePreview {
TangemModalBottomSheet<WcSignTransactionUM>(
TangemModalBottomSheet<WcSignTransactionItemUM>(
config = TangemBottomSheetConfig(
isShown = true,
onDismissRequest = {},
@ -156,41 +151,32 @@ private fun WcSignTransactionBottomSheetPreview(
}
}
private class WcSignTransactionStateProvider : CollectionPreviewParameterProvider<WcSignTransactionUM>(
private class WcSignTransactionStateProvider : CollectionPreviewParameterProvider<WcSignTransactionItemUM>(
listOf(
WcSignTransactionUM(
transaction = WcTransactionUM(
WcSignTransactionItemUM(
onDismiss = {},
onSign = {},
appInfo = WcTransactionAppInfoContentUM(
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()),
actions = WcTransactionActionsUM(
onDismiss = {},
onSign = {},
onCopy = {},
),
walletName = "Tangem 2.0",
networkInfo = WcNetworkInfoUM(name = "Ethereum", iconRes = R.drawable.img_eth_22),
),
WcSignTransactionUM(
transaction = WcTransactionUM(
WcSignTransactionItemUM(
onDismiss = {},
onSign = {},
appInfo = WcTransactionAppInfoContentUM(
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),
addressText = "0x345FF...34FA",
networkFee = "~ 0.22 $",
),
transactionRequestInfo = WcTransactionRequestInfoUM(persistentListOf()),
actions = WcTransactionActionsUM(
onDismiss = {},
onSign = {},
onCopy = {},
),
walletName = "Tangem 2.0",
addressText = "0x345FF...34FA",
networkInfo = WcNetworkInfoUM(name = "Ethereum", iconRes = R.drawable.img_eth_22),
),
),
)

View file

@ -1,119 +0,0 @@
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.*
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 androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import com.tangem.core.ui.res.TangemTheme
import com.tangem.features.walletconnect.connections.ui.WcAppInfoItem
import com.tangem.features.walletconnect.impl.R
import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionActionsUM
import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionUM
import com.tangem.features.walletconnect.transaction.ui.approve.SpendAllowanceItem
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 WcTransactionModalBottomSheetContent(transaction: WcTransactionUM, actions: WcTransactionActionsUM) {
Column(modifier = Modifier.padding(horizontal = TangemTheme.dimens.spacing16)) {
Column(
modifier = Modifier
.clip(RoundedCornerShape(TangemTheme.dimens.radius14))
.background(color = TangemTheme.colors.background.action)
.fillMaxWidth()
.animateContentSize(),
) {
WcSmallTitleItem(R.string.wc_request_from)
WcAppInfoItem(
iconUrl = transaction.appIcon,
title = transaction.appName,
subtitle = transaction.appSubtitle,
isVerified = transaction.isVerified,
)
DividerWithPadding(start = 0.dp, end = 0.dp)
WcTransactionRequestItem(
iconRes = R.drawable.ic_doc_new_24,
modifier = Modifier
.fillMaxWidth()
.clickable { actions.transactionRequestOnClick() }
.padding(TangemTheme.dimens.spacing12),
)
}
Column(modifier = Modifier.padding(top = TangemTheme.dimens.spacing16)) {
if (transaction.spendAllowance != null) {
SpendAllowanceItem(transaction.spendAllowance)
Spacer(Modifier.height(TangemTheme.dimens.spacing16))
}
WcSignTransactionItems(transaction)
WcTransactionRequestButtons(
modifier = Modifier.padding(vertical = TangemTheme.dimens.spacing16),
onDismiss = actions.onDismiss,
onSign = actions.activeButtonOnClick,
activeButtonText = transaction.activeButtonText,
isLoading = transaction.isLoading,
)
}
}
}
@Composable
private fun WcSignTransactionItems(transaction: WcTransactionUM) {
Column(
modifier = Modifier
.clip(RoundedCornerShape(TangemTheme.dimens.radius14))
.background(color = TangemTheme.colors.background.action)
.fillMaxWidth()
.animateContentSize(),
) {
val itemsModifier = Modifier
.fillMaxWidth()
.padding(TangemTheme.dimens.spacing12)
DividerWithPadding(start = 0.dp, end = 0.dp)
WcWalletItem(
modifier = itemsModifier,
walletName = transaction.walletName,
)
DividerWithPadding(start = TangemTheme.dimens.spacing40, end = TangemTheme.dimens.spacing12)
WcNetworkItem(
modifier = itemsModifier,
networkInfo = transaction.networkInfo,
)
if (!transaction.addressText.isNullOrEmpty()) {
DividerWithPadding(start = TangemTheme.dimens.spacing40, end = TangemTheme.dimens.spacing12)
WcAddressItem(
modifier = itemsModifier,
addressText = transaction.addressText,
)
}
if (!transaction.networkFee.isNullOrEmpty()) {
DividerWithPadding(start = TangemTheme.dimens.spacing40, end = TangemTheme.dimens.spacing12)
WcNetworkFeeItem(
modifier = itemsModifier,
networkFeeText = transaction.networkFee,
)
}
}
}
@Composable
private fun DividerWithPadding(start: Dp, end: Dp) {
HorizontalDivider(
modifier = Modifier.padding(
start = start,
end = end,
),
thickness = TangemTheme.dimens.size1,
color = TangemTheme.colors.stroke.primary,
)
}

View file

@ -11,13 +11,9 @@ 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.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.WcTransactionRequestBlockUM
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 com.tangem.features.walletconnect.transaction.entity.common.*
import com.tangem.features.walletconnect.transaction.entity.sign.WcSignTransactionItemUM
import com.tangem.features.walletconnect.transaction.entity.sign.WcSignTransactionUM
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList
@ -47,12 +43,15 @@ private fun WcMessageSignUseCase.signTypedDataToUM(
signModel: WcMessageSignUseCase.SignModel,
actions: WcTransactionActionsUM,
) = WcSignTransactionUM(
actions = actions,
transaction = WcTransactionUM(
appName = session.sdkModel.appMetaData.name,
appIcon = session.sdkModel.appMetaData.url,
isVerified = session.securityStatus == CheckDAppResult.SAFE,
appSubtitle = session.sdkModel.appMetaData.description,
transaction = WcSignTransactionItemUM(
onDismiss = actions.onDismiss,
onSign = actions.onSign,
appInfo = WcTransactionAppInfoContentUM(
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,
@ -62,7 +61,7 @@ private fun WcMessageSignUseCase.signTypedDataToUM(
isLoading = signState.domainStep == WcSignStep.Signing,
),
transactionRequestInfo = WcTransactionRequestInfoUM(
buildList {
blocks = buildList {
add(createInfoBlockUM(rawSdkRequest, signModel))
(method as? WcEthMethod.SignTypedData)?.params?.message?.to?.let { to ->
add(
@ -84,6 +83,7 @@ private fun WcMessageSignUseCase.signTypedDataToUM(
)
}
}.toImmutableList(),
onCopy = actions.onCopy,
),
)
@ -92,12 +92,15 @@ private fun WcMessageSignUseCase.messageSignToUM(
signModel: WcMessageSignUseCase.SignModel,
actions: WcTransactionActionsUM,
) = WcSignTransactionUM(
actions = actions,
transaction = WcTransactionUM(
appName = session.sdkModel.appMetaData.name,
appIcon = session.sdkModel.appMetaData.url,
isVerified = session.securityStatus == CheckDAppResult.SAFE,
appSubtitle = session.sdkModel.appMetaData.description,
transaction = WcSignTransactionItemUM(
onDismiss = actions.onDismiss,
onSign = actions.onSign,
appInfo = WcTransactionAppInfoContentUM(
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,
@ -107,6 +110,7 @@ private fun WcMessageSignUseCase.messageSignToUM(
),
transactionRequestInfo = WcTransactionRequestInfoUM(
persistentListOf(createInfoBlockUM(rawSdkRequest, signModel)),
onCopy = actions.onCopy,
),
)