Updated on 2026-08-14
This commit is contained in:
parent
fea0ea5890
commit
142ba20e35
11 changed files with 203 additions and 52 deletions
|
|
@ -1,11 +1,13 @@
|
|||
package com.tangem.core.ui.decorations
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.composed
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
|
||||
|
|
@ -15,46 +17,49 @@ fun Modifier.roundedShapeItemDecoration(
|
|||
lastIndex: Int,
|
||||
addDefaultPadding: Boolean = true,
|
||||
radius: Dp = TangemTheme.dimens.radius16,
|
||||
backgroundColor: Color? = null,
|
||||
): Modifier = composed {
|
||||
val modifier = if (addDefaultPadding) this.padding(horizontal = TangemTheme.dimens.spacing16) else this
|
||||
|
||||
val applyTopPadding: @Composable Modifier.() -> Modifier = {
|
||||
if (addDefaultPadding) {
|
||||
padding(top = TangemTheme.dimens.spacing12)
|
||||
} else {
|
||||
this
|
||||
}
|
||||
}
|
||||
|
||||
val applyShape: Modifier.(shape: RoundedCornerShape?) -> Modifier = { shape ->
|
||||
if (backgroundColor != null) {
|
||||
if (shape != null) {
|
||||
background(color = backgroundColor, shape = shape)
|
||||
} else {
|
||||
background(color = backgroundColor)
|
||||
}
|
||||
} else {
|
||||
if (shape != null) {
|
||||
clip(shape = shape)
|
||||
} else {
|
||||
this
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val isSingleItem = currentIndex == 0 && lastIndex == 0
|
||||
when {
|
||||
isSingleItem -> {
|
||||
modifier
|
||||
.then(
|
||||
if (addDefaultPadding) {
|
||||
Modifier.padding(top = TangemTheme.dimens.spacing12)
|
||||
} else {
|
||||
Modifier
|
||||
},
|
||||
)
|
||||
.clip(shape = RoundedCornerShape(radius))
|
||||
.applyTopPadding()
|
||||
.applyShape(RoundedCornerShape(radius))
|
||||
}
|
||||
currentIndex == 0 -> {
|
||||
modifier
|
||||
.then(
|
||||
if (addDefaultPadding) {
|
||||
Modifier.padding(top = TangemTheme.dimens.spacing12)
|
||||
} else {
|
||||
Modifier
|
||||
},
|
||||
)
|
||||
.clip(
|
||||
shape = RoundedCornerShape(
|
||||
topStart = radius,
|
||||
topEnd = radius,
|
||||
),
|
||||
)
|
||||
.applyTopPadding()
|
||||
.applyShape(RoundedCornerShape(topStart = radius, topEnd = radius))
|
||||
}
|
||||
currentIndex == lastIndex -> {
|
||||
modifier
|
||||
.clip(
|
||||
shape = RoundedCornerShape(
|
||||
bottomStart = radius,
|
||||
bottomEnd = radius,
|
||||
),
|
||||
)
|
||||
modifier.applyShape(RoundedCornerShape(bottomStart = radius, bottomEnd = radius))
|
||||
}
|
||||
else -> modifier
|
||||
else -> modifier.applyShape(null)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
package com.tangem.feature.wallet.presentation.selecttoken
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.context.child
|
||||
import com.tangem.feature.wallet.presentation.selecttoken.ui.SelectToken
|
||||
import com.tangem.feature.wallet.presentation.tokenlist.TokenListComponent
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
|
||||
internal class DefaultSelectTokenComponent @AssistedInject constructor(
|
||||
@Assisted appComponentContext: AppComponentContext,
|
||||
tokenListComponentFactory: TokenListComponent.Factory,
|
||||
@Assisted private val params: SelectTokenComponent.Params,
|
||||
) : AppComponentContext by appComponentContext, SelectTokenComponent {
|
||||
|
||||
private val tokenListComponent: TokenListComponent = tokenListComponentFactory.create(
|
||||
context = child(key = "token_list"),
|
||||
params = TokenListComponent.Params(
|
||||
hasSearchBar = params.hasSearchBar,
|
||||
userWalletId = params.userWalletId,
|
||||
onTokenClick = params.onTokenClick,
|
||||
),
|
||||
)
|
||||
|
||||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
SelectToken(
|
||||
titleResId = params.titleResId,
|
||||
onBackClick = router::pop,
|
||||
tokenListComponent = tokenListComponent,
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory : SelectTokenComponent.Factory {
|
||||
|
||||
override fun create(
|
||||
context: AppComponentContext,
|
||||
params: SelectTokenComponent.Params,
|
||||
): DefaultSelectTokenComponent
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
package com.tangem.feature.wallet.presentation.selecttoken
|
||||
|
||||
import androidx.annotation.StringRes
|
||||
import com.tangem.core.decompose.factory.ComponentFactory
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
|
||||
/**
|
||||
* Select token component
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
interface SelectTokenComponent : ComposableContentComponent {
|
||||
|
||||
interface Factory : ComponentFactory<Params, SelectTokenComponent>
|
||||
|
||||
/**
|
||||
* Params
|
||||
*
|
||||
* @property hasSearchBar flag that indicates if search bar should be shown
|
||||
* @property userWalletId id of multi-currency wallet
|
||||
* @property titleResId resource id of title
|
||||
* @property onTokenClick callback for token click
|
||||
*/
|
||||
data class Params(
|
||||
val hasSearchBar: Boolean,
|
||||
val userWalletId: UserWalletId,
|
||||
@StringRes val titleResId: Int,
|
||||
val onTokenClick: (CryptoCurrencyStatus) -> Unit,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package com.tangem.feature.wallet.presentation.selecttoken.di
|
||||
|
||||
import com.tangem.feature.wallet.presentation.selecttoken.DefaultSelectTokenComponent
|
||||
import com.tangem.feature.wallet.presentation.selecttoken.SelectTokenComponent
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal interface SelectTokenComponentModule {
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
fun bindSelectTokenComponentFactory(factory: DefaultSelectTokenComponent.Factory): SelectTokenComponent.Factory
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
package com.tangem.feature.wallet.presentation.selecttoken.ui
|
||||
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.imePadding
|
||||
import androidx.compose.foundation.layout.systemBarsPadding
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.components.appbar.AppBarWithBackButton
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.feature.wallet.impl.R
|
||||
import com.tangem.feature.wallet.presentation.tokenlist.TokenListComponent
|
||||
|
||||
@Composable
|
||||
internal fun SelectToken(
|
||||
@StringRes titleResId: Int,
|
||||
onBackClick: () -> Unit,
|
||||
tokenListComponent: TokenListComponent,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
BackHandler(onBack = onBackClick)
|
||||
|
||||
Column(
|
||||
modifier = modifier
|
||||
.background(TangemTheme.colors.background.secondary)
|
||||
.imePadding()
|
||||
.systemBarsPadding(),
|
||||
) {
|
||||
AppBarWithBackButton(
|
||||
onBackClick = onBackClick,
|
||||
text = stringResource(id = titleResId),
|
||||
iconRes = R.drawable.ic_close_24,
|
||||
)
|
||||
|
||||
tokenListComponent.Content(
|
||||
contentPadding = PaddingValues(vertical = 8.dp, horizontal = 16.dp),
|
||||
modifier = Modifier,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.feature.wallet.presentation.tokenlist
|
||||
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.runtime.getValue
|
||||
|
|
@ -22,10 +23,10 @@ internal class DefaultTokenListComponent @AssistedInject constructor(
|
|||
private val model: TokenListModel = getOrCreateModel(params)
|
||||
|
||||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
override fun Content(contentPadding: PaddingValues, modifier: Modifier) {
|
||||
val state by model.state.collectAsStateWithLifecycle()
|
||||
|
||||
TokenList(state = state, modifier = modifier)
|
||||
TokenList(state = state, contentPadding = contentPadding, modifier = modifier)
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
|
|
|
|||
|
|
@ -1,14 +1,19 @@
|
|||
package com.tangem.feature.wallet.presentation.tokenlist
|
||||
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.tangem.core.decompose.factory.ComponentFactory
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
|
||||
/** Token list component that present list of token for multi-currency wallet */
|
||||
@Stable
|
||||
internal interface TokenListComponent : ComposableContentComponent {
|
||||
internal interface TokenListComponent {
|
||||
|
||||
@Composable
|
||||
fun Content(contentPadding: PaddingValues, modifier: Modifier)
|
||||
|
||||
/** Component factory */
|
||||
interface Factory : ComponentFactory<Params, TokenListComponent>
|
||||
|
|
@ -16,9 +21,9 @@ internal interface TokenListComponent : ComposableContentComponent {
|
|||
/**
|
||||
* Params
|
||||
*
|
||||
* @property hasSearchBar flag that indicates if search bar should be shown
|
||||
* @property userWalletId id of multi-currency wallet
|
||||
* @property onTokenClick callback for token click
|
||||
* @property hasSearchBar flag that indicates if search bar should be shown
|
||||
* @property userWalletId id of multi-currency wallet
|
||||
* @property onTokenClick callback for token click
|
||||
*/
|
||||
data class Params(
|
||||
val hasSearchBar: Boolean,
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
package com.tangem.feature.wallet.presentation.tokenlist.ui
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.runtime.Composable
|
||||
|
|
@ -26,8 +26,8 @@ import com.tangem.feature.wallet.presentation.wallet.ui.components.multicurrency
|
|||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
@Composable
|
||||
internal fun TokenList(state: TokenListUM, modifier: Modifier = Modifier) {
|
||||
LazyColumn(modifier = modifier) {
|
||||
internal fun TokenList(state: TokenListUM, contentPadding: PaddingValues, modifier: Modifier = Modifier) {
|
||||
LazyColumn(modifier = modifier, contentPadding = contentPadding) {
|
||||
itemsIndexed(
|
||||
items = state.items,
|
||||
key = { _, item -> item.id },
|
||||
|
|
@ -42,6 +42,7 @@ internal fun TokenList(state: TokenListUM, modifier: Modifier = Modifier) {
|
|||
currentIndex = index,
|
||||
lastIndex = state.items.lastIndex,
|
||||
addDefaultPadding = false,
|
||||
backgroundColor = TangemTheme.colors.background.primary,
|
||||
),
|
||||
)
|
||||
},
|
||||
|
|
@ -55,10 +56,10 @@ private fun Preview_TokenList(@PreviewParameter(PreviewTokenListUMProvider::clas
|
|||
TangemThemePreview {
|
||||
TokenList(
|
||||
state = state,
|
||||
contentPadding = PaddingValues(all = 16.dp),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(color = TangemTheme.colors.background.secondary)
|
||||
.padding(16.dp),
|
||||
.background(color = TangemTheme.colors.background.secondary),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -23,7 +23,11 @@ internal class SearchTokensManager @Inject constructor() {
|
|||
|
||||
suspend fun update(value: String) {
|
||||
coroutineScope {
|
||||
withDebounce(jobHolder) { _query.value = value }
|
||||
if (value.isEmpty()) {
|
||||
_query.value = value
|
||||
} else {
|
||||
withDebounce(jobHolder) { _query.value = value }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -64,6 +64,7 @@ private fun LazyListScope.contentItems(
|
|||
modifier = modifier.roundedShapeItemDecoration(
|
||||
currentIndex = index,
|
||||
lastIndex = items.lastIndex,
|
||||
backgroundColor = TangemTheme.colors.background.primary,
|
||||
),
|
||||
)
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.ui.components.multicurrency
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
|
|
@ -8,7 +7,6 @@ import androidx.compose.ui.unit.dp
|
|||
import com.tangem.core.ui.components.fields.SearchBar
|
||||
import com.tangem.core.ui.components.token.TokenItem
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.feature.wallet.presentation.common.component.NetworkTitleItem
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletTokensListState.TokensListItemState
|
||||
|
||||
|
|
@ -26,24 +24,19 @@ internal fun MultiCurrencyContentItem(
|
|||
isBalanceHidden: Boolean,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val modifierWithBackground = modifier.background(color = TangemTheme.colors.background.primary)
|
||||
|
||||
when (state) {
|
||||
is TokensListItemState.NetworkGroupTitle -> {
|
||||
NetworkTitleItem(networkName = state.name.resolveReference(), modifier = modifierWithBackground)
|
||||
NetworkTitleItem(networkName = state.name.resolveReference(), modifier = modifier)
|
||||
}
|
||||
is TokensListItemState.Token -> {
|
||||
TokenItem(
|
||||
state = state.state,
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
modifier = modifierWithBackground,
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
is TokensListItemState.SearchBar -> {
|
||||
SearchBar(
|
||||
state = state.searchBarUM,
|
||||
modifier = modifierWithBackground.padding(all = 12.dp),
|
||||
)
|
||||
SearchBar(state = state.searchBarUM, modifier = modifier.padding(all = 12.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue