From a357afe09a0767914abd4072c9afd9bca2c0f280 Mon Sep 17 00:00:00 2001 From: Kevin Gorham Date: Fri, 31 Jan 2020 11:32:36 -0500 Subject: [PATCH] General fixes and cleanup. - Allow tiny transaction amounts and improve display - show toAddress and memo when we know it - Bugfix: self transactions are not duplicated - Turned Developer logs back on and cleaned up output a bit --- app/build.gradle | 15 ++++++- .../android/ui/detail/TransactionAdapter.kt | 2 + .../ui/detail/TransactionViewHolder.kt | 11 ++++- .../z/ecc/android/ui/home/HomeFragment.kt | 16 +------ .../z/ecc/android/ui/home/HomeViewModel.kt | 6 --- .../z/ecc/android/ui/home/MagicSnakeLoader.kt | 42 +------------------ .../z/ecc/android/ui/send/SendViewModel.kt | 4 +- .../android/ui/setup/WalletSetupViewModel.kt | 2 +- .../main/res/drawable/background_banner.xml | 2 +- app/src/main/res/values/colors.xml | 1 + gradle.properties | 25 +++++------ 11 files changed, 42 insertions(+), 84 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 3a50c46..5a9d467 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -11,7 +11,7 @@ apply plugin: 'com.google.firebase.firebase-perf' archivesBaseName = 'zcash-android-wallet' group = 'cash.z.ecc.android' -version = '1.0.0-alpha11' +version = '1.0.0-dev12' android { compileSdkVersion Deps.compileSdkVersion @@ -21,7 +21,7 @@ android { applicationId 'cash.z.ecc.android' minSdkVersion Deps.minSdkVersion targetSdkVersion Deps.targetSdkVersion - versionCode = 1_00_00_011 + versionCode = 1_00_00_112 // last digits are alpha(0XX) beta(2XX) rc(4XX) release(8XX). Ex: 1_08_04_401 is an release candidate build of version 1.8.4 and 1_08_04_800 would be the final release. versionName = "$version" testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' @@ -43,6 +43,17 @@ android { matchingFallbacks = ['zcashmainnet', 'release'] } } + + // TODO: delete this test code + variantFilter { variant -> + def names = variant.flavors*.name + // To check for a certain build type, use variant.buildType.name == "" + if (names.contains("zcashtestnet") || names.contains("Zcashtestnet") || variant.buildType.name == "release") { + // Gradle ignores any variants that satisfy the conditions above. + setIgnore(true) + } + } + buildTypes { release { minifyEnabled true diff --git a/app/src/main/java/cash/z/ecc/android/ui/detail/TransactionAdapter.kt b/app/src/main/java/cash/z/ecc/android/ui/detail/TransactionAdapter.kt index 93c8c6a..22aa563 100644 --- a/app/src/main/java/cash/z/ecc/android/ui/detail/TransactionAdapter.kt +++ b/app/src/main/java/cash/z/ecc/android/ui/detail/TransactionAdapter.kt @@ -14,6 +14,8 @@ class TransactionAdapter : oldItem: T, newItem: T ) = oldItem.minedHeight == newItem.minedHeight && oldItem.noteId == newItem.noteId + // bugfix: distinguish between self-transactions so they don't overwrite each other in the UI // TODO confirm that this is working, as intended + && ((oldItem.raw == null && newItem.raw == null) || (oldItem.raw != null && newItem.raw != null && oldItem.raw!!.contentEquals(newItem.raw!!))) override fun areContentsTheSame( oldItem: T, diff --git a/app/src/main/java/cash/z/ecc/android/ui/detail/TransactionViewHolder.kt b/app/src/main/java/cash/z/ecc/android/ui/detail/TransactionViewHolder.kt index 3dbaa22..2b824e5 100644 --- a/app/src/main/java/cash/z/ecc/android/ui/detail/TransactionViewHolder.kt +++ b/app/src/main/java/cash/z/ecc/android/ui/detail/TransactionViewHolder.kt @@ -8,6 +8,7 @@ import cash.z.ecc.android.ext.goneIf import cash.z.ecc.android.ext.toAppColor import cash.z.ecc.android.ui.MainActivity import cash.z.wallet.sdk.entity.ConfirmedTransaction +import cash.z.wallet.sdk.ext.ZcashSdk import cash.z.wallet.sdk.ext.convertZatoshiToZecString import cash.z.wallet.sdk.ext.isShielded import cash.z.wallet.sdk.ext.toAbbreviatedAddress @@ -60,8 +61,13 @@ class TransactionViewHolder(itemView: View) : Recycler lineTwo = "Unknown" } } + + // sanitize amount + if (value < ZcashSdk.MINERS_FEE_ZATOSHI) amount = "< 0.001" + else if (amount.length > 8) amount = "tap to view" } + topText.text = lineOne bottomText.text = lineTwo amountText.text = amount @@ -74,7 +80,10 @@ class TransactionViewHolder(itemView: View) : Recycler private fun onTransactionClicked(transaction: ConfirmedTransaction) { val txId = transaction.rawTransactionId.toTxId() val detailsMessage: String = "Zatoshi amount: ${transaction.value}\n\n" + - "Transaction: $txId" + "Transaction: $txId" + + "${if (transaction.toAddress != null) "\nto: ${transaction.toAddress}" else ""}" + + "${if (transaction.memo != null) "\nmemo: ${transaction.toAddress}" else ""}" + MaterialAlertDialogBuilder(itemView.context) .setMessage(detailsMessage) .setTitle("Transaction Details") diff --git a/app/src/main/java/cash/z/ecc/android/ui/home/HomeFragment.kt b/app/src/main/java/cash/z/ecc/android/ui/home/HomeFragment.kt index ae22792..6fc2f1f 100644 --- a/app/src/main/java/cash/z/ecc/android/ui/home/HomeFragment.kt +++ b/app/src/main/java/cash/z/ecc/android/ui/home/HomeFragment.kt @@ -137,9 +137,7 @@ class HomeFragment : BaseFragment() { super.onResume() twig("HomeFragment.onResume resumeScope.isActive: ${resumedScope.isActive} $resumedScope") viewModel.initializeMaybe() -twig("onResume (A)") onClearAmount() -twig("onResume (B)") viewModel.uiModels.scanReduce { old, new -> onModelUpdated(old, new) new @@ -149,18 +147,14 @@ twig("onResume (B)") twig("exception while processing uiModels $e") throw e }.launchIn(resumedScope) -twig("onResume (C)") // TODO: see if there is a better way to trigger a refresh of the uiModel on resume // the latest one should just be in the viewmodel and we should just "resubscribe" // but for some reason, this doesn't always happen, which kind of defeats the purpose // of having a cold stream in the view model resumedScope.launch { -twig("onResume (pre-fresh)") viewModel.refreshBalance() -twig("onResume (post-fresh)") } -twig("onResume (D)") } override fun onSaveInstanceState(outState: Bundle) { @@ -280,22 +274,14 @@ twig("onResume (D)") twig("onModelUpdated: $new") if (binding.lottieButtonLoading.visibility != View.VISIBLE) binding.lottieButtonLoading.visibility = View.VISIBLE uiModel = new -twig("onModelUpdated (A)") if (old?.pendingSend != new.pendingSend) { -twig("onModelUpdated (B)") setSendAmount(new.pendingSend) -twig("onModelUpdated (C)") } -twig("onModelUpdated (D)") // TODO: handle stopped and disconnected flows setProgress(uiModel) // TODO: we may not need to separate anymore -twig("onModelUpdated (E)") // if (new.status = SYNCING) onSyncing(new) else onSynced(new) if (new.status == SYNCED) onSynced(new) else onSyncing(new) -twig("onModelUpdated (F)") setSendEnabled(new.isSendEnabled) -twig("onModelUpdated (G) sendEnabled? ${new.isSendEnabled}") - twig("DONE onModelUpdated") } private fun onSyncing(uiModel: HomeViewModel.UiModel) { @@ -359,7 +345,7 @@ twig("onModelUpdated (G) sendEnabled? ${new.isSendEnabled}") // enum class BannerAction(val action: String) { - FUND_NOW("Fund Now"), + FUND_NOW(""), CANCEL("Cancel"), NONE(""), CLEAR("clear"); diff --git a/app/src/main/java/cash/z/ecc/android/ui/home/HomeViewModel.kt b/app/src/main/java/cash/z/ecc/android/ui/home/HomeViewModel.kt index d354c4e..84a35d9 100644 --- a/app/src/main/java/cash/z/ecc/android/ui/home/HomeViewModel.kt +++ b/app/src/main/java/cash/z/ecc/android/ui/home/HomeViewModel.kt @@ -96,13 +96,10 @@ class HomeViewModel @Inject constructor() : ViewModel() { if (lastDownloadRange.isEmpty()) { 100 } else { - twig("NUMERATOR: $lastDownloadedHeight - ${lastDownloadRange.first} + 1 = ${lastDownloadedHeight - lastDownloadRange.first + 1} block(s) downloaded") - twig("DENOMINATOR: ${lastDownloadRange.last} - ${lastDownloadRange.first} + 1 = ${lastDownloadRange.last - lastDownloadRange.first + 1} block(s) to download") val progress = (((lastDownloadedHeight - lastDownloadRange.first + 1).coerceAtLeast(0).toFloat() / (lastDownloadRange.last - lastDownloadRange.first + 1)) * 100.0f).coerceAtMost( 100.0f ).roundToInt() - twig("RESULT: $progress") progress } } @@ -112,10 +109,7 @@ class HomeViewModel @Inject constructor() : ViewModel() { if (lastScanRange.isEmpty()) { 100 } else { - twig("NUMERATOR: ${lastScannedHeight - lastScanRange.first + 1} block(s) scanned") - twig("DENOMINATOR: ${lastScanRange.last - lastScanRange.first + 1} block(s) to scan") val progress = (((lastScannedHeight - lastScanRange.first + 1).coerceAtLeast(0).toFloat() / (lastScanRange.last - lastScanRange.first + 1)) * 100.0f).coerceAtMost(100.0f).roundToInt() - twig("RESULT: $progress") progress } } diff --git a/app/src/main/java/cash/z/ecc/android/ui/home/MagicSnakeLoader.kt b/app/src/main/java/cash/z/ecc/android/ui/home/MagicSnakeLoader.kt index c9e7908..2cb2f56 100644 --- a/app/src/main/java/cash/z/ecc/android/ui/home/MagicSnakeLoader.kt +++ b/app/src/main/java/cash/z/ecc/android/ui/home/MagicSnakeLoader.kt @@ -15,9 +15,7 @@ class MagicSnakeLoader( var isSynced: Boolean = false set(value) { - twig("ZZZ isSynced=$value isStarted=$isStarted") if (value && !isStarted) { - twig("ZZZ isSynced=$value TURBO sync") lottie.progress = 1.0f field = value return @@ -25,19 +23,16 @@ class MagicSnakeLoader( // it is started but it hadn't reached the synced state yet if (value && !field) { - twig("ZZZ synced was $field but now is $value so playing to completion since we are now synced") field = value playToCompletion() } else { field = value - twig("ZZZ isSynced=$value and lottie.progress=${lottie.progress}") } } var scanProgress: Int = 0 set(value) { field = value - twig("ZZZ scanProgress=$value") if (value > 0) { startMaybe() onScanUpdated() @@ -47,7 +42,6 @@ class MagicSnakeLoader( var downloadProgress: Int = 0 set(value) { field = value - twig("ZZZ downloadProgress=$value") if (value > 0) startMaybe() } @@ -56,25 +50,12 @@ class MagicSnakeLoader( if (!isSynced && !isStarted) lottie.postDelayed({ // after some delay, if we're still not synced then we better start animating (unless we already are)! if (!isSynced && isPaused) { - twig("ZZZ yes start!") lottie.resumeAnimation() isPaused = false isStarted = true - } else { - twig("ZZZ I would have started but we're already synced!") } - }, 200L).also { twig("ZZZ startMaybe???") } + }, 200L) } -// set(value) { -// field = value -// if (value in 1..99 && isStopped) { -// lottie.playAnimation() -// isStopped = false -// } else if (value >= 100) { -// isStopped = true -// } -// } - private val isDownloading get() = downloadProgress in 1..99 private val isScanning get() = scanProgress in 1..99 @@ -83,25 +64,11 @@ class MagicSnakeLoader( lottie.addAnimatorUpdateListener(this) } - // downloading = true -// lottieAnimationView.playAnimation() -// lottieAnimationView.addAnimatorUpdateListener { valueAnimator -> -// // Set animation progress -// val progress = (valueAnimator.animatedValue as Float * 100).toInt() -// progressTv.text = "Progress: $progress%" -// -// if (downloading && progress >= 40) { -// lottieAnimationView.progress = 0f -// } -// } - override fun onAnimationUpdate(animation: ValueAnimator) { if (isSynced || isPaused) { // playToCompletion() return } - twig("ZZZ") - twig("ZZZ\t\tonAnimationUpdate(${animation.animatedValue})") // if we are scanning, then set the animation progress, based on the scan progress // if we're not scanning, then we're looping @@ -112,7 +79,6 @@ class MagicSnakeLoader( private val acceptablePauseFrames = arrayOf(33,34,67,68,99) private fun applyScanProgress(frame: Int) { - twig("ZZZ applyScanProgress($frame) : isPaused=$isPaused isStarted=$isStarted min=${lottie.minFrame} max=${lottie.maxFrame}") // don't hardcode the progress until the loop animation has completed, cleanly if (isPaused) { onScanUpdated() @@ -126,7 +92,6 @@ class MagicSnakeLoader( } private fun onScanUpdated() { - twig("ZZZ onScanUpdated : isPaused=$isPaused") if (isSynced) { // playToCompletion() return @@ -137,7 +102,6 @@ class MagicSnakeLoader( val scanRange = scanningEndFrame - scanningStartFrame val scanRangeProgress = scanProgress.toFloat() / 100.0f * scanRange.toFloat() lottie.progress = (scanningStartFrame.toFloat() + scanRangeProgress) / totalFrames - twig("ZZZ onScanUpdated : scanRange=$scanRange scanRangeProgress=$scanRangeProgress lottie.progress=${(scanningStartFrame.toFloat() + scanRangeProgress)}/$totalFrames=${lottie.progress}") } } @@ -160,17 +124,14 @@ class MagicSnakeLoader( } private fun allowLoop(frame: Int) { - twig("ZZZ allowLoop($frame) : isPaused=$isPaused") unpause() if (frame >= scanningStartFrame) { - twig("ZZZ resetting to 0f (LOOPING)") lottie.progress = 0f } } fun unpause() { if (isPaused) { - twig("ZZZ unpausing") lottie.resumeAnimation() isPaused = false } @@ -178,7 +139,6 @@ class MagicSnakeLoader( fun pause() { if (!isPaused) { - twig("ZZZ pausing") lottie.pauseAnimation() isPaused = true } diff --git a/app/src/main/java/cash/z/ecc/android/ui/send/SendViewModel.kt b/app/src/main/java/cash/z/ecc/android/ui/send/SendViewModel.kt index 114afe5..88bb146 100644 --- a/app/src/main/java/cash/z/ecc/android/ui/send/SendViewModel.kt +++ b/app/src/main/java/cash/z/ecc/android/ui/send/SendViewModel.kt @@ -81,8 +81,8 @@ class SendViewModel @Inject constructor() : ViewModel() { synchronizer.validateAddress(toAddress).isNotValid -> { emit("Please enter a valid address") } - zatoshiAmount < ZcashSdk.MINERS_FEE_ZATOSHI -> { - emit("Too little! Please enter at least 0.0001") + zatoshiAmount <= 1 -> { + emit("Too little! Please enter at least 1 Zatoshi.") } maxZatoshi != null && zatoshiAmount > maxZatoshi -> { emit( "Too much! Please enter no more than ${maxZatoshi.convertZatoshiToZecString(8)}") diff --git a/app/src/main/java/cash/z/ecc/android/ui/setup/WalletSetupViewModel.kt b/app/src/main/java/cash/z/ecc/android/ui/setup/WalletSetupViewModel.kt index c1db96a..3e5ac8f 100644 --- a/app/src/main/java/cash/z/ecc/android/ui/setup/WalletSetupViewModel.kt +++ b/app/src/main/java/cash/z/ecc/android/ui/setup/WalletSetupViewModel.kt @@ -62,7 +62,7 @@ class WalletSetupViewModel @Inject constructor() : ViewModel() { } suspend fun importWallet(seedPhrase: String, birthdayHeight: Int): Initializer { - twig("Importing wallet") + twig("Importing wallet. Requested birthday: $birthdayHeight") return ZcashWalletApp.component.initializerSubcomponent().create(Initializer.DefaultBirthdayStore(ZcashWalletApp.instance, birthdayHeight)).run { initializer().apply { import(importWallet(seedPhrase.toCharArray()), birthdayStore().getBirthday()) diff --git a/app/src/main/res/drawable/background_banner.xml b/app/src/main/res/drawable/background_banner.xml index 7742bd9..4d768e9 100644 --- a/app/src/main/res/drawable/background_banner.xml +++ b/app/src/main/res/drawable/background_banner.xml @@ -2,6 +2,6 @@ - + \ No newline at end of file diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index cbbbb10..7a0129d 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -58,6 +58,7 @@ but have a more useful name for use in code --> @color/zcashBlack_dark + #282828 @color/zcashBlack_87 #1FBB666A @color/text_light diff --git a/gradle.properties b/gradle.properties index dab4578..cce6d42 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,23 +1,18 @@ -# Project-wide Gradle settings. -# IDE (e.g. Android Studio) users: -# Gradle settings configured through the IDE *will override* -# any settings specified in this file. -# For more details on how to configure your build environment visit +## For more details on how to configure your build environment visit # http://www.gradle.org/docs/current/userguide/build_environment.html +# # Specifies the JVM arguments used for the daemon process. # The setting is particularly useful for tweaking memory settings. -org.gradle.jvmargs=-Xmx1536m +# Default value: -Xmx1024m -XX:MaxPermSize=256m +# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 +# # When configured, Gradle will run in incubating parallel mode. # This option should only be used with decoupled projects. More details, visit # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # org.gradle.parallel=true -# AndroidX package structure to make it clearer which packages are bundled with the -# Android operating system, and which are packaged with your app's APK -# https://developer.android.com/topic/libraries/support-library/androidx-rn -android.useAndroidX=true -# Automatically convert third-party libraries to use AndroidX -android.enableJetifier=true -# Kotlin code style for this project: "official" or "obsolete": +#Wed Jan 29 09:45:08 EST 2020 kotlin.code.style=official - -dagger.fastInit=enabled \ No newline at end of file +android.enableJetifier=true +org.gradle.jvmargs=-Xmx2048M -Dkotlin.daemon.jvm.options\="-Xmx2048M" +android.useAndroidX=true +dagger.fastInit=enabled