Updated on 2026-08-14
This commit is contained in:
commit
f2e19e40be
35 changed files with 1034 additions and 370 deletions
|
|
@ -37,5 +37,8 @@ fun createNetworkLoggingInterceptor(): Interceptor {
|
|||
return LoggingInterceptor.Builder()
|
||||
.setLevel(Level.BODY)
|
||||
.log(Log.VERBOSE)
|
||||
.tag(NETWORK_LOGS_TAG)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
|
||||
private const val NETWORK_LOGS_TAG = "NetworkLogs"
|
||||
|
|
@ -1,76 +1,67 @@
|
|||
package com.tangem.core.ui.components.transactions.state
|
||||
|
||||
import androidx.paging.PagingData
|
||||
import androidx.paging.TerminalSeparatorType
|
||||
import androidx.paging.insertHeaderItem
|
||||
import com.tangem.core.ui.components.wallet.WalletLockedContentState
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.flow.map
|
||||
|
||||
/**
|
||||
* Wallet transaction history state
|
||||
*/
|
||||
/** Wallet transaction history state */
|
||||
sealed interface TxHistoryState {
|
||||
|
||||
/**
|
||||
* Wallet transaction history state with content
|
||||
* Wallet transaction history state with content. Items contains a required [TxHistoryItemState.Title].
|
||||
*
|
||||
* @property items content items
|
||||
* @property contentItems content items
|
||||
*/
|
||||
sealed class ContentState(open val items: Flow<PagingData<TxHistoryItemState>>) : TxHistoryState
|
||||
sealed class ContentState(private val contentItems: Flow<PagingData<TxHistoryItemState>>) : TxHistoryState {
|
||||
|
||||
/** Lambda be invoke when explore button was clicked */
|
||||
abstract val onExploreClick: () -> Unit
|
||||
|
||||
/** Content items with [TxHistoryItemState.Title] */
|
||||
val items: Flow<PagingData<TxHistoryItemState>>
|
||||
get() {
|
||||
return contentItems.map {
|
||||
it.insertHeaderItem(
|
||||
terminalSeparatorType = TerminalSeparatorType.SOURCE_COMPLETE,
|
||||
item = TxHistoryItemState.Title(onExploreClick = onExploreClick),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loading state
|
||||
*
|
||||
* @property onExploreClick lambda be invoke when explore button was clicked
|
||||
* @property transactions loading transactions
|
||||
*/
|
||||
data class Loading(val onExploreClick: () -> Unit) : ContentState(
|
||||
items = flowOf(
|
||||
PagingData.from(
|
||||
listOf(
|
||||
TxHistoryItemState.Title(onExploreClick = onExploreClick),
|
||||
TxHistoryItemState.Transaction(state = TransactionState.Loading(txHash = LOADING_TX_HASH)),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
/**
|
||||
* Wallet transaction history state with loading transactions
|
||||
*
|
||||
* @property itemsCount count of loading transactions
|
||||
*/
|
||||
data class ContentWithLoadingItems(val itemsCount: Int) : ContentState(
|
||||
items = flowOf(
|
||||
value = PagingData.from(
|
||||
data = buildList(capacity = itemsCount) {
|
||||
add(TxHistoryItemState.Transaction(state = TransactionState.Loading(txHash = LOADING_TX_HASH)))
|
||||
},
|
||||
),
|
||||
),
|
||||
)
|
||||
data class Loading(
|
||||
override val onExploreClick: () -> Unit,
|
||||
val transactions: Flow<PagingData<TxHistoryItemState>> = getDefaultLoadingTransactions(),
|
||||
) : ContentState(transactions)
|
||||
|
||||
/**
|
||||
* Wallet transaction history state with content
|
||||
*
|
||||
* @property items content items
|
||||
* @property onExploreClick lambda be invoke when explore button was clicked
|
||||
* @property contentItems content items
|
||||
*/
|
||||
data class Content(override val items: Flow<PagingData<TxHistoryItemState>>) : ContentState(items)
|
||||
data class Content(
|
||||
override val onExploreClick: () -> Unit,
|
||||
val contentItems: Flow<PagingData<TxHistoryItemState>>,
|
||||
) : ContentState(contentItems)
|
||||
|
||||
/**
|
||||
* Locked state
|
||||
*
|
||||
* @property onExploreClick lambda be invoke when explore button was clicked
|
||||
*/
|
||||
data class Locked(val onExploreClick: () -> Unit) :
|
||||
ContentState(
|
||||
items = flowOf(
|
||||
PagingData.from(
|
||||
listOf(
|
||||
TxHistoryItemState.Title(onExploreClick = onExploreClick),
|
||||
TxHistoryItemState.Transaction(state = TransactionState.Loading(txHash = LOADING_TX_HASH)),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
data class Locked(override val onExploreClick: () -> Unit) :
|
||||
ContentState(contentItems = getDefaultLoadingTransactions()),
|
||||
WalletLockedContentState
|
||||
|
||||
/**
|
||||
|
|
@ -121,5 +112,17 @@ sealed interface TxHistoryState {
|
|||
|
||||
private companion object {
|
||||
const val LOADING_TX_HASH = "LOADING_TX_HASH"
|
||||
|
||||
private fun getDefaultLoadingTransactions(): Flow<PagingData<TxHistoryItemState>> {
|
||||
return flowOf(
|
||||
value = PagingData.from(
|
||||
data = listOf(
|
||||
element = TxHistoryItemState.Transaction(
|
||||
state = TransactionState.Loading(txHash = LOADING_TX_HASH),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -20,12 +20,19 @@ sealed interface TextReference {
|
|||
* Text resource id
|
||||
*
|
||||
* @property id resource id
|
||||
* @property formatArgs arguments
|
||||
*
|
||||
* Impossible to use [kotlinx.collections.immutable.ImmutableList] because [Any] is unstable.
|
||||
* @property formatArgs arguments. Impossible to use [kotlinx.collections.immutable.ImmutableList] because [Any] is
|
||||
* unstable.
|
||||
*/
|
||||
data class Res(@StringRes val id: Int, val formatArgs: WrappedList<Any> = WrappedList(emptyList())) : TextReference
|
||||
|
||||
/**
|
||||
* Plural resource id
|
||||
*
|
||||
* @property id resource id
|
||||
* @property count count
|
||||
* @property formatArgs arguments. Impossible to use [kotlinx.collections.immutable.ImmutableList] because [Any] is
|
||||
* unstable.
|
||||
*/
|
||||
data class PluralRes(@PluralsRes val id: Int, val count: Int, val formatArgs: WrappedList<Any>) : TextReference
|
||||
|
||||
/**
|
||||
|
|
@ -34,9 +41,16 @@ sealed interface TextReference {
|
|||
* @property value value
|
||||
*/
|
||||
data class Str(val value: String) : TextReference
|
||||
|
||||
/**
|
||||
* Combined reference. It concatenates all [refs].
|
||||
*
|
||||
* @see [TextReference.plus] method
|
||||
*/
|
||||
data class Combined(val refs: WrappedList<TextReference>) : TextReference
|
||||
}
|
||||
|
||||
/** Get text */
|
||||
/** Resolve [TextReference] as [String] */
|
||||
@Composable
|
||||
@ReadOnlyComposable
|
||||
fun TextReference.resolveReference(): String {
|
||||
|
|
@ -44,5 +58,23 @@ fun TextReference.resolveReference(): String {
|
|||
is TextReference.Res -> stringResource(id, *formatArgs.toTypedArray())
|
||||
is TextReference.PluralRes -> pluralStringResource(id, count, *formatArgs.toTypedArray())
|
||||
is TextReference.Str -> value
|
||||
is TextReference.Combined -> {
|
||||
buildString {
|
||||
refs.forEach {
|
||||
append(it.resolveReference())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Concatenate [this] reference with [ref] */
|
||||
operator fun TextReference.plus(ref: TextReference): TextReference {
|
||||
return when (this) {
|
||||
is TextReference.Combined -> copy(refs = (refs.data + ref).toWrappedList())
|
||||
is TextReference.PluralRes,
|
||||
is TextReference.Res,
|
||||
is TextReference.Str,
|
||||
-> TextReference.Combined(refs = wrappedList(this, ref))
|
||||
}
|
||||
}
|
||||
|
|
@ -7,4 +7,8 @@ import androidx.compose.runtime.Immutable
|
|||
*/
|
||||
@JvmInline
|
||||
@Immutable
|
||||
value class WrappedList<T>(val data: List<T>) : List<T> by data
|
||||
value class WrappedList<T>(val data: List<T>) : List<T> by data
|
||||
|
||||
fun <T> List<T>.toWrappedList(): WrappedList<T> = WrappedList(data = this)
|
||||
|
||||
fun <T> wrappedList(vararg elements: T): WrappedList<T> = WrappedList(data = listOf(*elements))
|
||||
|
|
@ -12,22 +12,14 @@ object BigDecimalFormatter {
|
|||
|
||||
private const val TEMP_CURRENCY_CODE = "USD"
|
||||
|
||||
fun formatCryptoAmount(
|
||||
cryptoAmount: BigDecimal,
|
||||
cryptoCurrency: String,
|
||||
decimals: Int,
|
||||
locale: Locale = Locale.getDefault(),
|
||||
): String {
|
||||
val formatterCurrency = getCurrency(cryptoCurrency)
|
||||
val formatter = NumberFormat.getCurrencyInstance(locale).apply {
|
||||
currency = formatterCurrency
|
||||
fun formatCryptoAmount(cryptoAmount: BigDecimal, cryptoCurrency: String, decimals: Int): String {
|
||||
val formatter = NumberFormat.getNumberInstance().apply {
|
||||
maximumFractionDigits = decimals.coerceAtMost(maximumValue = 8)
|
||||
minimumFractionDigits = 2
|
||||
roundingMode = RoundingMode.DOWN
|
||||
}
|
||||
|
||||
return formatter.format(cryptoAmount)
|
||||
.replace(formatterCurrency.getSymbol(locale), cryptoCurrency)
|
||||
return formatter.format(cryptoAmount) + "\u2009$cryptoCurrency"
|
||||
}
|
||||
|
||||
fun formatFiatAmount(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue