Updated on 2026-08-14

This commit is contained in:
Tangem 2023-10-11 17:29:26 +05:00
parent 7fb168b533
commit 7df5f9edc2
22 changed files with 153 additions and 22 deletions

View file

@ -2,6 +2,7 @@ package com.tangem.tap.di.domain
import com.tangem.domain.tokens.* import com.tangem.domain.tokens.*
import com.tangem.domain.txhistory.repository.TxHistoryRepository import com.tangem.domain.txhistory.repository.TxHistoryRepository
import com.tangem.domain.txhistory.usecase.GetExplorerTransactionUrlUseCase
import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsCountUseCase import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsCountUseCase
import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsUseCase import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsUseCase
import dagger.Module import dagger.Module
@ -25,4 +26,12 @@ internal object TxHistoryDomainModule {
fun provideGetTxHistoryItemsUseCase(txHistoryRepository: TxHistoryRepository): GetTxHistoryItemsUseCase { fun provideGetTxHistoryItemsUseCase(txHistoryRepository: TxHistoryRepository): GetTxHistoryItemsUseCase {
return GetTxHistoryItemsUseCase(repository = txHistoryRepository) return GetTxHistoryItemsUseCase(repository = txHistoryRepository)
} }
@Provides
@ViewModelScoped
fun providesGetExplorerTransactionUrlUseCase(
txHistoryRepository: TxHistoryRepository,
): GetExplorerTransactionUrlUseCase {
return GetExplorerTransactionUrlUseCase(repository = txHistoryRepository)
}
} }

View file

@ -2,6 +2,7 @@ package com.tangem.core.ui.components.transactions
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
@ -24,8 +25,8 @@ import com.tangem.core.ui.R
import com.tangem.core.ui.components.CircleShimmer import com.tangem.core.ui.components.CircleShimmer
import com.tangem.core.ui.components.RectangleShimmer import com.tangem.core.ui.components.RectangleShimmer
import com.tangem.core.ui.components.transactions.state.TransactionState import com.tangem.core.ui.components.transactions.state.TransactionState
import com.tangem.core.ui.components.transactions.state.TransactionState.Content.Status
import com.tangem.core.ui.components.transactions.state.TransactionState.Content.Direction import com.tangem.core.ui.components.transactions.state.TransactionState.Content.Direction
import com.tangem.core.ui.components.transactions.state.TransactionState.Content.Status
import com.tangem.core.ui.extensions.TextReference import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resolveReference import com.tangem.core.ui.extensions.resolveReference
import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.res.TangemTheme
@ -49,10 +50,15 @@ fun Transaction(state: TransactionState, isBalanceHidden: Boolean, modifier: Mod
modifier = modifier modifier = modifier
.background(TangemTheme.colors.background.primary) .background(TangemTheme.colors.background.primary)
.defaultMinSize(minHeight = TangemTheme.dimens.size56) .defaultMinSize(minHeight = TangemTheme.dimens.size56)
.clickable(
enabled = state is TransactionState.Content,
onClick = (state as? TransactionState.Content)?.onClick ?: {},
)
.padding(horizontal = TangemTheme.dimens.spacing12, vertical = TangemTheme.dimens.spacing10), .padding(horizontal = TangemTheme.dimens.spacing12, vertical = TangemTheme.dimens.spacing10),
color = TangemTheme.colors.background.primary, color = TangemTheme.colors.background.primary,
) { ) {
@Suppress("DestructuringDeclarationWithTooManyEntries") @Suppress("DestructuringDeclarationWithTooManyEntries")
// FIXME: split this composable to small composables(loading/content/error) to properly handle onClick
ConstraintLayout(modifier = Modifier.fillMaxWidth()) { ConstraintLayout(modifier = Modifier.fillMaxWidth()) {
val (iconItem, titleItem, subtitleItem, amountItem, timestampItem) = createRefs() val (iconItem, titleItem, subtitleItem, amountItem, timestampItem) = createRefs()
@ -359,6 +365,7 @@ private class TransactionItemStateProvider : CollectionPreviewParameterProvider<
timestamp = "8:41", timestamp = "8:41",
status = Status.Confirmed, status = Status.Confirmed,
direction = Direction.OUTGOING, direction = Direction.OUTGOING,
onClick = {},
), ),
TransactionState.Transfer( TransactionState.Transfer(
txHash = UUID.randomUUID().toString(), txHash = UUID.randomUUID().toString(),
@ -367,6 +374,7 @@ private class TransactionItemStateProvider : CollectionPreviewParameterProvider<
timestamp = "8:41", timestamp = "8:41",
status = Status.Unconfirmed, status = Status.Unconfirmed,
direction = Direction.INCOMING, direction = Direction.INCOMING,
onClick = {},
), ),
TransactionState.Approve( TransactionState.Approve(
txHash = UUID.randomUUID().toString(), txHash = UUID.randomUUID().toString(),
@ -375,6 +383,7 @@ private class TransactionItemStateProvider : CollectionPreviewParameterProvider<
timestamp = "8:41", timestamp = "8:41",
status = Status.Failed, status = Status.Failed,
direction = Direction.OUTGOING, direction = Direction.OUTGOING,
onClick = {},
), ),
TransactionState.Swap( TransactionState.Swap(
txHash = UUID.randomUUID().toString(), txHash = UUID.randomUUID().toString(),
@ -383,6 +392,7 @@ private class TransactionItemStateProvider : CollectionPreviewParameterProvider<
timestamp = "8:41", timestamp = "8:41",
status = Status.Unconfirmed, status = Status.Unconfirmed,
direction = Direction.INCOMING, direction = Direction.INCOMING,
onClick = {},
), ),
TransactionState.Custom( TransactionState.Custom(
txHash = UUID.randomUUID().toString(), txHash = UUID.randomUUID().toString(),
@ -393,6 +403,7 @@ private class TransactionItemStateProvider : CollectionPreviewParameterProvider<
direction = Direction.INCOMING, direction = Direction.INCOMING,
title = TextReference.Str("Submit"), title = TextReference.Str("Submit"),
subtitle = TextReference.Str("33BddS...ga2B"), subtitle = TextReference.Str("33BddS...ga2B"),
onClick = {},
), ),
TransactionState.Custom( TransactionState.Custom(
txHash = UUID.randomUUID().toString(), txHash = UUID.randomUUID().toString(),
@ -403,6 +414,7 @@ private class TransactionItemStateProvider : CollectionPreviewParameterProvider<
direction = Direction.OUTGOING, direction = Direction.OUTGOING,
title = TextReference.Str("Submit"), title = TextReference.Str("Submit"),
subtitle = TextReference.Str("33BddS...ga2B"), subtitle = TextReference.Str("33BddS...ga2B"),
onClick = {},
), ),
TransactionState.Loading(txHash = UUID.randomUUID().toString()), TransactionState.Loading(txHash = UUID.randomUUID().toString()),
), ),

View file

@ -20,6 +20,7 @@ sealed interface TransactionState {
* @property timestamp timestamp * @property timestamp timestamp
* @property status transaction status * @property status transaction status
* @property direction transaction direction * @property direction transaction direction
* @property onClick Lambda be invoked when manage button is clicked
*/ */
sealed class Content : TransactionState { sealed class Content : TransactionState {
@ -28,6 +29,7 @@ sealed interface TransactionState {
abstract val timestamp: String abstract val timestamp: String
abstract val status: Status abstract val status: Status
abstract val direction: Direction abstract val direction: Direction
abstract val onClick: () -> Unit
fun copySealed( fun copySealed(
txHash: String = this.txHash, txHash: String = this.txHash,
@ -73,6 +75,7 @@ sealed interface TransactionState {
override val timestamp: String, override val timestamp: String,
override val status: Status, override val status: Status,
override val direction: Direction, override val direction: Direction,
override val onClick: () -> Unit,
) : Content() ) : Content()
/** /**
@ -91,6 +94,7 @@ sealed interface TransactionState {
override val timestamp: String, override val timestamp: String,
override val status: Status, override val status: Status,
override val direction: Direction, override val direction: Direction,
override val onClick: () -> Unit,
) : Content() ) : Content()
/** /**
@ -109,6 +113,7 @@ sealed interface TransactionState {
override val timestamp: String, override val timestamp: String,
override val status: Status, override val status: Status,
override val direction: Direction, override val direction: Direction,
override val onClick: () -> Unit,
) : Content() ) : Content()
data class Custom( data class Custom(
@ -118,6 +123,7 @@ sealed interface TransactionState {
override val timestamp: String, override val timestamp: String,
override val status: Status, override val status: Status,
override val direction: Direction, override val direction: Direction,
override val onClick: () -> Unit,
val title: TextReference, val title: TextReference,
val subtitle: TextReference, val subtitle: TextReference,
) : Content() ) : Content()

View file

@ -24,6 +24,7 @@ dependencies {
implementation(deps.androidx.paging.runtime) implementation(deps.androidx.paging.runtime)
implementation(deps.timber) implementation(deps.timber)
implementation(deps.jodatime) implementation(deps.jodatime)
implementation(deps.tangem.blockchain)
implementation(deps.hilt.core) implementation(deps.hilt.core)
kapt(deps.hilt.kapt) kapt(deps.hilt.kapt)

View file

@ -3,6 +3,7 @@ package com.tangem.data.txhistory.repository
import androidx.paging.Pager import androidx.paging.Pager
import androidx.paging.PagingConfig import androidx.paging.PagingConfig
import androidx.paging.PagingData import androidx.paging.PagingData
import com.tangem.blockchain.common.Blockchain
import com.tangem.data.common.cache.CacheRegistry import com.tangem.data.common.cache.CacheRegistry
import com.tangem.data.txhistory.repository.paging.TxHistoryPagingSource import com.tangem.data.txhistory.repository.paging.TxHistoryPagingSource
import com.tangem.datasource.local.txhistory.TxHistoryItemsStore import com.tangem.datasource.local.txhistory.TxHistoryItemsStore
@ -63,6 +64,11 @@ class DefaultTxHistoryRepository(
return pager.flow return pager.flow
} }
override fun getTxExploreUrl(txHash: String, networkId: Network.ID): String {
val blockchain = Blockchain.fromId(networkId.value)
return blockchain.getExploreTxUrl(txHash)
}
private suspend fun getUserWallet(userWalletId: UserWalletId): UserWallet { private suspend fun getUserWallet(userWalletId: UserWalletId): UserWallet {
return requireNotNull(userWalletsStore.getSyncOrNull(userWalletId)) { return requireNotNull(userWalletsStore.getSyncOrNull(userWalletId)) {
"Unable to find user wallet with provided ID: $userWalletId" "Unable to find user wallet with provided ID: $userWalletId"

View file

@ -21,4 +21,6 @@ interface TxHistoryRepository {
pageSize: Int, pageSize: Int,
refresh: Boolean, refresh: Boolean,
): Flow<PagingData<TxHistoryItem>> ): Flow<PagingData<TxHistoryItem>>
fun getTxExploreUrl(txHash: String, networkId: Network.ID): String
} }

View file

@ -0,0 +1,12 @@
package com.tangem.domain.txhistory.usecase
import com.tangem.domain.tokens.model.Network
import com.tangem.domain.txhistory.repository.TxHistoryRepository
class GetExplorerTransactionUrlUseCase(
private val repository: TxHistoryRepository,
) {
operator fun invoke(txHash: String, networkId: Network.ID): String {
return repository.getTxExploreUrl(txHash, networkId)
}
}

View file

@ -13,6 +13,7 @@ import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDeta
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState
import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.TokenDetailsNotification import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.TokenDetailsNotification
import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.txhistory.TokenDetailsTxHistoryToTransactionStateConverter import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.txhistory.TokenDetailsTxHistoryToTransactionStateConverter
import com.tangem.feature.tokendetails.presentation.tokendetails.viewmodels.TokenDetailsClickIntents
import com.tangem.utils.converter.Converter import com.tangem.utils.converter.Converter
import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toPersistentList import kotlinx.collections.immutable.toPersistentList
@ -23,10 +24,11 @@ internal class TokenDetailsLoadedBalanceConverter(
private val appCurrencyProvider: Provider<AppCurrency>, private val appCurrencyProvider: Provider<AppCurrency>,
private val symbol: String, private val symbol: String,
private val decimals: Int, private val decimals: Int,
private val clickIntents: TokenDetailsClickIntents,
) : Converter<Either<CurrencyStatusError, CryptoCurrencyStatus>, TokenDetailsState> { ) : Converter<Either<CurrencyStatusError, CryptoCurrencyStatus>, TokenDetailsState> {
private val txHistoryItemConverter by lazy { private val txHistoryItemConverter by lazy {
TokenDetailsTxHistoryToTransactionStateConverter(symbol, decimals) TokenDetailsTxHistoryToTransactionStateConverter(symbol, decimals, clickIntents)
} }
override fun convert(value: Either<CurrencyStatusError, CryptoCurrencyStatus>): TokenDetailsState { override fun convert(value: Either<CurrencyStatusError, CryptoCurrencyStatus>): TokenDetailsState {

View file

@ -48,6 +48,7 @@ internal class TokenDetailsStateFactory(
appCurrencyProvider = appCurrencyProvider, appCurrencyProvider = appCurrencyProvider,
symbol = symbol, symbol = symbol,
decimals = decimals, decimals = decimals,
clickIntents = clickIntents,
) )
} }
@ -181,10 +182,7 @@ internal class TokenDetailsStateFactory(
) )
} }
fun getStateWithChooseAddressBottomSheet( fun getStateWithChooseAddressBottomSheet(addresses: List<Address>): TokenDetailsState {
addresses: List<Address>,
onAddressTypeClick: (AddressModel) -> Unit,
): TokenDetailsState {
return currentStateProvider().copy( return currentStateProvider().copy(
bottomSheetConfig = TangemBottomSheetConfig( bottomSheetConfig = TangemBottomSheetConfig(
isShow = true, isShow = true,
@ -196,7 +194,7 @@ internal class TokenDetailsStateFactory(
type = AddressModel.Type.valueOf(it.type.name), type = AddressModel.Type.valueOf(it.type.name),
) )
}, },
onClick = onAddressTypeClick, onClick = clickIntents::onAddressTypeSelected,
), ),
), ),
) )

View file

@ -30,6 +30,7 @@ internal class TokenDetailsTxHistoryItemFlowConverter(
TokenDetailsTxHistoryTransactionStateConverter( TokenDetailsTxHistoryTransactionStateConverter(
symbol = symbol, symbol = symbol,
decimals = decimals, decimals = decimals,
clickIntents = clickIntents,
) )
} }

View file

@ -4,6 +4,7 @@ import com.tangem.core.ui.components.transactions.state.TransactionState
import com.tangem.core.ui.extensions.TextReference import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.utils.DateTimeFormatters import com.tangem.core.ui.utils.DateTimeFormatters
import com.tangem.domain.txhistory.models.TxHistoryItem import com.tangem.domain.txhistory.models.TxHistoryItem
import com.tangem.feature.tokendetails.presentation.tokendetails.viewmodels.TokenDetailsClickIntents
import com.tangem.features.tokendetails.impl.R import com.tangem.features.tokendetails.impl.R
import com.tangem.utils.converter.Converter import com.tangem.utils.converter.Converter
import com.tangem.utils.toBriefAddressFormat import com.tangem.utils.toBriefAddressFormat
@ -14,6 +15,7 @@ import org.joda.time.DateTimeZone
internal class TokenDetailsTxHistoryToTransactionStateConverter( internal class TokenDetailsTxHistoryToTransactionStateConverter(
private val symbol: String, private val symbol: String,
private val decimals: Int, private val decimals: Int,
private val clickIntents: TokenDetailsClickIntents,
) : Converter<TxHistoryItem, TransactionState> { ) : Converter<TxHistoryItem, TransactionState> {
override fun convert(value: TxHistoryItem): TransactionState { override fun convert(value: TxHistoryItem): TransactionState {
@ -21,6 +23,7 @@ internal class TokenDetailsTxHistoryToTransactionStateConverter(
} }
// TODO: Finalize transaction types [REDACTED_JIRA] // TODO: Finalize transaction types [REDACTED_JIRA]
@Suppress("LongMethod")
private fun createTransactionStateItem(item: TxHistoryItem): TransactionState { private fun createTransactionStateItem(item: TxHistoryItem): TransactionState {
return when (val type = item.type) { return when (val type = item.type) {
TxHistoryItem.TransactionType.Transfer -> mapTransfer(item) TxHistoryItem.TransactionType.Transfer -> mapTransfer(item)
@ -35,6 +38,7 @@ internal class TokenDetailsTxHistoryToTransactionStateConverter(
direction = item.direction.toUiDirection(), direction = item.direction.toUiDirection(),
title = TextReference.Str("Deposit"), title = TextReference.Str("Deposit"),
subtitle = item.direction.extractAddress(), subtitle = item.direction.extractAddress(),
onClick = { clickIntents.onTransactionClick(item.txHash) },
) )
TxHistoryItem.TransactionType.Submit -> TransactionState.Custom( TxHistoryItem.TransactionType.Submit -> TransactionState.Custom(
txHash = item.txHash, txHash = item.txHash,
@ -45,6 +49,7 @@ internal class TokenDetailsTxHistoryToTransactionStateConverter(
direction = item.direction.toUiDirection(), direction = item.direction.toUiDirection(),
title = TextReference.Str("Submit"), title = TextReference.Str("Submit"),
subtitle = item.direction.extractAddress(), subtitle = item.direction.extractAddress(),
onClick = { clickIntents.onTransactionClick(item.txHash) },
) )
TxHistoryItem.TransactionType.Supply -> TransactionState.Custom( TxHistoryItem.TransactionType.Supply -> TransactionState.Custom(
txHash = item.txHash, txHash = item.txHash,
@ -55,6 +60,7 @@ internal class TokenDetailsTxHistoryToTransactionStateConverter(
direction = item.direction.toUiDirection(), direction = item.direction.toUiDirection(),
title = TextReference.Str("Supply"), title = TextReference.Str("Supply"),
subtitle = item.direction.extractAddress(), subtitle = item.direction.extractAddress(),
onClick = { clickIntents.onTransactionClick(item.txHash) },
) )
TxHistoryItem.TransactionType.Unoswap -> TransactionState.Custom( TxHistoryItem.TransactionType.Unoswap -> TransactionState.Custom(
txHash = item.txHash, txHash = item.txHash,
@ -65,6 +71,7 @@ internal class TokenDetailsTxHistoryToTransactionStateConverter(
direction = item.direction.toUiDirection(), direction = item.direction.toUiDirection(),
title = TextReference.Str("Unoswap"), title = TextReference.Str("Unoswap"),
subtitle = item.direction.extractAddress(), subtitle = item.direction.extractAddress(),
onClick = { clickIntents.onTransactionClick(item.txHash) },
) )
TxHistoryItem.TransactionType.Withdraw -> TransactionState.Custom( TxHistoryItem.TransactionType.Withdraw -> TransactionState.Custom(
txHash = item.txHash, txHash = item.txHash,
@ -75,6 +82,7 @@ internal class TokenDetailsTxHistoryToTransactionStateConverter(
direction = item.direction.toUiDirection(), direction = item.direction.toUiDirection(),
title = TextReference.Str("Withdraw"), title = TextReference.Str("Withdraw"),
subtitle = item.direction.extractAddress(), subtitle = item.direction.extractAddress(),
onClick = { clickIntents.onTransactionClick(item.txHash) },
) )
is TxHistoryItem.TransactionType.Custom -> TransactionState.Custom( is TxHistoryItem.TransactionType.Custom -> TransactionState.Custom(
txHash = item.txHash, txHash = item.txHash,
@ -85,6 +93,7 @@ internal class TokenDetailsTxHistoryToTransactionStateConverter(
direction = item.direction.toUiDirection(), direction = item.direction.toUiDirection(),
title = TextReference.Str(type.id), title = TextReference.Str(type.id),
subtitle = item.direction.extractAddress(), subtitle = item.direction.extractAddress(),
onClick = { clickIntents.onTransactionClick(item.txHash) },
) )
} }
} }
@ -97,6 +106,7 @@ internal class TokenDetailsTxHistoryToTransactionStateConverter(
timestamp = item.timestampInMillis.toTimeFormat(), timestamp = item.timestampInMillis.toTimeFormat(),
status = item.status.tiUiStatus(), status = item.status.tiUiStatus(),
direction = item.direction.toUiDirection(), direction = item.direction.toUiDirection(),
onClick = { clickIntents.onTransactionClick(item.txHash) },
) )
} }
@ -108,6 +118,7 @@ internal class TokenDetailsTxHistoryToTransactionStateConverter(
timestamp = item.timestampInMillis.toTimeFormat(), timestamp = item.timestampInMillis.toTimeFormat(),
status = item.status.tiUiStatus(), status = item.status.tiUiStatus(),
direction = item.direction.toUiDirection(), direction = item.direction.toUiDirection(),
onClick = { clickIntents.onTransactionClick(item.txHash) },
) )
} }
private fun mapSwap(item: TxHistoryItem): TransactionState { private fun mapSwap(item: TxHistoryItem): TransactionState {
@ -118,6 +129,7 @@ internal class TokenDetailsTxHistoryToTransactionStateConverter(
timestamp = item.timestampInMillis.toTimeFormat(), timestamp = item.timestampInMillis.toTimeFormat(),
status = item.status.tiUiStatus(), status = item.status.tiUiStatus(),
direction = item.direction.toUiDirection(), direction = item.direction.toUiDirection(),
onClick = { clickIntents.onTransactionClick(item.txHash) },
) )
} }

View file

@ -3,6 +3,7 @@ package com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.
import com.tangem.core.ui.components.transactions.state.TransactionState import com.tangem.core.ui.components.transactions.state.TransactionState
import com.tangem.core.ui.extensions.TextReference import com.tangem.core.ui.extensions.TextReference
import com.tangem.domain.txhistory.models.TxHistoryItem import com.tangem.domain.txhistory.models.TxHistoryItem
import com.tangem.feature.tokendetails.presentation.tokendetails.viewmodels.TokenDetailsClickIntents
import com.tangem.features.tokendetails.impl.R import com.tangem.features.tokendetails.impl.R
import com.tangem.utils.converter.Converter import com.tangem.utils.converter.Converter
import com.tangem.utils.toBriefAddressFormat import com.tangem.utils.toBriefAddressFormat
@ -11,6 +12,7 @@ import com.tangem.utils.toFormattedCurrencyString
internal class TokenDetailsTxHistoryTransactionStateConverter( internal class TokenDetailsTxHistoryTransactionStateConverter(
private val symbol: String, private val symbol: String,
private val decimals: Int, private val decimals: Int,
private val clickIntents: TokenDetailsClickIntents,
) : Converter<TxHistoryItem, TransactionState> { ) : Converter<TxHistoryItem, TransactionState> {
override fun convert(value: TxHistoryItem): TransactionState { override fun convert(value: TxHistoryItem): TransactionState {
@ -18,6 +20,7 @@ internal class TokenDetailsTxHistoryTransactionStateConverter(
} }
// TODO: Finalize transaction types [REDACTED_JIRA] // TODO: Finalize transaction types [REDACTED_JIRA]
@Suppress("LongMethod")
private fun createTransactionStateItem(item: TxHistoryItem): TransactionState { private fun createTransactionStateItem(item: TxHistoryItem): TransactionState {
return when (val type = item.type) { return when (val type = item.type) {
TxHistoryItem.TransactionType.Transfer -> mapTransfer(item) TxHistoryItem.TransactionType.Transfer -> mapTransfer(item)
@ -32,6 +35,7 @@ internal class TokenDetailsTxHistoryTransactionStateConverter(
direction = item.direction.toUiDirection(), direction = item.direction.toUiDirection(),
title = TextReference.Str("Deposit"), title = TextReference.Str("Deposit"),
subtitle = item.direction.extractAddress(), subtitle = item.direction.extractAddress(),
onClick = { clickIntents.onTransactionClick(item.txHash) },
) )
TxHistoryItem.TransactionType.Submit -> TransactionState.Custom( TxHistoryItem.TransactionType.Submit -> TransactionState.Custom(
txHash = item.txHash, txHash = item.txHash,
@ -42,6 +46,7 @@ internal class TokenDetailsTxHistoryTransactionStateConverter(
direction = item.direction.toUiDirection(), direction = item.direction.toUiDirection(),
title = TextReference.Str("Submit"), title = TextReference.Str("Submit"),
subtitle = item.direction.extractAddress(), subtitle = item.direction.extractAddress(),
onClick = { clickIntents.onTransactionClick(item.txHash) },
) )
TxHistoryItem.TransactionType.Supply -> TransactionState.Custom( TxHistoryItem.TransactionType.Supply -> TransactionState.Custom(
txHash = item.txHash, txHash = item.txHash,
@ -52,6 +57,7 @@ internal class TokenDetailsTxHistoryTransactionStateConverter(
direction = item.direction.toUiDirection(), direction = item.direction.toUiDirection(),
title = TextReference.Str("Supply"), title = TextReference.Str("Supply"),
subtitle = item.direction.extractAddress(), subtitle = item.direction.extractAddress(),
onClick = { clickIntents.onTransactionClick(item.txHash) },
) )
TxHistoryItem.TransactionType.Unoswap -> TransactionState.Custom( TxHistoryItem.TransactionType.Unoswap -> TransactionState.Custom(
txHash = item.txHash, txHash = item.txHash,
@ -62,6 +68,7 @@ internal class TokenDetailsTxHistoryTransactionStateConverter(
direction = item.direction.toUiDirection(), direction = item.direction.toUiDirection(),
title = TextReference.Str("Unoswap"), title = TextReference.Str("Unoswap"),
subtitle = item.direction.extractAddress(), subtitle = item.direction.extractAddress(),
onClick = { clickIntents.onTransactionClick(item.txHash) },
) )
TxHistoryItem.TransactionType.Withdraw -> TransactionState.Custom( TxHistoryItem.TransactionType.Withdraw -> TransactionState.Custom(
txHash = item.txHash, txHash = item.txHash,
@ -72,6 +79,7 @@ internal class TokenDetailsTxHistoryTransactionStateConverter(
direction = item.direction.toUiDirection(), direction = item.direction.toUiDirection(),
title = TextReference.Str("Withdraw"), title = TextReference.Str("Withdraw"),
subtitle = item.direction.extractAddress(), subtitle = item.direction.extractAddress(),
onClick = { clickIntents.onTransactionClick(item.txHash) },
) )
is TxHistoryItem.TransactionType.Custom -> TransactionState.Custom( is TxHistoryItem.TransactionType.Custom -> TransactionState.Custom(
txHash = item.txHash, txHash = item.txHash,
@ -82,6 +90,7 @@ internal class TokenDetailsTxHistoryTransactionStateConverter(
direction = item.direction.toUiDirection(), direction = item.direction.toUiDirection(),
title = TextReference.Str(type.id), title = TextReference.Str(type.id),
subtitle = item.direction.extractAddress(), subtitle = item.direction.extractAddress(),
onClick = { clickIntents.onTransactionClick(item.txHash) },
) )
} }
} }
@ -94,6 +103,7 @@ internal class TokenDetailsTxHistoryTransactionStateConverter(
timestamp = item.getRawTimestamp(), timestamp = item.getRawTimestamp(),
status = item.status.tiUiStatus(), status = item.status.tiUiStatus(),
direction = item.direction.toUiDirection(), direction = item.direction.toUiDirection(),
onClick = { clickIntents.onTransactionClick(item.txHash) },
) )
} }
@ -105,6 +115,7 @@ internal class TokenDetailsTxHistoryTransactionStateConverter(
timestamp = item.getRawTimestamp(), timestamp = item.getRawTimestamp(),
status = item.status.tiUiStatus(), status = item.status.tiUiStatus(),
direction = item.direction.toUiDirection(), direction = item.direction.toUiDirection(),
onClick = { clickIntents.onTransactionClick(item.txHash) },
) )
} }
private fun mapSwap(item: TxHistoryItem): TransactionState { private fun mapSwap(item: TxHistoryItem): TransactionState {
@ -115,6 +126,7 @@ internal class TokenDetailsTxHistoryTransactionStateConverter(
timestamp = item.getRawTimestamp(), timestamp = item.getRawTimestamp(),
status = item.status.tiUiStatus(), status = item.status.tiUiStatus(),
direction = item.direction.toUiDirection(), direction = item.direction.toUiDirection(),
onClick = { clickIntents.onTransactionClick(item.txHash) },
) )
} }

View file

@ -1,5 +1,7 @@
package com.tangem.feature.tokendetails.presentation.tokendetails.viewmodels package com.tangem.feature.tokendetails.presentation.tokendetails.viewmodels
import com.tangem.core.ui.components.bottomsheets.tokenreceive.AddressModel
interface TokenDetailsClickIntents { interface TokenDetailsClickIntents {
fun onBackClick() fun onBackClick()
@ -26,6 +28,10 @@ interface TokenDetailsClickIntents {
fun onExploreClick() fun onExploreClick()
fun onTransactionClick(txHash: String)
fun onAddressTypeSelected(addressModel: AddressModel)
fun onDismissBottomSheet() fun onDismissBottomSheet()
fun onCloseRentInfoNotification() fun onCloseRentInfoNotification()

View file

@ -9,6 +9,7 @@ import arrow.core.getOrElse
import com.tangem.blockchain.common.address.AddressType import com.tangem.blockchain.common.address.AddressType
import com.tangem.common.Provider import com.tangem.common.Provider
import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.ui.components.bottomsheets.tokenreceive.AddressModel
import com.tangem.core.ui.components.transactions.state.TxHistoryState import com.tangem.core.ui.components.transactions.state.TxHistoryState
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.appcurrency.model.AppCurrency
@ -25,6 +26,7 @@ import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsUseCase
import com.tangem.domain.walletmanager.WalletManagersFacade import com.tangem.domain.walletmanager.WalletManagersFacade
import com.tangem.domain.wallets.models.UserWalletId import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.domain.wallets.usecase.GetExploreUrlUseCase import com.tangem.domain.wallets.usecase.GetExploreUrlUseCase
import com.tangem.domain.txhistory.usecase.GetExplorerTransactionUrlUseCase
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
import com.tangem.feature.tokendetails.presentation.router.InnerTokenDetailsRouter import com.tangem.feature.tokendetails.presentation.router.InnerTokenDetailsRouter
import com.tangem.feature.tokendetails.presentation.tokendetails.analytics.TokenScreenEvent import com.tangem.feature.tokendetails.presentation.tokendetails.analytics.TokenScreenEvent
@ -60,6 +62,7 @@ internal class TokenDetailsViewModel @Inject constructor(
private val isBalanceHiddenUseCase: IsBalanceHiddenUseCase, private val isBalanceHiddenUseCase: IsBalanceHiddenUseCase,
private val listenToFlipsUseCase: ListenToFlipsUseCase, private val listenToFlipsUseCase: ListenToFlipsUseCase,
private val getCurrencyWarningsUseCase: GetCurrencyWarningsUseCase, private val getCurrencyWarningsUseCase: GetCurrencyWarningsUseCase,
private val getExplorerTransactionUrlUseCase: GetExplorerTransactionUrlUseCase,
private val walletManagersFacade: WalletManagersFacade, private val walletManagersFacade: WalletManagersFacade,
private val reduxStateHolder: ReduxStateHolder, private val reduxStateHolder: ReduxStateHolder,
private val analyticsEventsHandler: AnalyticsEventHandler, private val analyticsEventsHandler: AnalyticsEventHandler,
@ -340,31 +343,41 @@ internal class TokenDetailsViewModel @Inject constructor(
) )
if (addresses.size == 1) { if (addresses.size == 1) {
openUrl(AddressType.Default) router.openUrl(
} else { url = getExploreUrlUseCase(
uiState = stateFactory.getStateWithChooseAddressBottomSheet( userWalletId = userWalletId,
addresses = addresses, network = cryptoCurrency.network,
onAddressTypeClick = { addressType = AddressType.Default,
openUrl(AddressType.valueOf(it.type.name)) ),
uiState = stateFactory.getStateWithClosedBottomSheet()
},
) )
} else {
uiState = stateFactory.getStateWithChooseAddressBottomSheet(addresses = addresses)
} }
} }
} }
private fun openUrl(addressType: AddressType) { override fun onAddressTypeSelected(addressModel: AddressModel) {
viewModelScope.launch { viewModelScope.launch {
router.openUrl( router.openUrl(
url = getExploreUrlUseCase( url = getExploreUrlUseCase(
userWalletId = userWalletId, userWalletId = userWalletId,
network = cryptoCurrency.network, network = cryptoCurrency.network,
addressType = addressType, addressType = AddressType.valueOf(addressModel.type.name),
), ),
) )
uiState = stateFactory.getStateWithClosedBottomSheet()
} }
} }
override fun onTransactionClick(txHash: String) {
router.openUrl(
url = getExplorerTransactionUrlUseCase(
txHash = txHash,
networkId = cryptoCurrency.network.id,
),
)
}
override fun onRefreshSwipe() { override fun onRefreshSwipe() {
analyticsEventsHandler.send(TokenScreenEvent.Refreshed(cryptoCurrency.symbol)) analyticsEventsHandler.send(TokenScreenEvent.Refreshed(cryptoCurrency.symbol))

View file

@ -426,6 +426,7 @@ internal object WalletPreviewData {
timestamp = "8:41", timestamp = "8:41",
status = TransactionState.Content.Status.Unconfirmed, status = TransactionState.Content.Status.Unconfirmed,
direction = TransactionState.Content.Direction.OUTGOING, direction = TransactionState.Content.Direction.OUTGOING,
onClick = {},
), ),
), ),
TxHistoryState.TxHistoryItemState.GroupTitle("Yesterday"), TxHistoryState.TxHistoryItemState.GroupTitle("Yesterday"),
@ -437,6 +438,7 @@ internal object WalletPreviewData {
timestamp = "8:41", timestamp = "8:41",
status = TransactionState.Content.Status.Confirmed, status = TransactionState.Content.Status.Confirmed,
direction = TransactionState.Content.Direction.OUTGOING, direction = TransactionState.Content.Direction.OUTGOING,
onClick = {},
), ),
), ),
), ),

View file

@ -108,7 +108,7 @@ internal class DefaultWalletRouter(private val reduxNavController: ReduxNavContr
) )
} }
override fun openTxHistoryWebsite(url: String) { override fun openUrl(url: String) {
reduxNavController.navigate(action = NavigationAction.OpenUrl(url)) reduxNavController.navigate(action = NavigationAction.OpenUrl(url))
} }

View file

@ -40,7 +40,7 @@ internal interface InnerWalletRouter : WalletRouter {
fun openOnboardingScreen() fun openOnboardingScreen()
/** Open transaction history website by [url] */ /** Open transaction history website by [url] */
fun openTxHistoryWebsite(url: String) fun openUrl(url: String)
/** Open token details screen */ /** Open token details screen */
fun openTokenDetails(userWalletId: UserWalletId, currency: CryptoCurrency) fun openTokenDetails(userWalletId: UserWalletId, currency: CryptoCurrency)

View file

@ -43,6 +43,7 @@ internal class WalletTxHistoryItemFlowConverter(
WalletTxHistoryTransactionStateConverter( WalletTxHistoryTransactionStateConverter(
symbol = blockchain.currency, symbol = blockchain.currency,
decimals = blockchain.decimals(), decimals = blockchain.decimals(),
clickIntents = clickIntents,
) )
} }

View file

@ -4,13 +4,15 @@ import com.tangem.core.ui.components.transactions.state.TransactionState
import com.tangem.core.ui.extensions.TextReference import com.tangem.core.ui.extensions.TextReference
import com.tangem.domain.txhistory.models.TxHistoryItem import com.tangem.domain.txhistory.models.TxHistoryItem
import com.tangem.feature.wallet.impl.R import com.tangem.feature.wallet.impl.R
import com.tangem.feature.wallet.presentation.wallet.viewmodels.WalletClickIntents
import com.tangem.utils.converter.Converter import com.tangem.utils.converter.Converter
import com.tangem.utils.toBriefAddressFormat import com.tangem.utils.toBriefAddressFormat
import com.tangem.utils.toFormattedCurrencyString import com.tangem.utils.toFormattedCurrencyString
class WalletTxHistoryTransactionStateConverter( internal class WalletTxHistoryTransactionStateConverter(
private val symbol: String, private val symbol: String,
private val decimals: Int, private val decimals: Int,
private val clickIntents: WalletClickIntents,
) : Converter<TxHistoryItem, TransactionState> { ) : Converter<TxHistoryItem, TransactionState> {
override fun convert(value: TxHistoryItem): TransactionState { override fun convert(value: TxHistoryItem): TransactionState {
@ -18,6 +20,7 @@ class WalletTxHistoryTransactionStateConverter(
} }
// TODO: Finalize transaction types [REDACTED_JIRA] // TODO: Finalize transaction types [REDACTED_JIRA]
@Suppress("LongMethod")
private fun createTransactionStateItem(item: TxHistoryItem): TransactionState { private fun createTransactionStateItem(item: TxHistoryItem): TransactionState {
return when (val type = item.type) { return when (val type = item.type) {
TxHistoryItem.TransactionType.Transfer -> mapTransfer(item) TxHistoryItem.TransactionType.Transfer -> mapTransfer(item)
@ -32,6 +35,7 @@ class WalletTxHistoryTransactionStateConverter(
direction = item.direction.toUiDirection(), direction = item.direction.toUiDirection(),
title = TextReference.Str("Deposit"), title = TextReference.Str("Deposit"),
subtitle = item.direction.extractAddress(), subtitle = item.direction.extractAddress(),
onClick = { clickIntents.onTransactionClick(item.txHash) },
) )
TxHistoryItem.TransactionType.Submit -> TransactionState.Custom( TxHistoryItem.TransactionType.Submit -> TransactionState.Custom(
txHash = item.txHash, txHash = item.txHash,
@ -42,6 +46,7 @@ class WalletTxHistoryTransactionStateConverter(
direction = item.direction.toUiDirection(), direction = item.direction.toUiDirection(),
title = TextReference.Str("Submit"), title = TextReference.Str("Submit"),
subtitle = item.direction.extractAddress(), subtitle = item.direction.extractAddress(),
onClick = { clickIntents.onTransactionClick(item.txHash) },
) )
TxHistoryItem.TransactionType.Supply -> TransactionState.Custom( TxHistoryItem.TransactionType.Supply -> TransactionState.Custom(
txHash = item.txHash, txHash = item.txHash,
@ -52,6 +57,7 @@ class WalletTxHistoryTransactionStateConverter(
direction = item.direction.toUiDirection(), direction = item.direction.toUiDirection(),
title = TextReference.Str("Supply"), title = TextReference.Str("Supply"),
subtitle = item.direction.extractAddress(), subtitle = item.direction.extractAddress(),
onClick = { clickIntents.onTransactionClick(item.txHash) },
) )
TxHistoryItem.TransactionType.Unoswap -> TransactionState.Custom( TxHistoryItem.TransactionType.Unoswap -> TransactionState.Custom(
txHash = item.txHash, txHash = item.txHash,
@ -62,6 +68,7 @@ class WalletTxHistoryTransactionStateConverter(
direction = item.direction.toUiDirection(), direction = item.direction.toUiDirection(),
title = TextReference.Str("Unoswap"), title = TextReference.Str("Unoswap"),
subtitle = item.direction.extractAddress(), subtitle = item.direction.extractAddress(),
onClick = { clickIntents.onTransactionClick(item.txHash) },
) )
TxHistoryItem.TransactionType.Withdraw -> TransactionState.Custom( TxHistoryItem.TransactionType.Withdraw -> TransactionState.Custom(
txHash = item.txHash, txHash = item.txHash,
@ -72,6 +79,7 @@ class WalletTxHistoryTransactionStateConverter(
direction = item.direction.toUiDirection(), direction = item.direction.toUiDirection(),
title = TextReference.Str("Withdraw"), title = TextReference.Str("Withdraw"),
subtitle = item.direction.extractAddress(), subtitle = item.direction.extractAddress(),
onClick = { clickIntents.onTransactionClick(item.txHash) },
) )
is TxHistoryItem.TransactionType.Custom -> TransactionState.Custom( is TxHistoryItem.TransactionType.Custom -> TransactionState.Custom(
txHash = item.txHash, txHash = item.txHash,
@ -82,6 +90,7 @@ class WalletTxHistoryTransactionStateConverter(
direction = item.direction.toUiDirection(), direction = item.direction.toUiDirection(),
title = TextReference.Str(type.id), title = TextReference.Str(type.id),
subtitle = item.direction.extractAddress(), subtitle = item.direction.extractAddress(),
onClick = { clickIntents.onTransactionClick(item.txHash) },
) )
} }
} }
@ -94,6 +103,7 @@ class WalletTxHistoryTransactionStateConverter(
timestamp = item.getRawTimestamp(), timestamp = item.getRawTimestamp(),
status = item.status.tiUiStatus(), status = item.status.tiUiStatus(),
direction = item.direction.toUiDirection(), direction = item.direction.toUiDirection(),
onClick = { clickIntents.onTransactionClick(item.txHash) },
) )
} }
@ -105,6 +115,7 @@ class WalletTxHistoryTransactionStateConverter(
timestamp = item.getRawTimestamp(), timestamp = item.getRawTimestamp(),
status = item.status.tiUiStatus(), status = item.status.tiUiStatus(),
direction = item.direction.toUiDirection(), direction = item.direction.toUiDirection(),
onClick = { clickIntents.onTransactionClick(item.txHash) },
) )
} }
private fun mapSwap(item: TxHistoryItem): TransactionState { private fun mapSwap(item: TxHistoryItem): TransactionState {
@ -115,6 +126,7 @@ class WalletTxHistoryTransactionStateConverter(
timestamp = item.getRawTimestamp(), timestamp = item.getRawTimestamp(),
status = item.status.tiUiStatus(), status = item.status.tiUiStatus(),
direction = item.direction.toUiDirection(), direction = item.direction.toUiDirection(),
onClick = { clickIntents.onTransactionClick(item.txHash) },
) )
} }

View file

@ -72,4 +72,6 @@ internal interface WalletClickIntents {
fun onReloadClick() fun onReloadClick()
fun onExploreClick() fun onExploreClick()
fun onTransactionClick(txHash: String)
} }

View file

@ -47,6 +47,7 @@ import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.domain.tokens.model.NetworkGroup import com.tangem.domain.tokens.model.NetworkGroup
import com.tangem.domain.tokens.model.TokenList import com.tangem.domain.tokens.model.TokenList
import com.tangem.domain.tokens.models.analytics.TokenReceiveAnalyticsEvent import com.tangem.domain.tokens.models.analytics.TokenReceiveAnalyticsEvent
import com.tangem.domain.txhistory.usecase.GetExplorerTransactionUrlUseCase
import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsCountUseCase import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsCountUseCase
import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsUseCase import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsUseCase
import com.tangem.domain.userwallets.UserWalletBuilder import com.tangem.domain.userwallets.UserWalletBuilder
@ -119,6 +120,7 @@ internal class WalletViewModel @Inject constructor(
private val remindToRateAppLaterUseCase: RemindToRateAppLaterUseCase, private val remindToRateAppLaterUseCase: RemindToRateAppLaterUseCase,
private val neverToSuggestRateAppUseCase: NeverToSuggestRateAppUseCase, private val neverToSuggestRateAppUseCase: NeverToSuggestRateAppUseCase,
private val setWalletWithFundsFoundUseCase: SetWalletWithFundsFoundUseCase, private val setWalletWithFundsFoundUseCase: SetWalletWithFundsFoundUseCase,
private val getExplorerTransactionUrlUseCase: GetExplorerTransactionUrlUseCase,
wasCardScannedUseCase: WasCardScannedUseCase, wasCardScannedUseCase: WasCardScannedUseCase,
isReadyToShowRateAppUseCase: IsReadyToShowRateAppUseCase, isReadyToShowRateAppUseCase: IsReadyToShowRateAppUseCase,
isDemoCardUseCase: IsDemoCardUseCase, isDemoCardUseCase: IsDemoCardUseCase,
@ -702,7 +704,7 @@ internal class WalletViewModel @Inject constructor(
?.getOrNull() ?.getOrNull()
if (currencyStatus != null) { if (currencyStatus != null) {
router.openTxHistoryWebsite( router.openUrl(
url = getExploreUrlUseCase( url = getExploreUrlUseCase(
userWalletId = wallet.walletId, userWalletId = wallet.walletId,
network = currencyStatus.currency.network, network = currencyStatus.currency.network,
@ -829,6 +831,26 @@ internal class WalletViewModel @Inject constructor(
} }
} }
override fun onTransactionClick(txHash: String) {
viewModelScope.launch(dispatchers.io) {
val wallet = getWallet(
index = requireNotNull(uiState as? WalletState.ContentState).walletsListConfig.selectedWalletIndex,
)
val currencyStatus = getPrimaryCurrencyStatusUpdatesUseCase(wallet.walletId)
.firstOrNull()
?.getOrNull()
if (currencyStatus != null) {
router.openUrl(
url = getExplorerTransactionUrlUseCase(
txHash = txHash,
networkId = currencyStatus.currency.network.id,
),
)
}
}
}
private suspend fun getHideTokeAlert( private suspend fun getHideTokeAlert(
userWalletId: UserWalletId, userWalletId: UserWalletId,
cryptoCurrencyStatus: CryptoCurrencyStatus, cryptoCurrencyStatus: CryptoCurrencyStatus,

View file

@ -82,7 +82,7 @@ okHttp-prettyLogging = "3.1.0"
# endregion Other libraries # endregion Other libraries
# region Tangem # region Tangem
tangemBlockchainSdk = "develop-355" tangemBlockchainSdk = "develop-356"
#tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds #tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds
tangemCardSdk = "develop-302" tangemCardSdk = "develop-302"
#tangemCardSdk = "0.0.1" # Keep it! - used for local builds #tangemCardSdk = "0.0.1" # Keep it! - used for local builds