Updated on 2026-08-14

This commit is contained in:
Tangem 2023-12-18 20:05:37 +04:00
parent 0662e31ed0
commit 669d540b2a
9 changed files with 321 additions and 12 deletions

View file

@ -21,7 +21,7 @@ import kotlinx.coroutines.launch
@Composable
inline fun <reified T : TangemBottomSheetConfigContent> TangemBottomSheet(
config: TangemBottomSheetConfig,
contentColor: Color = TangemTheme.colors.background.primary,
containerColor: Color = TangemTheme.colors.background.primary,
crossinline content: @Composable ColumnScope.(T) -> Unit,
) {
var isVisible by remember { mutableStateOf(value = config.isShow) }
@ -31,9 +31,9 @@ inline fun <reified T : TangemBottomSheetConfigContent> TangemBottomSheet(
ModalBottomSheet(
onDismissRequest = config.onDismissRequest,
sheetState = sheetState,
containerColor = contentColor,
containerColor = containerColor,
shape = TangemTheme.shapes.bottomSheetLarge,
dragHandle = { TangemBottomSheetDraggableHeader(contentColor) },
dragHandle = { TangemBottomSheetDraggableHeader(color = containerColor) },
) {
content(config.content)
}

View file

@ -11,7 +11,7 @@ import com.tangem.managetokens.presentation.common.state.ChooseWalletState
internal fun ChooseWalletBottomSheet(config: TangemBottomSheetConfig) {
TangemBottomSheet<ChooseWalletBottomSheetConfig>(
config = config,
contentColor = TangemTheme.colors.background.tertiary,
containerColor = TangemTheme.colors.background.tertiary,
) {
ChooseWalletScreen(state = it.chooseWalletState)
}

View file

@ -12,7 +12,7 @@ import com.tangem.managetokens.presentation.managetokens.state.TokenItemState
internal fun ChooseNetworkBottomSheet(config: TangemBottomSheetConfig) {
TangemBottomSheet<ChooseNetworkBottomSheetConfig>(
config = config,
contentColor = TangemTheme.colors.background.tertiary,
containerColor = TangemTheme.colors.background.tertiary,
) {
ChooseNetworkScreen(state = it.selectedToken, walletState = it.chooseWalletState)
}

View file

@ -25,7 +25,7 @@ import kotlinx.collections.immutable.toImmutableList
fun ChooseProviderBottomSheet(config: TangemBottomSheetConfig) {
TangemBottomSheet(
config = config,
contentColor = TangemTheme.colors.background.tertiary,
containerColor = TangemTheme.colors.background.tertiary,
) { content: ChooseProviderBottomSheetConfig ->
ChooseProviderBottomSheetContent(content = content)
}

View file

@ -27,7 +27,7 @@ import com.tangem.feature.tokendetails.presentation.tokendetails.state.SwapTrans
internal fun ExchangeStatusBottomSheet(config: TangemBottomSheetConfig) {
TangemBottomSheet(
config = config,
contentColor = TangemTheme.colors.background.tertiary,
containerColor = TangemTheme.colors.background.tertiary,
) { content: ExchangeStatusBottomSheetConfig ->
ExchangeStatusBottomSheetContent(content = content)
}

View file

@ -0,0 +1,28 @@
package com.tangem.feature.wallet.presentation.wallet.state2.model
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
internal data class BalancesAndLimitsBottomSheetConfig(
val currency: String,
val balance: Balance,
val limit: Limit,
val onBalanceInfoClick: () -> Unit,
val onLimitInfoClick: () -> Unit,
) : TangemBottomSheetConfigContent {
data class Balance(
val totalBalance: String,
val availableBalance: String,
val blockedBalance: String,
val debit: String,
val pending: String,
val amlVerified: String,
)
data class Limit(
val availableBy: String,
val inStore: String,
val other: String,
val singleTransaction: String,
)
}

View file

@ -29,16 +29,14 @@ import com.tangem.feature.wallet.impl.R
import com.tangem.feature.wallet.presentation.wallet.state.ActionsBottomSheetConfig
import com.tangem.feature.wallet.presentation.wallet.state.WalletAlertState
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletBottomSheetConfig
import com.tangem.feature.wallet.presentation.wallet.state2.model.NOT_INITIALIZED_WALLET_INDEX
import com.tangem.feature.wallet.presentation.wallet.state2.model.WalletScreenState
import com.tangem.feature.wallet.presentation.wallet.state2.model.WalletState
import com.tangem.feature.wallet.presentation.wallet.state2.model.WalletTokensListState
import com.tangem.feature.wallet.presentation.wallet.state2.model.*
import com.tangem.feature.wallet.presentation.wallet.ui.components.TokenActionsBottomSheet
import com.tangem.feature.wallet.presentation.wallet.ui.components.WalletsList
import com.tangem.feature.wallet.presentation.wallet.ui.components.common.*
import com.tangem.feature.wallet.presentation.wallet.ui.components.multicurrency.organizeTokensButton
import com.tangem.feature.wallet.presentation.wallet.ui.components.singlecurrency.controlButtons
import com.tangem.feature.wallet.presentation.wallet.ui.components.singlecurrency.marketPriceBlock
import com.tangem.feature.wallet.presentation.wallet.ui.components.visa.BalancesAndLimitsBottomSheet
import com.tangem.feature.wallet.presentation.wallet.ui.components.visa.balancesAndLimitsBlock
import com.tangem.feature.wallet.presentation.wallet.ui.components.visa.depositButton
import com.tangem.feature.wallet.presentation.wallet.ui.utils.changeWalletAnimator
@ -172,6 +170,7 @@ private fun WalletContent(
is TokenReceiveBottomSheetConfig -> TokenReceiveBottomSheet(config = bottomSheetConfig)
is ActionsBottomSheetConfig -> TokenActionsBottomSheet(config = bottomSheetConfig)
is ChooseAddressBottomSheetConfig -> ChooseAddressBottomSheet(config = bottomSheetConfig)
is BalancesAndLimitsBottomSheetConfig -> BalancesAndLimitsBottomSheet(config = bottomSheetConfig)
}
}

View file

@ -0,0 +1,252 @@
package com.tangem.feature.wallet.presentation.wallet.ui.components.visa
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
import com.tangem.core.ui.components.SpacerH16
import com.tangem.core.ui.components.SpacerWMax
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheet
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
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.feature.wallet.impl.R
import com.tangem.feature.wallet.presentation.wallet.state2.model.BalancesAndLimitsBottomSheetConfig
@Composable
internal fun BalancesAndLimitsBottomSheet(config: TangemBottomSheetConfig) {
TangemBottomSheet(
config = config,
containerColor = TangemTheme.colors.background.secondary,
) { content: BalancesAndLimitsBottomSheetConfig ->
BalancesAndLimitsContent(content)
}
}
@Composable
private fun BalancesAndLimitsContent(config: BalancesAndLimitsBottomSheetConfig, modifier: Modifier = Modifier) {
ContentContainer(
modifier = modifier,
title = {
Text(
text = "Balances & Limits",
style = TangemTheme.typography.subtitle1,
color = TangemTheme.colors.text.primary1,
)
},
firstBlock = {
BlockContent(
title = stringReference("Balance, ${config.currency}"),
content = {
BlockItem(
title = stringReference("Total"),
value = config.balance.totalBalance,
)
BlockItem(
title = stringReference("AML Verified"),
value = config.balance.amlVerified,
)
BlockItem(
title = stringReference("Available"),
value = config.balance.availableBalance,
)
BlockItem(
title = stringReference("Blocked"),
value = config.balance.blockedBalance,
)
BlockItem(
title = stringReference("Debit"),
value = config.balance.debit,
)
BlockItem(
title = stringReference("Pending refund"),
value = config.balance.pending,
)
},
onInfoIconClick = config.onBalanceInfoClick,
)
},
secondBlock = {
BlockContent(
title = stringReference("Limits, ${config.currency}"),
description = stringReference("Available by ${config.limit.availableBy}"),
content = {
BlockItem(
title = stringReference("In-store (otp)"),
value = config.limit.inStore,
)
BlockItem(
title = stringReference("Other (no-otp)"),
value = config.limit.other,
)
BlockItem(
title = stringReference("Single transaction"),
value = config.limit.singleTransaction,
)
},
onInfoIconClick = config.onBalanceInfoClick,
)
},
)
}
@Composable
private inline fun BlockContent(
title: TextReference,
content: @Composable ColumnScope.() -> Unit,
noinline onInfoIconClick: () -> Unit,
modifier: Modifier = Modifier,
description: TextReference? = null,
) {
Column(
modifier = modifier
.padding(horizontal = TangemTheme.dimens.spacing16)
.fillMaxWidth()
.background(
color = TangemTheme.colors.background.primary,
shape = TangemTheme.shapes.roundedCornersXMedium,
)
.padding(vertical = TangemTheme.dimens.spacing8),
) {
Row(
modifier = Modifier
.padding(
start = TangemTheme.dimens.spacing12,
end = TangemTheme.dimens.spacing4,
)
.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically,
) {
Text(
text = title.resolveReference(),
style = TangemTheme.typography.subtitle2,
color = TangemTheme.colors.text.tertiary,
)
SpacerWMax()
if (description != null) {
Text(
text = description.resolveReference(),
style = TangemTheme.typography.body2,
color = TangemTheme.colors.text.tertiary,
)
}
IconButton(
modifier = Modifier.size(TangemTheme.dimens.size32),
onClick = onInfoIconClick,
) {
Icon(
modifier = Modifier.size(TangemTheme.dimens.size16),
painter = painterResource(id = R.drawable.ic_information_24),
tint = TangemTheme.colors.icon.informative,
contentDescription = null,
)
}
}
content()
}
}
@Composable
private fun BlockItem(title: TextReference, value: String, modifier: Modifier = Modifier) {
Row(
modifier = modifier
.padding(horizontal = TangemTheme.dimens.spacing12)
.fillMaxWidth()
.heightIn(min = TangemTheme.dimens.size32),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically,
) {
Text(
text = title.resolveReference(),
style = TangemTheme.typography.caption2,
color = TangemTheme.colors.text.tertiary,
)
Text(
text = value,
style = TangemTheme.typography.caption2,
color = TangemTheme.colors.text.primary1,
)
}
}
@Composable
private inline fun ContentContainer(
title: @Composable BoxScope.() -> Unit,
firstBlock: @Composable ColumnScope.() -> Unit,
secondBlock: @Composable ColumnScope.() -> Unit,
modifier: Modifier = Modifier,
) {
Column(
modifier = modifier.background(TangemTheme.colors.background.secondary),
verticalArrangement = Arrangement.spacedBy(space = TangemTheme.dimens.spacing12),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Box(
modifier = Modifier
.fillMaxWidth()
.heightIn(min = TangemTheme.dimens.size44),
contentAlignment = Alignment.Center,
content = title,
)
firstBlock()
secondBlock()
SpacerH16()
}
}
// region Preview
@Preview(showBackground = true, widthDp = 360)
@Composable
private fun BalancesAndLimitsBottomSheetPreview_Light(
@PreviewParameter(BalancesAndLimitsBottomSheetParameterProvider::class) state: BalancesAndLimitsBottomSheetConfig,
) {
TangemTheme {
BalancesAndLimitsContent(state)
}
}
@Preview(showBackground = true, widthDp = 360)
@Composable
private fun BalancesAndLimitsBottomSheetPreview_Dark(
@PreviewParameter(BalancesAndLimitsBottomSheetParameterProvider::class) state: BalancesAndLimitsBottomSheetConfig,
) {
TangemTheme(isDark = true) {
BalancesAndLimitsContent(state)
}
}
private class BalancesAndLimitsBottomSheetParameterProvider :
CollectionPreviewParameterProvider<BalancesAndLimitsBottomSheetConfig>(
collection = listOf(
BalancesAndLimitsBottomSheetConfig(
currency = "USDT",
balance = BalancesAndLimitsBottomSheetConfig.Balance(
totalBalance = "492.45",
availableBalance = "392.45",
blockedBalance = "36.00",
debit = "00.00",
pending = "20.99",
amlVerified = "356.45",
),
limit = BalancesAndLimitsBottomSheetConfig.Limit(
availableBy = "Nov, 11",
inStore = "563.00",
other = "100.00",
singleTransaction = "100.00",
),
onBalanceInfoClick = {},
onLimitInfoClick = {},
),
),
)
// endregion Preview

View file

@ -10,6 +10,7 @@ import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.feature.wallet.presentation.wallet.state.WalletEvent
import com.tangem.feature.wallet.presentation.wallet.state2.WalletStateController
import com.tangem.feature.wallet.presentation.wallet.state2.model.BalancesAndLimitsBottomSheetConfig
import com.tangem.feature.wallet.presentation.wallet.state2.utils.WalletEventSender
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import dagger.hilt.android.scopes.ViewModelScoped
@ -28,8 +29,8 @@ internal interface VisaWalletIntents {
@ViewModelScoped
internal class VisaWalletIntentsImplementor @Inject constructor(
private val eventSender: WalletEventSender,
private val stateController: WalletStateController,
private val eventSender: WalletEventSender,
private val getPrimaryCurrencyUseCase: GetPrimaryCurrencyStatusUpdatesUseCase,
private val dispatchers: CoroutineDispatcherProvider,
) : BaseWalletClickIntents(), VisaWalletIntents {
@ -75,6 +76,35 @@ internal class VisaWalletIntentsImplementor @Inject constructor(
}
override fun onBalancesAndLimitsClick() {
stateController.showBottomSheet(getBalancesAndLimitsConfig())
}
// TODO: Implement
private fun getBalancesAndLimitsConfig() = BalancesAndLimitsBottomSheetConfig(
currency = "USDT",
balance = BalancesAndLimitsBottomSheetConfig.Balance(
totalBalance = "492.45",
availableBalance = "392.45",
blockedBalance = "36.00",
debit = "00.00",
pending = "20.99",
amlVerified = "356.45",
),
limit = BalancesAndLimitsBottomSheetConfig.Limit(
availableBy = "Nov, 11",
inStore = "563.00",
other = "100.00",
singleTransaction = "100.00",
),
onBalanceInfoClick = this::showBalanceInfo,
onLimitInfoClick = this::showLimitInfo,
)
private fun showBalanceInfo() {
eventSender.send(WalletEvent.ShowToast(stringReference(value = "Not implemented yet")))
}
private fun showLimitInfo() {
eventSender.send(WalletEvent.ShowToast(stringReference(value = "Not implemented yet")))
}
}