Updated on 2026-08-14

This commit is contained in:
Tangem 2026-06-24 01:21:15 -07:00
parent f3192b6d27
commit 285bed34a4
15 changed files with 694 additions and 4 deletions

View file

@ -9,4 +9,13 @@ android {
}
dependencies {
/** Core */
api(projects.core.decompose)
api(projects.core.ui)
/** Domain */
api(projects.domain.models)
/** Compose */
implementation(deps.compose.runtime)
}

View file

@ -0,0 +1,14 @@
package com.tangem.features.virtualaccount.details.component
import com.tangem.core.decompose.factory.ComponentFactory
import com.tangem.core.ui.decompose.ComposableContentComponent
import com.tangem.domain.models.wallet.UserWalletId
interface VirtualAccountMainComponent : ComposableContentComponent {
data class Params(
val userWalletId: UserWalletId,
)
interface Factory : ComponentFactory<Params, VirtualAccountMainComponent>
}

View file

@ -11,11 +11,25 @@ android {
}
dependencies {
/** Core */
implementation(projects.core.configToggles)
implementation(projects.core.decompose)
implementation(projects.core.res)
implementation(projects.core.ui)
implementation(projects.core.utils)
/** Domain */
implementation(projects.domain.models)
/** Features */
implementation(projects.features.virtualAccounts.details.api)
implementation(projects.core.configToggles)
implementation(deps.compose.runtime)
/** Compose */
implementation(deps.compose.foundation)
implementation(deps.compose.material3)
implementation(deps.compose.ui)
implementation(deps.compose.ui.tooling)
implementation(deps.decompose.ext.compose)
/** DI */
implementation(deps.hilt.android)

View file

@ -0,0 +1,115 @@
package com.tangem.features.virtualaccount.common.ui
import android.content.res.Configuration
import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.core.tween
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.togetherWith
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.text.TextAutoSize
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.tangem.core.ui.components.text.applyBladeBrush
import com.tangem.core.ui.ds2.shimmers.TextShimmer
import com.tangem.core.ui.ds2.shimmers.TextShimmerStyle
import com.tangem.core.ui.extensions.*
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreviewRedesign
import com.tangem.utils.StringsSigns.DASH_SIGN
@Composable
fun TangemBalanceHeader(
state: TangemBalanceHeaderState,
label: TextReference,
modifier: Modifier = Modifier,
balanceModifier: Modifier = Modifier,
) {
Column(
modifier = modifier,
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens2.x2),
) {
AnimatedContent(
targetState = state,
label = "Updating the balance",
transitionSpec = {
fadeIn(animationSpec = tween(durationMillis = 220, delayMillis = 90)) togetherWith
fadeOut(animationSpec = tween(durationMillis = 90))
},
) { animatedState ->
when (animatedState) {
is TangemBalanceHeaderState.Loading -> TextShimmer(
modifier = Modifier.size(width = 160.dp, height = 56.dp),
text = "1234.00",
style = TextShimmerStyle.HEADING_MEDIUM,
radius = TangemTheme.dimens2.x25,
)
is TangemBalanceHeaderState.Content -> Text(
modifier = balanceModifier,
text = animatedState.balance
.orMaskWithStars(animatedState.isBalanceHidden)
.resolveAnnotatedReference(),
style = TangemTheme.typography3.display.medium.applyBladeBrush(
isEnabled = animatedState.isFlickering,
textColor = TangemTheme.colors3.text.primary,
),
color = TangemTheme.colors3.text.primary,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
autoSize = TextAutoSize.StepBased(
minFontSize = TangemTheme.typography3.heading.medium.fontSize,
maxFontSize = TangemTheme.typography3.display.medium.fontSize,
),
)
is TangemBalanceHeaderState.Error -> Text(
modifier = balanceModifier,
text = DASH_SIGN,
style = TangemTheme.typography3.display.medium,
color = TangemTheme.colors3.text.primary,
)
}
}
Text(
modifier = Modifier.padding(vertical = TangemTheme.dimens2.x1),
text = label.resolveReference(),
color = TangemTheme.colors3.text.secondary,
style = TangemTheme.typography3.caption.medium,
)
}
}
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
private fun TangemBalanceHeaderPreview() {
TangemThemePreviewRedesign {
Column(
modifier = Modifier.fillMaxWidth(),
verticalArrangement = Arrangement.spacedBy(16.dp),
) {
TangemBalanceHeader(
modifier = Modifier.fillMaxWidth(),
state = TangemBalanceHeaderState.Content(
balance = stringReference("$0.00"),
isBalanceHidden = false,
),
label = stringReference("Total balance"),
)
TangemBalanceHeader(
modifier = Modifier.fillMaxWidth(),
state = TangemBalanceHeaderState.Loading,
label = stringReference("Total balance"),
)
TangemBalanceHeader(
modifier = Modifier.fillMaxWidth(),
state = TangemBalanceHeaderState.Error,
label = stringReference("Total balance"),
)
}
}
}

View file

@ -0,0 +1,18 @@
package com.tangem.features.virtualaccount.common.ui
import androidx.compose.runtime.Immutable
import com.tangem.core.ui.extensions.TextReference
@Immutable
sealed interface TangemBalanceHeaderState {
data object Loading : TangemBalanceHeaderState
data class Content(
val balance: TextReference,
val isBalanceHidden: Boolean,
val isFlickering: Boolean = false,
) : TangemBalanceHeaderState
data object Error : TangemBalanceHeaderState
}

View file

@ -0,0 +1,70 @@
package com.tangem.features.virtualaccount.common.ui
import android.content.res.Configuration
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.text.TextAutoSize
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import com.tangem.core.ui.ds.image.TangemIconUM
import com.tangem.core.ui.ds2.button.TangemButton
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resolveAnnotatedReference
import com.tangem.core.ui.extensions.stringReference
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreviewRedesign
import com.tangem.core.ui.res.generated.icons.Icons
import com.tangem.core.ui.res.generated.icons.ic_arrow_down_24
@Composable
fun TangemCircleActionButton(
title: TextReference,
icon: TangemIconUM,
onClick: () -> Unit,
modifier: Modifier = Modifier,
isEnabled: Boolean = true,
isLoading: Boolean = false,
) {
Column(
modifier = modifier,
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens2.x2),
horizontalAlignment = Alignment.CenterHorizontally,
) {
TangemButton(
variant = TangemButton.Variant.Material,
size = TangemButton.Size.X14,
onClick = onClick,
iconStart = icon,
isLoading = isLoading,
isEnabled = isEnabled,
)
Text(
text = title.resolveAnnotatedReference(),
style = TangemTheme.typography3.subheading.medium,
color = TangemTheme.colors3.text.primary,
autoSize = TextAutoSize.StepBased(
minFontSize = TangemTheme.typography3.caption.medium.fontSize,
maxFontSize = TangemTheme.typography3.subheading.medium.fontSize,
),
maxLines = 1,
)
}
}
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
private fun TangemCircleActionButtonPreview() {
TangemThemePreviewRedesign {
TangemCircleActionButton(
title = stringReference("Action"),
icon = TangemIconUM.Icon(
imageVector = Icons.ic_arrow_down_24,
tintReference = { TangemTheme.colors3.icon.primary },
),
onClick = {},
)
}
}

View file

@ -0,0 +1,73 @@
package com.tangem.features.virtualaccount.common.ui
import android.content.res.Configuration
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
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.graphics.vector.ImageVector
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resolveReference
import com.tangem.core.ui.extensions.stringReference
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreviewRedesign
import com.tangem.core.ui.res.generated.icons.Icons
import com.tangem.core.ui.res.generated.icons.ic_binoculars_20
@Composable
fun TangemEmptyState(
icon: ImageVector,
text: TextReference,
modifier: Modifier = Modifier,
iconModifier: Modifier = Modifier,
textModifier: Modifier = Modifier,
) {
Column(
modifier = modifier,
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens2.x3, Alignment.CenterVertically),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Icon(
modifier = Modifier
.size(TangemTheme.dimens2.x10)
.background(
color = TangemTheme.colors3.bg.opaque.primary,
shape = CircleShape,
)
.padding(10.dp)
.then(iconModifier),
imageVector = icon,
tint = TangemTheme.colors3.icon.secondary,
contentDescription = null,
)
Text(
modifier = textModifier,
textAlign = TextAlign.Center,
text = text.resolveReference(),
style = TangemTheme.typography3.caption.medium,
color = TangemTheme.colors3.text.secondary,
)
}
}
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
private fun TangemEmptyStatePreview() {
TangemThemePreviewRedesign {
TangemEmptyState(
icon = Icons.ic_binoculars_20,
text = stringReference("No transactions yet\nStart spending and see history here"),
)
}
}

View file

@ -11,7 +11,7 @@ import javax.inject.Singleton
@Module
@InstallIn(SingletonComponent::class)
internal object VirtualAccountDetailsModule {
internal object VirtualAccountMainModule {
@Provides
@Singleton

View file

@ -0,0 +1,34 @@
package com.tangem.features.virtualaccount.main
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.features.virtualaccount.details.component.VirtualAccountMainComponent
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
internal class DefaultVirtualAccountMainComponent @AssistedInject constructor(
@Assisted appComponentContext: AppComponentContext,
@Assisted params: VirtualAccountMainComponent.Params,
) : VirtualAccountMainComponent, AppComponentContext by appComponentContext {
private val model: VirtualAccountMainModel = getOrCreateModel(params = params)
@Composable
override fun Content(modifier: Modifier) {
val state by model.uiState.collectAsStateWithLifecycle()
VirtualAccountMainScreen(state = state, modifier = modifier)
}
@AssistedFactory
interface Factory : VirtualAccountMainComponent.Factory {
override fun create(
context: AppComponentContext,
params: VirtualAccountMainComponent.Params,
): DefaultVirtualAccountMainComponent
}
}

View file

@ -0,0 +1,46 @@
package com.tangem.features.virtualaccount.main
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.extensions.resourceReference
import com.tangem.core.ui.extensions.stringReference
import com.tangem.features.virtualaccount.details.component.VirtualAccountMainComponent
import com.tangem.features.virtualaccount.details.impl.R
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import javax.inject.Inject
@Stable
@ModelScoped
internal class VirtualAccountMainModel @Inject constructor(
paramsContainer: ParamsContainer,
override val dispatchers: CoroutineDispatcherProvider,
private val router: Router,
) : Model() {
@Suppress("UnusedPrivateProperty")
private val params = paramsContainer.require<VirtualAccountMainComponent.Params>()
val uiState: StateFlow<VirtualAccountMainUM>
field = MutableStateFlow(
createInitialState(),
)
private fun createInitialState(): VirtualAccountMainUM = VirtualAccountMainUM(
title = resourceReference(R.string.virtual_account_title),
subtitle = resourceReference(R.string.tangempay_usdc_on_polygon_network),
balance = VirtualAccountBalanceBlockState.Content(
fiatBalance = stringReference("$0.00"),
isBalanceFlickering = false,
),
isBalanceHidden = false,
onBackClick = { router.pop() },
onMenuClick = {},
onAddFundsClick = {},
onSendClick = {},
)
}

View file

@ -0,0 +1,229 @@
package com.tangem.features.virtualaccount.main
import android.content.res.Configuration
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.onSizeChanged
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.tooling.preview.Devices
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import com.tangem.core.ui.components.SpacerH24
import com.tangem.core.ui.components.topFade
import com.tangem.core.ui.ds.image.TangemIconUM
import com.tangem.core.ui.ds.topbar.TangemTopBar
import com.tangem.core.ui.ds2.button.TangemButton
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringReference
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreviewRedesign
import com.tangem.core.ui.res.generated.icons.*
import com.tangem.features.virtualaccount.common.ui.TangemBalanceHeader
import com.tangem.features.virtualaccount.common.ui.TangemBalanceHeaderState
import com.tangem.features.virtualaccount.common.ui.TangemCircleActionButton
import com.tangem.features.virtualaccount.common.ui.TangemEmptyState
import com.tangem.features.virtualaccount.details.impl.R
import com.tangem.core.ui.R as CoreUiR
private val InitialTopBarHeight: Dp = 64.dp
private const val TOP_FADE_MID_STOP = 0.8f
private const val TOP_FADE_MID_ALPHA = 0.8f
@Composable
internal fun VirtualAccountMainScreen(state: VirtualAccountMainUM, modifier: Modifier = Modifier) {
val listState = rememberLazyListState()
val density = LocalDensity.current
val statusBarHeight = with(density) { WindowInsets.systemBars.getTop(this).toDp() }
val bottomBarHeight = with(density) { WindowInsets.systemBars.getBottom(this).toDp() }
var topBarTotalHeight by remember { mutableStateOf(InitialTopBarHeight + statusBarHeight) }
val rootBackground = TangemTheme.colors3.bg.primary
Box(
modifier = modifier
.fillMaxSize()
.background(rootBackground),
) {
LazyColumn(
modifier = Modifier
.fillMaxSize()
.topFade(
height = topBarTotalHeight,
0f to rootBackground,
TOP_FADE_MID_STOP to rootBackground.copy(alpha = TOP_FADE_MID_ALPHA),
1f to Color.Transparent,
),
horizontalAlignment = Alignment.CenterHorizontally,
state = listState,
contentPadding = PaddingValues(
top = topBarTotalHeight,
bottom = TangemTheme.dimens2.x4 + bottomBarHeight,
),
) {
body(
state = state,
listState = listState,
)
}
TopBar(
state = state,
onHeightChange = { measuredHeight ->
if (topBarTotalHeight != measuredHeight) topBarTotalHeight = measuredHeight
},
)
}
}
private fun LazyListScope.body(state: VirtualAccountMainUM, listState: LazyListState) {
item("balanceBlock") {
BalanceBlock(
state = state.balance,
isBalanceHidden = state.isBalanceHidden,
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = TangemTheme.dimens2.x4)
.padding(top = TangemTheme.dimens2.x12),
)
}
item("actionButtonsBlock") {
SpacerH24()
ActionBlock(state = state)
}
item("emptyTransactions") {
SpacerH24()
TangemEmptyState(
icon = Icons.ic_binoculars_20,
text = resourceReference(R.string.virtual_account_transactions_empty),
modifier = Modifier
.heightIn(min = rememberRemainingViewportHeight(listState, "emptyTransactions"))
.fillMaxWidth()
.padding(horizontal = TangemTheme.dimens2.x4, vertical = TangemTheme.dimens2.x3),
)
}
}
@Composable
private fun BalanceBlock(
state: VirtualAccountBalanceBlockState,
isBalanceHidden: Boolean,
modifier: Modifier = Modifier,
) {
TangemBalanceHeader(
state = when (state) {
is VirtualAccountBalanceBlockState.Loading -> TangemBalanceHeaderState.Loading
is VirtualAccountBalanceBlockState.Content -> TangemBalanceHeaderState.Content(
balance = state.fiatBalance,
isFlickering = state.isBalanceFlickering,
isBalanceHidden = isBalanceHidden,
)
is VirtualAccountBalanceBlockState.Error -> TangemBalanceHeaderState.Error
},
label = resourceReference(R.string.token_details_balance_total),
modifier = modifier,
)
}
@Composable
private fun LazyItemScope.ActionBlock(state: VirtualAccountMainUM, modifier: Modifier = Modifier) {
Row(
modifier = modifier.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.Center,
) {
TangemCircleActionButton(
modifier = Modifier.padding(horizontal = TangemTheme.dimens2.x4),
title = resourceReference(R.string.common_add_funds),
icon = TangemIconUM.Icon(
imageVector = Icons.ic_arrow_down_24,
tintReference = { TangemTheme.colors3.icon.primary },
),
onClick = state.onAddFundsClick,
)
TangemCircleActionButton(
modifier = Modifier.padding(horizontal = TangemTheme.dimens2.x4),
title = resourceReference(R.string.common_send),
icon = TangemIconUM.Icon(
imageVector = Icons.ic_arrow_up_24,
tintReference = { TangemTheme.colors3.icon.primary },
),
onClick = state.onSendClick,
)
}
}
@Composable
private fun TopBar(state: VirtualAccountMainUM, onHeightChange: (Dp) -> Unit, modifier: Modifier = Modifier) {
val density = LocalDensity.current
TangemTopBar(
modifier = modifier
.onSizeChanged { size -> onHeightChange(with(density) { size.height.toDp() }) }
.statusBarsPadding(),
title = state.title,
subtitle = state.subtitle,
startContent = {
TangemButton(
iconStart = TangemIconUM.Icon(iconRes = CoreUiR.drawable.ic_arrow_back_28),
onClick = state.onBackClick,
size = TangemButton.Size.X11,
variant = TangemButton.Variant.Material,
)
},
endContent = {
TangemButton(
iconStart = TangemIconUM.Icon(imageVector = Icons.ic_dots_vertical_24),
onClick = state.onMenuClick,
size = TangemButton.Size.X11,
variant = TangemButton.Variant.Material,
)
},
)
}
/**
* Computes the height left between the top of the item identified by [itemKey] and the bottom of the
* list's viewport (excluding bottom content padding). Returns `0.dp` until the item has been laid out.
*
* The item's own height does not affect its offset (only the items above it do), so reading the offset
* back to size the item is stable and does not loop.
*/
@Composable
private fun rememberRemainingViewportHeight(listState: LazyListState, itemKey: Any): Dp {
val density = LocalDensity.current
val remainingPx by remember(listState, itemKey) {
derivedStateOf {
val info = listState.layoutInfo
val item = info.visibleItemsInfo.firstOrNull { it.key == itemKey }
?: return@derivedStateOf 0
(info.viewportEndOffset - info.afterContentPadding - item.offset).coerceAtLeast(minimumValue = 0)
}
}
return with(density) { remainingPx.toDp() }
}
@Preview(device = Devices.PIXEL_7_PRO)
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES, device = Devices.PIXEL_7_PRO)
@Composable
private fun VirtualAccountMainScreenPreview() {
TangemThemePreviewRedesign {
VirtualAccountMainScreen(
state = VirtualAccountMainUM(
title = resourceReference(R.string.virtual_account_title),
subtitle = resourceReference(R.string.tangempay_usdc_on_polygon_network),
balance = VirtualAccountBalanceBlockState.Content(
fiatBalance = stringReference("$0.00"),
isBalanceFlickering = false,
),
isBalanceHidden = false,
onBackClick = {},
onMenuClick = {},
onAddFundsClick = {},
onSendClick = {},
),
)
}
}

View file

@ -0,0 +1,29 @@
package com.tangem.features.virtualaccount.main
import androidx.compose.runtime.Immutable
import com.tangem.core.ui.extensions.TextReference
@Immutable
internal data class VirtualAccountMainUM(
val title: TextReference,
val subtitle: TextReference,
val balance: VirtualAccountBalanceBlockState,
val isBalanceHidden: Boolean,
val onBackClick: () -> Unit,
val onMenuClick: () -> Unit,
val onAddFundsClick: () -> Unit,
val onSendClick: () -> Unit,
)
@Immutable
internal sealed class VirtualAccountBalanceBlockState {
data object Loading : VirtualAccountBalanceBlockState()
data class Content(
val fiatBalance: TextReference,
val isBalanceFlickering: Boolean,
) : VirtualAccountBalanceBlockState()
data object Error : VirtualAccountBalanceBlockState()
}

View file

@ -0,0 +1,18 @@
package com.tangem.features.virtualaccount.main.di
import com.tangem.features.virtualaccount.main.DefaultVirtualAccountMainComponent
import com.tangem.features.virtualaccount.details.component.VirtualAccountMainComponent
import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
@Module
@InstallIn(SingletonComponent::class)
internal interface VirtualAccountMainComponentModule {
@Binds
fun bindVirtualAccountMainComponentFactory(
factory: DefaultVirtualAccountMainComponent.Factory,
): VirtualAccountMainComponent.Factory
}

View file

@ -0,0 +1,20 @@
package com.tangem.features.virtualaccount.main.di
import com.tangem.core.decompose.di.ModelComponent
import com.tangem.core.decompose.model.Model
import com.tangem.features.virtualaccount.main.VirtualAccountMainModel
import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
import dagger.multibindings.ClassKey
import dagger.multibindings.IntoMap
@Module
@InstallIn(ModelComponent::class)
internal interface VirtualAccountMainModelModule {
@Binds
@IntoMap
@ClassKey(VirtualAccountMainModel::class)
fun bindVirtualAccountMainModel(model: VirtualAccountMainModel): Model
}

View file

@ -20,6 +20,7 @@ internal fun BaseExtension.configureCompilerOptions() {
internal fun BaseExtension.configureCompose(project: Project) {
val useCompose = with(project.path) {
contains(":ui") ||
contains(Regex(pattern = ":common-ui\$")) || // shared Composable UI component modules
contains(":common:ui-charts") ||
contains(":features:onboarding") || // TODO: divide on api/impl after migrating all onboarding to module
contains(Regex(pattern = ":presentation\$")) ||