Backup message shows only with zashi account

This commit is contained in:
Milan Cerovsky 2025-04-25 14:49:43 +02:00
parent 08a7cab446
commit cddacbc0ac
3 changed files with 155 additions and 46 deletions

View File

@ -1,7 +1,6 @@
package co.electriccoin.zcash.ui.common.repository
import cash.z.ecc.android.sdk.Synchronizer
import cash.z.ecc.android.sdk.model.AccountUuid
import cash.z.ecc.android.sdk.model.TransactionId
import cash.z.ecc.android.sdk.model.TransactionOutput
import cash.z.ecc.android.sdk.model.TransactionOverview
@ -10,7 +9,6 @@ import cash.z.ecc.android.sdk.model.TransactionState.Expired
import cash.z.ecc.android.sdk.model.TransactionState.Pending
import cash.z.ecc.android.sdk.model.Zatoshi
import co.electriccoin.zcash.ui.common.datasource.AccountDataSource
import co.electriccoin.zcash.ui.common.model.ZashiAccount
import co.electriccoin.zcash.ui.common.provider.SynchronizerProvider
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@ -23,7 +21,6 @@ import kotlinx.coroutines.flow.WhileSubscribed
import kotlinx.coroutines.flow.channelFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.distinctUntilChangedBy
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.firstOrNull
@ -42,8 +39,6 @@ import kotlin.time.Duration
import kotlin.time.Duration.Companion.seconds
interface TransactionRepository {
val zashiTransactions: Flow<List<Transaction>?>
val currentTransactions: Flow<List<Transaction>?>
suspend fun getMemos(transaction: Transaction): List<String>
@ -58,51 +53,21 @@ interface TransactionRepository {
}
class TransactionRepositoryImpl(
private val accountDataSource: AccountDataSource,
accountDataSource: AccountDataSource,
private val synchronizerProvider: SynchronizerProvider,
) : TransactionRepository {
private val scope = CoroutineScope(Dispatchers.Default + SupervisorJob())
override val zashiTransactions: Flow<List<Transaction>?> =
observeTransactions(
accountFlow = accountDataSource.zashiAccount.map { it?.sdkAccount?.accountUuid }.distinctUntilChanged()
).stateIn(
scope = scope,
started = SharingStarted.WhileSubscribed(5.seconds, Duration.ZERO),
initialValue = null
)
@OptIn(ExperimentalCoroutinesApi::class)
override val currentTransactions: Flow<List<Transaction>?> =
accountDataSource.selectedAccount
.distinctUntilChangedBy { it?.sdkAccount?.accountUuid }
.flatMapLatest { selected ->
if (selected is ZashiAccount) {
zashiTransactions
} else {
observeTransactions(
accountFlow =
accountDataSource.selectedAccount
.map { it?.sdkAccount?.accountUuid }
.distinctUntilChanged()
)
}
}.stateIn(
scope = scope,
started = SharingStarted.WhileSubscribed(5.seconds, Duration.ZERO),
initialValue = null
)
@OptIn(ExperimentalCoroutinesApi::class)
private fun TransactionRepositoryImpl.observeTransactions(accountFlow: Flow<AccountUuid?>) =
combine(
synchronizerProvider.synchronizer,
accountFlow
accountDataSource.selectedAccount.map { it?.sdkAccount }
) { synchronizer, account ->
synchronizer to account
}.distinctUntilChanged()
.flatMapLatest { (synchronizer, accountUuid) ->
if (synchronizer == null || accountUuid == null) {
.flatMapLatest { (synchronizer, account) ->
if (synchronizer == null || account == null) {
flowOf(null)
} else {
channelFlow<List<Transaction>?> {
@ -110,9 +75,144 @@ class TransactionRepositoryImpl(
launch {
synchronizer
.getTransactions(accountUuid)
.getTransactions(account.accountUuid)
.mapLatest { transactions ->
createTransactions(transactions = transactions, synchronizer = synchronizer)
transactions
.map { transaction ->
when (transaction.transactionState) {
Expired ->
when {
transaction.isShielding ->
ShieldTransaction.Failed(
timestamp =
createTimestamp(transaction) ?: Instant.now(),
transactionOutputs =
synchronizer.getTransactionOutputs
(transaction),
amount = transaction.totalSpent,
id = transaction.txId,
memoCount = transaction.memoCount,
fee = transaction.netValue,
overview = transaction
)
transaction.isSentTransaction ->
SendTransaction.Failed(
timestamp =
createTimestamp(transaction) ?: Instant.now(),
transactionOutputs =
synchronizer.getTransactionOutputs
(transaction),
amount = transaction.netValue,
id = transaction.txId,
memoCount = transaction.memoCount,
fee = transaction.feePaid,
overview = transaction
)
else ->
ReceiveTransaction.Failed(
timestamp =
createTimestamp(transaction) ?: Instant.now(),
transactionOutputs =
synchronizer.getTransactionOutputs(transaction),
amount = transaction.netValue,
id = transaction.txId,
memoCount = transaction.memoCount,
overview = transaction
)
}
Confirmed ->
when {
transaction.isShielding ->
ShieldTransaction.Success(
timestamp =
createTimestamp(transaction) ?: Instant.now(),
transactionOutputs =
synchronizer.getTransactionOutputs
(transaction),
amount = transaction.totalSpent,
id = transaction.txId,
memoCount = transaction.memoCount,
fee = transaction.netValue,
overview = transaction
)
transaction.isSentTransaction ->
SendTransaction.Success(
timestamp =
createTimestamp(transaction) ?: Instant.now(),
transactionOutputs =
synchronizer.getTransactionOutputs
(transaction),
amount = transaction.netValue,
id = transaction.txId,
memoCount = transaction.memoCount,
fee = transaction.feePaid,
overview = transaction
)
else ->
ReceiveTransaction.Success(
timestamp =
createTimestamp(transaction) ?: Instant.now(),
transactionOutputs =
synchronizer.getTransactionOutputs
(transaction),
amount = transaction.netValue,
id = transaction.txId,
memoCount = transaction.memoCount,
overview = transaction
)
}
Pending ->
when {
transaction.isShielding ->
ShieldTransaction.Pending(
timestamp = createTimestamp(transaction),
transactionOutputs =
synchronizer.getTransactionOutputs
(transaction),
amount = transaction.totalSpent,
id = transaction.txId,
memoCount = transaction.memoCount,
fee = transaction.netValue,
overview = transaction
)
transaction.isSentTransaction ->
SendTransaction.Pending(
timestamp = createTimestamp(transaction),
transactionOutputs =
synchronizer.getTransactionOutputs
(transaction),
amount = transaction.netValue,
id = transaction.txId,
memoCount = transaction.memoCount,
fee = transaction.feePaid,
overview = transaction
)
else ->
ReceiveTransaction.Pending(
timestamp = createTimestamp(transaction),
transactionOutputs =
synchronizer.getTransactionOutputs
(transaction),
amount = transaction.netValue,
id = transaction.txId,
memoCount = transaction.memoCount,
overview = transaction
)
}
else -> error("Unexpected transaction stat")
}
}.sortedByDescending { transaction ->
transaction.timestamp ?: Instant.now()
}
}.collect {
send(it)
}
@ -123,7 +223,11 @@ class TransactionRepositoryImpl(
}
}
}
}
}.stateIn(
scope = scope,
started = SharingStarted.WhileSubscribed(5.seconds, Duration.ZERO),
initialValue = null
)
@Suppress("CyclomaticComplexMethod")
private suspend fun createTransactions(

View File

@ -2,12 +2,14 @@ package co.electriccoin.zcash.ui.common.usecase
import cash.z.ecc.android.sdk.Synchronizer
import co.electriccoin.zcash.spackle.Twig
import co.electriccoin.zcash.ui.common.datasource.AccountDataSource
import co.electriccoin.zcash.ui.common.datasource.MessageAvailabilityDataSource
import co.electriccoin.zcash.ui.common.datasource.WalletBackupData
import co.electriccoin.zcash.ui.common.datasource.WalletBackupDataSource
import co.electriccoin.zcash.ui.common.datasource.WalletSnapshotDataSource
import co.electriccoin.zcash.ui.common.model.WalletRestoringState
import co.electriccoin.zcash.ui.common.model.WalletSnapshot
import co.electriccoin.zcash.ui.common.model.ZashiAccount
import co.electriccoin.zcash.ui.common.provider.CrashReportingStorageProvider
import co.electriccoin.zcash.ui.common.provider.SynchronizerProvider
import co.electriccoin.zcash.ui.common.repository.ExchangeRateRepository
@ -45,6 +47,7 @@ class GetHomeMessageUseCase(
walletSnapshotDataSource: WalletSnapshotDataSource,
crashReportingStorageProvider: CrashReportingStorageProvider,
synchronizerProvider: SynchronizerProvider,
accountDataSource: AccountDataSource,
private val messageAvailabilityDataSource: MessageAvailabilityDataSource,
private val cache: HomeMessageCacheRepository,
) {
@ -52,10 +55,12 @@ class GetHomeMessageUseCase(
private val backupFlow =
combine(
transactionRepository.zashiTransactions,
accountDataSource.selectedAccount,
transactionRepository.currentTransactions,
walletBackupDataSource.observe()
) { transactions, backup ->
) { account, transactions, backup ->
if (backup is WalletBackupData.Available &&
account is ZashiAccount &&
transactions.orEmpty().any { it is ReceiveTransaction }
) {
backup
@ -87,7 +92,7 @@ class GetHomeMessageUseCase(
Synchronizer.Status.SYNCING,
Synchronizer.Status.STOPPED
)
-> {
-> {
val progress = walletSnapshot.progress.decimal * 100f
if (walletSnapshot.restoringState == WalletRestoringState.RESTORING) {
HomeMessageData.Restoring(

View File

@ -11,5 +11,5 @@
<string name="integrations_keystone">Conectar Dispositivo Keystone</string>
<string name="integrations_keystone_subtitle">Empareja tu billetera de hardware Keystone con Zashi para firmar transacciones.</string>
<string name="integrations_disabled_info_flexa">Switch from Keystone to Zashi to use Flexa.</string>
<string name="integrations_dialog_more_options">More options</string>
<string name="integrations_dialog_more_options">Más Opciones</string>
</resources>