Updated on 2026-08-14

This commit is contained in:
Tangem 2023-09-14 15:39:54 +03:00
parent 70d2f5ee06
commit 93abd29e1a
32 changed files with 609 additions and 118 deletions

View file

@ -2,6 +2,7 @@ package com.tangem.feature.wallet.presentation.common
import androidx.paging.PagingData
import com.tangem.core.ui.R
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
import com.tangem.core.ui.components.marketprice.MarketPriceBlockState
import com.tangem.core.ui.components.marketprice.PriceChangeConfig
import com.tangem.core.ui.components.transactions.state.TransactionState
@ -290,10 +291,10 @@ internal object WalletPreviewData {
}
val bottomSheet by lazy {
WalletBottomSheetConfig(
TangemBottomSheetConfig(
isShow = false,
onDismissRequest = {},
content = WalletBottomSheetConfig.BottomSheetContentConfig.UnlockWallets(
content = WalletBottomSheetConfig.UnlockWallets(
onUnlockClick = {},
onScanClick = {},
),

View file

@ -1,5 +1,6 @@
package com.tangem.feature.wallet.presentation.wallet.state
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
import com.tangem.feature.wallet.presentation.wallet.state.components.*
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
@ -20,7 +21,7 @@ internal sealed class WalletMultiCurrencyState : WalletState.ContentState() {
override val walletsListConfig: WalletsListConfig,
override val pullToRefreshConfig: WalletPullToRefreshConfig,
override val notifications: ImmutableList<WalletNotification>,
override val bottomSheetConfig: WalletBottomSheetConfig?,
override val bottomSheetConfig: TangemBottomSheetConfig?,
override val tokensListState: WalletTokensListState,
val tokenActionsBottomSheet: ActionsBottomSheetConfig?,
val onManageTokensClick: () -> Unit,
@ -42,10 +43,10 @@ internal sealed class WalletMultiCurrencyState : WalletState.ContentState() {
WalletNotification.UnlockWallets(onUnlockWalletsNotificationClick),
)
override val bottomSheetConfig = WalletBottomSheetConfig(
override val bottomSheetConfig = TangemBottomSheetConfig(
isShow = isBottomSheetShow,
onDismissRequest = onBottomSheetDismiss,
content = WalletBottomSheetConfig.BottomSheetContentConfig.UnlockWallets(
content = WalletBottomSheetConfig.UnlockWallets(
onUnlockClick = onUnlockClick,
onScanClick = onScanClick,
),

View file

@ -2,6 +2,7 @@ package com.tangem.feature.wallet.presentation.wallet.state
import androidx.compose.runtime.Immutable
import androidx.paging.PagingData
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
import com.tangem.core.ui.components.marketprice.MarketPriceBlockState
import com.tangem.core.ui.components.transactions.state.TransactionState
import com.tangem.core.ui.components.transactions.state.TxHistoryState
@ -31,7 +32,7 @@ internal sealed class WalletSingleCurrencyState : WalletState.ContentState() {
override val walletsListConfig: WalletsListConfig,
override val pullToRefreshConfig: WalletPullToRefreshConfig,
override val notifications: ImmutableList<WalletNotification>,
override val bottomSheetConfig: WalletBottomSheetConfig?,
override val bottomSheetConfig: TangemBottomSheetConfig?,
override val buttons: PersistentList<WalletManageButton>,
override val txHistoryState: TxHistoryState,
val marketPriceBlockState: MarketPriceBlockState,
@ -55,10 +56,10 @@ internal sealed class WalletSingleCurrencyState : WalletState.ContentState() {
WalletNotification.UnlockWallets(onUnlockWalletsNotificationClick),
)
override val bottomSheetConfig = WalletBottomSheetConfig(
override val bottomSheetConfig = TangemBottomSheetConfig(
isShow = isBottomSheetShow,
onDismissRequest = onBottomSheetDismiss,
content = WalletBottomSheetConfig.BottomSheetContentConfig.UnlockWallets(
content = WalletBottomSheetConfig.UnlockWallets(
onUnlockClick = onUnlockClick,
onScanClick = onScanClick,
),

View file

@ -1,5 +1,6 @@
package com.tangem.feature.wallet.presentation.wallet.state
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
import com.tangem.feature.wallet.presentation.wallet.state.components.*
import kotlinx.collections.immutable.ImmutableList
@ -29,7 +30,7 @@ internal sealed class WalletState {
abstract val notifications: ImmutableList<WalletNotification>
/** Bottom sheet config */
abstract val bottomSheetConfig: WalletBottomSheetConfig?
abstract val bottomSheetConfig: TangemBottomSheetConfig?
/**
* Util function that allow to make a copy

View file

@ -2,6 +2,7 @@ package com.tangem.feature.wallet.presentation.wallet.state.components
import androidx.annotation.DrawableRes
import androidx.compose.ui.graphics.Color
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.WrappedList
import com.tangem.core.ui.res.TangemColorPalette
@ -10,90 +11,79 @@ import com.tangem.feature.wallet.impl.R
/**
* Wallet bottom sheet config
*
* @property isShow flag that determine if bottom sheet is shown
* @property onDismissRequest lambda be invoked when bottom sheet is dismissed
* @property content content config
*
[REDACTED_AUTHOR]
*/
// TODO: Finalize notification strings [REDACTED_JIRA]
internal data class WalletBottomSheetConfig(
val isShow: Boolean,
val onDismissRequest: () -> Unit,
val content: BottomSheetContentConfig,
) {
sealed class WalletBottomSheetConfig(
open val title: TextReference,
open val subtitle: TextReference,
@DrawableRes open val iconResId: Int,
open val tint: Color? = null,
val primaryButtonConfig: ButtonConfig,
val secondaryButtonConfig: ButtonConfig,
) : TangemBottomSheetConfigContent {
sealed class BottomSheetContentConfig(
open val title: TextReference,
open val subtitle: TextReference,
@DrawableRes open val iconResId: Int,
open val tint: Color? = null,
val primaryButtonConfig: ButtonConfig,
val secondaryButtonConfig: ButtonConfig,
) {
data class ButtonConfig(
val text: TextReference,
val onClick: () -> Unit,
@DrawableRes val iconResId: Int? = null,
)
data class ButtonConfig(
val text: TextReference,
val onClick: () -> Unit,
@DrawableRes val iconResId: Int? = null,
)
data class UnlockWallets(
val onUnlockClick: () -> Unit,
val onScanClick: () -> Unit,
) : WalletBottomSheetConfig(
title = TextReference.Str(value = "Unlock needed"),
subtitle = TextReference.Str(
value = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor " +
"incididunt ut labore et dolore magna aliqua.",
),
iconResId = R.drawable.ic_locked_24,
tint = TangemColorPalette.Black,
primaryButtonConfig = ButtonConfig(text = TextReference.Str(value = "Unlock"), onClick = onUnlockClick),
secondaryButtonConfig = ButtonConfig(
text = TextReference.Str(value = "Scan card"),
onClick = onScanClick,
iconResId = R.drawable.ic_tangem_24,
),
)
data class UnlockWallets(
val onUnlockClick: () -> Unit,
val onScanClick: () -> Unit,
) : BottomSheetContentConfig(
title = TextReference.Str(value = "Unlock needed"),
subtitle = TextReference.Str(
value = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor " +
"incididunt ut labore et dolore magna aliqua.",
),
iconResId = R.drawable.ic_locked_24,
tint = TangemColorPalette.Black,
primaryButtonConfig = ButtonConfig(text = TextReference.Str(value = "Unlock"), onClick = onUnlockClick),
secondaryButtonConfig = ButtonConfig(
text = TextReference.Str(value = "Scan card"),
onClick = onScanClick,
iconResId = R.drawable.ic_tangem_24,
),
)
data class LikeTangemApp(
val onRateTheAppClick: () -> Unit,
val onShareClick: () -> Unit,
) : WalletBottomSheetConfig(
title = TextReference.Str(value = "Like Tangem App?"),
subtitle = TextReference.Str(value = "How was your experience with our app? Let us know:"),
iconResId = R.drawable.ic_star_24,
tint = TangemColorPalette.Tangerine,
primaryButtonConfig = ButtonConfig(
text = TextReference.Str(value = "Rate the app"),
onClick = onRateTheAppClick,
),
secondaryButtonConfig = ButtonConfig(
text = TextReference.Str(value = "Share feedback"),
onClick = onShareClick,
),
)
data class LikeTangemApp(
val onRateTheAppClick: () -> Unit,
val onShareClick: () -> Unit,
) : BottomSheetContentConfig(
title = TextReference.Str(value = "Like Tangem App?"),
subtitle = TextReference.Str(value = "How was your experience with our app? Let us know:"),
iconResId = R.drawable.ic_star_24,
tint = TangemColorPalette.Tangerine,
primaryButtonConfig = ButtonConfig(
text = TextReference.Str(value = "Rate the app"),
onClick = onRateTheAppClick,
),
secondaryButtonConfig = ButtonConfig(
text = TextReference.Str(value = "Share feedback"),
onClick = onShareClick,
),
)
data class CriticalWarningAlreadySignedHashes(
val onOkClick: () -> Unit,
val onCancelClick: () -> Unit,
) : BottomSheetContentConfig(
title = TextReference.Res(
id = R.string.warning_important_security_info,
formatArgs = WrappedList(listOf("\u26A0")),
),
subtitle = TextReference.Res(id = R.string.alert_signed_hashes_message),
iconResId = R.drawable.img_attention_20,
tint = null,
primaryButtonConfig = ButtonConfig(
text = TextReference.Res(id = R.string.common_ok),
onClick = onOkClick,
),
secondaryButtonConfig = ButtonConfig(
text = TextReference.Res(id = R.string.common_cancel),
onClick = onCancelClick,
),
)
}
data class CriticalWarningAlreadySignedHashes(
val onOkClick: () -> Unit,
val onCancelClick: () -> Unit,
) : WalletBottomSheetConfig(
title = TextReference.Res(
id = R.string.warning_important_security_info,
formatArgs = WrappedList(listOf("\u26A0")),
),
subtitle = TextReference.Res(id = R.string.alert_signed_hashes_message),
iconResId = R.drawable.img_attention_20,
tint = null,
primaryButtonConfig = ButtonConfig(
text = TextReference.Res(id = R.string.common_ok),
onClick = onOkClick,
),
secondaryButtonConfig = ButtonConfig(
text = TextReference.Res(id = R.string.common_cancel),
onClick = onCancelClick,
),
)
}

View file

@ -3,6 +3,8 @@ package com.tangem.feature.wallet.presentation.wallet.state.factory
import androidx.paging.PagingData
import arrow.core.Either
import com.tangem.common.Provider
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.common.CardTypesResolver
import com.tangem.domain.tokens.error.CurrencyStatusError
@ -18,7 +20,6 @@ import com.tangem.feature.wallet.presentation.wallet.state.ActionsBottomSheetCon
import com.tangem.feature.wallet.presentation.wallet.state.WalletMultiCurrencyState
import com.tangem.feature.wallet.presentation.wallet.state.WalletSingleCurrencyState
import com.tangem.feature.wallet.presentation.wallet.state.WalletState
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletBottomSheetConfig
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletNotification
import com.tangem.feature.wallet.presentation.wallet.state.factory.txhistory.WalletLoadedTxHistoryConverter
import com.tangem.feature.wallet.presentation.wallet.state.factory.txhistory.WalletLoadingTxHistoryConverter
@ -161,10 +162,10 @@ internal class WalletStateFactory(
fun getRefreshedState(): WalletState = refreshStateConverter.convert(value = false)
fun getStateWithOpenWalletBottomSheet(content: WalletBottomSheetConfig.BottomSheetContentConfig): WalletState {
fun getStateWithOpenWalletBottomSheet(content: TangemBottomSheetConfigContent): WalletState {
return when (val state = currentStateProvider() as WalletState.ContentState) {
is WalletMultiCurrencyState.Content -> state.copy(
bottomSheetConfig = WalletBottomSheetConfig(
bottomSheetConfig = TangemBottomSheetConfig(
isShow = true,
onDismissRequest = clickIntents::onDismissBottomSheet,
content = content,
@ -175,7 +176,7 @@ internal class WalletStateFactory(
onBottomSheetDismiss = clickIntents::onDismissBottomSheet,
)
is WalletSingleCurrencyState.Content -> state.copy(
bottomSheetConfig = WalletBottomSheetConfig(
bottomSheetConfig = TangemBottomSheetConfig(
isShow = true,
onDismissRequest = clickIntents::onDismissBottomSheet,
content = content,

View file

@ -18,6 +18,8 @@ import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
import androidx.paging.compose.collectAsLazyPagingItems
import com.tangem.core.ui.components.PrimaryButton
import com.tangem.core.ui.components.bottomsheets.tokenreceive.TokenReceiveBottomSheet
import com.tangem.core.ui.components.bottomsheets.tokenreceive.TokenReceiveBottomSheetConfig
import com.tangem.core.ui.components.transactions.state.TxHistoryState
import com.tangem.core.ui.res.TangemTheme
import com.tangem.feature.wallet.impl.R
@ -25,6 +27,7 @@ import com.tangem.feature.wallet.presentation.common.WalletPreviewData
import com.tangem.feature.wallet.presentation.wallet.state.WalletMultiCurrencyState
import com.tangem.feature.wallet.presentation.wallet.state.WalletSingleCurrencyState
import com.tangem.feature.wallet.presentation.wallet.state.WalletState
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletBottomSheetConfig
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletTokensListState
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletTokensListState.OrganizeTokensButtonState
import com.tangem.feature.wallet.presentation.wallet.ui.components.TokenActionsBottomSheet
@ -167,7 +170,15 @@ private fun ManageTokensButton(onManageTokensClick: () -> Unit) {
private fun WalletBottomSheets(state: WalletState) {
val bottomSheetConfig = (state as? WalletState.ContentState)?.bottomSheetConfig
if (bottomSheetConfig != null && bottomSheetConfig.isShow) {
WalletBottomSheet(config = bottomSheetConfig)
when (bottomSheetConfig.content) {
is WalletBottomSheetConfig -> {
WalletBottomSheet(config = bottomSheetConfig)
}
is TokenReceiveBottomSheetConfig -> {
TokenReceiveBottomSheet(config = bottomSheetConfig)
}
}
}
(state as? WalletMultiCurrencyState.Content)?.let { multiCurrencyState ->

View file

@ -15,6 +15,8 @@ import com.tangem.core.ui.components.PrimaryButton
import com.tangem.core.ui.components.PrimaryButtonIconStart
import com.tangem.core.ui.components.SecondaryButton
import com.tangem.core.ui.components.SecondaryButtonIconStart
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheet
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
import com.tangem.core.ui.extensions.resolveReference
import com.tangem.core.ui.res.TangemTheme
import com.tangem.feature.wallet.presentation.common.WalletPreviewData
@ -27,21 +29,17 @@ import com.tangem.feature.wallet.presentation.wallet.state.components.WalletBott
*
[REDACTED_AUTHOR]
*/
@OptIn(ExperimentalMaterial3Api::class)
@Composable
internal fun WalletBottomSheet(config: WalletBottomSheetConfig) {
ModalBottomSheet(
onDismissRequest = config.onDismissRequest,
sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true),
containerColor = TangemTheme.colors.background.primary,
dragHandle = { BottomSheetDefaults.DragHandle() },
) {
BottomSheetContent(config = config.content)
internal fun WalletBottomSheet(config: TangemBottomSheetConfig) {
TangemBottomSheet(config) { content ->
BottomSheetContent(
config = content as WalletBottomSheetConfig,
)
}
}
@Composable
private fun BottomSheetContent(config: WalletBottomSheetConfig.BottomSheetContentConfig) {
private fun BottomSheetContent(config: WalletBottomSheetConfig) {
Column(
modifier = Modifier
.padding(horizontal = TangemTheme.dimens.spacing16)
@ -90,10 +88,7 @@ private fun BottomSheetContent(config: WalletBottomSheetConfig.BottomSheetConten
}
@Composable
private fun PrimaryButton(
config: WalletBottomSheetConfig.BottomSheetContentConfig.ButtonConfig,
modifier: Modifier = Modifier,
) {
private fun PrimaryButton(config: WalletBottomSheetConfig.ButtonConfig, modifier: Modifier = Modifier) {
if (config.iconResId == null) {
PrimaryButton(
text = config.text.resolveReference(),
@ -111,10 +106,7 @@ private fun PrimaryButton(
}
@Composable
private fun SecondaryButton(
config: WalletBottomSheetConfig.BottomSheetContentConfig.ButtonConfig,
modifier: Modifier = Modifier,
) {
private fun SecondaryButton(config: WalletBottomSheetConfig.ButtonConfig, modifier: Modifier = Modifier) {
if (config.iconResId == null) {
SecondaryButton(
text = config.text.resolveReference(),
@ -139,7 +131,7 @@ private fun WalletBottomSheetContent_Light(
) {
TangemTheme(isDark = false) {
// Use preview of content because ModalBottomSheet isn't supported in Preview mode
BottomSheetContent(config = config.content)
BottomSheetContent(config = config)
}
}
@ -151,10 +143,10 @@ private fun WalletBottomSheetContent_Dark(
) {
TangemTheme(isDark = false) {
// Use preview of content because ModalBottomSheet isn't supported in Preview mode
BottomSheetContent(config = config.content)
BottomSheetContent(config = config)
}
}
private class WalletBottomSheetConfigProvider : CollectionPreviewParameterProvider<WalletBottomSheetConfig>(
private class WalletBottomSheetConfigProvider : CollectionPreviewParameterProvider<TangemBottomSheetConfig>(
collection = listOf(WalletPreviewData.bottomSheet),
)

View file

@ -7,6 +7,8 @@ import com.tangem.common.Provider
import com.tangem.common.doOnFailure
import com.tangem.common.doOnSuccess
import com.tangem.core.navigation.AppScreen
import com.tangem.core.ui.components.bottomsheets.tokenreceive.AddressModel
import com.tangem.core.ui.components.bottomsheets.tokenreceive.TokenReceiveBottomSheetConfig
import com.tangem.core.ui.components.marketprice.MarketPriceBlockState
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
import com.tangem.domain.appcurrency.model.AppCurrency
@ -27,6 +29,7 @@ import com.tangem.domain.tokens.models.Network
import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsCountUseCase
import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsUseCase
import com.tangem.domain.userwallets.UserWalletBuilder
import com.tangem.domain.walletmanager.WalletManagersFacade
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.domain.wallets.usecase.*
@ -86,6 +89,7 @@ internal class WalletViewModel @Inject constructor(
private val shouldShowSaveWalletScreenUseCase: ShouldShowSaveWalletScreenUseCase,
private val canUseBiometryUseCase: CanUseBiometryUseCase,
private val shouldSaveUserWalletsUseCase: ShouldSaveUserWalletsUseCase,
private val walletManagersFacade: WalletManagersFacade,
private val reduxStateHolder: ReduxStateHolder,
private val dispatchers: CoroutineDispatcherProvider,
) : ViewModel(), DefaultLifecycleObserver, WalletClickIntents {
@ -271,7 +275,7 @@ internal class WalletViewModel @Inject constructor(
override fun onCriticalWarningAlreadySignedHashesClick() {
uiState = stateFactory.getStateWithOpenWalletBottomSheet(
content = WalletBottomSheetConfig.BottomSheetContentConfig.CriticalWarningAlreadySignedHashes(
content = WalletBottomSheetConfig.CriticalWarningAlreadySignedHashes(
onOkClick = {},
onCancelClick = {},
),
@ -284,7 +288,7 @@ internal class WalletViewModel @Inject constructor(
override fun onLikeTangemAppClick() {
uiState = stateFactory.getStateWithOpenWalletBottomSheet(
content = WalletBottomSheetConfig.BottomSheetContentConfig.LikeTangemApp(
content = WalletBottomSheetConfig.LikeTangemApp(
onRateTheAppClick = ::onRateTheAppClick,
onShareClick = ::onShareClick,
),
@ -428,7 +432,31 @@ internal class WalletViewModel @Inject constructor(
}
override fun onReceiveClick(cryptoCurrencyStatus: CryptoCurrencyStatus) {
// TODO: [REDACTED_JIRA]
val state = uiState as? WalletState.ContentState ?: return
viewModelScope.launch(dispatchers.io) {
val userWallet = getWallet(index = state.walletsListConfig.selectedWalletIndex)
val addresses = walletManagersFacade.getAddress(
userWalletId = userWallet.walletId,
network = cryptoCurrencyStatus.currency.network,
)
val currency = cryptoCurrencyStatus.currency
uiState = stateFactory.getStateWithOpenWalletBottomSheet(
content = TokenReceiveBottomSheetConfig(
name = currency.name,
symbol = currency.symbol,
network = currency.network.name,
addresses = addresses.map {
AddressModel(
value = it.value,
type = AddressModel.Type.valueOf(it.type.name),
)
},
),
)
}
}
override fun onSellClick(cryptoCurrencyStatus: CryptoCurrencyStatus) {