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 package co.electriccoin.zcash.ui.common.repository
import cash.z.ecc.android.sdk.Synchronizer 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.TransactionId
import cash.z.ecc.android.sdk.model.TransactionOutput import cash.z.ecc.android.sdk.model.TransactionOutput
import cash.z.ecc.android.sdk.model.TransactionOverview 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.TransactionState.Pending
import cash.z.ecc.android.sdk.model.Zatoshi import cash.z.ecc.android.sdk.model.Zatoshi
import co.electriccoin.zcash.ui.common.datasource.AccountDataSource 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 co.electriccoin.zcash.ui.common.provider.SynchronizerProvider
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@ -23,7 +21,6 @@ import kotlinx.coroutines.flow.WhileSubscribed
import kotlinx.coroutines.flow.channelFlow import kotlinx.coroutines.flow.channelFlow
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.distinctUntilChangedBy
import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.firstOrNull import kotlinx.coroutines.flow.firstOrNull
@ -42,8 +39,6 @@ import kotlin.time.Duration
import kotlin.time.Duration.Companion.seconds import kotlin.time.Duration.Companion.seconds
interface TransactionRepository { interface TransactionRepository {
val zashiTransactions: Flow<List<Transaction>?>
val currentTransactions: Flow<List<Transaction>?> val currentTransactions: Flow<List<Transaction>?>
suspend fun getMemos(transaction: Transaction): List<String> suspend fun getMemos(transaction: Transaction): List<String>
@ -58,51 +53,21 @@ interface TransactionRepository {
} }
class TransactionRepositoryImpl( class TransactionRepositoryImpl(
private val accountDataSource: AccountDataSource, accountDataSource: AccountDataSource,
private val synchronizerProvider: SynchronizerProvider, private val synchronizerProvider: SynchronizerProvider,
) : TransactionRepository { ) : TransactionRepository {
private val scope = CoroutineScope(Dispatchers.Default + SupervisorJob()) 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) @OptIn(ExperimentalCoroutinesApi::class)
override val currentTransactions: Flow<List<Transaction>?> = 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( combine(
synchronizerProvider.synchronizer, synchronizerProvider.synchronizer,
accountFlow accountDataSource.selectedAccount.map { it?.sdkAccount }
) { synchronizer, account -> ) { synchronizer, account ->
synchronizer to account synchronizer to account
}.distinctUntilChanged() }.distinctUntilChanged()
.flatMapLatest { (synchronizer, accountUuid) -> .flatMapLatest { (synchronizer, account) ->
if (synchronizer == null || accountUuid == null) { if (synchronizer == null || account == null) {
flowOf(null) flowOf(null)
} else { } else {
channelFlow<List<Transaction>?> { channelFlow<List<Transaction>?> {
@ -110,9 +75,144 @@ class TransactionRepositoryImpl(
launch { launch {
synchronizer synchronizer
.getTransactions(accountUuid) .getTransactions(account.accountUuid)
.mapLatest { transactions -> .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 { }.collect {
send(it) send(it)
} }
@ -123,7 +223,11 @@ class TransactionRepositoryImpl(
} }
} }
} }
} }.stateIn(
scope = scope,
started = SharingStarted.WhileSubscribed(5.seconds, Duration.ZERO),
initialValue = null
)
@Suppress("CyclomaticComplexMethod") @Suppress("CyclomaticComplexMethod")
private suspend fun createTransactions( 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 cash.z.ecc.android.sdk.Synchronizer
import co.electriccoin.zcash.spackle.Twig 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.MessageAvailabilityDataSource
import co.electriccoin.zcash.ui.common.datasource.WalletBackupData import co.electriccoin.zcash.ui.common.datasource.WalletBackupData
import co.electriccoin.zcash.ui.common.datasource.WalletBackupDataSource import co.electriccoin.zcash.ui.common.datasource.WalletBackupDataSource
import co.electriccoin.zcash.ui.common.datasource.WalletSnapshotDataSource import co.electriccoin.zcash.ui.common.datasource.WalletSnapshotDataSource
import co.electriccoin.zcash.ui.common.model.WalletRestoringState import co.electriccoin.zcash.ui.common.model.WalletRestoringState
import co.electriccoin.zcash.ui.common.model.WalletSnapshot 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.CrashReportingStorageProvider
import co.electriccoin.zcash.ui.common.provider.SynchronizerProvider import co.electriccoin.zcash.ui.common.provider.SynchronizerProvider
import co.electriccoin.zcash.ui.common.repository.ExchangeRateRepository import co.electriccoin.zcash.ui.common.repository.ExchangeRateRepository
@ -45,6 +47,7 @@ class GetHomeMessageUseCase(
walletSnapshotDataSource: WalletSnapshotDataSource, walletSnapshotDataSource: WalletSnapshotDataSource,
crashReportingStorageProvider: CrashReportingStorageProvider, crashReportingStorageProvider: CrashReportingStorageProvider,
synchronizerProvider: SynchronizerProvider, synchronizerProvider: SynchronizerProvider,
accountDataSource: AccountDataSource,
private val messageAvailabilityDataSource: MessageAvailabilityDataSource, private val messageAvailabilityDataSource: MessageAvailabilityDataSource,
private val cache: HomeMessageCacheRepository, private val cache: HomeMessageCacheRepository,
) { ) {
@ -52,10 +55,12 @@ class GetHomeMessageUseCase(
private val backupFlow = private val backupFlow =
combine( combine(
transactionRepository.zashiTransactions, accountDataSource.selectedAccount,
transactionRepository.currentTransactions,
walletBackupDataSource.observe() walletBackupDataSource.observe()
) { transactions, backup -> ) { account, transactions, backup ->
if (backup is WalletBackupData.Available && if (backup is WalletBackupData.Available &&
account is ZashiAccount &&
transactions.orEmpty().any { it is ReceiveTransaction } transactions.orEmpty().any { it is ReceiveTransaction }
) { ) {
backup backup
@ -87,7 +92,7 @@ class GetHomeMessageUseCase(
Synchronizer.Status.SYNCING, Synchronizer.Status.SYNCING,
Synchronizer.Status.STOPPED Synchronizer.Status.STOPPED
) )
-> { -> {
val progress = walletSnapshot.progress.decimal * 100f val progress = walletSnapshot.progress.decimal * 100f
if (walletSnapshot.restoringState == WalletRestoringState.RESTORING) { if (walletSnapshot.restoringState == WalletRestoringState.RESTORING) {
HomeMessageData.Restoring( HomeMessageData.Restoring(

View File

@ -11,5 +11,5 @@
<string name="integrations_keystone">Conectar Dispositivo Keystone</string> <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_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_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> </resources>