From a3bee722b7135f2ff9228ccf8de5af1d8b93d89d Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 2 Oct 2024 14:34:29 +0400 Subject: [PATCH] Updated on 2026-08-14 --- core/res/src/main/res/values-ja/strings.xml | 3 +- core/res/src/main/res/values-ru/strings.xml | 11 +- core/res/src/main/res/values/strings.xml | 10 +- .../components/token/state/TokenItemState.kt | 4 +- .../ui/components/ExchangesBottomSheet.kt | 206 ++++++++++++++++++ .../ui/state/ExchangesBottomSheetContent.kt | 73 +++++++ 6 files changed, 298 insertions(+), 9 deletions(-) create mode 100644 features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/ui/components/ExchangesBottomSheet.kt create mode 100644 features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/ui/state/ExchangesBottomSheetContent.kt diff --git a/core/res/src/main/res/values-ja/strings.xml b/core/res/src/main/res/values-ja/strings.xml index 15e20368f1..3f051e2972 100644 --- a/core/res/src/main/res/values-ja/strings.xml +++ b/core/res/src/main/res/values-ja/strings.xml @@ -375,7 +375,7 @@ トレンド %sについて - %1$s取引所 + %d取引所 %d のレーティングに基づいて @@ -405,6 +405,7 @@ 指定された期間中のトークンに利用可能な流動性の変化 流動性 流動性指数 + 上場先 低い 時価総額 暗号資産の市場価値の合計。コインの現在の価格と、流通しているコインの総数を掛けて計算されます。 diff --git a/core/res/src/main/res/values-ru/strings.xml b/core/res/src/main/res/values-ru/strings.xml index 040fca1460..00cebaa9f8 100644 --- a/core/res/src/main/res/values-ru/strings.xml +++ b/core/res/src/main/res/values-ru/strings.xml @@ -383,10 +383,10 @@ В тренде О %s - %1$s биржа - %1$s биржи - %1$s бирж - %1$s бирж + %d биржа + %d биржи + %d бирж + %d бирж На основе %d оценки @@ -402,6 +402,8 @@ Общее количество монет, доступных для торговли и находящихся в обращении на рынке Циркулирующее предложение Биржи не найдены + Биржа + Биржи Опытные трейдеры Покупатели, у которых было как минимум 100 исходящих транзакций. Опытные трейдеры @@ -442,6 +444,7 @@ Объем торгов (24ч) Общая сумма криптовалюты, которая была продана за последние 24 часа, показывающая уровень активности и ликвидности на рынке. Объем торгов (24ч) + Объем Потяните вверх или коснитесь поисковой строки, чтобы добавить токены напрямую из маркета Добавить токены Функция NFC недоступна на вашем устройстве diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml index 7e90b04d5e..da6e4bbab5 100644 --- a/core/res/src/main/res/values/strings.xml +++ b/core/res/src/main/res/values/strings.xml @@ -379,8 +379,8 @@ Trending About %s - %1$s exchange - %1$s exchanges + %d exchange + %d exchanges Based on %d rating @@ -394,6 +394,11 @@ The total number of coins that are available for trading and are circulating in the market Circulating supply No exchanges found + Exchange + Caution + Risky + Trusted + Exchanges Experienced buyers Net buyers with the additional requirement of having at least 100 outgoing transactions Experienced buyers @@ -434,6 +439,7 @@ Trading volume (24h) The total amount of a cryptocurrency that has been traded within the last 24 hours, indicating the level of activity and liquidity in the market Trading volume (24h) + Volume Pull this up or tap the search bar to add tokens directly from the market Add tokens NFC is not available on your device diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/token/state/TokenItemState.kt b/core/ui/src/main/java/com/tangem/core/ui/components/token/state/TokenItemState.kt index fbed4994dd..528978ea61 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/token/state/TokenItemState.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/token/state/TokenItemState.kt @@ -46,8 +46,8 @@ sealed class TokenItemState { */ data class Loading( override val id: String, - override val iconState: CurrencyIconState, - override val titleState: TitleState.Content, + override val iconState: CurrencyIconState = CurrencyIconState.Loading, + override val titleState: TitleState = TitleState.Loading, override val subtitleState: SubtitleState = SubtitleState.Loading, ) : TokenItemState() { override val fiatAmountState: FiatAmountState = FiatAmountState.Loading diff --git a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/ui/components/ExchangesBottomSheet.kt b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/ui/components/ExchangesBottomSheet.kt new file mode 100644 index 0000000000..e791211b63 --- /dev/null +++ b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/ui/components/ExchangesBottomSheet.kt @@ -0,0 +1,206 @@ +package com.tangem.features.markets.details.impl.ui.components + +import android.content.res.Configuration +import androidx.annotation.StringRes +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.key +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.tooling.preview.PreviewParameter +import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider +import androidx.compose.ui.unit.dp +import androidx.compose.ui.util.fastForEach +import com.tangem.core.ui.components.SpacerH +import com.tangem.core.ui.components.SpacerH12 +import com.tangem.core.ui.components.appbar.TangemTopAppBar +import com.tangem.core.ui.components.appbar.models.TopAppBarButtonUM +import com.tangem.core.ui.components.audits.AuditLabelUM +import com.tangem.core.ui.components.bottomsheets.TangemBottomSheet +import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig +import com.tangem.core.ui.components.buttons.SecondarySmallButton +import com.tangem.core.ui.components.buttons.SmallButtonConfig +import com.tangem.core.ui.components.currency.icon.CurrencyIconState +import com.tangem.core.ui.components.token.TokenItem +import com.tangem.core.ui.components.token.state.TokenItemState +import com.tangem.core.ui.extensions.TextReference +import com.tangem.core.ui.extensions.resolveReference +import com.tangem.core.ui.extensions.resourceReference +import com.tangem.core.ui.extensions.stringReference +import com.tangem.core.ui.res.TangemTheme +import com.tangem.core.ui.res.TangemThemePreview +import com.tangem.features.markets.details.impl.ui.state.ExchangesBottomSheetContent +import com.tangem.features.markets.impl.R +import kotlinx.collections.immutable.toImmutableList + +/** + * Exchanges bottom sheet + * + * @param config bottom sheet config + * +[REDACTED_AUTHOR] + */ +@Composable +internal fun ExchangesBottomSheet(config: TangemBottomSheetConfig) { + val bottomBarHeight = with(LocalDensity.current) { WindowInsets.systemBars.getBottom(this).toDp() } + + TangemBottomSheet( + config = config, + addBottomInsets = false, + title = { Title(textResId = it.titleResId, onBackClick = config.onDismissRequest) }, + content = { content -> + Column( + modifier = Modifier + .fillMaxSize() + .verticalScroll(state = rememberScrollState()), + ) { + Subtitle( + subtitleRes = content.subtitleResId, + volumeReference = content.volumeReference, + modifier = Modifier.padding( + start = TangemTheme.dimens.spacing16, + top = TangemTheme.dimens.spacing12, + end = TangemTheme.dimens.spacing16, + bottom = TangemTheme.dimens.spacing8, + ), + ) + + when (content) { + is ExchangesBottomSheetContent.Content, + is ExchangesBottomSheetContent.Loading, + -> { + content.exchangeItems.fastForEach { item -> + key(item.id) { + TokenItem(state = item, isBalanceHidden = false) + } + } + } + is ExchangesBottomSheetContent.Error -> { + Error( + content = content, + modifier = Modifier + .align(alignment = Alignment.CenterHorizontally) + .padding(horizontal = 16.dp) + .weight(1f), + ) + } + } + + SpacerH(bottomBarHeight) + } + }, + ) +} + +@Composable +private fun Title(@StringRes textResId: Int, onBackClick: () -> Unit) { + TangemTopAppBar( + title = stringResource(id = textResId), + startButton = TopAppBarButtonUM.Back(onBackClicked = onBackClick), + ) +} + +@Composable +private fun Subtitle(@StringRes subtitleRes: Int, volumeReference: TextReference, modifier: Modifier = Modifier) { + Row( + modifier = modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + ) { + SubtitleText(textReference = resourceReference(id = subtitleRes)) + + SubtitleText(textReference = volumeReference) + } +} + +@Composable +private fun SubtitleText(textReference: TextReference) { + Text( + text = textReference.resolveReference(), + color = TangemTheme.colors.text.tertiary, + overflow = TextOverflow.Ellipsis, + maxLines = 1, + style = TangemTheme.typography.body2, + ) +} + +@Composable +private fun Error(content: ExchangesBottomSheetContent.Error, modifier: Modifier = Modifier) { + Column( + modifier = modifier, + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally, + ) { + Text( + text = stringResource(id = content.message), + color = TangemTheme.colors.text.tertiary, + textAlign = TextAlign.Center, + style = TangemTheme.typography.caption1, + ) + + SpacerH12() + + SecondarySmallButton( + config = SmallButtonConfig( + text = resourceReference(id = R.string.alert_button_try_again), + onClick = content.onRetryClick, + ), + ) + } +} + +@Preview +@Preview(name = "Dark Theme", uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +private fun Preview_ExchangesBottomSheet( + @PreviewParameter(ExchangesBottomSheetContentProvider::class) content: ExchangesBottomSheetContent, +) { + TangemThemePreview { + ExchangesBottomSheet( + config = TangemBottomSheetConfig( + onDismissRequest = {}, + content = content, + isShow = true, + ), + ) + } +} + +private class ExchangesBottomSheetContentProvider : CollectionPreviewParameterProvider( + listOf( + ExchangesBottomSheetContent.Loading(exchangesCount = 13), + ExchangesBottomSheetContent.Error(onRetryClick = {}), + ExchangesBottomSheetContent.Content( + exchangeItems = List(size = 13) { index -> + TokenItemState.Content( + id = index.toString(), + iconState = CurrencyIconState.CoinIcon( + url = null, + fallbackResId = R.drawable.ic_facebook_24, + isGrayscale = false, + showCustomBadge = false, + ), + titleState = TokenItemState.TitleState.Content(text = "OKX"), + fiatAmountState = TokenItemState.FiatAmountState.Content(text = "$67.52M"), + subtitleState = TokenItemState.SubtitleState.TextContent(value = "CEX"), + subtitle2State = TokenItemState.Subtitle2State.LabelContent( + auditLabelUM = AuditLabelUM( + text = stringReference("Caution"), + type = AuditLabelUM.Type.Warning, + ), + ), + onItemClick = {}, + onItemLongClick = {}, + ) + } + .toImmutableList(), + ), + ), +) \ No newline at end of file diff --git a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/ui/state/ExchangesBottomSheetContent.kt b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/ui/state/ExchangesBottomSheetContent.kt new file mode 100644 index 0000000000..cccbf85d31 --- /dev/null +++ b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/ui/state/ExchangesBottomSheetContent.kt @@ -0,0 +1,73 @@ +package com.tangem.features.markets.details.impl.ui.state + +import androidx.annotation.StringRes +import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent +import com.tangem.core.ui.components.token.state.TokenItemState +import com.tangem.core.ui.extensions.TextReference +import com.tangem.core.ui.extensions.plus +import com.tangem.core.ui.extensions.resourceReference +import com.tangem.core.ui.extensions.stringReference +import com.tangem.features.markets.impl.R +import com.tangem.utils.StringsSigns.DOT +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf +import kotlinx.collections.immutable.toImmutableList + +/** + * Exchanges bottom sheet content + * +[REDACTED_AUTHOR] + */ +internal sealed interface ExchangesBottomSheetContent : TangemBottomSheetConfigContent { + + /** Title of bottom sheet. Like, app bar. */ + @get:StringRes + val titleResId: Int + get() = R.string.markets_token_details_exchanges_title + + /** Subtitle */ + @get:StringRes + val subtitleResId: Int + get() = R.string.markets_token_details_exchange + + /** Volume info */ + @get:StringRes + val volumeReference: TextReference + get() = resourceReference(id = R.string.markets_token_details_volume) + + stringReference(value = " $DOT ") + + resourceReference(id = R.string.markets_selector_interval_24h_title) + + /** Exchange items */ + val exchangeItems: ImmutableList + + /** + * Loading state + * + * @property exchangesCount count of exchanges + */ + data class Loading(val exchangesCount: Int) : ExchangesBottomSheetContent { + + override val exchangeItems: ImmutableList + get() = List(size = exchangesCount) { index -> TokenItemState.Loading(id = "loading#$index") } + .toImmutableList() + } + + /** + * Content state + * + * @property exchangeItems exchanges + */ + data class Content( + override val exchangeItems: ImmutableList, + ) : ExchangesBottomSheetContent + + /** Error state */ + data class Error( + val onRetryClick: () -> Unit, + ) : ExchangesBottomSheetContent { + override val exchangeItems: ImmutableList = persistentListOf() + + @StringRes + val message: Int = R.string.markets_loading_error_title + } +} \ No newline at end of file