Updated on 2026-08-14
This commit is contained in:
parent
35f4f97408
commit
8922d23eec
19 changed files with 374 additions and 95 deletions
|
|
@ -102,6 +102,7 @@ fun TangemTopBar(
|
|||
endContent = endContent,
|
||||
content = {
|
||||
Column(
|
||||
modifier = Modifier.weight(1f),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens2.x0_5),
|
||||
) {
|
||||
|
|
@ -128,47 +129,54 @@ fun TangemTopBar(
|
|||
* A top bar composable that displays a title and optional start and end icons.
|
||||
* [Figma](https://www.figma.com/design/RU7AIgwHtGdMfy83T5UOoR/Core-Library?node-id=8435-74860&m=dev)
|
||||
*
|
||||
* @param modifier Modifier to be applied to the top bar.
|
||||
* @param type Type of the top bar, which determines its size and padding.
|
||||
* @param content Composable content to be displayed in the center of the top bar
|
||||
* @param startContent Optional composable content to be displayed at the start (left) of the top bar.
|
||||
* @param endContent Optional composable content to be displayed at the end (right) of the top bar.
|
||||
* @param modifier Modifier to be applied to the top bar.
|
||||
* @param type Type of the top bar, which determines its size and padding.
|
||||
* @param content Composable content to be displayed in the center of the top bar
|
||||
* @param startContent Optional composable content to be displayed at the start (left) of the top bar.
|
||||
* @param endContent Optional composable content to be displayed at the end (right) of the top bar.
|
||||
* @param reserveSlotSpace If true (default), slot space is always reserved even when start/end content is null,
|
||||
* ensuring centered alignment of [content]. Set to false for edge-to-edge content like
|
||||
* search fields, where empty slots should not consume space.
|
||||
*/
|
||||
@Composable
|
||||
fun TangemTopBar(
|
||||
modifier: Modifier = Modifier,
|
||||
type: TangemTopBarType = TangemTopBarType.Default,
|
||||
content: @Composable () -> Unit,
|
||||
reserveSlotSpace: Boolean = true,
|
||||
content: @Composable RowScope.() -> Unit,
|
||||
startContent: @Composable (() -> Unit)? = null,
|
||||
endContent: @Composable (() -> Unit)? = null,
|
||||
) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.heightIn(min = type.getSize())
|
||||
.padding(type.getPadding()),
|
||||
) {
|
||||
AnimatedContent(
|
||||
targetState = startContent != null,
|
||||
modifier = Modifier.size(TangemTheme.dimens2.x11),
|
||||
label = "Start Content Visibility",
|
||||
) { isVisible ->
|
||||
if (isVisible) {
|
||||
startContent?.invoke()
|
||||
if (reserveSlotSpace || startContent != null) {
|
||||
AnimatedContent(
|
||||
targetState = startContent != null,
|
||||
modifier = Modifier.size(TangemTheme.dimens2.x11),
|
||||
label = "Start Content Visibility",
|
||||
) { isVisible ->
|
||||
if (isVisible) {
|
||||
startContent?.invoke()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
content()
|
||||
|
||||
AnimatedContent(
|
||||
targetState = endContent != null,
|
||||
modifier = Modifier.size(TangemTheme.dimens2.x11),
|
||||
label = "End Content Visibility",
|
||||
) { isVisible ->
|
||||
if (isVisible) {
|
||||
endContent?.invoke()
|
||||
if (reserveSlotSpace || endContent != null) {
|
||||
AnimatedContent(
|
||||
targetState = endContent != null,
|
||||
modifier = Modifier.size(TangemTheme.dimens2.x11),
|
||||
label = "End Content Visibility",
|
||||
) { isVisible ->
|
||||
if (isVisible) {
|
||||
endContent?.invoke()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@ internal class DefaultFeedEntryComponent @AssistedInject constructor(
|
|||
screenSource = AnalyticsParam.ScreensSources.Token,
|
||||
)
|
||||
},
|
||||
onMarketOpenClick = { onMarketOpenClick(null) },
|
||||
),
|
||||
),
|
||||
)
|
||||
|
|
@ -136,7 +137,10 @@ internal class DefaultFeedEntryComponent @AssistedInject constructor(
|
|||
override fun onOpenEarnPage() {
|
||||
innerRouter.push(
|
||||
FeedEntryChildFactory.Child.Earn(
|
||||
params = DefaultEarnComponent.Params(onBackClick = { onChildBack() }),
|
||||
params = DefaultEarnComponent.Params(
|
||||
onBackClick = { onChildBack() },
|
||||
onMarketOpenClick = { onMarketOpenClick(null) },
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -240,6 +244,7 @@ internal class DefaultFeedEntryComponent @AssistedInject constructor(
|
|||
paginationConfig = null,
|
||||
)
|
||||
},
|
||||
onMarketOpenClick = { clickIntents.onMarketOpenClick(null) },
|
||||
),
|
||||
)
|
||||
FeedEntryRoute.MarketTokenList -> FeedEntryChildFactory.Child.TokenList(
|
||||
|
|
|
|||
|
|
@ -1,9 +1,17 @@
|
|||
package com.tangem.features.feed.components.earn
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
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.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.drawBehind
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.arkivanov.decompose.ComponentContext
|
||||
import com.arkivanov.decompose.extensions.compose.subscribeAsState
|
||||
|
|
@ -17,11 +25,15 @@ import com.tangem.core.ui.components.appbar.models.TopAppBarButtonUM
|
|||
import com.tangem.core.ui.components.bottomsheets.state.BottomSheetState
|
||||
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
|
||||
import com.tangem.core.ui.decompose.ComposableModularBottomSheetContentComponent
|
||||
import com.tangem.core.ui.extensions.clickableSingle
|
||||
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||
import com.tangem.core.ui.res.LocalMainBottomSheetColor
|
||||
import com.tangem.core.ui.res.LocalRedesignEnabled
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.features.feed.components.feed.FeedBottomSheetRoute
|
||||
import com.tangem.features.feed.components.market.details.portfolio.add.AddToPortfolioPreselectedDataComponent
|
||||
import com.tangem.features.feed.model.earn.EarnModel
|
||||
import com.tangem.features.feed.ui.components.FeedSearchBar
|
||||
import com.tangem.features.feed.ui.earn.EarnContent
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
|
|
@ -44,15 +56,41 @@ internal class DefaultEarnComponent(
|
|||
override fun Title(bottomSheetState: State<BottomSheetState>) {
|
||||
val background = LocalMainBottomSheetColor.current.value
|
||||
val state by earnModel.state.collectAsStateWithLifecycle()
|
||||
TangemTopAppBar(
|
||||
containerColor = background,
|
||||
title = stringResourceSafe(R.string.earn_title),
|
||||
startButton = TopAppBarButtonUM.Icon(
|
||||
iconRes = R.drawable.ic_back_24,
|
||||
onClicked = state.onBackClick,
|
||||
isEnabled = bottomSheetState.value == BottomSheetState.EXPANDED,
|
||||
),
|
||||
)
|
||||
if (LocalRedesignEnabled.current) {
|
||||
FeedSearchBar(
|
||||
isSearchBarClickable = bottomSheetState.value == BottomSheetState.EXPANDED,
|
||||
feedListSearchBar = state.feedListSearchBar,
|
||||
modifier = Modifier.drawBehind { drawRect(background) },
|
||||
startContent = {
|
||||
Icon(
|
||||
imageVector = ImageVector.vectorResource(id = R.drawable.ic_arrow_back_28),
|
||||
contentDescription = null,
|
||||
tint = TangemTheme.colors2.graphic.neutral.primary,
|
||||
modifier = Modifier
|
||||
.size(TangemTheme.dimens2.x11)
|
||||
.background(
|
||||
color = TangemTheme.colors2.button.backgroundSecondary,
|
||||
shape = CircleShape,
|
||||
)
|
||||
.clickableSingle(
|
||||
onClick = state.onBackClick,
|
||||
enabled = bottomSheetState.value == BottomSheetState.EXPANDED,
|
||||
)
|
||||
.padding(TangemTheme.dimens2.x2),
|
||||
)
|
||||
},
|
||||
)
|
||||
} else {
|
||||
TangemTopAppBar(
|
||||
containerColor = background,
|
||||
title = stringResourceSafe(R.string.earn_title),
|
||||
startButton = TopAppBarButtonUM.Icon(
|
||||
iconRes = R.drawable.ic_back_24,
|
||||
onClicked = state.onBackClick,
|
||||
isEnabled = bottomSheetState.value == BottomSheetState.EXPANDED,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
|
@ -94,5 +132,6 @@ internal class DefaultEarnComponent(
|
|||
@Serializable
|
||||
data class Params(
|
||||
val onBackClick: () -> Unit,
|
||||
val onMarketOpenClick: () -> Unit,
|
||||
)
|
||||
}
|
||||
|
|
@ -1,10 +1,18 @@
|
|||
package com.tangem.features.feed.components.market.details
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
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.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.drawBehind
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.lifecycle.compose.LifecycleStartEffect
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.tangem.blockchainsdk.compatibility.getTokenIdIfL2Network
|
||||
|
|
@ -12,9 +20,13 @@ import com.tangem.core.analytics.api.AnalyticsEventHandler
|
|||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.context.child
|
||||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.components.bottomsheets.state.BottomSheetState
|
||||
import com.tangem.core.ui.decompose.ComposableModularBottomSheetContentComponent
|
||||
import com.tangem.core.ui.extensions.clickableSingle
|
||||
import com.tangem.core.ui.res.LocalMainBottomSheetColor
|
||||
import com.tangem.core.ui.res.LocalRedesignEnabled
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.markets.TokenMarketParams
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
|
|
@ -22,6 +34,7 @@ import com.tangem.features.feed.components.market.details.portfolio.api.MarketsP
|
|||
import com.tangem.features.feed.model.market.details.MarketsTokenDetailsModel
|
||||
import com.tangem.features.feed.model.market.details.analytics.MarketDetailsAnalyticsEvent
|
||||
import com.tangem.features.feed.model.market.details.state.TokenNetworksState
|
||||
import com.tangem.features.feed.ui.components.FeedSearchBar
|
||||
import com.tangem.features.feed.ui.market.detailed.MarketsTokenDetailsContent
|
||||
import com.tangem.features.feed.ui.market.detailed.MarketsTokenDetailsTopBar
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
|
|
@ -86,15 +99,59 @@ internal class DefaultMarketsTokenDetailsComponent(
|
|||
override fun Title(bottomSheetState: State<BottomSheetState>) {
|
||||
val state by model.state.collectAsStateWithLifecycle()
|
||||
val background = LocalMainBottomSheetColor.current.value
|
||||
MarketsTokenDetailsTopBar(
|
||||
onBackClick = { params.onBackClicked() },
|
||||
isBackButtonEnabled = bottomSheetState.value == BottomSheetState.EXPANDED,
|
||||
shouldShowPriceSubtitle = state.shouldShowPriceSubtitle,
|
||||
tokenName = state.tokenName,
|
||||
tokenPrice = state.priceText,
|
||||
backgroundColor = background,
|
||||
onShareClick = state.onShareClick,
|
||||
)
|
||||
if (LocalRedesignEnabled.current) {
|
||||
FeedSearchBar(
|
||||
isSearchBarClickable = bottomSheetState.value == BottomSheetState.EXPANDED,
|
||||
feedListSearchBar = state.feedListSearchBar,
|
||||
modifier = Modifier.drawBehind { drawRect(background) },
|
||||
startContent = {
|
||||
Icon(
|
||||
imageVector = ImageVector.vectorResource(id = R.drawable.ic_arrow_back_28),
|
||||
contentDescription = null,
|
||||
tint = TangemTheme.colors2.graphic.neutral.primary,
|
||||
modifier = Modifier
|
||||
.size(TangemTheme.dimens2.x11)
|
||||
.background(
|
||||
color = TangemTheme.colors2.button.backgroundSecondary,
|
||||
shape = CircleShape,
|
||||
)
|
||||
.clickableSingle(
|
||||
onClick = { params.onBackClicked() },
|
||||
enabled = bottomSheetState.value == BottomSheetState.EXPANDED,
|
||||
)
|
||||
.padding(TangemTheme.dimens2.x2),
|
||||
)
|
||||
},
|
||||
endContent = {
|
||||
Icon(
|
||||
imageVector = ImageVector.vectorResource(id = R.drawable.ic_share_new_24),
|
||||
contentDescription = null,
|
||||
tint = TangemTheme.colors2.graphic.neutral.primary,
|
||||
modifier = Modifier
|
||||
.size(TangemTheme.dimens2.x11)
|
||||
.background(
|
||||
color = TangemTheme.colors2.button.backgroundSecondary,
|
||||
shape = CircleShape,
|
||||
)
|
||||
.clickableSingle(
|
||||
onClick = state.onShareClick,
|
||||
enabled = bottomSheetState.value == BottomSheetState.EXPANDED,
|
||||
)
|
||||
.padding(TangemTheme.dimens2.x2_5),
|
||||
)
|
||||
},
|
||||
)
|
||||
} else {
|
||||
MarketsTokenDetailsTopBar(
|
||||
onBackClick = { params.onBackClicked() },
|
||||
isBackButtonEnabled = bottomSheetState.value == BottomSheetState.EXPANDED,
|
||||
shouldShowPriceSubtitle = state.shouldShowPriceSubtitle,
|
||||
tokenName = state.tokenName,
|
||||
tokenPrice = state.priceText,
|
||||
backgroundColor = background,
|
||||
onShareClick = state.onShareClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
|
@ -131,6 +188,7 @@ internal class DefaultMarketsTokenDetailsComponent(
|
|||
val analyticsParams: AnalyticsParams?,
|
||||
val onBackClicked: () -> Unit,
|
||||
val onArticleClick: (articleId: Int, preselectedArticlesId: List<Int>) -> Unit,
|
||||
val onMarketOpenClick: () -> Unit,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ import com.tangem.core.ui.decompose.ComposableModularBottomSheetContentComponent
|
|||
import com.tangem.core.ui.ds.topbar.TangemTopBar
|
||||
import com.tangem.core.ui.ds.topbar.TangemTopBarType
|
||||
import com.tangem.core.ui.extensions.clickableSingle
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.res.LocalMainBottomSheetColor
|
||||
import com.tangem.core.ui.res.LocalRedesignEnabled
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
|
|
@ -47,7 +46,6 @@ internal class DefaultNewsDetailsComponent(
|
|||
val state by newsDetailsModel.state.collectAsStateWithLifecycle()
|
||||
if (LocalRedesignEnabled.current) {
|
||||
TangemTopBar(
|
||||
title = resourceReference(R.string.common_news),
|
||||
type = TangemTopBarType.BottomSheet,
|
||||
startContent = {
|
||||
Icon(
|
||||
|
|
|
|||
|
|
@ -325,6 +325,7 @@ internal class EarnModel @Inject constructor(
|
|||
onNetworkFilterClick = ::onNetworkFilterClick,
|
||||
onTypeFilterClick = ::onTypeFilterClick,
|
||||
onScroll = ::onMostlyUsedScrolled,
|
||||
onSearchBarClicked = params.onMarketOpenClick,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
package com.tangem.features.feed.model.earn.state
|
||||
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.features.feed.model.earn.state.transformers.EarnUMTransformer
|
||||
import com.tangem.features.feed.ui.earn.state.*
|
||||
import com.tangem.features.feed.ui.feed.state.FeedListSearchBar
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
|
|
@ -34,6 +36,10 @@ internal class EarnStateController @Inject constructor() {
|
|||
onNetworkFilterClick = {},
|
||||
onTypeFilterClick = {},
|
||||
onSliderScroll = {},
|
||||
feedListSearchBar = FeedListSearchBar(
|
||||
placeholderText = TextReference.EMPTY,
|
||||
onBarClick = {},
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,12 +1,16 @@
|
|||
package com.tangem.features.feed.model.earn.state.transformers
|
||||
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.features.feed.impl.R
|
||||
import com.tangem.features.feed.ui.earn.state.EarnUM
|
||||
import com.tangem.features.feed.ui.feed.state.FeedListSearchBar
|
||||
|
||||
internal class UpdateEarnUMInitialStateTransformer(
|
||||
private val onBackClick: () -> Unit,
|
||||
private val onNetworkFilterClick: () -> Unit,
|
||||
private val onTypeFilterClick: () -> Unit,
|
||||
private val onScroll: () -> Unit,
|
||||
private val onSearchBarClicked: () -> Unit,
|
||||
) : EarnUMTransformer {
|
||||
|
||||
override fun transform(prevState: EarnUM): EarnUM {
|
||||
|
|
@ -15,6 +19,10 @@ internal class UpdateEarnUMInitialStateTransformer(
|
|||
onNetworkFilterClick = onNetworkFilterClick,
|
||||
onTypeFilterClick = onTypeFilterClick,
|
||||
onSliderScroll = onScroll,
|
||||
feedListSearchBar = FeedListSearchBar(
|
||||
onBarClick = onSearchBarClicked,
|
||||
placeholderText = resourceReference(id = R.string.markets_search_title_placeholder),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -232,7 +232,13 @@ internal class FeedComponentModel @Inject constructor(
|
|||
return FeedListUM(
|
||||
currentDate = getCurrentDate(),
|
||||
feedListSearchBar = FeedListSearchBar(
|
||||
placeholderText = resourceReference(R.string.markets_search_header_title),
|
||||
placeholderText = resourceReference(
|
||||
id = if (feedFeatureToggle.isEarnBlockEnabled) {
|
||||
R.string.markets_search_title_placeholder
|
||||
} else {
|
||||
R.string.markets_search_header_title
|
||||
},
|
||||
),
|
||||
onBarClick = {
|
||||
analyticsEventHandler.send(FeedAnalyticsEvent.TokenSearchedClicked())
|
||||
params.feedClickIntents.onMarketOpenClick(null)
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ import com.tangem.features.feed.model.market.details.converter.TokenMarketInfoCo
|
|||
import com.tangem.features.feed.model.market.details.formatter.*
|
||||
import com.tangem.features.feed.model.market.details.state.QuotesStateUpdater
|
||||
import com.tangem.features.feed.model.market.details.state.TokenNetworksState
|
||||
import com.tangem.features.feed.ui.feed.state.FeedListSearchBar
|
||||
import com.tangem.features.feed.ui.market.detailed.state.ExchangesBottomSheetContent
|
||||
import com.tangem.features.feed.ui.market.detailed.state.MarketsTokenDetailsUM
|
||||
import com.tangem.lib.crypto.BlockchainUtils
|
||||
|
|
@ -258,6 +259,10 @@ internal class MarketsTokenDetailsModel @Inject constructor(
|
|||
onScroll = {},
|
||||
),
|
||||
onShareClick = ::onShareClick,
|
||||
feedListSearchBar = FeedListSearchBar(
|
||||
onBarClick = { params.onMarketOpenClick() },
|
||||
placeholderText = resourceReference(id = R.string.markets_search_title_placeholder),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,136 @@
|
|||
package com.tangem.features.feed.ui.components
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.components.SpacerW
|
||||
import com.tangem.core.ui.ds.topbar.TangemTopBar
|
||||
import com.tangem.core.ui.ds.topbar.TangemTopBarType
|
||||
import com.tangem.core.ui.extensions.conditional
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.res.LocalRedesignEnabled
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.features.feed.ui.feed.state.FeedListSearchBar
|
||||
|
||||
@Composable
|
||||
internal fun FeedSearchBar(
|
||||
isSearchBarClickable: Boolean,
|
||||
feedListSearchBar: FeedListSearchBar,
|
||||
modifier: Modifier = Modifier,
|
||||
startContent: @Composable (() -> Unit)? = null,
|
||||
endContent: @Composable (() -> Unit)? = null,
|
||||
) {
|
||||
if (LocalRedesignEnabled.current) {
|
||||
FeedSearchBarV2(
|
||||
isSearchBarClickable = isSearchBarClickable,
|
||||
feedListSearchBar = feedListSearchBar,
|
||||
modifier = modifier,
|
||||
startContent = startContent,
|
||||
endContent = endContent,
|
||||
)
|
||||
} else {
|
||||
FeedSearchBarV1(
|
||||
isSearchBarClickable = isSearchBarClickable,
|
||||
feedListSearchBar = feedListSearchBar,
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun FeedSearchBarV1(
|
||||
isSearchBarClickable: Boolean,
|
||||
feedListSearchBar: FeedListSearchBar,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Row(
|
||||
modifier = modifier
|
||||
.padding(horizontal = 16.dp)
|
||||
.padding(bottom = 8.dp)
|
||||
.fillMaxWidth()
|
||||
.clip(RoundedCornerShape(36.dp))
|
||||
.background(color = TangemTheme.colors.field.focused)
|
||||
.conditional(condition = isSearchBarClickable) {
|
||||
clickable(onClick = feedListSearchBar.onBarClick)
|
||||
}
|
||||
.padding(14.dp),
|
||||
) {
|
||||
Icon(
|
||||
modifier = Modifier.size(TangemTheme.dimens.size20),
|
||||
imageVector = ImageVector.vectorResource(id = R.drawable.ic_search_24),
|
||||
tint = TangemTheme.colors.icon.informative,
|
||||
contentDescription = null,
|
||||
)
|
||||
|
||||
SpacerW(14.dp)
|
||||
|
||||
Text(
|
||||
text = feedListSearchBar.placeholderText.resolveReference(),
|
||||
style = TangemTheme.typography.body2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun FeedSearchBarV2(
|
||||
isSearchBarClickable: Boolean,
|
||||
feedListSearchBar: FeedListSearchBar,
|
||||
modifier: Modifier = Modifier,
|
||||
startContent: @Composable (() -> Unit)? = null,
|
||||
endContent: @Composable (() -> Unit)? = null,
|
||||
) {
|
||||
TangemTopBar(
|
||||
modifier = modifier,
|
||||
startContent = startContent,
|
||||
endContent = endContent,
|
||||
type = TangemTopBarType.BottomSheet,
|
||||
reserveSlotSpace = false,
|
||||
content = {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.padding(
|
||||
start = if (startContent != null) TangemTheme.dimens2.x3 else 0.dp,
|
||||
end = if (endContent != null) TangemTheme.dimens2.x3 else 0.dp,
|
||||
)
|
||||
.clip(CircleShape)
|
||||
.background(color = TangemTheme.colors2.field.backgroundDefault)
|
||||
.conditional(condition = isSearchBarClickable) {
|
||||
clickable(onClick = feedListSearchBar.onBarClick)
|
||||
}
|
||||
.padding(TangemTheme.dimens2.x3),
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
) {
|
||||
Icon(
|
||||
modifier = Modifier.size(TangemTheme.dimens2.x5),
|
||||
imageVector = ImageVector.vectorResource(id = R.drawable.ic_search_default_24),
|
||||
tint = TangemTheme.colors2.markers.iconGray,
|
||||
contentDescription = null,
|
||||
)
|
||||
|
||||
SpacerW(TangemTheme.dimens2.x1)
|
||||
|
||||
Text(
|
||||
text = feedListSearchBar.placeholderText.resolveReference(),
|
||||
style = TangemTheme.typography2.bodySemibold16,
|
||||
color = TangemTheme.colors2.text.neutral.tertiary,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
@ -22,6 +22,7 @@ import com.tangem.core.ui.components.*
|
|||
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
||||
import com.tangem.core.ui.components.list.InfiniteListHandler
|
||||
import com.tangem.core.ui.decorations.roundedShapeItemDecoration
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.conditional
|
||||
import com.tangem.core.ui.extensions.conditionalCompose
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
|
|
@ -29,6 +30,7 @@ import com.tangem.core.ui.extensions.stringResourceSafe
|
|||
import com.tangem.core.ui.res.*
|
||||
import com.tangem.features.feed.ui.earn.components.*
|
||||
import com.tangem.features.feed.ui.earn.state.*
|
||||
import com.tangem.features.feed.ui.feed.state.FeedListSearchBar
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
||||
private const val EARN_LOAD_MORE_BUFFER = 3
|
||||
|
|
@ -655,6 +657,10 @@ private fun previewEarnUM(
|
|||
onNetworkFilterClick = {},
|
||||
onTypeFilterClick = {},
|
||||
onSliderScroll = {},
|
||||
feedListSearchBar = FeedListSearchBar(
|
||||
placeholderText = TextReference.Str("Search tokens & news"),
|
||||
onBarClick = {},
|
||||
),
|
||||
)
|
||||
|
||||
private const val PLACEHOLDER_ITEMS_COUNT = 8
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.features.feed.ui.earn.state
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.tangem.features.feed.ui.feed.state.FeedListSearchBar
|
||||
|
||||
@Immutable
|
||||
internal data class EarnUM(
|
||||
|
|
@ -11,4 +12,5 @@ internal data class EarnUM(
|
|||
val onNetworkFilterClick: () -> Unit,
|
||||
val onTypeFilterClick: () -> Unit,
|
||||
val onSliderScroll: () -> Unit,
|
||||
val feedListSearchBar: FeedListSearchBar,
|
||||
)
|
||||
|
|
@ -4,34 +4,22 @@ import androidx.compose.animation.AnimatedContent
|
|||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.animation.togetherWith
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.draw.drawBehind
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.components.SpacerH
|
||||
import com.tangem.core.ui.components.SpacerW
|
||||
import com.tangem.core.ui.extensions.conditional
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.core.ui.res.LocalMainBottomSheetColor
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.core.ui.test.BaseSearchBarTestTags.SEARCH_BAR
|
||||
import com.tangem.features.feed.model.market.list.state.SortByTypeUM
|
||||
import com.tangem.features.feed.ui.components.FeedSearchBar
|
||||
import com.tangem.features.feed.ui.feed.components.*
|
||||
import com.tangem.features.feed.ui.feed.preview.FeedListPreviewDataProvider.createFeedPreviewState
|
||||
import com.tangem.features.feed.ui.feed.state.FeedListSearchBar
|
||||
|
|
@ -50,8 +38,6 @@ internal fun FeedListHeader(
|
|||
feedListSearchBar = feedListSearchBar,
|
||||
modifier = modifier
|
||||
.drawBehind { drawRect(background) }
|
||||
.padding(horizontal = 16.dp)
|
||||
.padding(bottom = 8.dp)
|
||||
.testTag(SEARCH_BAR),
|
||||
)
|
||||
}
|
||||
|
|
@ -95,39 +81,6 @@ internal fun FeedList(
|
|||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun FeedSearchBar(
|
||||
isSearchBarClickable: Boolean,
|
||||
feedListSearchBar: FeedListSearchBar,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Row(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.clip(RoundedCornerShape(36.dp))
|
||||
.background(color = TangemTheme.colors.field.focused)
|
||||
.conditional(condition = isSearchBarClickable) {
|
||||
clickable(onClick = feedListSearchBar.onBarClick)
|
||||
}
|
||||
.padding(14.dp),
|
||||
) {
|
||||
Icon(
|
||||
modifier = Modifier.size(TangemTheme.dimens.size20),
|
||||
imageVector = ImageVector.vectorResource(id = R.drawable.ic_search_24),
|
||||
tint = TangemTheme.colors.icon.informative,
|
||||
contentDescription = null,
|
||||
)
|
||||
|
||||
SpacerW(14.dp)
|
||||
|
||||
Text(
|
||||
text = feedListSearchBar.placeholderText.resolveReference(),
|
||||
style = TangemTheme.typography.body2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun FeedListContent(
|
||||
state: FeedListUM,
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import androidx.compose.ui.res.vectorResource
|
|||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.components.RectangleShimmer
|
||||
import com.tangem.core.ui.components.SpacerH
|
||||
import com.tangem.core.ui.components.SpacerW
|
||||
import com.tangem.core.ui.components.buttons.SecondarySmallButton
|
||||
import com.tangem.core.ui.components.buttons.SmallButtonConfig
|
||||
|
|
@ -23,13 +24,16 @@ import com.tangem.core.ui.res.LocalRedesignEnabled
|
|||
import com.tangem.core.ui.res.TangemTheme
|
||||
|
||||
@Composable
|
||||
internal fun Header(
|
||||
internal fun ColumnScope.Header(
|
||||
onSeeAllClick: () -> Unit,
|
||||
isLoading: Boolean,
|
||||
shouldShowSeeAll: Boolean,
|
||||
title: @Composable () -> Unit,
|
||||
) {
|
||||
val isRedesignEnabled = LocalRedesignEnabled.current
|
||||
if (isRedesignEnabled) {
|
||||
SpacerH(20.dp)
|
||||
}
|
||||
AnimatedContent(isLoading) { animatedState ->
|
||||
Row(
|
||||
modifier = Modifier
|
||||
|
|
|
|||
|
|
@ -9,10 +9,20 @@ import androidx.compose.ui.unit.dp
|
|||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.components.SpacerH
|
||||
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||
import com.tangem.core.ui.res.LocalRedesignEnabled
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
|
||||
@Composable
|
||||
internal fun DateBlock(currentDate: String) {
|
||||
if (LocalRedesignEnabled.current) {
|
||||
DateBlockV2(currentDate)
|
||||
} else {
|
||||
DateBlockV1(currentDate)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun DateBlockV1(currentDate: String) {
|
||||
SpacerH(20.dp)
|
||||
Text(
|
||||
modifier = Modifier
|
||||
|
|
@ -30,4 +40,26 @@ internal fun DateBlock(currentDate: String) {
|
|||
style = TangemTheme.typography.h2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun DateBlockV2(currentDate: String) {
|
||||
SpacerH(TangemTheme.dimens2.x1)
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 24.dp),
|
||||
text = stringResourceSafe(R.string.feed_market_and_news),
|
||||
style = TangemTheme.typography2.headingRegular28,
|
||||
color = TangemTheme.colors2.text.neutral.primary,
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 24.dp),
|
||||
text = currentDate,
|
||||
style = TangemTheme.typography2.headingRegular28,
|
||||
color = TangemTheme.colors2.text.neutral.tertiary,
|
||||
)
|
||||
SpacerH(TangemTheme.dimens2.x6)
|
||||
}
|
||||
|
|
@ -71,7 +71,7 @@ internal fun MarketBlock(marketChart: MarketChartUM?, feedListCallbacks: FeedLis
|
|||
isLoading = currentChart is MarketChartUM.Loading,
|
||||
)
|
||||
|
||||
SpacerH(12.dp)
|
||||
SpacerH(if (isRedesignEnabled) 20.dp else 12.dp)
|
||||
|
||||
Charts(
|
||||
onItemClick = feedListCallbacks.onMarketItemClick,
|
||||
|
|
@ -89,7 +89,7 @@ internal fun MarketBlock(marketChart: MarketChartUM?, feedListCallbacks: FeedLis
|
|||
|
||||
@Suppress("LongMethod")
|
||||
@Composable
|
||||
internal fun MarketPulseBlock(marketChartConfig: MarketChartConfig, feedListCallbacks: FeedListCallbacks) {
|
||||
internal fun ColumnScope.MarketPulseBlock(marketChartConfig: MarketChartConfig, feedListCallbacks: FeedListCallbacks) {
|
||||
val isRedesignEnabled = LocalRedesignEnabled.current
|
||||
val onSeeAllClick by rememberUpdatedState {
|
||||
feedListCallbacks.onMarketOpenClick(marketChartConfig.currentSortByType)
|
||||
|
|
|
|||
|
|
@ -5,8 +5,10 @@ import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
|||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
|
||||
import com.tangem.core.ui.components.marketprice.PriceChangeType
|
||||
import com.tangem.core.ui.event.consumedEvent
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.domain.markets.PriceChangeInterval
|
||||
import com.tangem.features.feed.ui.feed.state.FeedListSearchBar
|
||||
import com.tangem.features.feed.ui.market.detailed.state.*
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
||||
|
|
@ -50,6 +52,10 @@ internal object MarketsTokenDetailsPreview {
|
|||
onScroll = {},
|
||||
),
|
||||
onShareClick = {},
|
||||
feedListSearchBar = FeedListSearchBar(
|
||||
placeholderText = TextReference.Str("Search tokens & news"),
|
||||
onBarClick = {},
|
||||
),
|
||||
)
|
||||
|
||||
val contentState = MarketsTokenDetailsUM(
|
||||
|
|
@ -144,5 +150,9 @@ internal object MarketsTokenDetailsPreview {
|
|||
onScroll = {},
|
||||
),
|
||||
onShareClick = {},
|
||||
feedListSearchBar = FeedListSearchBar(
|
||||
placeholderText = TextReference.Str("Search tokens & news"),
|
||||
onBarClick = {},
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -8,6 +8,7 @@ import com.tangem.core.ui.components.marketprice.PriceChangeType
|
|||
import com.tangem.core.ui.event.StateEvent
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.domain.markets.PriceChangeInterval
|
||||
import com.tangem.features.feed.ui.feed.state.FeedListSearchBar
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import java.math.BigDecimal
|
||||
|
||||
|
|
@ -29,6 +30,7 @@ internal data class MarketsTokenDetailsUM(
|
|||
val onShouldShowPriceSubtitleChange: (Boolean) -> Unit,
|
||||
val relatedNews: RelatedNews,
|
||||
val onShareClick: () -> Unit,
|
||||
val feedListSearchBar: FeedListSearchBar,
|
||||
) {
|
||||
|
||||
data class ChartState(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue