Updated to the newly refactored (and published) SDK.

This commit is contained in:
Kevin Gorham 2020-06-10 07:49:38 -04:00
parent 901db38ee0
commit 4c4ef46efe
No known key found for this signature in database
GPG Key ID: CCA55602DF49FC38
39 changed files with 347 additions and 218 deletions

View File

@ -11,9 +11,10 @@ apply plugin: 'com.google.firebase.firebase-perf'
archivesBaseName = 'zcash-android-wallet'
group = 'cash.z.ecc.android'
version = '1.0.0-alpha25'
version = '1.0.0-alpha28'
android {
ndkVersion "21.1.6352462"
compileSdkVersion Deps.compileSdkVersion
buildToolsVersion Deps.buildToolsVersion
viewBinding.enabled = true
@ -27,7 +28,6 @@ android {
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
testInstrumentationRunnerArguments clearPackageData: 'true'
multiDexEnabled true
// manifestPlaceholders = [rollbarToken: properties["rollbarToken"]]
}
flavorDimensions 'network'
productFlavors {
@ -112,30 +112,40 @@ dependencies {
implementation project(':feedback')
implementation project(':mnemonic')
implementation project(':lockbox')
implementation project(':sdk')
implementation project(':chipsinputlayout')
// Zcash
implementation 'com.github.zcash:zcash-android-wallet-plugins:1.0.0'
implementation Deps.Zcash.ANDROID_WALLET_PLUGINS
zcashtestnetImplementation Deps.Zcash.Sdk.TESTNET
zcashmainnetImplementation Deps.Zcash.Sdk.MAINNET
// Kotlin
implementation Deps.Kotlin.STDLIB
// Android
implementation Deps.AndroidX.ANNOTATION
implementation Deps.AndroidX.APPCOMPAT
implementation Deps.AndroidX.CORE_KTX
implementation Deps.AndroidX.CONSTRAINT_LAYOUT
implementation Deps.AndroidX.Lifecycle.LIFECYCLE_RUNTIME_KTX
implementation Deps.AndroidX.CORE_KTX
implementation Deps.AndroidX.FRAGMENT_KTX
implementation Deps.AndroidX.LEGACY
implementation Deps.AndroidX.PAGING
implementation Deps.AndroidX.CameraX.CAMERA2
implementation Deps.AndroidX.CameraX.CORE
implementation Deps.AndroidX.CameraX.LIFECYCLE
implementation Deps.AndroidX.CameraX.View.EXT
implementation Deps.AndroidX.CameraX.View.VIEW
implementation Deps.AndroidX.Lifecycle.LIFECYCLE_EXTENSIONS
implementation Deps.AndroidX.Lifecycle.LIFECYCLE_RUNTIME_KTX
implementation Deps.AndroidX.Navigation.FRAGMENT_KTX
implementation Deps.AndroidX.Navigation.UI_KTX
implementation "androidx.room:room-ktx:2.2.3"
implementation "androidx.paging:paging-runtime-ktx:2.1.1"
implementation 'com.google.guava:guava:27.0.1-android'
kapt "androidx.room:room-compiler:2.2.3"
implementation Deps.AndroidX.Room.ROOM_KTX
kapt Deps.AndroidX.Room.ROOM_COMPILER
// Google
implementation Deps.Google.GUAVA
implementation Deps.Google.MATERIAL
implementation Deps.Google.ML_VISION // QR Scanner
// Dagger
implementation Deps.Dagger.ANDROID_SUPPORT
@ -143,44 +153,26 @@ dependencies {
kapt Deps.Dagger.COMPILER
// grpc-java
implementation "io.grpc:grpc-okhttp:1.25.0"
implementation "io.grpc:grpc-android:1.25.0"
implementation "io.grpc:grpc-protobuf-lite:1.25.0"
implementation "io.grpc:grpc-stub:1.25.0"
implementation 'javax.annotation:javax.annotation-api:1.3.2'
// solves error: Duplicate class com.google.common.util.concurrent.ListenableFuture found in modules jetified-guava-26.0-android.jar (com.google.guava:guava:26.0-android) and listenablefuture-1.0.jar (com.google.guava:listenablefuture:1.0)
// per this recommendation from Chris Povirk, given guava's decision to split ListenableFuture away from Guava: https://groups.google.com/d/msg/guava-discuss/GghaKwusjcY/bCIAKfzOEwAJ
implementation 'com.google.guava:guava:27.0.1-android'
implementation Deps.Grpc.ANDROID
implementation Deps.Grpc.OKHTTP
implementation Deps.Grpc.PROTOBUG
implementation Deps.Grpc.STUB
implementation Deps.JavaX.JAVA_ANNOTATION
// Analytics
implementation 'com.mixpanel.android:mixpanel-android:5.6.3'
implementation 'com.google.firebase:firebase-analytics:17.2.2'
implementation 'com.crashlytics.sdk.android:crashlytics:2.10.1'
implementation 'com.crashlytics.sdk.android:crashlytics-ndk:2.1.1'
implementation 'com.google.firebase:firebase-perf:19.0.5'
// QR Scanning
implementation 'com.google.firebase:firebase-ml-vision:24.0.1'
implementation 'androidx.camera:camera-core:1.0.0-alpha10'
implementation 'androidx.camera:camera-camera2:1.0.0-alpha10'
implementation "androidx.camera:camera-view:1.0.0-alpha07"
implementation "androidx.camera:camera-extensions:1.0.0-alpha07"
implementation "androidx.camera:camera-lifecycle:1.0.0-alpha10"
// Analytics (for dogfooding/crash-reporting/feedback only on internal team builds)
implementation Deps.Analytics.CRASHLYTICS
implementation Deps.Analytics.CRASHLYTICS_NDK
implementation Deps.Analytics.FIREBASE
implementation Deps.Analytics.FIREBASE_PERF
implementation Deps.Analytics.MIXPANEL
// Misc.
implementation 'com.airbnb.android:lottie:3.1.0'
implementation 'com.facebook.stetho:stetho:1.5.1'
// check for build errors at https://jitpack.io/com/github/gmale/chips-input-layout/<version>/build.log
// implementation 'com.github.gmale:chips-input-layout:4750760a7222bc04ca48266b387456d2b03541a7'
implementation 'androidx.annotation:annotation:1.1.0'
implementation Deps.Misc.LOTTIE
// Tests
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
testImplementation Deps.Test.COROUTINES_TEST
testImplementation Deps.Test.JUNIT
testImplementation "com.nhaarman.mockitokotlin2:mockito-kotlin:2.2.0"
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.3.3'
testImplementation Deps.Test.MOKITO
androidTestImplementation Deps.Test.Android.JUNIT
androidTestImplementation Deps.Test.Android.ESPRESSO
}

View File

@ -5,7 +5,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import cash.z.ecc.android.lockbox.LockBox
import cash.z.ecc.kotlin.mnemonic.Mnemonics
import cash.z.wallet.sdk.Initializer
import cash.z.ecc.android.sdk.Initializer
import okio.Buffer
import okio.GzipSink
import okio.Okio

View File

@ -8,10 +8,10 @@ import androidx.camera.core.CameraXConfig
import cash.z.ecc.android.di.component.AppComponent
import cash.z.ecc.android.di.component.DaggerAppComponent
import cash.z.ecc.android.feedback.FeedbackCoordinator
import cash.z.wallet.sdk.ext.SilentTwig
import cash.z.wallet.sdk.ext.TroubleshootingTwig
import cash.z.wallet.sdk.ext.Twig
import cash.z.wallet.sdk.ext.twig
import cash.z.ecc.android.sdk.ext.SilentTwig
import cash.z.ecc.android.sdk.ext.TroubleshootingTwig
import cash.z.ecc.android.sdk.ext.Twig
import cash.z.ecc.android.sdk.ext.twig
import kotlinx.coroutines.*
import javax.inject.Inject

View File

@ -4,7 +4,7 @@ import cash.z.ecc.android.ZcashWalletApp
import cash.z.ecc.android.di.annotation.ActivityScope
import cash.z.ecc.android.di.annotation.SynchronizerScope
import cash.z.ecc.android.di.module.InitializerModule
import cash.z.wallet.sdk.Initializer
import cash.z.ecc.android.sdk.Initializer
import dagger.BindsInstance
import dagger.Subcomponent

View File

@ -3,8 +3,8 @@ package cash.z.ecc.android.di.component
import androidx.lifecycle.ViewModelProvider
import cash.z.ecc.android.di.annotation.SynchronizerScope
import cash.z.ecc.android.di.module.SynchronizerModule
import cash.z.wallet.sdk.Initializer
import cash.z.wallet.sdk.Synchronizer
import cash.z.ecc.android.sdk.Initializer
import cash.z.ecc.android.sdk.Synchronizer
import dagger.BindsInstance
import dagger.Subcomponent
import javax.inject.Named

View File

@ -1,7 +1,7 @@
package cash.z.ecc.android.di.module
import android.content.Context
import cash.z.wallet.sdk.Initializer
import cash.z.ecc.android.sdk.Initializer
import dagger.Module
import dagger.Provides
import dagger.Reusable

View File

@ -2,8 +2,8 @@ package cash.z.ecc.android.di.module
import android.content.Context
import cash.z.ecc.android.di.annotation.SynchronizerScope
import cash.z.wallet.sdk.Initializer
import cash.z.wallet.sdk.Synchronizer
import cash.z.ecc.android.sdk.Initializer
import cash.z.ecc.android.sdk.Synchronizer
import dagger.Module
import dagger.Provides

View File

@ -0,0 +1,85 @@
package cash.z.ecc.android.ext
import android.app.ActivityManager
import android.app.Dialog
import android.content.Context
import android.content.Intent
import android.provider.Settings
import androidx.core.content.getSystemService
import com.google.android.material.dialog.MaterialAlertDialogBuilder
fun Context.showClearDataConfirmation(onDismiss: () -> Unit = {}, onCancel: () -> Unit = {}): Dialog {
return MaterialAlertDialogBuilder(this)
.setTitle("Nuke Wallet?")
.setMessage("WARNING: Potential Loss of Funds\n\nClearing all wallet data and can result in a loss of funds, if you cannot locate your correct seed phrase.\n\nPlease confirm that you have your 24-word seed phrase available before proceeding.")
.setCancelable(false)
.setPositiveButton("Cancel") { dialog, _ ->
dialog.dismiss()
onDismiss()
onCancel()
}
.setNegativeButton("Erase Wallet") { dialog, _ ->
dialog.dismiss()
onDismiss()
getSystemService<ActivityManager>()?.clearApplicationUserData()
}
.show()
}
fun Context.showUninitializedError(error: Throwable? = null, onDismiss: () -> Unit = {}): Dialog {
return MaterialAlertDialogBuilder(this)
.setTitle("Wallet Improperly Initialized")
.setMessage("This wallet has not been initialized correctly! Perhaps an error occurred during install.\n\nThis can be fixed with a reset. First, locate your backup seed phrase, then CLEAR DATA and reimport it.")
.setCancelable(false)
.setPositiveButton("Exit") { dialog, _ ->
dialog.dismiss()
onDismiss()
if (error != null) throw error
}
.setNegativeButton("Clear Data") { dialog, _ ->
showClearDataConfirmation(onDismiss, onCancel = {
// do not let the user back into the app because we cannot recover from this case
showUninitializedError(error, onDismiss)
})
}
.show()
}
fun Context.showScanFailure(error: Throwable?, onCancel: () -> Unit = {}, onDismiss: () -> Unit = {}): Dialog {
val message = if (error == null) {
"Unknown error"
} else {
"${error.message}${if (error.cause != null) "\n\nCaused by: ${error.cause}" else ""}"
}
return MaterialAlertDialogBuilder(this)
.setTitle("Scan Failure")
.setMessage(message)
.setCancelable(true)
.setPositiveButton("Retry") { d, _ ->
d.dismiss()
onDismiss()
}
.setNegativeButton("Ignore") { d, _ ->
d.dismiss()
onCancel()
onDismiss()
}
.show()
}
fun Context.showCriticalProcessorError(error: Throwable?, onRetry: () -> Unit = {}): Dialog {
return MaterialAlertDialogBuilder(this)
.setTitle("Processor Error")
.setMessage(error?.message ?: "Critical error while processing blocks!")
.setCancelable(false)
.setPositiveButton("Retry") { d, _ ->
d.dismiss()
onRetry()
}
.setNegativeButton("Exit") { dialog, _ ->
dialog.dismiss()
throw error ?: RuntimeException("Critical error while processing blocks and the user chose to exit.")
}
.show()
}

View File

@ -3,9 +3,9 @@ package cash.z.ecc.android.ext
import android.view.inputmethod.EditorInfo.IME_ACTION_DONE
import android.widget.EditText
import android.widget.TextView
import cash.z.wallet.sdk.ext.convertZecToZatoshi
import cash.z.wallet.sdk.ext.safelyConvertToBigDecimal
import cash.z.wallet.sdk.ext.twig
import cash.z.ecc.android.sdk.ext.convertZecToZatoshi
import cash.z.ecc.android.sdk.ext.safelyConvertToBigDecimal
import cash.z.ecc.android.sdk.ext.twig
fun EditText.onEditorActionDone(block: (EditText) -> Unit) {
this.setOnEditorActionListener { _, actionId, _ ->

View File

@ -38,10 +38,10 @@ import cash.z.ecc.android.feedback.Report.Error.NonFatal.Reorg
import cash.z.ecc.android.feedback.Report.NonUserAction.FEEDBACK_STOPPED
import cash.z.ecc.android.feedback.Report.NonUserAction.SYNC_START
import cash.z.ecc.android.feedback.Report.Tap.COPY_ADDRESS
import cash.z.wallet.sdk.Initializer
import cash.z.wallet.sdk.exception.CompactBlockProcessorException
import cash.z.wallet.sdk.ext.ZcashSdk
import cash.z.wallet.sdk.ext.twig
import cash.z.ecc.android.sdk.Initializer
import cash.z.ecc.android.sdk.exception.CompactBlockProcessorException
import cash.z.ecc.android.sdk.ext.ZcashSdk
import cash.z.ecc.android.sdk.ext.twig
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.snackbar.Snackbar
import kotlinx.coroutines.launch

View File

@ -5,7 +5,7 @@ import android.view.ViewGroup
import androidx.paging.PagedListAdapter
import androidx.recyclerview.widget.DiffUtil
import cash.z.ecc.android.R
import cash.z.wallet.sdk.entity.ConfirmedTransaction
import cash.z.ecc.android.sdk.db.entity.ConfirmedTransaction
class TransactionAdapter<T : ConfirmedTransaction> :
PagedListAdapter<T, TransactionViewHolder<T>>(

View File

@ -11,8 +11,8 @@ import cash.z.ecc.android.ui.MainActivity
import cash.z.ecc.android.ui.send.SendViewModel
import cash.z.ecc.android.ui.util.INCLUDE_MEMO_PREFIX
import cash.z.ecc.android.ui.util.toUtf8Memo
import cash.z.wallet.sdk.entity.ConfirmedTransaction
import cash.z.wallet.sdk.ext.*
import cash.z.ecc.android.sdk.db.entity.ConfirmedTransaction
import cash.z.ecc.android.sdk.ext.*
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import java.nio.charset.Charset
import java.text.SimpleDateFormat

View File

@ -15,12 +15,12 @@ import cash.z.ecc.android.ext.toColoredSpan
import cash.z.ecc.android.feedback.Report
import cash.z.ecc.android.feedback.Report.Tap.DETAIL_BACK
import cash.z.ecc.android.ui.base.BaseFragment
import cash.z.wallet.sdk.block.CompactBlockProcessor.WalletBalance
import cash.z.wallet.sdk.entity.ConfirmedTransaction
import cash.z.wallet.sdk.ext.collectWith
import cash.z.wallet.sdk.ext.convertZatoshiToZecString
import cash.z.wallet.sdk.ext.toAbbreviatedAddress
import cash.z.wallet.sdk.ext.twig
import cash.z.ecc.android.sdk.block.CompactBlockProcessor.WalletBalance
import cash.z.ecc.android.sdk.db.entity.ConfirmedTransaction
import cash.z.ecc.android.sdk.ext.collectWith
import cash.z.ecc.android.sdk.ext.convertZatoshiToZecString
import cash.z.ecc.android.sdk.ext.toAbbreviatedAddress
import cash.z.ecc.android.sdk.ext.twig
import kotlinx.coroutines.launch

View File

@ -1,8 +1,8 @@
package cash.z.ecc.android.ui.detail
import androidx.lifecycle.ViewModel
import cash.z.wallet.sdk.Synchronizer
import cash.z.wallet.sdk.ext.twig
import cash.z.ecc.android.sdk.Synchronizer
import cash.z.ecc.android.sdk.ext.twig
import javax.inject.Inject
class WalletDetailViewModel @Inject constructor() : ViewModel() {

View File

@ -18,13 +18,13 @@ import cash.z.ecc.android.ui.home.HomeFragment.BannerAction.*
import cash.z.ecc.android.ui.send.SendViewModel
import cash.z.ecc.android.ui.setup.WalletSetupViewModel
import cash.z.ecc.android.ui.setup.WalletSetupViewModel.WalletSetupState.NO_SEED
import cash.z.wallet.sdk.Synchronizer
import cash.z.wallet.sdk.Synchronizer.Status.*
import cash.z.wallet.sdk.block.CompactBlockProcessor
import cash.z.wallet.sdk.ext.convertZatoshiToZecString
import cash.z.wallet.sdk.ext.convertZecToZatoshi
import cash.z.wallet.sdk.ext.safelyConvertToBigDecimal
import cash.z.wallet.sdk.ext.twig
import cash.z.ecc.android.sdk.Synchronizer
import cash.z.ecc.android.sdk.Synchronizer.Status.*
import cash.z.ecc.android.sdk.block.CompactBlockProcessor
import cash.z.ecc.android.sdk.ext.convertZatoshiToZecString
import cash.z.ecc.android.sdk.ext.convertZecToZatoshi
import cash.z.ecc.android.sdk.ext.safelyConvertToBigDecimal
import cash.z.ecc.android.sdk.ext.twig
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.*

View File

@ -1,14 +1,14 @@
package cash.z.ecc.android.ui.home
import androidx.lifecycle.ViewModel
import cash.z.wallet.sdk.SdkSynchronizer
import cash.z.wallet.sdk.Synchronizer
import cash.z.wallet.sdk.Synchronizer.Status.*
import cash.z.wallet.sdk.block.CompactBlockProcessor
import cash.z.wallet.sdk.exception.RustLayerException
import cash.z.wallet.sdk.ext.ZcashSdk.MINERS_FEE_ZATOSHI
import cash.z.wallet.sdk.ext.ZcashSdk.ZATOSHI_PER_ZEC
import cash.z.wallet.sdk.ext.twig
import cash.z.ecc.android.sdk.SdkSynchronizer
import cash.z.ecc.android.sdk.Synchronizer
import cash.z.ecc.android.sdk.Synchronizer.Status.*
import cash.z.ecc.android.sdk.block.CompactBlockProcessor
import cash.z.ecc.android.sdk.exception.RustLayerException
import cash.z.ecc.android.sdk.ext.ZcashSdk.MINERS_FEE_ZATOSHI
import cash.z.ecc.android.sdk.ext.ZcashSdk.ZATOSHI_PER_ZEC
import cash.z.ecc.android.sdk.ext.twig
import kotlinx.coroutines.channels.ConflatedBroadcastChannel
import kotlinx.coroutines.flow.*
import javax.inject.Inject

View File

@ -1,7 +1,7 @@
package cash.z.ecc.android.ui.home
import android.animation.ValueAnimator
import cash.z.wallet.sdk.ext.twig
import cash.z.ecc.android.sdk.ext.twig
import com.airbnb.lottie.LottieAnimationView
class MagicSnakeLoader(

View File

@ -19,8 +19,8 @@ import cash.z.ecc.android.feedback.Report
import cash.z.ecc.android.feedback.Report.Funnel.UserFeedback
import cash.z.ecc.android.feedback.Report.Tap.*
import cash.z.ecc.android.ui.base.BaseFragment
import cash.z.wallet.sdk.ext.toAbbreviatedAddress
import cash.z.wallet.sdk.ext.twig
import cash.z.ecc.android.sdk.ext.toAbbreviatedAddress
import cash.z.ecc.android.sdk.ext.twig
import kotlinx.coroutines.launch
import okio.Okio
import java.io.File

View File

@ -1,8 +1,8 @@
package cash.z.ecc.android.ui.profile
import androidx.lifecycle.ViewModel
import cash.z.wallet.sdk.Synchronizer
import cash.z.wallet.sdk.ext.twig
import cash.z.ecc.android.sdk.Synchronizer
import cash.z.ecc.android.sdk.ext.twig
import javax.inject.Inject
class ProfileViewModel @Inject constructor() : ViewModel() {

View File

@ -13,8 +13,8 @@ import cash.z.ecc.android.ext.onClickNavTo
import cash.z.ecc.android.feedback.Report
import cash.z.ecc.android.feedback.Report.Tap.*
import cash.z.ecc.android.ui.base.BaseFragment
import cash.z.wallet.sdk.ext.toAbbreviatedAddress
import cash.z.wallet.sdk.ext.twig
import cash.z.ecc.android.sdk.ext.toAbbreviatedAddress
import cash.z.ecc.android.sdk.ext.twig
import kotlinx.coroutines.launch
import kotlin.math.roundToInt

View File

@ -1,8 +1,8 @@
package cash.z.ecc.android.ui.receive
import androidx.lifecycle.ViewModel
import cash.z.wallet.sdk.Synchronizer
import cash.z.wallet.sdk.ext.twig
import cash.z.ecc.android.sdk.Synchronizer
import cash.z.ecc.android.sdk.ext.twig
import javax.inject.Inject
class ReceiveViewModel @Inject constructor() : ViewModel() {

View File

@ -2,9 +2,9 @@ package cash.z.ecc.android.ui.scan
import androidx.camera.core.ImageAnalysis
import androidx.camera.core.ImageProxy
import cash.z.wallet.sdk.ext.retrySimple
import cash.z.wallet.sdk.ext.retryUpTo
import cash.z.wallet.sdk.ext.twig
import cash.z.ecc.android.sdk.ext.retrySimple
import cash.z.ecc.android.sdk.ext.retryUpTo
import cash.z.ecc.android.sdk.ext.twig
import com.google.android.gms.tasks.Task
import com.google.firebase.ml.vision.FirebaseVision
import com.google.firebase.ml.vision.barcode.FirebaseVisionBarcode

View File

@ -3,12 +3,10 @@ package cash.z.ecc.android.ui.scan
import android.content.Context
import android.content.pm.PackageManager
import android.os.Bundle
import android.util.DisplayMetrics
import android.view.LayoutInflater
import android.view.View
import androidx.camera.core.CameraSelector
import androidx.camera.core.ImageAnalysis
import androidx.camera.core.ImageProxy
import androidx.camera.core.Preview
import androidx.camera.core.*
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.core.content.ContextCompat
import cash.z.ecc.android.R
@ -18,11 +16,15 @@ import cash.z.ecc.android.di.viewmodel.viewModel
import cash.z.ecc.android.ext.onClickNavBack
import cash.z.ecc.android.ext.onClickNavTo
import cash.z.ecc.android.feedback.Report
import cash.z.ecc.android.feedback.Report.Tap.*
import cash.z.ecc.android.feedback.Report.Tap.SCAN_BACK
import cash.z.ecc.android.feedback.Report.Tap.SCAN_RECEIVE
import cash.z.ecc.android.sdk.ext.twig
import cash.z.ecc.android.ui.base.BaseFragment
import cash.z.ecc.android.ui.send.SendViewModel
import com.crashlytics.android.Crashlytics
import com.google.common.util.concurrent.ListenableFuture
import kotlinx.coroutines.launch
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
class ScanFragment : BaseFragment<FragmentScanBinding>() {
@ -33,11 +35,15 @@ class ScanFragment : BaseFragment<FragmentScanBinding>() {
private lateinit var cameraProviderFuture: ListenableFuture<ProcessCameraProvider>
private var cameraExecutor: ExecutorService? = null
override fun inflate(inflater: LayoutInflater): FragmentScanBinding =
FragmentScanBinding.inflate(inflater)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
if (cameraExecutor != null) cameraExecutor?.shutdown()
cameraExecutor = Executors.newSingleThreadExecutor()
binding.buttonReceive.onClickNavTo(R.id.action_nav_scan_to_nav_receive) { tapped(SCAN_RECEIVE) }
binding.backButtonHitArea.onClickNavBack() { tapped(SCAN_BACK) }
@ -56,26 +62,67 @@ class ScanFragment : BaseFragment<FragmentScanBinding>() {
}, ContextCompat.getMainExecutor(context))
}
override fun onDestroyView() {
super.onDestroyView()
cameraExecutor?.shutdown()
cameraExecutor = null
}
private fun bindPreview(cameraProvider: ProcessCameraProvider) {
Preview.Builder().setTargetName("Preview").build().let { preview ->
preview.setSurfaceProvider(binding.preview.previewSurfaceProvider)
// Most of the code here is adapted from: https://github.com/android/camera-samples/blob/master/CameraXBasic/app/src/main/java/com/android/example/cameraxbasic/fragments/CameraFragment.kt
// it's worth keeping tabs on that implementation because they keep making breaking changes to these APIs!
val cameraSelector = CameraSelector.Builder()
.requireLensFacing(CameraSelector.LENS_FACING_BACK)
.build()
// Get screen metrics used to setup camera for full screen resolution
val metrics = DisplayMetrics().also { binding.preview.display.getRealMetrics(it) }
val screenAspectRatio = aspectRatio(metrics.widthPixels, metrics.heightPixels)
val rotation = binding.preview.display.rotation
val imageAnalysis = ImageAnalysis.Builder()
.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
.build()
val preview =
Preview.Builder().setTargetName("Preview").setTargetAspectRatio(screenAspectRatio)
.setTargetRotation(rotation).build()
imageAnalysis.setAnalyzer(Executors.newSingleThreadExecutor(), QrAnalyzer { q, i ->
onQrScanned(q, i)
})
val cameraSelector = CameraSelector.Builder()
.requireLensFacing(CameraSelector.LENS_FACING_BACK)
.build()
val imageAnalysis = ImageAnalysis.Builder().setTargetAspectRatio(screenAspectRatio)
.setTargetRotation(rotation)
.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
.build()
imageAnalysis.setAnalyzer(cameraExecutor!!, QrAnalyzer { q, i ->
onQrScanned(q, i)
})
// Must unbind the use-cases before rebinding them
cameraProvider.unbindAll()
try {
cameraProvider.bindToLifecycle(this, cameraSelector, preview, imageAnalysis)
preview.setSurfaceProvider(binding.preview.createSurfaceProvider())
} catch (t: Throwable) {
// TODO: consider bubbling this up to the user
Crashlytics.logException(t)
twig("Error while opening the camera: $t")
}
}
/**
* Adapted from: https://github.com/android/camera-samples/blob/master/CameraXBasic/app/src/main/java/com/android/example/cameraxbasic/fragments/CameraFragment.kt#L350
*/
private fun aspectRatio(width: Int, height: Int): Int {
val previewRatio = kotlin.math.max(width, height).toDouble() / kotlin.math.min(
width,
height
)
if (kotlin.math.abs(previewRatio - (4.0 / 3.0))
<= kotlin.math.abs(previewRatio - (16.0 / 9.0))) {
return AspectRatio.RATIO_4_3
}
return AspectRatio.RATIO_16_9
}
private fun onQrScanned(qrContent: String, image: ImageProxy) {
resumedScope.launch {
if (viewModel.isNotValid(qrContent)) image.close() // continue scanning

View File

@ -1,8 +1,8 @@
package cash.z.ecc.android.ui.scan
import androidx.lifecycle.ViewModel
import cash.z.wallet.sdk.Synchronizer
import cash.z.wallet.sdk.ext.twig
import cash.z.ecc.android.sdk.Synchronizer
import cash.z.ecc.android.sdk.ext.twig
import javax.inject.Inject
class ScanViewModel @Inject constructor() : ViewModel() {

View File

@ -16,9 +16,10 @@ import cash.z.ecc.android.feedback.Report
import cash.z.ecc.android.feedback.Report.Funnel.Send
import cash.z.ecc.android.feedback.Report.Tap.*
import cash.z.ecc.android.ui.base.BaseFragment
import cash.z.wallet.sdk.Synchronizer
import cash.z.wallet.sdk.block.CompactBlockProcessor.WalletBalance
import cash.z.wallet.sdk.ext.*
import cash.z.ecc.android.sdk.Synchronizer
import cash.z.ecc.android.sdk.block.CompactBlockProcessor.WalletBalance
import cash.z.ecc.android.sdk.ext.*
import cash.z.ecc.android.sdk.validate.AddressType
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
@ -85,9 +86,9 @@ class SendAddressFragment : BaseFragment<FragmentSendAddressBinding>(),
private fun onAddressChanged(address: String) {
resumedScope.launch {
var type = when (sendViewModel.validateAddress(address)) {
is Synchronizer.AddressType.Transparent -> "This is a valid transparent address" to R.color.zcashGreen
is Synchronizer.AddressType.Shielded -> "This is a valid shielded address" to R.color.zcashGreen
is Synchronizer.AddressType.Invalid -> "This address appears to be invalid" to R.color.zcashRed
is AddressType.Transparent -> "This is a valid transparent address" to R.color.zcashGreen
is AddressType.Shielded -> "This is a valid shielded address" to R.color.zcashGreen
is AddressType.Invalid -> "This address appears to be invalid" to R.color.zcashRed
}
if (address == sendViewModel.synchronizer.getAddress()) type =
"Warning, this appears to be your address!" to R.color.zcashRed

View File

@ -13,8 +13,8 @@ import cash.z.ecc.android.feedback.Report
import cash.z.ecc.android.feedback.Report.Funnel.Send
import cash.z.ecc.android.feedback.Report.Tap.*
import cash.z.ecc.android.ui.base.BaseFragment
import cash.z.wallet.sdk.ext.toAbbreviatedAddress
import cash.z.wallet.sdk.ext.convertZatoshiToZecString
import cash.z.ecc.android.sdk.ext.toAbbreviatedAddress
import cash.z.ecc.android.sdk.ext.convertZatoshiToZecString
import kotlinx.coroutines.launch
class SendConfirmFragment : BaseFragment<FragmentSendConfirmBinding>() {

View File

@ -12,10 +12,10 @@ import cash.z.ecc.android.ext.goneIf
import cash.z.ecc.android.feedback.Report
import cash.z.ecc.android.feedback.Report.Tap.*
import cash.z.ecc.android.ui.base.BaseFragment
import cash.z.wallet.sdk.entity.*
import cash.z.wallet.sdk.ext.convertZatoshiToZecString
import cash.z.wallet.sdk.ext.toAbbreviatedAddress
import cash.z.wallet.sdk.ext.twig
import cash.z.ecc.android.sdk.db.entity.*
import cash.z.ecc.android.sdk.ext.convertZatoshiToZecString
import cash.z.ecc.android.sdk.ext.toAbbreviatedAddress
import cash.z.ecc.android.sdk.ext.twig
import com.crashlytics.android.Crashlytics
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.flow

View File

@ -14,12 +14,13 @@ import cash.z.ecc.android.feedback.Report.MetricType.*
import cash.z.ecc.android.lockbox.LockBox
import cash.z.ecc.android.ui.setup.WalletSetupViewModel
import cash.z.ecc.android.ui.util.INCLUDE_MEMO_PREFIX
import cash.z.wallet.sdk.Initializer
import cash.z.wallet.sdk.Synchronizer
import cash.z.wallet.sdk.entity.*
import cash.z.wallet.sdk.ext.ZcashSdk
import cash.z.wallet.sdk.ext.convertZatoshiToZecString
import cash.z.wallet.sdk.ext.twig
import cash.z.ecc.android.sdk.Initializer
import cash.z.ecc.android.sdk.Synchronizer
import cash.z.ecc.android.sdk.db.entity.*
import cash.z.ecc.android.sdk.ext.ZcashSdk
import cash.z.ecc.android.sdk.ext.convertZatoshiToZecString
import cash.z.ecc.android.sdk.ext.twig
import cash.z.ecc.android.sdk.validate.AddressType
import com.crashlytics.android.Crashlytics
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.flow.Flow
@ -94,7 +95,7 @@ class SendViewModel @Inject constructor() : ViewModel() {
}
}
suspend fun validateAddress(address: String): Synchronizer.AddressType =
suspend fun validateAddress(address: String): AddressType =
synchronizer.validateAddress(address)
fun validate(maxZatoshi: Long?) = flow<String?> {

View File

@ -18,7 +18,7 @@ import cash.z.ecc.android.feedback.Report.Tap.*
import cash.z.ecc.android.ui.base.BaseFragment
import cash.z.ecc.android.ui.setup.WalletSetupViewModel.WalletSetupState.SEED_WITHOUT_BACKUP
import cash.z.ecc.android.ui.setup.WalletSetupViewModel.WalletSetupState.SEED_WITH_BACKUP
import cash.z.wallet.sdk.Initializer
import cash.z.ecc.android.sdk.Initializer
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach

View File

@ -21,8 +21,8 @@ import cash.z.ecc.android.feedback.Report
import cash.z.ecc.android.feedback.Report.Funnel.Restore
import cash.z.ecc.android.feedback.Report.Tap.*
import cash.z.ecc.android.ui.base.BaseFragment
import cash.z.wallet.sdk.ext.ZcashSdk
import cash.z.wallet.sdk.ext.twig
import cash.z.ecc.android.sdk.ext.ZcashSdk
import cash.z.ecc.android.sdk.ext.twig
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.tylersuehr.chips.Chip
import com.tylersuehr.chips.ChipsAdapter

View File

@ -11,7 +11,7 @@ import cash.z.ecc.android.feedback.Report
import cash.z.ecc.android.feedback.Report.Funnel.Restore
import cash.z.ecc.android.ui.MainActivity
import cash.z.ecc.android.ui.setup.SeedWordChip
import cash.z.wallet.sdk.ext.twig
import cash.z.ecc.android.sdk.ext.twig
class SeedWordAdapter : ChipsAdapter {

View File

@ -8,11 +8,11 @@ import cash.z.ecc.android.feedback.measure
import cash.z.ecc.android.lockbox.LockBox
import cash.z.ecc.android.ui.setup.WalletSetupViewModel.WalletSetupState.*
import cash.z.ecc.kotlin.mnemonic.Mnemonics
import cash.z.wallet.sdk.Initializer
import cash.z.wallet.sdk.Initializer.DefaultBirthdayStore
import cash.z.wallet.sdk.Initializer.DefaultBirthdayStore.Companion.ImportedWalletBirthdayStore
import cash.z.wallet.sdk.Initializer.DefaultBirthdayStore.Companion.NewWalletBirthdayStore
import cash.z.wallet.sdk.ext.twig
import cash.z.ecc.android.sdk.Initializer
import cash.z.ecc.android.sdk.Initializer.DefaultBirthdayStore
import cash.z.ecc.android.sdk.Initializer.DefaultBirthdayStore.Companion.ImportedWalletBirthdayStore
import cash.z.ecc.android.sdk.Initializer.DefaultBirthdayStore.Companion.NewWalletBirthdayStore
import cash.z.ecc.android.sdk.ext.twig
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow

View File

@ -2,7 +2,7 @@ package cash.z.ecc.android
import cash.z.ecc.android.feedback.Feedback
import cash.z.ecc.android.ui.send.SendViewModel
import cash.z.wallet.sdk.entity.*
import cash.z.ecc.android.sdk.entity.*
import com.nhaarman.mockitokotlin2.verify
import com.nhaarman.mockitokotlin2.verifyZeroInteractions
import com.nhaarman.mockitokotlin2.whenever

View File

@ -1,9 +1,6 @@
import cash.z.ecc.android.Deps
buildscript {
ext {
kotlin_version = '1.3.61'
}
repositories {
google()
jcenter()
@ -12,7 +9,7 @@ buildscript {
}
}
dependencies {
classpath 'com.android.tools.build:gradle:3.6.0-rc02'
classpath 'com.android.tools.build:gradle:4.0.0'
classpath 'com.google.gms:google-services:4.3.3'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${Deps.kotlinVersion}"
classpath 'io.fabric.tools:gradle:1.31.2'

View File

@ -3,7 +3,7 @@ package cash.z.ecc.android
object Deps {
// For use in the top-level build.gradle which gives an error when provided
// `Deps.Kotlin.version` directly
const val kotlinVersion = "1.3.61"
const val kotlinVersion = "1.3.72"
const val compileSdkVersion = 29
const val buildToolsVersion = "29.0.2"
@ -11,18 +11,34 @@ object Deps {
const val targetSdkVersion = 29
object AndroidX {
const val ANNOTATION = "androidx.annotation:annotation:1.1.0"
const val APPCOMPAT = "androidx.appcompat:appcompat:1.1.0"
const val CORE_KTX = "androidx.core:core-ktx:1.1.0"
const val CONSTRAINT_LAYOUT = "androidx.constraintlayout:constraintlayout:1.1.3"
const val CORE_KTX = "androidx.core:core-ktx:1.1.0"
const val FRAGMENT_KTX = "androidx.fragment:fragment-ktx:1.1.0-beta01"
const val LEGACY = "androidx.legacy:legacy-support-v4:1.0.0"
const val MULTIDEX = "androidx.multidex:multidex:2.0.1"
const val PAGING = "androidx.paging:paging-runtime-ktx:2.1.2"
object CameraX : Version("1.0.0-beta04") {
val CAMERA2 = "androidx.camera:camera-camera2:1.0.0-beta04"
val CORE = "androidx.camera:camera-core:1.0.0-beta04"
val LIFECYCLE = "androidx.camera:camera-lifecycle:1.0.0-beta04"
object View : Version("1.0.0-alpha11") {
val EXT = "androidx.camera:camera-extensions:1.0.0-alpha11"
val VIEW = "androidx.camera:camera-view:1.0.0-alpha11"
}
}
object Lifecycle : Version("2.2.0-rc02") {
val LIFECYCLE_RUNTIME_KTX = "androidx.lifecycle:lifecycle-runtime-ktx:$version"
val LIFECYCLE_EXTENSIONS = "androidx.lifecycle:lifecycle-extensions:$version"
}
object Navigation : Version("2.2.0") {
val FRAGMENT_KTX = "androidx.navigation:navigation-fragment-ktx:$version"
val UI_KTX = "androidx.navigation:navigation-ui-ktx:$version"
}
object Lifecycle: Version("2.2.0-rc02") {
val LIFECYCLE_RUNTIME_KTX = "androidx.lifecycle:lifecycle-runtime-ktx:$version"
val LIFECYCLE_EXTENSIONS = "androidx.lifecycle:lifecycle-extensions:$version"
object Room : Version("2.2.5") {
val ROOM_COMPILER = "androidx.room:room-compiler:$version"
val ROOM_KTX = "androidx.room:room-ktx:$version"
}
}
object Dagger : Version("2.25.2") {
@ -31,35 +47,61 @@ object Deps {
val COMPILER = "com.google.dagger:dagger-compiler:$version"
}
object Google {
// solves error: Duplicate class com.google.common.util.concurrent.ListenableFuture found in modules jetified-guava-26.0-android.jar (com.google.guava:guava:26.0-android) and listenablefuture-1.0.jar (com.google.guava:listenablefuture:1.0)
// per this recommendation from Chris Povirk, given guava's decision to split ListenableFuture away from Guava: https://groups.google.com/d/msg/guava-discuss/GghaKwusjcY/bCIAKfzOEwAJ
const val GUAVA = "com.google.guava:guava:27.0.1-android"
const val MATERIAL = "com.google.android.material:material:1.1.0-beta01"
// QR Scanner
const val ML_VISION = "com.google.firebase:firebase-ml-vision:24.0.3"
}
object Grpc : Version("1.25.0") {
val ANDROID = "io.grpc:grpc-android:$version"
val OKHTTP = "io.grpc:grpc-okhttp:$version"
val PROTOBUG = "io.grpc:grpc-protobuf-lite:$version"
val STUB = "io.grpc:grpc-stub:$version"
}
object Analytics { // for dogfooding/crash-reporting/feedback only on internal team builds
val CRASHLYTICS = "com.crashlytics.sdk.android:crashlytics:2.10.1"
val CRASHLYTICS_NDK = "com.crashlytics.sdk.android:crashlytics-ndk:2.1.1"
val FIREBASE = "com.google.firebase:firebase-analytics:17.4.3"
val FIREBASE_PERF = "com.google.firebase:firebase-perf:19.0.7"
val MIXPANEL = "com.mixpanel.android:mixpanel-android:5.6.3"
}
object JavaX {
const val INJECT = "javax.inject:javax.inject:1"
const val INJECT = "javax.inject:javax.inject:1"
const val JAVA_ANNOTATION = "javax.annotation:javax.annotation-api:1.3.2"
}
object Kotlin : Version(kotlinVersion) {
val STDLIB = "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$version"
val STDLIB = "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$version"
object Coroutines : Version("1.3.2") {
val ANDROID = "org.jetbrains.kotlinx:kotlinx-coroutines-android:$version"
val CORE = "org.jetbrains.kotlinx:kotlinx-coroutines-core:$version"
val TEST = "org.jetbrains.kotlinx:kotlinx-coroutines-test:$version"
val ANDROID = "org.jetbrains.kotlinx:kotlinx-coroutines-android:$version"
val CORE = "org.jetbrains.kotlinx:kotlinx-coroutines-core:$version"
val TEST = "org.jetbrains.kotlinx:kotlinx-coroutines-test:$version"
}
}
object Zcash {
val ANDROID_WALLET_PLUGINS = "com.github.zcash:zcash-android-wallet-plugins:1.0.1"
const val ANDROID_WALLET_PLUGINS = "cash.z.ecc.android:zcash-android-wallet-plugins:1.0.0"
const val KOTLIN_BIP39 = "cash.z.ecc.android:kotlin-bip39:1.0.0-beta08"
object Sdk : Version("1.1.0-beta01") {
val MAINNET = "cash.z.ecc.android:sdk-mainnet:$version"
val TESTNET = "cash.z.ecc.android:sdk-testnet:$version"
}
}
object Misc {
const val LOTTIE = "com.airbnb.android:lottie:3.1.0"
object Plugins {
val SECURE_STORAGE = "de.adorsys.android:securestoragelibrary:1.2.2"
val ANDROID_BIP39 = "cash.z.ecc.android:android-bip39:1.0.0-beta07"
val QR_SCANNER = "com.google.zxing:core:3.2.1"
const val SECURE_STORAGE = "de.adorsys.android:securestoragelibrary:1.2.2"
const val QR_SCANNER = "com.google.zxing:core:3.2.1"
}
}
object Test {
const val JUNIT = "junit:junit:4.12"
const val JUNIT = "junit:junit:4.12"
const val MOKITO = "junit:junit:4.12"
const val COROUTINES_TEST = "junit:junit:4.12"
object Android {
const val JUNIT = "androidx.test.ext:junit:1.1.1"
const val ESPRESSO = "androidx.test.espresso:espresso-core:3.2.0"
const val JUNIT = "androidx.test.ext:junit:1.1.1"
const val ESPRESSO = "androidx.test.espresso:espresso-core:3.2.0"
}
}
}

View File

@ -1,6 +1,6 @@
#Tue Jan 07 12:00:21 EST 2020
#Fri May 29 19:00:53 EDT 2020
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip

View File

@ -8,7 +8,7 @@ dependencies {
// Zcash
implementation Deps.Zcash.ANDROID_WALLET_PLUGINS
implementation Deps.Misc.Plugins.ANDROID_BIP39
implementation Deps.Zcash.KOTLIN_BIP39
testImplementation Deps.Test.JUNIT
}

View File

@ -1,57 +1,22 @@
package cash.z.ecc.kotlin.mnemonic
import cash.z.android.plugin.MnemonicPlugin
import cash.z.ecc.android.bip39.Mnemonics
import cash.z.ecc.android.bip39.Mnemonics.MnemonicCode
import cash.z.ecc.android.bip39.Mnemonics.WordCount
import cash.z.ecc.android.bip39.toEntropy
import cash.z.ecc.android.bip39.toSeed
import java.util.*
import java.util.Locale.ENGLISH
import javax.inject.Inject
class Mnemonics @Inject constructor(): MnemonicPlugin {
override fun fullWordList(languageCode: String): List<String> {
return cash.z.ecc.android.bip39.Mnemonics.getCachedWords(Locale.ENGLISH.language)
}
override fun nextEntropy(): ByteArray {
return WordCount.COUNT_24.toEntropy()
}
override fun nextMnemonic(): CharArray {
return nextMnemonic(nextEntropy())
}
override fun nextMnemonic(entropy: ByteArray): CharArray {
return MnemonicCode(entropy).chars
}
override fun nextMnemonicList(): List<CharArray> {
return nextMnemonicList(nextEntropy())
}
override fun nextMnemonicList(entropy: ByteArray): List<CharArray> {
return MnemonicCode(entropy).map { it.toCharArray() }
}
override fun toSeed(mnemonic: CharArray): ByteArray {
return MnemonicCode(mnemonic).toSeed()
}
override fun toWordList(mnemonic: CharArray): List<CharArray> {
val wordList = mutableListOf<CharArray>()
var cursor = 0
repeat(mnemonic.size) { i ->
val isSpace = mnemonic[i] == ' '
if (isSpace || i == (mnemonic.size - 1)) {
val wordSize = i - cursor + if (isSpace) 0 else 1
wordList.add(CharArray(wordSize).apply {
repeat(wordSize) {
this[it] = mnemonic[cursor + it]
}
})
cursor = i + 1
}
}
return wordList
}
class Mnemonics @Inject constructor() : MnemonicPlugin {
override fun fullWordList(languageCode: String) = Mnemonics.getCachedWords(Locale.ENGLISH.language)
override fun nextEntropy(): ByteArray = WordCount.COUNT_24.toEntropy()
override fun nextMnemonic(): CharArray = MnemonicCode(WordCount.COUNT_24).chars
override fun nextMnemonic(entropy: ByteArray): CharArray = MnemonicCode(entropy).chars
override fun nextMnemonicList(): List<CharArray> = MnemonicCode(WordCount.COUNT_24).words
override fun nextMnemonicList(entropy: ByteArray): List<CharArray> = MnemonicCode(entropy).words
override fun toSeed(mnemonic: CharArray): ByteArray = MnemonicCode(mnemonic).toSeed()
override fun toWordList(mnemonic: CharArray): List<CharArray> = MnemonicCode(mnemonic).words
}

View File

@ -1,4 +1,3 @@
rootProject.name='Zcash Wallet'
include ':app', ':qrecycler', ':feedback', ':mnemonic', ':lockbox', ':sdk', ':chipsinputlayout'
project(":sdk").projectDir = file("../zcash-android-wallet-sdk")
include ':app', ':qrecycler', ':feedback', ':mnemonic', ':lockbox', ':chipsinputlayout'
project(":chipsinputlayout").projectDir = file("../../clones/chips-input-layout/library")