Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import one.mixin.android.ui.home.inscription.InscriptionActivity
import one.mixin.android.vo.Fiats
import one.mixin.android.vo.SnapshotItem
import one.mixin.android.vo.Ticker
import one.mixin.android.vo.safe.RawTransaction
import one.mixin.android.vo.safe.SafeSnapshotType
import one.mixin.android.vo.safe.TokenItem
import one.mixin.android.widget.linktext.RoundBackgroundColorSpan
Expand Down Expand Up @@ -61,7 +62,8 @@ interface TransactionInterface {
contentBinding.avatarVa.setOnClickListener {
clickAvatar(fragment, asset, snapshot.inscriptionHash)
}
updateUI(fragment, contentBinding, asset, snapshot)
val rawTransaction = snapshot.traceId?.let { walletViewModel.findRawTransaction(it) }
updateUI(fragment, contentBinding, asset, snapshot, rawTransaction)
fetchThatTimePrice(
fragment,
lifecycleScope,
Expand All @@ -77,6 +79,7 @@ interface TransactionInterface {
walletViewModel,
snapshot,
asset,
rawTransaction,
)
}
}
Expand All @@ -87,23 +90,27 @@ interface TransactionInterface {
contentBinding.avatarVa.setOnClickListener {
clickAvatar(fragment, tokenItem, snapshotItem.inscriptionHash)
}
updateUI(fragment, contentBinding, tokenItem, snapshotItem)
fetchThatTimePrice(
fragment,
lifecycleScope,
walletViewModel,
contentBinding,
tokenItem.assetId,
snapshotItem,
)
refreshIncompleteSnapshot(
fragment,
contentBinding,
lifecycleScope,
walletViewModel,
snapshotItem,
tokenItem,
)
lifecycleScope.launch {
val rawTransaction = snapshotItem.traceId?.let { walletViewModel.findRawTransaction(it) }
updateUI(fragment, contentBinding, tokenItem, snapshotItem, rawTransaction)
fetchThatTimePrice(
fragment,
lifecycleScope,
walletViewModel,
contentBinding,
tokenItem.assetId,
snapshotItem,
)
refreshIncompleteSnapshot(
fragment,
contentBinding,
lifecycleScope,
walletViewModel,
snapshotItem,
tokenItem,
rawTransaction,
)
}
}
}

Expand Down Expand Up @@ -286,12 +293,14 @@ interface TransactionInterface {
contentBinding: FragmentTransactionBinding,
asset: TokenItem,
snapshot: SnapshotItem,
rawTransaction: RawTransaction? = null,
) {
if (checkDestroyed(fragment)) return

contentBinding.apply {
val amountVal = snapshot.amount.toFloatOrNull()
val isPositive = if (amountVal == null) false else amountVal > 0
val showPendingHash = snapshot.shouldShowPendingHash(rawTransaction)
if (snapshot.inscriptionHash.isNullOrEmpty()) {
avatarVa.displayedChild = 0
contentBinding.avatar.loadToken(asset)
Expand Down Expand Up @@ -326,7 +335,7 @@ interface TransactionInterface {
val amountColor =
fragment.resources.getColor(
when {
snapshot.type == SafeSnapshotType.pending.name -> {
snapshot.type == SafeSnapshotType.pending.name || showPendingHash -> {
R.color.wallet_text_gray
}
isPositive -> {
Expand All @@ -352,6 +361,7 @@ interface TransactionInterface {
transactionIdTv.text = snapshot.snapshotId
transactionHashLayout.isVisible = !snapshot.transactionHash.isNullOrBlank()
transactionHashTv.text = snapshot.transactionHash
hashPendingPb.isVisible = false
dateTv.text = snapshot.createdAt.fullDate()
memoLl.isVisible = snapshot.formatMemo != null
memoTv.text = snapshot.formatMemo?.utf ?: snapshot.formatMemo?.hex
Expand Down Expand Up @@ -425,6 +435,7 @@ interface TransactionInterface {
if (snapshot.withdrawal != null) {
hashLl.isVisible = true
hashTitle.text = fragment.getString(R.string.withdrawal_hash)
hashPendingPb.isVisible = showPendingHash
if (snapshot.withdrawal.withdrawalHash.isBlank()) {
hashTv.text = fragment.getString(R.string.withdrawal_pending)
} else {
Expand Down Expand Up @@ -463,12 +474,13 @@ interface TransactionInterface {
walletViewModel: WalletViewModel,
snapshot: SnapshotItem,
asset: TokenItem,
rawTransaction: RawTransaction? = null,
) {
if (snapshot.isDataIncomplete()) {
lifecycleScope.launch {
walletViewModel.refreshSnapshot(snapshot.snapshotId)?.let {
it.label = snapshot.label // Saving temporary variables
updateUI(fragment, contentBinding, asset, it)
updateUI(fragment, contentBinding, asset, it, rawTransaction)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ import one.mixin.android.vo.UtxoItem
import one.mixin.android.vo.market.Market
import one.mixin.android.vo.market.MarketItem
import one.mixin.android.vo.safe.Output
import one.mixin.android.vo.safe.RawTransaction
import one.mixin.android.vo.safe.SafeSnapshot
import one.mixin.android.vo.safe.TokenItem
import one.mixin.android.vo.sumsub.ProfileResponse
Expand Down Expand Up @@ -319,6 +320,11 @@ internal constructor(
suspend fun findSnapshot(snapshotId: String): SnapshotItem? =
tokenRepository.findSnapshotById(snapshotId)

suspend fun findRawTransaction(traceId: String): RawTransaction? =
withContext(Dispatchers.IO) {
tokenRepository.findRawTransaction(traceId)
}

suspend fun profile(): MixinResponse<ProfileResponse> = tokenRepository.profile()

suspend fun fetchSessionsSuspend(ids: List<String>) = userRepository.fetchSessionsSuspend(ids)
Expand Down
4 changes: 4 additions & 0 deletions app/src/main/java/one/mixin/android/vo/SnapshotItem.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import kotlinx.serialization.SerialName
import one.mixin.android.extension.hexString
import one.mixin.android.extension.isByteArrayValidUtf8
import one.mixin.android.extension.isValidHex
import one.mixin.android.vo.safe.OutputState
import one.mixin.android.vo.safe.RawTransaction
import one.mixin.android.vo.safe.SafeDeposit
import one.mixin.android.vo.safe.SafeSnapshotType
import one.mixin.android.vo.safe.SafeWithdrawal
Expand Down Expand Up @@ -159,6 +161,8 @@ data class SnapshotItem(
}

fun isPendingWithdrawal() = withdrawal != null && withdrawal.withdrawalHash.isNullOrBlank()

fun shouldShowPendingHash(rawTransaction: RawTransaction?) = rawTransaction?.state == OutputState.unspent
}

@Parcelize
Expand Down
36 changes: 31 additions & 5 deletions app/src/main/res/layout/fragment_transaction.xml
Original file line number Diff line number Diff line change
Expand Up @@ -290,12 +290,38 @@
android:layout_height="wrap_content"
android:text="@string/deposit_hash" />

<TextView
android:id="@+id/hash_tv"
style="@style/TransactionDescTextStyle"
<LinearLayout
android:id="@+id/hash_content_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textIsSelectable="true" />
android:gravity="center_vertical"
android:layout_marginStart="20dp"
android:layout_marginEnd="20dp"
android:layout_marginTop="5dp"
android:layout_marginBottom="12dp"
android:orientation="horizontal">

<TextView
android:id="@+id/hash_tv"
style="@style/TransactionDescTextStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="0dp"
android:layout_marginTop="0dp"
android:layout_marginEnd="0dp"
android:layout_marginBottom="0dp"
android:textIsSelectable="true" />

<ProgressBar
android:id="@+id/hash_pending_pb"
style="?android:attr/progressBarStyleSmall"
android:layout_width="12dp"
android:layout_height="12dp"
android:layout_gravity="center_vertical"
android:layout_marginStart="3dp"
android:theme="@style/AppTheme.BlueAccent"
android:visibility="gone" />
</LinearLayout>
</LinearLayout>

<LinearLayout
Expand Down Expand Up @@ -353,4 +379,4 @@
</LinearLayout>
</LinearLayout>
</ScrollView>
</RelativeLayout>
</RelativeLayout>
78 changes: 78 additions & 0 deletions app/src/test/java/one/mixin/android/vo/SnapshotItemTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package one.mixin.android.vo

import kotlin.test.Test
import kotlin.test.assertEquals
import one.mixin.android.vo.safe.OutputState
import one.mixin.android.vo.safe.RawTransaction
import one.mixin.android.vo.safe.RawTransactionType
import one.mixin.android.vo.safe.SafeSnapshotType

class SnapshotItemTest {
@Test
fun `pending hash is shown when raw transaction is unspent`() {
val snapshot = snapshotItem(type = SafeSnapshotType.snapshot.name, traceId = "trace-id")
val rawTransaction = rawTransaction("trace-id", OutputState.unspent)

assertEquals(true, snapshot.shouldShowPendingHash(rawTransaction))
}

@Test
fun `pending hash is hidden when raw transaction was sent`() {
val snapshot = snapshotItem(type = SafeSnapshotType.snapshot.name, traceId = "trace-id")
val rawTransaction = rawTransaction("trace-id", OutputState.signed)

assertEquals(false, snapshot.shouldShowPendingHash(rawTransaction))
}

@Test
fun `pending hash is hidden when raw transaction is missing`() {
val snapshot = snapshotItem(type = SafeSnapshotType.withdrawal.name, traceId = "trace-id")

assertEquals(false, snapshot.shouldShowPendingHash(null))
}

private fun rawTransaction(
requestId: String,
state: OutputState,
) = RawTransaction(
requestId = requestId,
rawTransaction = "raw",
receiverId = "",
type = RawTransactionType.TRANSFER,
state = state,
createdAt = "2026-06-03T00:00:00Z",
inscriptionHash = null,
)

private fun snapshotItem(
type: String,
traceId: String?,
) = SnapshotItem(
snapshotId = "snapshot-id",
type = type,
assetId = "asset-id",
amount = "-1",
createdAt = "2026-06-03T00:00:00Z",
opponentId = "opponent-id",
opponentFullName = null,
transactionHash = "hash",
memo = null,
assetSymbol = "XIN",
confirmations = null,
avatarUrl = null,
assetConfirmations = 0,
traceId = traceId,
openingBalance = null,
closingBalance = null,
deposit = null,
withdrawal = null,
label = null,
inscriptionHash = null,
collectionHash = null,
name = null,
sequence = null,
contentType = null,
contentUrl = null,
iconUrl = null,
)
}