[#853] Adopt latest SDK changes
Co-authored-by: Honza <rychnovsky.honza@gmail.com>
This commit is contained in:
parent
e20221f117
commit
b6226c55eb
|
@ -153,7 +153,7 @@ ZCASH_ANDROID_WALLET_PLUGINS_VERSION=1.0.0
|
||||||
ZCASH_BIP39_VERSION=1.0.4
|
ZCASH_BIP39_VERSION=1.0.4
|
||||||
# TODO [#279]: Revert to stable SDK before app release
|
# TODO [#279]: Revert to stable SDK before app release
|
||||||
# TODO [#279]: https://github.com/zcash/secant-android-wallet/issues/279
|
# 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
|
ZXING_VERSION=3.5.1
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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)
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -332,6 +332,7 @@ if (zcashSdkIncludedBuildPath.isNotEmpty()) {
|
||||||
includeBuild(zcashSdkIncludedBuildPath) {
|
includeBuild(zcashSdkIncludedBuildPath) {
|
||||||
dependencySubstitution {
|
dependencySubstitution {
|
||||||
substitute(module("cash.z.ecc.android:zcash-android-sdk")).using(project(":sdk-lib"))
|
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"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.block.CompactBlockProcessor
|
||||||
import cash.z.ecc.android.sdk.model.Account
|
import cash.z.ecc.android.sdk.model.Account
|
||||||
import cash.z.ecc.android.sdk.model.BlockHeight
|
import cash.z.ecc.android.sdk.model.BlockHeight
|
||||||
import cash.z.ecc.android.sdk.model.PendingTransaction
|
import cash.z.ecc.android.sdk.model.PercentDecimal
|
||||||
import cash.z.ecc.android.sdk.model.Transaction
|
|
||||||
import cash.z.ecc.android.sdk.model.TransactionOverview
|
import cash.z.ecc.android.sdk.model.TransactionOverview
|
||||||
import cash.z.ecc.android.sdk.model.TransactionRecipient
|
import cash.z.ecc.android.sdk.model.TransactionRecipient
|
||||||
import cash.z.ecc.android.sdk.model.UnifiedSpendingKey
|
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 cash.z.ecc.android.sdk.type.ConsensusMatchType
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
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.
|
* 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")
|
@Suppress("TooManyFunctions", "UNUSED_PARAMETER")
|
||||||
internal class MockSynchronizer : CloseableSynchronizer {
|
internal class MockSynchronizer : CloseableSynchronizer {
|
||||||
|
|
||||||
override val clearedTransactions: Flow<List<TransactionOverview>>
|
|
||||||
get() = error("Intentionally not implemented in ${MockSynchronizer::class.simpleName} implementation.")
|
|
||||||
|
|
||||||
override val latestBirthdayHeight: BlockHeight
|
override val latestBirthdayHeight: BlockHeight
|
||||||
get() = error("Intentionally not implemented in ${MockSynchronizer::class.simpleName} implementation.")
|
get() = error("Intentionally not implemented in ${MockSynchronizer::class.simpleName} implementation.")
|
||||||
|
|
||||||
|
@ -63,26 +58,18 @@ internal class MockSynchronizer : CloseableSynchronizer {
|
||||||
override val orchardBalances: StateFlow<WalletBalance?>
|
override val orchardBalances: StateFlow<WalletBalance?>
|
||||||
get() = error("Intentionally not implemented in ${MockSynchronizer::class.simpleName} implementation.")
|
get() = error("Intentionally not implemented in ${MockSynchronizer::class.simpleName} implementation.")
|
||||||
|
|
||||||
override val pendingTransactions: Flow<List<PendingTransaction>>
|
|
||||||
get() = error("Intentionally not implemented in ${MockSynchronizer::class.simpleName} implementation.")
|
|
||||||
|
|
||||||
override val processorInfo: Flow<CompactBlockProcessor.ProcessorInfo>
|
override val processorInfo: Flow<CompactBlockProcessor.ProcessorInfo>
|
||||||
get() = error("Intentionally not implemented in ${MockSynchronizer::class.simpleName} implementation.")
|
get() = error("Intentionally not implemented in ${MockSynchronizer::class.simpleName} implementation.")
|
||||||
|
override val progress: Flow<PercentDecimal>
|
||||||
override val progress: Flow<Int>
|
get() = TODO("Not yet implemented")
|
||||||
get() = error("Intentionally not implemented in ${MockSynchronizer::class.simpleName} implementation.")
|
|
||||||
|
|
||||||
override val receivedTransactions: Flow<List<Transaction.Received>>
|
|
||||||
get() = error("Intentionally not implemented in ${MockSynchronizer::class.simpleName} implementation.")
|
|
||||||
|
|
||||||
override val saplingBalances: StateFlow<WalletBalance?>
|
override val saplingBalances: StateFlow<WalletBalance?>
|
||||||
get() = error("Intentionally not implemented in ${MockSynchronizer::class.simpleName} implementation.")
|
get() = error("Intentionally not implemented in ${MockSynchronizer::class.simpleName} implementation.")
|
||||||
|
|
||||||
override val sentTransactions: Flow<List<Transaction.Sent>>
|
|
||||||
get() = error("Intentionally not implemented in ${MockSynchronizer::class.simpleName} implementation.")
|
|
||||||
|
|
||||||
override val status: Flow<Synchronizer.Status>
|
override val status: Flow<Synchronizer.Status>
|
||||||
get() = error("Intentionally not implemented in ${MockSynchronizer::class.simpleName} implementation.")
|
get() = error("Intentionally not implemented in ${MockSynchronizer::class.simpleName} implementation.")
|
||||||
|
override val transactions: Flow<List<TransactionOverview>>
|
||||||
|
get() = TODO("Not yet implemented")
|
||||||
|
|
||||||
override val transparentBalances: StateFlow<WalletBalance?>
|
override val transparentBalances: StateFlow<WalletBalance?>
|
||||||
get() = error("Intentionally not implemented in ${MockSynchronizer::class.simpleName} implementation.")
|
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.")
|
error("Intentionally not implemented in ${MockSynchronizer::class.simpleName} implementation.")
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
override suspend fun sendToAddress(usk: UnifiedSpendingKey, amount: Zatoshi, toAddress: String, memo: String): Long {
|
||||||
* This method intentionally returns empty flow, as the PendingTransaction is only an SDK internal class.
|
return 1
|
||||||
*/
|
|
||||||
override fun sendToAddress(usk: UnifiedSpendingKey, amount: Zatoshi, toAddress: String, memo: String): Flow<PendingTransaction> {
|
|
||||||
return emptyFlow()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun shieldFunds(usk: UnifiedSpendingKey, memo: String): Flow<PendingTransaction> {
|
override suspend fun shieldFunds(usk: UnifiedSpendingKey, memo: String): Long {
|
||||||
error("Intentionally not implemented in ${MockSynchronizer::class.simpleName} implementation.")
|
error("Intentionally not implemented in ${MockSynchronizer::class.simpleName} implementation.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@ class HomeActivityTest : UiTestPrerequisites() {
|
||||||
@MediumTest
|
@MediumTest
|
||||||
fun open_close_drawer_menu_test() {
|
fun open_close_drawer_menu_test() {
|
||||||
val walletSnapshot = WalletSnapshotFixture.new(
|
val walletSnapshot = WalletSnapshotFixture.new(
|
||||||
status = Synchronizer.Status.DOWNLOADING,
|
status = Synchronizer.Status.SYNCING,
|
||||||
progress = PercentDecimal(0.5f)
|
progress = PercentDecimal(0.5f)
|
||||||
)
|
)
|
||||||
val testSetup = newTestSetup(walletSnapshot)
|
val testSetup = newTestSetup(walletSnapshot)
|
||||||
|
|
|
@ -37,7 +37,7 @@ class HomeViewIntegrationTest : UiTestPrerequisites() {
|
||||||
fun wallet_snapshot_restoration() {
|
fun wallet_snapshot_restoration() {
|
||||||
val restorationTester = StateRestorationTester(composeTestRule)
|
val restorationTester = StateRestorationTester(composeTestRule)
|
||||||
val walletSnapshot = WalletSnapshotFixture.new(
|
val walletSnapshot = WalletSnapshotFixture.new(
|
||||||
status = Synchronizer.Status.DOWNLOADING,
|
status = Synchronizer.Status.SYNCING,
|
||||||
progress = PercentDecimal(0.5f)
|
progress = PercentDecimal(0.5f)
|
||||||
)
|
)
|
||||||
val testSetup = newTestSetup(walletSnapshot)
|
val testSetup = newTestSetup(walletSnapshot)
|
||||||
|
@ -47,7 +47,7 @@ class HomeViewIntegrationTest : UiTestPrerequisites() {
|
||||||
}
|
}
|
||||||
|
|
||||||
assertNotEquals(WalletSnapshotFixture.STATUS, testSetup.getWalletSnapshot().status)
|
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)
|
assertNotEquals(WalletSnapshotFixture.PROGRESS, testSetup.getWalletSnapshot().progress)
|
||||||
assertEquals(0.5f, testSetup.getWalletSnapshot().progress.decimal)
|
assertEquals(0.5f, testSetup.getWalletSnapshot().progress.decimal)
|
||||||
|
@ -55,7 +55,7 @@ class HomeViewIntegrationTest : UiTestPrerequisites() {
|
||||||
restorationTester.emulateSavedInstanceStateRestore()
|
restorationTester.emulateSavedInstanceStateRestore()
|
||||||
|
|
||||||
assertNotEquals(WalletSnapshotFixture.STATUS, testSetup.getWalletSnapshot().status)
|
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)
|
assertNotEquals(WalletSnapshotFixture.PROGRESS, testSetup.getWalletSnapshot().progress)
|
||||||
assertEquals(0.5f, testSetup.getWalletSnapshot().progress.decimal)
|
assertEquals(0.5f, testSetup.getWalletSnapshot().progress.decimal)
|
||||||
|
|
|
@ -12,6 +12,7 @@ import co.electriccoin.zcash.ui.test.getStringResource
|
||||||
import org.junit.Assert.assertEquals
|
import org.junit.Assert.assertEquals
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import kotlin.test.assertNotNull
|
import kotlin.test.assertNotNull
|
||||||
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
class WalletDisplayValuesTest {
|
class WalletDisplayValuesTest {
|
||||||
|
|
||||||
|
@ -20,7 +21,7 @@ class WalletDisplayValuesTest {
|
||||||
fun download_running_test() {
|
fun download_running_test() {
|
||||||
val walletSnapshot = WalletSnapshotFixture.new(
|
val walletSnapshot = WalletSnapshotFixture.new(
|
||||||
progress = PercentDecimal.ONE_HUNDRED_PERCENT,
|
progress = PercentDecimal.ONE_HUNDRED_PERCENT,
|
||||||
status = Synchronizer.Status.SCANNING,
|
status = Synchronizer.Status.SYNCING,
|
||||||
orchardBalance = WalletSnapshotFixture.ORCHARD_BALANCE,
|
orchardBalance = WalletSnapshotFixture.ORCHARD_BALANCE,
|
||||||
saplingBalance = WalletSnapshotFixture.SAPLING_BALANCE,
|
saplingBalance = WalletSnapshotFixture.SAPLING_BALANCE,
|
||||||
transparentBalance = WalletSnapshotFixture.TRANSPARENT_BALANCE
|
transparentBalance = WalletSnapshotFixture.TRANSPARENT_BALANCE
|
||||||
|
@ -34,7 +35,7 @@ class WalletDisplayValuesTest {
|
||||||
assertNotNull(values)
|
assertNotNull(values)
|
||||||
assertEquals(1f, values.progress.decimal)
|
assertEquals(1f, values.progress.decimal)
|
||||||
assertEquals(walletSnapshot.totalBalance().toZecString(), values.zecAmountText)
|
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
|
// TODO [#578] https://github.com/zcash/zcash-android-wallet-sdk/issues/578
|
||||||
assertEquals(FiatCurrencyConversionRateState.Unavailable, values.fiatCurrencyAmountState)
|
assertEquals(FiatCurrencyConversionRateState.Unavailable, values.fiatCurrencyAmountState)
|
||||||
assertEquals(getStringResource(R.string.fiat_currency_conversion_rate_unavailable), values.fiatCurrencyAmountText)
|
assertEquals(getStringResource(R.string.fiat_currency_conversion_rate_unavailable), values.fiatCurrencyAmountText)
|
||||||
|
|
|
@ -70,7 +70,7 @@ class HomeViewTest : UiTestPrerequisites() {
|
||||||
newTestSetup(
|
newTestSetup(
|
||||||
isCircularProgressBar = true,
|
isCircularProgressBar = true,
|
||||||
walletSnapshot = WalletSnapshotFixture.new(
|
walletSnapshot = WalletSnapshotFixture.new(
|
||||||
status = Synchronizer.Status.SCANNING,
|
status = Synchronizer.Status.SYNCING,
|
||||||
progress = PercentDecimal.ONE_HUNDRED_PERCENT
|
progress = PercentDecimal.ONE_HUNDRED_PERCENT
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -87,7 +87,7 @@ class HomeViewTest : UiTestPrerequisites() {
|
||||||
newTestSetup(
|
newTestSetup(
|
||||||
isCircularProgressBar = false,
|
isCircularProgressBar = false,
|
||||||
walletSnapshot = WalletSnapshotFixture.new(
|
walletSnapshot = WalletSnapshotFixture.new(
|
||||||
status = Synchronizer.Status.SCANNING,
|
status = Synchronizer.Status.SYNCING,
|
||||||
progress = PercentDecimal.ONE_HUNDRED_PERCENT
|
progress = PercentDecimal.ONE_HUNDRED_PERCENT
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
|
@ -25,13 +25,10 @@ object WalletSnapshotFixture {
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
null,
|
|
||||||
null
|
|
||||||
),
|
),
|
||||||
orchardBalance: WalletBalance = ORCHARD_BALANCE,
|
orchardBalance: WalletBalance = ORCHARD_BALANCE,
|
||||||
saplingBalance: WalletBalance = SAPLING_BALANCE,
|
saplingBalance: WalletBalance = SAPLING_BALANCE,
|
||||||
transparentBalance: WalletBalance = TRANSPARENT_BALANCE,
|
transparentBalance: WalletBalance = TRANSPARENT_BALANCE,
|
||||||
pendingCount: Int = 0,
|
|
||||||
progress: PercentDecimal = PROGRESS,
|
progress: PercentDecimal = PROGRESS,
|
||||||
synchronizerError: SynchronizerError? = null
|
synchronizerError: SynchronizerError? = null
|
||||||
) = WalletSnapshot(
|
) = WalletSnapshot(
|
||||||
|
@ -40,7 +37,6 @@ object WalletSnapshotFixture {
|
||||||
orchardBalance,
|
orchardBalance,
|
||||||
saplingBalance,
|
saplingBalance,
|
||||||
transparentBalance,
|
transparentBalance,
|
||||||
pendingCount,
|
|
||||||
progress,
|
progress,
|
||||||
synchronizerError
|
synchronizerError
|
||||||
)
|
)
|
||||||
|
|
|
@ -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()
|
|
||||||
}
|
|
|
@ -39,9 +39,7 @@ data class WalletDisplayValues(
|
||||||
var fiatCurrencyAmountText = getFiatCurrencyRateValue(context, fiatCurrencyAmountState)
|
var fiatCurrencyAmountText = getFiatCurrencyRateValue(context, fiatCurrencyAmountState)
|
||||||
|
|
||||||
when (walletSnapshot.status) {
|
when (walletSnapshot.status) {
|
||||||
Synchronizer.Status.PREPARING,
|
Synchronizer.Status.SYNCING -> {
|
||||||
Synchronizer.Status.DOWNLOADING,
|
|
||||||
Synchronizer.Status.VALIDATING -> {
|
|
||||||
progress = walletSnapshot.progress
|
progress = walletSnapshot.progress
|
||||||
val progressPercent = (walletSnapshot.progress.decimal * 100).roundToInt()
|
val progressPercent = (walletSnapshot.progress.decimal * 100).roundToInt()
|
||||||
// we add "so far" to the amount
|
// we add "so far" to the amount
|
||||||
|
@ -53,11 +51,6 @@ data class WalletDisplayValues(
|
||||||
}
|
}
|
||||||
statusText = context.getString(R.string.home_status_syncing_format, progressPercent)
|
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.SYNCED,
|
||||||
Synchronizer.Status.ENHANCING -> {
|
Synchronizer.Status.ENHANCING -> {
|
||||||
statusText = if (updateAvailable) {
|
statusText = if (updateAvailable) {
|
||||||
|
|
|
@ -15,7 +15,6 @@ data class WalletSnapshot(
|
||||||
val orchardBalance: WalletBalance,
|
val orchardBalance: WalletBalance,
|
||||||
val saplingBalance: WalletBalance,
|
val saplingBalance: WalletBalance,
|
||||||
val transparentBalance: WalletBalance,
|
val transparentBalance: WalletBalance,
|
||||||
val pendingCount: Int,
|
|
||||||
val progress: PercentDecimal,
|
val progress: PercentDecimal,
|
||||||
val synchronizerError: SynchronizerError?
|
val synchronizerError: SynchronizerError?
|
||||||
) {
|
) {
|
||||||
|
|
|
@ -58,6 +58,7 @@ import androidx.compose.ui.unit.dp
|
||||||
import cash.z.ecc.android.sdk.Synchronizer
|
import cash.z.ecc.android.sdk.Synchronizer
|
||||||
import cash.z.ecc.android.sdk.model.FiatCurrencyConversionRateState
|
import cash.z.ecc.android.sdk.model.FiatCurrencyConversionRateState
|
||||||
import cash.z.ecc.android.sdk.model.PercentDecimal
|
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.crash.android.GlobalCrashReporter
|
||||||
import co.electriccoin.zcash.ui.R
|
import co.electriccoin.zcash.ui.R
|
||||||
import co.electriccoin.zcash.ui.common.DisableScreenTimeout
|
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.design.theme.ZcashTheme
|
||||||
import co.electriccoin.zcash.ui.fixture.WalletSnapshotFixture
|
import co.electriccoin.zcash.ui.fixture.WalletSnapshotFixture
|
||||||
import co.electriccoin.zcash.ui.screen.home.HomeTag
|
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.WalletDisplayValues
|
||||||
import co.electriccoin.zcash.ui.screen.home.model.WalletSnapshot
|
import co.electriccoin.zcash.ui.screen.home.model.WalletSnapshot
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
|
@ -110,7 +110,7 @@ fun ComposablePreview() {
|
||||||
@Composable
|
@Composable
|
||||||
fun Home(
|
fun Home(
|
||||||
walletSnapshot: WalletSnapshot,
|
walletSnapshot: WalletSnapshot,
|
||||||
transactionHistory: ImmutableList<CommonTransaction>,
|
transactionHistory: ImmutableList<TransactionOverview>,
|
||||||
isUpdateAvailable: Boolean,
|
isUpdateAvailable: Boolean,
|
||||||
isKeepScreenOnDuringSync: Boolean?,
|
isKeepScreenOnDuringSync: Boolean?,
|
||||||
isFiatConversionEnabled: Boolean,
|
isFiatConversionEnabled: Boolean,
|
||||||
|
@ -295,7 +295,7 @@ private fun HomeDrawer(
|
||||||
@Composable
|
@Composable
|
||||||
private fun HomeMainContent(
|
private fun HomeMainContent(
|
||||||
walletSnapshot: WalletSnapshot,
|
walletSnapshot: WalletSnapshot,
|
||||||
transactionHistory: ImmutableList<CommonTransaction>,
|
transactionHistory: ImmutableList<TransactionOverview>,
|
||||||
isUpdateAvailable: Boolean,
|
isUpdateAvailable: Boolean,
|
||||||
isKeepScreenOnDuringSync: Boolean?,
|
isKeepScreenOnDuringSync: Boolean?,
|
||||||
isFiatConversionEnabled: Boolean,
|
isFiatConversionEnabled: Boolean,
|
||||||
|
@ -347,9 +347,7 @@ private fun HomeMainContent(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isSyncing(status: Synchronizer.Status): Boolean {
|
private fun isSyncing(status: Synchronizer.Status): Boolean {
|
||||||
return status == Synchronizer.Status.DOWNLOADING ||
|
return status == Synchronizer.Status.SYNCING ||
|
||||||
status == Synchronizer.Status.VALIDATING ||
|
|
||||||
status == Synchronizer.Status.SCANNING ||
|
|
||||||
status == Synchronizer.Status.ENHANCING
|
status == Synchronizer.Status.ENHANCING
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -458,7 +456,7 @@ private fun Status(
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@Suppress("MagicNumber")
|
@Suppress("MagicNumber")
|
||||||
private fun History(transactionHistory: ImmutableList<CommonTransaction>) {
|
private fun History(transactionHistory: ImmutableList<TransactionOverview>) {
|
||||||
if (transactionHistory.isEmpty()) {
|
if (transactionHistory.isEmpty()) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.Account
|
||||||
import cash.z.ecc.android.sdk.model.BlockHeight
|
import cash.z.ecc.android.sdk.model.BlockHeight
|
||||||
import cash.z.ecc.android.sdk.model.FiatCurrency
|
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.PercentDecimal
|
||||||
import cash.z.ecc.android.sdk.model.PersistableWallet
|
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.WalletAddresses
|
||||||
import cash.z.ecc.android.sdk.model.WalletBalance
|
import cash.z.ecc.android.sdk.model.WalletBalance
|
||||||
import cash.z.ecc.android.sdk.model.Zatoshi
|
import cash.z.ecc.android.sdk.model.Zatoshi
|
||||||
import cash.z.ecc.android.sdk.model.ZcashNetwork
|
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.android.sdk.tool.DerivationTool
|
||||||
import cash.z.ecc.sdk.type.fromResources
|
import cash.z.ecc.sdk.type.fromResources
|
||||||
import co.electriccoin.zcash.global.getInstance
|
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.EncryptedPreferenceSingleton
|
||||||
import co.electriccoin.zcash.ui.preference.StandardPreferenceKeys
|
import co.electriccoin.zcash.ui.preference.StandardPreferenceKeys
|
||||||
import co.electriccoin.zcash.ui.preference.StandardPreferenceSingleton
|
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 co.electriccoin.zcash.ui.screen.home.model.WalletSnapshot
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
import kotlinx.collections.immutable.persistentListOf
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
|
@ -44,7 +41,6 @@ import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlinx.coroutines.flow.WhileSubscribed
|
import kotlinx.coroutines.flow.WhileSubscribed
|
||||||
import kotlinx.coroutines.flow.callbackFlow
|
import kotlinx.coroutines.flow.callbackFlow
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
|
||||||
import kotlinx.coroutines.flow.emitAll
|
import kotlinx.coroutines.flow.emitAll
|
||||||
import kotlinx.coroutines.flow.filterIsInstance
|
import kotlinx.coroutines.flow.filterIsInstance
|
||||||
import kotlinx.coroutines.flow.filterNotNull
|
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
|
// This is not the right API, because the transaction list could be very long and might need UI filtering
|
||||||
@OptIn(ExperimentalCoroutinesApi::class)
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
val transactionSnapshot: StateFlow<ImmutableList<CommonTransaction>> = synchronizer
|
val transactionSnapshot: StateFlow<ImmutableList<TransactionOverview>> = synchronizer
|
||||||
.flatMapLatest {
|
.flatMapLatest {
|
||||||
if (null == it) {
|
if (null == it) {
|
||||||
flowOf(persistentListOf())
|
flowOf(persistentListOf())
|
||||||
} else {
|
} else {
|
||||||
it.toTransactions()
|
it.transactions.map { list -> list.toPersistentList() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.stateIn(
|
.stateIn(
|
||||||
|
@ -331,25 +327,14 @@ private fun Synchronizer.toWalletSnapshot() =
|
||||||
orchardBalances, // 2
|
orchardBalances, // 2
|
||||||
saplingBalances, // 3
|
saplingBalances, // 3
|
||||||
transparentBalances, // 4
|
transparentBalances, // 4
|
||||||
pendingTransactions.distinctUntilChanged(), // 5
|
progress, // 5
|
||||||
progress, // 6
|
toCommonError() // 6
|
||||||
toCommonError() // 7
|
|
||||||
) { flows ->
|
) { flows ->
|
||||||
val pendingCount = (flows[5] as List<*>)
|
|
||||||
.filterIsInstance(PendingTransaction::class.java)
|
|
||||||
.count {
|
|
||||||
it.isSubmitSuccess() && !it.isMined()
|
|
||||||
}
|
|
||||||
val orchardBalance = flows[2] as WalletBalance?
|
val orchardBalance = flows[2] as WalletBalance?
|
||||||
val saplingBalance = flows[3] as WalletBalance?
|
val saplingBalance = flows[3] as WalletBalance?
|
||||||
val transparentBalance = flows[4] as WalletBalance?
|
val transparentBalance = flows[4] as WalletBalance?
|
||||||
|
|
||||||
val progressPercentDecimal = (flows[6] as Int).let { value ->
|
val progressPercentDecimal = flows[5] as PercentDecimal
|
||||||
if (value > PercentDecimal.MAX || value < PercentDecimal.MIN) {
|
|
||||||
PercentDecimal.ZERO_PERCENT
|
|
||||||
}
|
|
||||||
PercentDecimal((flows[6] as Int) / 100f)
|
|
||||||
}
|
|
||||||
|
|
||||||
WalletSnapshot(
|
WalletSnapshot(
|
||||||
flows[0] as Synchronizer.Status,
|
flows[0] as Synchronizer.Status,
|
||||||
|
@ -357,23 +342,7 @@ private fun Synchronizer.toWalletSnapshot() =
|
||||||
orchardBalance ?: WalletBalance(Zatoshi(0), Zatoshi(0)),
|
orchardBalance ?: WalletBalance(Zatoshi(0), Zatoshi(0)),
|
||||||
saplingBalance ?: WalletBalance(Zatoshi(0), Zatoshi(0)),
|
saplingBalance ?: WalletBalance(Zatoshi(0), Zatoshi(0)),
|
||||||
transparentBalance ?: WalletBalance(Zatoshi(0), Zatoshi(0)),
|
transparentBalance ?: WalletBalance(Zatoshi(0), Zatoshi(0)),
|
||||||
pendingCount,
|
|
||||||
progressPercentDecimal,
|
progressPercentDecimal,
|
||||||
flows[7] as SynchronizerError?
|
flows[6] as SynchronizerError?
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Synchronizer.toTransactions(): Flow<ImmutableList<CommonTransaction>> =
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
|
|
|
@ -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.UnifiedSpendingKey
|
||||||
import cash.z.ecc.android.sdk.model.Zatoshi
|
import cash.z.ecc.android.sdk.model.Zatoshi
|
||||||
import cash.z.ecc.android.sdk.model.ZecSend
|
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 cash.z.ecc.sdk.send
|
||||||
import co.electriccoin.zcash.spackle.Twig
|
import co.electriccoin.zcash.spackle.Twig
|
||||||
import co.electriccoin.zcash.ui.MainActivity
|
import co.electriccoin.zcash.ui.MainActivity
|
||||||
|
@ -85,7 +83,9 @@ internal fun WrapSend(
|
||||||
when (sendStage) {
|
when (sendStage) {
|
||||||
SendStage.Form -> goBack()
|
SendStage.Form -> goBack()
|
||||||
SendStage.Confirmation -> setSendStage(SendStage.Form)
|
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.SendFailure -> setSendStage(SendStage.Form)
|
||||||
SendStage.SendSuccessful -> goBack()
|
SendStage.SendSuccessful -> goBack()
|
||||||
}
|
}
|
||||||
|
@ -108,21 +108,16 @@ internal fun WrapSend(
|
||||||
onBack = onBackAction,
|
onBack = onBackAction,
|
||||||
onCreateAndSend = {
|
onCreateAndSend = {
|
||||||
scope.launch {
|
scope.launch {
|
||||||
synchronizer.send(spendingKey, it).collect {
|
Twig.debug { "Sending transaction" }
|
||||||
Twig.debug { "Sending transaction id: ${it.id}" }
|
runCatching { synchronizer.send(spendingKey, it) }
|
||||||
|
.onSuccess {
|
||||||
if (it.isSubmitSuccess()) {
|
|
||||||
setSendStage(SendStage.SendSuccessful)
|
setSendStage(SendStage.SendSuccessful)
|
||||||
Twig.debug {
|
Twig.debug { "Transaction id:$it submitted successfully" }
|
||||||
"Transaction id:${it.id} submitted successfully at ${it.createTime} with " +
|
|
||||||
"${it.submitAttempts} attempts."
|
|
||||||
}
|
}
|
||||||
} else if (it.isFailedSubmit()) {
|
.onFailure {
|
||||||
Twig.debug { "Transaction id:${it.id} submission failed with: ${it.errorMessage}." }
|
Twig.debug { "Transaction submission failed with: $it." }
|
||||||
setSendStage(SendStage.SendFailure)
|
setSendStage(SendStage.SendFailure)
|
||||||
}
|
}
|
||||||
// All other states of Pending transaction mean waiting for one of the states above
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onQrScannerOpen = goToQrScanner,
|
onQrScannerOpen = goToQrScanner,
|
||||||
|
|
|
@ -10,6 +10,7 @@ import androidx.work.PeriodicWorkRequestBuilder
|
||||||
import androidx.work.WorkerParameters
|
import androidx.work.WorkerParameters
|
||||||
import cash.z.ecc.android.sdk.Synchronizer
|
import cash.z.ecc.android.sdk.Synchronizer
|
||||||
import cash.z.ecc.android.sdk.WalletCoordinator
|
import cash.z.ecc.android.sdk.WalletCoordinator
|
||||||
|
import cash.z.ecc.android.sdk.model.PercentDecimal
|
||||||
import co.electriccoin.zcash.global.getInstance
|
import co.electriccoin.zcash.global.getInstance
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
import kotlinx.coroutines.flow.collect
|
import kotlinx.coroutines.flow.collect
|
||||||
|
@ -35,7 +36,7 @@ class SyncWorker(context: Context, workerParameters: WorkerParameters) : Corouti
|
||||||
} ?: emptyFlow()
|
} ?: emptyFlow()
|
||||||
}
|
}
|
||||||
.takeWhile {
|
.takeWhile {
|
||||||
it.status != Synchronizer.Status.DISCONNECTED && it.progress < ONE_HUNDRED_PERCENT
|
it.status != Synchronizer.Status.DISCONNECTED && it.progress.isLessThanHundredPercent()
|
||||||
}
|
}
|
||||||
.collect()
|
.collect()
|
||||||
|
|
||||||
|
@ -43,7 +44,6 @@ class SyncWorker(context: Context, workerParameters: WorkerParameters) : Corouti
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val ONE_HUNDRED_PERCENT = 100
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* There may be better periods; we have not optimized for this yet.
|
* 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)
|
||||||
|
|
Loading…
Reference in New Issue