Updated on 2026-08-14
This commit is contained in:
parent
e9512b1afe
commit
ecd02950fb
15 changed files with 796 additions and 0 deletions
|
|
@ -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>
|
||||
|
|
|
|||
19
core/ui/src/main/res/drawable/ic_doc_new_24.xml
Normal file
19
core/ui/src/main/res/drawable/ic_doc_new_24.xml
Normal 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>
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
|
|
@ -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,
|
||||
)
|
||||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -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),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -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 = {},
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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,
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
Loading…
Add table
Add a link
Reference in a new issue