diff --git a/build.gradle b/build.gradle
index 24c4db9b..fab03dec 100644
--- a/build.gradle
+++ b/build.gradle
@@ -6,12 +6,13 @@ buildscript {
]
ext.versions = [
'architectureComponents': [
- 'lifecycle': '2.2.0-alpha04',
- 'room': '2.1.0-rc01'
+ 'lifecycle': '2.2.0-alpha05',
+ 'room': '2.2.0',
+ 'paging': '2.1.0'
],
'grpc':'1.21.0',
'kotlin': '1.3.50',
- 'coroutines': '1.3.0-M1',
+ 'coroutines': '1.3.2',
'junitJupiter': '5.5.0-M1'
]
repositories {
@@ -22,7 +23,7 @@ buildscript {
}
}
dependencies {
- classpath 'com.android.tools.build:gradle:3.6.0-alpha11'
+ classpath 'com.android.tools.build:gradle:3.6.0-beta01'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${versions.kotlin}"
classpath "org.jetbrains.kotlin:kotlin-allopen:${versions.kotlin}"
classpath "org.jetbrains.dokka:dokka-gradle-plugin:0.9.18"
@@ -50,7 +51,7 @@ apply plugin: 'org.mozilla.rust-android-gradle.rust-android'
apply plugin: 'org.owasp.dependencycheck'
group = 'cash.z.android.wallet'
-version = '1.0.0-alpha02'
+version = '1.0.0-alpha03'
repositories {
google()
@@ -65,7 +66,7 @@ android {
defaultConfig {
minSdkVersion buildConfig.minSdkVersion
targetSdkVersion buildConfig.targetSdkVersion
- versionCode = 1_00_00_002 // 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.
+ versionCode = 1_00_00_003 // 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"
testInstrumentationRunnerArguments clearPackageData: 'true'
@@ -195,6 +196,8 @@ dependencies {
// Architecture Components: Room
implementation "androidx.room:room-runtime:${versions.architectureComponents.room}"
implementation "androidx.room:room-common:${versions.architectureComponents.room}"
+ implementation "androidx.room:room-ktx:${versions.architectureComponents.room}"
+ implementation "androidx.paging:paging-runtime-ktx:${versions.architectureComponents.paging}"
kapt "androidx.room:room-compiler:${versions.architectureComponents.room}"
// Kotlin
@@ -233,7 +236,7 @@ dependencies {
androidTestImplementation 'org.mockito:mockito-android:2.25.1'
androidTestImplementation "androidx.test:runner:1.2.0"
androidTestImplementation "androidx.test:core:1.2.0"
- androidTestImplementation "androidx.arch.core:core-testing:2.1.0-rc01"
+ androidTestImplementation "androidx.arch.core:core-testing:2.1.0"
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test:runner:1.2.0'
}
diff --git a/samples/addressAndKeys/app/.gitignore b/samples/addressAndKeys/app/.gitignore
deleted file mode 100644
index 796b96d1..00000000
--- a/samples/addressAndKeys/app/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-/build
diff --git a/samples/addressAndKeys/app/build.gradle b/samples/addressAndKeys/app/build.gradle
deleted file mode 100644
index 5f96b882..00000000
--- a/samples/addressAndKeys/app/build.gradle
+++ /dev/null
@@ -1,37 +0,0 @@
-apply plugin: 'com.android.application'
-apply plugin: 'kotlin-android'
-apply plugin: 'kotlin-android-extensions'
-
-android {
- compileSdkVersion 29
- defaultConfig {
- applicationId "cash.z.wallet.sdk.sample.address"
- minSdkVersion 21
- targetSdkVersion 29
- versionCode 1
- versionName "1.0"
- testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
- missingDimensionStrategy "network", "zcashtestnet"
- }
- buildTypes {
- release {
- minifyEnabled false
- proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
- matchingFallbacks = ['zcashtestnetRelease']
- }
- }
-}
-
-dependencies {
- implementation project(path: ':sdk')
-// api project(path: ':sdk', configuration: 'default')
- implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${versions.kotlin}"
- implementation 'androidx.appcompat:appcompat:1.1.0'
- implementation 'androidx.core:core-ktx:1.1.0'
- implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
- implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:${versions.coroutines}"
- implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:${versions.coroutines}"
- testImplementation 'junit:junit:4.12'
- androidTestImplementation 'androidx.test.ext:junit:1.1.1'
- androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
-}
diff --git a/samples/addressAndKeys/app/src/main/AndroidManifest.xml b/samples/addressAndKeys/app/src/main/AndroidManifest.xml
deleted file mode 100644
index dd6f1e4d..00000000
--- a/samples/addressAndKeys/app/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/samples/addressAndKeys/app/src/main/java/cash/z/wallet/sdk/sample/address/Injection.kt b/samples/addressAndKeys/app/src/main/java/cash/z/wallet/sdk/sample/address/Injection.kt
deleted file mode 100644
index 195cdb9d..00000000
--- a/samples/addressAndKeys/app/src/main/java/cash/z/wallet/sdk/sample/address/Injection.kt
+++ /dev/null
@@ -1,34 +0,0 @@
-package cash.z.wallet.sdk.sample.address
-
-import cash.z.wallet.sdk.jni.RustBackend
-import cash.z.wallet.sdk.jni.RustBackendWelding
-import cash.z.wallet.sdk.secure.Wallet
-import kotlin.properties.ReadOnlyProperty
-import kotlin.properties.ReadWriteProperty
-
-object Injection {
- private val rustBackend: RustBackendWelding = RustBackend()
- private const val dataDbName = "AddressSampleData.db"
-
- fun provideWallet(
- seedProvider: ReadOnlyProperty,
- spendingKeyProvider: ReadWriteProperty
- ): Wallet {
- // simulate new session for each call
- App.instance.getDatabasePath(dataDbName).absoluteFile.delete()
-
- return Wallet(
- context = App.instance,
- birthday = Wallet.loadBirthdayFromAssets(App.instance, 421720),
- rustBackend = provideRustBackend(),
- dataDbName = dataDbName,
- seedProvider = seedProvider,
- spendingKeyProvider = spendingKeyProvider
- )
- }
-
- fun provideRustBackend(): RustBackendWelding {
- return rustBackend
- }
-}
-
diff --git a/samples/addressAndKeys/app/src/main/java/cash/z/wallet/sdk/sample/address/MainActivity.kt b/samples/addressAndKeys/app/src/main/java/cash/z/wallet/sdk/sample/address/MainActivity.kt
deleted file mode 100644
index f7e1a463..00000000
--- a/samples/addressAndKeys/app/src/main/java/cash/z/wallet/sdk/sample/address/MainActivity.kt
+++ /dev/null
@@ -1,65 +0,0 @@
-package cash.z.wallet.sdk.sample.address
-
-import android.os.Bundle
-import android.view.View
-import android.widget.TextView
-import android.widget.Toast
-import androidx.appcompat.app.AppCompatActivity
-import cash.z.wallet.sdk.data.TroubleshootingTwig
-import cash.z.wallet.sdk.data.Twig
-import cash.z.wallet.sdk.ext.SampleSeedProvider
-import cash.z.wallet.sdk.secure.Wallet
-import kotlin.properties.Delegates
-
-/**
- * Sample app that shows how to access the address and spending key.
- */
-class MainActivity : AppCompatActivity() {
- private lateinit var wallet: Wallet
- private lateinit var addressInfo: TextView
-
- // Secure storage is out of scope for this example (wallet makers know how to securely store things)
- // However, any class can implement the required interface for these dependencies. The expectation is that a wallet
- // maker would wrap an existing class with something that implements the property interface to access data. These
- // dependencies would then point to those wrappers.
- private val mockSecureStorage = Delegates.notNull()
- private val mockSecureSeedProvider = SampleSeedProvider("testreferencealice")
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_main)
- Twig.plant(TroubleshootingTwig())
-
- addressInfo = findViewById(R.id.text_address_info)
-
- wallet = Injection.provideWallet(mockSecureSeedProvider, mockSecureStorage).also { it.initialize() }
- }
-
- override fun onResume() {
- super.onResume()
- addressInfo.text = createAddressInfo()
- }
-
- private fun createAddressInfo(): String {
- val address = wallet.getAddress()
- val key by mockSecureStorage
- val info = """
- seed:
- ${mockSecureSeedProvider.seedValue}
- --------------------------------------
- address:
- $address
- --------------------------------------
- spendingKey:
- $key
- """.trimIndent()
- return info
- }
-
- fun onTestThings(view: View) {
- // This is a good place to insert some test behavior to try out the SDK in response to a click
- // it may help to add objects to the Injection.kt file
- Toast.makeText(this, "Test SDK behavior", Toast.LENGTH_SHORT).show()
- }
-
-}
diff --git a/samples/addressAndKeys/app/src/main/java/cash/z/wallet/sdk/sample/address/ScopedActivity.kt b/samples/addressAndKeys/app/src/main/java/cash/z/wallet/sdk/sample/address/ScopedActivity.kt
deleted file mode 100644
index 9d578d4c..00000000
--- a/samples/addressAndKeys/app/src/main/java/cash/z/wallet/sdk/sample/address/ScopedActivity.kt
+++ /dev/null
@@ -1,26 +0,0 @@
-package cash.z.wallet.sdk.sample.address
-
-import android.os.Bundle
-import androidx.appcompat.app.AppCompatActivity
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.Job
-import kotlin.coroutines.CoroutineContext
-
-open class ScopedActivity : AppCompatActivity(), CoroutineScope {
- private lateinit var job: Job
-
- override val coroutineContext: CoroutineContext
- get() = job + Dispatchers.Main
-
- override fun onCreate(savedInstanceState: Bundle?) {
- job = Job()
- super.onCreate(savedInstanceState)
- }
-
- override fun onDestroy() {
- super.onDestroy()
- job.cancel()
- }
-
-}
diff --git a/samples/addressAndKeys/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/samples/addressAndKeys/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
deleted file mode 100644
index 6348baae..00000000
--- a/samples/addressAndKeys/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
diff --git a/samples/addressAndKeys/app/src/main/res/drawable/ic_launcher_background.xml b/samples/addressAndKeys/app/src/main/res/drawable/ic_launcher_background.xml
deleted file mode 100644
index a0ad202f..00000000
--- a/samples/addressAndKeys/app/src/main/res/drawable/ic_launcher_background.xml
+++ /dev/null
@@ -1,74 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/samples/addressAndKeys/app/src/main/res/layout/activity_main.xml b/samples/addressAndKeys/app/src/main/res/layout/activity_main.xml
deleted file mode 100644
index 345ce1a6..00000000
--- a/samples/addressAndKeys/app/src/main/res/layout/activity_main.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/samples/addressAndKeys/app/src/main/res/mipmap-hdpi/ic_launcher.png b/samples/addressAndKeys/app/src/main/res/mipmap-hdpi/ic_launcher.png
deleted file mode 100644
index 898f3ed5..00000000
Binary files a/samples/addressAndKeys/app/src/main/res/mipmap-hdpi/ic_launcher.png and /dev/null differ
diff --git a/samples/addressAndKeys/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/samples/addressAndKeys/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
deleted file mode 100644
index dffca360..00000000
Binary files a/samples/addressAndKeys/app/src/main/res/mipmap-hdpi/ic_launcher_round.png and /dev/null differ
diff --git a/samples/addressAndKeys/app/src/main/res/mipmap-mdpi/ic_launcher.png b/samples/addressAndKeys/app/src/main/res/mipmap-mdpi/ic_launcher.png
deleted file mode 100644
index 64ba76f7..00000000
Binary files a/samples/addressAndKeys/app/src/main/res/mipmap-mdpi/ic_launcher.png and /dev/null differ
diff --git a/samples/addressAndKeys/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/samples/addressAndKeys/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
deleted file mode 100644
index dae5e082..00000000
Binary files a/samples/addressAndKeys/app/src/main/res/mipmap-mdpi/ic_launcher_round.png and /dev/null differ
diff --git a/samples/addressAndKeys/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/samples/addressAndKeys/app/src/main/res/mipmap-xhdpi/ic_launcher.png
deleted file mode 100644
index e5ed4659..00000000
Binary files a/samples/addressAndKeys/app/src/main/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ
diff --git a/samples/addressAndKeys/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/samples/addressAndKeys/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
deleted file mode 100644
index 14ed0af3..00000000
Binary files a/samples/addressAndKeys/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png and /dev/null differ
diff --git a/samples/addressAndKeys/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/samples/addressAndKeys/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
deleted file mode 100644
index b0907cac..00000000
Binary files a/samples/addressAndKeys/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ
diff --git a/samples/addressAndKeys/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/samples/addressAndKeys/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
deleted file mode 100644
index d8ae0315..00000000
Binary files a/samples/addressAndKeys/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png and /dev/null differ
diff --git a/samples/addressAndKeys/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/samples/addressAndKeys/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
deleted file mode 100644
index 2c18de9e..00000000
Binary files a/samples/addressAndKeys/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ
diff --git a/samples/addressAndKeys/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/samples/addressAndKeys/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
deleted file mode 100644
index beed3cdd..00000000
Binary files a/samples/addressAndKeys/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png and /dev/null differ
diff --git a/samples/addressAndKeys/app/src/main/res/values/colors.xml b/samples/addressAndKeys/app/src/main/res/values/colors.xml
deleted file mode 100644
index 69b22338..00000000
--- a/samples/addressAndKeys/app/src/main/res/values/colors.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
- #008577
- #00574B
- #D81B60
-
diff --git a/samples/addressAndKeys/app/src/main/res/values/strings.xml b/samples/addressAndKeys/app/src/main/res/values/strings.xml
deleted file mode 100644
index 089d5a5e..00000000
--- a/samples/addressAndKeys/app/src/main/res/values/strings.xml
+++ /dev/null
@@ -1,3 +0,0 @@
-
- Zcash Address
-
diff --git a/samples/addressAndKeys/app/src/main/res/values/styles.xml b/samples/addressAndKeys/app/src/main/res/values/styles.xml
deleted file mode 100644
index 5885930d..00000000
--- a/samples/addressAndKeys/app/src/main/res/values/styles.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
diff --git a/samples/addressAndKeys/build.gradle b/samples/addressAndKeys/build.gradle
deleted file mode 100644
index d88fcd0d..00000000
--- a/samples/addressAndKeys/build.gradle
+++ /dev/null
@@ -1,25 +0,0 @@
-buildscript {
- ext.versions = [
- 'kotlin': '1.3.50',
- 'coroutines': '1.3.0-M1'
- ]
- repositories {
- google()
- jcenter()
- }
- dependencies {
- classpath 'com.android.tools.build:gradle:3.6.0-alpha11'
- classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${versions.kotlin}"
- }
-}
-
-allprojects {
- repositories {
- google()
- jcenter()
- }
-}
-
-task clean(type: Delete) {
- delete rootProject.buildDir
-}
diff --git a/samples/addressAndKeys/settings.gradle b/samples/addressAndKeys/settings.gradle
deleted file mode 100644
index 0349f723..00000000
--- a/samples/addressAndKeys/settings.gradle
+++ /dev/null
@@ -1,3 +0,0 @@
-include ':app', ":sdk"
-project(":sdk").projectDir = file("../../../zcash-android-wallet-sdk")
-rootProject.name='Zcash Address'
\ No newline at end of file
diff --git a/samples/addressAndKeys/.gitignore b/samples/demo-app/.gitignore
similarity index 100%
rename from samples/addressAndKeys/.gitignore
rename to samples/demo-app/.gitignore
diff --git a/samples/demo-app/app/build.gradle b/samples/demo-app/app/build.gradle
new file mode 100644
index 00000000..4c5a2e25
--- /dev/null
+++ b/samples/demo-app/app/build.gradle
@@ -0,0 +1,76 @@
+apply plugin: 'com.android.application'
+apply plugin: 'kotlin-android'
+apply plugin: 'kotlin-android-extensions'
+apply plugin: 'kotlin-kapt'
+apply plugin: 'androidx.navigation.safeargs'
+
+android {
+ compileSdkVersion 29
+ buildToolsVersion "29.0.2"
+ viewBinding.enabled = true
+ defaultConfig {
+ applicationId "cash.z.wallet.sdk.demoapp"
+ minSdkVersion 21
+ targetSdkVersion 29
+ versionCode 1
+ versionName "1.0"
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ missingDimensionStrategy "network", "zcashtestnet"
+ }
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+ compileOptions {
+ sourceCompatibility 1.8
+ targetCompatibility 1.8
+ }
+ kotlinOptions {
+ jvmTarget = "1.8"
+ }
+}
+
+dependencies {
+ // SDK
+ implementation project(path: ':sdk')
+// implementation "cash.z.android.wallet:zcash-android-core:$sdk_version@aar"
+// implementation "cash.z.android.wallet:zcash-kotlin-bip39:$sdk_version@aar"
+
+ // SDK: grpc
+ implementation "io.grpc:grpc-okhttp:1.21.0"
+ implementation "io.grpc:grpc-protobuf-lite:1.21.0"
+ implementation "io.grpc:grpc-stub:1.21.0"
+ implementation "io.grpc:grpc-android:1.21.0"
+ implementation 'javax.annotation:javax.annotation-api:1.3.2'
+ // SDK: Room
+ implementation "androidx.room:room-runtime:2.2.2"
+ implementation "androidx.room:room-common:2.2.2"
+ implementation "androidx.room:room-ktx:2.2.2"
+ implementation "androidx.paging:paging-runtime-ktx:2.1.0"
+ implementation 'com.google.guava:guava:27.0.1-android'
+ kapt "androidx.room:room-compiler:2.2.2"
+ // SDK: Other
+ implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.2"
+ implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.2"
+
+ // Android
+ implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
+ implementation 'androidx.appcompat:appcompat:1.1.0'
+ implementation 'androidx.core:core-ktx:1.1.0'
+ implementation 'androidx.legacy:legacy-support-v4:1.0.0'
+ implementation 'com.google.android.material:material:1.0.0'
+ implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
+ implementation 'androidx.navigation:navigation-fragment:2.1.0'
+ implementation 'androidx.navigation:navigation-ui:2.1.0'
+ implementation 'androidx.lifecycle:lifecycle-extensions:2.1.0'
+ implementation 'androidx.navigation:navigation-fragment-ktx:2.1.0'
+ implementation 'androidx.navigation:navigation-ui-ktx:2.1.0'
+ testImplementation 'junit:junit:4.12'
+ androidTestImplementation 'androidx.test.ext:junit:1.1.1'
+ androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
+ implementation "androidx.lifecycle:lifecycle-common-java8:2.2.0-rc02"
+ implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.2.0-rc02" // provides lifecycleScope!
+
+}
diff --git a/samples/demo-app/app/libs/zcash-android-testnet-1.0.0-alpha02.aar b/samples/demo-app/app/libs/zcash-android-testnet-1.0.0-alpha02.aar
new file mode 100644
index 00000000..bb096dec
Binary files /dev/null and b/samples/demo-app/app/libs/zcash-android-testnet-1.0.0-alpha02.aar differ
diff --git a/samples/demo-app/app/libs/zcash-android-testnet-1.0.0-alpha03.aar b/samples/demo-app/app/libs/zcash-android-testnet-1.0.0-alpha03.aar
new file mode 100644
index 00000000..f2a2f93b
Binary files /dev/null and b/samples/demo-app/app/libs/zcash-android-testnet-1.0.0-alpha03.aar differ
diff --git a/samples/addressAndKeys/app/proguard-rules.pro b/samples/demo-app/app/proguard-rules.pro
similarity index 100%
rename from samples/addressAndKeys/app/proguard-rules.pro
rename to samples/demo-app/app/proguard-rules.pro
diff --git a/samples/demo-app/app/src/androidTest/java/cash/z/wallet/sdk/sample/demoapp/SampleCodeTest.kt b/samples/demo-app/app/src/androidTest/java/cash/z/wallet/sdk/sample/demoapp/SampleCodeTest.kt
new file mode 100644
index 00000000..76184661
--- /dev/null
+++ b/samples/demo-app/app/src/androidTest/java/cash/z/wallet/sdk/sample/demoapp/SampleCodeTest.kt
@@ -0,0 +1,161 @@
+package cash.z.wallet.sdk.sample.demoapp
+
+import androidx.test.platform.app.InstrumentationRegistry
+import cash.z.wallet.sdk.Initializer
+import cash.z.wallet.sdk.Synchronizer
+import cash.z.wallet.sdk.entity.isFailure
+import cash.z.wallet.sdk.transaction.*
+import cash.z.wallet.sdk.ext.*
+import cash.z.wallet.sdk.jni.RustBackend
+import cash.z.wallet.sdk.service.LightWalletGrpcService
+import kotlinx.coroutines.cancel
+import kotlinx.coroutines.flow.collect
+import kotlinx.coroutines.flow.first
+import kotlinx.coroutines.runBlocking
+import org.junit.Assert.*
+import org.junit.BeforeClass
+import org.junit.Ignore
+import org.junit.Test
+
+/**
+ * Sample code to demonstrate key functionality without UI, inspired by:
+ * https://github.com/EdgeApp/eosjs-node-cli/blob/paul/cleanup/app.js
+ */
+class SampleCodeTest {
+
+ // ///////////////////////////////////////////////////
+ // Seed derivation
+ @Ignore @Test fun createBip39Seed_fromSeedPhrase() {
+ // TODO: log(seedPhrase.asRawEntropy().asBip39seed())
+ }
+
+ @Ignore @Test fun createRawEntropy() {
+ // TODO: call: Mnemonic::from_phrase(seed_phrase, Language::English).unwrap().entropy()
+ // log(seedPhrase.asRawEntropy())
+ }
+
+ @Ignore @Test fun createBip39Seed_fromRawEntropy() {
+ // get the 64 byte bip39 entropy
+ // TODO: call: bip39::Seed::new(&Mnemonic::from_entropy(&seed_bytes, Language::English).unwrap(), "")
+ // log(rawEntropy.asBip39Seed())
+ }
+
+ @Ignore @Test fun deriveSeedPhraseFrom() {
+ // TODO: let mnemonic = Mnemonic::from_entropy(entropy, Language::English).unwrap();
+ // log(entropy.asSeedPhrase())
+ }
+
+
+ /////////////////////////////////////////////////////
+ // Derive Extended Spending Key
+ @Test fun deriveSpendingKey() {
+ val spendingKeys = RustBackend().deriveSpendingKeys(seed)
+ assertEquals(1, spendingKeys.size)
+ log("Spending Key: ${spendingKeys?.get(0)}")
+ }
+
+ /////////////////////////////////////////////////////
+ // Get Address
+ @Test fun getAddress() = runBlocking {
+ val address = synchronizer.getAddress()
+ assertFalse(address.isNullOrBlank())
+ log("Address: $address")
+ }
+
+ /////////////////////////////////////////////////////
+ // Derive address from Extended Full Viewing Key
+ @Test fun getAddressFromViewingKey() {
+
+ }
+
+ // ///////////////////////////////////////////////////
+ // Query latest block height
+ @Test fun getLatestBlockHeightTest() {
+ val lightwalletService = LightWalletGrpcService(context, lightwalletdHost)
+ log("Latest Block: ${lightwalletService.getLatestBlockHeight()}")
+ }
+
+ // ///////////////////////////////////////////////////
+ // Download compact block range
+ @Test fun getBlockRange() {
+ val blockRange = 500_000..500_009
+ val lightwalletService = LightWalletGrpcService(context, lightwalletdHost)
+ val blocks = lightwalletService.getBlockRange(blockRange)
+ assertEquals(blockRange.count(), blocks.size)
+
+ blocks.forEachIndexed { i, block ->
+ log("Block #$i: height:${block.height} hash:${block.hash.toByteArray().toHex()}")
+ }
+ }
+
+ // ///////////////////////////////////////////////////
+ // Query account outgoing transactions
+ @Test fun queryOutgoingTransactions() {
+
+ }
+
+ // ///////////////////////////////////////////////////
+ // Query account incoming transactions
+ @Test fun queryIncomingTransactions() {
+
+ }
+
+ // ///////////////////////////////////////////////////
+ // Create a signed transaction (with memo)
+ @Test fun createTransaction() = runBlocking {
+ val rustBackend = RustBackend().init(context)
+ val repository = PagedTransactionRepository(context)
+ val encoder = WalletTransactionEncoder(rustBackend, repository)
+ val spendingKey = rustBackend.deriveSpendingKeys(seed)[0]
+
+ val amount = 0.123.convertZecToZatoshi()
+ val address = "ztestsapling1tklsjr0wyw0d58f3p7wufvrj2cyfv6q6caumyueadq8qvqt8lda6v6tpx474rfru9y6u75u7qnw"
+ val memo = "Test Transaction".toByteArray()
+
+ val encodedTx = encoder.createTransaction(spendingKey, amount, address, memo)
+ assertTrue(encodedTx.raw.isNotEmpty())
+ log("Transaction ID: ${encodedTx.txId.toHex()}")
+ }
+
+ // ///////////////////////////////////////////////////
+ // Create a signed transaction (with memo) and broadcast
+ @Test fun submitTransaction() = runBlocking {
+ val amount = 0.123.convertZecToZatoshi()
+ val address = "ztestsapling1tklsjr0wyw0d58f3p7wufvrj2cyfv6q6caumyueadq8qvqt8lda6v6tpx474rfru9y6u75u7qnw"
+ val memo = "Test Transaction"
+ val spendingKey = RustBackend().deriveSpendingKeys(seed)[0]
+ val transactionFlow = synchronizer.sendToAddress(spendingKey, amount, address, memo)
+ transactionFlow.collect {
+ log("pending transaction updated $it")
+ assertTrue("Failed to send funds. See log for details.", it?.isFailure() == false)
+ }
+ }
+
+
+ ///////////////////////////////////////////////////////
+ // Utility Functions
+ //////////////////////////////////////////////////////
+
+ companion object {
+ private val seed = "Insert seed for testing".toByteArray()
+ private val lightwalletdHost: String = ZcashSdk.DEFAULT_LIGHTWALLETD_HOST
+
+ private val context = InstrumentationRegistry.getInstrumentation().targetContext
+ private val synchronizer = Synchronizer(context, lightwalletdHost, seed)
+
+ @BeforeClass
+ @JvmStatic
+ fun init() {
+ Twig.plant(TroubleshootingTwig())
+ }
+
+ fun log(message: String?) = twig(message ?: "null")
+
+ private fun ByteArray.toHex(): String {
+ val sb = StringBuilder(size * 2)
+ for (b in this)
+ sb.append(String.format("%02x", b))
+ return sb.toString()
+ }
+ }
+}
diff --git a/samples/demo-app/app/src/main/AndroidManifest.xml b/samples/demo-app/app/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..cc4ae4c6
--- /dev/null
+++ b/samples/demo-app/app/src/main/AndroidManifest.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/samples/addressAndKeys/app/src/main/java/cash/z/wallet/sdk/sample/address/App.kt b/samples/demo-app/app/src/main/java/cash/z/wallet/sdk/demoapp/App.kt
similarity index 63%
rename from samples/addressAndKeys/app/src/main/java/cash/z/wallet/sdk/sample/address/App.kt
rename to samples/demo-app/app/src/main/java/cash/z/wallet/sdk/demoapp/App.kt
index c0d02831..551ea494 100644
--- a/samples/addressAndKeys/app/src/main/java/cash/z/wallet/sdk/sample/address/App.kt
+++ b/samples/demo-app/app/src/main/java/cash/z/wallet/sdk/demoapp/App.kt
@@ -1,8 +1,12 @@
-package cash.z.wallet.sdk.sample.address
+package cash.z.wallet.sdk.demoapp
import android.app.Application
+import cash.z.wallet.sdk.demoapp.util.DemoConfig
class App : Application() {
+
+ var defaultConfig = DemoConfig()
+
override fun onCreate() {
instance = this
super.onCreate()
diff --git a/samples/demo-app/app/src/main/java/cash/z/wallet/sdk/demoapp/BaseDemoFragment.kt b/samples/demo-app/app/src/main/java/cash/z/wallet/sdk/demoapp/BaseDemoFragment.kt
new file mode 100644
index 00000000..3b1559b2
--- /dev/null
+++ b/samples/demo-app/app/src/main/java/cash/z/wallet/sdk/demoapp/BaseDemoFragment.kt
@@ -0,0 +1,73 @@
+package cash.z.wallet.sdk.demoapp
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.fragment.app.Fragment
+import androidx.lifecycle.lifecycleScope
+import androidx.viewbinding.ViewBinding
+import cash.z.wallet.sdk.ext.TroubleshootingTwig
+import cash.z.wallet.sdk.ext.Twig
+import kotlinx.coroutines.Dispatchers.IO
+import kotlinx.coroutines.withContext
+
+abstract class BaseDemoFragment : Fragment() {
+
+ lateinit var binding: T
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ Twig.plant(TroubleshootingTwig())
+ }
+
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? {
+ binding = inflateBinding(layoutInflater)
+ return binding.root
+ }
+
+ override fun onResume() {
+ super.onResume()
+ // just a quick way of enforcing the following for each demo:
+ // - wait until the fragment is created, then run `initInBackground` on a background thread
+ // - wait until init is finished
+ // - and then run `onInitComplete` on the Main thread
+ // - but only once the fragment is resumed
+ // - and if the fragment/activity/app is stopped during any of this, exit cleanly
+ //
+ // Why?
+ // Because this is a demo. In a full-blown app, there would be other appropriate times to
+ // load things. Also, we want each demo to stand alone. It is abnormal for a fragment to
+ // always recreate application state but that's the behavior we want for the demos.
+ // So we use this approach to coordinate two sets of logic and ensure they run sequentially
+ // while also respecting the lifecycle. If we didn't do this, the `initInBackground` would
+ // freeze the UI while the fragment is created and `onInitComplete` would have no way of
+ // knowing when the background thread work is done and thereby could run in the wrong order.
+ lifecycleScope.launchWhenCreated {
+ withContext(IO) {
+ resetInBackground()
+ lifecycleScope.launchWhenResumed {
+ onResetComplete()
+ }
+ }
+ }
+ }
+
+ override fun onPause() {
+ super.onPause()
+ onClear()
+ }
+
+ /**
+ * Inflate the ViewBinding. Unfortunately, the `inflate` function is not part of the ViewBinding
+ * interface so the base class cannot take care of this behavior without some help.
+ */
+ abstract fun inflateBinding(layoutInflater: LayoutInflater): T
+ abstract fun resetInBackground()
+ abstract fun onResetComplete()
+ abstract fun onClear()
+}
\ No newline at end of file
diff --git a/samples/demo-app/app/src/main/java/cash/z/wallet/sdk/demoapp/MainActivity.kt b/samples/demo-app/app/src/main/java/cash/z/wallet/sdk/demoapp/MainActivity.kt
new file mode 100644
index 00000000..8969f4b2
--- /dev/null
+++ b/samples/demo-app/app/src/main/java/cash/z/wallet/sdk/demoapp/MainActivity.kt
@@ -0,0 +1,59 @@
+package cash.z.wallet.sdk.demoapp
+
+import android.os.Bundle
+import android.view.Menu
+import com.google.android.material.floatingactionbutton.FloatingActionButton
+import com.google.android.material.snackbar.Snackbar
+import com.google.android.material.navigation.NavigationView
+import androidx.navigation.findNavController
+import androidx.navigation.ui.AppBarConfiguration
+import androidx.navigation.ui.navigateUp
+import androidx.navigation.ui.setupActionBarWithNavController
+import androidx.navigation.ui.setupWithNavController
+import androidx.drawerlayout.widget.DrawerLayout
+import androidx.appcompat.app.AppCompatActivity
+import androidx.appcompat.widget.Toolbar
+import cash.z.wallet.sdk.demoapp.util.DemoConfig
+
+class MainActivity : AppCompatActivity() {
+
+ private lateinit var appBarConfiguration: AppBarConfiguration
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_main)
+ val toolbar: Toolbar = findViewById(R.id.toolbar)
+ setSupportActionBar(toolbar)
+
+ val fab: FloatingActionButton = findViewById(R.id.fab)
+ fab.setOnClickListener { view ->
+ Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
+ .setAction("Action", null).show()
+ }
+ val drawerLayout: DrawerLayout = findViewById(R.id.drawer_layout)
+ val navView: NavigationView = findViewById(R.id.nav_view)
+ val navController = findNavController(R.id.nav_host_fragment)
+ // Passing each menu ID as a set of Ids because each
+ // menu should be considered as top level destinations.
+ appBarConfiguration = AppBarConfiguration(
+ setOf(
+ R.id.nav_home, R.id.nav_address, R.id.nav_block, R.id.nav_private_key,
+ R.id.nav_latest_height, R.id.nav_block_range,
+ R.id.nav_transactions, R.id.nav_send
+ ), drawerLayout
+ )
+ setupActionBarWithNavController(navController, appBarConfiguration)
+ navView.setupWithNavController(navController)
+ }
+
+ override fun onCreateOptionsMenu(menu: Menu): Boolean {
+ // Inflate the menu; this adds items to the action bar if it is present.
+ menuInflater.inflate(R.menu.main, menu)
+ return true
+ }
+
+ override fun onSupportNavigateUp(): Boolean {
+ val navController = findNavController(R.id.nav_host_fragment)
+ return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
+ }
+}
diff --git a/samples/demo-app/app/src/main/java/cash/z/wallet/sdk/demoapp/demos/getaddress/GetAddressFragment.kt b/samples/demo-app/app/src/main/java/cash/z/wallet/sdk/demoapp/demos/getaddress/GetAddressFragment.kt
new file mode 100644
index 00000000..464af9be
--- /dev/null
+++ b/samples/demo-app/app/src/main/java/cash/z/wallet/sdk/demoapp/demos/getaddress/GetAddressFragment.kt
@@ -0,0 +1,32 @@
+package cash.z.wallet.sdk.demoapp.demos.getaddress
+
+import android.view.LayoutInflater
+import cash.z.wallet.sdk.Initializer
+import cash.z.wallet.sdk.demoapp.App
+import cash.z.wallet.sdk.demoapp.BaseDemoFragment
+import cash.z.wallet.sdk.demoapp.databinding.FragmentGetAddressBinding
+
+class GetAddressFragment : BaseDemoFragment() {
+
+ private var seed: ByteArray = App.instance.defaultConfig.seed
+ private val initializer: Initializer = Initializer(App.instance)
+
+ override fun inflateBinding(layoutInflater: LayoutInflater): FragmentGetAddressBinding
+ = FragmentGetAddressBinding.inflate(layoutInflater)
+
+ override fun resetInBackground() {
+ /**
+ * Create and initialize the wallet. Initialization will return the private keys but for the
+ * purposes of this demo we don't need them.
+ */
+ initializer.new(seed)
+ }
+
+ override fun onResetComplete() {
+ binding.textInfo.text = initializer.rustBackend.getAddress()
+ }
+
+ override fun onClear() {
+ initializer.clear()
+ }
+}
\ No newline at end of file
diff --git a/samples/demo-app/app/src/main/java/cash/z/wallet/sdk/demoapp/demos/getblock/GetBlockFragment.kt b/samples/demo-app/app/src/main/java/cash/z/wallet/sdk/demoapp/demos/getblock/GetBlockFragment.kt
new file mode 100644
index 00000000..6f528916
--- /dev/null
+++ b/samples/demo-app/app/src/main/java/cash/z/wallet/sdk/demoapp/demos/getblock/GetBlockFragment.kt
@@ -0,0 +1,46 @@
+package cash.z.wallet.sdk.demoapp.demos.getblock
+
+import android.view.LayoutInflater
+import android.view.View
+import cash.z.wallet.sdk.demoapp.App
+import cash.z.wallet.sdk.demoapp.BaseDemoFragment
+import cash.z.wallet.sdk.demoapp.databinding.FragmentGetBlockBinding
+import cash.z.wallet.sdk.service.LightWalletGrpcService
+import cash.z.wallet.sdk.service.LightWalletService
+
+class GetBlockFragment : BaseDemoFragment() {
+ private val host = App.instance.defaultConfig.host
+
+ private lateinit var lightwalletService: LightWalletService
+
+ override fun inflateBinding(layoutInflater: LayoutInflater): FragmentGetBlockBinding =
+ FragmentGetBlockBinding.inflate(layoutInflater)
+
+ override fun resetInBackground() {
+ lightwalletService = LightWalletGrpcService(App.instance, host)
+ }
+
+ override fun onResetComplete() {
+ binding.buttonApply.setOnClickListener(::onApply)
+ onApply(binding.textBlockHeight)
+ }
+
+ private fun onApply(_unused: View) {
+ setBlockHeight(binding.textBlockHeight.text.toString().toInt())
+ }
+
+ private fun setBlockHeight(blockHeight: Int) {
+ val blocks =
+ lightwalletService.getBlockRange(blockHeight..blockHeight)
+ val block = blocks.firstOrNull()
+ binding.textInfo.text = """
+ block height: ${block?.height}
+ block vtxCount: ${block?.vtxCount}
+ block time: ${block?.time}
+ """.trimIndent()
+ }
+
+ override fun onClear() {
+ lightwalletService.shutdown()
+ }
+}
\ No newline at end of file
diff --git a/samples/demo-app/app/src/main/java/cash/z/wallet/sdk/demoapp/demos/getblockrange/GetBlockRangeFragment.kt b/samples/demo-app/app/src/main/java/cash/z/wallet/sdk/demoapp/demos/getblockrange/GetBlockRangeFragment.kt
new file mode 100644
index 00000000..22f4cbc4
--- /dev/null
+++ b/samples/demo-app/app/src/main/java/cash/z/wallet/sdk/demoapp/demos/getblockrange/GetBlockRangeFragment.kt
@@ -0,0 +1,58 @@
+package cash.z.wallet.sdk.demoapp.demos.getblockrange
+
+import android.view.LayoutInflater
+import android.view.View
+import cash.z.wallet.sdk.demoapp.App
+import cash.z.wallet.sdk.demoapp.BaseDemoFragment
+import cash.z.wallet.sdk.demoapp.databinding.FragmentGetBlockRangeBinding
+import cash.z.wallet.sdk.service.LightWalletGrpcService
+import cash.z.wallet.sdk.service.LightWalletService
+
+class GetBlockRangeFragment : BaseDemoFragment() {
+
+ private val host = App.instance.defaultConfig.host
+
+ private lateinit var lightwalletService: LightWalletService
+
+ override fun inflateBinding(layoutInflater: LayoutInflater): FragmentGetBlockRangeBinding =
+ FragmentGetBlockRangeBinding.inflate(layoutInflater)
+
+ override fun resetInBackground() {
+ lightwalletService = LightWalletGrpcService(App.instance, host)
+ }
+
+ override fun onResetComplete() {
+ binding.buttonApply.setOnClickListener(::onApply)
+ onApply(binding.textInfo)
+ }
+
+ override fun onClear() {
+ lightwalletService.shutdown()
+ }
+
+ private fun onApply(_unused: View) {
+ val start = binding.textStartHeight.text.toString().toInt()
+ val end = binding.textEndHeight.text.toString().toInt()
+ if (start <= end) {
+ setBlockRange(start..end)
+ } else {
+ setError("Invalid range")
+ }
+ }
+
+ // TODO: iterate on this demo to show all the blocks in a recyclerview showing block heights and vtx count
+ private fun setBlockRange(blockRange: IntRange) {
+ val blocks =
+ lightwalletService.getBlockRange(blockRange)
+ val block = blocks.firstOrNull()
+ binding.textInfo.text = """
+ block height: ${block?.height}
+ block vtxCount: ${block?.vtxCount}
+ block time: ${block?.time}
+ """.trimIndent()
+ }
+
+ private fun setError(message: String) {
+ binding.textInfo.text = "Error: $message"
+ }
+}
\ No newline at end of file
diff --git a/samples/demo-app/app/src/main/java/cash/z/wallet/sdk/demoapp/demos/getlatestheight/GetLatestHeightFragment.kt b/samples/demo-app/app/src/main/java/cash/z/wallet/sdk/demoapp/demos/getlatestheight/GetLatestHeightFragment.kt
new file mode 100644
index 00000000..9619b7a9
--- /dev/null
+++ b/samples/demo-app/app/src/main/java/cash/z/wallet/sdk/demoapp/demos/getlatestheight/GetLatestHeightFragment.kt
@@ -0,0 +1,30 @@
+package cash.z.wallet.sdk.demoapp.demos.getlatestheight
+
+import android.view.LayoutInflater
+import android.view.View
+import cash.z.wallet.sdk.demoapp.App
+import cash.z.wallet.sdk.demoapp.BaseDemoFragment
+import cash.z.wallet.sdk.demoapp.databinding.FragmentGetLatestHeightBinding
+import cash.z.wallet.sdk.service.LightWalletGrpcService
+import cash.z.wallet.sdk.service.LightWalletService
+
+class GetLatestHeightFragment : BaseDemoFragment() {
+ private val host = App.instance.defaultConfig.host
+
+ private lateinit var lightwalletService: LightWalletService
+
+ override fun inflateBinding(layoutInflater: LayoutInflater): FragmentGetLatestHeightBinding =
+ FragmentGetLatestHeightBinding.inflate(layoutInflater)
+
+ override fun resetInBackground() {
+ lightwalletService = LightWalletGrpcService(App.instance, host)
+ }
+
+ override fun onResetComplete() {
+ binding.textInfo.text = lightwalletService.getLatestBlockHeight().toString()
+ }
+
+ override fun onClear() {
+ lightwalletService.shutdown()
+ }
+}
\ No newline at end of file
diff --git a/samples/demo-app/app/src/main/java/cash/z/wallet/sdk/demoapp/demos/getprivatekey/GetPrivateKeyFragment.kt b/samples/demo-app/app/src/main/java/cash/z/wallet/sdk/demoapp/demos/getprivatekey/GetPrivateKeyFragment.kt
new file mode 100644
index 00000000..1514e99e
--- /dev/null
+++ b/samples/demo-app/app/src/main/java/cash/z/wallet/sdk/demoapp/demos/getprivatekey/GetPrivateKeyFragment.kt
@@ -0,0 +1,45 @@
+package cash.z.wallet.sdk.demoapp.demos.getprivatekey
+
+import android.view.LayoutInflater
+import cash.z.wallet.sdk.Initializer
+import cash.z.wallet.sdk.demoapp.App
+import cash.z.wallet.sdk.demoapp.BaseDemoFragment
+import cash.z.wallet.sdk.demoapp.databinding.FragmentGetPrivateKeyBinding
+
+class GetPrivateKeyFragment : BaseDemoFragment() {
+ private var seed: ByteArray = App.instance.defaultConfig.seed
+ private val initializer: Initializer = Initializer(App.instance)
+ private lateinit var spendingKeys: Array
+ private lateinit var viewingKeys: Array
+
+ override fun inflateBinding(layoutInflater: LayoutInflater): FragmentGetPrivateKeyBinding =
+ FragmentGetPrivateKeyBinding.inflate(layoutInflater)
+
+ override fun resetInBackground() {
+ /*
+ * Initialize with the seed and retrieve one private key for each account specified (by
+ * default, only 1 account is created). In a normal circumstance, a wallet app would then
+ * store these keys in its secure storage for retrieval, later. Private keys are only needed
+ * for sending funds.
+ */
+ spendingKeys = initializer.new(seed)
+
+ /*
+ * Viewing keys can be derived from a seed or from spending keys.
+ */
+ viewingKeys = initializer.deriveViewingKeys(seed)
+
+ // just for demonstration purposes to show that these approaches produce the same result.
+ require(spendingKeys.first() == initializer.deriveSpendingKeys(seed).first())
+ require(viewingKeys.first() == initializer.deriveViewingKey(spendingKeys.first()))
+ }
+
+ override fun onResetComplete() {
+ binding.textInfo.text = "Spending Key:\n${spendingKeys[0]}\n\nViewing Key:\n${viewingKeys[0]}"
+ }
+
+ override fun onClear() {
+ initializer.clear()
+ }
+
+}
\ No newline at end of file
diff --git a/samples/demo-app/app/src/main/java/cash/z/wallet/sdk/demoapp/demos/home/HomeFragment.kt b/samples/demo-app/app/src/main/java/cash/z/wallet/sdk/demoapp/demos/home/HomeFragment.kt
new file mode 100644
index 00000000..87aa4df8
--- /dev/null
+++ b/samples/demo-app/app/src/main/java/cash/z/wallet/sdk/demoapp/demos/home/HomeFragment.kt
@@ -0,0 +1,41 @@
+package cash.z.wallet.sdk.demoapp.demos.home
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.TextView
+import androidx.fragment.app.Fragment
+import androidx.lifecycle.Observer
+import androidx.lifecycle.ViewModelProviders
+import cash.z.wallet.sdk.ext.twig
+import cash.z.wallet.sdk.demoapp.App
+import cash.z.wallet.sdk.demoapp.R
+import cash.z.wallet.sdk.ext.ZcashSdk
+
+class HomeFragment : Fragment() {
+
+ private lateinit var homeViewModel: HomeViewModel
+
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? {
+ homeViewModel =
+ ViewModelProviders.of(this).get(HomeViewModel::class.java)
+ val root = inflater.inflate(R.layout.fragment_home, container, false)
+ val textView: TextView = root.findViewById(R.id.text_home)
+ homeViewModel.text.observe(viewLifecycleOwner, Observer {
+ textView.text = it
+ })
+ return root
+ }
+
+ override fun onResume() {
+ super.onResume()
+ twig("CLEARING DATA: Visiting the home screen clears the default databases, for sanity" +
+ " sake, because each demo is intended to be self-contained.")
+ App.instance.getDatabasePath("unusued.db").parentFile.listFiles().forEach { it.delete() }
+ }
+}
diff --git a/samples/demo-app/app/src/main/java/cash/z/wallet/sdk/demoapp/demos/home/HomeViewModel.kt b/samples/demo-app/app/src/main/java/cash/z/wallet/sdk/demoapp/demos/home/HomeViewModel.kt
new file mode 100644
index 00000000..63842cd1
--- /dev/null
+++ b/samples/demo-app/app/src/main/java/cash/z/wallet/sdk/demoapp/demos/home/HomeViewModel.kt
@@ -0,0 +1,13 @@
+package cash.z.wallet.sdk.demoapp.demos.home
+
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+
+class HomeViewModel : ViewModel() {
+
+ private val _text = MutableLiveData().apply {
+ value = "\u25c4\tSelect a demo"
+ }
+ val text: LiveData = _text
+}
\ No newline at end of file
diff --git a/samples/demo-app/app/src/main/java/cash/z/wallet/sdk/demoapp/demos/listtransactions/ListTransactionsFragment.kt b/samples/demo-app/app/src/main/java/cash/z/wallet/sdk/demoapp/demos/listtransactions/ListTransactionsFragment.kt
new file mode 100644
index 00000000..8c9311c7
--- /dev/null
+++ b/samples/demo-app/app/src/main/java/cash/z/wallet/sdk/demoapp/demos/listtransactions/ListTransactionsFragment.kt
@@ -0,0 +1,90 @@
+package cash.z.wallet.sdk.demoapp.demos.listtransactions
+
+import android.view.LayoutInflater
+import android.view.View
+import androidx.lifecycle.lifecycleScope
+import androidx.paging.PagedList
+import androidx.recyclerview.widget.LinearLayoutManager
+import cash.z.wallet.sdk.Initializer
+import cash.z.wallet.sdk.Synchronizer
+import cash.z.wallet.sdk.demoapp.App
+import cash.z.wallet.sdk.demoapp.BaseDemoFragment
+import cash.z.wallet.sdk.demoapp.databinding.FragmentListTransactionsBinding
+import cash.z.wallet.sdk.entity.ConfirmedTransaction
+import cash.z.wallet.sdk.ext.collectWith
+import cash.z.wallet.sdk.ext.twig
+import kotlinx.coroutines.flow.collect
+import kotlinx.coroutines.launch
+
+/**
+ * List all transactions from a given seed and birthdate, defined in the Injector class which is
+ * intended to mimic dependency injection.
+ */
+class ListTransactionsFragment : BaseDemoFragment() {
+ private val config = App.instance.defaultConfig
+ private val initializer = Initializer(App.instance)
+ private lateinit var synchronizer: Synchronizer
+ private lateinit var adapter: TransactionAdapter
+
+ override fun inflateBinding(layoutInflater: LayoutInflater): FragmentListTransactionsBinding =
+ FragmentListTransactionsBinding.inflate(layoutInflater)
+
+ override fun resetInBackground() {
+ initializer.new(config.seed)
+ synchronizer = Synchronizer(App.instance, config.host, initializer.rustBackend)
+ }
+
+ override fun onResetComplete() {
+ initTransactionUI()
+ startSynchronizer()
+ monitorStatus()
+ }
+
+ override fun onClear() {
+ synchronizer.stop()
+ initializer.clear()
+ }
+
+ private fun initTransactionUI() {
+ binding.recyclerTransactions.layoutManager =
+ LinearLayoutManager(activity, LinearLayoutManager.VERTICAL, false)
+ adapter = TransactionAdapter()
+ lifecycleScope.launch {
+ synchronizer.receivedTransactions.collect { onTransactionsUpdated(it) }
+ }
+ binding.recyclerTransactions.adapter = adapter
+ }
+
+ private fun startSynchronizer() {
+ lifecycleScope.apply {
+ synchronizer.start(this)
+ }
+ }
+
+ private fun monitorStatus() {
+ synchronizer.status.collectWith(lifecycleScope, ::onStatus)
+ synchronizer.progress.collectWith(lifecycleScope, ::onProgress)
+ }
+
+ private fun onProgress(i: Int) {
+ val message = when (i) {
+ 100 -> "Scanning blocks..."
+ else -> "Downloading blocks...$i%"
+ }
+ binding.textInfo.text = message
+ }
+
+ private fun onStatus(status: Synchronizer.Status) {
+ binding.textStatus.text = "Status: $status"
+ if (status == Synchronizer.Status.SYNCED) onSyncComplete()
+ }
+
+ private fun onSyncComplete() {
+ binding.textInfo.visibility = View.INVISIBLE
+ }
+
+ private fun onTransactionsUpdated(transactions: PagedList) {
+ twig("got a new paged list of transactions")
+ adapter.submitList(transactions)
+ }
+}
diff --git a/samples/demo-app/app/src/main/java/cash/z/wallet/sdk/demoapp/demos/listtransactions/TransactionAdapter.kt b/samples/demo-app/app/src/main/java/cash/z/wallet/sdk/demoapp/demos/listtransactions/TransactionAdapter.kt
new file mode 100644
index 00000000..9a96534a
--- /dev/null
+++ b/samples/demo-app/app/src/main/java/cash/z/wallet/sdk/demoapp/demos/listtransactions/TransactionAdapter.kt
@@ -0,0 +1,37 @@
+package cash.z.wallet.sdk.demoapp.demos.listtransactions
+
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.paging.PagedListAdapter
+import androidx.recyclerview.widget.DiffUtil
+import cash.z.wallet.sdk.demoapp.R
+import cash.z.wallet.sdk.entity.ConfirmedTransaction
+
+class TransactionAdapter :
+ PagedListAdapter>(
+ object : DiffUtil.ItemCallback() {
+ override fun areItemsTheSame(
+ oldItem: T,
+ newItem: T
+ ) = oldItem.minedHeight == newItem.minedHeight
+
+ override fun areContentsTheSame(
+ oldItem: T,
+ newItem: T
+ ) = oldItem.equals(newItem)
+ }
+ ) {
+
+ override fun onCreateViewHolder(
+ parent: ViewGroup,
+ viewType: Int
+ ) = TransactionViewHolder(
+ LayoutInflater.from(parent.context).inflate(R.layout.item_transaction, parent, false)
+ )
+
+ override fun onBindViewHolder(
+ holder: TransactionViewHolder,
+ position: Int
+ ) = holder.bindTo(getItem(position))
+
+}
diff --git a/samples/demo-app/app/src/main/java/cash/z/wallet/sdk/demoapp/demos/listtransactions/TransactionViewHolder.kt b/samples/demo-app/app/src/main/java/cash/z/wallet/sdk/demoapp/demos/listtransactions/TransactionViewHolder.kt
new file mode 100644
index 00000000..c81b355d
--- /dev/null
+++ b/samples/demo-app/app/src/main/java/cash/z/wallet/sdk/demoapp/demos/listtransactions/TransactionViewHolder.kt
@@ -0,0 +1,23 @@
+package cash.z.wallet.sdk.demoapp.demos.listtransactions
+
+import android.view.View
+import android.widget.TextView
+import androidx.recyclerview.widget.RecyclerView
+import cash.z.wallet.sdk.demoapp.R
+import cash.z.wallet.sdk.entity.ConfirmedTransaction
+import cash.z.wallet.sdk.ext.convertZatoshiToZecString
+import java.text.SimpleDateFormat
+import java.util.*
+
+class TransactionViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
+ private val amountText = itemView.findViewById(R.id.text_transaction_amount)
+ private val timeText = itemView.findViewById(R.id.text_transaction_timestamp)
+ private val formatter = SimpleDateFormat("M/d h:mma", Locale.getDefault())
+
+ fun bindTo(transaction: T?) {
+ amountText.text = transaction?.value.convertZatoshiToZecString()
+ timeText.text =
+ if (transaction == null || transaction?.blockTimeInSeconds == 0L) "Pending"
+ else formatter.format(transaction.blockTimeInSeconds * 1000L)
+ }
+}
\ No newline at end of file
diff --git a/samples/demo-app/app/src/main/java/cash/z/wallet/sdk/demoapp/demos/send/SendFragment.kt b/samples/demo-app/app/src/main/java/cash/z/wallet/sdk/demoapp/demos/send/SendFragment.kt
new file mode 100644
index 00000000..e694232c
--- /dev/null
+++ b/samples/demo-app/app/src/main/java/cash/z/wallet/sdk/demoapp/demos/send/SendFragment.kt
@@ -0,0 +1,184 @@
+package cash.z.wallet.sdk.demoapp.demos.send
+
+import android.view.LayoutInflater
+import android.view.View
+import android.widget.TextView
+import androidx.lifecycle.lifecycleScope
+import cash.z.wallet.sdk.Initializer
+import cash.z.wallet.sdk.Synchronizer
+import cash.z.wallet.sdk.block.CompactBlockProcessor
+import cash.z.wallet.sdk.demoapp.App
+import cash.z.wallet.sdk.demoapp.BaseDemoFragment
+import cash.z.wallet.sdk.demoapp.R
+import cash.z.wallet.sdk.demoapp.databinding.FragmentSendBinding
+import cash.z.wallet.sdk.demoapp.util.SampleStorageBridge
+import cash.z.wallet.sdk.entity.*
+import cash.z.wallet.sdk.ext.*
+
+class SendFragment : BaseDemoFragment() {
+ private val config = App.instance.defaultConfig
+ private val initializer = Initializer(App.instance)
+
+ private lateinit var synchronizer: Synchronizer
+ private lateinit var keyManager: SampleStorageBridge
+
+ private lateinit var amountInput: TextView
+ private lateinit var addressInput: TextView
+
+
+ //
+ // Observable properties (done without livedata or flows for simplicity)
+ //
+
+ private var availableBalance = -1L
+ set(value) {
+ field = value
+ onUpdateSendButton()
+ }
+ private var isSending = false
+ set(value) {
+ field = value
+ if (value) Twig.sprout("Sending") else Twig.clip("Sending")
+ onUpdateSendButton()
+ }
+ private var isSyncing = true
+ set(value) {
+ field = value
+ onUpdateSendButton()
+ }
+
+
+ //
+ // BaseDemoFragment overrides
+ //
+
+ override fun inflateBinding(layoutInflater: LayoutInflater): FragmentSendBinding =
+ FragmentSendBinding.inflate(layoutInflater)
+
+ override fun resetInBackground() {
+ val spendingKeys = initializer.new(config.seed)
+ keyManager = SampleStorageBridge().securelyStorePrivateKey(spendingKeys[0])
+ synchronizer = Synchronizer(App.instance, config.host, initializer.rustBackend)
+ }
+
+ // STARTING POINT
+ override fun onResetComplete() {
+ initSendUi()
+ startSynchronizer()
+ monitorChanges()
+ }
+
+ override fun onClear() {
+ synchronizer.stop()
+ initializer.clear()
+ }
+
+
+ //
+ // Private functions
+ //
+
+ private fun initSendUi() {
+ amountInput = binding.root.findViewById(R.id.input_amount).apply {
+ text = config.sendAmount.toString()
+ }
+ addressInput = binding.root.findViewById(R.id.input_address).apply {
+ text = config.toAddress
+ }
+ binding.buttonSend.setOnClickListener(::onSend)
+ }
+
+ private fun startSynchronizer() {
+ lifecycleScope.apply {
+ synchronizer.start(this)
+ }
+ }
+
+ private fun monitorChanges() {
+ synchronizer.status.collectWith(lifecycleScope, ::onStatus)
+ synchronizer.progress.collectWith(lifecycleScope, ::onProgress)
+ synchronizer.balances.collectWith(lifecycleScope, ::onBalance)
+ }
+
+ private fun onStatus(status: Synchronizer.Status) {
+ binding.textStatus.text = "Status: $status"
+ if (status == Synchronizer.Status.SYNCING) {
+ isSyncing = true
+ binding.textBalance.text = "Calculating balance..."
+ } else {
+ isSyncing = false
+ }
+ }
+
+ private fun onProgress(i: Int) {
+ val message = when (i) {
+ 100 -> "Scanning blocks..."
+ else -> "Downloading blocks...$i%"
+ }
+ binding.textStatus.text = message
+ binding.textBalance.text = ""
+ }
+
+ private fun onBalance(balance: CompactBlockProcessor.WalletBalance) {
+ availableBalance = balance.available
+ binding.textBalance.text = """
+ Available balance: ${balance.available.convertZatoshiToZecString()}
+ Total balance: ${balance.total.convertZatoshiToZecString()}
+ """.trimIndent()
+ }
+
+ private fun onSend(unused: View) {
+ isSending = true
+ val amount = amountInput.text.toString().toDouble().convertZecToZatoshi()
+ val toAddress = addressInput.text.toString()
+ synchronizer.sendToAddress(
+ keyManager.key,
+ amount,
+ toAddress,
+ "Demo App Funds"
+ ).collectWith(lifecycleScope, ::onPendingTxUpdated)
+ }
+
+ private fun onPendingTxUpdated(pendingTransaction: PendingTransaction?) {
+ val id = pendingTransaction?.id ?: -1
+ val message = when {
+ pendingTransaction == null -> "Transaction not found"
+ pendingTransaction.isMined() -> "Transaction Mined (id: $id)!\n\nSEND COMPLETE".also { isSending = false }
+ pendingTransaction.isSubmitSuccess() -> "Successfully submitted transaction!\nAwaiting confirmation..."
+ pendingTransaction.isFailedEncoding() -> "ERROR: failed to encode transaction! (id: $id)".also { isSending = false }
+ pendingTransaction.isFailedSubmit() -> "ERROR: failed to submit transaction! (id: $id)".also { isSending = false }
+ pendingTransaction.isCreated() -> "Transaction creation complete! (id: $id)"
+ pendingTransaction.isCreating() -> "Creating transaction!".also { onResetInfo() }
+ else -> "Transaction updated!".also { twig("Unhandled TX state: $pendingTransaction") }
+ }
+ twig("Pending TX Updated: $message")
+ binding.textInfo.apply {
+ text = "$text\n$message"
+ }
+ }
+
+ private fun onUpdateSendButton() {
+ with(binding.buttonSend) {
+ when {
+ isSending -> {
+ text = "âž¡ sending"
+ isEnabled = false
+ }
+ isSyncing -> {
+ text = "⌛ syncing"
+ isEnabled = false
+ }
+ availableBalance <= 0 -> isEnabled = false
+ else -> {
+ text = "send"
+ isEnabled = true
+ }
+ }
+ }
+ }
+
+ private fun onResetInfo() {
+ binding.textInfo.text = "Active Transaction:"
+ }
+
+}
diff --git a/samples/demo-app/app/src/main/java/cash/z/wallet/sdk/demoapp/util/DemoConfig.kt b/samples/demo-app/app/src/main/java/cash/z/wallet/sdk/demoapp/util/DemoConfig.kt
new file mode 100644
index 00000000..b7d03027
--- /dev/null
+++ b/samples/demo-app/app/src/main/java/cash/z/wallet/sdk/demoapp/util/DemoConfig.kt
@@ -0,0 +1,13 @@
+package cash.z.wallet.sdk.demoapp.util
+
+data class DemoConfig(
+ val host: String = "34.68.177.238",//"192.168.1.134",//
+ val port: Int = 9067,
+ val birthdayHeight: Int = 620_000,//523_240,
+ val network: ZcashNetwork = ZcashNetwork.TEST_NET,
+ val seed: ByteArray = "testreferencealice".toByteArray(),
+ val toAddress: String = "ztestsapling1fg82ar8y8whjfd52l0xcq0w3n7nn7cask2scp9rp27njeurr72ychvud57s9tu90fdqgwdt07lg",
+ val sendAmount: Double = 0.0024
+)
+
+enum class ZcashNetwork { MAIN_NET, TEST_NET }
\ No newline at end of file
diff --git a/samples/demo-app/app/src/main/java/cash/z/wallet/sdk/demoapp/util/SampleStorage.kt b/samples/demo-app/app/src/main/java/cash/z/wallet/sdk/demoapp/util/SampleStorage.kt
new file mode 100644
index 00000000..8d3acd99
--- /dev/null
+++ b/samples/demo-app/app/src/main/java/cash/z/wallet/sdk/demoapp/util/SampleStorage.kt
@@ -0,0 +1,64 @@
+package cash.z.wallet.sdk.demoapp.util
+
+import android.content.Context
+import cash.z.wallet.sdk.demoapp.App
+
+
+@Deprecated(
+ message = "Do not use this! It is insecure and only intended for demo purposes to " +
+ "show how to bridge to an existing key storage mechanism. Instead, use the Android " +
+ "Keystore system or a 3rd party library that leverages it."
+)
+class SampleStorage {
+
+ private val prefs =
+ App.instance.getSharedPreferences("ExtremelyInsecureStorage", Context.MODE_PRIVATE)
+
+ fun saveSensitiveString(key: String, value: String) {
+ prefs.edit().putString(key, value).apply()
+ }
+
+ fun loadSensitiveString(key: String): String? = prefs.getString(key, null)
+
+ fun saveSensitiveBytes(key: String, value: ByteArray) {
+ saveSensitiveString(key, value.toString(Charsets.ISO_8859_1))
+ }
+
+ fun loadSensitiveBytes(key: String): ByteArray? =
+ prefs.getString(key, null)?.toByteArray(Charsets.ISO_8859_1)
+}
+
+/**
+ * Simple demonstration of how to take existing code that securely stores data and bridge it into
+ * the SDK. This class delegates to the storage object. For demo purposes, we're using an insecure
+ * SampleStorage implementation but this can easily be swapped for a truly secure storage solution.
+ */
+class SampleStorageBridge() {
+ private val delegate = SampleStorage()
+
+ /**
+ * Just a sugar method to help with being explicit in sample code. We want to show developers
+ * our intention that they write simple bridges to secure storage components.
+ */
+ fun securelyStoreSeed(seed: ByteArray): SampleStorageBridge {
+ delegate.saveSensitiveBytes(KEY_SEED, seed)
+ return this
+ }
+
+ /**
+ * Just a sugar method to help with being explicit in sample code. We want to show developers
+ * our intention that they write simple bridges to secure storage components.
+ */
+ fun securelyStorePrivateKey(key: String): SampleStorageBridge {
+ delegate.saveSensitiveString(KEY_PK, key)
+ return this
+ }
+
+ val seed: ByteArray get() = delegate.loadSensitiveBytes(KEY_SEED)!!
+ val key get() = delegate.loadSensitiveString(KEY_PK)!!
+
+ companion object {
+ private const val KEY_SEED = "cash.z.wallet.sdk.demoapp.SEED"
+ private const val KEY_PK = "cash.z.wallet.sdk.demoapp.PK"
+ }
+}
\ No newline at end of file
diff --git a/samples/demo-app/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/samples/demo-app/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
new file mode 100644
index 00000000..7361bc1a
--- /dev/null
+++ b/samples/demo-app/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/samples/demo-app/app/src/main/res/drawable/ic_floating_action.xml b/samples/demo-app/app/src/main/res/drawable/ic_floating_action.xml
new file mode 100644
index 00000000..7bd5af30
--- /dev/null
+++ b/samples/demo-app/app/src/main/res/drawable/ic_floating_action.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/samples/demo-app/app/src/main/res/drawable/ic_launcher_background.xml b/samples/demo-app/app/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 00000000..74852f7d
--- /dev/null
+++ b/samples/demo-app/app/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,171 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/demo-app/app/src/main/res/drawable/ic_list.xml b/samples/demo-app/app/src/main/res/drawable/ic_list.xml
new file mode 100644
index 00000000..4c2fb883
--- /dev/null
+++ b/samples/demo-app/app/src/main/res/drawable/ic_list.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/samples/demo-app/app/src/main/res/drawable/ic_menu_address.xml b/samples/demo-app/app/src/main/res/drawable/ic_menu_address.xml
new file mode 100644
index 00000000..ecfee417
--- /dev/null
+++ b/samples/demo-app/app/src/main/res/drawable/ic_menu_address.xml
@@ -0,0 +1,10 @@
+
+
+
+
\ No newline at end of file
diff --git a/samples/demo-app/app/src/main/res/drawable/ic_menu_block.xml b/samples/demo-app/app/src/main/res/drawable/ic_menu_block.xml
new file mode 100644
index 00000000..c428d728
--- /dev/null
+++ b/samples/demo-app/app/src/main/res/drawable/ic_menu_block.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/samples/demo-app/app/src/main/res/drawable/ic_menu_block_range.xml b/samples/demo-app/app/src/main/res/drawable/ic_menu_block_range.xml
new file mode 100644
index 00000000..ab36b076
--- /dev/null
+++ b/samples/demo-app/app/src/main/res/drawable/ic_menu_block_range.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/samples/demo-app/app/src/main/res/drawable/ic_menu_decrypt.xml b/samples/demo-app/app/src/main/res/drawable/ic_menu_decrypt.xml
new file mode 100644
index 00000000..6f1ccb6e
--- /dev/null
+++ b/samples/demo-app/app/src/main/res/drawable/ic_menu_decrypt.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/samples/demo-app/app/src/main/res/drawable/ic_menu_decrypt_range.xml b/samples/demo-app/app/src/main/res/drawable/ic_menu_decrypt_range.xml
new file mode 100644
index 00000000..d60cda4f
--- /dev/null
+++ b/samples/demo-app/app/src/main/res/drawable/ic_menu_decrypt_range.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/samples/demo-app/app/src/main/res/drawable/ic_menu_home.xml b/samples/demo-app/app/src/main/res/drawable/ic_menu_home.xml
new file mode 100644
index 00000000..70fb2910
--- /dev/null
+++ b/samples/demo-app/app/src/main/res/drawable/ic_menu_home.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/samples/demo-app/app/src/main/res/drawable/ic_menu_latest_height.xml b/samples/demo-app/app/src/main/res/drawable/ic_menu_latest_height.xml
new file mode 100644
index 00000000..5e776beb
--- /dev/null
+++ b/samples/demo-app/app/src/main/res/drawable/ic_menu_latest_height.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/samples/demo-app/app/src/main/res/drawable/ic_menu_memo.xml b/samples/demo-app/app/src/main/res/drawable/ic_menu_memo.xml
new file mode 100644
index 00000000..99b5867b
--- /dev/null
+++ b/samples/demo-app/app/src/main/res/drawable/ic_menu_memo.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/samples/demo-app/app/src/main/res/drawable/ic_menu_private_key.xml b/samples/demo-app/app/src/main/res/drawable/ic_menu_private_key.xml
new file mode 100644
index 00000000..2eddd16f
--- /dev/null
+++ b/samples/demo-app/app/src/main/res/drawable/ic_menu_private_key.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/samples/demo-app/app/src/main/res/drawable/ic_menu_send.xml b/samples/demo-app/app/src/main/res/drawable/ic_menu_send.xml
new file mode 100644
index 00000000..e145ca83
--- /dev/null
+++ b/samples/demo-app/app/src/main/res/drawable/ic_menu_send.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/samples/demo-app/app/src/main/res/drawable/ic_receive.xml b/samples/demo-app/app/src/main/res/drawable/ic_receive.xml
new file mode 100644
index 00000000..e10be10b
--- /dev/null
+++ b/samples/demo-app/app/src/main/res/drawable/ic_receive.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/samples/demo-app/app/src/main/res/drawable/ic_send.xml b/samples/demo-app/app/src/main/res/drawable/ic_send.xml
new file mode 100644
index 00000000..f3f6d708
--- /dev/null
+++ b/samples/demo-app/app/src/main/res/drawable/ic_send.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/samples/demo-app/app/src/main/res/drawable/side_nav_bar.xml b/samples/demo-app/app/src/main/res/drawable/side_nav_bar.xml
new file mode 100644
index 00000000..371d9778
--- /dev/null
+++ b/samples/demo-app/app/src/main/res/drawable/side_nav_bar.xml
@@ -0,0 +1,10 @@
+
+
+
\ No newline at end of file
diff --git a/samples/demo-app/app/src/main/res/layout/activity_main.xml b/samples/demo-app/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 00000000..9bfb2ed6
--- /dev/null
+++ b/samples/demo-app/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
diff --git a/samples/demo-app/app/src/main/res/layout/app_bar_main.xml b/samples/demo-app/app/src/main/res/layout/app_bar_main.xml
new file mode 100644
index 00000000..49597aff
--- /dev/null
+++ b/samples/demo-app/app/src/main/res/layout/app_bar_main.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/samples/demo-app/app/src/main/res/layout/content_main.xml b/samples/demo-app/app/src/main/res/layout/content_main.xml
new file mode 100644
index 00000000..7e58f6e0
--- /dev/null
+++ b/samples/demo-app/app/src/main/res/layout/content_main.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/samples/demo-app/app/src/main/res/layout/fragment_gallery.xml b/samples/demo-app/app/src/main/res/layout/fragment_gallery.xml
new file mode 100644
index 00000000..4399e62a
--- /dev/null
+++ b/samples/demo-app/app/src/main/res/layout/fragment_gallery.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/samples/demo-app/app/src/main/res/layout/fragment_get_address.xml b/samples/demo-app/app/src/main/res/layout/fragment_get_address.xml
new file mode 100644
index 00000000..9c45e7cd
--- /dev/null
+++ b/samples/demo-app/app/src/main/res/layout/fragment_get_address.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/samples/demo-app/app/src/main/res/layout/fragment_get_block.xml b/samples/demo-app/app/src/main/res/layout/fragment_get_block.xml
new file mode 100644
index 00000000..fefbdc06
--- /dev/null
+++ b/samples/demo-app/app/src/main/res/layout/fragment_get_block.xml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/samples/demo-app/app/src/main/res/layout/fragment_get_block_range.xml b/samples/demo-app/app/src/main/res/layout/fragment_get_block_range.xml
new file mode 100644
index 00000000..2db7867a
--- /dev/null
+++ b/samples/demo-app/app/src/main/res/layout/fragment_get_block_range.xml
@@ -0,0 +1,76 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/samples/demo-app/app/src/main/res/layout/fragment_get_latest_height.xml b/samples/demo-app/app/src/main/res/layout/fragment_get_latest_height.xml
new file mode 100644
index 00000000..740a1dfd
--- /dev/null
+++ b/samples/demo-app/app/src/main/res/layout/fragment_get_latest_height.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/samples/demo-app/app/src/main/res/layout/fragment_get_private_key.xml b/samples/demo-app/app/src/main/res/layout/fragment_get_private_key.xml
new file mode 100644
index 00000000..aa26b256
--- /dev/null
+++ b/samples/demo-app/app/src/main/res/layout/fragment_get_private_key.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/samples/demo-app/app/src/main/res/layout/fragment_home.xml b/samples/demo-app/app/src/main/res/layout/fragment_home.xml
new file mode 100644
index 00000000..77297978
--- /dev/null
+++ b/samples/demo-app/app/src/main/res/layout/fragment_home.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/samples/demo-app/app/src/main/res/layout/fragment_home_second.xml b/samples/demo-app/app/src/main/res/layout/fragment_home_second.xml
new file mode 100644
index 00000000..22cbf9fe
--- /dev/null
+++ b/samples/demo-app/app/src/main/res/layout/fragment_home_second.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/samples/demo-app/app/src/main/res/layout/fragment_list_transactions.xml b/samples/demo-app/app/src/main/res/layout/fragment_list_transactions.xml
new file mode 100644
index 00000000..2e5e31a1
--- /dev/null
+++ b/samples/demo-app/app/src/main/res/layout/fragment_list_transactions.xml
@@ -0,0 +1,68 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/samples/demo-app/app/src/main/res/layout/fragment_send.xml b/samples/demo-app/app/src/main/res/layout/fragment_send.xml
new file mode 100644
index 00000000..91942426
--- /dev/null
+++ b/samples/demo-app/app/src/main/res/layout/fragment_send.xml
@@ -0,0 +1,92 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/samples/demo-app/app/src/main/res/layout/fragment_slideshow.xml b/samples/demo-app/app/src/main/res/layout/fragment_slideshow.xml
new file mode 100644
index 00000000..c74cf4b2
--- /dev/null
+++ b/samples/demo-app/app/src/main/res/layout/fragment_slideshow.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/samples/demo-app/app/src/main/res/layout/item_transaction.xml b/samples/demo-app/app/src/main/res/layout/item_transaction.xml
new file mode 100644
index 00000000..152c92b0
--- /dev/null
+++ b/samples/demo-app/app/src/main/res/layout/item_transaction.xml
@@ -0,0 +1,64 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/samples/demo-app/app/src/main/res/layout/nav_header_main.xml b/samples/demo-app/app/src/main/res/layout/nav_header_main.xml
new file mode 100644
index 00000000..91f3868a
--- /dev/null
+++ b/samples/demo-app/app/src/main/res/layout/nav_header_main.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/demo-app/app/src/main/res/menu/activity_main_drawer.xml b/samples/demo-app/app/src/main/res/menu/activity_main_drawer.xml
new file mode 100644
index 00000000..64815c76
--- /dev/null
+++ b/samples/demo-app/app/src/main/res/menu/activity_main_drawer.xml
@@ -0,0 +1,41 @@
+
+
\ No newline at end of file
diff --git a/samples/demo-app/app/src/main/res/menu/main.xml b/samples/demo-app/app/src/main/res/menu/main.xml
new file mode 100644
index 00000000..ef4d01c6
--- /dev/null
+++ b/samples/demo-app/app/src/main/res/menu/main.xml
@@ -0,0 +1,10 @@
+
+
diff --git a/samples/addressAndKeys/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/samples/demo-app/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
similarity index 60%
rename from samples/addressAndKeys/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
rename to samples/demo-app/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
index bbd3e021..9f692741 100644
--- a/samples/addressAndKeys/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
+++ b/samples/demo-app/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -1,5 +1,6 @@
-
-
-
+
+
+
\ No newline at end of file
diff --git a/samples/addressAndKeys/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/samples/demo-app/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
similarity index 60%
rename from samples/addressAndKeys/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
rename to samples/demo-app/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
index bbd3e021..9f692741 100644
--- a/samples/addressAndKeys/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
+++ b/samples/demo-app/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -1,5 +1,6 @@
-
-
-
+
+
+
\ No newline at end of file
diff --git a/samples/demo-app/app/src/main/res/mipmap-hdpi/ic_launcher.png b/samples/demo-app/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 00000000..a571e600
Binary files /dev/null and b/samples/demo-app/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/samples/demo-app/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/samples/demo-app/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 00000000..61da551c
Binary files /dev/null and b/samples/demo-app/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ
diff --git a/samples/demo-app/app/src/main/res/mipmap-mdpi/ic_launcher.png b/samples/demo-app/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 00000000..c41dd285
Binary files /dev/null and b/samples/demo-app/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/samples/demo-app/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/samples/demo-app/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 00000000..db5080a7
Binary files /dev/null and b/samples/demo-app/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ
diff --git a/samples/demo-app/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/samples/demo-app/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 00000000..6dba46da
Binary files /dev/null and b/samples/demo-app/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/samples/demo-app/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/samples/demo-app/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 00000000..da31a871
Binary files /dev/null and b/samples/demo-app/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ
diff --git a/samples/demo-app/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/samples/demo-app/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 00000000..15ac6817
Binary files /dev/null and b/samples/demo-app/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/samples/demo-app/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/samples/demo-app/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 00000000..b216f2d3
Binary files /dev/null and b/samples/demo-app/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ
diff --git a/samples/demo-app/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/samples/demo-app/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 00000000..f25a4197
Binary files /dev/null and b/samples/demo-app/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/samples/demo-app/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/samples/demo-app/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 00000000..e96783cc
Binary files /dev/null and b/samples/demo-app/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ
diff --git a/samples/demo-app/app/src/main/res/navigation/mobile_navigation.xml b/samples/demo-app/app/src/main/res/navigation/mobile_navigation.xml
new file mode 100644
index 00000000..721ac403
--- /dev/null
+++ b/samples/demo-app/app/src/main/res/navigation/mobile_navigation.xml
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/samples/demo-app/app/src/main/res/values-v21/styles.xml b/samples/demo-app/app/src/main/res/values-v21/styles.xml
new file mode 100644
index 00000000..fd7a0584
--- /dev/null
+++ b/samples/demo-app/app/src/main/res/values-v21/styles.xml
@@ -0,0 +1,8 @@
+
+
+
+
diff --git a/samples/demo-app/app/src/main/res/values/colors.xml b/samples/demo-app/app/src/main/res/values/colors.xml
new file mode 100644
index 00000000..030098fe
--- /dev/null
+++ b/samples/demo-app/app/src/main/res/values/colors.xml
@@ -0,0 +1,6 @@
+
+
+ #6200EE
+ #3700B3
+ #03DAC5
+
diff --git a/samples/demo-app/app/src/main/res/values/dimens.xml b/samples/demo-app/app/src/main/res/values/dimens.xml
new file mode 100644
index 00000000..4ab4520f
--- /dev/null
+++ b/samples/demo-app/app/src/main/res/values/dimens.xml
@@ -0,0 +1,8 @@
+
+
+ 16dp
+ 16dp
+ 8dp
+ 176dp
+ 16dp
+
\ No newline at end of file
diff --git a/samples/demo-app/app/src/main/res/values/strings.xml b/samples/demo-app/app/src/main/res/values/strings.xml
new file mode 100644
index 00000000..3001581c
--- /dev/null
+++ b/samples/demo-app/app/src/main/res/values/strings.xml
@@ -0,0 +1,24 @@
+
+ Demo App
+ Open navigation drawer
+ Close navigation drawer
+ Android SDK Demo
+ v1.0.0-alpha02
+ Navigation header
+ Settings
+
+
+ Home
+ Get Private Key
+ Get Address
+ Get Latest Height
+ Get Block
+ Get Block Range
+ Decrypt Block
+ List Transactions
+ Send
+
+ Home Second
+ Next
+ Previous
+
diff --git a/samples/memo/app/src/main/res/values/styles.xml b/samples/demo-app/app/src/main/res/values/styles.xml
similarity index 54%
rename from samples/memo/app/src/main/res/values/styles.xml
rename to samples/demo-app/app/src/main/res/values/styles.xml
index 5885930d..545b9c6d 100644
--- a/samples/memo/app/src/main/res/values/styles.xml
+++ b/samples/demo-app/app/src/main/res/values/styles.xml
@@ -8,4 +8,13 @@
- @color/colorAccent
+
+
+
+
+
+
diff --git a/samples/demo-app/build.gradle b/samples/demo-app/build.gradle
new file mode 100644
index 00000000..0dfe6e71
--- /dev/null
+++ b/samples/demo-app/build.gradle
@@ -0,0 +1,34 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+
+
+
+buildscript {
+ ext.kotlin_version = '1.3.50'
+ ext.sdk_version = '1.0.0-alpha03'
+ repositories {
+ google ()
+ jcenter()
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:3.6.0-beta04'
+ classpath"org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+ // NOTE: Do not place your application dependencies here; they belong
+ // in the individual module build.gradle files
+ classpath 'androidx.navigation:navigation-safe-args-gradle-plugin:2.0.0'
+ }
+}
+
+allprojects {
+ repositories {
+// mavenLocal()
+// flatDir {
+// dirs 'libs'
+// }
+ google()
+ jcenter()
+ }
+}
+
+task clean(type: Delete) {
+ delete rootProject.buildDir
+}
diff --git a/samples/addressAndKeys/gradle.properties b/samples/demo-app/gradle.properties
similarity index 100%
rename from samples/addressAndKeys/gradle.properties
rename to samples/demo-app/gradle.properties
diff --git a/samples/addressAndKeys/gradle/wrapper/gradle-wrapper.jar b/samples/demo-app/gradle/wrapper/gradle-wrapper.jar
similarity index 100%
rename from samples/addressAndKeys/gradle/wrapper/gradle-wrapper.jar
rename to samples/demo-app/gradle/wrapper/gradle-wrapper.jar
diff --git a/samples/addressAndKeys/gradle/wrapper/gradle-wrapper.properties b/samples/demo-app/gradle/wrapper/gradle-wrapper.properties
similarity index 87%
rename from samples/addressAndKeys/gradle/wrapper/gradle-wrapper.properties
rename to samples/demo-app/gradle/wrapper/gradle-wrapper.properties
index 7cdf0d3e..e20b905f 100644
--- a/samples/addressAndKeys/gradle/wrapper/gradle-wrapper.properties
+++ b/samples/demo-app/gradle/wrapper/gradle-wrapper.properties
@@ -1,4 +1,4 @@
-#Sat Jun 08 14:45:29 EDT 2019
+#Mon Sep 30 13:00:06 MDT 2019
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
diff --git a/samples/addressAndKeys/gradlew b/samples/demo-app/gradlew
similarity index 100%
rename from samples/addressAndKeys/gradlew
rename to samples/demo-app/gradlew
diff --git a/samples/addressAndKeys/gradlew.bat b/samples/demo-app/gradlew.bat
similarity index 100%
rename from samples/addressAndKeys/gradlew.bat
rename to samples/demo-app/gradlew.bat
diff --git a/samples/memo/settings.gradle b/samples/demo-app/settings.gradle
similarity index 76%
rename from samples/memo/settings.gradle
rename to samples/demo-app/settings.gradle
index d8755053..6e8238d4 100644
--- a/samples/memo/settings.gradle
+++ b/samples/demo-app/settings.gradle
@@ -1,3 +1,3 @@
include ':app', ":sdk"
project(":sdk").projectDir = file("../../../zcash-android-wallet-sdk")
-rootProject.name='Zcash Memo'
+rootProject.name='Demo App'
diff --git a/samples/memo/.gitignore b/samples/memo/.gitignore
deleted file mode 100644
index 603b1407..00000000
--- a/samples/memo/.gitignore
+++ /dev/null
@@ -1,14 +0,0 @@
-*.iml
-.gradle
-/local.properties
-/.idea/caches
-/.idea/libraries
-/.idea/modules.xml
-/.idea/workspace.xml
-/.idea/navEditor.xml
-/.idea/assetWizardSettings.xml
-.DS_Store
-/build
-/captures
-.externalNativeBuild
-.cxx
diff --git a/samples/memo/app/.gitignore b/samples/memo/app/.gitignore
deleted file mode 100644
index 796b96d1..00000000
--- a/samples/memo/app/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-/build
diff --git a/samples/memo/app/build.gradle b/samples/memo/app/build.gradle
deleted file mode 100644
index 8eb1df0f..00000000
--- a/samples/memo/app/build.gradle
+++ /dev/null
@@ -1,39 +0,0 @@
-apply plugin: 'com.android.application'
-
-apply plugin: 'kotlin-android'
-
-apply plugin: 'kotlin-android-extensions'
-
-android {
- compileSdkVersion 29
- defaultConfig {
- applicationId "cash.z.wallet.sdk.sample.memo"
- minSdkVersion 21
- targetSdkVersion 29
- versionCode 1
- versionName "1.0"
- testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
- missingDimensionStrategy "network", "zcashtestnet"
- }
- buildTypes {
- release {
- minifyEnabled false
- proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
- matchingFallbacks = ['zcashtestnetRelease']
- }
- }
-}
-
-dependencies {
- implementation project(path: ':sdk', configuration: 'default')
- implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${versions.kotlin}"
- implementation 'androidx.appcompat:appcompat:1.1.0'
- implementation 'androidx.core:core-ktx:1.1.0'
- implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
- implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:${versions.coroutines}"
- implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:${versions.coroutines}"
- testImplementation 'junit:junit:4.12'
- androidTestImplementation 'androidx.test.ext:junit:1.1.1'
- androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
- implementation project(path: ':sdk')
-}
diff --git a/samples/memo/app/proguard-rules.pro b/samples/memo/app/proguard-rules.pro
deleted file mode 100644
index f1b42451..00000000
--- a/samples/memo/app/proguard-rules.pro
+++ /dev/null
@@ -1,21 +0,0 @@
-# Add project specific ProGuard rules here.
-# You can control the set of applied configuration files using the
-# proguardFiles setting in build.gradle.
-#
-# For more details, see
-# http://developer.android.com/guide/developing/tools/proguard.html
-
-# If your project uses WebView with JS, uncomment the following
-# and specify the fully qualified class name to the JavaScript interface
-# class:
-#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
-# public *;
-#}
-
-# Uncomment this to preserve the line number information for
-# debugging stack traces.
-#-keepattributes SourceFile,LineNumberTable
-
-# If you keep the line number information, uncomment this to
-# hide the original source file name.
-#-renamesourcefileattribute SourceFile
diff --git a/samples/memo/app/src/main/AndroidManifest.xml b/samples/memo/app/src/main/AndroidManifest.xml
deleted file mode 100644
index 09231ef6..00000000
--- a/samples/memo/app/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/samples/memo/app/src/main/java/cash/z/wallet/sdk/sample/memo/Injection.kt b/samples/memo/app/src/main/java/cash/z/wallet/sdk/sample/memo/Injection.kt
deleted file mode 100644
index 8d10221e..00000000
--- a/samples/memo/app/src/main/java/cash/z/wallet/sdk/sample/memo/Injection.kt
+++ /dev/null
@@ -1,65 +0,0 @@
-package cash.z.wallet.sdk.sample.memo
-
-import android.content.Context
-import cash.z.wallet.sdk.block.CompactBlockDbStore
-import cash.z.wallet.sdk.block.CompactBlockDownloader
-import cash.z.wallet.sdk.block.CompactBlockProcessor
-import cash.z.wallet.sdk.block.ProcessorConfig
-import cash.z.wallet.sdk.data.*
-import cash.z.wallet.sdk.ext.SampleSeedProvider
-import cash.z.wallet.sdk.ext.SimpleProvider
-import cash.z.wallet.sdk.jni.RustBackend
-import cash.z.wallet.sdk.secure.Wallet
-import cash.z.wallet.sdk.service.LightWalletGrpcService
-
-object Injection {
- private const val host: String = "34.68.177.238"
- private const val port: Int = 9067
- private const val cacheDbName = "memos-cache.db"
- private const val dataDbName = "memos-data.db"
- private val rustBackend = RustBackend()
-
- fun provideSynchronizer(appContext: Context): Synchronizer {
-
- // ledger
- val ledger = PollingTransactionRepository(appContext, dataDbName)
-
- // sender
- val manager = PersistentTransactionManager(appContext)
- val service = LightWalletGrpcService(appContext, host, port)
- val sender = PersistentTransactionSender(manager, service, ledger)
-
- // processor
- val config = ProcessorConfig(cacheDbName.toDbPath(appContext), dataDbName.toDbPath(appContext))
- val blockStore = CompactBlockDbStore(appContext, cacheDbName)
- val downloader = CompactBlockDownloader(service, blockStore)
- val processor = CompactBlockProcessor(config, downloader, ledger, rustBackend)
-
- // wrapper for rustbackend
- val wallet = Wallet(
- context = appContext,
- birthday = Wallet.loadBirthdayFromAssets(appContext, 421720),
- rustBackend = rustBackend,
- dataDbName = dataDbName,
- seedProvider = SampleSeedProvider("testreferencecarol"),
- spendingKeyProvider = SimpleProvider("dummyValue")
- )
-
- // Encoder
- val encoder = WalletTransactionEncoder(wallet, ledger)
-
- // ties everything together
- return SdkSynchronizer(
- wallet,
- ledger,
- sender,
- processor,
- encoder
- )
- }
-
- private fun String.toDbPath(context: Context): String {
- return context.getDatabasePath(this).absolutePath
- }
-}
-
diff --git a/samples/memo/app/src/main/java/cash/z/wallet/sdk/sample/memo/MainActivity.kt b/samples/memo/app/src/main/java/cash/z/wallet/sdk/sample/memo/MainActivity.kt
deleted file mode 100644
index b8ad46b4..00000000
--- a/samples/memo/app/src/main/java/cash/z/wallet/sdk/sample/memo/MainActivity.kt
+++ /dev/null
@@ -1,139 +0,0 @@
-package cash.z.wallet.sdk.sample.memo
-
-import android.annotation.SuppressLint
-import android.os.Bundle
-import android.view.View
-import android.view.inputmethod.InputMethodManager
-import androidx.core.content.getSystemService
-import cash.z.wallet.sdk.data.*
-import cash.z.wallet.sdk.ext.convertZatoshiToZec
-import cash.z.wallet.sdk.secure.Wallet
-import kotlinx.android.synthetic.main.activity_main.*
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Job
-import kotlinx.coroutines.cancel
-import kotlinx.coroutines.channels.ReceiveChannel
-import kotlinx.coroutines.launch
-import kotlin.properties.Delegates
-import kotlin.properties.Delegates.observable
-import kotlin.reflect.KProperty
-
-class MainActivity : ScopedActivity() {
-
- private lateinit var synchronizer: Synchronizer
- private var activeTransaction: TransactionInfo = TransactionInfo()
- private var loaded: Boolean by observable(false) {_, old: Boolean, new: Boolean ->
- if (!old && new) {
- launch {
- onBalance(synchronizer.lastBalance())
- }
- }
- }
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_main)
-
- // Turn on simple logging for debug builds
- Twig.plant(TroubleshootingTwig())
-
- synchronizer = Injection.provideSynchronizer(this.applicationContext)
- synchronizer.start(this)
-
- launchProgressMonitor(synchronizer.progress())
- launchBalanceMonitor(synchronizer.balances())
- }
-
- override fun onDestroy() {
- super.onDestroy()
- cancel()
- synchronizer.stop()
- }
-
- private fun CoroutineScope.launchProgressMonitor(channel: ReceiveChannel) = launch {
- for (i in channel) {
- onProgress(i)
- }
- }
-
-// private fun CoroutineScope.launchTransactionMonitor(channel: ReceiveChannel