Updated on 2026-08-14

This commit is contained in:
Tangem 2026-07-01 15:00:40 +05:00
parent 7443421bb1
commit b83b9d4ef6
19 changed files with 226 additions and 74 deletions

View file

@ -0,0 +1,34 @@
package com.tangem.features.virtualaccount.details.component
import com.tangem.core.decompose.factory.ComponentFactory
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
import com.tangem.domain.models.wallet.UserWalletId
/**
* Bottom sheet showing Virtual Account bank-transfer requisites (beneficiary, bank, account & routing numbers).
*
* Two stages: an educational intro and the requisites. Set [Params.shouldSkipIntro] to open straight at the
* requisites used by callers (e.g. TangemPay) that already show their own intro.
*/
interface VirtualAccountAddFundsBottomSheetComponent : ComposableBottomSheetComponent {
data class Params(
val userWalletId: UserWalletId,
val requisites: List<RequisitesRow>,
val dailyDepositLimit: String,
val listener: VirtualAccountAddFundsListener,
val shouldSkipIntro: Boolean = false,
)
data class RequisitesRow(
val title: String,
val titleForShare: String,
val value: String,
)
interface Factory : ComponentFactory<Params, VirtualAccountAddFundsBottomSheetComponent>
}
fun interface VirtualAccountAddFundsListener {
fun onAddFundsDismiss()
}

View file

@ -11,8 +11,8 @@ 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.features.virtualaccount.details.component.VirtualAccountAddFundsBottomSheetComponent
import com.tangem.features.virtualaccount.details.component.VirtualAccountMainComponent
import com.tangem.features.virtualaccount.main.addfunds.VirtualAccountAddFundsBottomSheetComponent
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
@ -20,6 +20,7 @@ import dagger.assisted.AssistedInject
internal class DefaultVirtualAccountMainComponent @AssistedInject constructor(
@Assisted appComponentContext: AppComponentContext,
@Assisted private val params: VirtualAccountMainComponent.Params,
private val addFundsComponentFactory: VirtualAccountAddFundsBottomSheetComponent.Factory,
) : VirtualAccountMainComponent, AppComponentContext by appComponentContext {
private val model: VirtualAccountMainModel = getOrCreateModel(params = params)
@ -44,8 +45,8 @@ internal class DefaultVirtualAccountMainComponent @AssistedInject constructor(
componentContext: ComponentContext,
): ComposableBottomSheetComponent {
return when (config) {
is VirtualAccountMainNavigationBottomSheetConfig.AddFunds -> VirtualAccountAddFundsBottomSheetComponent(
appComponentContext = childByContext(componentContext),
is VirtualAccountMainNavigationBottomSheetConfig.AddFunds -> addFundsComponentFactory.create(
context = childByContext(componentContext),
params = VirtualAccountAddFundsBottomSheetComponent.Params(
userWalletId = params.userWalletId,
listener = model,

View file

@ -10,10 +10,10 @@ 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.VirtualAccountAddFundsBottomSheetComponent
import com.tangem.features.virtualaccount.details.component.VirtualAccountAddFundsListener
import com.tangem.features.virtualaccount.details.component.VirtualAccountMainComponent
import com.tangem.features.virtualaccount.details.impl.R
import com.tangem.features.virtualaccount.main.addfunds.VirtualAccountAddFundsBottomSheetComponent
import com.tangem.features.virtualaccount.main.addfunds.VirtualAccountAddFundsListener
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
@ -57,22 +57,22 @@ internal class VirtualAccountMainModel @Inject constructor(
private fun buildRequisites(details: VirtualAccountDepositDetails) = listOf(
VirtualAccountAddFundsBottomSheetComponent.RequisitesRow(
title = stringReference("Beneficiary name and address"),
title = "Beneficiary name and address",
titleForShare = "Beneficiary name and address",
value = "${details.beneficiaryName}\n${details.beneficiaryAddress}",
),
VirtualAccountAddFundsBottomSheetComponent.RequisitesRow(
title = stringReference("Bank name and address"),
title = "Bank name and address",
titleForShare = "Bank name and address",
value = "${details.bankName}\n${details.bankAddress}",
),
VirtualAccountAddFundsBottomSheetComponent.RequisitesRow(
title = stringReference("Account number"),
title = "Account number",
titleForShare = "Account number",
value = details.accountNumber,
),
VirtualAccountAddFundsBottomSheetComponent.RequisitesRow(
title = stringReference("Routing number"),
title = "Routing number",
titleForShare = "Routing number",
value = details.routingNumber,
),

View file

@ -1,6 +1,6 @@
package com.tangem.features.virtualaccount.main
import com.tangem.features.virtualaccount.main.addfunds.VirtualAccountAddFundsBottomSheetComponent.RequisitesRow
import com.tangem.features.virtualaccount.details.component.VirtualAccountAddFundsBottomSheetComponent.RequisitesRow
import kotlinx.serialization.Serializable
@Serializable

View file

@ -0,0 +1,37 @@
package com.tangem.features.virtualaccount.main.addfunds
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
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.VirtualAccountAddFundsBottomSheetComponent
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
internal class DefaultVirtualAccountAddFundsBottomSheetComponent @AssistedInject constructor(
@Assisted appComponentContext: AppComponentContext,
@Assisted params: VirtualAccountAddFundsBottomSheetComponent.Params,
) : VirtualAccountAddFundsBottomSheetComponent, AppComponentContext by appComponentContext {
private val model: VirtualAccountAddFundsModel = getOrCreateModel(params = params)
override fun dismiss() {
model.onDismiss()
}
@Composable
override fun BottomSheet() {
val state by model.uiState.collectAsStateWithLifecycle()
VirtualAccountAddFundsBottomSheet(state = state)
}
@AssistedFactory
interface Factory : VirtualAccountAddFundsBottomSheetComponent.Factory {
override fun create(
context: AppComponentContext,
params: VirtualAccountAddFundsBottomSheetComponent.Params,
): DefaultVirtualAccountAddFundsBottomSheetComponent
}
}

View file

@ -1,45 +0,0 @@
package com.tangem.features.virtualaccount.main.addfunds
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.core.decompose.model.getOrCreateModel
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
import com.tangem.core.ui.extensions.TextReference
import com.tangem.domain.models.wallet.UserWalletId
internal class VirtualAccountAddFundsBottomSheetComponent(
appComponentContext: AppComponentContext,
params: Params,
) : ComposableBottomSheetComponent, AppComponentContext by appComponentContext {
private val model: VirtualAccountAddFundsModel = getOrCreateModel(params = params)
override fun dismiss() {
model.onDismiss()
}
@Composable
override fun BottomSheet() {
val state by model.uiState.collectAsStateWithLifecycle()
VirtualAccountAddFundsBottomSheet(state = state)
}
data class Params(
val userWalletId: UserWalletId,
val requisites: List<RequisitesRow>,
val dailyDepositLimit: String,
val listener: VirtualAccountAddFundsListener,
)
data class RequisitesRow(
val title: TextReference,
val titleForShare: String,
val value: String,
)
}
internal interface VirtualAccountAddFundsListener {
fun onAddFundsDismiss()
}

View file

@ -7,7 +7,8 @@ import com.tangem.core.decompose.model.Model
import com.tangem.core.decompose.model.ParamsContainer
import com.tangem.core.navigation.share.ShareManager
import com.tangem.core.ui.clipboard.ClipboardManager
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.stringReference
import com.tangem.features.virtualaccount.details.component.VirtualAccountAddFundsBottomSheetComponent
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.flow.MutableStateFlow
@ -30,9 +31,7 @@ internal class VirtualAccountAddFundsModel @Inject constructor(
field = MutableStateFlow(
VirtualAccountAddFundsUM(
onDismiss = ::onDismiss,
content = VirtualAccountAddFundsUM.Content.Intro(
onShowDetailsClick = { showDetailsContent() },
),
content = if (params.shouldSkipIntro) buildDetailsContent() else buildIntroContent(),
),
)
@ -40,22 +39,24 @@ internal class VirtualAccountAddFundsModel @Inject constructor(
params.listener.onAddFundsDismiss()
}
private fun buildIntroContent() = VirtualAccountAddFundsUM.Content.Intro(
onShowDetailsClick = ::showDetailsContent,
)
private fun showDetailsContent() {
uiState.update { state ->
state.copy(
content = VirtualAccountAddFundsUM.Content.Details(
items = params.requisites
.map { detailItem(label = it.title, value = it.value) }
.toImmutableList(),
dailyLimit = params.dailyDepositLimit,
onShareClick = { shareManager.shareText(buildShareText()) },
),
)
}
uiState.update { state -> state.copy(content = buildDetailsContent()) }
}
private fun detailItem(label: TextReference, value: String) = VirtualAccountAddFundsUM.DetailItem(
label = label,
private fun buildDetailsContent() = VirtualAccountAddFundsUM.Content.Details(
items = params.requisites
.map { detailItem(label = it.title, value = it.value) }
.toImmutableList(),
dailyLimit = params.dailyDepositLimit,
onShareClick = { shareManager.shareText(buildShareText()) },
)
private fun detailItem(label: String, value: String) = VirtualAccountAddFundsUM.DetailItem(
label = stringReference(label),
value = value,
onCopyClick = { clipboardManager.setText(text = value, isSensitive = true) },
)

View file

@ -1,7 +1,9 @@
package com.tangem.features.virtualaccount.main.di
import com.tangem.features.virtualaccount.main.DefaultVirtualAccountMainComponent
import com.tangem.features.virtualaccount.details.component.VirtualAccountAddFundsBottomSheetComponent
import com.tangem.features.virtualaccount.details.component.VirtualAccountMainComponent
import com.tangem.features.virtualaccount.main.DefaultVirtualAccountMainComponent
import com.tangem.features.virtualaccount.main.addfunds.DefaultVirtualAccountAddFundsBottomSheetComponent
import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
@ -15,4 +17,9 @@ internal interface VirtualAccountMainComponentModule {
fun bindVirtualAccountMainComponentFactory(
factory: DefaultVirtualAccountMainComponent.Factory,
): VirtualAccountMainComponent.Factory
@Binds
fun bindVirtualAccountAddFundsComponentFactory(
factory: DefaultVirtualAccountAddFundsBottomSheetComponent.Factory,
): VirtualAccountAddFundsBottomSheetComponent.Factory
}