diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/bottomsheets/modal/TangemModalBottomSheet.kt b/core/ui/src/main/java/com/tangem/core/ui/components/bottomsheets/modal/TangemModalBottomSheet.kt index f97a4f5daf..ff085bffb5 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/bottomsheets/modal/TangemModalBottomSheet.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/bottomsheets/modal/TangemModalBottomSheet.kt @@ -145,8 +145,6 @@ inline fun 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 BasicModalBottomSheet( .clip(TangemTheme.shapes.roundedCornersLarge) .background(containerColor) .heightIn(max = maxHeight.dp) - .padding(bottom = bottomBarHeight) .fillMaxWidth(), ) { Box(modifier = Modifier.fillMaxWidth()) { diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/components/ConnectionsComponent.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/components/ConnectionsComponent.kt index 09c4b03ff5..79b63e953b 100644 --- a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/components/ConnectionsComponent.kt +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/components/ConnectionsComponent.kt @@ -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, + ), + ) + } } } \ No newline at end of file diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/components/WcAppInfoComponent.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/components/WcAppInfoComponent.kt index bba2e61463..87a06ece5b 100644 --- a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/components/WcAppInfoComponent.kt +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/components/WcAppInfoComponent.kt @@ -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) } \ No newline at end of file diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/components/WcAppInfoContainerComponent.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/components/WcAppInfoContainerComponent.kt new file mode 100644 index 0000000000..83f3853ca6 --- /dev/null +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/components/WcAppInfoContainerComponent.kt @@ -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() + 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( + 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) +} \ No newline at end of file diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/entity/WcAppInfoUM.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/entity/WcAppInfoUM.kt index a588d1ddd0..401b13e42d 100644 --- a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/entity/WcAppInfoUM.kt +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/entity/WcAppInfoUM.kt @@ -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) : WcNetworksInfo() } \ No newline at end of file diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/entity/WcPrimaryButtonConfig.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/entity/WcPrimaryButtonConfig.kt new file mode 100644 index 0000000000..8f549ebb8b --- /dev/null +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/entity/WcPrimaryButtonConfig.kt @@ -0,0 +1,3 @@ +package com.tangem.features.walletconnect.connections.entity + +data class WcPrimaryButtonConfig(val showProgress: Boolean, val enabled: Boolean, val onClick: () -> Unit) \ No newline at end of file diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/model/WcAppInfoModel.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/model/WcAppInfoModel.kt new file mode 100644 index 0000000000..cb7aa69d4a --- /dev/null +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/model/WcAppInfoModel.kt @@ -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 + field = MutableStateFlow(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), + ) + } +} \ No newline at end of file diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/model/WcConnectionsModel.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/model/WcConnectionsModel.kt index a0b6c6aa91..69216f06c3 100644 --- a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/model/WcConnectionsModel.kt +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/model/WcConnectionsModel.kt @@ -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 field = MutableStateFlow(getInitialState()) + val bottomSheetNavigation: SlotNavigation = 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) } diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/routes/WcAppInfoRoutes.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/routes/WcAppInfoRoutes.kt new file mode 100644 index 0000000000..8c0d1fcc2c --- /dev/null +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/routes/WcAppInfoRoutes.kt @@ -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() +} \ No newline at end of file diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/routes/WcConnectionsBottomSheetRoutes.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/routes/WcConnectionsBottomSheetRoutes.kt new file mode 100644 index 0000000000..66f2dc4f1e --- /dev/null +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/routes/WcConnectionsBottomSheetRoutes.kt @@ -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() +} \ No newline at end of file diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/ui/InternalComponents.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/ui/InternalComponents.kt index ca17e5f44f..2f583ee287 100644 --- a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/ui/InternalComponents.kt +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/ui/InternalComponents.kt @@ -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, ) diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/ui/WcAppInfoContent.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/ui/WcAppInfoContent.kt index 5ce783ebb7..540be9a66f 100644 --- a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/ui/WcAppInfoContent.kt +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/ui/WcAppInfoContent.kt @@ -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( - 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, 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( 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