diff --git a/core/ui/src/main/java/com/tangem/core/ui/ds/row/header/TangemHeaderRow.kt b/core/ui/src/main/java/com/tangem/core/ui/ds/row/header/TangemHeaderRow.kt index dee6b40952..2778e5efd8 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/ds/row/header/TangemHeaderRow.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/ds/row/header/TangemHeaderRow.kt @@ -94,16 +94,17 @@ fun TangemHeaderRow( AnimatedVisibility( visible = subtitle != null, ) { - val wrappedSubtitle = remember(this) { requireNotNull(subtitle) } - Text( - text = wrappedSubtitle.orMaskWithStars(isBalanceHidden).resolveAnnotatedReference(), - style = TangemTheme.typography2.captionSemibold12, - color = TangemTheme.colors2.text.neutral.secondary, - maxLines = 1, - modifier = Modifier - .testTag(tag = TokenElementsTestTags.TOKEN_CRYPTO_AMOUNT) - .padding(start = TangemTheme.dimens2.x1), - ) + if (subtitle != null) { + Text( + text = subtitle.orMaskWithStars(isBalanceHidden).resolveAnnotatedReference(), + style = TangemTheme.typography2.captionSemibold12, + color = TangemTheme.colors2.text.neutral.secondary, + maxLines = 1, + modifier = Modifier + .testTag(tag = TokenElementsTestTags.TOKEN_CRYPTO_AMOUNT) + .padding(start = TangemTheme.dimens2.x1), + ) + } } SpacerWMax() TangemRowTail(tangemRowTailUM = tailUM) @@ -165,16 +166,17 @@ fun TangemHeaderRow( AnimatedVisibility( visible = subtitle != null, ) { - val wrappedSubtitle = remember(this) { requireNotNull(subtitle) } - Text( - text = wrappedSubtitle.orMaskWithStars(isBalanceHidden).resolveAnnotatedReference(), - style = TangemTheme.typography2.captionSemibold12, - color = TangemTheme.colors2.text.neutral.secondary, - maxLines = 1, - modifier = Modifier - .testTag(tag = TokenElementsTestTags.TOKEN_CRYPTO_AMOUNT) - .padding(start = TangemTheme.dimens2.x1), - ) + if (subtitle != null) { + Text( + text = subtitle.orMaskWithStars(isBalanceHidden).resolveAnnotatedReference(), + style = TangemTheme.typography2.captionSemibold12, + color = TangemTheme.colors2.text.neutral.secondary, + maxLines = 1, + modifier = Modifier + .testTag(tag = TokenElementsTestTags.TOKEN_CRYPTO_AMOUNT) + .padding(start = TangemTheme.dimens2.x1), + ) + } } SpacerWMax() TangemRowTail( diff --git a/core/ui/src/main/java/com/tangem/core/ui/ds/topbar/TangemTopBar.kt b/core/ui/src/main/java/com/tangem/core/ui/ds/topbar/TangemTopBar.kt index 28a966df76..3fa6190cdf 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/ds/topbar/TangemTopBar.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/ds/topbar/TangemTopBar.kt @@ -263,41 +263,41 @@ private fun TangemTopBarTitle(title: TextReference?, @DrawableRes titleIconRes: enter = slideInVertically(initialOffsetY = { it / 2 }) + fadeIn(), exit = slideOutVertically(targetOffsetY = { it / 2 }) + fadeOut(), ) { - val wrappedTitle = remember(this) { requireNotNull(title) } - - Row( - horizontalArrangement = Arrangement.spacedBy( - space = TangemTheme.dimens2.x1, - alignment = Alignment.CenterHorizontally, - ), - verticalAlignment = Alignment.CenterVertically, - ) { - AnimatedVisibility( - visible = titleIconRes != null, - label = "Title Icon Visibility", + if (title != null) { + Row( + horizontalArrangement = Arrangement.spacedBy( + space = TangemTheme.dimens2.x1, + alignment = Alignment.CenterHorizontally, + ), + verticalAlignment = Alignment.CenterVertically, ) { - val wrappedTitleIconRes = remember(this) { - requireNotNull(titleIconRes) + AnimatedVisibility( + visible = titleIconRes != null, + label = "Title Icon Visibility", + ) { + val wrappedTitleIconRes = remember(this) { + requireNotNull(titleIconRes) + } + Icon( + imageVector = ImageVector.vectorResource(id = wrappedTitleIconRes), + contentDescription = null, + tint = TangemTheme.colors2.graphic.neutral.primary, + modifier = Modifier.size(TangemTheme.dimens2.x4), + ) } - Icon( - imageVector = ImageVector.vectorResource(id = wrappedTitleIconRes), - contentDescription = null, - tint = TangemTheme.colors2.graphic.neutral.primary, - modifier = Modifier.size(TangemTheme.dimens2.x4), + + Text( + text = title.resolveAnnotatedReference(), + color = TangemTheme.colors2.text.neutral.primary, + style = TangemTheme.typography2.headingSemibold17, + textAlign = TextAlign.Center, + maxLines = 1, + autoSize = TextAutoSize.StepBased( + minFontSize = TangemTheme.typography2.captionRegular12.fontSize, + maxFontSize = TangemTheme.typography2.headingSemibold17.fontSize, + ), ) } - - Text( - text = wrappedTitle.resolveAnnotatedReference(), - color = TangemTheme.colors2.text.neutral.primary, - style = TangemTheme.typography2.headingSemibold17, - textAlign = TextAlign.Center, - maxLines = 1, - autoSize = TextAutoSize.StepBased( - minFontSize = TangemTheme.typography2.captionRegular12.fontSize, - maxFontSize = TangemTheme.typography2.headingSemibold17.fontSize, - ), - ) } } } diff --git a/core/utils/src/main/java/com/tangem/utils/StringsSigns.kt b/core/utils/src/main/java/com/tangem/utils/StringsSigns.kt index 90655e7d52..4a864c1986 100644 --- a/core/utils/src/main/java/com/tangem/utils/StringsSigns.kt +++ b/core/utils/src/main/java/com/tangem/utils/StringsSigns.kt @@ -13,8 +13,8 @@ object StringsSigns { const val INFINITY_SIGN = "∞" const val NON_BREAKING_SPACE = '\u00A0' const val PERCENT = "%" - const val THREE_STARS = "\u2217\u2217\u2217" - const val ASTERISK = "\u2217" + const val THREE_STARS = "***" + const val ASTERISK = "*" const val PASSWORD_VISUAL_CHAR = '\u2022' const val APPROXIMATE = "≈" const val WHITE_SPACE = " " diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/components/search/DefaultSearchComponent.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/components/search/DefaultSearchComponent.kt index 1947475d45..8843decf91 100644 --- a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/components/search/DefaultSearchComponent.kt +++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/components/search/DefaultSearchComponent.kt @@ -99,7 +99,6 @@ internal class DefaultSearchComponent( params = SearchTokenSelectorComponent.Params( entries = config.entries, appCurrency = config.appCurrency, - isBalanceHidden = config.isBalanceHidden, onTokenSelected = config.onTokenSelected, onDismiss = config.onDismiss, ), diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/components/search/SearchBottomSheetRoute.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/components/search/SearchBottomSheetRoute.kt index b595fbe70c..6ff760b511 100644 --- a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/components/search/SearchBottomSheetRoute.kt +++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/components/search/SearchBottomSheetRoute.kt @@ -8,7 +8,6 @@ internal sealed interface SearchBottomSheetRoute { data class TokenSelector( val entries: List, val appCurrency: AppCurrency, - val isBalanceHidden: Boolean, val onTokenSelected: (UserAssetEntry) -> Unit, val onDismiss: () -> Unit, ) : SearchBottomSheetRoute diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/components/search/SearchTokenSelectorComponent.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/components/search/SearchTokenSelectorComponent.kt index 6fe668dc82..dae5eb8b90 100644 --- a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/components/search/SearchTokenSelectorComponent.kt +++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/components/search/SearchTokenSelectorComponent.kt @@ -39,7 +39,6 @@ internal class SearchTokenSelectorComponent @AssistedInject constructor( data class Params( val entries: List, val appCurrency: AppCurrency, - val isBalanceHidden: Boolean, val onTokenSelected: (UserAssetEntry) -> Unit, val onDismiss: () -> Unit, ) diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/search/SearchModel.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/search/SearchModel.kt index 28d4ac7e21..691e91a017 100644 --- a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/search/SearchModel.kt +++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/search/SearchModel.kt @@ -229,7 +229,6 @@ internal class SearchModel @Inject constructor( SearchBottomSheetRoute.TokenSelector( entries = grouped.entries, appCurrency = currentAppCurrency.value, - isBalanceHidden = isBalanceHidden.value, onTokenSelected = ::onTokenSelectedFromGroup, onDismiss = { bottomSheetNavigation.dismiss() }, ), diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/search/SearchTokenSelectorModel.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/search/SearchTokenSelectorModel.kt index fce20d9372..530b37d6a0 100644 --- a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/search/SearchTokenSelectorModel.kt +++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/search/SearchTokenSelectorModel.kt @@ -6,25 +6,31 @@ import com.tangem.common.ui.userwallet.converter.WalletIconUMConverter 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.ui.ds.image.DeviceIconUM +import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase import com.tangem.domain.common.wallets.UserWalletsListRepository +import com.tangem.domain.models.wallet.UserWalletId import com.tangem.domain.wallets.usecase.GetWalletIconUseCase import com.tangem.features.feed.components.search.SearchTokenSelectorComponent import com.tangem.features.feed.model.search.state.TokenSelectorStateController import com.tangem.features.feed.model.search.state.transformers.BuildTokenSelectorSectionsTransformer import com.tangem.utils.coroutines.CoroutineDispatcherProvider import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.filterNotNull -import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch import javax.inject.Inject +@Suppress("LongParameterList") @Stable @ModelScoped internal class SearchTokenSelectorModel @Inject constructor( override val dispatchers: CoroutineDispatcherProvider, paramsContainer: ParamsContainer, + getBalanceHidingSettingsUseCase: GetBalanceHidingSettingsUseCase, + userWalletsListRepository: UserWalletsListRepository, private val stateController: TokenSelectorStateController, - private val userWalletsListRepository: UserWalletsListRepository, private val getWalletIconUseCase: GetWalletIconUseCase, private val walletIconUMConverter: WalletIconUMConverter, ) : Model() { @@ -35,25 +41,37 @@ internal class SearchTokenSelectorModel @Inject constructor( get() = stateController.uiState init { - modelScope.launch(dispatchers.default) { - val requiredWalletIds = params.entries.map { it.userWalletId }.toSet() - val walletIcons = userWalletsListRepository.userWallets - .filterNotNull() - .first() - .filter { it.walletId in requiredWalletIds } - .associate { wallet -> - wallet.walletId to walletIconUMConverter.convert(getWalletIconUseCase(wallet)) - } + val requiredWalletIds = params.entries.map { it.userWalletId }.toSet() + val walletIconsFlow = userWalletsListRepository.userWallets + .filterNotNull() + .map { wallets -> + wallets + .filter { it.walletId in requiredWalletIds } + .associate { wallet -> + wallet.walletId to walletIconUMConverter.convert(getWalletIconUseCase(wallet)) + } + } - stateController.update( - BuildTokenSelectorSectionsTransformer( - entries = params.entries, - appCurrency = params.appCurrency, - isBalanceHidden = params.isBalanceHidden, - walletIcons = walletIcons, - onTokenSelected = params.onTokenSelected, - ), - ) + modelScope.launch(dispatchers.default) { + combine( + walletIconsFlow, + getBalanceHidingSettingsUseCase.isBalanceHidden(), + ::Pair, + ).collect { (walletIcons, isBalanceHidden) -> + rebuildSections(isBalanceHidden, walletIcons) + } } } + + private fun rebuildSections(isBalanceHidden: Boolean, walletIcons: Map) { + stateController.update( + BuildTokenSelectorSectionsTransformer( + entries = params.entries, + appCurrency = params.appCurrency, + isBalanceHidden = isBalanceHidden, + walletIcons = walletIcons, + onTokenSelected = params.onTokenSelected, + ), + ) + } } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/WalletScreen2.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/WalletScreen2.kt index 99fdfba8af..62e8944f16 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/WalletScreen2.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/WalletScreen2.kt @@ -187,6 +187,7 @@ private fun WalletContent2( WalletTopBar( topBarConfig = state.topBarConfig, walletBalance = walletBalance, + isBalanceHidden = state.isHidingMode, behavior = behavior, ) }, diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/common/WalletTopBar.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/common/WalletTopBar.kt index 1bd9089304..16a8840a2d 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/common/WalletTopBar.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/common/WalletTopBar.kt @@ -26,6 +26,7 @@ import com.tangem.core.ui.ds.topbar.TangemTopBarActionUM import com.tangem.core.ui.ds.topbar.collapsing.TangemCollapsingAppBarBehavior import com.tangem.core.ui.ds.topbar.collapsing.rememberTangemExitUntilCollapsedScrollBehavior import com.tangem.core.ui.extensions.TextReference +import com.tangem.core.ui.extensions.orMaskWithStars import com.tangem.core.ui.extensions.stringReference import com.tangem.core.ui.res.LocalRootBackgroundColor import com.tangem.core.ui.res.TangemTheme @@ -46,12 +47,14 @@ private const val VISIBILITY_THRESHOLD = 0.5f * * @param topBarConfig top bar config * @param walletBalance wallet balance text reference + * @param isBalanceHidden whether the balance must be masked with stars * @param behavior collapsing behavior */ @Composable internal fun WalletTopBar( topBarConfig: WalletTopBarConfig, walletBalance: TextReference?, + isBalanceHidden: Boolean, behavior: TangemCollapsingAppBarBehavior, ) { Surface( @@ -63,8 +66,8 @@ internal fun WalletTopBar( derivedStateOf { behavior.state.collapsedFraction > VISIBILITY_THRESHOLD } } - val wrappedBalance = remember(walletBalance, isWrappedBalanceShown) { - walletBalance.takeIf { isWrappedBalanceShown } + val wrappedBalance = remember(walletBalance, isWrappedBalanceShown, isBalanceHidden) { + walletBalance?.orMaskWithStars(isBalanceHidden).takeIf { isWrappedBalanceShown } } TangemTopBar( @@ -173,6 +176,7 @@ private fun WalletTopBar_Preview() { WalletTopBar( topBarConfig = WalletTopBarConfig(), walletBalance = stringReference("$ 8923,05"), + isBalanceHidden = false, behavior = rememberTangemExitUntilCollapsedScrollBehavior(), ) } @@ -197,6 +201,7 @@ private fun WalletTopBar_WithQrButton_Preview() { ), ), walletBalance = stringReference("$ 8923,05"), + isBalanceHidden = false, behavior = rememberTangemExitUntilCollapsedScrollBehavior(), ) }