Updated on 2026-08-14

This commit is contained in:
Tangem 2025-04-25 12:15:06 +05:00
parent 0dd5b23b64
commit e1f5d41f27
13 changed files with 447 additions and 76 deletions

View file

@ -145,8 +145,6 @@ inline fun <reified T : TangemBottomSheetConfigContent> BasicModalBottomSheet(
) {
val model = config.content as? T ?: return
val bottomBarHeight = with(LocalDensity.current) { WindowInsets.systemBars.getBottom(this).toDp() }
val bsContent: @Composable ColumnScope.() -> Unit = {
val maxHeight = LocalConfiguration.current.screenHeightDp * MODAL_SHEET_MAX_HEIGHT
@ -157,7 +155,6 @@ inline fun <reified T : TangemBottomSheetConfigContent> BasicModalBottomSheet(
.clip(TangemTheme.shapes.roundedCornersLarge)
.background(containerColor)
.heightIn(max = maxHeight.dp)
.padding(bottom = bottomBarHeight)
.fillMaxWidth(),
) {
Box(modifier = Modifier.fillMaxWidth()) {

View file

@ -4,10 +4,18 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.arkivanov.decompose.ComponentContext
import com.arkivanov.decompose.extensions.compose.subscribeAsState
import com.arkivanov.decompose.router.slot.childSlot
import com.arkivanov.decompose.router.slot.dismiss
import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.core.decompose.context.childByContext
import com.tangem.core.decompose.model.getOrCreateModel
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
import com.tangem.core.ui.decompose.ComposableContentComponent
import com.tangem.domain.walletconnect.usecase.pair.WcPairUseCase
import com.tangem.features.walletconnect.connections.model.WcConnectionsModel
import com.tangem.features.walletconnect.connections.routes.WcConnectionsBottomSheetRoutes
import com.tangem.features.walletconnect.connections.ui.WcConnectionsContent
internal class ConnectionsComponent(
@ -15,10 +23,35 @@ internal class ConnectionsComponent(
) : AppComponentContext by appComponentContext, ComposableContentComponent {
private val model: WcConnectionsModel = getOrCreateModel()
private val bottomSheetSlot = childSlot(
source = model.bottomSheetNavigation,
serializer = null,
handleBackButton = false,
childFactory = ::bottomSheetChild,
)
@Composable
override fun Content(modifier: Modifier) {
val state by model.uiState.collectAsStateWithLifecycle()
val bottomSheet by bottomSheetSlot.subscribeAsState()
WcConnectionsContent(modifier = modifier, state = state)
bottomSheet.child?.instance?.BottomSheet()
}
private fun bottomSheetChild(
config: WcConnectionsBottomSheetRoutes,
componentContext: ComponentContext,
): ComposableBottomSheetComponent {
return when (config) {
is WcConnectionsBottomSheetRoutes.AppInfo -> WcAppInfoContainerComponent(
appComponentContext = childByContext(componentContext),
params = WcAppInfoContainerComponent.Params(
wcUrl = config.wcUrl,
source = WcPairUseCase.Source.QR,
onDismiss = model.bottomSheetNavigation::dismiss,
),
)
}
}
}

View file

@ -1,31 +1,27 @@
package com.tangem.features.walletconnect.connections.components
import androidx.compose.foundation.layout.padding
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.ui.components.bottomsheets.TangemBottomSheetConfig
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
import com.tangem.core.ui.decompose.ComposableContentComponent
import com.tangem.core.ui.res.TangemTheme
import com.tangem.features.walletconnect.connections.model.WcAppInfoModel
import com.tangem.features.walletconnect.connections.ui.WcAppInfoModalBottomSheet
internal class WcAppInfoComponent(
private val appComponentContext: AppComponentContext,
private val params: Params,
) : AppComponentContext by appComponentContext, ComposableBottomSheetComponent {
override fun dismiss() {
params.onDismiss()
}
private val model: WcAppInfoModel,
) : AppComponentContext by appComponentContext, ComposableContentComponent {
@Composable
override fun BottomSheet() {
override fun Content(modifier: Modifier) {
val state by model.appInfoUiState.collectAsStateWithLifecycle()
WcAppInfoModalBottomSheet(
config = TangemBottomSheetConfig(
isShown = true,
onDismissRequest = ::dismiss,
content = TangemBottomSheetConfigContent.Empty, // todo(wc) will be fixed in next PR's
),
modifier = modifier.padding(horizontal = TangemTheme.dimens.spacing16),
state = state,
)
}
data class Params(val onDismiss: () -> Unit)
}

View file

@ -0,0 +1,107 @@
package com.tangem.features.walletconnect.connections.components
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import com.arkivanov.decompose.ComponentContext
import com.arkivanov.decompose.extensions.compose.stack.Children
import com.arkivanov.decompose.extensions.compose.stack.animation.stackAnimation
import com.arkivanov.decompose.extensions.compose.subscribeAsState
import com.arkivanov.decompose.router.stack.StackNavigation
import com.arkivanov.decompose.router.stack.childStack
import com.arkivanov.decompose.router.stack.pop
import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.core.decompose.context.childByContext
import com.tangem.core.decompose.model.getOrCreateModel
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.decompose.ComposableBottomSheetComponent
import com.tangem.core.ui.decompose.ComposableContentComponent
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.res.TangemTheme
import com.tangem.domain.walletconnect.usecase.pair.WcPairUseCase
import com.tangem.features.walletconnect.connections.model.WcAppInfoModel
import com.tangem.features.walletconnect.connections.routes.WcAppInfoRoutes
import com.tangem.features.walletconnect.impl.R
internal class WcAppInfoContainerComponent(
private val appComponentContext: AppComponentContext,
params: Params,
) : AppComponentContext by appComponentContext, ComposableBottomSheetComponent {
private val model: WcAppInfoModel = getOrCreateModel(params = params)
private val contentNavigation = StackNavigation<WcAppInfoRoutes>()
private val contentStack = childStack(
source = contentNavigation,
serializer = WcAppInfoRoutes.serializer(),
initialConfiguration = WcAppInfoRoutes.AppInfo,
childFactory = ::screenChild,
)
override fun dismiss() {
model.dismiss()
}
@Composable
override fun BottomSheet() {
val content by contentStack.subscribeAsState()
TangemModalBottomSheet<WcAppInfoRoutes>(
config = TangemBottomSheetConfig(
isShown = true,
onDismissRequest = ::dismiss,
content = content.active.configuration,
),
containerColor = TangemTheme.colors.background.tertiary,
title = { config -> Title(route = config) },
content = {
Children(stack = content, animation = stackAnimation()) { child ->
child.instance.Content(modifier = Modifier)
}
},
)
}
@Composable
private fun Title(route: WcAppInfoRoutes) {
TangemModalBottomSheetTitle(
title = resourceReference(R.string.wc_wallet_connect),
startIconRes = when (route) {
is WcAppInfoRoutes.AppInfo, is WcAppInfoRoutes.Alert -> null
is WcAppInfoRoutes.SelectNetworks, is WcAppInfoRoutes.SelectWallet -> R.drawable.ic_back_24
},
onStartClick = when (route) {
is WcAppInfoRoutes.AppInfo, is WcAppInfoRoutes.Alert -> null
is WcAppInfoRoutes.SelectNetworks, is WcAppInfoRoutes.SelectWallet -> ::contentBack
},
endIconRes = when (route) {
is WcAppInfoRoutes.AppInfo, is WcAppInfoRoutes.Alert -> R.drawable.ic_close_24
is WcAppInfoRoutes.SelectNetworks, is WcAppInfoRoutes.SelectWallet -> null
},
onEndClick = when (route) {
is WcAppInfoRoutes.AppInfo -> ::dismiss
is WcAppInfoRoutes.Alert -> ::contentBack
is WcAppInfoRoutes.SelectNetworks,
is WcAppInfoRoutes.SelectWallet,
-> null
},
)
}
private fun contentBack() {
contentNavigation.pop()
}
private fun screenChild(config: WcAppInfoRoutes, componentContext: ComponentContext): ComposableContentComponent =
when (config) {
is WcAppInfoRoutes.AppInfo -> WcAppInfoComponent(
appComponentContext = childByContext(componentContext),
model = model,
)
is WcAppInfoRoutes.Alert -> TODO()
WcAppInfoRoutes.SelectNetworks -> TODO()
WcAppInfoRoutes.SelectWallet -> TODO()
}
data class Params(val wcUrl: String, val source: WcPairUseCase.Source, val onDismiss: () -> Unit)
}

View file

@ -6,20 +6,31 @@ import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
import kotlinx.collections.immutable.ImmutableList
@Immutable
internal data class WcAppInfoUM(
val appName: String,
val appIcon: String,
val isVerified: Boolean,
val appSubtitle: String,
val notificationUM: NotificationUM?,
val walletName: String,
val networksInfo: WcNetworksInfo,
val onDismiss: () -> Unit,
val onConnect: () -> Unit,
) : TangemBottomSheetConfigContent
internal sealed class WcAppInfoUM : TangemBottomSheetConfigContent {
abstract val onDismiss: () -> Unit
abstract val connectButtonConfig: WcPrimaryButtonConfig
data class Loading(
override val onDismiss: () -> Unit,
override val connectButtonConfig: WcPrimaryButtonConfig,
) : WcAppInfoUM()
data class Content(
val appName: String,
val appIcon: String,
val isVerified: Boolean,
val appSubtitle: String,
val notificationUM: NotificationUM?,
val walletName: String,
val networksInfo: WcNetworksInfo,
override val connectButtonConfig: WcPrimaryButtonConfig,
override val onDismiss: () -> Unit,
) : WcAppInfoUM()
}
@Immutable
internal sealed class WcNetworksInfo {
data class MissingRequiredNetworkInfo(val network: String) : WcNetworksInfo()
data class MissingRequiredNetworkInfo(val networks: String) : WcNetworksInfo()
data class ContainsAllRequiredNetworks(val icons: ImmutableList<Int>) : WcNetworksInfo()
}

View file

@ -0,0 +1,3 @@
package com.tangem.features.walletconnect.connections.entity
data class WcPrimaryButtonConfig(val showProgress: Boolean, val enabled: Boolean, val onClick: () -> Unit)

View file

@ -0,0 +1,40 @@
package com.tangem.features.walletconnect.connections.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.features.walletconnect.connections.components.WcAppInfoContainerComponent
import com.tangem.features.walletconnect.connections.entity.WcAppInfoUM
import com.tangem.features.walletconnect.connections.entity.WcPrimaryButtonConfig
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import javax.inject.Inject
@Stable
@ModelScoped
internal class WcAppInfoModel @Inject constructor(
override val dispatchers: CoroutineDispatcherProvider,
paramsContainer: ParamsContainer,
) : Model() {
private val params: WcAppInfoContainerComponent.Params = paramsContainer.require()
val appInfoUiState: StateFlow<WcAppInfoUM>
field = MutableStateFlow<WcAppInfoUM>(createLoadingState())
fun dismiss() {
params.onDismiss()
}
private fun onConnect() {
// TODO: [REDACTED_JIRA]
}
private fun createLoadingState(): WcAppInfoUM.Loading {
return WcAppInfoUM.Loading(
onDismiss = ::dismiss,
connectButtonConfig = WcPrimaryButtonConfig(showProgress = false, enabled = false, onClick = ::onConnect),
)
}
}

View file

@ -1,6 +1,8 @@
package com.tangem.features.walletconnect.connections.model
import arrow.core.getOrElse
import com.arkivanov.decompose.router.slot.SlotNavigation
import com.arkivanov.decompose.router.slot.activate
import com.tangem.common.routing.AppRoute
import com.tangem.core.decompose.di.ModelScoped
import com.tangem.core.decompose.model.Model
@ -18,6 +20,7 @@ import com.tangem.domain.walletconnect.usecase.WcSessionsUseCase
import com.tangem.features.walletconnect.connections.entity.WcConnectionsState
import com.tangem.features.walletconnect.connections.entity.WcConnectionsTopAppBarConfig
import com.tangem.features.walletconnect.connections.model.transformers.WcSessionsTransformer
import com.tangem.features.walletconnect.connections.routes.WcConnectionsBottomSheetRoutes
import com.tangem.features.walletconnect.impl.R
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import com.tangem.utils.transformer.update
@ -37,6 +40,7 @@ internal class WcConnectionsModel @Inject constructor(
val uiState: StateFlow<WcConnectionsState>
field = MutableStateFlow<WcConnectionsState>(getInitialState())
val bottomSheetNavigation: SlotNavigation<WcConnectionsBottomSheetRoutes> = SlotNavigation()
init {
listenQrUpdates()
@ -46,10 +50,7 @@ internal class WcConnectionsModel @Inject constructor(
private fun listenQrUpdates() {
listenToQrScanningUseCase(SourceType.WALLET_CONNECT)
.getOrElse { emptyFlow() }
.onEach {
// TODO: [REDACTED_JIRA]
Timber.d(it)
}
.onEach { wcUrl -> bottomSheetNavigation.activate(WcConnectionsBottomSheetRoutes.AppInfo(wcUrl)) }
.launchIn(modelScope)
}

View file

@ -0,0 +1,15 @@
package com.tangem.features.walletconnect.connections.routes
import androidx.compose.runtime.Immutable
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
import com.tangem.features.walletconnect.connections.components.AlertsComponent
import kotlinx.serialization.Serializable
@Serializable
@Immutable
internal sealed class WcAppInfoRoutes : TangemBottomSheetConfigContent {
data object AppInfo : WcAppInfoRoutes()
data object SelectWallet : WcAppInfoRoutes()
data object SelectNetworks : WcAppInfoRoutes()
data class Alert(val alertType: AlertsComponent.AlertType) : WcAppInfoRoutes()
}

View file

@ -0,0 +1,9 @@
package com.tangem.features.walletconnect.connections.routes
import kotlinx.serialization.Serializable
@Serializable
internal sealed class WcConnectionsBottomSheetRoutes {
@Serializable
data class AppInfo(val wcUrl: String) : WcConnectionsBottomSheetRoutes()
}

View file

@ -1,6 +1,5 @@
package com.tangem.features.walletconnect.connections.ui
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Icon
@ -31,8 +30,7 @@ internal fun WcAppInfoItem(
AsyncImage(
modifier = Modifier
.size(TangemTheme.dimens.size48)
.clip(RoundedCornerShape(TangemTheme.dimens.radius8))
.background(Color.Black),
.clip(RoundedCornerShape(TangemTheme.dimens.radius8)),
model = iconUrl,
contentDescription = title,
)

View file

@ -9,6 +9,7 @@ import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
@ -17,6 +18,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.StrokeCap
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource
@ -27,11 +29,7 @@ import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
import androidx.compose.ui.unit.dp
import com.tangem.common.ui.notifications.NotificationUM
import com.tangem.core.ui.components.PrimaryButton
import com.tangem.core.ui.components.SecondaryButton
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.components.*
import com.tangem.core.ui.components.notifications.Notification
import com.tangem.core.ui.components.notifications.NotificationConfig
import com.tangem.core.ui.extensions.resourceReference
@ -41,29 +39,23 @@ import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.features.walletconnect.connections.entity.WcAppInfoUM
import com.tangem.features.walletconnect.connections.entity.WcNetworksInfo
import com.tangem.features.walletconnect.connections.entity.WcPrimaryButtonConfig
import com.tangem.features.walletconnect.impl.R
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
@Composable
internal fun WcAppInfoModalBottomSheet(config: TangemBottomSheetConfig) {
TangemModalBottomSheet<WcAppInfoUM>(
config = config,
containerColor = TangemTheme.colors.background.tertiary,
title = { state ->
TangemModalBottomSheetTitle(
title = resourceReference(R.string.wc_wallet_connect),
endIconRes = R.drawable.ic_close_24,
onEndClick = state.onDismiss,
)
},
content = { state -> WcAppInfoModalBottomSheetContent(state) },
)
internal fun WcAppInfoModalBottomSheet(state: WcAppInfoUM, modifier: Modifier = Modifier) {
when (state) {
is WcAppInfoUM.Content -> WcAppInfoModalBottomSheetContent(state, modifier)
is WcAppInfoUM.Loading -> WcAppInfoModalBottomSheetLoading(state, modifier)
}
}
// region Content state
@Composable
private fun WcAppInfoModalBottomSheetContent(state: WcAppInfoUM) {
Column(modifier = Modifier.padding(horizontal = TangemTheme.dimens.spacing16)) {
private fun WcAppInfoModalBottomSheetContent(state: WcAppInfoUM.Content, modifier: Modifier = Modifier) {
Column(modifier = modifier) {
val blocksModifier = Modifier
.clip(RoundedCornerShape(TangemTheme.dimens.radius14))
.background(color = TangemTheme.colors.background.action)
@ -85,13 +77,13 @@ private fun WcAppInfoModalBottomSheetContent(state: WcAppInfoUM) {
WcAppInfoButtons(
modifier = Modifier.padding(vertical = TangemTheme.dimens.spacing16),
onDismiss = state.onDismiss,
onConnect = state.onConnect,
connectButtonConfig = state.connectButtonConfig,
)
}
}
@Composable
private fun WcAppInfoFirstBlock(state: WcAppInfoUM, modifier: Modifier = Modifier) {
private fun WcAppInfoFirstBlock(state: WcAppInfoUM.Content, modifier: Modifier = Modifier) {
var connectionRequestExpanded by remember { mutableStateOf(false) }
Column(modifier = modifier.animateContentSize()) {
WcAppInfoItem(
@ -213,7 +205,7 @@ private fun ConnectionRequestDescriptionRow(
}
@Composable
private fun WcAppInfoSecondBlock(state: WcAppInfoUM, modifier: Modifier = Modifier) {
private fun WcAppInfoSecondBlock(state: WcAppInfoUM.Content, modifier: Modifier = Modifier) {
Column(modifier = modifier) {
val itemsModifier = Modifier
.fillMaxWidth()
@ -234,7 +226,7 @@ private fun WcAppInfoSecondBlock(state: WcAppInfoUM, modifier: Modifier = Modifi
title = resourceReference(R.string.wc_missing_required_network_title),
subtitle = resourceReference(
R.string.wc_missing_required_network_description,
wrappedList(state.networksInfo.network),
wrappedList(state.networksInfo.networks),
),
),
iconTint = TangemTheme.colors.icon.attention,
@ -374,7 +366,11 @@ private fun NetworkIcons(icons: ImmutableList<Int>, modifier: Modifier = Modifie
}
@Composable
private fun WcAppInfoButtons(onDismiss: () -> Unit, onConnect: () -> Unit, modifier: Modifier = Modifier) {
private fun WcAppInfoButtons(
onDismiss: () -> Unit,
connectButtonConfig: WcPrimaryButtonConfig,
modifier: Modifier = Modifier,
) {
Row(modifier = modifier, horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing8)) {
SecondaryButton(
modifier = Modifier
@ -388,7 +384,166 @@ private fun WcAppInfoButtons(onDismiss: () -> Unit, onConnect: () -> Unit, modif
.fillMaxWidth()
.weight(1f),
text = stringResourceSafe(R.string.wc_common_connect),
onClick = onConnect,
onClick = connectButtonConfig.onClick,
showProgress = connectButtonConfig.showProgress,
enabled = connectButtonConfig.enabled,
)
}
}
// endregion
// region Loading state
@Composable
private fun WcAppInfoModalBottomSheetLoading(state: WcAppInfoUM.Loading, modifier: Modifier = Modifier) {
Column(modifier = modifier) {
val blocksModifier = Modifier
.clip(RoundedCornerShape(TangemTheme.dimens.radius14))
.background(color = TangemTheme.colors.background.action)
.fillMaxWidth()
WcAppInfoFirstLoadingBlock(blocksModifier)
WcAppInfoSecondLoadingBlock(
modifier = Modifier
.padding(top = 14.dp)
.then(blocksModifier),
)
WcAppInfoButtons(
modifier = Modifier.padding(vertical = TangemTheme.dimens.spacing16),
onDismiss = state.onDismiss,
connectButtonConfig = state.connectButtonConfig,
)
}
}
@Composable
private fun WcAppInfoFirstLoadingBlock(modifier: Modifier = Modifier) {
Column(modifier = modifier) {
WcLoadingAppInfoItem()
HorizontalDivider(thickness = 1.dp, color = TangemTheme.colors.stroke.primary)
Row(
modifier = Modifier.padding(all = 12.dp),
horizontalArrangement = Arrangement.spacedBy(8.dp),
verticalAlignment = Alignment.CenterVertically,
) {
CircularProgressIndicator(
modifier = Modifier.size(24.dp),
color = TangemTheme.colors.icon.accent,
strokeWidth = 2.dp,
strokeCap = StrokeCap.Square,
)
Text(
text = "Connecting...",
style = TangemTheme.typography.body1,
color = TangemTheme.colors.text.primary1,
)
}
}
}
@Composable
private fun WcAppInfoSecondLoadingBlock(modifier: Modifier = Modifier) {
Column(modifier) {
Row(modifier = Modifier.padding(all = 12.dp), verticalAlignment = Alignment.CenterVertically) {
Icon(
modifier = Modifier.size(24.dp),
painter = painterResource(R.drawable.ic_wallet_new_24),
contentDescription = null,
tint = TangemTheme.colors.icon.accent,
)
Text(
modifier = Modifier
.padding(start = 8.dp)
.weight(1f),
text = stringResourceSafe(R.string.wc_common_wallet),
style = TangemTheme.typography.body1,
color = TangemTheme.colors.text.primary1,
)
TextShimmer(style = TangemTheme.typography.body1, radius = 8.dp, text = "Wallet 2.0")
}
HorizontalDivider(thickness = 1.dp, color = TangemTheme.colors.stroke.primary)
Row(modifier = Modifier.padding(all = 12.dp), verticalAlignment = Alignment.CenterVertically) {
Icon(
modifier = Modifier.size(24.dp),
painter = painterResource(R.drawable.ic_network_new_24),
contentDescription = null,
tint = TangemTheme.colors.icon.accent,
)
Text(
modifier = Modifier
.padding(start = 8.dp)
.weight(1f),
text = stringResourceSafe(R.string.wc_common_networks),
style = TangemTheme.typography.body1,
color = TangemTheme.colors.text.primary1,
)
WcAppInfoLoadingNetworkIcons()
}
}
}
@Suppress("MagicNumber")
@Composable
private fun WcAppInfoLoadingNetworkIcons(modifier: Modifier = Modifier) {
Box(modifier = modifier.wrapContentWidth()) {
for (index in 0..3) {
CircleShimmer(
modifier = Modifier
.padding(start = TangemTheme.dimens.spacing16.times(index))
.border(
width = 2.dp,
color = TangemTheme.colors.background.action,
shape = CircleShape,
)
.padding(2.dp)
.clip(CircleShape)
.size(20.dp),
)
}
}
}
@Composable
private fun WcLoadingAppInfoItem(modifier: Modifier = Modifier) {
Row(
modifier = modifier.padding(TangemTheme.dimens.spacing12),
horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing16),
) {
RectangleShimmer(modifier = Modifier.size(TangemTheme.dimens.size48), radius = 16.dp)
Column(
modifier = Modifier.fillMaxWidth(),
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing4),
) {
TextShimmer(
modifier = Modifier
.width(106.dp)
.height(24.dp),
style = TangemTheme.typography.h3,
radius = 8.dp,
)
TextShimmer(
modifier = Modifier
.width(168.dp)
.height(20.dp),
style = TangemTheme.typography.body2,
radius = 8.dp,
)
}
}
}
// endregion
@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 WcAppInfoBottomSheetPreview() {
TangemThemePreview {
WcAppInfoModalBottomSheetLoading(
state = WcAppInfoUM.Loading(
onDismiss = {},
WcPrimaryButtonConfig(showProgress = false, enabled = false, onClick = {}),
),
modifier = Modifier
.background(TangemTheme.colors.background.tertiary)
.padding(horizontal = TangemTheme.dimens.spacing16),
)
}
}
@ -396,21 +551,21 @@ private fun WcAppInfoButtons(onDismiss: () -> Unit, onConnect: () -> Unit, modif
@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 WcAppInfoBottomSheetPreview(@PreviewParameter(WcAppInfoStateProvider::class) state: WcAppInfoUM) {
private fun WcAppInfoBottomSheetPreview(@PreviewParameter(WcAppInfoStateProvider::class) state: WcAppInfoUM.Content) {
TangemThemePreview {
WcAppInfoModalBottomSheet(
config = TangemBottomSheetConfig(
isShown = true,
onDismissRequest = {},
content = state,
),
state = state,
modifier = Modifier
.background(TangemTheme.colors.background.tertiary)
.padding(horizontal = TangemTheme.dimens.spacing16),
)
}
}
private class WcAppInfoStateProvider : CollectionPreviewParameterProvider<WcAppInfoUM>(
collection = listOf(
WcAppInfoUM(
WcAppInfoUM.Loading(onDismiss = {}, WcPrimaryButtonConfig(showProgress = false, enabled = false, onClick = {})),
WcAppInfoUM.Content(
appName = "React App",
appIcon = "",
isVerified = true,
@ -427,9 +582,9 @@ private class WcAppInfoStateProvider : CollectionPreviewParameterProvider<WcAppI
),
),
onDismiss = {},
onConnect = {},
connectButtonConfig = WcPrimaryButtonConfig(showProgress = false, enabled = true, onClick = {}),
),
WcAppInfoUM(
WcAppInfoUM.Content(
appName = "React App",
appIcon = "",
isVerified = false,
@ -439,9 +594,9 @@ private class WcAppInfoStateProvider : CollectionPreviewParameterProvider<WcAppI
subtitle = resourceReference(R.string.wc_alert_domain_issues_description),
),
walletName = "Tangem 2.0",
networksInfo = WcNetworksInfo.MissingRequiredNetworkInfo(network = "Solana"),
networksInfo = WcNetworksInfo.MissingRequiredNetworkInfo(networks = "Solana"),
onDismiss = {},
onConnect = {},
connectButtonConfig = WcPrimaryButtonConfig(showProgress = false, enabled = true, onClick = {}),
),
),
)

View file

@ -2,6 +2,7 @@ package com.tangem.features.walletconnect.di
import com.tangem.core.decompose.di.ModelComponent
import com.tangem.core.decompose.model.Model
import com.tangem.features.walletconnect.connections.model.WcAppInfoModel
import com.tangem.features.walletconnect.connections.model.WcConnectionsModel
import dagger.Binds
import dagger.Module
@ -17,4 +18,9 @@ internal interface WalletConnectModelModule {
@IntoMap
@ClassKey(WcConnectionsModel::class)
fun bindWcConnectionsModel(model: WcConnectionsModel): Model
@Binds
@IntoMap
@ClassKey(WcAppInfoModel::class)
fun bindWcAppInfoModel(model: WcAppInfoModel): Model
}