diff --git a/gradle.properties b/gradle.properties index 9b5eb88d..698bdf5e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -153,7 +153,7 @@ ZCASH_ANDROID_WALLET_PLUGINS_VERSION=1.0.0 ZCASH_BIP39_VERSION=1.0.4 # TODO [#279]: Revert to stable SDK before app release # TODO [#279]: https://github.com/zcash/secant-android-wallet/issues/279 -ZCASH_SDK_VERSION=1.14.0-beta01-SNAPSHOT +ZCASH_SDK_VERSION=1.17.0-beta01-SNAPSHOT ZXING_VERSION=3.5.1 diff --git a/sdk-ext-lib/src/main/java/cash/z/ecc/sdk/model/CompactBlockProcessorExt.kt b/sdk-ext-lib/src/main/java/cash/z/ecc/sdk/model/CompactBlockProcessorExt.kt deleted file mode 100644 index d88c5d58..00000000 --- a/sdk-ext-lib/src/main/java/cash/z/ecc/sdk/model/CompactBlockProcessorExt.kt +++ /dev/null @@ -1,57 +0,0 @@ -package cash.z.ecc.sdk.model - -import cash.z.ecc.android.sdk.block.CompactBlockProcessor -import cash.z.ecc.android.sdk.model.PercentDecimal - -fun CompactBlockProcessor.ProcessorInfo.downloadProgress(): PercentDecimal { - val lastDownloadRangeSnapshot = lastDownloadRange - val lastDownloadedHeightSnapshot = lastDownloadedHeight - - return if (lastDownloadRangeSnapshot?.isEmpty() != false || lastDownloadedHeightSnapshot == null) { - PercentDecimal.ONE_HUNDRED_PERCENT - } else { - val numerator = (lastDownloadedHeightSnapshot.value - lastDownloadRangeSnapshot.start.value + 1) - .toFloat() - .coerceAtLeast(PercentDecimal.MIN) - val denominator = (lastDownloadRangeSnapshot.endInclusive.value - lastDownloadRangeSnapshot.start.value + 1) - .toFloat() - - val progress = (numerator / denominator).coerceAtMost(PercentDecimal.MAX) - - PercentDecimal(progress) - } -} - -fun CompactBlockProcessor.ProcessorInfo.scanProgress(): PercentDecimal { - val lastScanRangeSnapshot = lastScanRange - val lastScannedHeightSnapshot = lastScannedHeight - - return if (lastScanRangeSnapshot?.isEmpty() != false || lastScannedHeightSnapshot == null) { - PercentDecimal.ONE_HUNDRED_PERCENT - } else { - val numerator = (lastScannedHeightSnapshot.value - lastScanRangeSnapshot.start.value + 1) - .toFloat() - .coerceAtLeast(PercentDecimal.MIN) - val demonimator = (lastScanRangeSnapshot.endInclusive.value - lastScanRangeSnapshot.start.value + 1) - .toFloat() - - val progress = (numerator / demonimator).coerceAtMost(PercentDecimal.MAX) - - PercentDecimal(progress) - } -} - -// These are estimates -@Suppress("MagicNumber") -private val DOWNLOAD_WEIGHT = PercentDecimal(0.4f) -private val SCAN_WEIGHT = PercentDecimal(PercentDecimal.MAX - DOWNLOAD_WEIGHT.decimal) - -fun CompactBlockProcessor.ProcessorInfo.totalProgress(): PercentDecimal { - val downloadWeighted = DOWNLOAD_WEIGHT.decimal * (downloadProgress().decimal).coerceAtMost(PercentDecimal.MAX) - val scanWeighted = SCAN_WEIGHT.decimal * (scanProgress().decimal).coerceAtMost(PercentDecimal.MAX) - - return PercentDecimal( - downloadWeighted.coerceAtLeast(PercentDecimal.MIN) + - scanWeighted.coerceAtLeast(PercentDecimal.MIN) - ) -} diff --git a/settings.gradle.kts b/settings.gradle.kts index 961d1c4a..d2128db6 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -332,6 +332,7 @@ if (zcashSdkIncludedBuildPath.isNotEmpty()) { includeBuild(zcashSdkIncludedBuildPath) { dependencySubstitution { substitute(module("cash.z.ecc.android:zcash-android-sdk")).using(project(":sdk-lib")) + substitute(module("cash.z.ecc.android:zcash-android-sdk-incubator")).using(project(":sdk-incubator-lib")) } } } diff --git a/ui-lib/src/androidTest/java/co/electriccoin/zcash/ui/fixture/MockSynchronizer.kt b/ui-lib/src/androidTest/java/co/electriccoin/zcash/ui/fixture/MockSynchronizer.kt index 85214157..41124ce6 100644 --- a/ui-lib/src/androidTest/java/co/electriccoin/zcash/ui/fixture/MockSynchronizer.kt +++ b/ui-lib/src/androidTest/java/co/electriccoin/zcash/ui/fixture/MockSynchronizer.kt @@ -5,8 +5,7 @@ import cash.z.ecc.android.sdk.Synchronizer import cash.z.ecc.android.sdk.block.CompactBlockProcessor import cash.z.ecc.android.sdk.model.Account import cash.z.ecc.android.sdk.model.BlockHeight -import cash.z.ecc.android.sdk.model.PendingTransaction -import cash.z.ecc.android.sdk.model.Transaction +import cash.z.ecc.android.sdk.model.PercentDecimal import cash.z.ecc.android.sdk.model.TransactionOverview import cash.z.ecc.android.sdk.model.TransactionRecipient import cash.z.ecc.android.sdk.model.UnifiedSpendingKey @@ -17,7 +16,6 @@ import cash.z.ecc.android.sdk.type.AddressType import cash.z.ecc.android.sdk.type.ConsensusMatchType import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.emptyFlow /** * Mocked Synchronizer that can be used instead of the production SdkSynchronizer e.g. for tests. @@ -25,9 +23,6 @@ import kotlinx.coroutines.flow.emptyFlow @Suppress("TooManyFunctions", "UNUSED_PARAMETER") internal class MockSynchronizer : CloseableSynchronizer { - override val clearedTransactions: Flow> - get() = error("Intentionally not implemented in ${MockSynchronizer::class.simpleName} implementation.") - override val latestBirthdayHeight: BlockHeight get() = error("Intentionally not implemented in ${MockSynchronizer::class.simpleName} implementation.") @@ -63,26 +58,18 @@ internal class MockSynchronizer : CloseableSynchronizer { override val orchardBalances: StateFlow get() = error("Intentionally not implemented in ${MockSynchronizer::class.simpleName} implementation.") - override val pendingTransactions: Flow> - get() = error("Intentionally not implemented in ${MockSynchronizer::class.simpleName} implementation.") - override val processorInfo: Flow get() = error("Intentionally not implemented in ${MockSynchronizer::class.simpleName} implementation.") - - override val progress: Flow - get() = error("Intentionally not implemented in ${MockSynchronizer::class.simpleName} implementation.") - - override val receivedTransactions: Flow> - get() = error("Intentionally not implemented in ${MockSynchronizer::class.simpleName} implementation.") + override val progress: Flow + get() = TODO("Not yet implemented") override val saplingBalances: StateFlow get() = error("Intentionally not implemented in ${MockSynchronizer::class.simpleName} implementation.") - override val sentTransactions: Flow> - get() = error("Intentionally not implemented in ${MockSynchronizer::class.simpleName} implementation.") - override val status: Flow get() = error("Intentionally not implemented in ${MockSynchronizer::class.simpleName} implementation.") + override val transactions: Flow> + get() = TODO("Not yet implemented") override val transparentBalances: StateFlow get() = error("Intentionally not implemented in ${MockSynchronizer::class.simpleName} implementation.") @@ -143,14 +130,11 @@ internal class MockSynchronizer : CloseableSynchronizer { error("Intentionally not implemented in ${MockSynchronizer::class.simpleName} implementation.") } - /** - * This method intentionally returns empty flow, as the PendingTransaction is only an SDK internal class. - */ - override fun sendToAddress(usk: UnifiedSpendingKey, amount: Zatoshi, toAddress: String, memo: String): Flow { - return emptyFlow() + override suspend fun sendToAddress(usk: UnifiedSpendingKey, amount: Zatoshi, toAddress: String, memo: String): Long { + return 1 } - override fun shieldFunds(usk: UnifiedSpendingKey, memo: String): Flow { + override suspend fun shieldFunds(usk: UnifiedSpendingKey, memo: String): Long { error("Intentionally not implemented in ${MockSynchronizer::class.simpleName} implementation.") } diff --git a/ui-lib/src/androidTest/java/co/electriccoin/zcash/ui/screen/home/integration/HomeActivityTest.kt b/ui-lib/src/androidTest/java/co/electriccoin/zcash/ui/screen/home/integration/HomeActivityTest.kt index 03b78b44..1942d7aa 100644 --- a/ui-lib/src/androidTest/java/co/electriccoin/zcash/ui/screen/home/integration/HomeActivityTest.kt +++ b/ui-lib/src/androidTest/java/co/electriccoin/zcash/ui/screen/home/integration/HomeActivityTest.kt @@ -34,7 +34,7 @@ class HomeActivityTest : UiTestPrerequisites() { @MediumTest fun open_close_drawer_menu_test() { val walletSnapshot = WalletSnapshotFixture.new( - status = Synchronizer.Status.DOWNLOADING, + status = Synchronizer.Status.SYNCING, progress = PercentDecimal(0.5f) ) val testSetup = newTestSetup(walletSnapshot) diff --git a/ui-lib/src/androidTest/java/co/electriccoin/zcash/ui/screen/home/integration/HomeViewIntegrationTest.kt b/ui-lib/src/androidTest/java/co/electriccoin/zcash/ui/screen/home/integration/HomeViewIntegrationTest.kt index be595c72..24f1608d 100644 --- a/ui-lib/src/androidTest/java/co/electriccoin/zcash/ui/screen/home/integration/HomeViewIntegrationTest.kt +++ b/ui-lib/src/androidTest/java/co/electriccoin/zcash/ui/screen/home/integration/HomeViewIntegrationTest.kt @@ -37,7 +37,7 @@ class HomeViewIntegrationTest : UiTestPrerequisites() { fun wallet_snapshot_restoration() { val restorationTester = StateRestorationTester(composeTestRule) val walletSnapshot = WalletSnapshotFixture.new( - status = Synchronizer.Status.DOWNLOADING, + status = Synchronizer.Status.SYNCING, progress = PercentDecimal(0.5f) ) val testSetup = newTestSetup(walletSnapshot) @@ -47,7 +47,7 @@ class HomeViewIntegrationTest : UiTestPrerequisites() { } assertNotEquals(WalletSnapshotFixture.STATUS, testSetup.getWalletSnapshot().status) - assertEquals(Synchronizer.Status.DOWNLOADING, testSetup.getWalletSnapshot().status) + assertEquals(Synchronizer.Status.SYNCING, testSetup.getWalletSnapshot().status) assertNotEquals(WalletSnapshotFixture.PROGRESS, testSetup.getWalletSnapshot().progress) assertEquals(0.5f, testSetup.getWalletSnapshot().progress.decimal) @@ -55,7 +55,7 @@ class HomeViewIntegrationTest : UiTestPrerequisites() { restorationTester.emulateSavedInstanceStateRestore() assertNotEquals(WalletSnapshotFixture.STATUS, testSetup.getWalletSnapshot().status) - assertEquals(Synchronizer.Status.DOWNLOADING, testSetup.getWalletSnapshot().status) + assertEquals(Synchronizer.Status.SYNCING, testSetup.getWalletSnapshot().status) assertNotEquals(WalletSnapshotFixture.PROGRESS, testSetup.getWalletSnapshot().progress) assertEquals(0.5f, testSetup.getWalletSnapshot().progress.decimal) diff --git a/ui-lib/src/androidTest/java/co/electriccoin/zcash/ui/screen/home/model/WalletDisplayValuesTest.kt b/ui-lib/src/androidTest/java/co/electriccoin/zcash/ui/screen/home/model/WalletDisplayValuesTest.kt index b5d4be08..f7445a46 100644 --- a/ui-lib/src/androidTest/java/co/electriccoin/zcash/ui/screen/home/model/WalletDisplayValuesTest.kt +++ b/ui-lib/src/androidTest/java/co/electriccoin/zcash/ui/screen/home/model/WalletDisplayValuesTest.kt @@ -12,6 +12,7 @@ import co.electriccoin.zcash.ui.test.getStringResource import org.junit.Assert.assertEquals import org.junit.Test import kotlin.test.assertNotNull +import kotlin.test.assertTrue class WalletDisplayValuesTest { @@ -20,7 +21,7 @@ class WalletDisplayValuesTest { fun download_running_test() { val walletSnapshot = WalletSnapshotFixture.new( progress = PercentDecimal.ONE_HUNDRED_PERCENT, - status = Synchronizer.Status.SCANNING, + status = Synchronizer.Status.SYNCING, orchardBalance = WalletSnapshotFixture.ORCHARD_BALANCE, saplingBalance = WalletSnapshotFixture.SAPLING_BALANCE, transparentBalance = WalletSnapshotFixture.TRANSPARENT_BALANCE @@ -34,7 +35,7 @@ class WalletDisplayValuesTest { assertNotNull(values) assertEquals(1f, values.progress.decimal) assertEquals(walletSnapshot.totalBalance().toZecString(), values.zecAmountText) - assertEquals(getStringResource(R.string.home_status_syncing_catchup), values.statusText) + assertTrue(values.statusText.startsWith(getStringResource(R.string.home_status_syncing_catchup))) // TODO [#578] https://github.com/zcash/zcash-android-wallet-sdk/issues/578 assertEquals(FiatCurrencyConversionRateState.Unavailable, values.fiatCurrencyAmountState) assertEquals(getStringResource(R.string.fiat_currency_conversion_rate_unavailable), values.fiatCurrencyAmountText) diff --git a/ui-lib/src/androidTest/java/co/electriccoin/zcash/ui/screen/home/view/HomeViewTest.kt b/ui-lib/src/androidTest/java/co/electriccoin/zcash/ui/screen/home/view/HomeViewTest.kt index 83a07568..60d7d0a0 100644 --- a/ui-lib/src/androidTest/java/co/electriccoin/zcash/ui/screen/home/view/HomeViewTest.kt +++ b/ui-lib/src/androidTest/java/co/electriccoin/zcash/ui/screen/home/view/HomeViewTest.kt @@ -70,7 +70,7 @@ class HomeViewTest : UiTestPrerequisites() { newTestSetup( isCircularProgressBar = true, walletSnapshot = WalletSnapshotFixture.new( - status = Synchronizer.Status.SCANNING, + status = Synchronizer.Status.SYNCING, progress = PercentDecimal.ONE_HUNDRED_PERCENT ) ) @@ -87,7 +87,7 @@ class HomeViewTest : UiTestPrerequisites() { newTestSetup( isCircularProgressBar = false, walletSnapshot = WalletSnapshotFixture.new( - status = Synchronizer.Status.SCANNING, + status = Synchronizer.Status.SYNCING, progress = PercentDecimal.ONE_HUNDRED_PERCENT ) ) diff --git a/ui-lib/src/main/java/co/electriccoin/zcash/ui/fixture/WalletSnapshotFixture.kt b/ui-lib/src/main/java/co/electriccoin/zcash/ui/fixture/WalletSnapshotFixture.kt index 2c43b4a1..210a8a53 100644 --- a/ui-lib/src/main/java/co/electriccoin/zcash/ui/fixture/WalletSnapshotFixture.kt +++ b/ui-lib/src/main/java/co/electriccoin/zcash/ui/fixture/WalletSnapshotFixture.kt @@ -25,13 +25,10 @@ object WalletSnapshotFixture { null, null, null, - null, - null ), orchardBalance: WalletBalance = ORCHARD_BALANCE, saplingBalance: WalletBalance = SAPLING_BALANCE, transparentBalance: WalletBalance = TRANSPARENT_BALANCE, - pendingCount: Int = 0, progress: PercentDecimal = PROGRESS, synchronizerError: SynchronizerError? = null ) = WalletSnapshot( @@ -40,7 +37,6 @@ object WalletSnapshotFixture { orchardBalance, saplingBalance, transparentBalance, - pendingCount, progress, synchronizerError ) diff --git a/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/home/model/CommonTransaction.kt b/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/home/model/CommonTransaction.kt deleted file mode 100644 index e2e0473f..00000000 --- a/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/home/model/CommonTransaction.kt +++ /dev/null @@ -1,12 +0,0 @@ -package co.electriccoin.zcash.ui.screen.home.model - -import cash.z.ecc.android.sdk.model.PendingTransaction -import cash.z.ecc.android.sdk.model.TransactionOverview - -/** - * A common transactions wrapper class to provide unified way to work with a transactions classes from our SDK. - */ -sealed class CommonTransaction { - data class Pending(val data: PendingTransaction) : CommonTransaction() - data class Overview(val data: TransactionOverview) : CommonTransaction() -} diff --git a/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/home/model/WalletDisplayValues.kt b/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/home/model/WalletDisplayValues.kt index c0b766f9..63af57f2 100644 --- a/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/home/model/WalletDisplayValues.kt +++ b/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/home/model/WalletDisplayValues.kt @@ -39,9 +39,7 @@ data class WalletDisplayValues( var fiatCurrencyAmountText = getFiatCurrencyRateValue(context, fiatCurrencyAmountState) when (walletSnapshot.status) { - Synchronizer.Status.PREPARING, - Synchronizer.Status.DOWNLOADING, - Synchronizer.Status.VALIDATING -> { + Synchronizer.Status.SYNCING -> { progress = walletSnapshot.progress val progressPercent = (walletSnapshot.progress.decimal * 100).roundToInt() // we add "so far" to the amount @@ -53,11 +51,6 @@ data class WalletDisplayValues( } statusText = context.getString(R.string.home_status_syncing_format, progressPercent) } - Synchronizer.Status.SCANNING -> { - // SDK provides us only one progress, which keeps on 100 in the scanning state - progress = PercentDecimal.ONE_HUNDRED_PERCENT - statusText = context.getString(R.string.home_status_syncing_catchup) - } Synchronizer.Status.SYNCED, Synchronizer.Status.ENHANCING -> { statusText = if (updateAvailable) { diff --git a/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/home/model/WalletSnapshot.kt b/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/home/model/WalletSnapshot.kt index eaa023cb..85223daf 100644 --- a/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/home/model/WalletSnapshot.kt +++ b/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/home/model/WalletSnapshot.kt @@ -15,7 +15,6 @@ data class WalletSnapshot( val orchardBalance: WalletBalance, val saplingBalance: WalletBalance, val transparentBalance: WalletBalance, - val pendingCount: Int, val progress: PercentDecimal, val synchronizerError: SynchronizerError? ) { diff --git a/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/home/view/HomeView.kt b/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/home/view/HomeView.kt index 156e1d62..94588258 100644 --- a/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/home/view/HomeView.kt +++ b/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/home/view/HomeView.kt @@ -58,6 +58,7 @@ import androidx.compose.ui.unit.dp import cash.z.ecc.android.sdk.Synchronizer import cash.z.ecc.android.sdk.model.FiatCurrencyConversionRateState import cash.z.ecc.android.sdk.model.PercentDecimal +import cash.z.ecc.android.sdk.model.TransactionOverview import co.electriccoin.zcash.crash.android.GlobalCrashReporter import co.electriccoin.zcash.ui.R import co.electriccoin.zcash.ui.common.DisableScreenTimeout @@ -71,7 +72,6 @@ import co.electriccoin.zcash.ui.design.component.PrimaryButton import co.electriccoin.zcash.ui.design.theme.ZcashTheme import co.electriccoin.zcash.ui.fixture.WalletSnapshotFixture import co.electriccoin.zcash.ui.screen.home.HomeTag -import co.electriccoin.zcash.ui.screen.home.model.CommonTransaction import co.electriccoin.zcash.ui.screen.home.model.WalletDisplayValues import co.electriccoin.zcash.ui.screen.home.model.WalletSnapshot import kotlinx.collections.immutable.ImmutableList @@ -110,7 +110,7 @@ fun ComposablePreview() { @Composable fun Home( walletSnapshot: WalletSnapshot, - transactionHistory: ImmutableList, + transactionHistory: ImmutableList, isUpdateAvailable: Boolean, isKeepScreenOnDuringSync: Boolean?, isFiatConversionEnabled: Boolean, @@ -295,7 +295,7 @@ private fun HomeDrawer( @Composable private fun HomeMainContent( walletSnapshot: WalletSnapshot, - transactionHistory: ImmutableList, + transactionHistory: ImmutableList, isUpdateAvailable: Boolean, isKeepScreenOnDuringSync: Boolean?, isFiatConversionEnabled: Boolean, @@ -347,9 +347,7 @@ private fun HomeMainContent( } private fun isSyncing(status: Synchronizer.Status): Boolean { - return status == Synchronizer.Status.DOWNLOADING || - status == Synchronizer.Status.VALIDATING || - status == Synchronizer.Status.SCANNING || + return status == Synchronizer.Status.SYNCING || status == Synchronizer.Status.ENHANCING } @@ -458,7 +456,7 @@ private fun Status( @Composable @Suppress("MagicNumber") -private fun History(transactionHistory: ImmutableList) { +private fun History(transactionHistory: ImmutableList) { if (transactionHistory.isEmpty()) { return } diff --git a/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/home/viewmodel/WalletViewModel.kt b/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/home/viewmodel/WalletViewModel.kt index 686418aa..d1fc8d30 100644 --- a/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/home/viewmodel/WalletViewModel.kt +++ b/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/home/viewmodel/WalletViewModel.kt @@ -11,15 +11,13 @@ import cash.z.ecc.android.sdk.block.CompactBlockProcessor import cash.z.ecc.android.sdk.model.Account import cash.z.ecc.android.sdk.model.BlockHeight import cash.z.ecc.android.sdk.model.FiatCurrency -import cash.z.ecc.android.sdk.model.PendingTransaction import cash.z.ecc.android.sdk.model.PercentDecimal import cash.z.ecc.android.sdk.model.PersistableWallet +import cash.z.ecc.android.sdk.model.TransactionOverview import cash.z.ecc.android.sdk.model.WalletAddresses import cash.z.ecc.android.sdk.model.WalletBalance import cash.z.ecc.android.sdk.model.Zatoshi import cash.z.ecc.android.sdk.model.ZcashNetwork -import cash.z.ecc.android.sdk.model.isMined -import cash.z.ecc.android.sdk.model.isSubmitSuccess import cash.z.ecc.android.sdk.tool.DerivationTool import cash.z.ecc.sdk.type.fromResources import co.electriccoin.zcash.global.getInstance @@ -30,7 +28,6 @@ import co.electriccoin.zcash.ui.preference.EncryptedPreferenceKeys import co.electriccoin.zcash.ui.preference.EncryptedPreferenceSingleton import co.electriccoin.zcash.ui.preference.StandardPreferenceKeys import co.electriccoin.zcash.ui.preference.StandardPreferenceSingleton -import co.electriccoin.zcash.ui.screen.home.model.CommonTransaction import co.electriccoin.zcash.ui.screen.home.model.WalletSnapshot import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf @@ -44,7 +41,6 @@ import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.WhileSubscribed import kotlinx.coroutines.flow.callbackFlow import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.emitAll import kotlinx.coroutines.flow.filterIsInstance import kotlinx.coroutines.flow.filterNotNull @@ -154,12 +150,12 @@ class WalletViewModel(application: Application) : AndroidViewModel(application) // This is not the right API, because the transaction list could be very long and might need UI filtering @OptIn(ExperimentalCoroutinesApi::class) - val transactionSnapshot: StateFlow> = synchronizer + val transactionSnapshot: StateFlow> = synchronizer .flatMapLatest { if (null == it) { flowOf(persistentListOf()) } else { - it.toTransactions() + it.transactions.map { list -> list.toPersistentList() } } } .stateIn( @@ -331,25 +327,14 @@ private fun Synchronizer.toWalletSnapshot() = orchardBalances, // 2 saplingBalances, // 3 transparentBalances, // 4 - pendingTransactions.distinctUntilChanged(), // 5 - progress, // 6 - toCommonError() // 7 + progress, // 5 + toCommonError() // 6 ) { flows -> - val pendingCount = (flows[5] as List<*>) - .filterIsInstance(PendingTransaction::class.java) - .count { - it.isSubmitSuccess() && !it.isMined() - } val orchardBalance = flows[2] as WalletBalance? val saplingBalance = flows[3] as WalletBalance? val transparentBalance = flows[4] as WalletBalance? - val progressPercentDecimal = (flows[6] as Int).let { value -> - if (value > PercentDecimal.MAX || value < PercentDecimal.MIN) { - PercentDecimal.ZERO_PERCENT - } - PercentDecimal((flows[6] as Int) / 100f) - } + val progressPercentDecimal = flows[5] as PercentDecimal WalletSnapshot( flows[0] as Synchronizer.Status, @@ -357,23 +342,7 @@ private fun Synchronizer.toWalletSnapshot() = orchardBalance ?: WalletBalance(Zatoshi(0), Zatoshi(0)), saplingBalance ?: WalletBalance(Zatoshi(0), Zatoshi(0)), transparentBalance ?: WalletBalance(Zatoshi(0), Zatoshi(0)), - pendingCount, progressPercentDecimal, - flows[7] as SynchronizerError? + flows[6] as SynchronizerError? ) } - -private fun Synchronizer.toTransactions(): Flow> = - combine( - clearedTransactions.distinctUntilChanged(), - pendingTransactions.distinctUntilChanged() - ) { cleared, pending -> - // TODO [#157]: Sort the transactions to show the most recent - // TODO [#157]: https://github.com/zcash/secant-android-wallet/issues/157 - - // Note that the list of transactions will not be sorted. - buildList { - addAll(cleared.map { CommonTransaction.Overview(it) }) - addAll(pending.map { CommonTransaction.Pending(it) }) - }.toPersistentList() - } diff --git a/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/send/AndroidSend.kt b/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/send/AndroidSend.kt index 3092d4cc..6eb38d8a 100644 --- a/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/send/AndroidSend.kt +++ b/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/send/AndroidSend.kt @@ -16,8 +16,6 @@ import cash.z.ecc.android.sdk.Synchronizer import cash.z.ecc.android.sdk.model.UnifiedSpendingKey import cash.z.ecc.android.sdk.model.Zatoshi import cash.z.ecc.android.sdk.model.ZecSend -import cash.z.ecc.android.sdk.model.isFailedSubmit -import cash.z.ecc.android.sdk.model.isSubmitSuccess import cash.z.ecc.sdk.send import co.electriccoin.zcash.spackle.Twig import co.electriccoin.zcash.ui.MainActivity @@ -85,7 +83,9 @@ internal fun WrapSend( when (sendStage) { SendStage.Form -> goBack() SendStage.Confirmation -> setSendStage(SendStage.Form) - SendStage.Sending -> { /* no action - wait until done */ } + SendStage.Sending -> { // no action - wait until done + } + SendStage.SendFailure -> setSendStage(SendStage.Form) SendStage.SendSuccessful -> goBack() } @@ -108,21 +108,16 @@ internal fun WrapSend( onBack = onBackAction, onCreateAndSend = { scope.launch { - synchronizer.send(spendingKey, it).collect { - Twig.debug { "Sending transaction id: ${it.id}" } - - if (it.isSubmitSuccess()) { + Twig.debug { "Sending transaction" } + runCatching { synchronizer.send(spendingKey, it) } + .onSuccess { setSendStage(SendStage.SendSuccessful) - Twig.debug { - "Transaction id:${it.id} submitted successfully at ${it.createTime} with " + - "${it.submitAttempts} attempts." - } - } else if (it.isFailedSubmit()) { - Twig.debug { "Transaction id:${it.id} submission failed with: ${it.errorMessage}." } + Twig.debug { "Transaction id:$it submitted successfully" } + } + .onFailure { + Twig.debug { "Transaction submission failed with: $it." } setSendStage(SendStage.SendFailure) } - // All other states of Pending transaction mean waiting for one of the states above - } } }, onQrScannerOpen = goToQrScanner, diff --git a/ui-lib/src/main/java/co/electriccoin/zcash/work/SyncWorker.kt b/ui-lib/src/main/java/co/electriccoin/zcash/work/SyncWorker.kt index 8051d2ed..59815ca7 100644 --- a/ui-lib/src/main/java/co/electriccoin/zcash/work/SyncWorker.kt +++ b/ui-lib/src/main/java/co/electriccoin/zcash/work/SyncWorker.kt @@ -10,6 +10,7 @@ import androidx.work.PeriodicWorkRequestBuilder import androidx.work.WorkerParameters import cash.z.ecc.android.sdk.Synchronizer import cash.z.ecc.android.sdk.WalletCoordinator +import cash.z.ecc.android.sdk.model.PercentDecimal import co.electriccoin.zcash.global.getInstance import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.collect @@ -35,7 +36,7 @@ class SyncWorker(context: Context, workerParameters: WorkerParameters) : Corouti } ?: emptyFlow() } .takeWhile { - it.status != Synchronizer.Status.DISCONNECTED && it.progress < ONE_HUNDRED_PERCENT + it.status != Synchronizer.Status.DISCONNECTED && it.progress.isLessThanHundredPercent() } .collect() @@ -43,7 +44,6 @@ class SyncWorker(context: Context, workerParameters: WorkerParameters) : Corouti } companion object { - private const val ONE_HUNDRED_PERCENT = 100 /* * There may be better periods; we have not optimized for this yet. @@ -63,4 +63,4 @@ class SyncWorker(context: Context, workerParameters: WorkerParameters) : Corouti } } -private data class StatusAndProgress(val status: Synchronizer.Status, val progress: Int) +private data class StatusAndProgress(val status: Synchronizer.Status, val progress: PercentDecimal)